/////////////////////////////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2025, ООО 1С-Софт // Все права защищены. Эта программа и сопроводительные материалы предоставляются // в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0) // Текст лицензии доступен по ссылке: // https://creativecommons.org/licenses/by/4.0/legalcode /////////////////////////////////////////////////////////////////////////////////////////////////////// #Область ПрограммныйИнтерфейс #Область ОповещениеПользователя // Формирует и выводит сообщение, которое может быть связано с элементом управления формы. // // В фоновом задании длительной операции, если вызов выполнен вне транзакции, // сообщение записывается в служебный регистр и отправляется сразу на клиент, // если подключена система взаимодействия. // В конце фонового задания длительной операции, а также при отправке прогресса, // все сообщения извлекаются из очереди сообщений фонового задания, // записываются в служебный регистр и отправляются сразу на клиент, // если подключена система взаимодействия. // // АПК:142-выкл 4 необязательных параметра для совместимости // с устаревшей процедурой ОбщегоНазначенияКлиентСервер.СообщитьПользователю. // // Параметры: // ТекстСообщенияПользователю - Строка - текст сообщения. // КлючДанных - Произвольный - объект, ссылка или ключ записи информационной базы, к которому это сообщение относится. // Поле - Строка - наименование реквизита формы. // ПутьКДанным - Строка - путь к данным (путь к реквизиту формы). // Отказ - Булево - выходной параметр, всегда устанавливается в значение Истина. // // Пример: // // 1. Для вывода сообщения у поля управляемой формы, связанного с реквизитом объекта: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = 'Сообщение об ошибке.'"), , // "ПолеВРеквизитеФормыОбъект", // "Объект"); // // Альтернативный вариант использования в форме объекта: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = 'Сообщение об ошибке.'"), , // "Объект.ПолеВРеквизитеФормыОбъект"); // // 2. Для вывода сообщения рядом с полем управляемой формы, связанным с реквизитом формы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = 'Сообщение об ошибке.'"), , // "ИмяРеквизитаФормы"); // // 3. Для вывода сообщения связанного с объектом информационной базы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = 'Сообщение об ошибке.'"), ОбъектИнформационнойБазы, "Ответственный",,Отказ); // // 4. Для вывода сообщения по ссылке на объект информационной базы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = 'Сообщение об ошибке.'"), Ссылка, , , Отказ); // // Случаи некорректного использования: // 1. Передача одновременно параметров КлючДанных и ПутьКДанным. // 2. Передача в параметре КлючДанных значения типа отличного от допустимого. // 3. Установка ссылки без установки поля (и/или пути к данным). // Процедура СообщитьПользователю(Знач ТекстСообщенияПользователю, Знач КлючДанных = Неопределено, Знач Поле = "", Знач ПутьКДанным = "", Отказ = Ложь) Экспорт ЭтоОбъект = Ложь; Если КлючДанных <> Неопределено И XMLТипЗнч(КлючДанных) <> Неопределено Тогда ТипЗначенияСтрокой = XMLТипЗнч(КлючДанных).ИмяТипа; ЭтоОбъект = СтрНайти(ТипЗначенияСтрокой, "Object.") > 0; КонецЕсли; Сообщение = ОбщегоНазначенияСлужебныйКлиентСервер.СообщениеПользователю(ТекстСообщенияПользователю, КлючДанных, Поле, ПутьКДанным, Отказ, ЭтоОбъект); #Если НЕ МобильныйАвтономныйСервер Тогда Если СтандартныеПодсистемыПовтИсп.ЭтоСеансДлительнойОперации() И Не ТранзакцияАктивна() Тогда ДлительныеОперации.ОтправитьОповещениеКлиенту("СообщениеПользователю", Сообщение); Иначе Сообщение.Сообщить(); КонецЕсли; #Иначе Сообщение.Сообщить(); #КонецЕсли КонецПроцедуры // АПК:142-вкл #КонецОбласти #Если НЕ МобильныйАвтономныйСервер Тогда #Область ДанныеВБазе //////////////////////////////////////////////////////////////////////////////// // Общие процедуры и функции для работы с данными в базе. // Возвращает структуру, содержащую значения реквизитов, прочитанные из информационной базы по ссылке на объект. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить. // - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить. // Реквизиты - Строка - имена реквизитов, перечисленные через запятую, в формате // требований к свойствам структуры. // Например, "Код, Наименование, Родитель". // - Структура // - ФиксированнаяСтруктура - в качестве ключа передается // псевдоним поля для возвращаемой структуры с результатом, а в качестве // значения (опционально) фактическое имя поля в таблице. // Если ключ задан, а значение не определено, то имя поля берется из ключа. // Допускается указание имени поля через точку, но при этом параметр КодЯзыка для такого поля // учитываться не будет. // - Массив из Строка // - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя; // если есть ограничение на уровне записей, то все реквизиты вернутся со // значением Неопределено; если нет прав для работы с таблицей, то возникнет исключение; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Структура - содержит имена (ключи) и значения затребованных реквизитов. // Если в параметр Реквизиты передана пустая строка, то возвращается пустая структура. // Если в параметр Ссылка передана пустая ссылка, то возвращается структура, // соответствующая именам реквизитов со значениями Неопределено. // Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка), // то все реквизиты вернутся со значением Неопределено. // Функция ЗначенияРеквизитовОбъекта(Ссылка, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт // Если передано имя предопределенного. Если ТипЗнч(Ссылка) = Тип("Строка") Тогда ПолноеИмяПредопределенногоЭлемента = Ссылка; // Вычисление ссылки по имени предопределенного. // - дополнительно выполняет проверку метаданных предопределенного, выполняется предварительно. Попытка Ссылка = ПредопределенныйЭлемент(ПолноеИмяПредопределенногоЭлемента); Исключение ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный первый параметр %1 в функции %2: |%3'"), "Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецПопытки; // Разбор полного имени предопределенного. ЧастиПолногоИмени = СтрРазделить(ПолноеИмяПредопределенногоЭлемента, "."); ПолноеИмяОбъектаМетаданных = ЧастиПолногоИмени[0] + "." + ЧастиПолногоИмени[1]; // Если предопределенный не создан в ИБ, то требуется выполнить проверку доступа к объекту. // В других сценариях проверка доступа выполняется в момент исполнения запроса. Если Ссылка = Неопределено Тогда МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных); Если Не ПравоДоступа("Чтение", МетаданныеОбъекта) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недостаточно прав для работы с таблицей ""%1""'"), ПолноеИмяОбъектаМетаданных), КатегорияОшибки.НарушениеПравДоступа); КонецЕсли; КонецЕсли; Иначе // Если передана ссылка. Попытка ПолноеИмяОбъектаМетаданных = Ссылка.Метаданные().ПолноеИмя(); Исключение ВызватьИсключение (СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный первый параметр %1 в функции %2: |Значение должно быть ссылкой или именем предопределенного элемента.'"), "Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта"), КатегорияОшибки.ОшибкаКонфигурации); КонецПопытки; КонецЕсли; // Разбор реквизитов, если второй параметр Строка. Если ТипЗнч(Реквизиты) = Тип("Строка") Тогда Если ПустаяСтрока(Реквизиты) Тогда Возврат Новый Структура; КонецЕсли; Реквизиты = СтрРазделить(Реквизиты, ",", Ложь); Для Индекс = 0 По Реквизиты.ВГраница() Цикл Реквизиты[Индекс] = СокрЛП(Реквизиты[Индекс]); КонецЦикла; КонецЕсли; МультиязычныеРеквизиты = Новый Соответствие; СуффиксЯзыка = ""; Если ЗначениеЗаполнено(КодЯзыка) Тогда Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылка); КонецЕсли; КонецЕсли; КонецЕсли; // Приведение реквизитов к единому формату. СтруктураПолей = Новый Структура; Если ТипЗнч(Реквизиты) = Тип("Структура") Или ТипЗнч(Реквизиты) = Тип("ФиксированнаяСтруктура") Тогда Для Каждого КлючИЗначение Из Реквизиты Цикл СтруктураПолей.Вставить(КлючИЗначение.Ключ, СокрЛП(КлючИЗначение.Значение)); КонецЦикла; ИначеЕсли ТипЗнч(Реквизиты) = Тип("Массив") Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда Для Каждого Реквизит Из Реквизиты Цикл Реквизит = СокрЛП(Реквизит); Попытка ПсевдонимПоля = СтрЗаменить(Реквизит, ".", ""); СтруктураПолей.Вставить(ПсевдонимПоля, Реквизит); Исключение // Если псевдоним не является ключом. // Поиск ошибки доступности полей. Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; // Не удалось распознать ошибку, проброс первичной ошибки. ВызватьИсключение; КонецПопытки; КонецЦикла; Иначе ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный тип второго параметра %1 в функции %2: %3.'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Строка(ТипЗнч(Реквизиты))), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; // Подготовка результата (после выполнения запроса переопределится). Результат = Новый Структура; // Формирование текста запроса к выбираемым полям. ТекстЗапросаПолей = ""; Для каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); ПсевдонимПоля = КлючИЗначение.Ключ; Если МультиязычныеРеквизиты[ИмяПоля] = Ложь Тогда ИмяПоля = ИмяПоля + СуффиксЯзыка; КонецЕсли; ТекстЗапросаПолей = ТекстЗапросаПолей + ?(ПустаяСтрока(ТекстЗапросаПолей), "", ",") + " | " + ИмяПоля + " КАК " + ПсевдонимПоля; // Предварительное добавление поля по псевдониму в возвращаемый результат. Результат.Вставить(ПсевдонимПоля); КонецЦикла; // Если предопределенного нет в ИБ. // - приведение результата к отсутствию объекта в ИБ или передаче пустой ссылки. Если Ссылка = Неопределено Тогда Возврат Результат; КонецЕсли; Если Тип("Структура") = ТипЗнч(Реквизиты) Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда Реквизиты = Новый Массив; Для Каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Реквизиты.Добавить(ИмяПоля); КонецЦикла; КонецЕсли; РеквизитыЧерезТочку = Новый Массив; Для Индекс = -Реквизиты.ВГраница() По 0 Цикл ИмяПоля = Реквизиты[-Индекс]; Если СтрНайти(ИмяПоля, ".") Тогда РеквизитыЧерезТочку.Добавить(ИмяПоля); Реквизиты.Удалить(-Индекс); КонецЕсли; КонецЦикла; Если ЗначениеЗаполнено(Реквизиты) Тогда ЗначенияРеквизитовОбъекта = ЗначенияРеквизитовОбъектов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка), Реквизиты, ВыбратьРазрешенные, КодЯзыка)[Ссылка]; Если ЗначенияРеквизитовОбъекта <> Неопределено Тогда Для Каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Если СтрНайти(ИмяПоля, ".") = 0 И ЗначенияРеквизитовОбъекта.Свойство(ИмяПоля) Тогда Результат[КлючИЗначение.Ключ] = ЗначенияРеквизитовОбъекта[ИмяПоля]; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; Если Не ЗначениеЗаполнено(РеквизитыЧерезТочку) Тогда Возврат Результат; КонецЕсли; Реквизиты = РеквизитыЧерезТочку; ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ |&ТекстЗапросаПолей |ИЗ | &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка = &Ссылка"; Если Не ВыбратьРазрешенные Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекстЗапросаПолей", ТекстЗапросаПолей); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных); // Выполнение запроса. Запрос = Новый Запрос; Запрос.УстановитьПараметр("Ссылка", Ссылка); Запрос.Текст = ТекстЗапроса; Попытка Выборка = Запрос.Выполнить().Выбрать(); Исключение // Если реквизиты были переданы строкой, то они уже конвертированы в массив. // Если реквизиты - массив, оставляем без изменений. // Если реквизиты - структура - конвертируем в массив. // В остальных случаях уже было бы выброшено исключение. Если Тип("Структура") = ТипЗнч(Реквизиты) Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда Реквизиты = Новый Массив; Для каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Реквизиты.Добавить(ИмяПоля); КонецЦикла; КонецЕсли; // Поиск ошибки доступности полей. Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ВызватьИсключение; КонецПопытки; // Заполнение реквизитов. Если Выборка.Следующий() Тогда ЗаполнитьЗначенияСвойств(Результат, Выборка); КонецЕсли; Возврат Результат; КонецФункции // Возвращает значения реквизита, прочитанного из информационной базы по ссылке на объект. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить. // - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить. // ИмяРеквизита - Строка - имя получаемого реквизита. // Допускается указание имени реквизита через точку, но при этом параметр КодЯзыка для // такого реквизита учитываться не будет. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя; // если есть ограничение на уровне записей, то возвращается Неопределено; // если нет прав для работы с таблицей, то возникнет исключение; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Произвольный - если в параметр Ссылка передана пустая ссылка, то возвращается Неопределено. // Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка), // то возвращается Неопределено. // Функция ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ПустаяСтрока(ИмяРеквизита) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: |Имя реквизита должно быть заполнено.'"), "ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъекта"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; Результат = ЗначенияРеквизитовОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка); Возврат Результат[СтрЗаменить(ИмяРеквизита, ".", "")]; КонецФункции // Возвращает значения реквизитов, прочитанные из информационной базы для нескольких объектов. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // Ссылки - Массив из ЛюбаяСсылка // - ФиксированныйМассив из ЛюбаяСсылка - ссылки на объекты. // Если массив пуст, то результатом будет пустое соответствие. // Реквизиты - Строка - имена реквизитов перечисленные через запятую, в формате требований к свойствам // структуры. Например, "Код, Наименование, Родитель". // - Массив из Строка // - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя; // если какой-либо объект будет исключен из выборки по правам, то этот объект // будет исключен и из результата; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Соответствие из КлючИЗначение - список объектов и значений их реквизитов: // * Ключ - ЛюбаяСсылка - ссылка на объект; // * Значение - Структура: // ** Ключ - Строка - имя реквизита; // ** Значение - Произвольный - значение реквизита. // Функция ЗначенияРеквизитовОбъектов(Ссылки, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ТипЗнч(Реквизиты) = Тип("Массив") Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда Реквизиты = СтрСоединить(Реквизиты, ","); КонецЕсли; Если ПустаяСтрока(Реквизиты) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: |Поле объекта должно быть указано.'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; Если СтрНайти(Реквизиты, ".") <> 0 Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: |Обращение через точку не поддерживается.'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ЗначенияРеквизитов = Новый Соответствие; Если Ссылки.Количество() = 0 Тогда Возврат ЗначенияРеквизитов; КонецЕсли; Если ЗначениеЗаполнено(КодЯзыка) Тогда КодЯзыка = СтрРазделить(КодЯзыка, "_", Истина)[0]; КонецЕсли; РеквизитыТекстЗапроса = Реквизиты; Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Если ЗначениеЗаполнено(КодЯзыка) Тогда СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылки[0]); НаборРеквизитов = СтрРазделить(Реквизиты, ","); Для Позиция = 0 По НаборРеквизитов.ВГраница() Цикл ИмяРеквизита = СокрЛП(НаборРеквизитов[Позиция]); Если МультиязычныеРеквизиты[ИмяРеквизита] = Ложь Тогда ИмяССуффиксом = ИмяРеквизита + СуффиксЯзыка; НаборРеквизитов[Позиция] = ИмяССуффиксом + " КАК " + ИмяРеквизита; КонецЕсли; КонецЦикла; РеквизитыТекстЗапроса = СтрСоединить(НаборРеквизитов, ","); КонецЕсли; КонецЕсли; КонецЕсли; СсылкиПоТипам = Новый Соответствие; Для Каждого Ссылка Из Ссылки Цикл Тип = ТипЗнч(Ссылка); Если СсылкиПоТипам[Тип] = Неопределено Тогда СсылкиПоТипам[Тип] = Новый Массив; КонецЕсли; ЭлементПоТипу = СсылкиПоТипам[Тип]; // Массив ЭлементПоТипу.Добавить(Ссылка); КонецЦикла; ТекстыЗапросов = Новый Массив; ПараметрыЗапроса = Новый Структура; ИменаОбъектовМетаданных = Новый Массив; Для Каждого СсылкиПоТипу Из СсылкиПоТипам Цикл Тип = СсылкиПоТипу.Ключ; ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); Если ОбъектМетаданных = Неопределено Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный первый параметр %1 в функции %2: |Значения массива должны быть ссылками.'"), "Ссылки", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ПолноеИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя(); ИменаОбъектовМетаданных.Добавить(ПолноеИмяОбъектаМетаданных); ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | Ссылка, | &Реквизиты |ИЗ | &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка В (&Ссылки)"; Если Не ВыбратьРазрешенные Или ТекстыЗапросов.Количество() > 0 Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Реквизиты", РеквизитыТекстЗапроса); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных); ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", ""); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); // @Query-part-1 ПараметрыЗапроса.Вставить(ИмяПараметра, СсылкиПоТипу.Значение); Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Если ЗначениеЗаполнено(КодЯзыка) И КодЯзыка <> КодОсновногоЯзыка() И МодульМультиязычностьСервер.ОбъектСодержитТЧПредставления(ПолноеИмяОбъектаМетаданных) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(ОбъектМетаданных); ПоляТаблиц = Новый Массив; ПоляТаблиц.Добавить("ПсевдонимЗаданнойТаблицы.Ссылка"); Для Каждого Реквизит Из СтрРазделить(Реквизиты, ",") Цикл Если МультиязычныеРеквизиты[Реквизит] <> Неопределено Тогда Если МультиязычныеРеквизиты[Реквизит] = Истина Тогда ПолеРеквизита = "ЕСТЬNULL(ТаблицаПредставления." + Реквизит + ", """")"; Иначе СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); ПолеРеквизита = ?(ЗначениеЗаполнено(СуффиксЯзыка), Реквизит + СуффиксЯзыка, Реквизит); КонецЕсли; ПоляТаблиц.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 КАК %2", ПолеРеквизита, Реквизит)); Иначе ПоляТаблиц.Добавить(Реквизит); КонецЕсли; КонецЦикла; ПоляТаблиц = СтрСоединить(ПоляТаблиц, "," + Символы.ПС); Таблицы = ПолноеИмяОбъектаМетаданных + " " + "КАК ПсевдонимЗаданнойТаблицы" + Символы.ПС + "ЛЕВОЕ СОЕДИНЕНИЕ" + " " + ПолноеИмяОбъектаМетаданных + ".Представления КАК ТаблицаПредставления" + Символы.ПС + "ПО ТаблицаПредставления.Ссылка = ПсевдонимЗаданнойТаблицы.Ссылка И ТаблицаПредставления.КодЯзыка = &КодЯзыка"; ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", ""); Условия = "ПсевдонимЗаданнойТаблицы.Ссылка В (&" + ИмяПараметра + ")"; СтрокиЗапроса = Новый Массив; СтрокиЗапроса.Добавить("ВЫБРАТЬ" + ?(ВыбратьРазрешенные И Не ЗначениеЗаполнено(ТекстыЗапросов), " " + "РАЗРЕШЕННЫЕ", "")); // @Query-part-1, @Query-part-3 СтрокиЗапроса.Добавить(ПоляТаблиц); СтрокиЗапроса.Добавить("ИЗ"); // @Query-part-1 СтрокиЗапроса.Добавить(Таблицы); СтрокиЗапроса.Добавить("ГДЕ"); // @Query-part-1 СтрокиЗапроса.Добавить(Условия); ТекстЗапроса = СтрСоединить(СтрокиЗапроса, Символы.ПС); КонецЕсли; КонецЕсли; ТекстыЗапросов.Добавить(ТекстЗапроса); КонецЦикла; ТекстЗапроса = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("КодЯзыка", КодЯзыка); Для Каждого Параметр Из ПараметрыЗапроса Цикл Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение); КонецЦикла; Попытка Выборка = Запрос.Выполнить().Выбрать(); Исключение // Удаление пробелов. Реквизиты = СтрЗаменить(Реквизиты, " ", ""); // Преобразование параметра в массив полей. Реквизиты = СтрРазделить(Реквизиты, ","); // Поиск ошибки доступности полей. СписокОшибок = Новый Массив; Для Каждого ПолноеИмяОбъектаМетаданных Из ИменаОбъектовМетаданных Цикл Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда СписокОшибок.Добавить(Результат.ОписаниеОшибки); КонецЕсли; КонецЦикла; Если ЗначениеЗаполнено(СписокОшибок) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов", СтрСоединить(СписокОшибок, Символы.ПС)), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ВызватьИсключение; КонецПопытки; Пока Выборка.Следующий() Цикл Результат = Новый Структура(Реквизиты); ЗаполнитьЗначенияСвойств(Результат, Выборка); ЗначенияРеквизитов[Выборка.Ссылка] = Результат; КонецЦикла; Возврат ЗначенияРеквизитов; КонецФункции // Возвращает значения реквизита, прочитанного из информационной базы для нескольких объектов. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // МассивСсылок - Массив из ЛюбаяСсылка // - ФиксированныйМассив из ЛюбаяСсылка // ИмяРеквизита - Строка - например, "Код". // ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя; // если какой-либо объект будет исключен из выборки по правам, то этот объект // будет исключен и из результата; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка - ссылка на объект, // * Значение - Произвольный - значение прочитанного реквизита. // Функция ЗначениеРеквизитаОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ПустаяСтрока(ИмяРеквизита) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверный второй параметр %1 в функции %2: |Имя реквизита должно быть заполнено.'"), "ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъектов"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ЗначенияРеквизитов = ЗначенияРеквизитовОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка); Для каждого Элемент Из ЗначенияРеквизитов Цикл ЗначенияРеквизитов[Элемент.Ключ] = Элемент.Значение[ИмяРеквизита]; КонецЦикла; Возврат ЗначенияРеквизитов; КонецФункции // Добавляет или изменяет значение реквизита в объекте. // // Если передано имя несуществующего реквизита, то вызывается исключение. // // Параметры: // Объект - СправочникОбъект // - ДокументОбъект // - ПланВидовХарактеристикОбъект // - РегистрСведенийЗапись - заполняемый объект. // ИмяРеквизита - Строка - имя заполняемого реквизита. Например, "Комментарий" // Значение - Строка - значение помещаемое в реквизит. // КодЯзыка - Строка - код языка реквизита. Например, "ru". // Процедура УстановитьЗначениеРеквизита(Объект, ИмяРеквизита, Значение, КодЯзыка = Неопределено) Экспорт УстановитьЗначенияРеквизитов(Объект, Новый Структура(ИмяРеквизита, Значение), КодЯзыка); КонецПроцедуры // Добавляет или изменяет значения реквизитов в объекте. // // Если передано имя несуществующего реквизита, то вызывается исключение. // // Параметры: // Объект - СправочникОбъект // - ДокументОбъект // - ПланВидовХарактеристикОбъект // - РегистрСведенийЗапись - заполняемый объект. // Значения - Структура - где ключ это имя реквизита, а значение содержит строку помещаемую в реквизит. // КодЯзыка - Строка - код языка реквизита. Например, "ru". // Процедура УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка = Неопределено) Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); МодульМультиязычностьСервер.УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка); Возврат; КонецЕсли; Для Каждого ЗначениеРеквизита Из Значения Цикл Значение = ЗначениеРеквизита.Значение; Если ТипЗнч(Значение) = Тип("Строка") И СтрокаВВидеНСтр(Значение) Тогда Значение = НСтр(ЗначениеРеквизита.Значение); КонецЕсли; Объект[ЗначениеРеквизита.Ключ] = Значение; КонецЦикла; КонецПроцедуры // Возвращает код основного языка информационной базы, например "ru". // На котором программно записываются автогенерируемые строки в информационную базу. // Например, при начальном заполнении информационной базы данными из макета, автогенерации комментария // к проводке или определении значения параметра ИмяСобытия метода ЗаписьЖурналаРегистрации. // // Возвращаемое значение: // Строка // Функция КодОсновногоЯзыка() Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Возврат МодульМультиязычностьСервер.КодОсновногоЯзыка(); КонецЕсли; Возврат Метаданные.ОсновнойЯзык.КодЯзыка; КонецФункции // Возвращает признак того, что для пользователя установлен язык интерфейса // соответствующий основному языку информационной базы. // // Возвращаемое значение: // Булево // Функция ЭтоОсновнойЯзык() Экспорт Возврат СтрСравнить(КодОсновногоЯзыка(), ТекущийЯзык().КодЯзыка) = 0; КонецФункции // Возвращает ссылку предопределенного элемента по его полному имени в следующих объектах: // - справочники; // - планы видов характеристик; // - планы счетов; // - планы видов расчета. // См. также функцию ОбщегоНазначенияКлиент.ПредопределенныйЭлемент. // // Для корректной работы этой функции после изменения состава предопределенных следует вызывать // метод ОбновитьПовторноИспользуемыеЗначения. // // Параметры: // ПолноеИмяПредопределенного - Строка - полное имя предопределенного элемента. // Формат аналогичен функции глобального контекста ПредопределенноеЗначение, например: // "Справочник.ВидыКонтактнойИнформации.EmailПользователя" // "ПланСчетов.Хозрасчетный.Материалы" // "ПланВидовРасчета.Начисления.ОплатаПоОкладу". // // Возвращаемое значение: // - ЛюбаяСсылка - ссылка на предопределенный элемент. // - Неопределено - если предопределенного элемента нет в метаданных или не создан в информационной базе. // Функция ПредопределенныйЭлемент(ПолноеИмяПредопределенного) Экспорт СтандартнаяОбработка = ОбщегоНазначенияСлужебныйКлиентСервер.ИспользоватьСтандартнуюФункциюПолученияПредопределенного( ПолноеИмяПредопределенного); Если СтандартнаяОбработка Тогда Возврат ПредопределенноеЗначение(ПолноеИмяПредопределенного); КонецЕсли; ПоляПредопределенного = ОбщегоНазначенияСлужебныйКлиентСервер.ИмяПредопределенногоПоПолям(ПолноеИмяПредопределенного); ПредопределенныеЗначения = СтандартныеПодсистемыПовтИсп.СсылкиПоИменамПредопределенных( ПоляПредопределенного.ПолноеИмяОбъектаМетаданных); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредопределенныйЭлемент( ПолноеИмяПредопределенного, ПоляПредопределенного, ПредопределенныеЗначения); КонецФункции // Возвращает информацию о том, являются ли переданные элементы предопределенными. // Если нет прав доступа на уровне записей, то элемент не включается в результат. // Если нет прав доступа к таблице, то вызывается исключение. // // Параметры: // Элементы - Массив из ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение - список объектов и значений их реквизитов: // * Ключ - ЛюбаяСсылка - ссылка на объект. // * Значение - Булево - Истина, если это ссылка на предопределенный элемент. // Функция ЭтоПредопределенныеЭлементы(Знач Элементы) Экспорт ИменаРеквизитов = Новый Массив; Для каждого ИмяРеквизита Из СтандартныеПодсистемыСервер.РеквизитыПредопределенныхДанных() Цикл ИменаРеквизитов.Добавить(ИмяРеквизита.Ключ); КонецЦикла; ЗначенияРеквизитов = СтандартныеПодсистемыСервер.ЗначенияРеквизитовОбъектовЕслиСуществуют(Элементы, ИменаРеквизитов); Результат = Новый Соответствие; Для каждого Элемент Из ЗначенияРеквизитов Цикл ЭтоПредопределенныйЭлемент = Ложь; Для каждого Значение Из Элемент.Значение Цикл Если ЗначениеЗаполнено(Значение.Значение) Тогда ЭтоПредопределенныйЭлемент = Истина; КонецЕсли; КонецЦикла; Результат[Элемент.Ключ] = ЭтоПредопределенныйЭлемент; КонецЦикла; Возврат Результат; КонецФункции // Проверяет статус проведения переданных документов и возвращает // те из них, которые не проведены. // // Параметры: // Документы - Массив из ДокументСсылка - документы, статус проведения которых необходимо проверить. // // Возвращаемое значение: // Массив из ДокументСсылка - непроведенные документы. // Функция ПроверитьПроведенностьДокументов(Знач Документы) Экспорт Результат = Новый Массив; ШаблонЗапроса = "ВЫБРАТЬ | ПсевдонимЗаданнойТаблицы.Ссылка КАК Ссылка |ИЗ | &ИмяДокумента КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка В(&МассивДокументов) | И НЕ ПсевдонимЗаданнойТаблицы.Проведен"; ТекстОбъединитьВсе = ТекстОбъединитьВсе(); ИменаДокументов = Новый Массив; Для Каждого Документ Из Документы Цикл МетаданныеДокумента = Документ.Метаданные(); Если ИменаДокументов.Найти(МетаданныеДокумента.ПолноеИмя()) = Неопределено И Метаданные.Документы.Содержит(МетаданныеДокумента) И МетаданныеДокумента.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда ИменаДокументов.Добавить(МетаданныеДокумента.ПолноеИмя()); КонецЕсли; КонецЦикла; ТекстЗапроса = ""; Для Каждого ИмяДокумента Из ИменаДокументов Цикл Если Не ПустаяСтрока(ТекстЗапроса) Тогда ТекстЗапроса = ТекстЗапроса + ТекстОбъединитьВсе; КонецЕсли; ТекстПодзапроса = СтрЗаменить(ШаблонЗапроса, "&ИмяДокумента", ИмяДокумента); ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса; КонецЦикла; Запрос = Новый Запрос; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("МассивДокументов", Документы); Если Не ПустаяСтрока(ТекстЗапроса) Тогда Результат = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); КонецЕсли; Возврат Результат; КонецФункции // Выполняет попытку проведения документов и возвращает информацию о документах, которые не удалось провести. // // Параметры: // Документы - Массив из ДокументСсылка - документы, которые необходимо провести. // // Возвращаемое значение: // Массив из Структура: // * Ссылка - ДокументСсылка - документ, который не удалось провести, // * ОписаниеОшибки - Строка - текст описания ошибки при проведении. // Функция ПровестиДокументы(Документы) Экспорт НепроведенныеДокументы = Новый Массив; Для Каждого ДокументСсылка Из Документы Цикл ВыполненоУспешно = Ложь; ПредставлениеОшибки = ""; Блокировка = Новый БлокировкаДанных(); ЭлементБлокировки = Блокировка.Добавить(ДокументСсылка.Метаданные().ПолноеИмя()); ЭлементБлокировки.УстановитьЗначение("Ссылка", ДокументСсылка); НачатьТранзакцию(); Попытка Блокировка.Заблокировать(); ДокументОбъект = ДокументСсылка.ПолучитьОбъект(); Если ДокументОбъект.ПроверитьЗаполнение() Тогда РежимПроведения = РежимПроведенияДокумента.Неоперативный; Если ДокументОбъект.Дата >= НачалоДня(ТекущаяДатаСеанса()) И ДокументСсылка.Метаданные().ОперативноеПроведение = Метаданные.СвойстваОбъектов.ОперативноеПроведение.Разрешить Тогда РежимПроведения = РежимПроведенияДокумента.Оперативный; КонецЕсли; ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведения); ВыполненоУспешно = Истина; Иначе ПредставлениеОшибки = НСтр("ru = 'Поля документа не заполнены.'"); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); КонецПопытки; Если Не ВыполненоУспешно Тогда НепроведенныеДокументы.Добавить(Новый Структура("Ссылка,ОписаниеОшибки", ДокументСсылка, ПредставлениеОшибки)); КонецЕсли; КонецЦикла; Возврат НепроведенныеДокументы; КонецФункции // Проверяет наличие ссылок на объект в базе данных. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // // Параметры: // СсылкаИлиМассивСсылок - ЛюбаяСсылка // - Массив из ЛюбаяСсылка - объект или список объектов. // ИскатьСредиСлужебныхОбъектов - Булево - если Истина, то не будут учитываться // исключения поиска ссылок, заданные при разработке конфигурации. // Про исключение поиска ссылок см. подробнее // ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. // // Возвращаемое значение: // Булево - Истина, если есть ссылки на объект. // Функция ЕстьСсылкиНаОбъект(Знач СсылкаИлиМассивСсылок, Знач ИскатьСредиСлужебныхОбъектов = Ложь) Экспорт Если ТипЗнч(СсылкаИлиМассивСсылок) = Тип("Массив") Тогда МассивСсылок = СсылкаИлиМассивСсылок; Иначе МассивСсылок = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаИлиМассивСсылок); КонецЕсли; УстановитьПривилегированныйРежим(Истина); МестаИспользования = НайтиПоСсылкам(МассивСсылок); УстановитьПривилегированныйРежим(Ложь); Если Не ИскатьСредиСлужебныхОбъектов Тогда Для каждого Элемент Из СлужебныеСвязиДанных(МестаИспользования) Цикл МестаИспользования.Удалить(Элемент.Ключ); КонецЦикла; КонецЕсли; Возврат МестаИспользования.Количество() > 0; КонецФункции // Определяет, указаны ли места использования в исключениях поиска ссылок. // // Параметры: // МестаИспользования - ТаблицаЗначений - результат функции НайтиПоСсылкам: // * Ссылка - ЛюбаяСсылка - проверяемая ссылка. // * Данные - ЛюбаяСсылка - место использования. // * Метаданные - ОбъектМетаданных - метаданные места использования. // ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - СтрокаТаблицыЗначений // * Значение - Булево - всегда Истина. Если это не служебная связь данных, то в соответствии нет элемента. // Функция СлужебныеСвязиДанных(Знач МестаИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт Если ИсключенияПоискаСсылок = Неопределено Тогда ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); КонецЕсли; Результат = Новый Соответствие; МестоИспользованияПоМетаданным = Новый Соответствие; Для каждого МестоИспользования Из МестаИспользования Цикл ИсключениеПоиска = ИсключенияПоискаСсылок[МестоИспользования.Метаданные]; // Данные могут быть как ссылкой, так и ключом записи регистра. Если ИсключениеПоиска = Неопределено Тогда Если МестоИспользования.Ссылка = МестоИспользования.Данные Тогда Результат[МестоИспользования] = Истина; // Ссылку саму на себя исключаем. КонецЕсли; Продолжить; ИначеЕсли ИсключениеПоиска = "*" Тогда Результат[МестоИспользования] = Истина; // Если указано исключить все - считаем все исключением. Продолжить; КонецЕсли; ЭтоСсылка = ЭтоСсылка(ТипЗнч(МестоИспользования.Данные)); Если Не ЭтоСсылка Тогда Для Каждого ПутьКРеквизиту Из ИсключениеПоиска Цикл ЗначениеРеквизита = Новый Структура(ПутьКРеквизиту); ЗаполнитьЗначенияСвойств(ЗначениеРеквизита, МестоИспользования.Данные); Если ЗначениеРеквизита[ПутьКРеквизиту] = МестоИспользования.Ссылка Тогда Результат[МестоИспользования] = Истина; Прервать; КонецЕсли; КонецЦикла; Продолжить; КонецЕсли; Если ИсключениеПоиска.Количество() = 0 Тогда Продолжить; КонецЕсли; ИмяТаблицы = МестоИспользования.Метаданные.ПолноеИмя(); Значение = МестоИспользованияПоМетаданным[ИмяТаблицы]; Если Значение = Неопределено Тогда Значение = Новый ТаблицаЗначений; Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Метаданные"); МестоИспользованияПоМетаданным[ИмяТаблицы] = Значение; КонецЕсли; ЗаполнитьЗначенияСвойств(Значение.Добавить(), МестоИспользования); КонецЦикла; Индекс = 1; Запрос = Новый Запрос; ТекстыЗапроса = Новый Массив; ВременныеТаблицы = Новый Массив; Для каждого МестоИспользования Из МестоИспользованияПоМетаданным Цикл ИмяТаблицы = МестоИспользования.Ключ; // Строка МестоИспользования = МестоИспользования.Значение; // ТаблицаЗначений // Проверка, есть ли по исключаемому пути в указанных данных проверяемая ссылка. Если МестоИспользования.Количество() > 1 Тогда ШаблонЗапроса = "ВЫБРАТЬ | Ссылки.Данные КАК Ссылка, | Ссылки.Ссылка КАК ПроверяемаяСсылка |ПОМЕСТИТЬ ВТТаблицаСсылок |ИЗ | &Ссылки КАК Ссылки |; | |ВЫБРАТЬ | ТаблицаСсылок.Ссылка КАК Ссылка, | ТаблицаСсылок.ПроверяемаяСсылка КАК ПроверяемаяСсылка |ИЗ | ВТТаблицаСсылок КАК ТаблицаСсылок | ЛЕВОЕ СОЕДИНЕНИЕ #ПолноеИмяОбъектаМетаданных КАК Таблица | ПО ТаблицаСсылок.Ссылка = Таблица.Ссылка |ГДЕ | &Условие"; ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВТТаблицаСсылок", "ВТТаблицаСсылок" + Формат(Индекс, "ЧГ=;ЧН=")); ИмяПараметра = "Ссылки" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования); ЧастиЗапроса = СтрРазделить(ТекстЗапроса, ";"); ВременныеТаблицы.Добавить(ЧастиЗапроса[0]); ТекстЗапроса = ЧастиЗапроса[1]; Иначе ШаблонЗапроса = "ВЫБРАТЬ | &СсылкаНаВладельца КАК Ссылка, | &ПроверяемаяСсылка КАК ПроверяемаяСсылка |ИЗ | #ПолноеИмяОбъектаМетаданных КАК Таблица |ГДЕ | Таблица.Ссылка = &СсылкаНаВладельца | И (&Условие)"; ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы); ИмяПараметра = "СсылкаНаВладельца" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СсылкаНаВладельца", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Данные); ИмяПараметра = "ПроверяемаяСсылка" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверяемаяСсылка", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Ссылка); КонецЕсли; ТекстУсловия = Новый Массив; // Относительный путь к реквизиту: "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]". Для Каждого ПутьКРеквизиту Из ИсключенияПоискаСсылок[МестоИспользования[0].Метаданные] Цикл ТекстУсловия.Добавить(ПутьКРеквизиту + " = " + ?(МестоИспользования.Количество() > 1, "ТаблицаСсылок.ПроверяемаяСсылка", "&" + ИмяПараметра)); КонецЦикла; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Условие", СтрСоединить(ТекстУсловия, " ИЛИ ")); ТекстыЗапроса.Добавить(ТекстЗапроса); Индекс = Индекс + 1; КонецЦикла; Если ТекстыЗапроса.Количество() = 0 Тогда Возврат Результат; КонецЕсли; Запрос.Текст = СтрСоединить(ВременныеТаблицы, ";" + Символы.ПС) + ?(ВременныеТаблицы.Количество() > 0, ";" + Символы.ПС, "") + СтрСоединить(ТекстыЗапроса, Символы.ПС + "ОБЪЕДИНИТЬ" + Символы.ПС); УстановитьПривилегированныйРежим(Истина); ВыборкаЗапроса = Запрос.Выполнить().Выбрать(); УстановитьПривилегированныйРежим(Ложь); МестаИспользования.Индексы.Добавить("Ссылка,Данные"); Пока ВыборкаЗапроса.Следующий() Цикл СлужебныеСвязиДанных = МестаИспользования.НайтиСтроки(Новый Структура("Ссылка,Данные", ВыборкаЗапроса.ПроверяемаяСсылка, ВыборкаЗапроса.Ссылка)); Для каждого СлужебнаяСвязьДанных Из СлужебныеСвязиДанных Цикл Результат[СлужебнаяСвязьДанных] = Истина; КонецЦикла; КонецЦикла; Возврат Результат; КонецФункции // Определяет, указано ли место использования в исключениях поиска ссылок. // // Параметры: // МестоИспользования - Структура: // * Ссылка - ЛюбаяСсылка - проверяемая ссылка. // * Данные - ЛюбаяСсылка - место использования. // * Метаданные - ОбъектМетаданных - метаданные места использования. // ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок // // Возвращаемое значение: // Булево // Функция ЭтоСлужебнаяСвязьДанных(Знач МестоИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт Если ИсключенияПоискаСсылок = Неопределено Тогда ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); КонецЕсли; Значение = Новый ТаблицаЗначений; Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Метаданные"); МестоИспользованияСтрока = Значение.Добавить(); ЗаполнитьЗначенияСвойств(МестоИспользованияСтрока, МестоИспользования); Результат = СлужебныеСвязиДанных(Значение, ИсключенияПоискаСсылок); Возврат Результат[МестоИспользованияСтрока] <> Неопределено; КонецФункции // Производит замену ссылок во всех данных. После замены неиспользуемые ссылки опционально удаляются. // Замена ссылок происходит с транзакциями по изменяемому объекту и его связям, не по анализируемой ссылке. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // Если описаны связи подчиненных и основных объектов (см. СвязиПодчиненныхОбъектов), то: // * при замене основных объектов будет выполнен поиск замен подчиненных объектов; // * если ВыполнятьАвтоматическийПоискЗамен = Истина, то будет выполнена попытка поиска замен для подчиненных объектов // по значениям полей связи. В случае, если объект не существует, будет выполнена процедура ПриПоискеЗаменыСсылок; // * если МетодПоиска в описании связей задан, то если автоматический поиск не нашел замен // или не выполнялся, будет вызван МетодПоиска для подбора замен. // // Параметры: // ПарыЗамен - Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка - что ищем (дубль). // * Значение - ЛюбаяСсылка - на что заменяем (оригинал). // Ссылки сами на себя и пустые ссылки для поиска будут проигнорированы. // // ПараметрыЗамены - см. ОбщегоНазначения.ПараметрыЗаменыСсылок // // Возвращаемое значение: // ТаблицаЗначений - неуспешные замены (ошибки): // * Ссылка - ЛюбаяСсылка - ссылка, которую заменяли. // * ДубльРодитель - ЛюбаяСсылка - ссылка на дубль для группировки ошибок подчиненных объектов. // Если нет связанных подчиненных, заполняется значением из колонки Ссылка. // * ОбъектОшибки - Произвольный - объект-причина ошибки. // * ПредставлениеОбъектаОшибки - Строка - строковое представление объекта ошибки. // * ТипОшибки - Строка - тип ошибки: // "ОшибкаБлокировки" - при замене в объекте данные были заблокированы другим сеансом. // "ДанныеИзменены" - в процессе замены данные были изменены другим пользователем. // "ОшибкаЗаписи" - не удалось записать объект, или метод ВозможностьЗаменыЭлементов вернул отказ. // "ОшибкаУдаления" - не удалось удалить объект. // "НеизвестныеДанные" - при обработке были найдены данные, которые не планировались к замене. // * ИнформацияОбОшибке - ИнформацияОбОшибке // * ТекстОшибки - Строка - если свойство ИнформацияОбОшибке содержит Неопределено, то описание причины. // Функция ЗаменитьСсылки(Знач ПарыЗамен, Знач ПараметрыЗамены = Неопределено) Экспорт Статистика = Новый Соответствие; ТипСтрока = Новый ОписаниеТипов("Строка"); ОшибкиЗамены = Новый ТаблицаЗначений; ОшибкиЗамены.Колонки.Добавить("Ссылка"); ОшибкиЗамены.Колонки.Добавить("ДубльРодитель"); ОшибкиЗамены.Колонки.Добавить("ОбъектОшибки"); ОшибкиЗамены.Колонки.Добавить("ПредставлениеОбъектаОшибки", ТипСтрока); ОшибкиЗамены.Колонки.Добавить("ТипОшибки", ТипСтрока); ОшибкиЗамены.Колонки.Добавить("ТекстОшибки", ТипСтрока); ОшибкиЗамены.Колонки.Добавить("ИнформацияОбОшибке"); ОшибкиЗамены.Индексы.Добавить("Ссылка"); ОшибкиЗамены.Индексы.Добавить("Ссылка, ОбъектОшибки, ТипОшибки"); Результат = РезультатЗаменыСсылок(ОшибкиЗамены); ПараметрыВыполнения = НовыйПараметрыВыполненияЗаменыСсылок(ПараметрыЗамены); ПараметрыПоискаМестИспользования = ПараметрыПоискаМестИспользования(); ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(ПараметрыПоискаМестИспользования.ДополнительныеИсключенияПоискаСсылок); ПараметрыВыполнения.Вставить("ПараметрыПоискаМестИспользования", ПараметрыПоискаМестИспользования); ПараметрыВыполнения.Вставить("ПодчиненныеКДублям", Новый Соответствие()); ИнтеграцияПодсистемБСП.ПередПоискомМестИспользования(ПарыЗамен, ПараметрыВыполнения); Если ПарыЗамен.Количество() = 0 Тогда Возврат Результат.Ошибки; КонецЕсли; Дубли = СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат); ТаблицаПоиска = МестаИспользования(Дубли,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования); // Для каждой ссылки объекта будем производить замены в порядке "Константа", "Объект", "Набор". // Одновременно пустая строка в этой колонке - флаг того, что эта замена не нужна или уже была произведена. ТаблицаПоиска.Колонки.Добавить("КлючЗамены", ТипСтрока); ТаблицаПоиска.Индексы.Добавить("Ссылка, КлючЗамены"); ТаблицаПоиска.Индексы.Добавить("Данные, КлючЗамены"); // Вспомогательные данные ТаблицаПоиска.Колонки.Добавить("ЦелеваяСсылка"); ТаблицаПоиска.Колонки.Добавить("Обработано", Новый ОписаниеТипов("Булево")); // Определяем порядок обработки и проверяем то, что можно обработать. ОшибкиРазметки = Новый Массив; ОбъектыСОшибками = Новый Массив; Количество = Дубли.Количество(); Для Номер = 1 По Количество Цикл ОбратныйИндекс = Количество - Номер; Дубль = Дубли[ОбратныйИндекс]; РезультатРазметки = РазметитьМестаИспользования(ПараметрыВыполнения, Дубль, ПарыЗамен[Дубль], ТаблицаПоиска); Если Не РезультатРазметки.Успех Тогда Дубли.Удалить(ОбратныйИндекс); Для Каждого Ошибка Из РезультатРазметки.ОшибкиРазметки Цикл Ошибка.Вставить("Дубль", Дубль); ОбъектыСОшибками.Добавить(Ошибка.Объект); КонецЦикла; ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОшибкиРазметки, РезультатРазметки.ОшибкиРазметки); КонецЕсли; КонецЦикла; Если ОшибкиРазметки.Количество() > 0 Тогда ПредставленияОбъектов = ПредметыСтрокой(ОбъектыСОшибками); Для Каждого Ошибка Из ОшибкиРазметки Цикл ЗарегистрироватьОшибкуЗамены( Результат, Ошибка.Дубль, ОписаниеОшибкиЗамены("НеизвестныеДанные", Ошибка.Объект, ПредставленияОбъектов[Ошибка.Объект], Ошибка.Текст), ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; КонецЕсли; // Замена и удаление найденных дублей. ПараметрыВыполнения.Вставить("ПарыЗамен", ПарыЗамен); ПараметрыВыполнения.Вставить("УспешныеЗамены", Новый Соответствие); ОтключитьОбновлениеКлючейДоступа(Истина); Попытка ТекстПрогресса = НСтр("ru = 'Замена дублей...'"); ДополнительныеПараметрыПрогресса = Новый Структура; ДополнительныеПараметрыПрогресса.Вставить("КоличествоОбработанных", 0); Для Каждого Дубль Из Дубли Цикл БылиОшибки = Результат.ЕстьОшибки; Результат.ЕстьОшибки = Ложь; // @skip-check query-in-loop - Порционная обработка большого объема данных. ЗаменитьСсылкиКороткимиТранзакциями(Результат, ПараметрыВыполнения, Дубль, ТаблицаПоиска); Если НЕ Результат.ЕстьОшибки Тогда ПараметрыВыполнения.УспешныеЗамены.Вставить(Дубль, ПараметрыВыполнения.ПарыЗамен[Дубль]); КонецЕсли; Результат.ЕстьОшибки = Результат.ЕстьОшибки ИЛИ БылиОшибки; ДополнительныеПараметрыПрогресса.КоличествоОбработанных = ДополнительныеПараметрыПрогресса.КоличествоОбработанных + 1; ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, Результат.ЕстьОшибки); Если ДополнительныеПараметрыПрогресса.КоличествоОбработанных >9 Тогда ДлительныеОперации.СообщитьПрогресс(ДополнительныеПараметрыПрогресса.КоличествоОбработанных, ТекстПрогресса, ДополнительныеПараметрыПрогресса); ДополнительныеПараметрыПрогресса.КоличествоОбработанных = 0; КонецЕсли; КонецЦикла; Если ДополнительныеПараметрыПрогресса.КоличествоОбработанных > 0 Тогда ДлительныеОперации.СообщитьПрогресс(ДополнительныеПараметрыПрогресса.КоличествоОбработанных, ТекстПрогресса, ДополнительныеПараметрыПрогресса); КонецЕсли; ОбщегоНазначенияПереопределяемый.ПослеЗаменыСсылок(Результат, ПараметрыВыполнения, ТаблицаПоиска); ОтключитьОбновлениеКлючейДоступа(Ложь); Исключение ОтключитьОбновлениеКлючейДоступа(Ложь); ВызватьИсключение; КонецПопытки; Если ПодсистемаСуществует("СтандартныеПодсистемы.УдалениеПомеченныхОбъектов") И ПараметрыВыполнения.УдалятьНепосредственно Тогда МодульУдалениеПомеченныхОбъектов = ОбщийМодуль("УдалениеПомеченныхОбъектов"); ДополнительныеПараметрыПрогресса = Новый Структура; ДлительныеОперации.СообщитьПрогресс(0, НСтр("ru = 'Удаление дублей...'"), ДополнительныеПараметрыПрогресса); РезультатУдаления = МодульУдалениеПомеченныхОбъектов.УдалитьПомеченныеОбъекты(Результат.ОчередьКНепосредственномуУдалению); ЗарегистрироватьОшибкиУдаления(Результат, РезультатУдаления.ПрепятствующиеУдалению, ПараметрыВыполнения); КонецЕсли; ОтправитьСтатистикуЗаменыСсылок(Статистика); Возврат Результат.Ошибки; КонецФункции // Конструктор структуры для параметра ПараметрыЗамены функции ОбщегоНазначения.ЗаменитьСсылки. // // Возвращаемое значение: // Структура: // * СпособУдаления - Строка - указывает, что делать с дублем после успешной замены: // "" - не предпринимать никаких действий (по умолчанию); // "Пометка" - помечать на удаление; // "Непосредственно" - удалять непосредственно. // * УчитыватьПрикладныеПравила - Булево - если Истина, то для каждой пары "дубль-оригинал" // вызывается функция ВозможностьЗаменыЭлементов модуля менеджера // (требуется подсистема "Поиск и удаление дублей"). По умолчанию, Ложь. // * ВключатьБизнесЛогику - Булево - режим записи объектов при замене в них ссылок дублей на оригиналы. // Если Истина (по умолчанию), то места использования дублей записываются в обычном режиме, // иначе запись ведется в режиме ОбменДанными.Загрузка = Истина. // * ЗаменаПарыВТранзакции - Булево - устарел. определяет размер транзакции при замене дублей. // Если Истина (по умолчанию), то все места использования одного дубля заменяются в одной транзакции. // Это может быть очень ресурсоемко в случае большого количества мест использований. // Если Ложь, то замена в каждом месте использования выполняется в отдельной транзакции. // * ПривилегированнаяЗапись - Булево - если Истина, то устанавливать привилегированный режим перед запись // объектов при замене в них ссылок дублей на оригиналы. По умолчанию Ложь. // Функция ПараметрыЗаменыСсылок() Экспорт Результат = Новый Структура; Результат.Вставить("СпособУдаления", ""); Результат.Вставить("УчитыватьПрикладныеПравила", Ложь); Результат.Вставить("ВключатьБизнесЛогику", Истина); Результат.Вставить("ЗаменаПарыВТранзакции", Ложь); Результат.Вставить("ПривилегированнаяЗапись", Ложь); Возврат Результат; КонецФункции // Получает все места использования ссылок. // Если какая-либо ссылка нигде не используется, то строк для нее в результирующей таблице не будет. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // // Параметры: // НаборСсылок - Массив из ЛюбаяСсылка - ссылки, для которых ищем места использования. // АдресРезультата - Строка - адрес во временном хранилище, куда будет помещен копия результата замены. // ДополнительныеПараметры - см. ОбщегоНазначения.ПараметрыПоискаМестИспользования // // Возвращаемое значение: // ТаблицаЗначений: // * Ссылка - ЛюбаяСсылка - ссылка, которая анализируется. // * Данные - Произвольный - данные, содержащие анализируемую ссылку. // * Метаданные - ОбъектМетаданных - метаданные найденных данных. // * ПредставлениеДанных - Строка - представление данных, содержащих анализируемую ссылку. // * ТипСсылки - Тип - тип анализируемой ссылки. // * ВспомогательныеДанные - Булево - Истина, если данные используются анализируемой ссылкой как // вспомогательные данные (ведущее измерение или попали в исключение ПриДобавленииИсключенийПоискаСсылок). // * ЭтоСлужебныеДанные - Булево - данные попали в исключение ПриДобавленииИсключенийПоискаСсылок // Функция МестаИспользования(Знач НаборСсылок, Знач АдресРезультата = "", ДополнительныеПараметры = Неопределено) Экспорт МестаИспользования = Новый ТаблицаЗначений; ИсключенияПоискаРегистровПодчиненныхРегистратору = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры( ДополнительныеПараметры, "ИсключенияПоискаРегистровПодчиненныхРегистратору", Неопределено); УстановитьПривилегированныйРежим(Истина); МестаИспользования = НайтиПоСсылкам(НаборСсылок, , , ИсключенияПоискаРегистровПодчиненныхРегистратору); // см. МестаИспользования. УстановитьПривилегированныйРежим(Ложь); // МестаИспользования - ТаблицаЗначений - где: // * Ссылка - ЛюбаяСсылка - Ссылка, которая анализируется. // * Данные - Произвольный - Данные, содержащие анализируемую ссылку. // * Метаданные - ОбъектМетаданных - Метаданные найденных данных. МестаИспользования.Колонки.Добавить("ПредставлениеДанных", Новый ОписаниеТипов("Строка")); МестаИспользования.Колонки.Добавить("ТипСсылки"); МестаИспользования.Колонки.Добавить("ИнформацияОМестеИспользования"); МестаИспользования.Колонки.Добавить("ВспомогательныеДанные", Новый ОписаниеТипов("Булево")); МестаИспользования.Колонки.Добавить("ЭтоСлужебныеДанные", Новый ОписаниеТипов("Булево")); МестаИспользования.Индексы.Добавить("Ссылка"); МестаИспользования.Индексы.Добавить("Данные"); МестаИспользования.Индексы.Добавить("ВспомогательныеДанные"); МестаИспользования.Индексы.Добавить("Ссылка, ВспомогательныеДанные"); ТипКлючиЗаписей = ОписаниеТипаКлючиЗаписей(); ТипВсеСсылки = ОписаниеТипаВсеСсылки(); МетаданныеПоследовательностей = Метаданные.Последовательности; МетаданныеКонстант = Метаданные.Константы; МетаданныеДокументов = Метаданные.Документы; ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); ДополнительныеИсключенияПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры( ДополнительныеПараметры, "ДополнительныеИсключенияПоискаСсылок", Новый Соответствие); Для каждого МетаданныеРеквизитыИсключения Из ДополнительныеИсключенияПоискаСсылок Цикл ЗначениеИсключения = ИсключенияПоискаСсылок[МетаданныеРеквизитыИсключения.Ключ]; Если ЗначениеИсключения = Неопределено Тогда ИсключенияПоискаСсылок.Вставить(МетаданныеРеквизитыИсключения.Ключ, МетаданныеРеквизитыИсключения.Значение); ИначеЕсли ТипЗнч(ЗначениеИсключения) = Тип("Массив") Тогда ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗначениеИсключения, МетаданныеРеквизитыИсключения.Значение); КонецЕсли; КонецЦикла; ОтменаИсключенийПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеПараметры, "ОтменаИсключенийПоискаСсылок", Новый Массив); Для каждого ОтменаИсключения Из ОтменаИсключенийПоискаСсылок Цикл ИсключенияПоискаСсылок.Удалить(ОтменаИсключения); КонецЦикла; СлужебныеСвязиДанных = СлужебныеСвязиДанных(МестаИспользования, ИсключенияПоискаСсылок); КэшИзмеренийРегистров = Новый Соответствие; Для Каждого МестоИспользования Из МестаИспользования Цикл ТипДанных = ТипЗнч(МестоИспользования.Данные); ЭтоСлужебныеДанные = СлужебныеСвязиДанных[МестоИспользования] <> Неопределено; ЭтоВспомогательныеДанные = ЭтоСлужебныеДанные; Если ТипДанных = Неопределено Или МетаданныеДокументов.Содержит(МестоИспользования.Метаданные) Тогда Представление = Строка(МестоИспользования.Данные); ИначеЕсли МетаданныеКонстант.Содержит(МестоИспользования.Метаданные) Тогда Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'константа'") + ")"; ИначеЕсли МетаданныеПоследовательностей.Содержит(МестоИспользования.Метаданные) Тогда Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'последовательность'") + ")"; ИначеЕсли ТипВсеСсылки.СодержитТип(ТипДанных) Тогда МетаПредставлениеОбъекта = Новый Структура("ПредставлениеОбъекта"); ЗаполнитьЗначенияСвойств(МетаПредставлениеОбъекта, МестоИспользования.Метаданные); Если ПустаяСтрока(МетаПредставлениеОбъекта.ПредставлениеОбъекта) Тогда МетаПредставление = МестоИспользования.Метаданные.Представление(); Иначе МетаПредставление = МетаПредставлениеОбъекта.ПредставлениеОбъекта; КонецЕсли; Представление = Строка(МестоИспользования.Данные); Если Не ПустаяСтрока(МетаПредставление) Тогда Представление = Представление + " (" + МетаПредставление + ")"; КонецЕсли; ИначеЕсли ТипКлючиЗаписей.СодержитТип(ТипДанных) Тогда Представление = МестоИспользования.Метаданные.ПредставлениеЗаписи; Если ПустаяСтрока(Представление) Тогда Представление = МестоИспользования.Метаданные.Представление(); КонецЕсли; ОписаниеИзмерений = Новый Массив; Для Каждого МетаданныеРеквизитыИсключения Из ОписаниеИзмеренийНабора(МестоИспользования.Метаданные, КэшИзмеренийРегистров) Цикл Значение = МестоИспользования.Данные[МетаданныеРеквизитыИсключения.Ключ]; Описание = МетаданныеРеквизитыИсключения.Значение; Если МестоИспользования.Ссылка = Значение Тогда Если Описание.Ведущее Тогда ЭтоВспомогательныеДанные = Истина; КонецЕсли; КонецЕсли; Если Не ЭтоСлужебныеДанные Тогда // для оптимизации ФорматЗначения = Описание.Формат; ОписаниеИзмерений.Добавить(Описание.Представление + " """ + ?(ФорматЗначения = Неопределено, Строка(Значение), Формат(Значение, ФорматЗначения)) + """"); КонецЕсли; КонецЦикла; Если ОписаниеИзмерений.Количество() > 0 Тогда Представление = Представление + " (" + СтрСоединить(ОписаниеИзмерений, ", ") + ")"; КонецЕсли; Иначе Представление = Строка(МестоИспользования.Данные); КонецЕсли; МестоИспользования.ПредставлениеДанных = Представление; МестоИспользования.ВспомогательныеДанные = ЭтоВспомогательныеДанные; МестоИспользования.ЭтоСлужебныеДанные = ЭтоСлужебныеДанные; МестоИспользования.ТипСсылки = ТипЗнч(МестоИспользования.Ссылка); КонецЦикла; Если Не ПустаяСтрока(АдресРезультата) Тогда ПоместитьВоВременноеХранилище(МестаИспользования, АдресРезультата); КонецЕсли; Возврат МестаИспользования; КонецФункции // Возвращает структуру для параметра ДополнительныеПараметры функции ОбщегоНазначения.МестаИспользования. // // Возвращаемое значение: // Структура: // * ДополнительныеИсключенияПоискаСсылок - Соответствие - позволяет расширить исключения поиска ссылок // см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. // * ОтменаИсключенийПоискаСсылок - Массив из ОбъектМетаданных - полностью отменяет исключения поиска ссылок для // объектов метаданных. // * ИсключенияПоискаРегистровПодчиненныхРегистратору - Массив из ОбъектМетаданных - если в см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок // указаны регистры подчиненные регистратору, то их необходимо добавить. // Функция ПараметрыПоискаМестИспользования() Экспорт ПараметрыПоиска = Новый Структура; ПараметрыПоиска.Вставить("ДополнительныеИсключенияПоискаСсылок", Новый Соответствие); ПараметрыПоиска.Вставить("ОтменаИсключенийПоискаСсылок", Новый Соответствие); ПараметрыПоиска.Вставить("ИсключенияПоискаРегистровПодчиненныхРегистратору", Новый Массив); Возврат ПараметрыПоиска; КонецФункции // Возвращает исключения при поиске мест использования объектов. // // Возвращаемое значение: // Соответствие из КлючИЗначение - исключения поиска ссылок в разрезе объектов метаданных: // * Ключ - ОбъектМетаданных - объект метаданных, для которого применяются исключения. // * Значение - Строка // - Массив из Строка - описание исключенных реквизитов. // Если "*", то исключены все реквизиты объекта метаданных. // Если массив строк, то содержит относительные имена исключенных реквизитов. // Функция ИсключенияПоискаСсылок() Экспорт ИсключенияПоискаИнтеграция = Новый Массив; ИнтеграцияПодсистемБСП.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаИнтеграция); ИсключенияПоиска = Новый Массив; ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИсключенияПоиска, ИсключенияПоискаИнтеграция); ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоиска); Результат = Новый Соответствие; Для Каждого ИсключениеПоиска Из ИсключенияПоиска Цикл // Определение полного имени реквизита и объекта метаданных - носителя реквизита. Если ТипЗнч(ИсключениеПоиска) = Тип("Строка") Тогда ПолноеИмя = ИсключениеПоиска; МассивПодстрок = СтрРазделить(ПолноеИмя, "."); КоличествоПодстрок = МассивПодстрок.Количество(); ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(МассивПодстрок[0] + "." + МассивПодстрок[1]); Иначе ОбъектМетаданных = ИсключениеПоиска; ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); МассивПодстрок = СтрРазделить(ПолноеИмя, "."); КоличествоПодстрок = МассивПодстрок.Количество(); Если КоличествоПодстрок > 2 Тогда Пока Истина Цикл Родитель = ОбъектМетаданных.Родитель(); Если ТипЗнч(Родитель) = Тип("ОбъектМетаданныхКонфигурация") Тогда Прервать; Иначе ОбъектМетаданных = Родитель; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; // Регистрация. Если КоличествоПодстрок < 4 Тогда Результат.Вставить(ОбъектМетаданных, "*"); Иначе ПутиКРеквизитам = Результат.Получить(ОбъектМетаданных); Если ПутиКРеквизитам = "*" Тогда Продолжить; // Весь объект метаданных уже исключен. ИначеЕсли ПутиКРеквизитам = Неопределено Тогда ПутиКРеквизитам = Новый Массив; Результат.Вставить(ОбъектМетаданных, ПутиКРеквизитам); КонецЕсли; // Формат реквизита: // "<ВидОМ>.<ИмяОМ>.<ТипРеквизитаИлиТЧ>.<ИмяРеквизитаИлиТЧ>[.<ТипРеквизита>.<ИмяРеквизитаТЧ>]". // Примеры: // "РегистрСведений.ВерсииОбъектов.Реквизит.АвторВерсии", // "Документ.ЗаказПокупателя.ТабличнаяЧасть.СчетаНаОплату.Реквизит.Счет", // "ПланВидовРасчета.ОсновныеНачисления.СтандартнаяТабличнаяЧасть.БазовыеВидыРасчета.СтандартныйРеквизит.ВидРасчета". // Относительный путь к реквизиту должен получиться таким, чтобы его можно было использовать в условиях запроса: // "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]". Если КоличествоПодстрок = 4 Тогда ОтносительныйПутьКРеквизиту = МассивПодстрок[3]; Иначе ОтносительныйПутьКРеквизиту = МассивПодстрок[3] + "." + МассивПодстрок[5]; КонецЕсли; ПутиКРеквизитам.Добавить(ОтносительныйПутьКРеквизиту); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает связи подчиненных объектов и перечень реквизитов, по которым осуществляется связь. // // Есть возможность переопределить процедуру поиска подчиненных объектов. // Для этого в общем модуле или модуле менеджера необходимо реализовать процедуру // ПриПоискеЗаменыСсылок с параметрами: // ПарыЗамен - Соответствие - содержит пары значение оригинал/дубль. // НеобработанныеЗначенияОригиналов - Массив из Структура - дополнительная информация об обрабатываемых объектах: // * ЗаменяемоеЗначение - ПроизвольнаяСсылка - оригинальное значение заменяемого объекта. // * ИспользуемыеСвязи - см. ОбщегоНазначения.СвязиПодчиненныхОбъектовПоТипам // * ЗначениеКлючевыхРеквизитов - Структура - где Ключ - имя реквизита, значение - значение реквизита. // // Возвращаемое значение: // ТаблицаЗначений: // * ПодчиненныйОбъект - ОбъектМетаданных - объект метаданных подчиненного объекта. // * ПоляСвязей - Строка - имена реквизитов, определяющих связь между основными и подчиненными объектами. // * ПриПоискеЗаменыСсылок - Строка - опционально. Имя общего модуля или модуля менеджера, в котором определена // процедура ПриПоискеЗаменыСсылок. // * ВыполнятьАвтоматическийПоискЗаменСсылок - Булево - если указать Истина, то будет выполнена попытка поиска замен // для подчиненных объектов по значениям полей связи. В случае, если объект не существует, // будет выполнена процедура ПриПоискеЗаменыСсылок. См. также ЗаменитьСсылки. // Функция ПодчиненныеОбъекты() Экспорт ОписаниеСвязей = Новый ТаблицаЗначений; ОписаниеСвязей.Колонки.Добавить("ПодчиненныйОбъект", Новый ОписаниеТипов("ОбъектМетаданных")); ОписаниеСвязей.Колонки.Добавить("ПоляСвязей"); ОписаниеСвязей.Колонки.Добавить("ПриПоискеЗаменыСсылок", ОписаниеТипаСтрока(0)); ОписаниеСвязей.Колонки.Добавить("ВыполнятьАвтоматическийПоискЗаменСсылок", Новый ОписаниеТипов("Булево")); ИнтеграцияПодсистемБСП.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей); ОбщегоНазначенияПереопределяемый.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей); // Если передали соответствие или структуру преобразуем к необходимому типу. Для каждого СтрокаСвязи Из ОписаниеСвязей Цикл ТипОписанияПолейСвязи = ТипЗнч(СтрокаСвязи.ПоляСвязей); Если ТипОписанияПолейСвязи = Тип("Структура") ИЛИ ТипОписанияПолейСвязи = Тип("Соответствие") Тогда ПоляСвязейСтрокой = ""; Для каждого КлючЗначение Из СтрокаСвязи.ПоляСвязей Цикл ПоляСвязейСтрокой = ПоляСвязейСтрокой + КлючЗначение.Ключ + ","; КонецЦикла; СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПоляСвязейСтрокой,1); СтрокаСвязи.ПоляСвязей = ПоляСвязейСтрокой; КонецЕсли; Если ТипОписанияПолейСвязи = Тип("Массив") Тогда СтрокаСвязи.ПоляСвязей = СтрСоединить(СтрокаСвязи.ПоляСвязей, ","); КонецЕсли; КонецЦикла; Возврат ОписаниеСвязей; КонецФункции // Возвращает связи подчиненных объектов с указанием типа поля связи. // // Возвращаемое значение: // ТаблицаЗначений: // * Ключ - Строка // * ТипРеквизита - Тип // * ИмяРеквизита - Строка // * Используется - Булево // * Метаданные - ОбъектМетаданных // Функция СвязиПодчиненныхОбъектовПоТипам() Экспорт Результат = Новый ТаблицаЗначений; Результат.Колонки.Добавить("ТипРеквизита", Новый ОписаниеТипов("Тип")); Результат.Колонки.Добавить("ИмяРеквизита", ОписаниеТипаСтрока(0)); Результат.Колонки.Добавить("Ключ", ОписаниеТипаСтрока(0)); Результат.Колонки.Добавить("Используется", Новый ОписаниеТипов("Булево")); Результат.Колонки.Добавить("Метаданные"); Возврат Результат; КонецФункции #КонецОбласти #Область УсловныеВызовы //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для вызова необязательных подсистем. // Возвращает Истина, если функциональная подсистема существует в конфигурации. // Предназначена для вызова необязательной подсистемы (условного вызова) совместно с ОбщегоНазначения.ОбщийМодуль. // // У функциональной подсистемы снят флажок "Включать в командный интерфейс". // См. также ОбщегоНазначенияПереопределяемый.ПриОпределенииОтключенныхПодсистем // и ОбщегоНазначенияКлиент.ПодсистемаСуществует для вызова из клиентского кода. // // Параметры: // ПолноеИмяПодсистемы - Строка - полное имя объекта метаданных подсистема // без слов "Подсистема." и с учетом регистра символов. // Например: "СтандартныеПодсистемы.ВариантыОтчетов". // // Пример: // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда // МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов"); // МодульВариантыОтчетов.<Имя процедуры>(); // КонецЕсли; // // Возвращаемое значение: // Булево // Функция ПодсистемаСуществует(ПолноеИмяПодсистемы) Экспорт ИменаПодсистем = СтандартныеПодсистемыПовтИсп.ИменаПодсистем(); Возврат ИменаПодсистем.Получить(ПолноеИмяПодсистемы) <> Неопределено; КонецФункции // Возвращает ссылку на общий модуль или модуль менеджера по имени. // Применяется для условного вызова процедуры или функции совместно с ОбщегоНазначения.ПодсистемаСуществует. // См. также ОбщегоНазначенияКлиент.ОбщийМодуль для вызова клиентского кода. // // Параметры: // Имя - Строка - имя общего модуля или модуля менеджера, например "ОбновлениеКонфигурации", // "Обработки.ПолнотекстовыйПоиск". // // Возвращаемое значение: // - ОбщийМодуль // - ПланОбменаМенеджер // - КритерийОтбораМенеджер // - ХранилищеНастроекМенеджер // - КонстантаМенеджер // - СправочникМенеджер // - ДокументМенеджер // - ЖурналДокументовМенеджер // - ПеречислениеМенеджер // - ОтчетМенеджер // - ОбработкаМенеджер // - ПланВидовХарактеристикМенеджер // - ПланСчетовМенеджер // - ПланВидовРасчетаМенеджер // - РегистрСведенийМенеджер // - РегистрНакопленияМенеджер // - РегистрБухгалтерииМенеджер // - РегистрРасчетаМенеджер // - БизнесПроцессМенеджер // - ЗадачаМенеджер // - ВнешнийИсточникДанныхТаблицаМенеджер // - ВнешнийИсточникДанныхКубМенеджер // - ВнешнийИсточникДанныхКубТаблицаИзмеренияМенеджер // // Пример: // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда // МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации"); // МодульОбновлениеКонфигурации.<Имя процедуры>(); // КонецЕсли; // // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолнотекстовыйПоиск") Тогда // МодульОбработкаПолнотекстовыйПоиск = ОбщегоНазначения.ОбщийМодуль("Обработки.ПолнотекстовыйПоиск"); // МодульОбработкаПолнотекстовыйПоиск.<Имя процедуры>(); // КонецЕсли; // Функция ОбщийМодуль(Имя) Экспорт Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда // АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно. УстановитьБезопасныйРежим(Истина); Модуль = Вычислить(Имя); // Не нарушает безопасность информации, так как вычисляется ссылка на общий модуль по проверенному имени. // АПК:488-вкл ИначеЕсли СтрЧислоВхождений(Имя, ".") > 0 Тогда Возврат МенеджерОбъектаПоИмени(Имя, Истина, Истина, Истина, "ОбщегоНазначения.ОбщийМодуль", "Имя"); Иначе Модуль = Неопределено; КонецЕсли; Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение параметра %1 в %2. Общий модуль ""%3"" не существует.'"), "Имя", "ОбщегоНазначения.ОбщийМодуль", Имя), КатегорияОшибки.ОшибкаКонфигурации, "СтандартныеПодсистемы.БазоваяФункциональность.ЭтоОшибкаПолученияОбщегоМодуляПоИмени"); КонецЕсли; Возврат Модуль; КонецФункции #КонецОбласти #Область ТекущееОкружение //////////////////////////////////////////////////////////////////////////////// // Функции описания текущего окружения клиентского приложения и операционной системы. // Возвращает Истина, если клиентское приложение запущено под управлением ОС Windows. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоWindowsКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоWindowsКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоWindowsКлиент"); Если ЭтоWindowsКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоWindowsКлиент; КонецФункции // Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Windows. // // Возвращаемое значение: // Булево - Истина, если сервер работает под управлением ОС Windows. // Функция ЭтоWindowsСервер() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация; Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64; КонецФункции // Возвращает Истина, если клиентское приложение запущено под управлением ОС Linux. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоLinuxКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоLinuxКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоLinuxКлиент"); Если ЭтоLinuxКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоLinuxКлиент; КонецФункции // Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Linux. // // Возвращаемое значение: // Булево - Истина, если сервер работает под управлением ОС Linux. // Функция ЭтоLinuxСервер() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация; Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_ARM64"] Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_E2K"]; КонецФункции // Возвращает Истина, если клиентское приложение запущено под управлением macОС. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоMacOSКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент"); Если ЭтоMacOSКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоMacOSКлиент; КонецФункции // Возвращает Истина, если клиентское приложение является Веб-клиентом. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоВебКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоВебКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоВебКлиент"); Если ЭтоВебКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоВебКлиент; КонецФункции // Возвращает Истина, если клиентское приложение является мобильным клиентом. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоМобильныйКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоМобильныйКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоМобильныйКлиент"); Если ЭтоМобильныйКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоМобильныйКлиент; КонецФункции // Возвращает Истина, если клиентское приложение подключено к базе через веб-сервер. // // Возвращаемое значение: // Булево - Истина, если подключен. // Функция КлиентПодключенЧерезВебСервер() Экспорт УстановитьПривилегированныйРежим(Истина); СтрокаСоединенияИнформационнойБазы = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СтрокаСоединенияИнформационнойБазы"); Если СтрокаСоединенияИнформационнойБазы = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "WS=") = 1; КонецФункции // Возвращает системную информацию клиента, если есть клиентское приложение. // До первого серверного вызова с клиента вернет Неопределено. // // Возвращаемое значение: // - ФиксированнаяСтруктура: // * ВерсияОС - Строка // * ВерсияПриложения - Строка // * ИдентификаторКлиента - УникальныйИдентификатор // * ИнформацияПрограммыПросмотра - Строка // * ОперативнаяПамять - Число // * Процессор - Строка // * ТипПлатформы - см. ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы // - Неопределено - если нет клиентского приложения или информация запрашивается // до первого серверного вызова, например, при первом вызове события // платформы УстановкаПараметровСеанса в модуле сеанса. // Функция СистемнаяИнформацияКлиента() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СистемнаяИнформация"); КонецФункции // Возвращает имя используемого клиента, а для веб-браузера название и версию, если есть. // До первого серверного вызова с клиента вернет Неопределено. // // Возвращаемое значение: // - Строка - варианты строк "ВебКлиент.<Название>[.<Версия>]", "ТонкийКлиент", // "ТолстыйКлиентУправляемоеПриложение", "ТолстыйКлиентОбычноеПриложение", // где <Название> - варианты строк "Chrome", "Firefox", "Safari", "IE", "Opera" // или "Другой", когда не определен (ни один из указанных), например "ВебКлиент.Chrome.109". // - Неопределено - если нет клиентского приложения или информация запрашивается // до первого серверного вызова, например, при первом вызове события // платформы УстановкаПараметровСеанса в модуле сеанса. // Функция ИспользуемыйКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИспользуемыйКлиент"); КонецФункции // Возвращает Истина, если включен режим отладки. // // Возвращаемое значение: // Булево - Истина, если включен режим отладки. // Функция РежимОтладки() Экспорт ПараметрЗапускаПриложения = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере(Ложь).Получить("ПараметрЗапуска"); Возврат СтрНайти(ПараметрЗапускаПриложения, "РежимОтладки") > 0; КонецФункции // Возвращает объем оперативной памяти, доступной клиентскому приложению. // // Возвращаемое значение: // Число - количество гигабайтов оперативной памяти с точностью до десятых долей. // Неопределено - нет клиентского приложения, то есть ТекущийРежимЗапуска() = Неопределено. // Функция ОперативнаяПамятьДоступнаяКлиентскомуПриложению() Экспорт ДоступныйОбъем = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ОперативнаяПамять"); Возврат ДоступныйОбъем; КонецФункции // Определяет режим эксплуатации информационной базы файловый (Истина) или серверный (Ложь). // При проверке используется СтрокаСоединенияИнформационнойБазы, которую можно указать явно. // // Параметры: // СтрокаСоединенияИнформационнойБазы - Строка - параметр используется, если // нужно проверить строку соединения не текущей информационной базы. // // Возвращаемое значение: // Булево - Истина, если файловая. // Функция ИнформационнаяБазаФайловая(Знач СтрокаСоединенияИнформационнойБазы = "") Экспорт Если ПустаяСтрока(СтрокаСоединенияИнформационнойБазы) Тогда Возврат СтандартныеПодсистемыПовтИсп.ИнформационнаяБазаФайловая(); КонецЕсли; Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "FILE=") = 1; КонецФункции // Возвращает Истина, если эта информационная база подключена к 1С:Fresh. // // Возвращаемое значение: // Булево - признак автономного рабочего места. // Функция ЭтоАвтономноеРабочееМесто() Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер"); Возврат МодульОбменДаннымиСервер.ЭтоАвтономноеРабочееМесто(); КонецЕсли; Возврат Ложь; КонецФункции // Возвращает признак того, что информационная база является распределенной (РИБ). // // Возвращаемое значение: // Булево // Функция ЭтоРаспределеннаяИнформационнаяБаза() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ(); КонецФункции // Определяет, что эта информационная база является подчиненным узлом // распределенной информационной базы (РИБ). // // Возвращаемое значение: // Булево - Истина, если эта информационная база является подчиненным узлом РИБ. // Функция ЭтоПодчиненныйУзелРИБ() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат ПланыОбмена.ГлавныйУзел() <> Неопределено; КонецФункции // Определяет, что эта информационная база является подчиненным узлом // распределенной информационной базы (РИБ) с фильтром. // // Возвращаемое значение: // Булево - Истина, если эта информационная база является подчиненным узлом РИБ с фильтром. // Функция ЭтоПодчиненныйУзелРИБСФильтром() Экспорт УстановитьПривилегированныйРежим(Истина); Если ПланыОбмена.ГлавныйУзел() <> Неопределено И ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер"); Если МодульОбменДаннымиСервер.НазначениеПланаОбмена(ПланыОбмена.ГлавныйУзел().Метаданные().Имя) = "РИБСФильтром" Тогда Возврат Истина; КонецЕсли; КонецЕсли; Возврат Ложь; КонецФункции // Возвращает Истина при необходимости обновления конфигурации информационной базы подчиненного узла РИБ. // В главном узле всегда Ложь. // // Возвращаемое значение: // Булево - Истина, если требуется. // Функция ТребуетсяОбновлениеКонфигурацииПодчиненногоУзлаРИБ() Экспорт Возврат ЭтоПодчиненныйУзелРИБ() И КонфигурацияИзменена(); КонецФункции // Возвращает признак работы в режиме разделения данных по областям // (технически это признак условного разделения). // // Возвращает Ложь, если конфигурация не может работать в режиме разделения данных // (не содержит общих реквизитов, предназначенных для разделения данных). // // Возвращаемое значение: // Булево - Истина, если разделение включено, // Ложь, если разделение выключено или не поддерживается. // Функция РазделениеВключено() Экспорт Возврат СтандартныеПодсистемыПовтИсп.РазделениеВключено(); КонецФункции // Возвращает признак возможности обращения к разделенным данным (которые входят в состав разделителей). // Признак относится к сеансу, но может меняться во время работы сеанса, если разделение было включено // в самом сеансе, поэтому проверку следует делать непосредственно перед обращением к разделенным данным. // // Возвращает Истина, если конфигурация не может работать в режиме разделения данных // (не содержит общих реквизитов, предназначенных для разделения данных). // // Возвращаемое значение: // Булево - Истина, если разделение не поддерживается, либо разделение выключено, // либо разделение включено и разделители установлены. // Ложь, если разделение включено и разделители не установлены. // Функция ДоступноИспользованиеРазделенныхДанных() Экспорт Возврат СтандартныеПодсистемыПовтИсп.ДоступноИспользованиеРазделенныхДанных(); КонецФункции // Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ // для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию в сети Интернет. // Например, если такой адрес включить в электронное письмо, то из письма одним нажатием // можно перейти к форме объекта в самой программе. // // Возвращаемое значение: // Строка - адрес информационной базы, как он задан в настройке "Адрес в Интернете" в панели администрирования // (хранится в константе АдресПубликацииИнформационнойБазыВИнтернете). // Например, "http://1c.com/database". // // Пример: // ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта"; // возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта. // Функция АдресПубликацииИнформационнойБазыВИнтернете() Экспорт УстановитьПривилегированныйРежим(Истина); Результат = Константы.АдресПубликацииИнформационнойБазыВИнтернете.Получить(); Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда Если ПустаяСтрока(Результат) И ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") И ПодсистемаСуществует("ТехнологияСервиса.ВнешнийПрограммныйИнтерфейс") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); МодульПрограммныйИнтерфейсСервиса = ОбщийМодуль("ПрограммныйИнтерфейсСервиса"); РазделительСеанса = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса(); Попытка Результат = МодульПрограммныйИнтерфейсСервиса.СвойстваПриложения(РазделительСеанса).АдресПриложения; Исключение ЗаписьЖурналаРегистрации(НСтр("ru = 'Адрес публикации приложения'", КодОсновногоЯзыка()), // АПК:154 Не считаем ошибкой проблемы недоступности Менеджера сервиса. УровеньЖурналаРегистрации.Предупреждение,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); Возврат ""; КонецПопытки; Константы.АдресПубликацииИнформационнойБазыВИнтернете.Установить(Результат); КонецЕсли; Возврат Результат; КонецЕсли; Возврат Результат; КонецФункции // Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ // для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию локальной сети. // Например, если такой адрес включить в электронное письмо, то из письма за одно нажатие // можно перейти к форме объекта в самой программе. // // При работе в приложении в Интернете возвращает значение функции АдресПубликацииИнформационнойБазыВИнтернете. // // Возвращаемое значение: // Строка - адрес информационной базы, как он задан в настройке "Локальный адрес" в панели администрирования // (хранится в константе АдресПубликацииИнформационнойБазыВЛокальнойСети). // Например, "http://localserver/base". // // Пример: // ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта"; // возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта. // Функция АдресПубликацииИнформационнойБазыВЛокальнойСети() Экспорт Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда Возврат АдресПубликацииИнформационнойБазыВИнтернете(); КонецЕсли; УстановитьПривилегированныйРежим(Истина); Возврат Константы.АдресПубликацииИнформационнойБазыВЛокальнойСети.Получить(); КонецФункции // Формирует ссылку для входа в программу для указанного пользователя. // // Параметры: // Пользователь - Строка - логин пользователя для входа в программу; // Пароль - Строка - пароль пользователя для входа в программу; // ВидПубликацииИБ - Строка - через какую публикацию пользователь входит в программу: // "ВИнтернете" или "ВЛокальнойСети". // // Возвращаемое значение: // Строка, Неопределено - адрес входа в программу или Неопределено, если адрес не настроен. // Функция АдресВходаВПрограмму(Пользователь, Пароль, ВидПубликацииИБ) Экспорт Результат = ""; Если НРег(ВидПубликацииИБ) = НРег("ВИнтернете") Тогда Результат = АдресПубликацииИнформационнойБазыВИнтернете(); ИначеЕсли НРег(ВидПубликацииИБ) = НРег("ВЛокальнойСети") Тогда Результат = АдресПубликацииИнформационнойБазыВЛокальнойСети(); КонецЕсли; Если ПустаяСтрока(Результат) Тогда Возврат Неопределено; КонецЕсли; Если Не СтрЗаканчиваетсяНа(Результат, "/") Тогда Результат = Результат + "/"; КонецЕсли; Результат = Результат + "?n=" + КодироватьСтроку(Пользователь, СпособКодированияСтроки.КодировкаURL); Если ЗначениеЗаполнено(Пароль) Тогда Результат = Результат + "&p=" + КодироватьСтроку(Пароль, СпособКодированияСтроки.КодировкаURL); КонецЕсли; Возврат Результат; КонецФункции // Возвращает редакцию конфигурации. // Редакцией принято называть две первые группы цифр полной версии конфигурации. // Например, у версии "1.2.3.4" редакция "1.2". // // Возвращаемое значение: // Строка - номер редакции конфигурации. // Функция РедакцияКонфигурации() Экспорт Результат = ""; ВерсияКонфигурации = Метаданные.Версия; Позиция = СтрНайти(ВерсияКонфигурации, "."); Если Позиция > 0 Тогда Результат = Лев(ВерсияКонфигурации, Позиция); ВерсияКонфигурации = Сред(ВерсияКонфигурации, Позиция + 1); Позиция = СтрНайти(ВерсияКонфигурации, "."); Если Позиция > 0 Тогда Результат = Результат + Лев(ВерсияКонфигурации, Позиция - 1); Иначе Результат = ""; КонецЕсли; КонецЕсли; Если ПустаяСтрока(Результат) Тогда Результат = Метаданные.Версия; КонецЕсли; Возврат Результат; КонецФункции // Возвращает общие параметры работы. // // Параметры: // ВернутьЗакешированноеЗначение - Булево - служебный параметр. // // Возвращаемое значение: // см. ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности.ОбщиеПараметры // Функция ОбщиеПараметрыБазовойФункциональности(ВернутьЗакешированноеЗначение = Истина) Экспорт Если ВернутьЗакешированноеЗначение Тогда Возврат СтандартныеПодсистемыПовтИсп.ОбщиеПараметрыБазовойФункциональности(); КонецЕсли; Результат = Новый Структура; Результат.Вставить("ИмяФормыПерсональныхНастроек", ""); Результат.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Истина); Результат.Вставить("РекомендуемыйОбъемОперативнойПамяти", 4); Результат.Вставить("МинимальнаяВерсияПлатформы", МинимальнаяВерсияПлатформы()); Результат.Вставить("РекомендуемаяВерсияПлатформы", Результат.МинимальнаяВерсияПлатформы); Результат.Вставить("ВыводитьПолныйСтекПриОшибкеДлительнойОперации", Ложь); Результат.Вставить("ОтключитьИдентификаторыОбъектовМетаданных", Ложь); Результат.Вставить("ГруппироватьСтатусыИВажныеСообщенияГоризонтально", Ложь); ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности(Результат); Результат.МинимальнаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(Результат.МинимальнаяВерсияПлатформы); Результат.РекомендуемаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(Результат.РекомендуемаяВерсияПлатформы); УточнитьМинимальнуюВерсиюПлатформыИзСервиса(Результат); СистемнаяИнформация = Новый СистемнаяИнформация; Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, Результат.МинимальнаяВерсияПлатформы) < 0 И ЭтоВерсияЗащищенногоПрограммногоКомплекса(СистемнаяИнформация.ВерсияПриложения) Тогда Результат.МинимальнаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения; Результат.РекомендуемаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения; КонецЕсли; Минимальная = Результат.МинимальнаяВерсияПлатформы; Рекомендуемая = Результат.РекомендуемаяВерсияПлатформы; Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда ТекстСообщения = НСтр("ru = 'Указанные в %1 минимальная и рекомендуемая версии платформы не соответствуют следующим требованиям: | - минимальная версия должна быть заполнена; | - минимальная версия не должна быть меньше минимальной версии БСП (см. %2); | - минимальная версия не должна быть меньше рекомендуемой версии. |Минимальная версия: %3 |Минимальная версия БСП: %4 |Рекомендуемая версия: %5'", КодОсновногоЯзыка()); ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения, "ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности", "ОбщегоНазначения.МинимальнаяВерсияПлатформы", Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), Рекомендуемая); ЗаписьЖурналаРегистрации(НСтр("ru = 'Базовая функциональность'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщения); КонецЕсли; УточнитьВерсиюПлатформы(Результат); // Обратная совместимость. ИмяУстаревшегоСвойства = "МинимальноНеобходимаяВерсияПлатформы"; Результат.Вставить(ИмяУстаревшегоСвойства, Результат.МинимальнаяВерсияПлатформы); ИмяУстаревшегоСвойства = "РаботаВПрограммеЗапрещена"; Результат.Вставить(ИмяУстаревшегоСвойства, Ложь); Возврат Результат; КонецФункции // Возвращает описания всех библиотек конфигурации, включая // описание самой конфигурации. // // Возвращаемое значение: // Массив - структур со свойствами: // * Имя - Строка - имя подсистемы, например, "СтандартныеПодсистемы". // * ИдентификаторИнтернетПоддержки - Строка - уникальное имя программы в сервисах интернет-поддержки. // * Версия - Строка - версия в формате из четырех цифр, например "2.3.3.1". // * ЭтоКонфигурация - Булево - признак того, что данная подсистема является основной конфигурацией. // Функция ОписанияПодсистем() Экспорт Результат = Новый Массив; ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем(); Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл Параметры = Новый Структура; Параметры.Вставить("Имя"); Параметры.Вставить("ИдентификаторИнтернетПоддержки"); Параметры.Вставить("Версия"); Параметры.Вставить("ЭтоКонфигурация"); ЗаполнитьЗначенияСвойств(Параметры, ОписаниеПодсистемы.Значение); Результат.Добавить(Параметры); КонецЦикла; Возврат Результат; КонецФункции // Возвращает идентификатор Интернет-поддержки основной конфигурации. // // Возвращаемое значение: // Строка - уникальное имя программы в сервисах Интернет-поддержки. // Функция ИдентификаторИнтернетПоддержкиКонфигурации() Экспорт ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем(); Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл Если ОписаниеПодсистемы.Значение.ЭтоКонфигурация Тогда Возврат ОписаниеПодсистемы.Значение.ИдентификаторИнтернетПоддержки; КонецЕсли; КонецЦикла; Возврат ""; КонецФункции #КонецОбласти #Область Даты #Область ФункцииДляРаботыСДатамиСУчетомЧасовогоПоясаСеанса // Преобразует локальную дату к формату "YYYY-MM-DDThh:mm:ssTZD" согласно ISO 8601. // // Параметры: // ЛокальнаяДата - Дата - дата в часовом поясе сеанса. // // Возвращаемое значение: // Строка - представление даты. // Функция ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата) Экспорт Смещение = СмещениеСтандартногоВремени(ЧасовойПоясСеанса()); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата, Смещение); КонецФункции // Возвращает строковое представление интервала между переданными датами или // относительно переданной даты и текущей даты сеанса. // // Параметры: // ВремяНачала - Дата - начальная точка интервала. // ВремяОкончания - Дата - конечная точка интервала. Если не задана, берется текущая дата сеанса. // // Возвращаемое значение: // Строка - представление интервала времени. Пустая строка, если ВремяНачала больше ВремяОкончания. // Функция ИнтервалВремениСтрокой(Знач ВремяНачала, Знач ВремяОкончания = Неопределено) Экспорт Если ВремяОкончания = Неопределено Тогда ВремяОкончания = ТекущаяДатаСеанса(); КонецЕсли; Если ВремяНачала > ВремяОкончания Тогда Возврат ""; КонецЕсли; ВеличинаИнтервала = ВремяОкончания - ВремяНачала; ВеличинаИнтервалаВДнях = Цел(ВеличинаИнтервала/60/60/24); Если ВеличинаИнтервалаВДнях > 365 Тогда ОписаниеИнтервала = НСтр("ru = 'более года'"); ИначеЕсли ВеличинаИнтервалаВДнях > 31 Тогда ОписаниеИнтервала = НСтр("ru = 'более месяца'"); ИначеЕсли ВеличинаИнтервалаВДнях >= 1 Тогда ОписаниеИнтервала = Формат(ВеличинаИнтервалаВДнях, "ЧДЦ=0") + " " + ПользователиСлужебныйКлиентСервер.ПредметЦелогоЧисла(ВеличинаИнтервалаВДнях, "", НСтр("ru = 'день,дня,дней,,,,,,0'")); Иначе ОписаниеИнтервала = НСтр("ru = 'менее одного дня'"); КонецЕсли; Возврат ОписаниеИнтервала; КонецФункции #КонецОбласти #Область ФункцииДляРаботыСНастройкойРабочейДаты // Сохраняет настройку рабочей даты пользователя. // // Параметры: // НоваяРабочаяДата - Дата - дата, которую необходимо установить в качестве рабочей даты пользователя. // ИмяПользователя - Строка - имя пользователя, для которого устанавливается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // Процедура УстановитьРабочуюДатуПользователя(НоваяРабочаяДата, ИмяПользователя = Неопределено) Экспорт КлючОбъекта = ВРег("РабочаяДата"); ХранилищеОбщихНастроекСохранить(КлючОбъекта, "", НоваяРабочаяДата, , ИмяПользователя); КонецПроцедуры // Возвращает значение настройки рабочей даты для пользователя. // // Параметры: // ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // // Возвращаемое значение: // Дата - значение настройки рабочей даты пользователя или пустая дата, если настройка не задана. // Функция РабочаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт КлючОбъекта = ВРег("РабочаяДата"); Результат = ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, "", '0001-01-01', , ИмяПользователя); Если ТипЗнч(Результат) <> Тип("Дата") Тогда Результат = '0001-01-01'; КонецЕсли; Возврат Результат; КонецФункции // Возвращает значение настройки рабочей даты для пользователя или текущей даты сеанса, // если рабочая дата пользователя не задана. // // Параметры: // ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // // Возвращаемое значение: // Дата - значение настройки рабочей даты пользователя или текущая дата сеанса, если настройка не задана. // Функция ТекущаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт Результат = РабочаяДатаПользователя(ИмяПользователя); Если НЕ ЗначениеЗаполнено(Результат) Тогда Результат = ТекущаяДатаСеанса(); КонецЕсли; Возврат НачалоДня(Результат); КонецФункции #КонецОбласти #КонецОбласти #Область Данные //////////////////////////////////////////////////////////////////////////////// // Общие процедуры и функции для работы с прикладными типами и коллекциями значений. // Возвращает строковое имя значения перечисления по его ссылке. // Вызывает исключение, если передано несуществующее значение перечисления // (например, удаленное в конфигурации или от отключенного расширения конфигурации). // // Параметры: // Значение - ПеречислениеСсылка - значение, для которого необходимо получить имя перечисления. // // Возвращаемое значение: // Строка // // Пример: // В результат будет помещено строковое значение "ФизическоеЛицо": // Результат = ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо); // Функция ИмяЗначенияПеречисления(Значение) Экспорт ОбъектМетаданных = Значение.Метаданные(); ИндексЗначения = Перечисления[ОбъектМетаданных.Имя].Индекс(Значение); Возврат ОбъектМетаданных.ЗначенияПеречисления[ИндексЗначения].Имя; КонецФункции // Процедура удаляет из массива МассивРеквизитов элементы, соответствующие именам // реквизитов объекта из массива МассивНепроверяемыхРеквизитов. // Для использования в обработчиках события ОбработкаПроверкиЗаполнения. // // Параметры: // МассивРеквизитов - Массив - коллекция имен реквизитов объекта. // МассивНепроверяемыхРеквизитов - Массив - коллекция имен реквизитов объекта, не требующих проверки. // Процедура УдалитьНепроверяемыеРеквизитыИзМассива(МассивРеквизитов, МассивНепроверяемыхРеквизитов) Экспорт Для Каждого ЭлементМассива Из МассивНепроверяемыхРеквизитов Цикл ПорядковыйНомер = МассивРеквизитов.Найти(ЭлементМассива); Если ПорядковыйНомер <> Неопределено Тогда МассивРеквизитов.Удалить(ПорядковыйНомер); КонецЕсли; КонецЦикла; КонецПроцедуры // Преобразует таблицу значений в массив структур. // Может использоваться для передачи на клиент данных в том случае, если таблица // значений содержит только такие значения, которые могут // быть переданы с сервера на клиент. // // Полученный массив содержит структуры, каждая из которых повторяет // структуру колонок таблицы значений. // // Не рекомендуется использовать для преобразования таблиц значений // с большим количеством строк. // // Параметры: // ТаблицаЗначений - ТаблицаЗначений - исходная таблица значений. // // Возвращаемое значение: // Массив - коллекция строк таблицы в виде структур. // Функция ТаблицаЗначенийВМассив(ТаблицаЗначений) Экспорт Массив = Новый Массив(); СтруктураСтрокой = ""; НужнаЗапятая = Ложь; Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл Если НужнаЗапятая Тогда СтруктураСтрокой = СтруктураСтрокой + ","; КонецЕсли; СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя; НужнаЗапятая = Истина; КонецЦикла; Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл НоваяСтрока = Новый Структура(СтруктураСтрокой); ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТаблицы); Массив.Добавить(НоваяСтрока); КонецЦикла; Возврат Массив; КонецФункции // Преобразует строку таблицы значений в структуру. // Свойства структуры и их значения совпадают с колонками переданной строки. // // Параметры: // СтрокаТаблицыЗначений - СтрокаТаблицыЗначений // // Возвращаемое значение: // Структура - преобразованная строка таблицы значений. // Функция СтрокаТаблицыЗначенийВСтруктуру(СтрокаТаблицыЗначений) Экспорт Структура = Новый Структура; Для каждого Колонка Из СтрокаТаблицыЗначений.Владелец().Колонки Цикл Структура.Вставить(Колонка.Имя, СтрокаТаблицыЗначений[Колонка.Имя]); КонецЦикла; Возврат Структура; КонецФункции // Создает структуру, содержащую имена и значения измерений, ресурсов и реквизитов // переданного менеджера записи регистра сведений. // // Параметры: // МенеджерЗаписи - РегистрСведенийМенеджерЗаписиИмяРегистраСведений - менеджер записи, из которого надо получить структуру. // МетаданныеРегистра - ОбъектМетаданныхРегистрСведений - метаданные регистра сведений. // // Возвращаемое значение: // Структура - коллекция измерений ресурсов и реквизитов, переданного менеджеру записи. // Функция СтруктураПоМенеджеруЗаписи(МенеджерЗаписи, МетаданныеРегистра) Экспорт ЗаписьКакСтруктура = Новый Структура; Если МетаданныеРегистра.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда ЗаписьКакСтруктура.Вставить("Период", МенеджерЗаписи.Период); КонецЕсли; Для Каждого Поле Из МетаданныеРегистра.Измерения Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Для Каждого Поле Из МетаданныеРегистра.Ресурсы Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Для Каждого Поле Из МетаданныеРегистра.Реквизиты Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Возврат ЗаписьКакСтруктура; КонецФункции // Создает массив и копирует в него значения, содержащиеся в колонке объекта, для // которого доступен обход посредством оператора Для каждого … Из. // // Параметры: // КоллекцияСтрок - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Структура - коллекция, колонку которой нужно выгрузить в массив. // А так же другие объекты, для которых доступен обход // посредством оператора Для каждого … Из … Цикл. // ИмяКолонки - Строка - имя поля коллекции, значения которого нужно выгрузить. // ТолькоУникальныеЗначения - Булево - если Истина, то в массив будут включены // только различающиеся значения. // // Возвращаемое значение: // Массив - значения колонки. // Функция ВыгрузитьКолонку(КоллекцияСтрок, ИмяКолонки, ТолькоУникальныеЗначения = Ложь) Экспорт МассивЗначений = Новый Массив; УникальныеЗначения = Новый Соответствие; Для каждого СтрокаКоллекции Из КоллекцияСтрок Цикл Значение = СтрокаКоллекции[ИмяКолонки]; Если ТолькоУникальныеЗначения И УникальныеЗначения[Значение] <> Неопределено Тогда Продолжить; КонецЕсли; МассивЗначений.Добавить(Значение); УникальныеЗначения.Вставить(Значение, Истина); КонецЦикла; Возврат МассивЗначений; КонецФункции // Преобразует текст указанного формата XML в таблицу значений, // при этом колонки таблицы формируются на основе описания в XML. // // Схема XML: // // // // // // // // // // // // // // // // // // // // // Параметры: // XML - Строка // - ЧтениеXML - текст в формате XML или ЧтениеXML. // // Возвращаемое значение: // Структура: // * ИмяТаблицы - Строка - имя таблицы. // * Данные - ТаблицаЗначений - преобразованная из XML таблица. // // Пример: // КлассификаторТаблица = ОбщегоНазначения.ПрочитатьXMLВТаблицу( // Обработки.ЗагрузкаКурсовВалют.ПолучитьМакет("ОбщероссийскийКлассификаторВалют").ПолучитьТекст()).Данные; // Функция ПрочитатьXMLВТаблицу(Знач XML) Экспорт Если ТипЗнч(XML) <> Тип("ЧтениеXML") Тогда Чтение = Новый ЧтениеXML; Чтение.УстановитьСтроку(XML); Иначе Чтение = XML; КонецЕсли; // Прочитаем первый узел и проверим его. Если Не Чтение.Прочитать() Тогда ВызватьИсключение НСтр("ru = 'Не удалось загрузить данные из XML-файла, т.к. он пустой.'"); ИначеЕсли Чтение.Имя <> "Items" Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось загрузить данные из XML-файла: отсутствует обязательный тег %1.'"), "Items"); КонецЕсли; // Получим описание таблицы и создадим ее. ИмяТаблицы = Чтение.ПолучитьАтрибут("Description"); ИменаКолонок = СтрЗаменить(Чтение.ПолучитьАтрибут("Columns"), ",", Символы.ПС); Колонок = СтрЧислоСтрок(ИменаКолонок); ТаблицаЗначений = Новый ТаблицаЗначений; Для Сч = 1 По Колонок Цикл ТаблицаЗначений.Колонки.Добавить(СтрПолучитьСтроку(ИменаКолонок, Сч), Новый ОписаниеТипов("Строка")); КонецЦикла; // Заполним значения в таблице. Пока Чтение.Прочитать() Цикл Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "Items" Тогда Прервать; ИначеЕсли Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда Продолжить; ИначеЕсли Чтение.Имя <> "Item" Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось загрузить данные из XML-файла: в теге %1 отсутствует обязательный тег %2.'"), "Items", "Item"); КонецЕсли; новСтр = ТаблицаЗначений.Добавить(); Для Сч = 1 По Колонок Цикл ИмяКолонки = СтрПолучитьСтроку(ИменаКолонок, Сч); новСтр[Сч-1] = Чтение.ПолучитьАтрибут(ИмяКолонки); КонецЦикла; КонецЦикла; // Заполним результат Результат = Новый Структура; Результат.Вставить("ИмяТаблицы", ИмяТаблицы); Результат.Вставить("Данные", ТаблицаЗначений); Возврат Результат; КонецФункции // Сравнивает две коллекции строк (ТаблицаЗначений, ДеревоЗначений и т.д.), // для которых доступен обход посредством оператора Для каждого … Из … Цикл. // Сравниваемые коллекции должны отвечать следующим требованиям: // - доступен обход посредством оператора Для каждого … Из … Цикл, // - наличие в обеих коллекциях всех колонок, перечисленных в параметре ИменаКолонок // (если ИменаКолонок не заполнен - все колонки первой коллекции должны существовать во второй коллекции). // Также позволяет сравнивать массивы. // Для сравнения других коллекций, а также для сравнения коллекций с учетом вложенности см. функцию ДанныеСовпадают. // // Параметры: // КоллекцияСтрок1 - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Массив // - ФиксированныйМассив // - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие // объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл. // КоллекцияСтрок2 - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Массив // - ФиксированныйМассив // - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие // объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл. // ИменаКолонок - Строка - имена колонок через запятую, по которым производится сравнение. // Не обязательно для коллекций, состав колонок которых можно определить автоматически: // ТаблицаЗначений, СписокЗначений, Соответствие, Структура. // Если не указан, то сравнение производится по колонкам первой коллекции. // Для коллекций других типов является обязательным. // Следует также учитывать, что при сравнении коллекций, содержащих вместо строк другие типы // элементов, в качестве имен колонок можно указывать только имена свойств этих элементов. // Для соответствий и структур это "Ключ" и "Значение", но не значения ключей. // Для списков значений это "Значение" и "Представление", но не сами значения. // // ИсключаяКолонки - Строка - имена колонок, которые игнорируются при сравнении. // УчитыватьПоследовательностьСтрок - Булево - если Истина, то коллекции признаются // идентичными, только если одинаковые строки размещены в коллекциях на одинаковых местах. // // Возвращаемое значение: // Булево - Истина, если идентичны. // Функция КоллекцииИдентичны(КоллекцияСтрок1, КоллекцияСтрок2, Знач ИменаКолонок = "", Знач ИсключаяКолонки = "", УчитыватьПоследовательностьСтрок = Ложь) Экспорт ТипКоллекции = ТипЗнч(КоллекцияСтрок1); СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив")); СравниваемыеКолонки = Неопределено; Если Не СравниваютсяМассивы Тогда СравниваемыеКолонки = СравниваемыеКолонки(КоллекцияСтрок1, ИменаКолонок, ИсключаяКолонки); КонецЕсли; Если УчитыватьПоследовательностьСтрок Тогда Возврат СравнитьСУчетомПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки); ИначеЕсли СравниваютсяМассивы Тогда // Для массивов используется более простой алгоритм. Возврат СравнитьМассивы(КоллекцияСтрок1, КоллекцияСтрок2); Иначе Возврат СравнитьБезУчетаПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки); КонецЕсли; КонецФункции // Сравнивает данные сложной структуры с учетом вложенности. // // Параметры: // Данные1 - Структура // - ФиксированнаяСтруктура // - Соответствие // - ФиксированноеСоответствие // - Массив // - ФиксированныйМассив // - ХранилищеЗначения // - ТаблицаЗначений // - Строка // - Число // - Булево - сравниваемые данные. // Данные2 - Произвольный - те же типы, что и для параметра Данные1. // // Возвращаемое значение: // Булево - Истина, если совпадают. // Функция ДанныеСовпадают(Данные1, Данные2) Экспорт Если ТипЗнч(Данные1) <> ТипЗнч(Данные2) Тогда Возврат Ложь; КонецЕсли; Если ТипЗнч(Данные1) = Тип("Структура") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированнаяСтруктура") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Для каждого КлючИЗначение Из Данные1 Цикл СтароеЗначение = Неопределено; Если НЕ Данные2.Свойство(КлючИЗначение.Ключ, СтароеЗначение) ИЛИ НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("Соответствие") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированноеСоответствие") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; КлючиНовогоСоответствия = Новый Соответствие; Для каждого КлючИЗначение Из Данные1 Цикл КлючиНовогоСоответствия.Вставить(КлючИЗначение.Ключ, Истина); СтароеЗначение = Данные2.Получить(КлючИЗначение.Ключ); Если НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Для каждого КлючИЗначение Из Данные2 Цикл Если КлючиНовогоСоответствия[КлючИЗначение.Ключ] = Неопределено Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("Массив") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированныйМассив") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Индекс = Данные1.Количество()-1; Пока Индекс >= 0 Цикл Если НЕ ДанныеСовпадают(Данные1.Получить(Индекс), Данные2.Получить(Индекс)) Тогда Возврат Ложь; КонецЕсли; Индекс = Индекс - 1; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("ТаблицаЗначений") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Если Данные1.Колонки.Количество() <> Данные2.Колонки.Количество() Тогда Возврат Ложь; КонецЕсли; Для каждого Колонка Из Данные1.Колонки Цикл Если Данные2.Колонки.Найти(Колонка.Имя) = Неопределено Тогда Возврат Ложь; КонецЕсли; Индекс = Данные1.Количество()-1; Пока Индекс >= 0 Цикл Если НЕ ДанныеСовпадают(Данные1[Индекс][Колонка.Имя], Данные2[Индекс][Колонка.Имя]) Тогда Возврат Ложь; КонецЕсли; Индекс = Индекс - 1; КонецЦикла; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("ХранилищеЗначения") Тогда Если НЕ ДанныеСовпадают(Данные1.Получить(), Данные2.Получить()) Тогда Возврат Ложь; КонецЕсли; Возврат Истина; КонецЕсли; Возврат Данные1 = Данные2; КонецФункции // Фиксирует данные типов Структура, Соответствие, Массив с учетом вложенности. // // Параметры: // Данные - Структура // - Соответствие // - Массив - коллекции, значения которых являются примитивными типами, // хранилищем значения или не могут быть изменены. Поддерживаются типы значений: // Булево, Строка, Число, Дата, Неопределено, УникальныйИдентификатор, Null, Тип, // ХранилищеЗначения, ОбщийМодуль, ОбъектМетаданных, ТипЗначенияXDTO, ТипОбъектаXDTO, // ЛюбаяСсылка. // // ВызыватьИсключение - Булево - начальное значение Истина. Когда установлено Ложь, тогда в случае наличия // нефиксируемых данных исключение не будет вызвано, при этом данные будут // зафиксированы на сколько возможно. // // Возвращаемое значение: // ФиксированнаяСтруктура, ФиксированноеСоответствие, ФиксированныйМассив - фиксированные данные, аналогичные // переданным в параметре Данные. // Функция ФиксированныеДанные(Данные, ВызыватьИсключение = Истина) Экспорт Если ТипЗнч(Данные) = Тип("Массив") Тогда Массив = Новый Массив; Для каждого Значение Из Данные Цикл Если ТипЗнч(Значение) = Тип("Структура") ИЛИ ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда Массив.Добавить(ФиксированныеДанные(Значение, ВызыватьИсключение)); Иначе Если ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Значение, Истина); КонецЕсли; Массив.Добавить(Значение); КонецЕсли; КонецЦикла; Возврат Новый ФиксированныйМассив(Массив); ИначеЕсли ТипЗнч(Данные) = Тип("Структура") ИЛИ ТипЗнч(Данные) = Тип("Соответствие") Тогда Если ТипЗнч(Данные) = Тип("Структура") Тогда Коллекция = Новый Структура; Иначе Коллекция = Новый Соответствие; КонецЕсли; Для каждого КлючИЗначение Из Данные Цикл Значение = КлючИЗначение.Значение; Если ТипЗнч(Значение) = Тип("Структура") ИЛИ ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда Коллекция.Вставить( КлючИЗначение.Ключ, ФиксированныеДанные(Значение, ВызыватьИсключение)); Иначе Если ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Значение, Истина); КонецЕсли; Коллекция.Вставить(КлючИЗначение.Ключ, Значение); КонецЕсли; КонецЦикла; Если ТипЗнч(Данные) = Тип("Структура") Тогда Возврат Новый ФиксированнаяСтруктура(Коллекция); Иначе Возврат Новый ФиксированноеСоответствие(Коллекция); КонецЕсли; ИначеЕсли ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Данные); КонецЕсли; Возврат Данные; КонецФункции // Вычисляет контрольную сумму для произвольных данных по указанному алгоритму. // // Параметры: // Данные - Произвольный - любое сериализуемое значение. // Алгоритм - ХешФункция - алгоритм расчета контрольной суммы. По умолчанию, MD5. // // Возвращаемое значение: // Строка - контрольная сумма строкой без пробелов (например 32 символа). // Функция КонтрольнаяСуммаСтрокой(Знач Данные, Знач Алгоритм = Неопределено) Экспорт Если Алгоритм = Неопределено Тогда Алгоритм = ХешФункция.MD5; КонецЕсли; ХешированиеДанных = Новый ХешированиеДанных(Алгоритм); Если ТипЗнч(Данные) <> Тип("Строка") И ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда Данные = ЗначениеВСтрокуXML(Данные); КонецЕсли; ХешированиеДанных.Добавить(Данные); Если ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("ДвоичныеДанные") Тогда Результат = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", ""); ИначеЕсли ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("Число") Тогда Результат = Формат(ХешированиеДанных.ХешСумма, "ЧГ="); КонецЕсли; Возврат Результат; КонецФункции // Сокращает строку до нужной длины, при этом обрезанная часть хешируется, // обеспечивая уникальность строки. Проверяет длину строки на входе и, в случае // превышения максимальной длины, преобразует ее конец по алгоритму MD5 в // уникальную строку из 32 символов. // // Параметры: // Строка - Строка - исходная строка произвольной длины. // МаксимальнаяДлина - Число - требуемое максимальное количество символов в строке, // минимальное значение: 32. // // Возвращаемое значение: // Строка - строка, не превышающая максимальную длину. // Функция СократитьСтрокуКонтрольнойСуммой(Строка, МаксимальнаяДлина) Экспорт Если МаксимальнаяДлина < 32 Тогда ОбщегоНазначенияКлиентСервер.Проверить(Ложь, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Параметр %1 не может быть меньше 32.'"), "МаксимальнаяДлина"), "ОбщегоНазначения.СократитьСтрокуКонтрольнойСуммой"); КонецЕсли; Результат = Строка; Если СтрДлина(Строка) > МаксимальнаяДлина Тогда Результат = Лев(Строка, МаксимальнаяДлина - 32); ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5); ХешированиеДанных.Добавить(Сред(Строка, МаксимальнаяДлина - 32 + 1)); Результат = Результат + СтрЗаменить(ХешированиеДанных.ХешСумма, " ", ""); КонецЕсли; Возврат Результат; КонецФункции // Создает полную копию структуры, соответствия, массива, списка или таблицы значений, рекурсивно, // с учетом типов дочерних элементов. При этом содержимое значений объектных типов // (СправочникОбъект, ДокументОбъект и т.п.) не копируются, а возвращаются ссылки на исходный объект. // // Параметры: // Источник - Структура // - ФиксированнаяСтруктура // - Соответствие // - ФиксированноеСоответствие // - Массив // - ФиксированныйМассив // - СписокЗначений - объект, который необходимо скопировать. // ФиксироватьДанные - Булево - если Истина - фиксировать, если Ложь - снять фиксацию. // - Неопределено - не изменять. // // Возвращаемое значение: // - Структура // - ФиксированнаяСтруктура // - Соответствие // - ФиксированноеСоответствие // - Массив // - ФиксированныйМассив // - СписокЗначений - копия объекта, переданного в параметре Источник. // Функция СкопироватьРекурсивно(Источник, ФиксироватьДанные = Неопределено) Экспорт Перем Приемник; ТипИсточника = ТипЗнч(Источник); Если ТипИсточника = Тип("ТаблицаЗначений") Тогда Приемник = Источник.Скопировать(); СкопироватьЗначенияТаблицыЗначений(Приемник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("ДеревоЗначений") Тогда Приемник = Источник.Скопировать(); СкопироватьЗначенияСтрокиДереваЗначений(Приемник.Строки, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Структура") Или ТипИсточника = Тип("ФиксированнаяСтруктура") Тогда Приемник = СкопироватьСтруктуру(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Соответствие") Или ТипИсточника = Тип("ФиксированноеСоответствие") Тогда Приемник = СкопироватьСоответствие(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Массив") Или ТипИсточника = Тип("ФиксированныйМассив") Тогда Приемник = СкопироватьМассив(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("СписокЗначений") Тогда Приемник = СкопироватьСписокЗначений(Источник, ФиксироватьДанные); Иначе Приемник = Источник; КонецЕсли; Возврат Приемник; КонецФункции // Возвращает описание предмета в виде текстовой строки. // Для документов возвращается представление, для остальных ссылочных типов возвращается // представление и тип в скобках, например, "Ножницы (Номенклатура)". // Для пустых ссылок, Неопределено или незаполненных значений примитивных типов возвращается "не задан". // // Параметры: // СсылкаНаПредмет - Произвольный. // // Возвращаемое значение: // Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан". // Функция ПредметСтрокой(СсылкаНаПредмет) Экспорт Если СсылкаНаПредмет <> Неопределено Тогда Возврат ПредметыСтрокой(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаНаПредмет))[СсылкаНаПредмет]; Иначе Возврат НСтр("ru = 'не задан'"); КонецЕсли; КонецФункции // Возвращает описания предметов СсылкиНаПредметы. // Для документов возвращается представление, для остальных ссылочных типов возвращается // представление и тип в скобках, например, "Ножницы (Номенклатура)". // Для пустых ссылок или незаполненных значений примитивных типов возвращается "не задан". // Значение "удален", если объект не существует в информационной базе. // Значения Неопределено пропускаются. // // Параметры: // СсылкиНаПредметы - Массив из ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка // * Значение - Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан". // Функция ПредметыСтрокой(Знач СсылкиНаПредметы) Экспорт ПроверяемыеСсылки = Новый Массив; Результат = Новый Соответствие; Для каждого СсылкаНаПредмет Из СсылкиНаПредметы Цикл Если СсылкаНаПредмет = Неопределено Тогда Результат[СсылкаНаПредмет] = НСтр("ru = 'не задан'"); ИначеЕсли Не ЭтоСсылка(ТипЗнч(СсылкаНаПредмет)) Тогда Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет); ИначеЕсли СсылкаНаПредмет.Пустая() Тогда Результат[СсылкаНаПредмет] = НСтр("ru = 'не задан'"); ИначеЕсли Метаданные.Перечисления.Содержит(СсылкаНаПредмет.Метаданные()) Тогда Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет); Иначе ПроверяемыеСсылки.Добавить(СсылкаНаПредмет); КонецЕсли; КонецЦикла; Для каждого СуществующаяСсылка Из ПредставленияСсылок(ПроверяемыеСсылки) Цикл СсылкаНаПредмет = СуществующаяСсылка.Ключ; Результат[СсылкаНаПредмет] = СуществующаяСсылка.Значение; Если Не Метаданные.Документы.Содержит(СсылкаНаПредмет.Метаданные()) Тогда ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().ПредставлениеОбъекта; Если ПустаяСтрока(ПредставлениеОбъекта) Тогда ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().Представление(); КонецЕсли; Результат[СсылкаНаПредмет] = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)", Результат[СсылкаНаПредмет], ПредставлениеОбъекта); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает представления переданных ссылок. // // Параметры: // ПроверяемыеСсылки - Массив из ЛюбаяСсылка, ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка // * Значение - Строка - представление ссылки или "удален", если ссылка не существует в информационной базе. // Функция ПредставленияСсылок(ПроверяемыеСсылки) Экспорт ОбъектыПоТипу = Новый Соответствие; Если ТипЗнч(ПроверяемыеСсылки) = Тип("Массив") Тогда Для каждого ПроверяемаяСсылка Из ПроверяемыеСсылки Цикл Объекты = ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()]; Если Объекты = Неопределено Тогда Объекты = Новый Массив; ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()] = Объекты; КонецЕсли; Объекты.Добавить(ПроверяемаяСсылка); КонецЦикла; Иначе ОбъектыПоТипу[ПроверяемыеСсылки.Метаданные()] = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПроверяемыеСсылки); КонецЕсли; Результат = Новый Соответствие; Если ОбъектыПоТипу.Количество() = 0 Тогда Возврат Результат; КонецЕсли; Запрос = Новый Запрос; ТекстыЗапросов = Новый Массив; Индекс = 0; Для каждого ТипОбъекта Из ОбъектыПоТипу Цикл ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | Представление КАК Представление, | Таблица.Ссылка КАК Ссылка |ИЗ | &ИмяТаблицы КАК Таблица |ГДЕ | Таблица.Ссылка В (&Ссылка)"; Если ТекстыЗапросов.Количество() > 0 Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипОбъекта.Ключ.ПолноеИмя()); ИмяПараметра = "Ссылка" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылка", "&" + ИмяПараметра); ТекстыЗапросов.Добавить(ТекстЗапроса); Запрос.УстановитьПараметр(ИмяПараметра, ТипОбъекта.Значение); Индекс = Индекс + 1; КонецЦикла; Запрос.Текст = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); // @query-part; УстановитьПривилегированныйРежим(Истина); ФактическиеСсылки = Запрос.Выполнить().Выгрузить(); УстановитьПривилегированныйРежим(Ложь); ПредставленияСсылок = Запрос.Выполнить().Выгрузить(); ПредставленияСсылок.Индексы.Добавить("Ссылка"); Для каждого Ссылка Из ФактическиеСсылки Цикл Если ЗначениеЗаполнено(Ссылка.Ссылка) Тогда ПредставлениеСсылки = ПредставленияСсылок.Найти(Ссылка.Ссылка, "Ссылка"); Результат[Ссылка.Ссылка] = ?(ПредставлениеСсылки <> Неопределено, ПредставлениеСсылки.Представление, Строка(Ссылка.Ссылка)); КонецЕсли; КонецЦикла; Для каждого Ссылка Из ПроверяемыеСсылки Цикл Если Результат[Ссылка] = Неопределено Тогда Результат[Ссылка] = НСтр("ru = 'удален'"); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции #КонецОбласти #Область ДинамическийСписок // Создает структуру для второго параметра СвойстваСписка процедуры УстановитьСвойстваДинамическогоСписка. // // Возвращаемое значение: // Структура - любое поле может иметь значение Неопределено, если оно не устанавливается: // * ТекстЗапроса - Строка - новый текст запроса. // * ОсновнаяТаблица - Строка - имя основной таблицы. // * ДинамическоеСчитываниеДанных - Булево - признак использования динамического считывания. // Функция СтруктураСвойствДинамическогоСписка() Экспорт Возврат Новый Структура("ТекстЗапроса, ОсновнаяТаблица, ДинамическоеСчитываниеДанных"); КонецФункции // Установить текст запроса, основную таблицу или динамическое считывание в динамическом списке. // Устанавливать эти свойства следует за один вызов этой процедуры, чтобы не снижалась производительность. // // Параметры: // Список - ТаблицаФормы - элемент формы динамического списка, для которого устанавливаются свойства. // СвойстваСписка - см. СтруктураСвойствДинамическогоСписка // Процедура УстановитьСвойстваДинамическогоСписка(Список, СвойстваСписка) Экспорт Форма = Список.Родитель; ТипФормаКлиентскогоПриложения = Тип("ФормаКлиентскогоПриложения"); Пока ТипЗнч(Форма) <> ТипФормаКлиентскогоПриложения Цикл Форма = Форма.Родитель; КонецЦикла; ДинамическийСписок = Форма[Список.ПутьКДанным]; ТекстЗапроса = СвойстваСписка.ТекстЗапроса; Если Не ПустаяСтрока(ТекстЗапроса) Тогда ДинамическийСписок.ТекстЗапроса = ТекстЗапроса; КонецЕсли; ОсновнаяТаблица = СвойстваСписка.ОсновнаяТаблица; Если ОсновнаяТаблица <> Неопределено Тогда ДинамическийСписок.ОсновнаяТаблица = ОсновнаяТаблица; КонецЕсли; ДинамическоеСчитываниеДанных = СвойстваСписка.ДинамическоеСчитываниеДанных; Если ТипЗнч(ДинамическоеСчитываниеДанных) = Тип("Булево") Тогда ДинамическийСписок.ДинамическоеСчитываниеДанных = ДинамическоеСчитываниеДанных; КонецЕсли; КонецПроцедуры #КонецОбласти #Область ВнешнееСоединение //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с внешним соединением. // Возвращает CLSID COM-класса для работы с "1С:Предприятием 8" через COM-соединение. // // Параметры: // ИмяCOMСоединителя - Строка - имя COM-класса для работы с "1С:Предприятием 8" через COM-соединение. // // Возвращаемое значение: // Строка - строковое представление CLSID. // Функция ИдентификаторCOMСоединителя(Знач ИмяCOMСоединителя) Экспорт Если ИмяCOMСоединителя = "v83.COMConnector" Тогда Возврат "181E893D-73A4-4722-B61D-D604B3D67D47"; ИначеЕсли ИмяCOMСоединителя = "v85.COMConnector" Тогда Возврат "BBAB44B3-6C80-43B1-AFEC-3094B12122BE"; КонецЕсли; ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение параметра %1 функции %2. Не задан CLSID для класса %3.'"), "ИмяCOMСоединителя", "ОбщегоНазначения.ИдентификаторCOMСоединителя", ИмяCOMСоединителя), КатегорияОшибки.ОшибкаКонфигурации); КонецФункции // Устанавливает внешнее соединение с информационной базой по переданным параметрам подключения и возвращает указатель // на это соединение. // // Параметры: // Параметры - см. ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения // // Возвращаемое значение: // Структура: // * Соединение - COMОбъект // - Неопределено - COM-объект соединения или Неопределено в случае ошибки; // * КраткоеОписаниеОшибки - Строка - краткое описание ошибки; // * ПодробноеОписаниеОшибки - Строка - подробное описание ошибки; // * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM. // Функция УстановитьВнешнееСоединениеСБазой(Параметры) Экспорт ПодключениеНедоступно = ЭтоLinuxСервер(); КраткоеОписаниеОшибки = НСтр("ru = 'Прямое подключение к информационной базе недоступно на сервере под управлением ОС Linux.'"); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.УстановитьВнешнееСоединениеСБазой(Параметры, ПодключениеНедоступно, КраткоеОписаниеОшибки); КонецФункции #КонецОбласти #Область Метаданные #Область ФункцииОпределенияТиповОбъектовМетаданных // Ссылочные типы данных // Определяет принадлежность объекта метаданных к общему типу "Документ". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к документам. // // Возвращаемое значение: // Булево - Истина, если объект является документом. // Функция ЭтоДокумент(ОбъектМетаданных) Экспорт Возврат Метаданные.Документы.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Справочник". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является справочником. // Функция ЭтоСправочник(ОбъектМетаданных) Экспорт Возврат Метаданные.Справочники.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Перечисление". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является перечислением. // Функция ЭтоПеречисление(ОбъектМетаданных) Экспорт Возврат Метаданные.Перечисления.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План обмена". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом обмена. // Функция ЭтоПланОбмена(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План видов характеристик". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом видов характеристик. // Функция ЭтоПланВидовХарактеристик(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Бизнес-процесс". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является бизнес-процессом. // Функция ЭтоБизнесПроцесс(ОбъектМетаданных) Экспорт Возврат Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Задача". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является задачей. // Функция ЭтоЗадача(ОбъектМетаданных) Экспорт Возврат Метаданные.Задачи.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План счетов". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом счетов. // Функция ЭтоПланСчетов(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План видов расчета". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом видов расчета. // Функция ЭтоПланВидовРасчета(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных); КонецФункции // Регистры // Определяет принадлежность объекта метаданных к общему типу "Регистр сведений". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром сведений. // Функция ЭтоРегистрСведений(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр накопления". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром накопления. // Функция ЭтоРегистрНакопления(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр бухгалтерии". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром бухгалтерии. // Функция ЭтоРегистрБухгалтерии(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр расчета". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром расчета. // Функция ЭтоРегистрРасчета(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных); КонецФункции // Константы // Определяет принадлежность объекта метаданных к общему типу "Константа". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является константой. // Функция ЭтоКонстанта(ОбъектМетаданных) Экспорт Возврат Метаданные.Константы.Содержит(ОбъектМетаданных); КонецФункции // Журналы документов // Определяет принадлежность объекта метаданных к общему типу "Журнал документов". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является журналом документов. // Функция ЭтоЖурналДокументов(ОбъектМетаданных) Экспорт Возврат Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных); КонецФункции // Последовательности // Определяет принадлежность объекта метаданных к общему типу "Последовательности". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является последовательностью. // Функция ЭтоПоследовательность(ОбъектМетаданных) Экспорт Возврат Метаданные.Последовательности.Содержит(ОбъектМетаданных); КонецФункции // РегламентныеЗадания // Определяет принадлежность объекта метаданных к общему типу "Регламентные задания". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регламентным заданием. // Функция ЭтоРегламентноеЗадание(ОбъектМетаданных) Экспорт Возврат Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных); КонецФункции // Общие // Определяет принадлежность объекта метаданных к типу регистр. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является каким-либо регистром. // Функция ЭтоРегистр(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к ссылочному типу. // Принадлежность определяется по базовому типу, то есть для формы справочника будет Истина, // для формы регистра будет Ложь. Если объект метаданных не найден по типу, тогда будет Ложь. // // Параметры: // ОписаниеОбъекта - ОбъектМетаданных, Тип // // Возвращаемое значение: // Булево - Истина, если базовый тип объекта ссылочного типа. // Функция ЭтоОбъектСсылочногоТипа(ОписаниеОбъекта) Экспорт Если ТипЗнч(ОписаниеОбъекта) = Тип("Тип") Тогда ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъекта); Если ОбъектМетаданных = Неопределено Тогда Возврат Ложь; КонецЕсли; Иначе ОбъектМетаданных = ОписаниеОбъекта; КонецЕсли; ИмяВидаОбъектов = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".")[0]; ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов)); Если Свойства.ИмяКоллекции = "Перечисления" Тогда // Обратная совместимость. Возврат Ложь; КонецЕсли; Возврат Свойства <> Неопределено И Свойства.ЕстьСсылка; КонецФункции #КонецОбласти #Область ПроцедурыИФункцииДляРаботыСТипамиОбъектамиМетаданныхИИхСтроковымиПредставлениями // Возвращает имена реквизитов объекта заданного типа. // // Параметры: // Ссылка - ЛюбаяСсылка - ссылка на элемент базы данных, для которого требуется получить результат функции; // Тип - Тип - тип значения реквизита. // // Возвращаемое значение: // Строка - строка реквизитов объекта метаданных конфигурации, разделенных символом ",". // // Пример: // РеквизитыОрганизации = ОбщегоНазначения.ИменаРеквизитовПоТипу(Документ.Ссылка, Тип("СправочникСсылка.Организации")); // Функция ИменаРеквизитовПоТипу(Ссылка, Тип) Экспорт Результат = ""; МетаданныеОбъекта = Ссылка.Метаданные(); Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл Если Реквизит.Тип.СодержитТип(Тип) Тогда Результат = Результат + ?(ПустаяСтрока(Результат), "", ", ") + Реквизит.Имя; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает имя базового типа по началу полного имени объекта метаданных. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект метаданных, для которого необходимо определить базовый тип. // // Возвращаемое значение: // Строка - имя базового типа указанного объекта метаданных, например, // "ОбщиеМодули", ..., "Языки", ..., "Документы", ..., "РегистрыСведений", ... // Для перерасчетов регистров расчета возвращается "Перерасчеты". // // Пример: // ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(Метаданные.Справочники.Номенклатура); // Функция ИмяБазовогоТипаПоОбъектуМетаданных(ОбъектМетаданных) Экспорт ЧастиИмени = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), "."); ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0])); Если Свойства = Неопределено Тогда Возврат ""; КонецЕсли; Если Свойства.ИмяВидаОбъекта = "РегистрРасчета" И ЧастиИмени.Количество() = 4 И ВРег(ЧастиИмени[2]) = "ПЕРЕРАСЧЕТ" Тогда Возврат "Перерасчеты"; КонецЕсли; Возврат Свойства.ИмяКоллекции; КонецФункции // Возвращает менеджер объекта по началу полному имени объекта метаданных. // Вызывает исключение при неверном начале полного имени или // отсутствии объектов в конфигурации из начала полного имени, // определяющего менеджер объекта. // Например, для реквизитов или форм справочника используется только // имя справочника и возвращается менеджер справочника, // а для перерасчета используется имя регистра расчета, имя перерасчета и // возвращается менеджер перерасчета. // // Параметры: // ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Справочник.Организации". // // Возвращаемое значение: // - ПланОбменаМенеджер // - КритерийОтбораМенеджер // - ХранилищеНастроекМенеджер // - WSСсылкаМенеджер // - СервисИнтеграцииМенеджер // - КонстантаМенеджер // - СправочникМенеджер // - ДокументМенеджер // - ПоследовательностьМенеджер // - ЖурналДокументовМенеджер // - ПеречислениеМенеджер // - ОтчетМенеджер // - ОбработкаМенеджер // - ПланВидовХарактеристикМенеджер // - ПланСчетовМенеджер // - ПланВидовРасчетаМенеджер // - РегистрСведенийМенеджер // - РегистрНакопленияМенеджер // - РегистрБухгалтерииМенеджер // - РегистрРасчетаМенеджер // - ПерерасчетМенеджер // - БизнесПроцессМенеджер // - ЗадачаМенеджер // - ВнешнийИсточникДанныхМенеджер // - ВнешнийИсточникДанныхТаблицаМенеджер // - ВнешнийИсточникДанныхКубМенеджер // - ВнешнийИсточникДанныхКубТаблицаИзмеренияМенеджер // // Пример: // МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени("Справочник.Организации"); // ПустаяСсылка = МенеджерСправочника.ПустаяСсылка(); // Функция МенеджерОбъектаПоПолномуИмени(ПолноеИмя) Экспорт Возврат МенеджерОбъектаПоИмени(ПолноеИмя, Истина, Ложь, Ложь, "ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени", "ПолноеИмя", Ложь); КонецФункции // Возвращает менеджер объекта по ссылке на объект. // См. МенеджерОбъектаПоПолномуИмени. // // Параметры: // Ссылка - ЛюбаяСсылка - ссылка на объект, менеджер которого требуется получить. // // Возвращаемое значение: // - ПланОбменаМенеджер // - СправочникМенеджер // - ДокументМенеджер // - ПеречислениеМенеджер // - ПланВидовХарактеристикМенеджер // - ПланСчетовМенеджер // - ПланВидовРасчетаМенеджер // - БизнесПроцессМенеджер // - ЗадачаМенеджер // // Пример: // МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОрганизацию); // ПустаяСсылка = МенеджерСправочника.ПустаяСсылка(); // Функция МенеджерОбъектаПоСсылке(Ссылка) Экспорт ЧастиИмени = СтрРазделить(Ссылка.Метаданные().ПолноеИмя(), "."); ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0])); Если Свойства <> Неопределено И Свойства.ЕстьСсылка Тогда Возврат Свойства.Менеджер[ЧастиИмени[1]]; КонецЕсли; ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4.'"), Ссылка, ТипЗнч(Ссылка), "Ссылка", "ОбщегоНазначения.МенеджерОбъектаПоСсылке"); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецФункции // Проверка того, что переданный тип является ссылочным типом данных. // Для типа Неопределено возвращается Ложь. // // Параметры: // ПроверяемыйТип - Тип - для проверки на ссылочный тип данных. // // Возвращаемое значение: // Булево - Истина, если это ссылка. // Функция ЭтоСсылка(ПроверяемыйТип) Экспорт Возврат ПроверяемыйТип <> Тип("Неопределено") И ОписаниеТипаВсеСсылки().СодержитТип(ПроверяемыйТип); КонецФункции // Проверяет физическое наличие записи в информационной базе данных о переданном значении ссылки. // // Параметры: // ПроверяемаяСсылка - ЛюбаяСсылка - значение любой ссылки информационной базы данных. // // Возвращаемое значение: // Булево - Истина, если существует. // Функция СсылкаСуществует(ПроверяемаяСсылка) Экспорт ТекстЗапроса = "ВЫБРАТЬ ПЕРВЫЕ 1 | 1 КАК Поле1 |ИЗ | &ИмяТаблицы КАК Таблица |ГДЕ | Таблица.Ссылка = &Ссылка"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИмяТаблицыПоСсылке(ПроверяемаяСсылка)); Запрос = Новый Запрос; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("Ссылка", ПроверяемаяСсылка); УстановитьПривилегированныйРежим(Истина); Возврат НЕ Запрос.Выполнить().Пустой(); КонецФункции // Возвращает имя вида объектов метаданных по ссылке на объект. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // См. так же ВидОбъектаПоТипу. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, вид которого требуется получить. // // Возвращаемое значение: // Строка - имя вида объектов метаданных. Например: "Справочник", "Документ". // Функция ВидОбъектаПоСсылке(Ссылка) Экспорт Возврат ВидОбъектаПоТипу(ТипЗнч(Ссылка)); КонецФункции // Возвращает имя вида объектов метаданных по типу объекта. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // См. так же ВидОбъектаПоСсылке. // // Параметры: // ТипОбъекта - Тип - тип прикладного объекта, определенный в конфигурации. // // Возвращаемое значение: // Строка - имя вида объектов метаданных. Например: "Справочник", "Документ". // Функция ВидОбъектаПоТипу(ТипОбъекта) Экспорт ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипОбъекта); Если ОбъектМетаданных = Неопределено Тогда ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.ВидОбъектаПоТипу", "ТипОбъекта", ТипОбъекта, Тип("Тип")); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объекта метаданных для указанного типа.'"), ТипОбъекта, ТипЗнч(ТипОбъекта), "ТипОбъекта", "ОбщегоНазначения.ВидОбъектаПоТипу"); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ИмяВидаОбъектов = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".")[0]; ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов)); Если Свойства = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не определен вид объектов метаданных для указанного типа.'"), ТипОбъекта, ТипЗнч(ТипОбъекта), "ТипОбъекта", "ОбщегоНазначения.ВидОбъектаПоТипу"); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; Возврат Свойства.ИмяВидаОбъекта; КонецФункции // Возвращает полное имя объекта метаданных по переданному значению ссылки. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, для которого необходимо получить имя таблицы ИБ. // // Возвращаемое значение: // Строка - полное имя объекта метаданных для указанного объекта. Например: "Справочник.Номенклатура". // Функция ИмяТаблицыПоСсылке(Ссылка) Экспорт Возврат Ссылка.Метаданные().ПолноеИмя(); КонецФункции // Проверяет, что переданное значение имеет ссылочный тип данных. // // Параметры: // Значение - Произвольный - проверяемое значение. // // Возвращаемое значение: // Булево - Истина, если тип значения ссылочный. // Функция ЗначениеСсылочногоТипа(Значение) Экспорт Возврат ЭтоСсылка(ТипЗнч(Значение)); КонецФункции // Проверяет, является ли элемент справочника или плана видов характеристик группой элементов. // // Параметры: // Объект - СправочникСсылка // - ПланВидовХарактеристикСсылка // - СправочникОбъект // - ПланВидовХарактеристикОбъект - проверяемый объект. // // Возвращаемое значение: // Булево // Функция ОбъектЯвляетсяГруппой(Объект) Экспорт Если ЗначениеСсылочногоТипа(Объект) Тогда Ссылка = Объект; Иначе Ссылка = Объект.Ссылка; КонецЕсли; МетаданныеОбъекта = Ссылка.Метаданные(); Если ЭтоСправочник(МетаданныеОбъекта) Тогда Если Не МетаданныеОбъекта.Иерархический Или МетаданныеОбъекта.ВидИерархии <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда Возврат Ложь; КонецЕсли; ИначеЕсли Не ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или Не МетаданныеОбъекта.Иерархический Тогда Возврат Ложь; КонецЕсли; Если Ссылка <> Объект Тогда Возврат Объект.ЭтоГруппа; КонецЕсли; Возврат ЗначениеРеквизитаОбъекта(Ссылка, "ЭтоГруппа") = Истина; КонецФункции // Возвращает ссылку, соответствующую объекту метаданных, для использования в базе данных. // См. также ОбщегоНазначения.ИдентификаторыОбъектовМетаданных. // // Ссылки возвращаются для следующих объектов метаданных: // - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - ПланыОбмена; // - Константы; // - Справочники; // - Документы; // - ЖурналыДокументов; // - Отчеты; // - Обработки; // - ПланыВидовХарактеристик; // - ПланыСчетов; // - ПланыВидовРасчета; // - РегистрыСведений; // - РегистрыНакопления; // - РегистрыБухгалтерии; // - РегистрыРасчета; // - БизнесПроцессы; // - Задачи. // // Параметры: // ОписаниеОбъектаМетаданных - ОбъектМетаданных - объект метаданных конфигурации; // - Тип - тип, который можно использовать в функции Метаданные.НайтиПоТипу; // - Строка - полное имя объекта метаданных, которое можно // использовать в функции Метаданные.НайтиПоПолномуИмени. // // ВызыватьИсключение - Булево - если Ложь, то вместо вызова исключения возвращается Null для несуществующего // или неподдерживаемого объекта метаданных. // // Возвращаемое значение: // - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений // - Null // // Пример: // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ТипЗнч(Ссылка)); // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных); // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.Организации"); // Функция ИдентификаторОбъектаМетаданных(ОписаниеОбъектаМетаданных, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных( ОписаниеОбъектаМетаданных, ВызыватьИсключение); КонецФункции // Возвращает ссылки, соответствующие объектам метаданных, для использования в базе данных. // См. также ОбщегоНазначения.ИдентификаторОбъектаМетаданных. // // Ссылки возвращаются для следующих объектов метаданных: // - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - ПланыОбмена. // - Константы. // - Справочники. // - Документы. // - ЖурналыДокументов. // - Отчеты. // - Обработки. // - ПланыВидовХарактеристик. // - ПланыСчетов. // - ПланыВидовРасчета. // - РегистрыСведений. // - РегистрыНакопления. // - РегистрыБухгалтерии. // - РегистрыРасчета. // - БизнесПроцессы. // - Задачи. // // Параметры: // ОписаниеОбъектовМетаданных - Массив из ОбъектМетаданных - объекты метаданных конфигурации; // - Массив из Строка - полные имена объектов метаданных, которые можно использовать // в функции Метаданные.НайтиПоПолномуИмени; // - Массив из Тип - типы, которые можно использовать в функции Метаданные.НайтиПоТипу. // ВызыватьИсключение - Булево - если Ложь, то несуществующие и неподдерживаемые объекты метаданных // будут пропущены в возвращаемом значении. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - Строка - полное имя указанного объекта метаданных. // * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - найденный идентификатор. // // Пример: // ПолныеИмена = Новый Массив; // ПолныеИмена.Добавить(Метаданные.Справочники.Валюты.ПолноеИмя()); // ПолныеИмена.Добавить(Метаданные.РегистрыСведений.КурсыВалют.ПолноеИмя()); // Идентификаторы = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена); // Функция ИдентификаторыОбъектовМетаданных(ОписаниеОбъектовМетаданных, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторыОбъектовМетаданных( ОписаниеОбъектовМетаданных, ВызыватьИсключение); КонецФункции // Возвращает объект метаданных по переданному идентификатору. // // Параметры: // Идентификатор - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор // объекта метаданных конфигурации или расширения конфигурации. // // ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных // не существует или недоступен, возвращает соответственно // Null или Неопределено вместо вызова исключения. // // Возвращаемое значение: // - ОбъектМетаданных - объект метаданных, соответствующий идентификатору. // // - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что // для указанного идентификатора объект метаданных не существует (идентификатор устарел). // // - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, // что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен. // Для расширений конфигурации это значит, что расширение установлено, но не подключено, // либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка. // Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект // метаданных имеется, а в текущем (старом) сеансе нет. // Функция ОбъектМетаданныхПоИдентификатору(Идентификатор, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектМетаданныхПоИдентификатору( Идентификатор, ВызыватьИсключение); КонецФункции // Возвращает объекты метаданных по переданным идентификаторам. // // Параметры: // Идентификаторы - Массив - со значениями: // * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификаторы // объектов метаданных конфигурации или расширений конфигурации. // // ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных // не существует или недоступен, возвращает соответственно // Null или Неопределено вместо вызова исключения. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - переданный идентификатор. // * Значение - ОбъектМетаданных - объект метаданных, соответствующий идентификатору. // - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что // для указанного идентификатора объект метаданных не существует (идентификатор устарел). // - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, // что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен. // Для расширений конфигурации это значит, что расширение установлено, но не подключено, // либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка. // Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект // метаданных имеется, а в текущем (старом) сеансе нет. // Функция ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектыМетаданныхПоИдентификаторам( Идентификаторы, ВызыватьИсключение); КонецФункции // Возвращает ОбъектМетаданных, быстро найденный по полному имени. // Более производительный аналог метода платформы Метаданные.НайтиПоПолномуИмени // для корневых объектов метаданных. // // Параметры: // ПолноеИмя - Строка - полное имя объекта метаданных, например, Справочник.Организации // // Возвращаемое значение: // - ОбъектМетаданных - когда найден // - Неопределено - когда не найден // Функция ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) Экспорт ПозицияТочки = СтрНайти(ПолноеИмя, "."); ИмяВидаОбъектов = Лев(ПолноеИмя, ПозицияТочки - 1); ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов)); Если Свойства <> Неопределено Тогда Если Свойства.ИмяКоллекции <> "Подсистемы" Тогда ИмяОбъекта = Сред(ПолноеИмя, ПозицияТочки + 1); ОбъектМетаданных = Метаданные[Свойства.ИмяКоллекции].Найти(ИмяОбъекта); Иначе ИменаПодсистем = СтрРазделить(ВРег(ПолноеИмя), "."); Количество = ИменаПодсистем.Количество(); Подсистема = Метаданные; ОбъектМетаданных = Неопределено; Индекс = 0; Пока Истина Цикл Индекс = Индекс + 1; Если Индекс >= Количество Тогда Прервать; КонецЕсли; ИмяПодсистемы = ИменаПодсистем[Индекс]; Подсистема = Подсистема.Подсистемы.Найти(ИмяПодсистемы); Если Подсистема = Неопределено Тогда Прервать; КонецЕсли; Индекс = Индекс + 1; Если Индекс = Количество Тогда ОбъектМетаданных = Подсистема; Прервать; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; Если ОбъектМетаданных = Неопределено Тогда ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмя); КонецЕсли; Возврат ОбъектМетаданных; КонецФункции // Определяет доступность объекта метаданных по функциональным опциям. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных // - Строка - проверяемый объект метаданных. // // Возвращаемое значение: // Булево - Истина, если объект доступен. // Функция ОбъектМетаданныхДоступенПоФункциональнымОпциям(Знач ОбъектМетаданных) Экспорт Если ОбъектМетаданных = Неопределено Тогда Возврат Ложь; КонецЕсли; Если ТипЗнч(ОбъектМетаданных) <> Тип("Строка") Тогда ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); Иначе ПолноеИмя = ОбъектМетаданных; КонецЕсли; Возврат СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям().Получить(ПолноеИмя) <> Ложь; КонецФункции // Позволяет отразить переименование объекта метаданных при переходе на новую версию конфигурации. // Для вызова в процедуре ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных. // // Параметры: // Переименования - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.Переименования // ВерсияИБ - Строка - версия конечной конфигурации, при переходе на которую нужно // выполнить переименование, например, "2.1.2.14". // СтароеПолноеИмя - Строка - старое полное имя объекта метаданных, которое нужно переименовать, // например "Подсистема.СлужебныеПодсистемы". // НовоеПолноеИмя - Строка - новое полное имя объекта метаданных, на которое нужно переименовать, // например "Подсистема.СервисныеПодсистемы". // ИдентификаторБиблиотеки - Строка - внутренний идентификатор библиотеки, к которой относится ВерсияИБ. // Для основной конфигурации не требуется. // Например, "СтандартныеПодсистемы" - как указано // в ОбновлениеИнформационнойБазыБСП.ПриДобавленииПодсистемы. // Пример: // ОбщегоНазначения.ДобавитьПереименование(Переименования, "2.1.2.14", // "Подсистема.СлужебныеПодсистемы", // "Подсистема.СервисныеПодсистемы"); // Процедура ДобавитьПереименование(Переименования, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки = "") Экспорт Справочники.ИдентификаторыОбъектовМетаданных.ДобавитьПереименование(Переименования, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки); КонецПроцедуры // Возвращает строковое представление типа, например, "СправочникСсылка.ИмяОбъекта", "Форма клиентского приложения". // Тип приводится к строке напрямую, кроме простых типов, ссылочных типов, // типов ключа записи регистров, типов объекта и типов набора записей. // // Параметры: // Тип - Тип - для которого надо получить представление. // // Возвращаемое значение: // Строка - "СправочникСсылка.ИмяОбъекта", "РегистрСведенийКлючЗаписи.ИмяОбъекта", // "СправочникОбъект.ИмяОбъекта", "РегистрСведенийНаборЗаписей.ИмяОбъекта", ... // Функция СтроковоеПредставлениеТипа(Тип) Экспорт ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); Если ОбъектМетаданных <> Неопределено Тогда ЧастиИмени = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), "."); ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов; Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0])); Если Свойства <> Неопределено Тогда Если Свойства.ИмяВидаОбъекта = "БизнесПроцесс" И БизнесПроцессы.ТипВсеСсылкиТочекМаршрутаБизнесПроцессов().СодержитТип(Тип) Тогда ИмяТипа = "ТочкаМаршрутаБизнесПроцессаСсылка"; ИначеЕсли Свойства.ЕстьСсылка Тогда ИмяТипа = Свойства.ИмяТипаСсылки; ИначеЕсли Свойства.ЕстьКлючЗаписи Тогда ИмяТипа = Свойства.ИмяТипаКлючаЗаписи; КонецЕсли; Если ЗначениеЗаполнено(ИмяТипа) Тогда Результат = ИмяТипа + "." + ЧастиИмени[1]; Если Тип(Результат) = Тип Тогда Возврат Результат; КонецЕсли; КонецЕсли; ИмяТипа = Неопределено; Если ЗначениеЗаполнено(Свойства.ИмяТипаОбъекта) Тогда ИмяТипа = Свойства.ИмяТипаОбъекта; ИначеЕсли ЗначениеЗаполнено(Свойства.ИмяТипаНабораЗаписей) Тогда ИмяТипа = Свойства.ИмяТипаНабораЗаписей; КонецЕсли; Если ЗначениеЗаполнено(ИмяТипа) Тогда Результат = ИмяТипа + "." + ЧастиИмени[1]; Если Тип(Результат) = Тип Тогда Возврат Результат; КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; Если Тип = Тип("Неопределено") Тогда Результат = "Неопределено"; ИначеЕсли Тип = Тип("Строка") Тогда Результат = "Строка"; ИначеЕсли Тип = Тип("Число") Тогда Результат = "Число"; ИначеЕсли Тип = Тип("Булево") Тогда Результат = "Булево"; ИначеЕсли Тип = Тип("Дата") Тогда Результат = "Дата"; Иначе Результат = Строка(Тип); КонецЕсли; Возврат Результат; КонецФункции // Возвращает таблицу значений с описанием требуемых свойств всех реквизитов объекта метаданных. // Получает значения свойств стандартных реквизитов и пользовательских реквизитов (созданных в режиме конфигуратора). // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо получить значение свойств реквизитов. // Например: Метаданные.Документ.РеализацияТоваровИУслуг // Свойства - Строка - свойства реквизитов, перечисленные через запятую, значение которых необходимо получить. // Например: "Имя, Тип, Синоним, Подсказка". // // Возвращаемое значение: // ТаблицаЗначений - описание требуемых свойств всех реквизитов объекта метаданных. // Функция ОписаниеСвойствОбъекта(ОбъектМетаданных, Свойства) Экспорт МассивСвойств = СтрРазделить(Свойства, ","); // Возвращаемое значение функции. ТаблицаОписанияСвойствОбъекта = Новый ТаблицаЗначений; // Добавляем в таблицу поля согласно именам переданных свойств. Для Каждого ИмяСвойства Из МассивСвойств Цикл ТаблицаОписанияСвойствОбъекта.Колонки.Добавить(СокрЛП(ИмяСвойства)); КонецЦикла; // Заполняем строку таблицы свойствами реквизитов объекта метаданных. Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит); КонецЦикла; // Заполняем строку таблицы свойствами стандартных реквизитов объекта метаданных. Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит); КонецЦикла; Возврат ТаблицаОписанияСвойствОбъекта; КонецФункции // Возвращает признак того, что реквизит входит в подмножество стандартных реквизитов. // // Параметры: // СтандартныеРеквизиты - ОписанияСтандартныхРеквизитов - тип и значение, описывающие коллекцию настроек различных // стандартных реквизитов; // ИмяРеквизита - Строка - реквизит, который необходимо проверить на принадлежность множеству стандартных // реквизитов. // // Возвращаемое значение: // Булево - Истина, если реквизит входит в подмножество стандартных реквизитов. // Функция ЭтоСтандартныйРеквизит(СтандартныеРеквизиты, ИмяРеквизита) Экспорт Для Каждого Реквизит Из СтандартныеРеквизиты Цикл Если Реквизит.Имя = ИмяРеквизита Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Позволяет определить, есть ли среди реквизитов объекта реквизит с переданным именем. // // Параметры: // ИмяРеквизита - Строка - имя реквизита; // МетаданныеОбъекта - ОбъектМетаданных - объект, в котором требуется проверить наличие реквизита. // // Возвращаемое значение: // Булево - Истина, если есть. // Функция ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта) Экспорт Реквизиты = МетаданныеОбъекта.Реквизиты; // КоллекцияОбъектовМетаданных Возврат НЕ (Реквизиты.Найти(ИмяРеквизита) = Неопределено); КонецФункции // Проверить, что описание типа состоит из единственного типа значения и // совпадает с нужным типом. // // Параметры: // ОписаниеТипа - ОписаниеТипов - проверяемая коллекция типов; // ТипЗначения - Тип - проверяемый тип. // // Возвращаемое значение: // Булево - Истина, если совпадает. // // Пример: // Если ОбщегоНазначения.ОписаниеТипаСостоитИзТипа(ТипЗначенияСвойства, Тип("Булево") Тогда // // Выводим поле в виде флажка. // КонецЕсли; // Функция ОписаниеТипаСостоитИзТипа(ОписаниеТипа, ТипЗначения) Экспорт Если ОписаниеТипа.Типы().Количество() = 1 И ОписаниеТипа.Типы().Получить(0) = ТипЗначения Тогда Возврат Истина; КонецЕсли; Возврат Ложь; КонецФункции // Создает объект ОписаниеТипов, содержащий тип Строка. // // Параметры: // ДлинаСтроки - Число - длина строки. // // Возвращаемое значение: // ОписаниеТипов - описание типа Строка. // Функция ОписаниеТипаСтрока(ДлинаСтроки) Экспорт Возврат Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(ДлинаСтроки)); КонецФункции // Создает объект ОписаниеТипов, содержащий тип Число. // // Параметры: // Разрядность - Число - общее количество разрядов числа (количество разрядов // целой части плюс количество разрядов дробной части). // РазрядностьДробнойЧасти - Число - число разрядов дробной части. // ЗнакЧисла - ДопустимыйЗнак - допустимый знак числа. // // Возвращаемое значение: // ОписаниеТипов - описание типа Число. // Функция ОписаниеТипаЧисло(Разрядность, РазрядностьДробнойЧасти = 0, Знач ЗнакЧисла = Неопределено) Экспорт Если ЗнакЧисла = Неопределено Тогда ЗнакЧисла = ДопустимыйЗнак.Любой; КонецЕсли; Возврат Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(Разрядность, РазрядностьДробнойЧасти, ЗнакЧисла)); КонецФункции // Создает объект ОписаниеТипов, содержащий тип Дата. // // Параметры: // ЧастиДаты - ЧастиДаты - набор вариантов использования значений типа Дата. // // Возвращаемое значение: // ОписаниеТипов - описание типа Дата. // Функция ОписаниеТипаДата(ЧастиДаты) Экспорт Возврат Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты)); КонецФункции // Возвращает описание типа, включающего в себя все возможные ссылочные типы конфигурации. // // Возвращаемое значение: // ОписаниеТипов - все ссылочные типы конфигурации. // Функция ОписаниеТипаВсеСсылки() Экспорт Возврат СтандартныеПодсистемыПовтИсп.ОписаниеТипаВсеСсылки(); КонецФункции // Возвращает строковое представление списка, заданное в свойствах объекта метаданных. // В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном // порядке: Расширенное представление списка, Представление списка, Синоним или Имя. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - произвольный объект. // // Возвращаемое значение: // Строка - представление списка. // Функция ПредставлениеСписка(ОбъектМетаданных) Экспорт СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеСписка,ПредставлениеСписка"); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных); Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеСписка) Тогда Результат = СвойстваОбъекта.РасширенноеПредставлениеСписка; ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеСписка) Тогда Результат = СвойстваОбъекта.ПредставлениеСписка; Иначе Результат = ОбъектМетаданных.Представление(); КонецЕсли; Возврат Результат; КонецФункции // Возвращает строковое представление объекта, заданное в свойствах объекта метаданных. // В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном // порядке: Расширенное представление объекта, Представление объекта, Синоним или Имя. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - произвольный объект. // // Возвращаемое значение: // Строка - представление объекта. // Функция ПредставлениеОбъекта(ОбъектМетаданных) Экспорт СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеОбъекта,ПредставлениеОбъекта"); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных); Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеОбъекта) Тогда Результат = СвойстваОбъекта.РасширенноеПредставлениеОбъекта; ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеОбъекта) Тогда Результат = СвойстваОбъекта.ПредставлениеОбъекта; Иначе Результат = ОбъектМетаданных.Представление(); КонецЕсли; Возврат Результат; КонецФункции // Возвращает условие отбора и параметры запроса для выбора записей из базы данных // по указанному набору записей с учетом режима замещения. // // Если Замещение равно Истина или РежимЗамещения.Замещение, тогда // записи будут извлекаться из базы данных по настройке свойства Отбор, // в противном случае по ключам строк записей в наборе записей. // // Параметры: // НаборЗаписей - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей - набор записей, который используется // для подготовки условия и параметров для запроса. // - Отбор - отбор набора записей (в этом случае Замещение считается Истина). // // Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью. // - Неопределено - получить и установить в этот параметр значение из свойства // Замещение структуры ДополнительныеСвойства указанного набора записей // (если свойства нет, тогда устанавливается Истина). // // Запрос - Запрос - установить параметры в указанный запрос и заменить на возвращаемое // УсловиеЗапроса строку "&УсловиеОтбора" в тексте запроса, если есть. // - Неопределено // // ДополнительныеПараметры - см. НовыеПараметрыОтбораЗаписейНабораИзБазыДанных // // Возвращаемое значение: // Структура: // * УсловиеЗапроса - Строка - условие для подстановки в текст запроса. // * ПараметрыЗапроса - Структура из КлючИЗначение: // ** Ключ - Строка - имя поля отбора или ЗначенияПолейОтбораСтрок с указанным префиксом. // ** Значение - Произвольный - значение поля отбора или таблица значений. // // Пример: // Запрос = Новый Запрос; // Запрос.Текст = // "ВЫБРАТЬ РАЗЛИЧНЫЕ // | ТекущаяТаблица.Пользователь КАК Пользователь, // | ТекущаяТаблица.ПотребоватьСменуПароляПриВходе КАК ПотребоватьСменуПароляПриВходе, // | ТекущаяТаблица.СрокДействияНеОграничен КАК СрокДействияНеОграничен, // | ТекущаяТаблица.СрокДействия КАК СрокДействия, // | ТекущаяТаблица.ПросрочкаРаботыВПрограммеДоЗапрещенияВхода КАК ПросрочкаРаботыВПрограммеДоЗапрещенияВхода // |ИЗ // | РегистрСведений.СведенияОПользователях КАК ТекущаяТаблица // |ГДЕ // | &УсловиеОтбора"; // ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение, Запрос); // СуществующиеЗаписи = Запрос.Выполнить().Выгрузить(); // Функция ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение = Неопределено, Запрос = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт Параметры = ?(ДополнительныеПараметры <> Неопределено, ДополнительныеПараметры, НовыеПараметрыОтбораЗаписейНабораИзБазыДанных()); Режим = Новый Структура("Замещение", Истина); Если ТипЗнч(НаборЗаписей) = Тип("Отбор") Или ТипЗнч(НаборЗаписей) = Тип("Массив") Тогда Отбор = НаборЗаписей; Иначе Отбор = НаборЗаписей.Отбор; Если Замещение = Неопределено Тогда ЗаполнитьЗначенияСвойств(Режим, НаборЗаписей.ДополнительныеСвойства); ИмяПараметра = "НаборЗаписей.ДополнительныеСвойства.Замещение"; Иначе Режим.Замещение = Замещение; ИмяПараметра = "Замещение"; КонецЕсли; Если ТипЗнч(Режим.Замещение) <> Тип("Булево") И Не ЭтоДобавлениеНабораЗаписей(Режим.Замещение) И Не ЭтоЗамещениеНабораЗаписей(Режим.Замещение) И Не ЭтоОбновлениеНабораЗаписей(Режим.Замещение) И Не ЭтоСлияниеНабораЗаписей(Режим.Замещение) И Не ЭтоУдалениеНабораЗаписей(Режим.Замещение) Тогда ОжидаемыеТипы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Тип("Булево")); Если СтандартныеПодсистемыПовтИсп.РежимДобавленияНабораЗаписей() <> Неопределено Тогда ОжидаемыеТипы.Добавить(СтандартныеПодсистемыПовтИсп.ТипРежимЗамещения()); КонецЕсли; ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных", ИмяПараметра, Режим.Замещение, ОжидаемыеТипы); КонецЕсли; КонецЕсли; Если Замещение = Неопределено Тогда Замещение = Режим.Замещение; КонецЕсли; ПараметрыЗапроса = Новый Структура; Условие = "ЛОЖЬ"; Псевдоним = Параметры.ПсевдонимТаблицы; Если ЭтоОбновлениеНабораЗаписей(Режим.Замещение) Или ЭтоСлияниеНабораЗаписей(Режим.Замещение) Или ЭтоУдалениеНабораЗаписей(Режим.Замещение) Тогда ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи( НаборЗаписей.Метаданные().ПолноеИмя()); СписокПолей = ОписаниеКлючаЗаписи.СписокПолейОбновления; Если ЗначениеЗаполнено(СписокПолей) Тогда ИмяПараметраТаблицы = Параметры.ИмяПараметраТаблицыКлючевыхПолей; Выгрузка = НаборЗаписей.Выгрузить(, СписокПолей); ПараметрыЗапроса.Вставить(ИмяПараметраТаблицы, Выгрузка); Если Запрос <> Неопределено Тогда Запрос.УстановитьПараметр(ИмяПараметраТаблицы, Выгрузка); КонецЕсли; Условие = СтрШаблон("(%1) В (&" + ИмяПараметраТаблицы + ")", Псевдоним + СтрЗаменить(СписокПолей, ",", ", " + Псевдоним)); // @query-part-1 Иначе Условие = "ИСТИНА"; КонецЕсли; ИначеЕсли Режим.Замещение = Истина Или ЭтоЗамещениеНабораЗаписей(Режим.Замещение) Тогда ЧастиУсловия = Новый Массив; Префикс = Параметры.ПрефиксИменПолейВПараметрах; Шаблон = Псевдоним + "%1 = &" + Префикс + "%1"; // @query-part-1 Для Каждого ЭлементОтбора Из Отбор Цикл Если Не ЭлементОтбора.Использование Тогда Продолжить; КонецЕсли; ЧастиУсловия.Добавить(СтрШаблон(Шаблон, ЭлементОтбора.Имя)); ПараметрыЗапроса.Вставить(Префикс + ЭлементОтбора.Имя, ЭлементОтбора.Значение); Если Запрос <> Неопределено Тогда Запрос.УстановитьПараметр(Префикс + ЭлементОтбора.Имя, ЭлементОтбора.Значение); КонецЕсли; КонецЦикла; Условие = ?(Не ЗначениеЗаполнено(ЧастиУсловия), "ИСТИНА", СтрСоединить(ЧастиУсловия, Символы.ПС + " И ")); КонецЕсли; Результат = Новый Структура; Результат.Вставить("УсловиеЗапроса", Условие); Результат.Вставить("ПараметрыЗапроса", ПараметрыЗапроса); Если Запрос <> Неопределено Тогда Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", Условие); КонецЕсли; Возврат Результат; КонецФункции // Дополнительные параметры для функции ОтборЗаписейНабораИзБазыДанных. // // Возвращаемое значение: // Структура: // * ПсевдонимТаблицы - Строка - префикс, добавляемый к именам полей // (начальное значение "ТекущаяТаблица."). // // * ПрефиксИменПолейВПараметрах - Строка - префикс, добавляемый к именам // полей отбора в условии и параметрах запроса (начальное значение без префикса). // // * ИмяПараметраТаблицыКлючевыхПолей - Строка - начальное значение ЗначенияПолейОтбораСтрок. // Функция НовыеПараметрыОтбораЗаписейНабораИзБазыДанных() Экспорт Результат = Новый Структура; Результат.Вставить("ПсевдонимТаблицы", "ТекущаяТаблица."); Результат.Вставить("ПрефиксИменПолейВПараметрах", ""); Результат.Вставить("ИмяПараметраТаблицыКлючевыхПолей", "ЗначенияПолейОтбораСтрок"); Возврат Результат; КонецФункции // Возвращает указанные поля строк регистра из базы данных, которые будут // записаны при записи указанного набора записей с учетом режима замещения. // // Параметры: // НаборЗаписей - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей - набор записей, // который используется вычисления изменений. // // Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью. // - Неопределено - получить и установить в этот параметр значение из свойства // Замещение структуры ДополнительныеСвойства указанного набора записей // (если свойства нет, тогда устанавливается Истина). // // СписокПолей - Строка - список полей набора записей через запятую. // Если не указан, значит все поля набора записей. // // Возвращаемое значение: // ТаблицаЗначений - поля из параметра СписокПолей, // строки без повторений для указанного списка полей. // Функция ЗаписиНабораИзБазыДанных(НаборЗаписей, Замещение = Неопределено, СписокПолей = "") Экспорт ПолноеИмяРегистра = НаборЗаписей.Метаданные().ПолноеИмя(); СвернутьРезультат = Ложь; Если ЗначениеЗаполнено(СписокПолей) Тогда ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); Поля = СтрРазделить(ВРег(СписокПолей), ","); Для Каждого Поле Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл Если Поля.Найти(ВРег(Поле.Имя)) = Неопределено Тогда СвернутьРезультат = Истина; Прервать; КонецЕсли; КонецЦикла; Иначе Таблица = НаборЗаписей.Выгрузить(Новый Массив); Поля = Новый Массив; Для Каждого Колонка Из Таблица.Колонки Цикл Поля.Добавить(Колонка.Имя); КонецЦикла; СписокПолей = СтрСоединить(Поля, ","); КонецЕсли; Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | &ВыбираемыеПоля |ИЗ | &Таблица КАК ТекущаяТаблица |ГДЕ | &УсловиеОтбора"; ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение, Запрос); Если Замещение = Ложь Или ЭтоДобавлениеНабораЗаписей(Замещение) Тогда Возврат НаборЗаписей.Выгрузить(Новый Массив, ?(ЗначениеЗаполнено(СписокПолей), СписокПолей, Неопределено)); КонецЕсли; Запрос.Текст = СтрЗаменить(Запрос.Текст, "&Таблица", ПолноеИмяРегистра); Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ВыбираемыеПоля", СписокПолей); Результат = Запрос.Выполнить().Выгрузить(); Если СвернутьРезультат Тогда Результат.Свернуть(СписокПолей); КонецЕсли; Возврат Результат; КонецФункции // Возвращает удаленные и добавленные строки регистра // для указанного набора записей с учетом режима замещения. // // Параметры: // ЗаписиИзБазыДанных - см. ЗаписиНабораИзБазыДанных // // НаборЗаписей - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей - набор записей, // который используется вычисления изменений. // // Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью. // // ТолькоИзменения - Булево - если установить Истина, тогда в результате // не будет строк без изменений (ВидИзмененияСтроки = 0). // // Возвращаемое значение: // ТаблицаЗначений: // * ВидИзмененияСтроки - Число - если 1, то строка добавлена, // если -1, то удалена, если 0, то не изменилась. // Далее поля из таблицы ЗаписиИзБазыДанных. // Функция ИзменениеЗаписейНабора(ЗаписиИзБазыДанных, НаборЗаписей, Замещение, ТолькоИзменения = Ложь) Экспорт ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи( НаборЗаписей.Метаданные().ПолноеИмя()); СписокПолейКлючаЗаписи = ВРег("," + ОписаниеКлючаЗаписи.СписокПолей + ","); ПоляКлючаЗаписи = Новый Массив; Поля = Новый Массив; Для Каждого Колонка Из ЗаписиИзБазыДанных.Колонки Цикл Поля.Добавить(Колонка.Имя); Если СтрНайти(СписокПолейКлючаЗаписи, "," + ВРег(Колонка.Имя) + ",") > 0 Тогда ПоляКлючаЗаписи.Добавить(Колонка.Имя); КонецЕсли; КонецЦикла; СписокПолей = СтрСоединить(Поля, ","); НовыеСтроки = ?(ЭтоУдалениеНабораЗаписей(Замещение), Новый Массив, Неопределено); Таблица = НаборЗаписей.Выгрузить(НовыеСтроки, СписокПолей); Если ОписаниеКлючаЗаписи.ОписаниеПолей.Количество() <> ПоляКлючаЗаписи.Количество() Тогда Таблица.Свернуть(СписокПолей); КонецЕсли; Таблица.Колонки.Добавить("ВидИзмененияСтроки", Новый ОписаниеТипов("Число")); Таблица.ЗаполнитьЗначения(1, "ВидИзмененияСтроки"); Для Каждого СтараяЗапись Из ЗаписиИзБазыДанных Цикл НоваяСтрока = Таблица.Добавить(); ЗаполнитьЗначенияСвойств(НоваяСтрока, СтараяЗапись); НоваяСтрока.ВидИзмененияСтроки = -1; КонецЦикла; Таблица.Свернуть(СписокПолей, "ВидИзмененияСтроки"); Если ТолькоИзменения Тогда СтрокиБезИзменений = Таблица.НайтиСтроки(Новый Структура("ВидИзмененияСтроки", 0)); Для Каждого СтрокаТаблицы Из СтрокиБезИзменений Цикл Таблица.Удалить(СтрокаТаблицы); КонецЦикла; КонецЕсли; Возврат Таблица; КонецФункции #КонецОбласти #КонецОбласти #Область ХранилищеНастроек //////////////////////////////////////////////////////////////////////////////// // Сохранение, чтение и удаление настроек из хранилищ. // Сохраняет настройку в хранилище общих настроек, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеОбщихНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Сохраняет несколько настроек в хранилище общих настроек, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // НесколькоНастроек - Массив - со значениями: // * Значение - Структура: // * Объект - Строка - см. параметр КлючОбъекта в синтакс-помощнике платформы. // * Настройка - Строка - см. параметр КлючНастроек в синтакс-помощнике платформы. // * Значение - Произвольный - см. параметр Настройки в синтакс-помощнике платформы. // // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеОбщихНастроекСохранитьМассив(НесколькоНастроек, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Возврат; КонецЕсли; Для Каждого Элемент Из НесколькоНастроек Цикл ХранилищеОбщихНастроек.Сохранить(Элемент.Объект, КлючНастроек(Элемент.Настройка), Элемент.Значение); КонецЦикла; Если ОбновитьПовторноИспользуемыеЗначения Тогда ОбновитьПовторноИспользуемыеЗначения(); КонецЕсли; КонецПроцедуры // Загружает настройку из хранилища общих настроек, как метод платформы Загрузить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища общих настроек, как метод платформы Удалить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеОбщихНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры // Сохраняет настройку в хранилище системных настроек, как метод платформы Сохранить // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеСистемныхНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Загружает настройку из хранилища системных настроек, как метод платформы Загрузить, // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно: // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеСистемныхНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища системных настроек, как метод платформы Удалить, // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеСистемныхНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры // Сохраняет настройку в хранилище настроек данных форм, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеНастроекДанныхФормСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Загружает настройку из хранилища настроек данных форм, как метод платформы Загрузить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеНастроекДанныхФормЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища настроек данных форм, как метод платформы Удалить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеНастроекДанныхФормУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры #КонецОбласти #Область СериализацияXML // Преобразует (сериализует) любое значение в XML-строку. // Преобразованы в могут быть только те объекты, для которых в синтакс-помощнике указано, что они сериализуются. // См. также ЗначениеИзСтрокиXML. // // Параметры: // Значение - Произвольный - значение, которое необходимо сериализовать в XML-строку. // // Возвращаемое значение: // Строка - XML-строка. // Функция ЗначениеВСтрокуXML(Значение) Экспорт ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(); СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение, НазначениеТипаXML.Явное); Возврат ЗаписьXML.Закрыть(); КонецФункции // Выполняет преобразование (десериализацию) XML-строки в значение. // См. также ЗначениеВСтрокуXML. // // Параметры: // СтрокаXML - Строка - XML-строка, с сериализованным объектом.. // // Возвращаемое значение: // Произвольный - значение, полученное из переданной XML-строки. // Функция ЗначениеИзСтрокиXML(СтрокаXML) Экспорт ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(СтрокаXML); Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML); КонецФункции // Возвращает XML-представление XDTO-объекта. // // Параметры: // ОбъектXDTO - ОбъектXDTO - объект, для которого требуется сформировать XML-представление. // Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XML-представление. // Если параметр не указан - будет использоваться глобальная фабрика XDTO. // // Возвращаемое значение: // Строка - XML-представление XDTO-объекта. // Функция ОбъектXDTOВСтрокуXML(Знач ОбъектXDTO, Знач Фабрика = Неопределено) Экспорт ОбъектXDTO.Проверить(); Если Фабрика = Неопределено Тогда Фабрика = ФабрикаXDTO; КонецЕсли; Запись = Новый ЗаписьXML(); Запись.УстановитьСтроку(); Фабрика.ЗаписатьXML(Запись, ОбъектXDTO, , , , НазначениеТипаXML.Явное); Возврат Запись.Закрыть(); КонецФункции // Формирует XDTO-объект по XML-представлению. // // Параметры: // СтрокаXML - Строка - XML-представление XDTO-объекта, // Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XDTO-объект. // Если параметр не указан - будет использоваться глобальная фабрика XDTO. // // Возвращаемое значение: // ОбъектXDTO - XDTO-объект. // Функция ОбъектXDTOИзСтрокиXML(Знач СтрокаXML, Знач Фабрика = Неопределено) Экспорт Если Фабрика = Неопределено Тогда Фабрика = ФабрикаXDTO; КонецЕсли; Чтение = Новый ЧтениеXML(); Чтение.УстановитьСтроку(СтрокаXML); Возврат Фабрика.ПрочитатьXML(Чтение); КонецФункции #КонецОбласти #Область СериализацияJSON // Преобразует значение в строку JSON при помощи метода глобального контекста ЗаписатьJSON. // Допускаются не все типы значений, подробности см. в синтакс-помощнике. // Даты преобразуются в формат ISO (YYYY-MM-DDThh:mm:ssZ). // // Параметры: // Значение - Произвольный // // Возвращаемое значение: // Строка // Функция ЗначениеВJSON(Знач Значение) Экспорт ЗаписьJSON = Новый ЗаписьJSON; ЗаписьJSON.УстановитьСтроку(); ЗаписатьJSON(ЗаписьJSON, Значение); Возврат ЗаписьJSON.Закрыть(); КонецФункции // Преобразует строку в формате JSON в значение при помощи метода глобального контекста ПрочитатьJSON. // См. ограничения в синтакс-помощнике. // Объекты JSON по умолчанию преобразует в значения типа Соответствие. // Имена свойств со значением типа Дата необходимо явно указывать, чтобы было выполнено преобразование. // Ожидаемый формат дат - ISO (YYYY-MM-DDThh:mm:ssZ). // // Параметры: // Строка - Строка - значение в формате JSON. // ИменаСвойствСоЗначениямиДата - Строка - имя свойства, содержащее значение типа Дата. Допустимо указывать несколько // свойств через запятую. // - Массив из Строка // ПрочитатьВСоответствие - Булево - если Ложь, то объекты JSON будут преобразованы в значение типа Структура. // // Возвращаемое значение: // Произвольный // Функция JSONВЗначение(Знач Строка, Знач ИменаСвойствСоЗначениямиДата = Неопределено, Знач ПрочитатьВСоответствие = Истина) Экспорт Если ТипЗнч(ИменаСвойствСоЗначениямиДата) = Тип("Строка") Тогда ИменаСвойствСоЗначениямиДата = СтрРазделить(ИменаСвойствСоЗначениямиДата, ", " + Символы.ПС, Ложь); КонецЕсли; ЧтениеJSON = Новый ЧтениеJSON; ЧтениеJSON.УстановитьСтроку(Строка); Возврат ПрочитатьJSON(ЧтениеJSON, ПрочитатьВСоответствие, ИменаСвойствСоЗначениямиДата); КонецФункции #КонецОбласти #Область РаботаСИнтернетом // Проверяет, что разрешена работа с Интернет-сервисами из приложения. // Параметры: // ПоказатьОшибку - Булево - вызвать исключение. // // Возвращаемое значение: // Булево // Функция РазрешенДоступКИнтернетСервисам(ПоказатьОшибку = Ложь) Экспорт Если РазделениеВключено() Тогда Возврат Истина; КонецЕсли; ДоступРазрешен = ПолучитьФункциональнуюОпцию("РазрешитьДоступКИнтернетСервисам"); Если Не ДоступРазрешен Тогда ВерсияМетаданных = Метаданные.Версия; Если Не ПустаяСтрока(ВерсияМетаданных) И ВерсияМетаданных <> ОбновлениеИнформационнойБазыСлужебный.ВерсияИБ( Метаданные.Имя) Тогда Возврат Истина; КонецЕсли; КонецЕсли; Если Не ДоступРазрешен И ПоказатьОшибку Тогда ВызватьИсключение ЗапрещенДоступКИнтернетСервисамТекстСообщения(); КонецЕсли; Возврат ДоступРазрешен; КонецФункции // Текст ошибки при отключенном доступе к сервисам интернета. // // Возвращаемое значение: // Строка // Функция ЗапрещенДоступКИнтернетСервисамТекстСообщения() Экспорт Возврат НСтр("ru = 'Доступ к Интернет-сервисам в приложении запрещен администратором (""Интернет-поддержка и сервисы"" - ""Доступ к Интернет-сервисам"").'"); КонецФункции // Устанавливает признак разрешения работа с Интернет-сервисами из приложения. После вызова на клиенте рекомендуется // вызвать оповещение о записи константы. // // Параметры: // Разрешить - Булево // Процедура НастроитьРаботуСИнтернетСервисами(Разрешить) Экспорт Если Не Разрешить И РазделениеВключено() Тогда Возврат; КонецЕсли; Константы.РазрешитьДоступКИнтернетСервисам.Установить(Разрешить); Если Разрешить И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами"); МодульБлокировкаРаботыСВнешнимиРесурсами.ПриВключенииДоступаКИнтернетСервисам(); КонецЕсли; КонецПроцедуры // Возвращает структуру параметров для функции СоздатьWSПрокси. // // Возвращаемое значение: // см. СоздатьWSПрокси.ПараметрыПодключенияWSПрокси // Функция ПараметрыПодключенияWSПрокси() Экспорт Результат = Новый Структура; Результат.Вставить("АдресWSDL"); Результат.Вставить("URIПространстваИмен"); Результат.Вставить("ИмяСервиса"); Результат.Вставить("ИмяТочкиПодключения", ""); Результат.Вставить("ИмяПользователя"); Результат.Вставить("Пароль"); Результат.Вставить("Таймаут", 0); Результат.Вставить("Местоположение"); Результат.Вставить("ИспользоватьАутентификациюОС", Ложь); Результат.Вставить("ДелатьКонтрольныйВызов", Ложь); Результат.Вставить("ЗащищенноеСоединение", Неопределено); Результат.Вставить("ПроверятьДоставкуПакетовПриОшибке", Истина); Результат.Вставить("ПроверятьДоступКИнтернетСервисам", Истина); Возврат Результат; КонецФункции // Конструктор объекта WSПрокси с дополнительными возможностями по сравнению с конструктором Новый WSПрокси: // - создает WSОпределения; // - кэширует файл WSDL для ускорения работы с веб-сервисом; // - не требуется указание ИнтернетПрокси (используется автоматически, если настроен); // - позволяет делать быструю проверку доступности сервиса с помощью операции Ping. // // Параметры: // ПараметрыПодключенияWSПрокси - Структура: // * АдресWSDL - Строка - месторасположение wsdl, например, "http://webservice.net/webservice.asmx?wsdl". // * URIПространстваИмен - Строка - URI пространства имен web-сервиса, например, "http://www.webservice.net/WebService/1.0.0.1". // * ИмяСервиса - Строка - имя сервиса, например, "WebService_1_0_0_1". // * ИмяТочкиПодключения - Строка - необязательный параметр. Если не задано, образуется как "<ИмяСервиса>Soap". // * ИмяПользователя - Строка - необязательный параметр. Имя пользователя для входа на сервер. // * Пароль - Строка - необязательный параметр. Пароль пользователя. // * Таймаут - Число - необязательный параметр. Таймаут на операции веб-сервиса, выполняемые // через прокси. В секундах. // * Местоположение - Строка - необязательный параметр. Фактический адрес сервиса. Используется, если // адрес реального расположения сервиса отличается от адреса, который указан // в WSDL-файле. // * ИспользоватьАутентификациюОС - Булево - необязательный параметр. Включает использование авторизации NTLM или // Negotiate на сервере. // * ДелатьКонтрольныйВызов - Булево - необязательный параметр. Выполнять проверку доступности сервиса (требуется // поддержка команды Ping в веб-сервисе). По умолчанию, Ложь. // * ЗащищенноеСоединение - ЗащищенноеСоединениеOpenSSL // - Неопределено - необязательные параметры защищенного соединения. // * ПроверятьДоставкуПакетовПриОшибке - см. ПолучениеФайловИзИнтернета.ДиагностикаСоединения.ПроверятьДоставкуПакетов. // * ПроверятьДоступКИнтернетСервисам - Булево - необязательный параметр, по умолчанию Истина - выполняется проверка // разрешения доступа к Интернет-сервисам из приложения. // // Возвращаемое значение: // WSПрокси // // Пример: // ПараметрыПодключения = ОбщегоНазначения.ПараметрыПодключенияWSПрокси(); // ПараметрыПодключения.АдресWSDL = "http://webservice.net/webservice.asmx?wsdl"; // ПараметрыПодключения.URIПространстваИмен = "http://www.webservice.net/WebService/1.0.0.1"; // ПараметрыПодключения.ИмяСервиса = "WebService_1_0_0_1"; // ПараметрыПодключения.Таймаут = 20; // Прокси = ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПодключения); // Функция СоздатьWSПрокси(Знач ПараметрыПодключенияWSПрокси) Экспорт ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("СоздатьWSПрокси", "Параметры", ПараметрыПодключенияWSПрокси, Тип("Структура"), Новый Структура("АдресWSDL,URIПространстваИмен,ИмяСервиса", Тип("Строка"), Тип("Строка"), Тип("Строка"))); ПараметрыПодключения = ПараметрыПодключенияWSПрокси(); ЗаполнитьЗначенияСвойств(ПараметрыПодключения, ПараметрыПодключенияWSПрокси); Если ПараметрыПодключения.ПроверятьДоступКИнтернетСервисам Тогда РазрешенДоступКИнтернетСервисам(Истина); КонецЕсли; ДелатьКонтрольныйВызов = ПараметрыПодключения.ДелатьКонтрольныйВызов; Таймаут = ПараметрыПодключения.Таймаут; Если ДелатьКонтрольныйВызов И Таймаут <> Неопределено И Таймаут > 20 Тогда ПараметрыПодключения.Таймаут = 7; WSПроксиPing = РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения); Попытка WSПроксиPing.Ping(); Исключение АдресТочкиПодключения = WSПроксиPing.ТочкаПодключения.Местоположение; ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось проверить доступность web-сервиса |%1 |по причине: |%2'"), ПараметрыПодключения.АдресWSDL, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); Если ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда МодульПолучениеФайловИзИнтернета = ОбщийМодуль("ПолучениеФайловИзИнтернета"); РезультатДиагностики = МодульПолучениеФайловИзИнтернета.ДиагностикаСоединения(АдресТочкиПодключения,, ПараметрыПодключения.ПроверятьДоставкуПакетовПриОшибке); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = '%1 |Результат диагностики: |%2'"), ТекстОшибки, РезультатДиагностики.ОписаниеОшибки); КонецЕсли; ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаСети); КонецПопытки; ПараметрыПодключения.Таймаут = Таймаут; КонецЕсли; Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения); КонецФункции #Область ВерсионированиеПрограммныхИнтерфейсов // Возвращает номера версий программных интерфейсов удаленной системы, доступной через веб-сервис. // Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах // с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии, // то только в этом случае допустимо вызывать у него новую функцию. // // В целях экономии трафика при интенсивном взаимодействии между вызывающей и вызываемой сторонами // сведения о версиях кэшируются на одни сутки. Если для целей отладки требуется сбросить кэш раньше этого времени, // следует удалить соответствующие записи из регистра сведений КэшПрограммныхИнтерфейсов. // // Параметры: // Адрес - Строка - адрес веб-сервиса версионирования интерфейсов InterfaceVersion; // Пользователь - Строка - имя пользователя веб-сервиса; // Пароль - Строка - пароль пользователя веб-сервиса; // Интерфейс - Строка - имя запрашиваемого программного интерфейса, например, "СервисПередачиФайлов"; // ПроверятьДоставкуПакетовПриОшибке - см. ПолучениеФайловИзИнтернета.ДиагностикаСоединения.ПроверятьДоставкуПакетов // // Возвращаемое значение: // ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса. // Например, "1.0.2.1". // // Пример: // Версии = ПолучитьВерсииИнтерфейса("http://vsrvx/sm", "ivanov",, "СервисПередачиФайлов"); // // Также для обратной совместимости поддерживается устаревший вариант вызова: // ПараметрыПодключения = Новый Структура; // ПараметрыПодключения.Вставить("URL", "http://vsrvx/sm"); // ПараметрыПодключения.Вставить("UserName", "ivanov"); // ПараметрыПодключения.Вставить("Password", ""); // Версии = ПолучитьВерсииИнтерфейса(ПараметрыПодключения, "СервисПередачиФайлов"); // Функция ПолучитьВерсииИнтерфейса(Знач Адрес, Знач Пользователь, Знач Пароль = Неопределено, Знач Интерфейс = Неопределено, Знач ПроверятьДоставкуПакетовПриОшибке = Истина) Экспорт Если ТипЗнч(Адрес) = Тип("Структура") Тогда // для обратной совместимости ПараметрыПодключения = Адрес; ИмяИнтерфейса = Пользователь; Иначе ПараметрыПодключения = Новый Структура; ПараметрыПодключения.Вставить("URL", Адрес); ПараметрыПодключения.Вставить("UserName", Пользователь); ПараметрыПодключения.Вставить("Password", Пароль); ИмяИнтерфейса = Интерфейс; КонецЕсли; ПараметрыПодключения.Вставить("ПроверятьДоставкуПакетовПриОшибке", ПроверятьДоставкуПакетовПриОшибке); Если Не ПараметрыПодключения.Свойство("URL") Или Не ЗначениеЗаполнено(ПараметрыПодключения.URL) Тогда ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение параметра %1 функции %2. Не задан URL сервиса.'"), "ПараметрыПодключения", "ОбщегоНазначения.ПолучитьВерсииИнтерфейса"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ПараметрыПолучения = Новый Массив; ПараметрыПолучения.Добавить(ПараметрыПодключения); ПараметрыПолучения.Добавить(ИмяИнтерфейса); Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ДанныеКэшаВерсий( РегистрыСведений.КэшПрограммныхИнтерфейсов.ИдентификаторЗаписиКэшаВерсий(ПараметрыПодключения.URL, ИмяИнтерфейса), Перечисления.ТипыДанныхКэшаПрограммныхИнтерфейсов.ВерсииИнтерфейса, ПараметрыПолучения, Истина); КонецФункции // Возвращает номера версий программных интерфейсов удаленной системы, подключенной через внешнее соединение. // Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах // с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии, // то только в этом случае допустимо вызывать у него новую функцию. // // Параметры: // ВнешнееСоединение - COMОбъект - внешнее соединение, которое используется для работы с удаленной системой. // ИмяИнтерфейса - Строка - имя запрашиваемого программного интерфейса, например "СервисПередачиФайлов". // // Возвращаемое значение: // ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса. // Например "1.0.2.1". // // Пример: // Версии = ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, "СервисПередачиФайлов"); // Функция ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, Знач ИмяИнтерфейса) Экспорт Попытка ВерсииИнтерфейсаXML = ВнешнееСоединение.СтандартныеПодсистемыСервер.ПоддерживаемыеВерсии(ИмяИнтерфейса); Исключение СтрокаСообщения = НСтр("ru = 'Корреспондент не поддерживает версионирование программных интерфейсов. |Описание ошибки: %1'"); СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); ЗаписьЖурналаРегистрации(НСтр("ru = 'Получение версий интерфейса'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , СтрокаСообщения); Возврат Новый ФиксированныйМассив(Новый Массив); КонецПопытки; Возврат Новый ФиксированныйМассив(ЗначениеИзСтрокиXML(ВерсииИнтерфейсаXML)); КонецФункции // Удаляет записи кэша версий программных интерфейсов, содержащих в идентификаторе указанную подстроку. // В качестве подстроки может использоваться, например, имя интерфейса, более не используемого в конфигурации. // // Параметры: // ПодстрокаПоискаИдентификаторов - Строка - подстрока поиска идентификаторов. // Не может содержать символов %, _ и [. // Процедура УдалитьЗаписиКэшаВерсий(Знач ПодстрокаПоискаИдентификаторов) Экспорт НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов"); Блокировка.Заблокировать(); ТекстЗапроса = "ВЫБРАТЬ | ТаблицаКэша.Идентификатор КАК Идентификатор, | ТаблицаКэша.ТипДанных КАК ТипДанных |ИЗ | РегистрСведений.КэшПрограммныхИнтерфейсов КАК ТаблицаКэша |ГДЕ | ТаблицаКэша.Идентификатор ПОДОБНО ""%ПодстрокаПоиска%"" СПЕЦСИМВОЛ ""~"""; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПодстрокаПоиска", СформироватьСтрокуДляПоискаВЗапросе(ПодстрокаПоискаИдентификаторов)); Запрос = Новый Запрос(ТекстЗапроса); Результат = Запрос.Выполнить(); Выборка = Результат.Выбрать(); Пока Выборка.Следующий() Цикл Запись = РегистрыСведений.КэшПрограммныхИнтерфейсов.СоздатьМенеджерЗаписи(); Запись.Идентификатор = Выборка.Идентификатор; Запись.ТипДанных = Выборка.ТипДанных; Запись.Удалить(); КонецЦикла; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецПроцедуры // Список версий программных интерфейсов, доступных через web-сервис InterfaceVersions. // // Возвращаемое значение: // Структура: // * Ключ - Строка - имя программного интерфейса // * Значение - Массив из Строка - поддерживаемые версии интерфейса. // Функция ВерсииИнтерфейсов() Экспорт Результат = Новый Структура; ИнтеграцияПодсистемБСП.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Результат); ОбщегоНазначенияПереопределяемый.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Результат); Возврат Результат; КонецФункции #КонецОбласти #КонецОбласти #Область БезопасноеХранилище //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с хранилищем паролей. // Записывает конфиденциальные данные в безопасное хранилище. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или строка до 128 символов. // Для объектов других типов в качестве владельца рекомендуется использовать ссылку на // элемент метаданных этого типа в справочнике ИдентификаторыОбъектовМетаданных // или ключ в виде строки с учетом имен подсистем. // Например, для БСП: // Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("РегистрСведений.АдресныеОбъекты"); // если нужно 1 хранилище на подсистему БСП: // Владелец = "СтандартныеПодсистемы.УправлениеДоступом"; // если нужно более 1 хранилища на подсистему БСП: // Владелец = "СтандартныеПодсистемы.УправлениеДоступом.<Уточнение>"; // Данные - Произвольный - данные помещаемые в безопасное хранилище. Неопределенно - удаляет все данные. // Для удаления данных по ключу следует использовать процедуру УдалитьДанныеИзБезопасногоХранилища. // - Структура - если параметр Ключ содержит Неопределено. Подробнее см. описание параметра Ключ // Ключ - Строка - ключ сохраняемых настроек, по умолчанию "Пароль". // Ключ должен соответствовать правилам имен идентификаторов: // 1. Первым символом ключа должна быть буква или символ подчеркивания (_). // 2. Каждый из последующих символов может быть буквой, цифрой или символом подчеркивания (_). // Неопределено - для добавления набора данных структурой, где ключ структуры - это имя ключа данных, // а значение - сохраняемые данные. Пример использования см. ниже. // // Пример: // // Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) // Если ТекущийПользовательМожетИзменятьПароль Тогда // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Логин, "Логин"); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Пароль); // УстановитьПривилегированныйРежим(Ложь); // КонецЕсли; // КонецПроцедуры // // Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) // Если ТекущийПользовательМожетИзменятьПароль Тогда // ЛогинИПароль = Новый Структура; // ЛогинИПароль.Вставить("Логин", Логин); // ЛогинИПароль.Вставить("Пароль", Пароль); // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, ЛогинИПароль, Неопределено); // УстановитьПривилегированныйРежим(Ложь); // КонецЕсли; // КонецПроцедуры // Процедура ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ = "Пароль") Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |параметр должен содержать ссылку; передано значение: %3 (тип %4).'"), "Владелец", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Владелец, ТипЗнч(Владелец))); Если ЗначениеЗаполнено(Ключ) Тогда ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Ключ) = Тип("Строка"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |параметр должен содержать строку; передано значение: %3 (тип %4).'"), "Ключ", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Ключ, ТипЗнч(Ключ))); Иначе ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Данные) = Тип("Структура"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |Если Ключ = Неопределено, то параметр должен содержать структуру; передано значение: %3 (тип %4).'"), "Данные", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Данные, ТипЗнч(Данные))); КонецЕсли; Блокировка = Новый БлокировкаДанных(); ЭтоОбластьДанных = РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных(); Если ЭтоОбластьДанных Тогда БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи(); ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных"); Иначе БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи(); ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанных"); КонецЕсли; БезопасноеХранилищеДанных.Владелец = Владелец; ЭлементБлокировки.УстановитьЗначение("Владелец", Владелец); НачатьТранзакцию(); Попытка Блокировка.Заблокировать(); Если Данные <> Неопределено Тогда БезопасноеХранилищеДанных.Прочитать(); Если БезопасноеХранилищеДанных.Выбран() Тогда ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить(); Если ТипЗнч(ДанныеДляСохранения) <> Тип("Структура") Тогда ДанныеДляСохранения = Новый Структура(); КонецЕсли; Если ЗначениеЗаполнено(Ключ) Тогда ДанныеДляСохранения.Вставить(Ключ, Данные); Иначе ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ДанныеДляСохранения, Данные, Истина); КонецЕсли; Иначе ДанныеДляСохранения = ?(ЗначениеЗаполнено(Ключ), Новый Структура(Ключ, Данные), Данные); БезопасноеХранилищеДанных.Владелец = Владелец; КонецЕсли; ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(9)); БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения; БезопасноеХранилищеДанных.Записать(); Иначе БезопасноеХранилищеДанных.Удалить(); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецПроцедуры // Возвращает данные из безопасного хранилища. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владельцы - Массив из ПланОбменаСсылка // - Массив из СправочникСсылка // - Массив из Строка - ссылки на объекты информационной базы, // представляющих объекты-владельцы или уникальные строки(до 128 символов) владельцев данных. // Ключи - Строка - содержит имя ключа данных или список имен ключей, указанных через запятую. // - Неопределено - будут возвращены все сохраненные данные переданных владельцев. // ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме. // ОбластьДанных - Число - содержит номер области данных для которой необходимо выполнить получение данных из // безопасного хранилища области данных. Параметр следует передавать только в случае получения // данных из неразделенного сеанса для области данных. Во всех остальных случаях параметр // игнорируется. // Неопределено - режим получения данных из безопасного хранилища определяется автоматический // по доступности использования разделенных данных. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы // или строка до 128 символов идентифицирующая владельца данных. // * Значение - Произвольный - если в параметре Ключи указан один ключ, // то возвращается его значение произвольного типа. // - Структура - если в параметре Ключи указано несколько ключей или Неопределено, // где ключ структуры - это имя ключа сохраненных данных, // а значение - данные произвольного типа. Когда для ключа отсутствуют данные, // то значение содержит Неопределено. // - Неопределено - если данные по ключу отсутствуют. // // Пример: // Процедура РассылкаПриглашений(Пользователи) // // УстановитьПривилегированныйРежим(Истина); // ДанныеАвторизации = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Пользователи, "Логин, Пароль"); // УстановитьПривилегированныйРежим(Ложь); // // Для каждого Пользователь Из Пользователи Цикл // ОтправитьПриглашение(Пользователь, ДанныеАвторизации[Пользователь]); // КонецЦикла; // // КонецПроцедуры // Функция ПрочитатьДанныеВладельцевИзБезопасногоХранилища( Владельцы, Ключи = "Пароль", ОбщиеДанные = Неопределено, ОбластьДанных = Неопределено) Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Владельцы) = Тип("Массив"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |параметр должен содержать массив; передано значение: %3 (тип %4).'"), "Владельцы", "ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища", Владельцы, ТипЗнч(Владельцы))); Если ЗначениеЗаполнено(ОбластьДанных) Тогда ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(ОбластьДанных) = Тип("Число"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |параметр должен содержать строку; передано значение: %3 (тип %4).'"), "ОбластьДанных", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", ОбластьДанных, ТипЗнч(ОбластьДанных))); КонецЕсли; Возврат ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных); КонецФункции // Возвращает данные из безопасного хранилища. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов). // Ключи - Строка - содержит список имен сохраненных данных, указанных через запятую. // - Неопределено - будут возвращены все сохраненные данные владельца. // ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме. // ОбластьДанных - Число - содержит номер области данных для которой необходимо выполнить получение данных из // безопасного хранилища области данных. Параметр следует передавать только в случае получения // данных из неразделенного сеанса для области данных. Во всех остальных случаях параметр // игнорируется. // Неопределено - режим получения данных из безопасного хранилища определяется автоматический // по доступности использования разделенных данных. // // Возвращаемое значение: // Произвольный, Структура, Неопределено - данные из безопасного хранилища. Если указан один ключ, // то возвращается его значение, иначе структура. // Если данные отсутствуют - Неопределенно. // // Пример: // Если ТекущийПользовательМожетИзменятьПароль Тогда // УстановитьПривилегированныйРежим(Истина); // Логин = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, "Логин"); // Пароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка); // УстановитьПривилегированныйРежим(Ложь); // Иначе // Элементы.ГруппаЛогинИПароль.Видимость = Ложь; // КонецЕсли; // // УстановитьПривилегированныйРежим(Истина); // ЛогинИПароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, Неопределено); // Функция ПрочитатьДанныеИзБезопасногоХранилища( Владелец, Ключи = "Пароль", ОбщиеДанные = Неопределено, ОбластьДанных = Неопределено) Экспорт Владельцы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец); ДанныеВладельца = ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных); Возврат ДанныеВладельца[Владелец]; КонецФункции // Удаляет конфиденциальные данные в безопасное хранилище. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов). // - Массив - ссылки на объекты информационной базы для удаления данным по нескольким владельцам. // Ключи - Строка - содержит список имен удаляемых данных, указанных через запятую. // Неопределено - удаляет все данные. // // Пример: // Процедура ПередУдалением(Отказ) // // // Проверка значения свойства ОбменДанными.Загрузка отсутствует, так как удалять данные // // из безопасного хранилища нужно даже при удалении объекта при обмене данными. // // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(Ссылка); // УстановитьПривилегированныйРежим(Ложь); // // КонецПроцедуры // Процедура УдалитьДанныеИзБезопасногоХранилища(Знач Владелец, Знач Ключи = Неопределено) Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Недопустимое значение параметра %1 в %2. |параметр должен содержать ссылку; передано значение: %3 (тип %4).'"), "Владелец", "ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища", Владелец, ТипЗнч(Владелец))); Блокировка = Новый БлокировкаДанных(); Владельцы = ?(ТипЗнч(Владелец) = Тип("Массив"), Владелец, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец)); Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи(); ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных"); Иначе БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи(); ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанных"); КонецЕсли; Для каждого ВладелецДанных Из Владельцы Цикл ЭлементБлокировки.УстановитьЗначение("Владелец", ВладелецДанных); КонецЦикла; НачатьТранзакцию(); Попытка Блокировка.Заблокировать(); Для Каждого ВладелецДанных Из Владельцы Цикл БезопасноеХранилищеДанных.Владелец = ВладелецДанных; БезопасноеХранилищеДанных.Прочитать(); Если ТипЗнч(БезопасноеХранилищеДанных.Данные) = Тип("ХранилищеЗначения") Тогда ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить(); Если Ключи <> Неопределено И ТипЗнч(ДанныеДляСохранения) = Тип("Структура") Тогда СписокКлючей = СтрРазделить(Ключи, ",", Ложь); Если БезопасноеХранилищеДанных.Выбран() И СписокКлючей.Количество() > 0 Тогда Для каждого КлючДляУдаления Из СписокКлючей Цикл Если ДанныеДляСохранения.Свойство(КлючДляУдаления) Тогда ДанныеДляСохранения.Удалить(КлючДляУдаления); КонецЕсли; КонецЦикла; БезопасноеХранилищеДанных.Данные = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(9)); БезопасноеХранилищеДанных.Записать(); Продолжить; КонецЕсли; КонецЕсли; КонецЕсли; БезопасноеХранилищеДанных.Удалить(); КонецЦикла; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецПроцедуры #КонецОбласти #Область БуферОбмена //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с внутренним буфером обмена. // Помещает выделенные строки табличной части во внутренний буфер обмена // откуда их можно получить с помощью СтрокиИзБуфераОбмена. // // Параметры: // ТабличнаяЧасть - ДанныеФормыКоллекция - табличная часть, строки которой // необходимо поместить во внутренний буфер обмена. // ВыделенныеСтроки - Массив - массив идентификаторов выделенных строк. // Источник - Строка - произвольный строковый идентификатор, например, имя объекта, // строки табличной части которого помещаются во внутренний буфер обмена. // Процедура СкопироватьСтрокиВБуферОбмена(ТабличнаяЧасть, ВыделенныеСтроки, Источник = Неопределено) Экспорт Если ВыделенныеСтроки = Неопределено Тогда Возврат; КонецЕсли; ТаблицаЗначений = ТабличнаяЧасть.Выгрузить(); ТаблицаЗначений.Очистить(); УдаляемыеКолонки = Новый Массив; УдаляемыеКолонки.Добавить("ИсходныйНомерСтроки"); УдаляемыеКолонки.Добавить("НомерСтроки"); Для Каждого ИмяКолонки Из УдаляемыеКолонки Цикл Колонка = ТаблицаЗначений.Колонки.Найти(ИмяКолонки); Если Колонка = Неопределено Тогда Продолжить; КонецЕсли; ТаблицаЗначений.Колонки.Удалить(Колонка); КонецЦикла; Для Каждого ИдентификаторСтроки Из ВыделенныеСтроки Цикл КопируемаяСтрока = ТабличнаяЧасть.НайтиПоИдентификатору(ИдентификаторСтроки); ЗаполнитьЗначенияСвойств(ТаблицаЗначений.Добавить(), КопируемаяСтрока); КонецЦикла; СкопироватьВБуферОбмена(ТаблицаЗначений, Источник); КонецПроцедуры // Помещает произвольные данные во внутренний буфер обмена, откуда их можно получить с помощью СтрокиИзБуфераОбмена. // // Параметры: // Данные - Произвольный - данные, которые необходимо поместить в внутренний буфер обмена. // Источник - Строка - произвольный строковый идентификатор, например, имя объекта, // строки табличной части которого помещаются во внутренний буфер обмена. // Процедура СкопироватьВБуферОбмена(Данные, Источник = Неопределено) Экспорт ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; Если ЗначениеЗаполнено(ТекущийБуферОбмена.Данные) Тогда Адрес = ТекущийБуферОбмена.Данные; Иначе Адрес = Новый УникальныйИдентификатор; КонецЕсли; ДанныеВХранилище = ПоместитьВоВременноеХранилище(Данные, Адрес); СтруктураБуфераОбмена = Новый Структура; СтруктураБуфераОбмена.Вставить("Источник", Источник); СтруктураБуфераОбмена.Вставить("Данные", ДанныеВХранилище); ПараметрыСеанса.БуферОбмена = Новый ФиксированнаяСтруктура(СтруктураБуфераОбмена); КонецПроцедуры // Получает строки табличной части, помещенные во внутренний буфер обмена с помощью СкопироватьСтрокиВБуферОбмена. // // Возвращаемое значение: // Структура: // * Данные - Произвольный - данные из внутреннего буфера обмена. // Например, ТаблицаЗначений при вызове СкопироватьСтрокиВБуферОбмена. // * Источник - Строка - объект, к которому относятся данные. // Если при помещении во внутренний буфер не был указан, то Неопределено. // Функция СтрокиИзБуфераОбмена() Экспорт Результат = Новый Структура; Результат.Вставить("Источник", Неопределено); Результат.Вставить("Данные", Неопределено); Если ПустойБуферОбмена() Тогда Возврат Результат; КонецЕсли; ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена Результат.Источник = ТекущийБуферОбмена.Источник; Результат.Данные = ПолучитьИзВременногоХранилища(ТекущийБуферОбмена.Данные); Возврат Результат; КонецФункции // Проверяет наличие сохраненных данных во внутренний буфере обмена. // // Параметры: // Источник - Строка - если передан, то проверяется наличие данных // в внутреннем буфере обмена с этим ключом. // По умолчанию - Неопределено. // Возвращаемое значение: // Булево - Истина, если пустой. // Функция ПустойБуферОбмена(Источник = Неопределено) Экспорт ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена ИсточникСовпадает = Истина; Если Источник <> Неопределено Тогда ИсточникСовпадает = (Источник = ТекущийБуферОбмена.Источник); КонецЕсли; Возврат (Не ИсточникСовпадает Или Не ЗначениеЗаполнено(ТекущийБуферОбмена.Данные)); КонецФункции #КонецОбласти #Область БезопасноеВыполнениеВнешнегоКода // Запускает фоновое задание с проверкой вызываемой процедуры. // // Параметры: // ИмяМетода - Строка - также как у метода платформы ФоновыеЗадания.Выполнить. // ПараметрыВыполнения - см. НовыеПараметрыВыполненияФоновогоЗадания // - Неопределено - использовать значения по умолчанию. // // Возвращаемое значение: // ФоновоеЗадание - также как у метода платформы ФоновыеЗадания.Выполнить. // Функция ВыполнитьФоновоеЗадание(Знач ИмяМетода, Знач ПараметрыВыполнения = Неопределено) Экспорт Если ПараметрыВыполнения = Неопределено Тогда ПараметрыВыполнения = НовыеПараметрыВыполненияФоновогоЗадания(); КонецЕсли; Попытка СтандартныеПодсистемыСервер.ПроверитьМетодДляВызоваКакПроизвольныйКод(ИмяМетода, Истина); Исключение ИнформацияОбОшибке = ИнформацияОбОшибке(); ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильное значение параметра %1 (передано значение: ""%2"") в %3:'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьФоновоеЗадание"); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, ЗаголовокОшибки); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; Если ПараметрыВыполнения.СРасширениямиБазыДанных = Истина Тогда ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных(ИмяМетода, ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование); ИначеЕсли ПараметрыВыполнения.СРасширениямиБазыДанных = Ложь Тогда ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеБезРасширений(ИмяМетода, ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование); Иначе ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяМетода, ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование); КонецЕсли; Возврат ФоновоеЗадание; КонецФункции // Конструктор параметров для функции ВыполнитьФоновоеЗадание. // // Возвращаемое значение: // Структура: // * Параметры - Неопределено - значение по умолчанию. // - Массив - также как у метода платформы ФоновыеЗадания.Выполнить. // // * Ключ - Неопределено - значение по умолчанию. // - Строка - также как у метода платформы ФоновыеЗадания.Выполнить. // // * Наименование - Неопределено - значение по умолчанию. // - Строка - также как у метода платформы ФоновыеЗадания.Выполнить. // // * СРасширениямиБазыДанных - Неопределено - ФоновыеЗадания.Выполнить // - Булево - Истина - РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных // Ложь - РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеБезРасширений // Функция НовыеПараметрыВыполненияФоновогоЗадания() Экспорт Результат = Новый Структура; Результат.Вставить("Параметры"); Результат.Вставить("Ключ"); Результат.Вставить("Наименование"); Результат.Вставить("СРасширениямиБазыДанных"); Возврат Результат; КонецФункции //////////////////////////////////////////////////////////////////////////////// // Функции для поддержки работы конфигурации с профилем безопасности, в котором // запрещено подключение внешних модулей без установки безопасного режима. // // Выполнить экспортную процедуру или функцию по имени с уровнем привилегий конфигурации. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемым для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // ИмяМетода - Строка - имя экспортной процедуры или функции в формате // <имя объекта>.<имя процедуры или функции>, где <имя объекта> - это // общий модуль или модуль менеджера объекта. // Параметры - Массив - параметры передаются в процедуру или функцию <ИмяМетода> // в порядке расположения элементов массива. // ЭтоФункция - Булево - указать Истина, если вызывается функция. // // Возвращаемое значение: // Произвольный - если это функция, иначе Неопределено. // // Пример: // Параметры = Новый Массив(); // Параметры.Добавить("1"); // ОбщегоНазначения.ВыполнитьМетодКонфигурации("МойОбщийМодуль.МояПроцедура", Параметры); // Функция ВыполнитьМетодКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено, ЭтоФункция = Ложь) Экспорт ПрофильБезопасностиИБ = СтандартныеПодсистемыСервер.ПрофильБезопасностиДляВыполнитьВычислить(); Если ЗначениеЗаполнено(ПрофильБезопасностиИБ) Тогда УстановитьБезопасныйРежим(ПрофильБезопасностиИБ); КонецЕсли; СтрокаВызова = СтрокаВызоваМетодаКакПроизвольногоКода(ИмяМетода, Параметры); Если ЭтоФункция Тогда Возврат Вычислить(СтрокаВызова); // АПК:488 Исполняемый код безопасен. КонецЕсли; Выполнить(СтрокаВызова); // АПК:487 Исполняемый код безопасен. КонецФункции // Выполнить экспортную процедуру или функцию объекта по имени. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемым для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // ОбъектМетода - ПланОбменаОбъект // - КонстантаМенеджерЗначения // - СправочникОбъект // - ДокументОбъект // - ПоследовательностьНаборЗаписей // - ОтчетОбъект // - ОбработкаОбъект // - ПланВидовХарактеристикОбъект // - ПланСчетовОбъект // - ПланВидовРасчетаОбъект // - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей // - ПерерасчетНаборЗаписей // - БизнесПроцессОбъект // - ЗадачаОбъект // - ВнешнийИсточникДанныхТаблицаОбъект // - ВнешнийИсточникДанныхТаблицаНаборЗаписей // - ВнешнийИсточникДанныхКубНаборЗаписей // - ВнешнийИсточникДанныхКубТаблицаИзмеренияОбъект // // ИмяМетода - Строка - имя экспортной процедуры модуля объекта обработки. // Параметры - Массив - параметры передаются в процедуру <ИмяПроцедуры> // в порядке расположения элементов массива. // ЭтоФункция - Булево - указать Истина, если вызывается функция. // // Возвращаемое значение: // Произвольный - если это функция, иначе Неопределено. // Функция ВыполнитьМетодОбъекта(Знач ОбъектМетода, Знач ИмяМетода, Знач Параметры = Неопределено, ЭтоФункция = Ложь) Экспорт ПрофильБезопасностиИБ = СтандартныеПодсистемыСервер.ПрофильБезопасностиДляВыполнитьВычислить(); Если ЗначениеЗаполнено(ПрофильБезопасностиИБ) Тогда УстановитьБезопасныйРежим(ПрофильБезопасностиИБ); КонецЕсли; СтрокаВызова = СтрокаВызоваМетодаКакПроизвольногоКода(ИмяМетода, Параметры, ОбъектМетода); Если ЭтоФункция Тогда Возврат Вычислить(СтрокаВызова); // АПК:488 Исполняемый код безопасен. КонецЕсли; Выполнить(СтрокаВызова); // АПК:487 Исполняемый код безопасен. КонецФункции // Выполняет произвольный алгоритм на встроенном языке 1С:Предприятия, предварительно устанавливая // безопасный режим выполнения кода и безопасный режим разделения данных для всех разделителей, // присутствующих в составе конфигурации. // // Для выполняемого кода так же применяются дополнительные ограничения, запрещается: // // 1) Вызов методов платформы: // - Выполнить // - Вычислить // - Подключить (для внешних обработок) // - НачатьТранзакцию // - ОтменитьТранзакцию // - ЗафиксироватьТранзакцию // - СократитьЖурналРегистрации // - УстановитьИспользованиеСобытияЖурналаРегистрации // - ЗапуститьПриложение // - Base64Значение // - ЗначениеИзСтрокиВнутр // - XMLЗначение // // 2) Вызов общих модулей и свойств глобального контекста: // - ДлительныеОперации // - ПользователиИнформационнойБазы // // 3) Вызов процедур и функций БСП: // - ВыполнитьМетодОбъекта // - ВыполнитьМетодКонфигурации // - ВыполнитьФоновоеЗадание // - ОбщийМодуль // - ЗначениеИзСтрокиXML // // Помимо этого рекомендуется вызывать метод вне транзакции, тогда выполняемый код будет // автоматически выполнен в транзакции с ее отменой по завершении, что позволит более // надежно защититься от изменения данных выполняемым кодом. // // Параметры: // Алгоритм - Строка - алгоритм на встроенном языке "1С:Предприятия". // Параметры - Произвольный - контекст, который требуется для выполнения алгоритма. // В тексте алгоритма обращение к контексту должно происходить по имени "Параметры". // Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям // "Значение1" и "Значение2", переданным в Параметры, как свойства. // ПараметрыПроверкиАлгоритма - см. ОбщегоНазначения.ПараметрыПроверкиАлгоритма // Позволяет указать список методов, модулей и свойств глобального контекста, использование // которых не допускается при выполнении алгоритма. Дополняет базовую проверку. // // Пример: // // // Пример 1 // Параметры = Новый Структура; // Параметры.Вставить("Значение1", 1); // Параметры.Вставить("Значение2", 10); // ОбщегоНазначения.ВыполнитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры); // // // Пример 2 // Параметры = Новый Структура; // Параметры.Вставить("Источник", Источник); // Параметры.Вставить("Результат", Неопределено); // ПараметрыПроверкиАлгоритма = ОбщегоНазначения.ПараметрыПроверкиАлгоритма(); // ПараметрыПроверкиАлгоритма.НедопустимыеМетоды.Добавить("Записать"); // ПараметрыПроверкиАлгоритма.НедопустимыеМетоды.Добавить("Base64Значение"); // ОбщегоНазначения.ВыполнитьВБезопасномРежиме(ВычисляемоеВыражение, Параметры, ПараметрыПроверкиАлгоритма); // Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено, Знач ПараметрыПроверкиАлгоритма = Неопределено) Экспорт ПроверитьАлгоритм(Алгоритм, ПараметрыПроверкиАлгоритма); УстановитьБезопасныйРежим(Истина); Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации(); Иначе МассивРазделителей = Новый Массив; КонецЕсли; Для Каждого ИмяРазделителя Из МассивРазделителей Цикл УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина); КонецЦикла; Попытка Если ТранзакцияАктивна() Тогда Выполнить Алгоритм; // АПК:487 Код выполняется в безопасном режиме. Иначе НачатьТранзакцию(); // АПК:326 принудительная отмена транзакции Попытка Выполнить Алгоритм; // АПК:487 Код выполняется в безопасном режиме. ОтменитьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецЕсли; Исключение ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); ВызватьИсключение(Уточнение.Текст, КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных ,,, ИнформацияОбОшибке); КонецПопытки; КонецПроцедуры // Вычисляет переданное выражение, предварительно устанавливая безопасный режим выполнения кода // и безопасный режим разделения данных для всех разделителей, присутствующих в составе конфигурации. // // Для выполняемого кода так же применяются дополнительные ограничения, запрещается: // // 1) Вызов методов платформы: // - Выполнить // - Вычислить // - Подключить (для внешних обработок) // - НачатьТранзакцию // - ОтменитьТранзакцию // - ЗафиксироватьТранзакцию // - СократитьЖурналРегистрации // - УстановитьИспользованиеСобытияЖурналаРегистрации // - ЗапуститьПриложение // - Base64Значение // - ЗначениеИзСтрокиВнутр // - XMLЗначение // // 2) Вызов общих модулей и свойств глобального контекста: // - ДлительныеОперации // - ПользователиИнформационнойБазы // // 3) Вызов процедур и функций БСП: // - ВыполнитьМетодОбъекта // - ВыполнитьМетодКонфигурации // - ВыполнитьФоновоеЗадание // - ОбщийМодуль // - ЗначениеИзСтрокиXML // // Помимо этого рекомендуется вызывать метод вне транзакции, тогда выполняемый код будет // автоматически выполнен в транзакции с ее отменой по завершении, что позволит более // надежно защититься от изменения данных выполняемым кодом. // // Параметры: // Выражение - Строка - выражение на встроенном языке 1С:Предприятия. // Параметры - Произвольный - контекст, который требуется для вычисления выражения. // В тексте выражения обращение к контексту должно происходить по имени "Параметры". // Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям // "Значение1" и "Значение2" переданные в Параметры, как свойства. // ПараметрыПроверкиАлгоритма - см. ОбщегоНазначения.ПараметрыПроверкиАлгоритма // Позволяет указать список методов, модулей и свойств глобального контекста, использование // которых не допускается при выполнении алгоритма. Дополняет базовую проверку. // // Возвращаемое значение: // Произвольный - результат вычисления выражения. // // Пример: // // // Пример 1 // Параметры = Новый Структура; // Параметры.Вставить("Значение1", 1); // Параметры.Вставить("Значение2", 10); // Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры); // // // Пример 2 // Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("СтандартныеПодсистемыСервер.ВерсияБиблиотеки()"); // Функция ВычислитьВБезопасномРежиме(Знач Выражение, Знач Параметры = Неопределено, Знач ПараметрыПроверкиАлгоритма = Неопределено) Экспорт ПроверитьАлгоритм(Выражение, ПараметрыПроверкиАлгоритма); УстановитьБезопасныйРежим(Истина); Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации(); Иначе МассивРазделителей = Новый Массив; КонецЕсли; Для Каждого ИмяРазделителя Из МассивРазделителей Цикл УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина); КонецЦикла; Попытка Если ТранзакцияАктивна() Тогда Результат = Вычислить(Выражение); // АПК:488 Код выполняется в безопасном режиме. Иначе НачатьТранзакцию(); // АПК:326 принудительная отмена транзакции Попытка Результат = Вычислить(Выражение); // АПК:488 Код выполняется в безопасном режиме. ОтменитьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецЕсли; Возврат Результат; Исключение ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); ВызватьИсключение(Уточнение.Текст, КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных ,,, ИнформацияОбОшибке); КонецПопытки; КонецФункции // Возвращает строку для вызова указанного метода с параметрами с помощью Выполнить/Вычислить. // См. ВыполнитьМетодКонфигурации и см. ВыполнитьМетодОбъекта. // // Проверяет, что переданное имя метода является именем экспортной процедуры или функции // конфигурации или объекта и не содержит произвольного алгоритма на встроенном языке 1С:Предприятия. // В случае если переданная строка не соответствует требованиям, вызывается исключение. // // Параметры: // ИмяМетода - см. ВыполнитьМетодОбъекта.ИмяМетода // - см. ВыполнитьМетодКонфигурации.ИмяМетода // Параметры - см. ВыполнитьМетодОбъекта.Параметры // - см. ВыполнитьМетодКонфигурации.Параметры // ОбъектМетода - см. ВыполнитьМетодОбъекта.ОбъектМетода // - Неопределено - строка для вызова метода конфигурации. // // Возвращаемое значение: // Строка - если параметр Объект указан, тогда строка в формате // "ОбъектМетода.ИмяМетода(Параметры[0],...)", // если параметр Объект не указан, тогда строка в формате // "ИмяМетода(Параметры[0],...)". // Функция СтрокаВызоваМетодаКакПроизвольногоКода(Знач ИмяМетода, Знач Параметры = Неопределено, Знач ОбъектМетода = Неопределено) Экспорт Если ОбъектМетода = Неопределено Тогда ЧастиИмени = СтрРазделить(ИмяМетода, "."); Если ЧастиИмени.Количество() <> 2 И ЧастиИмени.Количество() <> 3 Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3.'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода"); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; ИмяОбъекта = ЧастиИмени[0]; Если ЧастиИмени.Количество() = 2 И Метаданные.ОбщиеМодули.Найти(ИмяОбъекта) = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Не существует общий модуль ""%4"".'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ИмяОбъекта); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; Если ЧастиИмени.Количество() = 3 Тогда ПолноеИмяОбъекта = ЧастиИмени[0] + "." + ЧастиИмени[1]; Попытка Менеджер = МенеджерОбъектаПоИмени(ПолноеИмяОбъекта, Истина, Истина, Истина, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", "ИмяМетода"); Исключение Менеджер = Неопределено; КонецПопытки; Если Менеджер = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Не существует менеджер объекта ""%4"".'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ПолноеИмяОбъекта); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; КонецЕсли; ИмяМетодаОбъекта = ЧастиИмени[ЧастиИмени.ВГраница()]; Иначе ИмяМетодаОбъекта = ИмяМетода; СериализованныйТипОбъекта = ЗначениеВСтрокуВнутр(ТипЗнч(ОбъектМетода)); Если Не СтандартныеПодсистемыПовтИсп.ЭтоОбъектСМодулем(СериализованныйТипОбъекта) И Не ЭтоВнешнийОтчетИлиВнешняяОбработка(ОбъектМетода) Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильный формат параметра %1 (передано значение типа: ""%2"") в %3: |Указан недопустимый тип объекта для выполнения метода.'"), "ОбъектМетода", СтроковоеПредставлениеТипа(ТипЗнч(ОбъектМетода)), "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода"); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; КонецЕсли; ВременнаяСтруктура = Новый Структура; Попытка ВременнаяСтруктура.Вставить(ИмяМетодаОбъекта); Исключение ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Имя ""%4"" не соответствует требованиям образования имен процедур и функций.'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ИмяМетодаОбъекта); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); КонецПопытки; Попытка СтандартныеПодсистемыСервер.ПроверитьМетодДляВызоваКакПроизвольныйКод(ИмяМетода,, ОбъектМетода); Исключение ИнформацияОбОшибке = ИнформацияОбОшибке(); ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неправильное значение параметра %1 (передано значение: ""%2"") в %3:'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода"); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, ЗаголовокОшибки); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; ПараметрыСтрока = ""; Если Параметры <> Неопределено Тогда Если ТипЗнч(Параметры) <> Тип("Массив") Тогда ДопустимыеТипы = Новый Массив; ДопустимыеТипы.Добавить(Тип("Неопределено")); ДопустимыеТипы.Добавить(Тип("Массив")); ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", "Параметры", Параметры, ДопустимыеТипы); КонецЕсли; Если Параметры.Количество() > 0 Тогда Для Индекс = 0 По Параметры.ВГраница() Цикл ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],"; КонецЦикла; ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1); КонецЕсли; КонецЕсли; Если ОбъектМетода = Неопределено Тогда Возврат ИмяМетода + "(" + ПараметрыСтрока + ")"; КонецЕсли; Возврат "ОбъектМетода." + ИмяМетода + "(" + ПараметрыСтрока + ")"; КонецФункции // Возвращает описание защиты от опасных действий с отключенными предупреждениями. // // Возвращаемое значение: // ОписаниеЗащитыОтОпасныхДействий - со свойством ПредупреждатьОбОпасныхДействиях = Ложь. // Функция ОписаниеЗащитыБезПредупреждений() Экспорт ОписаниеЗащиты = Новый ОписаниеЗащитыОтОпасныхДействий; ОписаниеЗащиты.ПредупреждатьОбОпасныхДействиях = Ложь; Возврат ОписаниеЗащиты; КонецФункции // Конструктор структуры для параметра ПараметрыПроверкиАлгоритма функций // ОбщегоНазначения.ВыполнитьВБезопасномРежиме и ОбщегоНазначения.ВычислитьВБезопасномРежиме. // // Возвращаемое значение: // Структура: // * НедопустимыеМетоды - Массив из Строка - список методов, вызов которых не допускается при // выполнении алгоритма. // * ЗапрещенныеСвойстваГлобальногоКонтекста - Массив из Строка - список свойств глобального контекста, // обращение к которым не допускается при выполнении алгоритма. // * ЗапрещенныеМодули - Массив из Строка - список модулей, использование которых не допускается при // выполнении алгоритма. // Функция ПараметрыПроверкиАлгоритма() Экспорт ПараметрыПроверки = Новый Структура; ПараметрыПроверки.Вставить("НедопустимыеМетоды", Новый Массив); ПараметрыПроверки.Вставить("ЗапрещенныеСвойстваГлобальногоКонтекста", Новый Массив); ПараметрыПроверки.Вставить("ЗапрещенныеМодули", Новый Массив); Возврат ПараметрыПроверки; КонецФункции #КонецОбласти #Область Запросы // Подготавливает строку для использования в качестве шаблона поиска в запросе с оператором ПОДОБНО. // Экранирует служебные символы, если они есть в строке. // // Параметры: // СтрокаПоиска - Строка - произвольная строка. // // Возвращаемое значение: // Строка // // Пример: // ВЫБРАТЬ // Номенклатура.Ссылка КАК Ссылка // ИЗ // Справочник.Номенклатура КАК Номенклатура // ГДЕ // Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~" // // Запрос.УстановитьПараметр("Шаблон", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИскомыйТекст)); // Функция СформироватьСтрокуДляПоискаВЗапросе(Знач СтрокаПоиска) Экспорт Результат = СтрокаПоиска; Результат = СтрЗаменить(Результат, "~", "~~"); Результат = СтрЗаменить(Результат, "%", "~%"); Результат = СтрЗаменить(Результат, "_", "~_"); Результат = СтрЗаменить(Результат, "[", "~["); Результат = СтрЗаменить(Результат, "]", "~]"); Результат = СтрЗаменить(Результат, "^", "~^"); Возврат Результат; КонецФункции // Возвращает фрагмент текста запроса, отделяющего один запрос от другого. // // Возвращаемое значение: // Строка - разделитель запросов. // Функция РазделительПакетаЗапросов() Экспорт Возврат " |; | |//////////////////////////////////////////////////////////////////////////////// |"; КонецФункции // Возвращает фрагмент текста запроса, объединяющего результаты запросов в один запрос. // // Возвращаемое значение: // Строка // Функция ТекстОбъединитьВсе() Экспорт Возврат " | |ОБЪЕДИНИТЬ ВСЕ | |"; КонецФункции #КонецОбласти #Область Прочее // Выполняет проверки перед выполнением обработчика регламентного задания и прерывает выполнение, // если его запуск в данный момент невозможен, например: // - еще не завершено обновление программы; // - запуск через консоль или другим способом, минуя включение функциональной опции // (если регламентное задание зависит от функциональных опций); // - попытка выполнения задания, работающего с внешними ресурсами в копии информационной базы. // // Параметры: // РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание, // из которого вызывается данная процедура. // // Пример: // ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.<ИмяРегламентногоЗадания>); // Процедура ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание = Неопределено) Экспорт УстановитьПривилегированныйРежим(Истина); Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда Текст = НСтр("ru = 'Вход в приложение временно невозможен в связи с обновлением на новую версию. |Рекомендуется запрещать выполнение регламентных заданий на время обновления.'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Если Не РазделениеВключено() И ПланыОбмена.ГлавныйУзел() = Неопределено И ЗначениеЗаполнено(Константы.ГлавныйУзел.Получить()) Тогда Текст = НСтр("ru = 'Вход в приложение временно невозможен до восстановления связи с главным узлом. |Рекомендуется запрещать выполнение регламентных заданий на время восстановления.'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Если РегламентноеЗадание <> Неопределено И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами"); МодульБлокировкаРаботыСВнешнимиРесурсами.ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание); МодульРегламентныеЗаданияСлужебный = ОбщийМодуль("РегламентныеЗаданияСлужебный"); Доступно = МодульРегламентныеЗаданияСлужебный.РегламентноеЗаданиеДоступноПоФункциональнымОпциям(РегламентноеЗадание); Если Не Доступно Тогда Задания = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", РегламентноеЗадание)); Для Каждого Задание Из Задания Цикл РегламентныеЗаданияСервер.ИзменитьЗадание(Задание.УникальныйИдентификатор, Новый Структура("Использование", Ложь)); КонецЦикла; Текст = НСтр("ru = 'Регламентное задание недоступно по функциональным опциям или |не поддерживает работу в текущем режиме работы. |Выполнение прервано. Задание отключено.'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; КонецЕсли; Если СтандартныеПодсистемыСервер.ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Тогда Текст = НСтр("ru = 'Регламентное задание недоступно до установки начальных региональных настроек приложения. |Выполнение прервано.'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Справочники.ВерсииРасширений.ЗарегистрироватьИспользованиеВерсииРасширений(); РегистрыСведений.ПараметрыРаботыВерсийРасширений.ПриУспешномНачалеВыполненияРегламентногоЗадания(); КонецПроцедуры // Переводит параметры сеанса в состояние "Не установлено". // // Параметры: // ПараметрыДляОчистки - Строка - имена параметров сеанса для очистки, разделенные ",". // Исключения - Строка - имена параметров сеанса не предназначенные для очистки, разделенные ",". // Процедура ОчиститьПараметрыСеанса(ПараметрыДляОчистки = "", Исключения = "") Экспорт МассивИсключений = СтрРазделить(Исключения, ","); МассивПараметровДляОчистки = СтрРазделить(ПараметрыДляОчистки, ",", Ложь); Если МассивПараметровДляОчистки.Количество() = 0 Тогда Для Каждого ПараметрСеанса Из Метаданные.ПараметрыСеанса Цикл Если МассивИсключений.Найти(ПараметрСеанса.Имя) = Неопределено Тогда МассивПараметровДляОчистки.Добавить(ПараметрСеанса.Имя); КонецЕсли; КонецЦикла; КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("ПараметрыКлиентаНаСервере"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("ОсновнойЯзык"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("УстановленныеРасширения"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; ПараметрыСеанса.Очистить(МассивПараметровДляОчистки); КонецПроцедуры // Проверяет, умещаются ли переданные табличные документы на страницу при печати. // // Параметры: // ТабДокумент - ТабличныйДокумент - табличный документ. // ВыводимыеОбласти - Массив // - ТабличныйДокумент - массив из проверяемых таблиц или табличный документ. // РезультатПриОшибке - Булево - какой возвращать результат при возникновении ошибки. // // Возвращаемое значение: // Булево - умещаются или нет переданные документы. // Функция ПроверитьВыводТабличногоДокумента(ТабДокумент, ВыводимыеОбласти, РезультатПриОшибке = Истина) Экспорт Попытка Возврат ТабДокумент.ПроверитьВывод(ВыводимыеОбласти); Исключение Возврат РезультатПриОшибке; КонецПопытки; КонецФункции // Сохраняет персональные настройки пользователя, относящиеся к подсистеме БазоваяФункциональность. // Для получения настроек предусмотрены следующие функции: // - СтандартныеПодсистемыСервер.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы, // - СтандартныеПодсистемыСервер.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы, // - ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботы1СПредприятия. // // Параметры: // Настройки - Структура: // * НапоминатьОбУстановкеРасширенияРаботыСФайлами - Булево - если Истина, то напоминать об установке // расширения для работы с 1С:Предприятием в веб-клиенте. // * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - запрашивать подтверждение по завершении работы. // * ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы - Булево - показывать оповещение при // динамическом обновлении приложения. // Процедура СохранитьПерсональныеНастройки(Настройки) Экспорт Если Настройки.Свойство("НапоминатьОбУстановкеРасширенияРаботыСФайлами") Тогда Если ЭтоВебКлиент() Тогда ИдентификаторКлиента = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИдентификаторКлиента"); Если ИдентификаторКлиента = Неопределено Тогда СистемнаяИнформация = Новый СистемнаяИнформация; ИдентификаторКлиента = СистемнаяИнформация.ИдентификаторКлиента; КонецЕсли; ХранилищеОбщихНастроекСохранить( "НастройкиПрограммы/ПредлагатьУстановкуРасширенияРаботыСФайлами", ИдентификаторКлиента, Настройки.НапоминатьОбУстановкеРасширенияРаботыСФайлами); КонецЕсли; КонецЕсли; Если Настройки.Свойство("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы") Тогда ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя", "ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Настройки.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы); КонецЕсли; Если Настройки.Свойство("ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы") Тогда ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя", "ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы", Настройки.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы); КонецЕсли; КонецПроцедуры // Выполняет пропорциональное распределение суммы в соответствии // с заданными коэффициентами распределения. // // Параметры: // РаспределяемаяСумма - Число - сумма, которую надо распределить, если сумма равна 0 - то возвращается Неопределено; // Если передана отрицательная - расчет по модулю и после инверсия знаков результата. // Коэффициенты - Массив из Число - коэффициенты распределения, должны быть положительны или отрицательными // одновременно. // Точность - Число - точность округления при распределении. // // Возвращаемое значение: // Массив из Число - массив размерностью равный массиву коэффициентов, содержит // суммы в соответствии с весом коэффициента (из массива коэффициентов). // В случае, если распределить невозможно (кол-во коэффициентов = 0 // есть коэффициенты с отрицательным значением или суммарный вес коэффициентов = 0), // тогда будет возвращено Неопределено. // // Пример: // // Коэффициенты = Новый Массив; // Коэффициенты.Добавить(1); // Коэффициенты.Добавить(2); // Результат = ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(1, Коэффициенты); // // Результат = [0.33, 0.67] // Функция РаспределитьСуммуПропорциональноКоэффициентам( Знач РаспределяемаяСумма, Коэффициенты, Знач Точность = 2) Экспорт Возврат ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам( РаспределяемаяСумма, Коэффициенты, Точность); КонецФункции // Процедура предназначена для заполнения реквизита формы типа ДанныеФормыДерево. // // Параметры: // КоллекцияЭлементовДерева - ДанныеФормыКоллекцияЭлементовДерева - реквизит, который нужно заполнить. // ДеревоЗначений - ДеревоЗначений - данные для заполнения. // Процедура ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, ДеревоЗначений) Экспорт Для Каждого СтрокаТаблицы Из ДеревоЗначений.Строки Цикл ЭлементДерева = КоллекцияЭлементовДерева.Добавить(); ЗаполнитьЗначенияСвойств(ЭлементДерева, СтрокаТаблицы); Если СтрокаТаблицы.Строки.Количество() > 0 Тогда ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(ЭлементДерева.ПолучитьЭлементы(), СтрокаТаблицы); КонецЕсли; КонецЦикла; КонецПроцедуры // Подключает внешнюю компоненту, выполненную по технологии Native API или COM, // из макета конфигурации (хранится в виде ZIP-архива). // // Параметры: // Идентификатор - Строка - идентификатор объекта внешней компоненты. // ПолноеИмяМакета - Строка - полное имя макета конфигурации с ZIP-архивом. // Изолированно - Булево - если Истина, компонента должна подключаться изолированно, // в этом случае она загружается в отдельный процесс операционной системы. // Если Ложь, то в этом случае компонента будет выполняться в том же процессе // операционной системы, который выполняет код встроенного языка. // - Неопределено - (по умолчанию Неопределено) соответствует поведению платформы: // не изолированно - если компонентой поддерживается только этот режим, // изолированно - в остальных случаях. // См. https://its.1c.eu/db/v83doc#bookmark:dev:TI000001866 // // Возвращаемое значение: // - ОбъектВнешнейКомпоненты - экземпляр объекта внешней компоненты. // - Неопределено - если не удалось создать. // // Пример: // // ПодключаемыйМодуль = ОбщегоНазначения.ПодключитьКомпонентуИзМакета( // "QRCodeExtension", // "ОбщийМакет.КомпонентаПечатиQRКода"); // // Если ПодключаемыйМодуль <> Неопределено Тогда // // ПодключаемыйМодуль содержит созданный экземпляр подключенной компоненты. // КонецЕсли; // // ПодключаемыйМодуль = Неопределено; // Функция ПодключитьКомпонентуИзМакета(Знач Идентификатор, Знач ПолноеИмяМакета, Знач Изолированно = Неопределено) Экспорт РезультатПроверкиВнешнейКомпоненты = Неопределено; Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный"); РезультатПроверкиВнешнейКомпоненты = МодульВнешниеКомпонентыСлужебный.ПроверитьПодключениеКомпоненты(Идентификатор); РезультатПроверкиВнешнейКомпоненты.Вставить("Доступна", Не ЗначениеЗаполнено(РезультатПроверкиВнешнейКомпоненты.ОписаниеОшибки)); КонецЕсли; КомпонентаПоследнейВерсии = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии( Идентификатор, ПолноеИмяМакета, РезультатПроверкиВнешнейКомпоненты); Результат = ПодключитьКомпонентуПоИдентификатору(Идентификатор, КомпонентаПоследнейВерсии.Местоположение, Изолированно); Возврат Результат.ПодключаемыйМодуль; КонецФункции #КонецОбласти #Область ПереходныеПроцедурыИФункции // Проверяет, что указанный режим соответствует добавлению набора записей. // // Параметры: // Режим - Булево, РежимЗамещения // // Возвращаемое значение: // Булево // Функция ЭтоДобавлениеНабораЗаписей(Режим) Экспорт Значение = СтандартныеПодсистемыПовтИсп.РежимДобавленияНабораЗаписей(); Возврат Значение <> Неопределено И Режим = Значение; КонецФункции // Проверяет, что указанный режим соответствует замещению набора записей. // // Параметры: // Режим - Булево, РежимЗамещения // // Возвращаемое значение: // Булево // Функция ЭтоЗамещениеНабораЗаписей(Режим) Экспорт Значение = СтандартныеПодсистемыПовтИсп.РежимЗамещенияНабораЗаписей(); Возврат Значение <> Неопределено И Режим = Значение; КонецФункции // Проверяет, что указанный режим соответствует обновлению набора записей. // // Параметры: // Режим - Булево, РежимЗамещения // // Возвращаемое значение: // Булево // Функция ЭтоОбновлениеНабораЗаписей(Режим) Экспорт Значение = СтандартныеПодсистемыПовтИсп.РежимОбновленияНабораЗаписей(); Возврат Значение <> Неопределено И Режим = Значение; КонецФункции // Проверяет, что указанный режим соответствует слиянию набора записей. // // Параметры: // Режим - Булево, РежимЗамещения // // Возвращаемое значение: // Булево // Функция ЭтоСлияниеНабораЗаписей(Режим) Экспорт Значение = СтандартныеПодсистемыПовтИсп.РежимСлиянияНабораЗаписей(); Возврат Значение <> Неопределено И Режим = Значение; КонецФункции // Проверяет, что указанный режим соответствует удалению набора записей. // // Параметры: // Режим - Булево, РежимЗамещения // // Возвращаемое значение: // Булево // Функция ЭтоУдалениеНабораЗаписей(Режим) Экспорт Значение = СтандартныеПодсистемыПовтИсп.РежимУдаленияНабораЗаписей(); Возврат Значение <> Неопределено И Режим = Значение; КонецФункции // Возвращает РежимЗамещения.Обновление или Неопределено, // если не поддерживается в текущей версии 1С:Предприятия. // // Возвращаемое значение: // Неопределено, РежимЗамещения // Функция РежимОбновленияНабораЗаписей() Экспорт Возврат СтандартныеПодсистемыПовтИсп.РежимОбновленияНабораЗаписей(); КонецФункции // Возвращает РежимЗамещения.Слияние или Неопределено, // если не поддерживается в текущей версии 1С:Предприятия. // // Возвращаемое значение: // - Неопределено // - РежимЗамещения // Функция РежимСлиянияНабораЗаписей() Экспорт Возврат СтандартныеПодсистемыПовтИсп.РежимСлиянияНабораЗаписей(); КонецФункции // Возвращает РежимЗамещения.Удаление или Неопределено, // если не поддерживается в текущей версии 1С:Предприятия. // // Возвращаемое значение: // - Неопределено // - РежимЗамещения // Функция РежимУдаленияНабораЗаписей() Экспорт Возврат СтандартныеПодсистемыПовтИсп.РежимУдаленияНабораЗаписей(); КонецФункции #КонецОбласти #Область РаботаСоСтатусамиИВажнымиСообщениями // Добавляет важное сообщение для привлечения внимания пользователя с размещением в шапке формы. // Данная процедура только дополняет список сообщений, которые необходимо показать // пользователю и не выводит его непосредственно на форму. // // При повторном добавлении сообщения с уже существующим идентификатором предыдущее будет удалено. // // Вывод важных сообщений на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму, // подробнее про использование см. в описании к ней. // // Параметры: // Форма - ФормаКлиентскогоПриложения // Параметры - см. ОбщегоНазначения.ПараметрыВажногоСообщения // Процедура ДобавитьВажноеСообщение(Форма, Параметры) Экспорт НезаполненныеПараметры = Новый Массив; Если Не ЗначениеЗаполнено(Параметры.ТипСообщения) Тогда НезаполненныеПараметры.Добавить("ТипСообщения"); КонецЕсли; Если Не ЗначениеЗаполнено(Параметры.Сообщение) Тогда НезаполненныеПараметры.Добавить("Сообщение"); КонецЕсли; Если Не ЗначениеЗаполнено(Параметры.КраткоеПредставление) И Не ЗначениеЗаполнено(Параметры.Родитель) Тогда НезаполненныеПараметры.Добавить("КраткоеПредставление"); КонецЕсли; Если НезаполненныеПараметры.Количество() > 0 Тогда ТекстОшибки = НСтр("ru = 'Некорректный вызов процедуры добавления важного сообщения. Не заполнены обязательные параметры: |%1'"); ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НезаполненныеПараметры, ", ")); КонецЕсли; Проверка = Новый Структура("БФ_ДобавляемыеВажныеСообщения, БФ_КонтрольнаяСумма", "Проверка", "Проверка"); ЗаполнитьЗначенияСвойств(Проверка, Форма); Если Проверка.БФ_ДобавляемыеВажныеСообщения = "Проверка" Тогда Реквизиты = Новый Массив; Реквизиты.Добавить(Новый РеквизитФормы("БФ_ДобавляемыеВажныеСообщения", Новый ОписаниеТипов("СписокЗначений"))); Реквизиты.Добавить(Новый РеквизитФормы("БФ_ОбработчикиКомандВажногоСообщения", Новый ОписаниеТипов())); Реквизиты.Добавить(Новый РеквизитФормы("БФ_ВсегоВажныхСообщений", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный)))); Если Проверка.БФ_КонтрольнаяСумма = "Проверка" Тогда Реквизиты.Добавить(Новый РеквизитФормы("БФ_КонтрольнаяСумма", Новый ОписаниеТипов("Строка"))); КонецЕсли; Форма.ИзменитьРеквизиты(Реквизиты); Форма.БФ_ОбработчикиКомандВажногоСообщения = Новый Структура; КонецЕсли; Если ТипЗнч(Параметры.Сообщение) = Тип("ФорматированнаяСтрока") И ЗначениеЗаполнено(Параметры.Обработчик) Тогда ИмяОбработчикаЧастями = СтрРазделить(Параметры.Обработчик, "."); // Если в качестве обработчика передана процедура формы, то сохранять параметры не требуется, // т.к. процедура будет обработчиком элемента формы и ссылка будет передана штатно платформой. Если ИмяОбработчикаЧастями.Количество() > 1 Тогда Строка = ЗначениеВСтрокуВнутр(Параметры.Сообщение); РегулярноеВыражение = "]+)>"; РезультатыПоиска = СтрНайтиВсеПоРегулярномуВыражению(Строка, РегулярноеВыражение); Для Каждого РезультатПоиска Из РезультатыПоиска Цикл Ссылка = СокрЛП(СтрЗаменить(СтрЗаменить(РезультатПоиска.Значение, "", "")); Ссылка = СтандартныеПодсистемыСервер.ПреобразоватьСтрокуВДопустимоеНаименованиеКолонки(Ссылка); Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(Ссылка, Параметры.Обработчик); КонецЦикла; КонецЕсли; КонецЕсли; Если Параметры.ПараметрыДействия <> Неопределено Тогда Если ТипЗнч(Параметры.ПараметрыДействия) <> Тип("Массив") Тогда ПараметрыДействияВажногоСообщения = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Параметры.ПараметрыДействия); Иначе ПараметрыДействияВажногоСообщения = Параметры.ПараметрыДействия; КонецЕсли; Для Каждого ОписаниеДействия Из ПараметрыДействияВажногоСообщения Цикл Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(ОписаниеДействия.ИмяКоманды, ОписаниеДействия.Обработчик); КонецЦикла; КонецЕсли; Если ЗначениеЗаполнено(Параметры.Идентификатор) Тогда Для Каждого Элемент Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл Если Элемент.Значение.Идентификатор = Параметры.Идентификатор Тогда Элемент.Значение = Параметры; Возврат; КонецЕсли; КонецЦикла; КонецЕсли; Форма.БФ_ДобавляемыеВажныеСообщения.Добавить(Параметры); КонецПроцедуры // Добавляет контекстное важное сообщение для привлечения внимания пользователя с размещением в указанном месте на форме. // Важно: Контекстно в группу можно вставить только одно сообщение. // // Данная процедура только дополняет список сообщений, которые необходимо показать // пользователю и не выводит его непосредственно на форму. // // При повторном добавлении сообщения с уже существующим идентификатором предыдущее будет удалено. // // Вывод важных сообщений на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму, // подробнее про использование см. в описании к ней. // // Параметры: // Форма - ФормаКлиентскогоПриложения // Параметры - см. ОбщегоНазначения.ПараметрыВажногоСообщения // Родитель - Строка // - ГруппаФормы - имя группы, в которой разместить сообщение. // Элемент - Строка // - ДекорацияФормы // - ГруппаФормы // - КнопкаФормы // - ТаблицаФормы // - ПолеФормы - элемент, перед которым должно быть вставлено важное сообщение. // Процедура ВставитьВажноеСообщение(Форма, Параметры, Родитель, Элемент = Неопределено) Экспорт Если ТипЗнч(Родитель) = Тип("Строка") Тогда Параметры.Родитель = Родитель; ИначеЕсли Родитель <> Неопределено Тогда Параметры.Родитель = Родитель.Имя; КонецЕсли; Если ТипЗнч(Элемент) = Тип("Строка") Тогда Параметры.Элемент = Элемент; ИначеЕсли Элемент <> Неопределено Тогда Параметры.Элемент = Элемент.Имя; КонецЕсли; ДобавитьВажноеСообщение(Форма, Параметры); КонецПроцедуры // Коллекция параметров для настройки важного сообщения. // // Возвращаемое значение: // Структура: // * ТипСообщения - Строка - возможны значения Ошибка, Предупреждение, Информация, Успех. Заполнять обязательно. // * Идентификатор - Строка - идентификатор сообщения, который будет использоваться для // обновления информации или удаления сообщения при перечитывании данных формы. // Необходимо заполнять, если требуется обновлять или удалять важное сообщение при работе пользователя // или если добавление сообщения может выполняться не только в событии ПриСозданииНаСервере, в остальных // случаях необязательно. // * Заголовок - Строка - заголовок важного сообщения. // * Сообщение - Строка, ФорматированнаяСтрока - содержимое сообщения, заполнять обязательно. // * КраткоеПредставление - Строка - краткое и понятное описание сути проблемы. // Использование обобщающих формулировок вида "Найдены проблемы" не допускается, вместо // этого правильно будет написать, например, "Проблемы проверки учета". // Рекомендуемая длина до 30 символов, максимум - 38. // Обязательно заполнять для сообщений, выводимых в шапке формы процедурой ДобавитьВажноеСообщение. // * Обработчик - Строка - нужно указывать, если передана форматированная строка. Варианты: // 1) Процедура модуля формы, состав параметров как у события ОбработкаНавигационнойСсылки. // 2) Процедура клиентского общего модуля с параметрами: // # Форма - ФормаКлиентскогоПриложения // # Ссылка - Строка - ссылка из форматированной строки. // * ОбработчикЗакрытия - обработчик нажатия на кнопку закрытия сообщения. Для работы требуется заполнить свойство Идентификатор. // Важно: Закрытие сообщения в необходимо делать самостоятельно вызовом процедуры ОбщегоНазначенияКлиентСервер.УдалитьСтатусИлиВажноеСообщение. // Возможные варианты: // 1) Процедура модуля формы, состав параметров как у обработчика команды. // 2) Процедура клиентского общего модуля с параметрами: // # Форма - ФормаКлиентскогоПриложения // # Идентификатор - Строка - идентификатор важного сообщения. // * Скрываемый - Булево - можно ли скрыть важное сообщение нажатием на "х". По умолчанию - Истина. // * ПараметрыДействия - см. ОбщегоНазначения.ПараметрыДействияВажногоСообщения // - Массив из см. ОбщегоНазначения.ПараметрыДействияВажногоСообщения // Функция ПараметрыВажногоСообщения() Экспорт Параметры = Новый Структура; Параметры.Вставить("ТипСообщения", "Предупреждение"); Параметры.Вставить("Скрываемый", Истина); Параметры.Вставить("Идентификатор", ""); Параметры.Вставить("Заголовок", ""); Параметры.Вставить("Сообщение", ""); Параметры.Вставить("КраткоеПредставление", ""); Параметры.Вставить("Обработчик", ""); Параметры.Вставить("ОбработчикЗакрытия", ""); Параметры.Вставить("ПараметрыДействия", Неопределено); Параметры.Вставить("Родитель", Неопределено); // Для внутреннего использования. Параметры.Вставить("Элемент", Неопределено); // Для внутреннего использования. Возврат Параметры; КонецФункции // Коллекция параметров для настройки команд, выводимых в важном сообщении. // // Возвращаемое значение: // Структура: // * ИмяКоманды - Строка - имя команды. Рекомендуется подбирать уникальное имя, которое не пересечется с другими командами. // * Обработчик - Строка - процедура-обработчик команды формы, возможные варианты: // 1) Процедура модуля формы, состав параметров как у обработчика команды. // 2) Процедура клиентского общего модуля с параметрами: // # Форма - ФормаКлиентскогоПриложения // # Ссылка - Строка - значение из свойства ИмяКоманды. // * Заголовок - Строка // Функция ПараметрыДействияВажногоСообщения() Экспорт ПараметрыДействия = Новый Структура; ПараметрыДействия.Вставить("ИмяКоманды", ""); ПараметрыДействия.Вставить("Обработчик", ""); ПараметрыДействия.Вставить("Заголовок", ""); Возврат ПараметрыДействия; КонецФункции // Добавляет статус на форму. // Например, для отображения текущего статуса заказа покупателя. // // При повторном добавлении статуса с уже существующим идентификатором предыдущий будет удален. // // Вывод статуса на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму, // подробнее про использование см. в описании к ней. // // Параметры: // Форма - ФормаКлиентскогоПриложения // Параметры - см. ОбщегоНазначения.ПараметрыСтатуса // Процедура ДобавитьСтатус(Форма, Параметры) Экспорт НезаполненныеПараметры = Новый Массив; Если Не ЗначениеЗаполнено(Параметры.Наименование) Тогда НезаполненныеПараметры.Добавить("Наименование"); КонецЕсли; Если Не ЗначениеЗаполнено(Параметры.Идентификатор) Тогда НезаполненныеПараметры.Добавить("Идентификатор"); КонецЕсли; Если НезаполненныеПараметры.Количество() > 0 Тогда ТекстОшибки = НСтр("ru = 'Некорректный вызов процедуры добавления статуса. Не заполнены обязательные параметры: |%1'"); ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НезаполненныеПараметры, ", ")); КонецЕсли; Проверка = Новый Структура("БФ_ДобавляемыеСтатусы, БФ_КонтрольнаяСумма", "Проверка", "Проверка"); ЗаполнитьЗначенияСвойств(Проверка, Форма); Если Проверка.БФ_ДобавляемыеСтатусы = "Проверка" Тогда Реквизиты = Новый Массив; Реквизиты.Добавить(Новый РеквизитФормы("БФ_ДобавляемыеСтатусы", Новый ОписаниеТипов("СписокЗначений"))); Реквизиты.Добавить(Новый РеквизитФормы("БФ_ОбработчикиСтатусов", Новый ОписаниеТипов())); Реквизиты.Добавить(Новый РеквизитФормы("БФ_ВсегоСтатусов", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный)))); Если Проверка.БФ_КонтрольнаяСумма = "Проверка" Тогда Реквизиты.Добавить(Новый РеквизитФормы("БФ_КонтрольнаяСумма", Новый ОписаниеТипов("Строка"))); КонецЕсли; Форма.ИзменитьРеквизиты(Реквизиты); Форма.БФ_ОбработчикиСтатусов = Новый Структура; КонецЕсли; Для Каждого Элемент Из Форма.БФ_ДобавляемыеСтатусы Цикл Если Элемент.Значение.Идентификатор = Параметры.Идентификатор Тогда Элемент.Значение = Параметры; Возврат; КонецЕсли; КонецЦикла; Форма.БФ_ДобавляемыеСтатусы.Добавить(Параметры); КонецПроцедуры // Коллекция параметров для настройки выводимого на форму статуса. // // Возвращаемое значение: // Структура: // * Наименование - Строка, ФорматированнаяСтрока - представление статуса. Рекомендуемая длина до 15 символов. // Заполнять обязательно. Форматированную строку допустимо использовать только для // оформления цвета статуса, добавление гиперссылок не поддерживается. Пример // использования: СтроковыеФункции.ФорматированнаяСтрока( // НСтр("ru = 'Состояние: зарегистрирован'")); // * Идентификатор - Строка - идентификатор статуса, должен удовлетворять требованиям, предъявляемым // к именованию переменных встроенного языка. Заполнять обязательно. // * Картинка - Картинка - картинка статуса. // * Порядок - Число, Неопределено - порядок вывода статуса на форме. Статусы будут выводиться по // возрастанию значения. По умолчанию - Неопределено, в порядке добавления // на форму. // * Обработчик - Строка - обработчик нажатия на гиперссылку статуса. // Если не заполнен, то статус выводится обычной надписью. Варианты: // 1) Процедура модуля формы, состав параметров как у события Нажатие у элемента ДекорацияФормы. // 2) Процедура клиентского общего модуля с параметрами: // # Форма - ФормаКлиентскогоПриложения // # Параметры - Структура: // * Идентификатор - Строка - идентификатор статуса. // * Родитель - ГруппаФормы - элемент формы, к которому привязывается // расшифровка статуса. // Функция ПараметрыСтатуса() Экспорт Параметры = Новый Структура; Параметры.Вставить("Наименование", ""); Параметры.Вставить("Идентификатор", Неопределено); Параметры.Вставить("Картинка", Неопределено); Параметры.Вставить("Порядок", Неопределено); Параметры.Вставить("Обработчик", ""); Возврат Параметры; КонецФункции // Выводит на форму статусы и важные сообщения для привлечения внимания пользователя. // // Внешний вид важных сообщений зависит от их количества: // - Если было добавлено только одно сообщение, то оно отображается целиком и // дополнительно выделяется цветом в зависимости от значения свойства ТипСообщения. // - Если сообщений добавлено больше одного, то они выводятся одной строкой в виде // кратких представлений с отображением подробностей по нажатии на них. // // Для удаления ранее выведенного на форму статуса или сообщения можно воспользоваться процедурой // см. ОбщегоНазначенияКлиентСервер.УдалитьСтатусИлиВажноеСообщение. // // Использование: // 1) Вызывать необходимо разово, в конце события ПриСозданииНаСервере, при необходимости можно // добавить дополнительные вызовы для обновления состояния статусов и важных сообщений после некоторых действий пользователя. // // 2)Для корректной работы так же необходимо добавить подключаемый обработчик события формы: // // &НаКлиенте // Процедура Подключаемый_ОбработатьДействиеИнформационногоСообщения(ЭлементИлиКоманда, НавигационнаяСсылка = Неопределено, СтандартнаяОбработка = Неопределено) // ОбщегоНазначенияКлиент.ОбработатьДействиеИнформационногоСообщения(ЭтотОбъект, ЭлементИлиКоманда, НавигационнаяСсылка, СтандартнаяОбработка); // КонецПроцедуры // // Параметры: // Форма - ФормаКлиентскогоПриложения // Процедура ВывестиСтатусыИВажныеСообщенияНаФорму(Форма) Экспорт Проверка = Новый Массив; ПроверкаВажныеСообщения = Новый Структура; ПроверкаВажныеСообщения.Вставить("БФ_ДобавляемыеВажныеСообщения"); ЗаполнитьЗначенияСвойств(ПроверкаВажныеСообщения, Форма); ЕстьВажныеСообщения = (ПроверкаВажныеСообщения.БФ_ДобавляемыеВажныеСообщения <> Неопределено И Форма.БФ_ДобавляемыеВажныеСообщения.Количество() <> 0); Если ЕстьВажныеСообщения Тогда Проверка.Добавить(Форма.БФ_ДобавляемыеВажныеСообщения); КонецЕсли; ПроверкаСтатусы = Новый Структура; ПроверкаСтатусы.Вставить("БФ_ДобавляемыеСтатусы"); ЗаполнитьЗначенияСвойств(ПроверкаСтатусы, Форма); ЕстьСтатусы = (ПроверкаСтатусы.БФ_ДобавляемыеСтатусы <> Неопределено И Форма.БФ_ДобавляемыеСтатусы.Количество() <> 0); Если ЕстьСтатусы Тогда Проверка.Добавить(Форма.БФ_ДобавляемыеСтатусы); КонецЕсли; Если Не ЕстьВажныеСообщения И Не ЕстьСтатусы Тогда Возврат; КонецЕсли; Если Не ЗначениеЗаполнено(Форма.БФ_КонтрольнаяСумма) Или Форма.БФ_КонтрольнаяСумма <> КонтрольнаяСуммаСтрокой(Проверка) Тогда Форма.БФ_КонтрольнаяСумма = КонтрольнаяСуммаСтрокой(Проверка); ИначеЕсли Форма.БФ_КонтрольнаяСумма = КонтрольнаяСуммаСтрокой(Проверка) Тогда Возврат; КонецЕсли; РодительскаяГруппа = Форма.Элементы.Найти("БФ_ГруппаВажныеСообщенияИСтатусы"); Если РодительскаяГруппа <> Неопределено Тогда Форма.Элементы.Удалить(РодительскаяГруппа); КонецЕсли; ПодчиненныеЭлементы = Форма.ПодчиненныеЭлементы; Если ПодчиненныеЭлементы.Количество() = 0 Тогда ПервыйЭлемент = Неопределено; Иначе ПервыйЭлемент = ПодчиненныеЭлементы[0]; КонецЕсли; ОбщиеПараметры = ОбщиеПараметрыБазовойФункциональности(); РодительскаяГруппа = Форма.Элементы.Вставить("БФ_ГруппаВажныеСообщенияИСтатусы", Тип("ГруппаФормы"), Форма, ПервыйЭлемент); РодительскаяГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа; РодительскаяГруппа.ОтображатьЗаголовок = Ложь; РодительскаяГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда; Если Не ОбщегоНазначенияКлиентСервер.ЭтоВариантИнтерфейса85() И Не ОбщиеПараметры.ГруппироватьСтатусыИВажныеСообщенияГоризонтально Тогда РодительскаяГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; КонецЕсли; // Вывод статусов. Если ЕстьСтатусы Тогда ВывестиСтатусыНаФорму(Форма, РодительскаяГруппа); КонецЕсли; Если Не ЕстьВажныеСообщения Тогда Возврат; КонецЕсли; // Группа для важных сообщений. ГруппаРазмещенияВажныхСообщений = Форма.Элементы.Найти("БФ_ГруппаСообщенияШапки"); Если ГруппаРазмещенияВажныхСообщений <> Неопределено Тогда // Повторный вывод сообщения. Форма.Элементы.Удалить(ГруппаРазмещенияВажныхСообщений); КонецЕсли; ГруппаРазмещенияВажныхСообщений = НоваяГруппаВажногоСообщения(Форма, "БФ_ГруппаСообщенияШапки", РодительскаяГруппа); ГруппаРазмещенияВажныхСообщений.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ВсегоВажныхСообщений = Форма.БФ_ДобавляемыеВажныеСообщения.Количество(); // Вывод контекстных важных сообщений. ВывестиКонтекстноеВажноеСообщение(Форма, ВсегоВажныхСообщений); Если ВсегоВажныхСообщений = 0 Тогда Возврат; КонецЕсли; // Вывод одиночного сообщения. Если ВсегоВажныхСообщений = 1 Тогда ВывестиОдиночноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений); Возврат; КонецЕсли; СгруппированныеСообщения = НоваяТаблицаСгруппированныхСообщений(); СгруппироватьСообщения(СгруппированныеСообщения, Форма.БФ_ДобавляемыеВажныеСообщения); ГруппаРазмещенияВажныхСообщений.Группировка = ГруппировкаПодчиненныхЭлементовФормы.АвтоматическиУчитыватьВидЭкрана; ГруппаРазмещенияВажныхСообщений.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Авто; ГруппаРазмещенияВажныхСообщений.РастягиватьПоГоризонтали = Истина; ГруппаРазмещенияВажныхСообщений.ОтображатьКакКарточку = Истина; // Вывод агрегированного сообщения, когда важных сообщений больше одного. ВывестиАгрегированноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений, СгруппированныеСообщения, ЕстьСтатусы); // Добавление группы со списком всех важных сообщений. ВывестиГруппуПоказатьВсеВажныеСообщения(Форма, СгруппированныеСообщения, ГруппаРазмещенияВажныхСообщений); Форма.БФ_ВсегоВажныхСообщений = СгруппированныеСообщения.Количество(); КонецПроцедуры #КонецОбласти #Область УстаревшиеПроцедурыИФункции // Устарела. Следует использовать ОбщегоНазначения.ЭтоMacOSКлиент // Возвращает Истина, если клиентское приложение запущено под управлением ОС X. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоOSXКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент"); Если ЭтоMacOSКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоMacOSКлиент; КонецФункции #КонецОбласти #КонецЕсли #КонецОбласти #Если НЕ МобильныйАвтономныйСервер Тогда #Область СлужебныйПрограммныйИнтерфейс // Выгружает запрос в строку XML, которую можно вставить в Консоль запросов. // Для переноса запроса и всех его параметров в Консоль запросов, необходимо вызвать функцию в окне. // "Вычислить выражение" (Shift + F9), скопировать полученный XML в поле "Текст запроса" // консоли запросов и выполнить команду "Заполнить из XML" из меню "Еще". // Подробнее об использование функции смотрите в справке к консоли запросов. // // Параметры: // Запрос - Запрос - запрос, который необходимо выгрузить в формат строки XML. // // Возвращаемое значение: // Строка - строка в формате XML, которую можно извлечь при помощи метода "ОбщегоНазначения.ЗначениеИзСтрокиXML". // После извлечения получится объект типа "Структура" с полями: // * Текст - Строка - текст запроса. // * Параметры - Структура - параметры запроса. // Функция ЗапросВСтрокуXML(Запрос) Экспорт // АПК:299 - используется при отладке запросов, см. описание функции. Структура = Новый Структура("Текст, Параметры"); ЗаполнитьЗначенияСвойств(Структура, Запрос); Возврат ЗначениеВСтрокуXML(Структура); КонецФункции Функция ПодключитьКомпонентуПоИдентификатору(Знач Идентификатор, Знач Местоположение, Знач Изолированно = Неопределено) Экспорт ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение); Результат = Новый Структура; Результат.Вставить("Подключено", Ложь); Результат.Вставить("ПодключаемыйМодуль", Неопределено); Результат.Вставить("ОписаниеОшибки", ""); Попытка #Если МобильноеПриложениеСервер Тогда РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName"); #Иначе РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName",, ОбщегоНазначенияСлужебныйКлиентСервер.ТипПодключенияКомпоненты(Изолированно)); #КонецЕсли Исключение ИнформацияОбОшибке = ИнформацияОбОшибке(); ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине:'"), Идентификатор); Результат.ОписаниеОшибки = ЗаголовокОшибки + Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); КомментарийДляЖурнала = ЗаголовокОшибки + Символы.ПС + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке) + СистемнаяИнформацияДляЖурналаРегистрации(); ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала); Возврат Результат; КонецПопытки; Если Не РезультатПодключения Тогда ОшибкаСовместимостиКомпонентыИзМакета = ОшибкаСовместимостиКомпонентыИзМакета(Местоположение); Если ЗначениеЗаполнено(ОшибкаСовместимостиКомпонентыИзМакета) Тогда Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине: |%2. |Техническая информация: |%3 |Метод %4 вернул Ложь.'"), Идентификатор, ОшибкаСовместимостиКомпонентыИзМакета, Местоположение, "ПодключитьВнешнююКомпоненту"); Иначе Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере. |Техническая информация: |%2 |Метод %3 вернул Ложь.'"), Идентификатор, Местоположение, "ПодключитьВнешнююКомпоненту"); КонецЕсли; Попытка ВызватьИсключение НСтр("ru = 'Стек вызовов:'") Исключение КомментарийДляЖурнала = Результат.ОписаниеОшибки + Символы.ПС + Символы.ПС + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()) + СистемнаяИнформацияДляЖурналаРегистрации(); КонецПопытки; ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала); Возврат Результат; КонецЕсли; ПодключаемыйМодуль = Неопределено; Попытка ПодключаемыйМодуль = Новый("AddIn." + Идентификатор + "SymbolicName" + "." + Идентификатор); Если ПодключаемыйМодуль = Неопределено Тогда ВызватьИсключение НСтр("ru = 'Оператор Новый вернул Неопределено'"); КонецЕсли; Исключение ПодключаемыйМодуль = Неопределено; ИнформацияОбОшибке = ИнформацияОбОшибке(); КонецПопытки; Если ПодключаемыйМодуль = Неопределено Тогда Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине: |%2'"), Идентификатор, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)); КомментарийДляЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине: |%2'"), Идентификатор, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке) + СистемнаяИнформацияДляЖурналаРегистрации()); ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала); Возврат Результат; КонецЕсли; Результат.Подключено = Истина; Результат.ПодключаемыйМодуль = ПодключаемыйМодуль; ОтправитьСтатистикуПодключенияКомпоненты(Идентификатор, Местоположение); Возврат Результат; КонецФункции Функция СтрокаВВидеНСтр(Знач ПроверяемаяСтрока) Экспорт ПроверяемаяСтрока = СтрЗаменить(ПроверяемаяСтрока, " ", ""); ВариантыСовпадений = Новый Массив; Для каждого Язык Из Метаданные.Языки Цикл ВариантыСовпадений.Добавить(Язык.КодЯзыка + "="); КонецЦикла; Для каждого ВариантСовпадения Из ВариантыСовпадений Цикл Если СтрНайти(ПроверяемаяСтрока, ВариантСовпадения) > 0 Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Устанавливает условное оформление списка выбора // // Параметры: // Форма - ФормаКлиентскогоПриложения - форма, для которой устанавливается оформление. // ИмяЭлемента - Строка - имя элемента, для которого устанавливается оформление. // ИмяПоляКомпоновкиДанных - Строка - имя поля компоновки данных. // Процедура УстановитьУсловноеОформлениеСпискаВыбора(Форма, ИмяЭлемента, ИмяПоляКомпоновкиДанных) Экспорт Элементы = Форма.Элементы; УсловноеОформление = Форма.УсловноеОформление; Для каждого ЭлементВыбора Из Элементы[ИмяЭлемента].СписокВыбора Цикл Элемент = УсловноеОформление.Элементы.Добавить(); ПолеЭлемента = Элемент.Поля.Элементы.Добавить(); ЭлементФормы = Элементы[ИмяЭлемента]; // ПолеФормы ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ЭлементФормы.Имя); ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоляКомпоновкиДанных); ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; ОтборЭлемента.ПравоеЗначение = ЭлементВыбора.Значение; Элемент.Оформление.УстановитьЗначениеПараметра("Текст", ЭлементВыбора.Представление); КонецЦикла; КонецПроцедуры // Возвращает суффикс текущего языка для мультиязычных реквизитов. // // Возвращаемое значение: // - Строка - "Язык1" или "Язык2", если язык пользователя является дополнительным // Пустая строка, если язык пользователя является основным. // - Неопределено - мультиязычное хранение данных не используется. // Функция СуффиксЯзыкаТекущегоПользователя() Экспорт Результат = Новый Структура(); Результат.Вставить("СуффиксТекущегоЯзыка", ""); Результат.Вставить("ЭтоОсновнойЯзык", ""); Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); СуффиксТекущегоЯзыка = МодульМультиязычностьСервер.СуффиксТекущегоЯзыка(); Если ЗначениеЗаполнено(СуффиксТекущегоЯзыка) Тогда Возврат СуффиксТекущегоЯзыка; КонецЕсли; Иначе СуффиксТекущегоЯзыка = ""; КонецЕсли; Если ЭтоОсновнойЯзык() Тогда Возврат СуффиксТекущегоЯзыка; КонецЕсли; Возврат Неопределено; КонецФункции // Сокращает имя файла с расширением, если оно превышает размер в 255 байт. // При этом сокращается часть имени файла без расширения, в конец которой добавляется уникальное значение, // вычисленное по алгоритму MD5. // // Параметры: // ИмяФайла - Строка - имя файла с расширением // Процедура СократитьИмяФайла(ИмяФайла) Экспорт ОграничениеВБайтах = 127; Файл = Новый Файл(ИмяФайла); Если РазмерСтрокиВБайтах(Файл.Имя) <= ОграничениеВБайтах Тогда Возврат; КонецЕсли; Строка = ""; ОстатокСтроки = ""; РазмерСтроки = 0; МаксимальныйРазмерСтроки = ОграничениеВБайтах - 32; РазмерРасширения = РазмерСтрокиВБайтах(Файл.Расширение); СокращатьВместеСРасширением = РазмерРасширения > 32; Если СокращатьВместеСРасширением Тогда СокращаемоеИмя = Файл.Имя; Иначе СокращаемоеИмя = Файл.ИмяБезРасширения; РазмерСтроки = РазмерРасширения; КонецЕсли; Для НомерСимвола = 1 По СтрДлина(СокращаемоеИмя) Цикл Символ = Сред(СокращаемоеИмя, НомерСимвола, 1); РазмерСимвола = РазмерСтрокиВБайтах(Символ); Если РазмерСтроки + РазмерСимвола > МаксимальныйРазмерСтроки Тогда ОстатокСтроки = Сред(СокращаемоеИмя, НомерСимвола); Прервать; КонецЕсли; Строка = Строка + Символ; РазмерСтроки = РазмерСтроки + РазмерСимвола; КонецЦикла; ИмяФайла = Строка; ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5); ХешированиеДанных.Добавить(ОстатокСтроки); ХешСумма = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", ""); ИмяФайла = Файл.Путь + ИмяФайла + ХешСумма + ?(СокращатьВместеСРасширением, "", Файл.Расширение); КонецПроцедуры // Служебные объекты и объекты при загрузке из резервной копии, // должны записываться без какой-либо прикладной логики. // // Запись служебных объектов без отключения прикладной логики, // может привести к зацикливанию, снижению производительности, // а также избыточным изменениях, которые в некоторых случаях // могут неожиданно повлиять на логику работы. // // Служебными являются объекты, которые обычно не участвуют // в обмене данными, не зависят от других объектов, например: // - кэши; // - даты обновления кэшей и аналогичные признаки; // - промежуточные данные для передачи параметров в фоновые задания; // - вспомогательные служебные данные (например, ключи доступа, // идентификаторы объектов метаданных). // // При использовании подсистемы Управление доступом, требуется // отдельно вызывать процедуру ОтключитьОбновлениеКлючейДоступа // общего модуля УправлениеДоступом. // // Процедура включает режим загрузки данных, // отключает регистрацию объектов на планах обмена, // отключает контроль механизма удаления помеченных объектов. // // Параметры: // Объект - ПланОбменаОбъект // - КонстантаМенеджерЗначения // - СправочникОбъект // - ДокументОбъект // - ПоследовательностьНаборЗаписей // - ПланВидовХарактеристикОбъект // - ПланСчетовОбъект // - ПланВидовРасчетаОбъект // - БизнесПроцессОбъект // - ЗадачаОбъект // - УдалениеОбъекта // - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей // - ПерерасчетНаборЗаписей // // ЭтоУзелПланаОбмена - Булево // Процедура ОтключитьКонтрольЗаписи(Объект, ЭтоУзелПланаОбмена = Ложь) Экспорт Объект.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); Объект.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); Объект.ОбменДанными.Загрузка = Истина; Если Не ЭтоУзелПланаОбмена Тогда Объект.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; КонецЕсли; КонецПроцедуры Функция МакетСуществует(ПолноеИмяМакета) Экспорт Макет = Метаданные.НайтиПоПолномуИмени(ПолноеИмяМакета); Если ТипЗнч(Макет) = Тип("ОбъектМетаданных") Тогда Шаблон = Новый Структура("ТипМакета"); ЗаполнитьЗначенияСвойств(Шаблон, Макет); ТипМакета = Неопределено; Если Шаблон.Свойство("ТипМакета", ТипМакета) Тогда Возврат ТипМакета <> Неопределено; КонецЕсли; КонецЕсли; Возврат Ложь; КонецФункции Функция ДоменноеИмяКорректное(ДоменноеИмя) Экспорт Если СтрДлина(ДоменноеИмя) > 255 Тогда Возврат Ложь; КонецЕсли; Выражение = "(?:xn--[a-z0-9-]{1,59})(?:\.xn--[a-z0-9-]{1,59})*" + "|(?!^\d+$)(?:(?!-)[a-z0-9-]{1,63}(? 0 Тогда ТекстОшибки = НСтр("ru = 'Вызовы недопустимых методов: |%1'"); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС)); ТекстыОшибок.Добавить(ТекстОшибки); КонецЕсли; // Проверка обращений к общим модулям и свойствам глобального контекста. ЗапрещенныеСвойстваГлобальногоКонтекста = ЗапрещенныеСвойстваГлобальногоКонтекста(); ОбщегоНазначенияКлиентСервер.ДополнитьМассив( ЗапрещенныеСвойстваГлобальногоКонтекста, ПараметрыПроверки.ЗапрещенныеСвойстваГлобальногоКонтекста, Истина); НайденныеВызовы = НайденныеВызовы(Алгоритм, ЗапрещенныеСвойстваГлобальногоКонтекста, "."); НайденныеВызовыАльтернативные = НайденныеВызовы(Алгоритм, ЗапрещенныеСвойстваГлобальногоКонтекста, "["); ОбщегоНазначенияКлиентСервер.ДополнитьМассив(НайденныеВызовы, НайденныеВызовыАльтернативные, Истина); Если НайденныеВызовы.Количество() > 0 Тогда ТекстОшибки = НСтр("ru = 'Вызовы недопустимых свойств глобального контекста: |%1'"); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС)); ТекстыОшибок.Добавить(ТекстОшибки); КонецЕсли; ЗапрещенныеМодули = ЗапрещенныеМодули(); ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗапрещенныеМодули, ПараметрыПроверки.ЗапрещенныеМодули, Истина); НайденныеВызовы = НайденныеВызовы(Алгоритм, ЗапрещенныеМодули, "."); Если НайденныеВызовы.Количество() > 0 Тогда ТекстОшибки = НСтр("ru = 'Вызовы недопустимых модулей: |%1'"); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС)); ТекстыОшибок.Добавить(ТекстОшибки); КонецЕсли; Если ТекстыОшибок.Количество() > 0 Тогда ВызватьИсключение (СтрСоединить(ТекстыОшибок, Символы.ПС + Символы.ПС), КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных); КонецЕсли; КонецПроцедуры #КонецОбласти #Область СлужебныеПроцедурыИФункции #Область ДанныеВБазе #Область ЗначенияРеквизитов // Проверяет существование указанных реквизитов у объекта метаданных. // // Параметры: // ПолноеИмяОбъектаМетаданных - Строка - полное имя проверяемого объекта. // ПроверяемыеВыражения - Массив - имена полей или проверяемые выражения объекта метаданных. // // Возвращаемое значение: // Структура: // * Ошибка - Булево - найдена ошибка. // * ОписаниеОшибки - Строка - описание найденных ошибок. // // Пример: // // Реквизиты = Новый Массив; // Реквизиты.Добавить("Номер"); // Реквизиты.Добавить("Валюта.НаименованиеПолное"); // // Результат = ОбщегоНазначения.ПроверитьСуществованиеРеквизитовОбъекта("Документ.ЗаказПокупателя", Реквизиты); // // Если Результат.Ошибка Тогда // ВызватьИсключение Результат.ОписаниеОшибки; // КонецЕсли; // Функция ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, ПроверяемыеВыражения) МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных); Если МетаданныеОбъекта = Неопределено Тогда Возврат Новый Структура("Ошибка, ОписаниеОшибки", Истина, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Несуществующий объект метаданных ""%1"".'"), ПолноеИмяОбъектаМетаданных)); КонецЕсли; // Разрешение вызова из безопасного режима внешней обработки или расширения. // Информация о доступности полей источника схемы при проверке метаданных не является секретной. УстановитьОтключениеБезопасногоРежима(Истина); УстановитьПривилегированныйРежим(Истина); Схема = Новый СхемаЗапроса; Пакет = Схема.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса")); Оператор = Пакет.Операторы.Получить(0); Источник = Оператор.Источники.Добавить(ПолноеИмяОбъектаМетаданных, "Таблица"); ТекстОшибки = ""; Для Каждого ТекущееВыражение Из ПроверяемыеВыражения Цикл Если Не ПолеИсточникаСхемыЗапросаДоступно(Источник, ТекущееВыражение) Тогда ТекстОшибки = ТекстОшибки + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Поле объекта ""%1"" не существует.'"), ТекущееВыражение); КонецЕсли; КонецЦикла; Возврат Новый Структура("Ошибка, ОписаниеОшибки", Не ПустаяСтрока(ТекстОшибки), ТекстОшибки); КонецФункции // Используется в ПроверитьСуществованиеРеквизитовОбъекта. // Выполняет проверку доступности поля проверяемого выражения в источнике оператора схемы запроса. // Функция ПолеИсточникаСхемыЗапросаДоступно(ИсточникОператора, ПроверяемоеВыражение) ЧастиИмениПоля = СтрРазделить(ПроверяемоеВыражение, "."); ДоступныеПоля = ИсточникОператора.Источник.ДоступныеПоля; ТекущаяЧастьИмениПоля = 0; Пока ТекущаяЧастьИмениПоля < ЧастиИмениПоля.Количество() Цикл ТекущееПоле = ДоступныеПоля.Найти(ЧастиИмениПоля.Получить(ТекущаяЧастьИмениПоля)); Если ТекущееПоле = Неопределено Тогда Возврат Ложь; КонецЕсли; // Инкрементация следующей части имени поля и соответствующего списка доступности полей. ТекущаяЧастьИмениПоля = ТекущаяЧастьИмениПоля + 1; ДоступныеПоля = ТекущееПоле.Поля; КонецЦикла; Возврат Истина; КонецФункции #КонецОбласти #Область ЗаменитьСсылки Функция РазметитьМестаИспользования(Знач ПараметрыВыполнения, Знач Ссылка, Знач ЦелеваяСсылка, Знач ТаблицаПоиска) УстановитьПривилегированныйРежим(Истина); // Устанавливаем порядок известных и проверяем наличие неопознанных объектов. Результат = Новый Структура; Результат.Вставить("МестаИспользования", ТаблицаПоиска.НайтиСтроки(Новый Структура("Ссылка", Ссылка))); Результат.Вставить("ОшибкиРазметки", Новый Массив); Результат.Вставить("Успех", Истина); Для Каждого МестоИспользования Из Результат.МестаИспользования Цикл Если МестоИспользования.ЭтоСлужебныеДанные Тогда Продолжить; // Зависимые данные не обрабатываются. КонецЕсли; Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения); Если Информация.Вид = "КОНСТАНТА" Тогда МестоИспользования.КлючЗамены = "Константа"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда МестоИспользования.КлючЗамены = "Последовательность"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" Тогда МестоИспользования.КлючЗамены = "РегистрСведений"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "РЕГИСТРБУХГАЛТЕРИИ" Или Информация.Вид = "РЕГИСТРНАКОПЛЕНИЯ" Или Информация.Вид = "РЕГИСТРРАСЧЕТА" Тогда МестоИспользования.КлючЗамены = "КлючЗаписи"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Ссылочный Тогда МестоИспользования.КлючЗамены = "Объект"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; Иначе // Неизвестный объект для замены ссылок. Результат.Успех = Ложь; Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Замена ссылок в ""%1"" недоступна.'"), Информация.ПолноеИмя); ОписаниеОшибки = Новый Структура("Объект, Текст", МестоИспользования.Данные, Текст); Результат.ОшибкиРазметки.Добавить(ОписаниеОшибки); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Параметры: // ТаблицаПоиска - см. МестаИспользования // Процедура ЗаменитьСсылкиКороткимиТранзакциями(Результат, Знач ПараметрыВыполнения, Знач Дубль, Знач ТаблицаПоиска) // Основной цикл обработки ФильтрСсылок = Новый Структура("Ссылка, КлючЗамены"); Результат.ЕстьОшибки = Ложь; ФильтрСсылок.Ссылка = Дубль; ФильтрСсылок.КлючЗамены = "Константа"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВКонстанте(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "Объект"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВОбъекте(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "КлючЗаписи"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "Последовательность"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "РегистрСведений"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВРегистреСведений(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ПроизводимыеЗамены = Новый Массив; ПроизводимыеЗамены.Добавить(Дубль); Если ПараметрыВыполнения.УдалятьНепосредственно ИЛИ ПараметрыВыполнения.ПомечатьНаУдаление Тогда УстановитьПометкуУдаленияДляОбъектов(Результат, ПроизводимыеЗамены, ПараметрыВыполнения); Иначе ТаблицаПовторногоПоиска = МестаИспользования(ПроизводимыеЗамены,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования); ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска, ПараметрыВыполнения); КонецЕсли; КонецПроцедуры Процедура ПроизвестиЗаменуВКонстанте(Результат, Знач МестоИспользования, Знач ПараметрыЗаписи) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; МетаданныеКонстанты = МестоИспользования.Метаданные; ПредставлениеДанных = Строка(Данные); Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Константа"); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл СтрокаТаблицы.КлючЗамены = ""; КонецЦикла; СостояниеОперации = ""; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; Блокировка.Добавить(МетаданныеКонстанты.ПолноеИмя()); Попытка Блокировка.Заблокировать(); Исключение СостояниеОперации = "ОшибкаБлокировки"; УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось заменить в константе ""%1"", т.к. данные редактируются в другом сеансе работы с приложением. |Повторите попытку замены.'"), ПредставлениеДанных); ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; МенеджерКонстанты = Константы[МетаданныеКонстанты.Имя].СоздатьМенеджерЗначения(); МенеджерКонстанты.Прочитать(); ЗаменаПроизведена = Ложь; Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл Если МенеджерКонстанты.Значение = СтрокаТаблицы.Ссылка Тогда МенеджерКонстанты.Значение = СтрокаТаблицы.ЦелеваяСсылка; ЗаменаПроизведена = Истина; КонецЕсли; КонецЦикла; Если Не ЗаменаПроизведена Тогда ОтменитьТранзакцию(); Возврат; КонецЕсли; // Пытаемся сохранить Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка ЗаписатьОбъект(МенеджерКонстанты, ПараметрыЗаписи); Исключение СостояниеОперации = "ОшибкаЗаписи"; ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, НСтр("ru = 'Не удалось заменить по причине:'")); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, МетаданныеКонстанты,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, ОписаниеОшибкиЗамены("ОшибкаЗаписи", Данные, ПредставлениеДанных, ИнформацияОбОшибке()), ПараметрыЗаписи.ПодчиненныеКДублям); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке()), ПараметрыЗаписи.ПодчиненныеКДублям); КонецЕсли; КонецПопытки; КонецПроцедуры Процедура ПроизвестиЗаменуВОбъекте(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; // Будем производить сразу все замены для этих данных. Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Объект"); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования ПредставлениеДанных = ПредметСтрокой(Данные); СостояниеОперации = ""; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования); Попытка Блокировка.Заблокировать(); Исключение СостояниеОперации = "ОшибкаБлокировки"; УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось заменить в ""%1"", т.к. данные редактируются в другом сеансе работы с приложением. |Повторите попытку замены.'"), ПредставлениеДанных); ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; ОбъектыЗаписи = ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки); // Пытаемся сохранить, сам объект идет последним. Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка Если ПараметрыВыполнения.ВключатьБизнесЛогику Тогда // Первая запись без контроля, чтобы устранить циклические ссылки. НовыеПараметрыВыполнения = СкопироватьРекурсивно(ПараметрыВыполнения); НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Ложь; Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения); КонецЦикла; // Вторая запись c контролем. НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Истина; Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения); КонецЦикла; Иначе // Запись без контроля бизнес-логики. Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, ПараметрыВыполнения); КонецЦикла; КонецЕсли; Исключение СостояниеОперации = "ОшибкаЗаписи"; ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, НСтр("ru = 'Не удалось заменить по причине:'")); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Информация = ИнформацияОбОшибке(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, МестоИспользования.Метаданные,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация)); Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке()); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, Ошибка, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЕсли; КонецПопытки; // Помечаем как обработанные Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл СтрокаТаблицы.КлючЗамены = ""; КонецЦикла; КонецПроцедуры Процедура ПроизвестиЗаменуВНаборе(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; МетаданныеРегистра = МестоИспользования.Метаданные; ПредставлениеДанных = Строка(Данные); // Будем производить сразу все замены для этих данных. Фильтр = Новый Структура("Данные, КлючЗамены"); ЗаполнитьЗначенияСвойств(Фильтр, МестоИспользования); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования ОписаниеНабора = ОписаниеНабораЗаписей(МетаданныеРегистра); НаборЗаписей = ОписаниеНабора.НаборЗаписей; // РегистрСведенийНаборЗаписей ПарыЗамен = Новый Соответствие; Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл ПарыЗамен.Вставить(СтрокаТаблицы.Ссылка, СтрокаТаблицы.ЦелеваяСсылка); КонецЦикла; // Помечаем как обработанные Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл СтрокаТаблицы.КлючЗамены = ""; КонецЦикла; СостояниеОперации = ""; НачатьТранзакцию(); Попытка // Блокировка и подготовка набора. Блокировка = Новый БлокировкаДанных; Для Каждого КлючЗначение Из ОписаниеНабора.СписокИзмерений Цикл ТипИзмерения = КлючЗначение.Значение; Имя = КлючЗначение.Ключ; Значение = Данные[Имя]; Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл ТекущаяСсылка = СтрокаТаблицы.Ссылка; Если ТипИзмерения.СодержитТип(ТипЗнч(ТекущаяСсылка)) Тогда Блокировка.Добавить(ОписаниеНабора.ПространствоБлокировки).УстановитьЗначение(Имя, ТекущаяСсылка); КонецЕсли; КонецЦикла; НаборЗаписей.Отбор[Имя].Установить(Значение); КонецЦикла; Попытка Блокировка.Заблокировать(); Исключение СостояниеОперации = "ОшибкаБлокировки"; УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Не удалось заменить в регистре ""%1"", т.к. данные редактируются в другом сеансе работы с приложением. |Повторите попытку замены.'"), ПредставлениеДанных); ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; НаборЗаписей.Прочитать(); ЗаменитьВКоллекцииСтрок("НаборЗаписей", "НаборЗаписей", НаборЗаписей, НаборЗаписей, ОписаниеНабора.СписокПолей, ПарыЗамен); Если НаборЗаписей.Модифицированность() Тогда ОтменитьТранзакцию(); Возврат; КонецЕсли; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка ЗаписатьОбъект(НаборЗаписей, ПараметрыВыполнения); Исключение СостояниеОперации = "ОшибкаЗаписи"; ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, НСтр("ru = 'Не удалось заменить по причине:'")); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Информация = ИнформацияОбОшибке(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, МетаданныеРегистра,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация)); Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке()); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, Ошибка, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЕсли; КонецПопытки; КонецПроцедуры Процедура ПроизвестиЗаменуВРегистреСведений(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) Если МестоИспользования.Обработано Тогда Возврат; КонецЕсли; МестоИспользования.Обработано = Истина; // В случае, если дубль указан в измерениях набора, тогда используется 2 набора записей: // НаборЗаписейДубля - чтение старых значений (по старым измерениям) и удаление старых значений. // НаборЗаписейОригинала - чтение актуальных значений (по новым измерениям) и запись новых значений. // Данные дублей и оригиналов объединяются по правилам: // Приоритет у данных оригинала. // Если в оригинале нет данных, то берутся данные из дубля. // Набор оригинала записывается, а набор дубля удаляется. // // В случае, если дубль не указан в измерениях набора, тогда используется 1 набор записей: // НаборЗаписейДубля - чтение старых значений и запись новых значений. // // Замена ссылок в ресурсах и реквизитах производится в обоих случаях. УстановитьПривилегированныйРежим(Истина); Дубль = МестоИспользования.Ссылка; Оригинал = МестоИспользования.ЦелеваяСсылка; МетаданныеРегистра = МестоИспользования.Метаданные; КлючЗаписиРегистра = МестоИспользования.Данные; Информация = ИнформацияОТипе(МетаданныеРегистра, ПараметрыВыполнения); ТребуетсяДваНабора = Ложь; Для Каждого КлючЗначение Из Информация.Измерения Цикл ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ]; Если ЗначениеИзмеренияДубля = Дубль Или ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля] = Дубль Тогда ТребуетсяДваНабора = Истина; // Дубль указан в измерениях. Прервать; КонецЕсли; КонецЦикла; Менеджер = МенеджерОбъектаПоПолномуИмени(Информация.ПолноеИмя); НаборЗаписейДубля = Менеджер.СоздатьНаборЗаписей(); Если ТребуетсяДваНабора Тогда ЗначенияИзмеренийОригинала = Новый Структура; НаборЗаписейОригинала = Менеджер.СоздатьНаборЗаписей(); КонецЕсли; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; БлокировкаДубля = Блокировка.Добавить(Информация.ПолноеИмя); Если ТребуетсяДваНабора Тогда БлокировкаОригинала = Блокировка.Добавить(Информация.ПолноеИмя); КонецЕсли; Для Каждого КлючЗначение Из Информация.Измерения Цикл ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ]; // Для решения проблемы уникальности // выполняется замена старых значений измерений ключа записи на актуальные. // Соответствие старых и актуальных обеспечивает соответствием УспешныеЗамены. // Данные соответствия актуальны на текущий момент времени, // т.к. пополняются только после успешной обработки очередной пары и фиксации транзакции. НовоеЗначениеИзмеренияДубля = ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля]; Если НовоеЗначениеИзмеренияДубля <> Неопределено Тогда ЗначениеИзмеренияДубля = НовоеЗначениеИзмеренияДубля; КонецЕсли; НаборЗаписейДубля.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияДубля); // Замена в конкретной паре и блокировка на конкретную замену. БлокировкаДубля.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияДубля); Если ТребуетсяДваНабора Тогда Если ЗначениеИзмеренияДубля = Дубль Тогда ЗначениеИзмеренияОригинала = Оригинал; Иначе ЗначениеИзмеренияОригинала = ЗначениеИзмеренияДубля; КонецЕсли; НаборЗаписейОригинала.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияОригинала); ЗначенияИзмеренийОригинала.Вставить(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала); // Замена в конкретной паре и блокировка на конкретную замену. БлокировкаОригинала.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала); КонецЕсли; КонецЦикла; Блокировка.Заблокировать(); НаборЗаписейДубля.Прочитать(); Если НаборЗаписейДубля.Количество() = 0 Тогда ОтменитьТранзакцию(); Возврат; КонецЕсли; ЗаписьДубля = НаборЗаписейДубля[0]; Если ТребуетсяДваНабора Тогда // Пишем в набор с другими измерениями. НаборЗаписейОригинала.Прочитать(); Если НаборЗаписейОригинала.Количество() = 0 Тогда ЗаписьОригинала = НаборЗаписейОригинала.Добавить(); ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗаписьДубля); ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗначенияИзмеренийОригинала); Иначе ЗаписьОригинала = НаборЗаписейОригинала[0]; КонецЕсли; Иначе // Пишем туда же, откуда и читаем. НаборЗаписейОригинала = НаборЗаписейДубля; ЗаписьОригинала = ЗаписьДубля; // Ситуация с нулевым количеством записей в наборе обработана выше. КонецЕсли; // Замена дубля на оригинал в ресурсах и реквизитах. Для Каждого КлючЗначение Из Информация.Ресурсы Цикл ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ]; Если ЗначениеРеквизитаВОригинале = Дубль Тогда ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал; КонецЕсли; КонецЦикла; Для Каждого КлючЗначение Из Информация.Реквизиты Цикл ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ]; Если ЗначениеРеквизитаВОригинале = Дубль Тогда ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал; КонецЕсли; КонецЦикла; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; // Удаление данных дубля. Если ТребуетсяДваНабора Тогда НаборЗаписейДубля.Очистить(); ЗаписатьОбъект(НаборЗаписейДубля, ПараметрыВыполнения); КонецЕсли; // Запись данных оригинала. Если НаборЗаписейОригинала.Модифицированность() Тогда ЗаписатьОбъект(НаборЗаписейОригинала, ПараметрыВыполнения); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, КлючЗаписиРегистра, Информация, "БлокировкаДляРегистра", ИнформацияОбОшибке()); КонецПопытки КонецПроцедуры Функция ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки) Данные = МестоИспользования.Данные; ОписаниеПоследовательностей = ОписаниеПоследовательностей(МестоИспользования.Метаданные); ОписаниеДвижений = ОписаниеДвижений(МестоИспользования.Метаданные, ПараметрыВыполнения); ОписаниеЗадач = ОписаниеЗадач(МестоИспользования.Метаданные); УстановитьПривилегированныйРежим(Истина); // Возвращаем измененные обработанные объекты. Измененные = Новый Соответствие; // Считываем Описание = ОписаниеОбъекта(Данные.Метаданные()); Попытка Объект = Данные.ПолучитьОбъект(); Исключение // Был уже обработан с ошибками. Объект = Неопределено; КонецПопытки; Если Объект = Неопределено Тогда Возврат Измененные; КонецЕсли; Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл ОписаниеДвижения.НаборЗаписей.Отбор.Регистратор.Установить(Данные); ОписаниеДвижения.НаборЗаписей.Прочитать(); КонецЦикла; Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл ОписаниеПоследовательности.НаборЗаписей.Отбор.Регистратор.Установить(Данные); ОписаниеПоследовательности.НаборЗаписей.Прочитать(); КонецЦикла; // Заменяем сразу все варианты. ПарыЗамен = Новый Соответствие; Для Каждого МестоИспользования Из ОбрабатываемыеСтроки Цикл ПарыЗамен.Вставить(МестоИспользования.Ссылка, МестоИспользования.ЦелеваяСсылка); КонецЦикла; ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен); // Движения Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл ЗаменитьВКоллекцииСтрок( "Движения", ОписаниеДвижения.ПространствоБлокировки, ОписаниеДвижения.НаборЗаписей, ОписаниеДвижения.НаборЗаписей, ОписаниеДвижения.СписокПолей, ПарыЗамен); КонецЦикла; // Последовательности Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл ЗаменитьВКоллекцииСтрок( "Последовательности", ОписаниеПоследовательности.ПространствоБлокировки, ОписаниеПоследовательности.НаборЗаписей, ОписаниеПоследовательности.НаборЗаписей, ОписаниеПоследовательности.СписокПолей, ПарыЗамен); КонецЦикла; Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл Если ОписаниеДвижения.НаборЗаписей.Модифицированность() Тогда Измененные.Вставить(ОписаниеДвижения.НаборЗаписей, Ложь); КонецЕсли; КонецЦикла; Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл Если ОписаниеПоследовательности.НаборЗаписей.Модифицированность() Тогда Измененные.Вставить(ОписаниеПоследовательности.НаборЗаписей, Ложь); КонецЕсли; КонецЦикла; Если ОписаниеЗадач <> Неопределено Тогда ЗадачаПроцесса = ЗадачиПроцесса(Данные, ОписаниеЗадач.ПространствоБлокировки); Пока ЗадачаПроцесса.Следующий() Цикл ЗадачаОбъект = ЗадачаПроцесса.Ссылка.ПолучитьОбъект(); Фильтр = Новый Структура("Данные, КлючЗамены", ЗадачаПроцесса.Ссылка, "Объект"); ОбрабатываемыеСтрокиЗадачи = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования Для каждого МестоИспользованияЗадачи Из ОбрабатываемыеСтрокиЗадачи Цикл ПарыЗамен.Вставить(МестоИспользованияЗадачи.Ссылка, МестоИспользованияЗадачи.ЦелеваяСсылка); КонецЦикла; ВыполнитьЗаменуВРеквизитахОбъекта(ЗадачаОбъект, ОписаниеЗадач, ПарыЗамен); Если ЗадачаОбъект.Модифицированность() Тогда Измененные.Вставить(ЗадачаОбъект, Ложь); КонецЕсли; КонецЦикла; КонецЕсли; // Сам объект последний - для возможного перепроведения. Если Объект.Модифицированность() Тогда Измененные.Вставить(Объект, Описание.МожетБытьПроведен); КонецЕсли; Возврат Измененные; КонецФункции Функция ЗадачиПроцесса(БизнесПроцесс, ТипЗадач) ТекстЗапроса = "ВЫБРАТЬ | ИмяТаблицы.Ссылка |ИЗ | &ИмяТаблицы КАК ИмяТаблицы |ГДЕ | ИмяТаблицы.БизнесПроцесс = &БизнесПроцесс"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипЗадач); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("БизнесПроцесс", БизнесПроцесс); Возврат Запрос.Выполнить().Выбрать(); КонецФункции Процедура ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен) // Реквизиты Для Каждого КлючЗначение Из Описание.Реквизиты Цикл Имя = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "Реквизиты", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; // Стандартные реквизиты Для Каждого КлючЗначение Из Описание.СтандартныеРеквизиты Цикл Имя = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "СтандартныеРеквизиты", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; // Табличные части Для Каждого Элемент Из Описание.ТабличныеЧасти Цикл ЗаменитьВКоллекцииСтрок( "ТабличныеЧасти", Элемент.Имя, Объект, Объект[Элемент.Имя], Элемент.СписокПолей, ПарыЗамен); КонецЦикла; // Стандартные табличные части. Для Каждого Элемент Из Описание.СтандартныеТабличныеЧасти Цикл ЗаменитьВКоллекцииСтрок( "СтандартныеТабличныеЧасти", Элемент.Имя, Объект, Объект[Элемент.Имя], Элемент.СписокПолей, ПарыЗамен); КонецЦикла; Для Каждого Реквизит Из Описание.РеквизитыАдресации Цикл Имя = Реквизит.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "РеквизитыАдресации", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ЗарегистрироватьФактЗамены(Объект, СсылкаДубля, СсылкаОригинала, ВидРеквизита, ИмяРеквизита, Индекс = Неопределено, ИмяКолонки = Неопределено) ЕстьДополнительныеСвойства = Новый Структура("ДополнительныеСвойства"); ЗаполнитьЗначенияСвойств(ЕстьДополнительныеСвойства, Объект); Если ТипЗнч(ЕстьДополнительныеСвойства.ДополнительныеСвойства) <> Тип("Структура") Тогда Возврат; КонецЕсли; ДополнительныеСвойства = Объект.ДополнительныеСвойства; ДополнительныеСвойства.Вставить("ЗаменаСсылок", Истина); ВыполненныеЗамены = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеСвойства, "ВыполненныеЗамены"); Если ВыполненныеЗамены = Неопределено Тогда ВыполненныеЗамены = Новый Массив; ДополнительныеСвойства.Вставить("ВыполненныеЗамены", ВыполненныеЗамены); КонецЕсли; ОписаниеЗамены = Новый Структура; ОписаниеЗамены.Вставить("СсылкаДубля", СсылкаДубля); ОписаниеЗамены.Вставить("СсылкаОригинала", СсылкаОригинала); ОписаниеЗамены.Вставить("ВидРеквизита", ВидРеквизита); ОписаниеЗамены.Вставить("ИмяРеквизита", ИмяРеквизита); ОписаниеЗамены.Вставить("Индекс", Индекс); ОписаниеЗамены.Вставить("ИмяКолонки", ИмяКолонки); ВыполненныеЗамены.Добавить(ОписаниеЗамены); КонецПроцедуры Процедура УстановитьПометкуУдаленияДляОбъектов(Результат, Знач УдаляемыеСсылки, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); ЕстьВнешняяТранзакция = ТранзакцияАктивна(); ВсеМестаИспользования = МестаИспользования(УдаляемыеСсылки,,ПараметрыВыполнения.ПараметрыПоискаМестИспользования); Для Каждого УдаляемаяСсылка Из УдаляемыеСсылки Цикл Информация = ИнформацияОТипе(ТипЗнч(УдаляемаяСсылка), ПараметрыВыполнения); Блокировка = Новый БлокировкаДанных; Блокировка.Добавить(Информация.ПолноеИмя).УстановитьЗначение("Ссылка", УдаляемаяСсылка); НачатьТранзакцию(); Попытка ЭтоОшибкаБлокировки = Истина; Блокировка.Заблокировать(); ЭтоОшибкаБлокировки = Ложь; Успешно = УстановитьПометкуУдаления(Результат, УдаляемаяСсылка, ВсеМестаИспользования, ПараметрыВыполнения, ЕстьВнешняяТранзакция); Если Не Успешно Тогда ОтменитьТранзакцию(); Продолжить; КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Если ЭтоОшибкаБлокировки Тогда ЗарегистрироватьОшибкуВТаблицу(Результат, УдаляемаяСсылка, Неопределено, УдаляемаяСсылка, Информация, "БлокировкаДляУдаленияДубля", ИнформацияОбОшибке()); КонецЕсли; Если ЕстьВнешняяТранзакция Тогда ВызватьИсключение; КонецЕсли; КонецПопытки; КонецЦикла; КонецПроцедуры Функция УстановитьПометкуУдаления(Результат, Знач УдаляемаяСсылка, Знач ВсеМестаИспользования, Знач ПараметрыВыполнения, ЕстьВнешняяТранзакция) УстановитьПривилегированныйРежим(Истина); ПредставлениеСсылки = ПредметСтрокой(УдаляемаяСсылка); Фильтр = Новый Структура("Ссылка"); Фильтр.Ссылка = УдаляемаяСсылка; МестаИспользования = ВсеМестаИспользования.НайтиСтроки(Фильтр); Индекс = МестаИспользования.ВГраница(); Пока Индекс >= 0 Цикл Если МестаИспользования[Индекс].ВспомогательныеДанные Тогда МестаИспользования.Удалить(Индекс); КонецЕсли; Индекс = Индекс - 1; КонецЦикла; Если МестаИспользования.Количество() > 0 Тогда ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, МестаИспользования, ПараметрыВыполнения); Возврат Ложь; // Остались места использования, нельзя удалять. КонецЕсли; Объект = УдаляемаяСсылка.ПолучитьОбъект(); // ДокументОбъект, СправочникОбъект Если Объект = Неопределено Тогда Возврат Ложь; // Уже удален. КонецЕсли; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Успешно = Истина; Попытка ЗаписатьОбъектСПерехватомСообщений(Объект, "ПометкаУдаления", Неопределено, ПараметрыВыполнения); Результат.ОчередьКНепосредственномуУдалению.Добавить(Объект.Ссылка); Исключение Успешно = Ложь; ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, НСтр("ru = 'Элемент не был помечен на удаление по причине:'")); Попытка ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); Исключение ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", УдаляемаяСсылка, ПредставлениеСсылки, ИнформацияОбОшибке()); ЗарегистрироватьОшибкуЗамены(Результат, УдаляемаяСсылка, ОписаниеОшибки, ПараметрыВыполнения.ПодчиненныеКДублям); Если ЕстьВнешняяТранзакция Тогда ВызватьИсключение; КонецЕсли; КонецПопытки; КонецПопытки; Возврат Успешно; КонецФункции Процедура ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска, ПараметрыВыполнения) Фильтр = Новый Структура("Ссылка, ОбъектОшибки"); Для Каждого СтрокаТаблицы Из ТаблицаПовторногоПоиска Цикл Тест = Новый Структура("ВспомогательныеДанные", Ложь); ЗаполнитьЗначенияСвойств(Тест, СтрокаТаблицы); Если Тест.ВспомогательныеДанные Тогда Продолжить; КонецЕсли; Фильтр.ОбъектОшибки = СтрокаТаблицы.Данные; Фильтр.Ссылка = СтрокаТаблицы.Ссылка; Если Результат.Ошибки.НайтиСтроки(Фильтр).Количество() > 0 Тогда Продолжить; // По данной проблеме уже записана ошибка. КонецЕсли; ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, ОписаниеОшибкиЗамены("ДанныеИзменены", СтрокаТаблицы.Данные, ПредметСтрокой(СтрокаТаблицы.Данные), НСтр("ru = 'Заменены не все места использования. Возможно места использования были добавлены или изменены другим пользователем.'")), ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; КонецПроцедуры Процедура ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования) Если МестоИспользования.КлючЗамены = "Константа" Тогда Блокировка.Добавить(МестоИспользования.Метаданные.ПолноеИмя()); ИначеЕсли МестоИспользования.КлючЗамены = "Объект" Тогда СсылкаОбъекта = МестоИспользования.Данные; МетаданныеОбъекта = МестоИспользования.Метаданные; // Сам объект. Блокировка.Добавить(МетаданныеОбъекта.ПолноеИмя()).УстановитьЗначение("Ссылка", СсылкаОбъекта); // Движения по регистратору. ОписаниеДвижений = ОписаниеДвижений(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеДвижений Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки + ".НаборЗаписей").УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; // Последовательности. ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеПоследовательностей Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; // Задачи (для бизнес-процессов) ОписаниеЗадач = ОписаниеЗадач(МетаданныеОбъекта); Если ОписаниеЗадач <> Неопределено Тогда Блокировка.Добавить(ОписаниеЗадач.ПространствоБлокировки).УстановитьЗначение("БизнесПроцесс", СсылкаОбъекта); КонецЕсли; ИначеЕсли МестоИспользования.КлючЗамены = "Последовательность" Тогда СсылкаОбъекта = МестоИспользования.Данные; МетаданныеОбъекта = МестоИспользования.Метаданные; ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеПоследовательностей Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; ИначеЕсли МестоИспользования.КлючЗамены = "КлючЗаписи" Или МестоИспользования.КлючЗамены = "РегистрСведений" Тогда Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения); ТипДубля = МестоИспользования.ТипСсылки; ТипОригинала = ТипЗнч(МестоИспользования.ЦелеваяСсылка); Для Каждого КлючЗначение Из Информация.Измерения Цикл ТипИзмерения = КлючЗначение.Значение.Тип; Если ТипИзмерения.СодержитТип(ТипДубля) Тогда БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя); БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.Ссылка); КонецЕсли; Если ТипИзмерения.СодержитТип(ТипОригинала) Тогда БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя); БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.ЦелеваяСсылка); КонецЕсли; КонецЦикла; КонецЕсли; КонецПроцедуры Процедура ОтключитьОбновлениеКлючейДоступа(Значение) Если ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда УстановитьПривилегированныйРежим(Истина); МодульУправлениеДоступом = ОбщийМодуль("УправлениеДоступом"); МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Значение); КонецЕсли; КонецПроцедуры // Параметры: // ОбъектМетаданных - ОбъектМетаданных // ПараметрыВыполнения - см. ПараметрыПоискаМестИспользования // // Возвращаемое значение: // Массив из Структура: // * СписокПолей - Структура // * СтруктураИзмерений - Структура // * СписокВедущих - Структура // * НаборЗаписей - РегистрСведенийНаборЗаписей // * ПространствоБлокировки - Строка // Функция ОписаниеДвижений(Знач ОбъектМетаданных, ПараметрыВыполнения = Неопределено) ОписаниеДвижений = Новый Массив; Если Не Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда Возврат ОписаниеДвижений; КонецЕсли; Исключения = ИсключенияПоискаСсылок(); Для Каждого Движение Из ОбъектМетаданных.Движения Цикл Если Исключения[Движение] = "*" Тогда Если ПараметрыВыполнения <> Неопределено И ПараметрыВыполнения.УдалятьНепосредственно Тогда ОбщегоНазначенияКлиентСервер.ДополнитьМассив( ПараметрыВыполнения.ПараметрыПоискаМестИспользования.ИсключенияПоискаРегистровПодчиненныхРегистратору, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Движение), Истина); КонецЕсли; Продолжить; КонецЕсли; Если Метаданные.РегистрыНакопления.Содержит(Движение) Тогда НаборЗаписей = РегистрыНакопления[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыСведений.Содержит(Движение) Тогда НаборЗаписей = РегистрыСведений[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(Движение) Тогда НаборЗаписей = РегистрыБухгалтерии[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыРасчета.Содержит(Движение) Тогда НаборЗаписей = РегистрыРасчета[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, БазовыйПериодКонец, БазовыйПериодНачало, НомерСтроки, ПериодДействия, |ПериодДействияКонец, ПериодДействияНачало, ПериодРегистрации, Регистратор, Сторно, |ФактическийПериодДействия"; Иначе // Неизвестный тип Продолжить; КонецЕсли; // Поля ссылочного типа и измерения - кандидаты. // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. Описание = СпискиПолейОбъекта(НаборЗаписей, Движение.Измерения, ИсключатьПоля); Если Описание.СписокПолей.Количество() = 0 Тогда // Незачем обрабатывать Продолжить; КонецЕсли; Описание.Вставить("НаборЗаписей", НаборЗаписей); Описание.Вставить("ПространствоБлокировки", Движение.ПолноеИмя() ); ОписаниеДвижений.Добавить(Описание); КонецЦикла; Возврат ОписаниеДвижений; КонецФункции // Параметры: // Мета - ОбъектМетаданных // // Возвращаемое значение: // Массив из Структура: // * НаборЗаписей - ПоследовательностьНаборЗаписей // * ПространствоБлокировки - Строка // * Измерения - Структура // Функция ОписаниеПоследовательностей(Знач Мета) ОписаниеПоследовательностей = Новый Массив; Если Не Метаданные.Документы.Содержит(Мета) Тогда Возврат ОписаниеПоследовательностей; КонецЕсли; Для Каждого Последовательность Из Метаданные.Последовательности Цикл Если Не Последовательность.Документы.Содержит(Мета) Тогда Продолжить; КонецЕсли; ИмяТаблицы = Последовательность.ПолноеИмя(); // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. Описание = СпискиПолейОбъекта(ИмяТаблицы, Последовательность.Измерения, "Регистратор"); Если Описание.СписокПолей.Количество() > 0 Тогда Описание.Вставить("НаборЗаписей", Последовательности[Последовательность.Имя].СоздатьНаборЗаписей()); Описание.Вставить("ПространствоБлокировки", ИмяТаблицы + ".Записи"); Описание.Вставить("Измерения", Новый Структура); ОписаниеПоследовательностей.Добавить(Описание); КонецЕсли; КонецЦикла; Возврат ОписаниеПоследовательностей; КонецФункции // Возвращаемое значение: // Структура: // * СтандартныеРеквизиты - Структура // * РеквизитыАдресации - Структура // * Реквизиты - Структура // * СтандартныеТабличныеЧасти - Массив из Структура: // ** Имя - Строка // ** СписокПолей - Структура // * ТабличныеЧасти - Массив из Структура: // ** Имя - Строка // ** СписокПолей - Структура // * МожетБытьПроведен - Булево // Функция ОписаниеОбъекта(Знач ОбъектМетаданных) ТипВсеСсылки = ОписаниеТипаВсеСсылки(); Кандидаты = Новый Структура("Реквизиты, СтандартныеРеквизиты, ТабличныеЧасти, СтандартныеТабличныеЧасти, РеквизитыАдресации"); ЗаполнитьЗначенияСвойств(Кандидаты, ОбъектМетаданных); ОписаниеОбъекта = Новый Структура; ОписаниеОбъекта.Вставить("Реквизиты", Новый Структура); Если Кандидаты.Реквизиты <> Неопределено Тогда Для Каждого МетаРеквизит Из Кандидаты.Реквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("СтандартныеРеквизиты", Новый Структура); Если Кандидаты.СтандартныеРеквизиты <> Неопределено Тогда Исключаемые = Новый Структура("Ссылка"); Для Каждого МетаРеквизит Из Кандидаты.СтандартныеРеквизиты Цикл Имя = МетаРеквизит.Имя; Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("ТабличныеЧасти", Новый Массив); Если Кандидаты.ТабличныеЧасти <> Неопределено Тогда Для Каждого МетаТаблица Из Кандидаты.ТабличныеЧасти Цикл СписокПолей = Новый Структура; Для Каждого МетаРеквизит Из МетаТаблица.Реквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда СписокПолей.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; Если СписокПолей.Количество() > 0 Тогда ОписаниеОбъекта.ТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей)); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("СтандартныеТабличныеЧасти", Новый Массив); Если Кандидаты.СтандартныеТабличныеЧасти <> Неопределено Тогда Для Каждого МетаТаблица Из Кандидаты.СтандартныеТабличныеЧасти Цикл СписокПолей = Новый Структура; Для Каждого МетаРеквизит Из МетаТаблица.СтандартныеРеквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда СписокПолей.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; Если СписокПолей.Количество() > 0 Тогда ОписаниеОбъекта.СтандартныеТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей)); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("РеквизитыАдресации", Новый Структура); Если Кандидаты.РеквизитыАдресации <> Неопределено Тогда Для Каждого Реквизит Из Кандидаты.РеквизитыАдресации Цикл Если ОписанияТиповПересекаются(Реквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.РеквизитыАдресации.Вставить(Реквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("МожетБытьПроведен", Метаданные.Документы.Содержит(ОбъектМетаданных)); Возврат ОписаниеОбъекта; КонецФункции // Параметры: // ОбъектМетаданных - ОбъектМетаданных // // Возвращаемое значение: // Массив из Структура: // * СписокПолей - Структура // * СтруктураИзмерений - Структура // * СписокВедущих - Структура // * НаборЗаписей - РегистрСведенийНаборЗаписей // * ПространствоБлокировки - Строка // Функция ОписаниеЗадач(Знач Мета) ОписаниеЗадач = Неопределено; Если НЕ Метаданные.БизнесПроцессы.Содержит(Мета) Тогда Возврат ОписаниеЗадач; КонецЕсли; ОписаниеЗадач = ОписаниеОбъекта(Мета.Задача); ОписаниеЗадач.Вставить("ПространствоБлокировки", Мета.Задача.ПолноеИмя()); Возврат ОписаниеЗадач; КонецФункции Функция ОписаниеНабораЗаписей(Знач МетаданныеТаблицы) ИмяТаблицы = МетаданныеТаблицы.ПолноеИмя(); // Поля ссылочного типа - кандидаты и набор измерений. // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. ОписаниеКлюча = СпискиПолейОбъекта(ИмяТаблицы, МетаданныеТаблицы.Измерения, "Период, Регистратор"); Если Метаданные.РегистрыСведений.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыСведений[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыНакопления.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыНакопления[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыБухгалтерии[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыРасчета.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыРасчета[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.Последовательности.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = Последовательности[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); Иначе НаборЗаписей = Неопределено; КонецЕсли; ОписаниеКлюча.Вставить("НаборЗаписей", НаборЗаписей); ОписаниеКлюча.Вставить("ПространствоБлокировки", ИмяТаблицы); Возврат ОписаниеКлюча; КонецФункции Функция ОписанияТиповПересекаются(Знач Описание1, Знач Описание2) Для Каждого Тип Из Описание1.Типы() Цикл Если Описание2.СодержитТип(Тип) Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Возвращает описание по имени таблицы или по набору записей. Функция СпискиПолейОбъекта(Знач ИсточникДанных, Знач МетаданныеИзмеренийРегистра, Знач ИсключатьПоля) Описание = Новый Структура; Описание.Вставить("СписокПолей", Новый Структура); Описание.Вставить("СтруктураИзмерений", Новый Структура); Описание.Вставить("СписокВедущих", Новый Структура); ТипКонтроля = ОписаниеТипаВсеСсылки(); Исключаемые = Новый Структура(ИсключатьПоля); ТипИсточникаДанных = ТипЗнч(ИсточникДанных); Если ТипИсточникаДанных = Тип("Строка") Тогда // Источник - имя таблицы, получаем поля запросом. ТекстЗапроса = "ВЫБРАТЬ * ИЗ &ИмяТаблицы ГДЕ ЛОЖЬ"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИсточникДанных); Запрос = Новый Запрос(ТекстЗапроса); ИсточникПолей = Запрос.Выполнить(); Иначе // Источник - набор записей ИсточникПолей = ИсточникДанных.ВыгрузитьКолонки(); КонецЕсли; Для Каждого Колонка Из ИсточникПолей.Колонки Цикл Имя = Колонка.Имя; Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(Колонка.ТипЗначения, ТипКонтроля) Тогда Описание.СписокПолей.Вставить(Имя); // И проверка на ведущее измерение. Мета = МетаданныеИзмеренийРегистра.Найти(Имя); Если Мета <> Неопределено Тогда Описание.СтруктураИзмерений.Вставить(Имя, Мета.Тип); Тест = Новый Структура("Ведущее", Ложь); ЗаполнитьЗначенияСвойств(Тест, Мета); Если Тест.Ведущее Тогда Описание.СписокВедущих.Вставить(Имя, Мета.Тип); КонецЕсли; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Описание; КонецФункции Процедура ЗаменитьВКоллекцииСтрок(ВидКоллекции, ИмяКоллекции, Объект, Коллекция, Знач СписокПолей, Знач ПарыЗамен) ИзмененнаяКоллекция = Коллекция.Выгрузить(); Модифицировано = Ложь; ИменаИзмененныхРеквизитов = Новый Массив; Для Каждого СтрокаТаблицы Из ИзмененнаяКоллекция Цикл Для Каждого КлючЗначение Из СписокПолей Цикл ИмяРеквизита = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ СтрокаТаблицы[ИмяРеквизита] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, СтрокаТаблицы[ИмяРеквизита], ЦелеваяСсылка, ВидКоллекции, ИмяКоллекции, ИзмененнаяКоллекция.Индекс(СтрокаТаблицы), ИмяРеквизита); СтрокаТаблицы[ИмяРеквизита] = ЦелеваяСсылка; Модифицировано = Истина; ИменаИзмененныхРеквизитов.Добавить(ИмяРеквизита); КонецЕсли; КонецЦикла; КонецЦикла; Если Модифицировано Тогда ЭтоРегистрБухгалтерии = ВидКоллекции = "Движения" И ЭтоРегистрБухгалтерии(Коллекция.Метаданные()); Если ЭтоРегистрБухгалтерии Тогда ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(Коллекция, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов); Иначе Коллекция.Загрузить(ИзмененнаяКоллекция); КонецЕсли; КонецЕсли; КонецПроцедуры Процедура ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(НаборЗаписей, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов) НеизмененныеИзмерения = Новый Соответствие; ИзмененныеИзмерения = Новый Соответствие; НеизмененныеРесурсы = Новый Соответствие; ИзмененныеРесурсы = Новый Соответствие; МетаданныеРегистра = НаборЗаписей.Метаданные(); Для Каждого Измерение Из МетаданныеРегистра.Измерения Цикл ИменаИзмерений = Новый Массив; Если Измерение.Балансовый Или Не МетаданныеРегистра.Корреспонденция Тогда ИменаИзмерений.Добавить(Измерение.Имя); Иначе ИменаИзмерений.Добавить(Измерение.Имя + "Дт"); ИменаИзмерений.Добавить(Измерение.Имя + "Кт"); КонецЕсли; Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл Если ИменаИзмененныхРеквизитов.Найти(ИмяИзмерения) = Неопределено Тогда НеизмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения)); Иначе ИзмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения)); КонецЕсли; КонецЦикла; КонецЦикла; Для Каждого Ресурс Из МетаданныеРегистра.Ресурсы Цикл ИменаРесурсов = Новый Массив; Если Ресурс.Балансовый Или Не МетаданныеРегистра.Корреспонденция Тогда ИменаРесурсов.Добавить(Ресурс.Имя); Иначе ИменаРесурсов.Добавить(Ресурс.Имя + "Дт"); ИменаРесурсов.Добавить(Ресурс.Имя + "Кт"); КонецЕсли; Для Каждого ИмяРесурса Из ИменаРесурсов Цикл Если ИменаИзмененныхРеквизитов.Найти(ИмяРесурса) = Неопределено Тогда НеизмененныеРесурсы.Вставить(ИмяРесурса, НаборЗаписей.ВыгрузитьКолонку(ИмяРесурса)); Иначе ИзмененныеРесурсы.Вставить(ИмяРесурса, НаборЗаписей.ВыгрузитьКолонку(ИмяРесурса)); КонецЕсли; КонецЦикла; КонецЦикла; Для Сч = 0 По НаборЗаписей.Количество() - 1 Цикл Для Каждого ИмяИзмеренияЗначения Из ИзмененныеИзмерения Цикл Если НаборЗаписей[Сч][ИмяИзмеренияЗначения.Ключ] = NULL Тогда ИмяИзмеренияЗначения.Значение[Сч] = NULL; Иначе ИмяИзмеренияЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяИзмеренияЗначения.Ключ]; КонецЕсли; КонецЦикла; Для Каждого ИмяРесурсаЗначения Из ИзмененныеРесурсы Цикл Если НаборЗаписей[Сч][ИмяРесурсаЗначения.Ключ] = NULL Тогда ИмяРесурсаЗначения.Значение[Сч] = NULL; Иначе ИмяРесурсаЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяРесурсаЗначения.Ключ]; КонецЕсли; КонецЦикла; КонецЦикла; НаборЗаписей.Загрузить(ИзмененнаяКоллекция); Для Каждого ИзмеренияЗначенияВКолонке Из НеизмененныеИзмерения Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; Для Каждого ИзмеренияЗначенияВКолонке Из ИзмененныеИзмерения Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; Для Каждого ИзмеренияЗначенияВКолонке Из НеизмененныеРесурсы Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; Для Каждого ИзмеренияЗначенияВКолонке Из ИзмененныеРесурсы Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; КонецПроцедуры Процедура ЗаписатьОбъектСПерехватомСообщений(Знач Объект, Знач Действие, Знач РежимЗаписи, Знач ПараметрыЗаписи) // Текущие сообщения до исключения запоминаем. ПредыдущиеСообщения = ПолучитьСообщенияПользователю(Истина); СообщатьПовторно = ТекущийРежимЗапуска() <> Неопределено; Попытка Если Действие = "Запись" Тогда Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Если РежимЗаписи = Неопределено Тогда Объект.Записать(); Иначе Объект.Записать(РежимЗаписи); КонецЕсли; ИначеЕсли Действие = "ПометкаУдаления" Тогда МетаданныеОбъекта = Объект.Метаданные(); Если ЭтоСправочник(МетаданныеОбъекта) Или ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или ЭтоПланСчетов(МетаданныеОбъекта) Тогда Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Объект.УстановитьПометкуУдаления(Истина, Ложь); ИначеЕсли ЭтоДокумент(МетаданныеОбъекта) И МетаданныеОбъекта.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда Объект.УстановитьПометкуУдаления(Истина); Иначе Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Объект.УстановитьПометкуУдаления(Истина); КонецЕсли; КонецЕсли; Исключение ТекстСообщений = ""; Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Ложь) Цикл ТекстСообщений = ТекстСообщений + Символы.ПС + Сообщение.Текст; КонецЦикла; Если СообщатьПовторно Тогда СообщитьОтложенныеСообщения(ПредыдущиеСообщения); КонецЕсли; Если ТекстСообщений = "" Тогда ВызватьИсключение; КонецЕсли; ИнформацияОбОшибке = ИнформацияОбОшибке(); Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); Уточнение.Текст = Уточнение.Текст + Символы.ПС + СокрЛП(ТекстСообщений); ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке); КонецПопытки; Если СообщатьПовторно Тогда СообщитьОтложенныеСообщения(ПредыдущиеСообщения); КонецЕсли; КонецПроцедуры Процедура СообщитьОтложенныеСообщения(Знач Сообщения) Для Каждого Сообщение Из Сообщения Цикл Сообщение.Сообщить(); КонецЦикла; КонецПроцедуры Процедура ЗаписатьОбъект(Знач Объект, Знач ПараметрыЗаписи) МетаданныеОбъекта = Объект.Метаданные(); Если ЭтоДокумент(МетаданныеОбъекта) Тогда ЗаписатьОбъектСПерехватомСообщений(Объект, "Запись", РежимЗаписиДокумента.Запись, ПараметрыЗаписи); Возврат; КонецЕсли; // Проверка на возможные циклические ссылки. СвойстваОбъекта = Новый Структура("Иерархический, ВидыСубконто, Владельцы", Ложь, Неопределено, Новый Массив); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, МетаданныеОбъекта); // По родителю Если СвойстваОбъекта.Иерархический Или СвойстваОбъекта.ВидыСубконто <> Неопределено Тогда Если Объект.Родитель = Объект.Ссылка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Невозможно записать ""%1"", т.к. его родительским элементом не может быть он сам.'"), ПредметСтрокой(Объект)); КонецЕсли; КонецЕсли; // По владельцу Если СвойстваОбъекта.Владельцы.Количество() > 1 И Объект.Владелец = Объект.Ссылка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Невозможно записать ""%1"", т.к. его владельцем не может быть он сам.'"), ПредметСтрокой(Объект)); КонецЕсли; // Для последовательностей право "Изменение" может отсутствовать даже у роли "АдминистраторСистемы". Если ЭтоПоследовательность(МетаданныеОбъекта) И Не ПравоДоступа("Изменение", МетаданныеОбъекта) И Пользователи.ЭтоПолноправныйПользователь(,, Ложь) Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; ЗаписатьОбъектСПерехватомСообщений(Объект, "Запись", Неопределено, ПараметрыЗаписи); КонецПроцедуры Функция СобытиеЖурналаРегистрацииЗаменыСсылок() Возврат НСтр("ru = 'Поиск и удаление ссылок'", КодОсновногоЯзыка()); КонецФункции // Параметры: // Результат - см. РезультатЗаменыСсылок // Ссылка - ЛюбаяСсылка // ОписаниеОшибки - см. ОписаниеОшибкиЗамены // ПодчиненныеКДублям - Соответствие, Неопределено // Процедура ЗарегистрироватьОшибкуЗамены(Результат, Знач Ссылка, Знач ОписаниеОшибки, ПодчиненныеКДублям = Неопределено) Результат.ЕстьОшибки = Истина; Строка = Результат.Ошибки.Добавить(); Строка.Ссылка = Ссылка; Строка.ПредставлениеОбъектаОшибки = ОписаниеОшибки.ПредставлениеОбъектаОшибки; Строка.ОбъектОшибки = ОписаниеОшибки.ОбъектОшибки; Строка.ИнформацияОбОшибке = ?(ТипЗнч(ОписаниеОшибки.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке"), ОписаниеОшибки.ИнформацияОбОшибке, Неопределено); Строка.ТекстОшибки = ?(ТипЗнч(ОписаниеОшибки.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ОписаниеОшибки.ИнформацияОбОшибке), ОписаниеОшибки.ИнформацияОбОшибке); Строка.ТипОшибки = ОписаниеОшибки.ТипОшибки; ДубльРодитель = Ссылка; Если ПодчиненныеКДублям <> Неопределено И ПодчиненныеКДублям[Ссылка] <> Неопределено Тогда ДубльРодитель = ПодчиненныеКДублям[Ссылка]; КонецЕсли; Строка.ДубльРодитель = ДубльРодитель; КонецПроцедуры // Возвращаемое значение: // Структура: // * ТипОшибки - Строка // * ОбъектОшибки - ЛюбаяСсылка // * ПредставлениеОбъектаОшибки - Строка // * ИнформацияОбОшибке - ИнформацияОбОшибке, Строка // Функция ОписаниеОшибкиЗамены(Знач ТипОшибки, Знач ОбъектОшибки, Знач ПредставлениеОбъектаОшибки, Знач ИнформацияОбОшибке) Результат = Новый Структура; Результат.Вставить("ТипОшибки", ТипОшибки); Результат.Вставить("ОбъектОшибки", ОбъектОшибки); Результат.Вставить("ПредставлениеОбъектаОшибки", ПредставлениеОбъектаОшибки); Результат.Вставить("ИнформацияОбОшибке", ИнформацияОбОшибке); Возврат Результат; КонецФункции // Возвращаемое значение: // Структура: // * ЕстьОшибки - Булево // * ОчередьКНепосредственномуУдалению - Массив // * Ошибки - см. ОбщегоНазначения.ЗаменитьСсылки // Функция РезультатЗаменыСсылок(Знач ОшибкиЗамены) Результат = Новый Структура; Результат.Вставить("ЕстьОшибки", Ложь); Результат.Вставить("ОчередьКНепосредственномуУдалению", Новый Массив); Результат.Вставить("Ошибки", ОшибкиЗамены); Возврат Результат КонецФункции Процедура ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, Данные, Информация, ТипОшибки, ИнформацияОбОшибке) Результат.ЕстьОшибки = Истина; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); ПолноеПредставлениеДанных = Строка(Данные) + " (" + Информация.ПредставлениеЭлемента + ")"; Ошибка = Результат.Ошибки.Добавить(); Ошибка.Ссылка = Дубль; Ошибка.ОбъектОшибки = Данные; Ошибка.ПредставлениеОбъектаОшибки = ПолноеПредставлениеДанных; Если ТипОшибки = "БлокировкаДляРегистра" Тогда НовыйШаблон = НСтр("ru = 'Не удалось начать редактирование %1: %2'"); Ошибка.ТипОшибки = "ОшибкаБлокировки"; ИначеЕсли ТипОшибки = "БлокировкаДляУдаленияДубля" Тогда НовыйШаблон = НСтр("ru = 'Не удалось начать удаление: %2'"); Ошибка.ТипОшибки = "ОшибкаБлокировки"; ИначеЕсли ТипОшибки = "УдалитьНаборДубля" Тогда НовыйШаблон = НСтр("ru = 'Не удалось очистить сведения о дубле в %1: %2'"); Ошибка.ТипОшибки = "ОшибкаЗаписи"; ИначеЕсли ТипОшибки = "ЗаписатьНаборОригинала" Тогда НовыйШаблон = НСтр("ru = 'Не удалось обновить сведения в %1: %2'"); Ошибка.ТипОшибки = "ОшибкаЗаписи"; Иначе НовыйШаблон = ТипОшибки + " (%1): %2"; Ошибка.ТипОшибки = ТипОшибки; КонецЕсли; НовыйШаблон = НовыйШаблон + Символы.ПС + Символы.ПС + НСтр("ru = 'Подробности в журнале регистрации.'"); КраткоеПредставление = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); Ошибка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НовыйШаблон, ПолноеПредставлениеДанных, КраткоеПредставление); КонецПроцедуры // Формирует информацию о типе объекта метаданных: полное имя, представления, вид и т.п. Функция ИнформацияОТипе(ПолноеИмяИлиМетаданныеИлиТип, Кэш) ТипПервогоПараметра = ТипЗнч(ПолноеИмяИлиМетаданныеИлиТип); Если ТипПервогоПараметра = Тип("Строка") Тогда ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяИлиМетаданныеИлиТип); Иначе Если ТипПервогоПараметра = Тип("Тип") Тогда // Поиск объекта метаданных. ОбъектМетаданных = Метаданные.НайтиПоТипу(ПолноеИмяИлиМетаданныеИлиТип); Иначе ОбъектМетаданных = ПолноеИмяИлиМетаданныеИлиТип; КонецЕсли; КонецЕсли; ПолноеИмя = ВРег(ОбъектМетаданных.ПолноеИмя()); ИнформацияОТипах = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Кэш, "ИнформацияОТипах"); Если ИнформацияОТипах = Неопределено Тогда ИнформацияОТипах = Новый Соответствие; Кэш.Вставить("ИнформацияОТипах", ИнформацияОТипах); Иначе Информация = ИнформацияОТипах.Получить(ПолноеИмя); Если Информация <> Неопределено Тогда Возврат Информация; КонецЕсли; КонецЕсли; Информация = Новый Структура("ПолноеИмя, ПредставлениеЭлемента, |Вид, Ссылочный, Технический, Разделенный, |Иерархический, |ЕстьПодчиненные, ИменаПодчиненных, |Измерения, Реквизиты, Ресурсы"); ИнформацияОТипах.Вставить(ПолноеИмя, Информация); // Заполнение базовой информации. Информация.ПолноеИмя = ПолноеИмя; // Представление элемента. Информация.ПредставлениеЭлемента = ПредставлениеОбъекта(ОбъектМетаданных); // Вид и его свойства. Информация.Вид = Лев(Информация.ПолноеИмя, СтрНайти(Информация.ПолноеИмя, ".")-1); Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ДОКУМЕНТ" Или Информация.Вид = "ПЕРЕЧИСЛЕНИЕ" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Или Информация.Вид = "ПЛАНСЧЕТОВ" Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА" Или Информация.Вид = "БИЗНЕСПРОЦЕСС" Или Информация.Вид = "ЗАДАЧА" Или Информация.Вид = "ПЛАНОБМЕНА" Тогда Информация.Ссылочный = Истина; Иначе Информация.Ссылочный = Ложь; КонецЕсли; Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Тогда Информация.Иерархический = ОбъектМетаданных.Иерархический; ИначеЕсли Информация.Вид = "ПЛАНСЧЕТОВ" Тогда Информация.Иерархический = Истина; Иначе Информация.Иерархический = Ложь; КонецЕсли; Информация.ЕстьПодчиненные = Ложь; Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Или Информация.Вид = "ПЛАНОБМЕНА" Или Информация.Вид = "ПЛАНСЧЕТОВ" Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА" Тогда Для Каждого Справочник Из Метаданные.Справочники Цикл Если Справочник.Владельцы.Содержит(ОбъектМетаданных) Тогда Если Информация.ЕстьПодчиненные = Ложь Тогда Информация.ЕстьПодчиненные = Истина; Информация.ИменаПодчиненных = Новый Массив; КонецЕсли; ИменаПодчиненных = Информация.ИменаПодчиненных; // Массив - ИменаПодчиненных.Добавить(Справочник.ПолноеИмя()); КонецЕсли; КонецЦикла; КонецЕсли; Если Информация.ПолноеИмя = "СПРАВОЧНИК.ИДЕНТИФИКАТОРЫОБЪЕКТОВМЕТАДАННЫХ" Или Информация.ПолноеИмя = "СПРАВОЧНИК.ПРЕДОПРЕДЕЛЕННЫЕВАРИАНТЫОТЧЕТОВ" Тогда Информация.Технический = Истина; Информация.Разделенный = Ложь; Иначе Информация.Технический = Ложь; Если Не Кэш.Свойство("МодельСервиса") Тогда Кэш.Вставить("МодельСервиса", РазделениеВключено()); Если Кэш.МодельСервиса Тогда Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); РазделительОсновныхДанных = МодульРаботаВМоделиСервиса.РазделительОсновныхДанных(); РазделительВспомогательныхДанных = МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных(); Иначе РазделительОсновныхДанных = Неопределено; РазделительВспомогательныхДанных = Неопределено; КонецЕсли; Кэш.Вставить("ВОбластиДанных", РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных()); Кэш.Вставить("РазделительОсновныхДанных", РазделительОсновныхДанных); Кэш.Вставить("РазделительВспомогательныхДанных", РазделительВспомогательныхДанных); КонецЕсли; КонецЕсли; Если Кэш.МодельСервиса Тогда Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ОбъектМетаданных); Иначе ЭтоРазделенныйОбъектМетаданных = Истина; КонецЕсли; Информация.Разделенный = ЭтоРазделенныйОбъектМетаданных; КонецЕсли; КонецЕсли; Информация.Измерения = Новый Структура; Информация.Реквизиты = Новый Структура; Информация.Ресурсы = Новый Структура; ВидыРеквизитов = Новый Структура("СтандартныеРеквизиты, Реквизиты, Измерения, Ресурсы"); ЗаполнитьЗначенияСвойств(ВидыРеквизитов, ОбъектМетаданных); Для Каждого КлючИЗначение Из ВидыРеквизитов Цикл Коллекция = КлючИЗначение.Значение; // КоллекцияОбъектовМетаданных Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда КудаПишем = ?(Информация.Свойство(КлючИЗначение.Ключ), Информация[КлючИЗначение.Ключ], Информация.Реквизиты); Для Каждого Реквизит Из Коллекция Цикл КудаПишем.Вставить(Реквизит.Имя, ИнформацияПоРеквизиту(Реквизит)); КонецЦикла; КонецЕсли; КонецЦикла; Если Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" И ОбъектМетаданных.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда ИнформацияПоРеквизиту = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения"); ИнформацияПоРеквизиту.Ведущее = Ложь; ИнформацияПоРеквизиту.ЗаполнятьИзДанныхЗаполнения = Ложь; Если ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора Тогда ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("МоментВремени"); ИначеЕсли ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Секунда Тогда ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)); Иначе ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)); КонецЕсли; Информация.Измерения.Вставить("Период", ИнформацияПоРеквизиту); КонецЕсли; Возврат Информация; КонецФункции // Параметры: // МетаданныеРеквизита - ОбъектМетаданныхРеквизит // Функция ИнформацияПоРеквизиту(МетаданныеРеквизита) // ОписаниеСтандартногоРеквизита // ОбъектМетаданных: Измерение // ОбъектМетаданных: Ресурс // ОбъектМетаданных: Реквизит Информация = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения"); ЗаполнитьЗначенияСвойств(Информация, МетаданныеРеквизита); Информация.Представление = МетаданныеРеквизита.Представление(); Если Информация.ЗаполнятьИзДанныхЗаполнения = Истина Тогда Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.ЗначениеЗаполнения; Иначе Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.Тип.ПривестиЗначение(); КонецЕсли; Возврат Информация; КонецФункции Процедура ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, ЕстьОшибки) КлючДубля = Дубль.Метаданные().ПолноеИмя(); ЭлементСтатистики = Статистика[КлючДубля]; Если ЭлементСтатистики = Неопределено Тогда ЭлементСтатистики = Новый Структура("КоличествоЭлементов, КоличествоОшибок",0,0); Статистика.Вставить(КлючДубля, ЭлементСтатистики); КонецЕсли; ЭлементСтатистики.КоличествоЭлементов = ЭлементСтатистики.КоличествоЭлементов + 1; ЭлементСтатистики.КоличествоОшибок = ЭлементСтатистики.КоличествоОшибок + ?(ЕстьОшибки, 1,0); КонецПроцедуры Процедура ОтправитьСтатистикуЗаменыСсылок(Статистика) Если НЕ ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда Возврат; КонецЕсли; МодульЦентрМониторинга = ОбщийМодуль("ЦентрМониторинга"); Для каждого ЭлементСтатистики Из Статистика Цикл МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики( "БазоваяФункциональность.ЗаменаСсылок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоЭлементов); МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики( "БазоваяФункциональность.ЗаменаСсылокКоличествоОшибок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоОшибок); КонецЦикла; КонецПроцедуры Процедура ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(Знач ИсключенияПоискаСсылок) Для каждого ОписаниеПодчиненногоОбъекта Из ПодчиненныеОбъекты() Цикл ПоляСвязи = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок( ОписаниеПодчиненногоОбъекта.ПоляСвязей, ",",, Истина); ЗначениеИсключенияПоискаСсылок = Новый Массив; Для каждого ПолеСвязи Из ПоляСвязи Цикл ЗначениеИсключенияПоискаСсылок.Добавить(ПолеСвязи); КонецЦикла; ИсключенияПоискаСсылок.Вставить(ОписаниеПодчиненногоОбъекта.ПодчиненныйОбъект, ЗначениеИсключенияПоискаСсылок); КонецЦикла; КонецПроцедуры Процедура ЗарегистрироватьОшибкиУдаления(Результат, ПрепятствующиеУдалению, ПараметрыВыполнения) ПредставленияСсылок = ПредметыСтрокой(ПрепятствующиеУдалению.ВыгрузитьКолонку("МестоИспользования")); Для каждого ПрепятствующийУдалению Из ПрепятствующиеУдалению Цикл ТекстОшибки = НСтр("ru = 'Элемент не удален, т.к. на него есть ссылки.'"); ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", ПрепятствующийУдалению.МестоИспользования, ПредставленияСсылок[ПрепятствующийУдалению.МестоИспользования], ТекстОшибки); ЗарегистрироватьОшибкуЗамены(Результат, ПрепятствующийУдалению.УдаляемыйСсылка, ОписаниеОшибки, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; КонецПроцедуры Функция СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат) Дубли = Новый Массив; Для Каждого КлючЗначение Из ПарыЗамен Цикл Дубль = КлючЗначение.Ключ; Оригинал = КлючЗначение.Значение; Если Дубль = Оригинал Или Дубль.Пустая() Тогда Продолжить; // Самого на себя и пустые ссылки не заменяем. КонецЕсли; Дубли.Добавить(Дубль); // Пропускаем промежуточные замены, чтобы не строить граф (если A->B и B->C то вместо A->B производится замена A->C). ОригиналОригинала = ПарыЗамен[Оригинал]; ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал); Если ЕстьОригиналОригинала Тогда Пока ЕстьОригиналОригинала Цикл Оригинал = ОригиналОригинала; ОригиналОригинала = ПарыЗамен[Оригинал]; ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал); КонецЦикла; ПарыЗамен.Вставить(Дубль, Оригинал); КонецЕсли; КонецЦикла; Если ПараметрыВыполнения.УчитыватьПрикладныеПравила И ПодсистемаСуществует("СтандартныеПодсистемы.ПоискИУдалениеДублей") Тогда МодульПоискИУдалениеДублей = ОбщийМодуль("ПоискИУдалениеДублей"); Ошибки = МодульПоискИУдалениеДублей.ПроверитьВозможностьЗаменыЭлементов(ПарыЗамен, ПараметрыЗамены); ОригиналыОбъектов = Новый Массив; Для Каждого КлючЗначение Из Ошибки Цикл Дубль = КлючЗначение.Ключ; ОригиналыОбъектов.Добавить(ПарыЗамен[Дубль]); Индекс = Дубли.Найти(Дубль); Если Индекс <> Неопределено Тогда Дубли.Удалить(Индекс); // пропускаем проблемный элемент. КонецЕсли; КонецЦикла; ПредставленияОбъектов = ПредметыСтрокой(ОригиналыОбъектов); Для Каждого КлючЗначение Из Ошибки Цикл Дубль = КлючЗначение.Ключ; Оригинал = ПарыЗамен[Дубль]; ТекстОшибки = КлючЗначение.Значение; Причина = ОписаниеОшибкиЗамены("ОшибкаЗаписи", Оригинал, ПредставленияОбъектов[Оригинал], ТекстОшибки); ЗарегистрироватьОшибкуЗамены(Результат, Дубль, Причина, ПараметрыВыполнения.ПодчиненныеКДублям); КонецЦикла; КонецЕсли; Возврат Дубли; КонецФункции Функция НовыйПараметрыВыполненияЗаменыСсылок(Знач ПараметрыЗамены) ПараметрыПоУмолчанию = ПараметрыЗаменыСсылок(); ПараметрыВыполнения = Новый Структура; ПараметрыВыполнения.Вставить("УдалятьНепосредственно", ПараметрыПоУмолчанию.СпособУдаления = "Непосредственно"); ПараметрыВыполнения.Вставить("ПомечатьНаУдаление", ПараметрыПоУмолчанию.СпособУдаления = "Пометка"); ПараметрыВыполнения.Вставить("ВключатьБизнесЛогику", ПараметрыПоУмолчанию.ВключатьБизнесЛогику); ПараметрыВыполнения.Вставить("ПривилегированнаяЗапись", ПараметрыПоУмолчанию.ПривилегированнаяЗапись); ПараметрыВыполнения.Вставить("УчитыватьПрикладныеПравила", ПараметрыПоУмолчанию.УчитыватьПрикладныеПравила); ПараметрыВыполнения.Вставить("МестаЗамены", Новый Массив); // Переданные параметры обрабатываются условно для обратной совместимости. ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "СпособУдаления"); Если ЗначениеПараметра = "Непосредственно" Тогда ПараметрыВыполнения.УдалятьНепосредственно = Истина; ПараметрыВыполнения.ПомечатьНаУдаление = Ложь; ИначеЕсли ЗначениеПараметра = "Пометка" Тогда ПараметрыВыполнения.УдалятьНепосредственно = Ложь; ПараметрыВыполнения.ПомечатьНаУдаление = Истина; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ВключатьБизнесЛогику"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.ВключатьБизнесЛогику = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ПривилегированнаяЗапись"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.ПривилегированнаяЗапись = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "УчитыватьПрикладныеПравила"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.УчитыватьПрикладныеПравила = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "МестаЗамены", Новый Массив); Если (ЗначениеПараметра.Количество() > 0) Тогда ПараметрыВыполнения.МестаЗамены = Новый Массив(Новый ФиксированныйМассив(ЗначениеПараметра)); КонецЕсли; Возврат ПараметрыВыполнения; КонецФункции #КонецОбласти #Область МестаИспользования Функция ОписаниеТипаКлючиЗаписей() ДобавляемыеТипы = Новый Массив; Для Каждого Мета Из Метаданные.РегистрыСведений Цикл ДобавляемыеТипы.Добавить(Тип("РегистрСведенийКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыНакопления Цикл ДобавляемыеТипы.Добавить(Тип("РегистрНакопленияКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыБухгалтерии Цикл ДобавляемыеТипы.Добавить(Тип("РегистрБухгалтерииКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыРасчета Цикл ДобавляемыеТипы.Добавить(Тип("РегистрРасчетаКлючЗаписи." + Мета.Имя)); КонецЦикла; Возврат Новый ОписаниеТипов(ДобавляемыеТипы); КонецФункции Функция ОписаниеИзмеренийНабора(Знач МетаданныеРегистра, КэшИзмеренийРегистров) ОписаниеИзмерений = КэшИзмеренийРегистров[МетаданныеРегистра]; Если ОписаниеИзмерений <> Неопределено Тогда Возврат ОписаниеИзмерений; КонецЕсли; // Период и регистратор, если есть. ОписаниеИзмерений = Новый Структура; ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип", Ложь); Если Метаданные.РегистрыСведений.Содержит(МетаданныеРегистра) Тогда // Возможно есть период МетаПериод = МетаданныеРегистра.ПериодичностьРегистраСведений; Периодичность = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений; Если МетаПериод = Периодичность.ПозицияРегистратора Тогда ДанныеИзмерения.Тип = Документы.ТипВсеСсылки(); ДанныеИзмерения.Представление = НСтр("ru = 'Регистратор'"); ДанныеИзмерения.Ведущее = Истина; ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Год Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = 'Период'"); ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''yyyy ""г.""''; ДП=''Дата не задана'''"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.День Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = 'Период'"); ДанныеИзмерения.Формат = НСтр("ru = 'ДЛФ=D; ДП=''Дата не задана'''"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Квартал Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = 'Период'"); ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''к """"квартал """"yyyy """"г.""""''; ДП=''Дата не задана'''"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Месяц Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = 'Период'"); ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''ММММ yyyy """"г.""""''; ДП=''Дата не задана'''"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Секунда Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = 'Период'"); ДанныеИзмерения.Формат = НСтр("ru = 'ДЛФ=DT; ДП=''Дата не задана'''"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); КонецЕсли; Иначе ДанныеИзмерения.Тип = Документы.ТипВсеСсылки(); ДанныеИзмерения.Представление = НСтр("ru = 'Регистратор'"); ДанныеИзмерения.Ведущее = Истина; ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения); КонецЕсли; // Все измерения Для Каждого МетаИзмерение Из МетаданныеРегистра.Измерения Цикл ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип"); ДанныеИзмерения.Тип = МетаИзмерение.Тип; ДанныеИзмерения.Представление = МетаИзмерение.Представление(); ДанныеИзмерения.Ведущее = МетаИзмерение.Ведущее; ОписаниеИзмерений.Вставить(МетаИзмерение.Имя, ДанныеИзмерения); КонецЦикла; КэшИзмеренийРегистров[МетаданныеРегистра] = ОписаниеИзмерений; Возврат ОписаниеИзмерений; КонецФункции #КонецОбласти #КонецОбласти #Область Данные Функция СравниваемыеКолонки(Знач КоллекцияСтрок, Знач ИменаКолонок, Знач ИсключаяКолонки) Если ПустаяСтрока(ИменаКолонок) Тогда ТипКоллекции = ТипЗнч(КоллекцияСтрок); ЭтоСписокЗначений = (ТипКоллекции = Тип("СписокЗначений")); ЭтоТаблицаЗначений = (ТипКоллекции = Тип("ТаблицаЗначений")); ЭтоКоллекцияКлючИЗначение = (ТипКоллекции = Тип("Соответствие")) Или (ТипКоллекции = Тип("Структура")) Или (ТипКоллекции = Тип("ФиксированноеСоответствие")) Или (ТипКоллекции = Тип("ФиксированнаяСтруктура")); СравниваемыеКолонки = Новый Массив; Если ЭтоТаблицаЗначений Тогда Для Каждого Колонка Из КоллекцияСтрок.Колонки Цикл СравниваемыеКолонки.Добавить(Колонка.Имя); КонецЦикла; ИначеЕсли ЭтоСписокЗначений Тогда СравниваемыеКолонки.Добавить("Значение"); СравниваемыеКолонки.Добавить("Картинка"); СравниваемыеКолонки.Добавить("Пометка"); СравниваемыеКолонки.Добавить("Представление"); ИначеЕсли ЭтоКоллекцияКлючИЗначение Тогда СравниваемыеКолонки.Добавить("Ключ"); СравниваемыеКолонки.Добавить("Значение"); Иначе ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение параметра %1 (тип %2) в %3. Укажите имена полей, по которым производится сравнение.'"), "КоллекцияСтрок1", ТипКоллекции, "ОбщегоНазначения.КоллекцииИдентичны"), КатегорияОшибки.ОшибкаКонфигурации); КонецЕсли; Иначе СравниваемыеКолонки = СтрРазделить(СтрЗаменить(ИменаКолонок, " ", ""), ","); КонецЕсли; // Вычитаем исключаемые поля Если Не ПустаяСтрока(ИсключаяКолонки) Тогда ИсключаяКолонки = СтрРазделить(СтрЗаменить(ИсключаяКолонки, " ", ""), ","); СравниваемыеКолонки = ОбщегоНазначенияКлиентСервер.РазностьМассивов(СравниваемыеКолонки, ИсключаяКолонки); КонецЕсли; Возврат СравниваемыеКолонки; КонецФункции Функция СравнитьСУчетомПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки) ТипКоллекции = ТипЗнч(КоллекцияСтрок1); СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив")); // Параллельный обход обеих коллекций. НомерСтрокиКоллекции1 = 0; Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл // Спозиционируемся на аналогичную строку второй коллекции. НомерСтрокиКоллекции2 = 0; ЕстьСтрокиКоллекции2 = Ложь; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл ЕстьСтрокиКоллекции2 = Истина; Если НомерСтрокиКоллекции2 = НомерСтрокиКоллекции1 Тогда Прервать; КонецЕсли; НомерСтрокиКоллекции2 = НомерСтрокиКоллекции2 + 1; КонецЦикла; Если Не ЕстьСтрокиКоллекции2 Тогда // Во второй коллекции вообще нет строк. Возврат Ложь; КонецЕсли; // Сравниваем значения полей двух строк. Если СравниваютсяМассивы Тогда Если СтрокаКоллекции1 <> СтрокаКоллекции2 Тогда Возврат Ложь; КонецЕсли; Иначе Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаКоллекции2[ИмяКолонки] Тогда Возврат Ложь; КонецЕсли; КонецЦикла; КонецЕсли; НомерСтрокиКоллекции1 = НомерСтрокиКоллекции1 + 1; КонецЦикла; КоличествоСтрокКоллекции1 = НомерСтрокиКоллекции1; // Отдельно подсчитаем количество строк второй коллекции. КоличествоСтрокКоллекции2 = 0; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл КоличествоСтрокКоллекции2 = КоличествоСтрокКоллекции2 + 1; КонецЦикла; // Если в первой коллекции не оказалось строк, // то их не должно быть и во второй. Если КоличествоСтрокКоллекции1 = 0 Тогда Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл Возврат Ложь; КонецЦикла; КоличествоСтрокКоллекции2 = 0; КонецЕсли; // Количество строк не должно отличаться. Если КоличествоСтрокКоллекции1 <> КоличествоСтрокКоллекции2 Тогда Возврат Ложь; КонецЕсли; Возврат Истина; КонецФункции Функция СравнитьБезУчетаПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки) // Строки отбора накапливаем по первой коллекции для того, чтобы: // - повторно не искать одинаковые строки, // - убедиться, что во второй коллекции ни одной такой строки, которой нет в накопленных. СтрокиОтбора = Новый ТаблицаЗначений; ПараметрыОтбора = Новый Структура; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл СтрокиОтбора.Колонки.Добавить(ИмяКолонки); ПараметрыОтбора.Вставить(ИмяКолонки); КонецЦикла; ЕстьСтрокиКоллекции1 = Ложь; Для Каждого СтрокаОтбора Из КоллекцияСтрок1 Цикл ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаОтбора); Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() > 0 Тогда // Строку с такими полями уже искали. Продолжить; КонецЕсли; ЗаполнитьЗначенияСвойств(СтрокиОтбора.Добавить(), СтрокаОтбора); // Подсчитаем количество таких строк в первой коллекции. НайденоСтрокКоллекции1 = 0; Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл СтрокаПодходит = Истина; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда СтрокаПодходит = Ложь; Прервать; КонецЕсли; КонецЦикла; Если СтрокаПодходит Тогда НайденоСтрокКоллекции1 = НайденоСтрокКоллекции1 + 1; КонецЕсли; КонецЦикла; // Подсчитаем количество таких строк во второй коллекции. НайденоСтрокКоллекции2 = 0; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл СтрокаПодходит = Истина; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции2[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда СтрокаПодходит = Ложь; Прервать; КонецЕсли; КонецЦикла; Если СтрокаПодходит Тогда НайденоСтрокКоллекции2 = НайденоСтрокКоллекции2 + 1; // Если количество таких строк во второй коллекции превысило количество в первой, // то уже можно сделать вывод, что коллекции не идентичны. Если НайденоСтрокКоллекции2 > НайденоСтрокКоллекции1 Тогда Возврат Ложь; КонецЕсли; КонецЕсли; КонецЦикла; // Количество таких строк не должно отличаться. Если НайденоСтрокКоллекции1 <> НайденоСтрокКоллекции2 Тогда Возврат Ложь; КонецЕсли; ЕстьСтрокиКоллекции1 = Истина; КонецЦикла; // Если в первой коллекции не оказалось строк, // то их не должно быть и во второй. Если Не ЕстьСтрокиКоллекции1 Тогда Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл Возврат Ложь; КонецЦикла; КонецЕсли; // Проверим, что во второй коллекции нет ни одной такой строки, которой нет в накопленных. Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаКоллекции2); Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() = 0 Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; КонецФункции Функция СравнитьМассивы(Знач Массив1, Знач Массив2) Если Массив1.Количество() <> Массив2.Количество() Тогда Возврат Ложь; КонецЕсли; Для Каждого Элемент Из Массив1 Цикл Если Массив2.Найти(Элемент) = Неопределено Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; КонецФункции Процедура ПроверкаФиксированностиДанных(Данные, ДанныеВЗначенииФиксированныхТипов = Ложь) ТипДанных = ТипЗнч(Данные); СоставТипов = Новый ОписаниеТипов( "ХранилищеЗначения, |ФиксированныйМассив, |ФиксированнаяСтруктура, |ФиксированноеСоответствие"); Если СоставТипов.СодержитТип(ТипДанных) Тогда Возврат; КонецЕсли; Если ДанныеВЗначенииФиксированныхТипов Тогда СоставТипов = Новый ОписаниеТипов( "Булево,Строка,Число,Дата, |Неопределено,УникальныйИдентификатор,Null,Тип, |РежимОтправкиИнформацииОбОшибке, |ХранилищеЗначения,ОбщийМодуль,ОбъектМетаданных, |ТипЗначенияXDTO,ТипОбъектаXDTO, |ИдентификаторОбсужденияСистемыВзаимодействия"); Если СоставТипов.СодержитТип(ТипДанных) Или ЭтоСсылка(ТипДанных) Тогда Возврат; КонецЕсли; КонецЕсли; ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение параметра %1 в функции %2. Данные типа %3 не могут быть зафиксированы.'"), "Данные", "ОбщегоНазначения.ФиксированныеДанные", Строка(ТипДанных)), КатегорияОшибки.ОшибкаКонфигурации); КонецПроцедуры Функция РазмерСтрокиВБайтах(Знач Строка) Возврат ПолучитьДвоичныеДанныеИзСтроки(Строка, "UTF-8").Размер(); КонецФункции #Область СкопироватьРекурсивно Функция СкопироватьСтруктуру(СтруктураИсточник, ФиксироватьДанные) СтруктураРезультат = Новый Структура; Для Каждого КлючИЗначение Из СтруктураИсточник Цикл СтруктураРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(СтруктураИсточник) = Тип("ФиксированнаяСтруктура") Тогда Возврат Новый ФиксированнаяСтруктура(СтруктураРезультат); КонецЕсли; Возврат СтруктураРезультат; КонецФункции Функция СкопироватьСоответствие(СоответствиеИсточник, ФиксироватьДанные) СоответствиеРезультат = Новый Соответствие; Для Каждого КлючИЗначение Из СоответствиеИсточник Цикл СоответствиеРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(СоответствиеИсточник) = Тип("ФиксированноеСоответствие") Тогда Возврат Новый ФиксированноеСоответствие(СоответствиеРезультат); КонецЕсли; Возврат СоответствиеРезультат; КонецФункции Функция СкопироватьМассив(МассивИсточник, ФиксироватьДанные) МассивРезультат = Новый Массив; Для Каждого Элемент Из МассивИсточник Цикл МассивРезультат.Добавить(СкопироватьРекурсивно(Элемент, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(МассивИсточник) = Тип("ФиксированныйМассив") Тогда Возврат Новый ФиксированныйМассив(МассивРезультат); КонецЕсли; Возврат МассивРезультат; КонецФункции Функция СкопироватьСписокЗначений(СписокИсточник, ФиксироватьДанные) СписокРезультат = Новый СписокЗначений; Для Каждого ЭлементСписка Из СписокИсточник Цикл СписокРезультат.Добавить( СкопироватьРекурсивно(ЭлементСписка.Значение, ФиксироватьДанные), ЭлементСписка.Представление, ЭлементСписка.Пометка, ЭлементСписка.Картинка); КонецЦикла; Возврат СписокРезультат; КонецФункции Процедура СкопироватьЗначенияТаблицыЗначений(ТаблицаЗначений, ФиксироватьДанные) Для Каждого СтрокаТаблицыЗначений Из ТаблицаЗначений Цикл Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл СтрокаТаблицыЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаТаблицыЗначений[Колонка.Имя], ФиксироватьДанные); КонецЦикла; КонецЦикла; КонецПроцедуры Процедура СкопироватьЗначенияСтрокиДереваЗначений(СтрокиДереваЗначений, ФиксироватьДанные); Для Каждого СтрокаДереваЗначений Из СтрокиДереваЗначений Цикл Для Каждого Колонка Из СтрокаДереваЗначений.Владелец().Колонки Цикл СтрокаДереваЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаДереваЗначений[Колонка.Имя], ФиксироватьДанные); КонецЦикла; СкопироватьЗначенияСтрокиДереваЗначений(СтрокаДереваЗначений.Строки, ФиксироватьДанные); КонецЦикла; КонецПроцедуры Функция ЭтоВнешнийОтчетИлиВнешняяОбработка(ОбъектМетода) Попытка ПолноеИмя = ОбъектМетода.Метаданные().ПолноеИмя(); Исключение Возврат Ложь; КонецПопытки; ЧастиИмени = СтрРазделить(ПолноеИмя, "."); Если ЧастиИмени.Количество() <> 2 Тогда Возврат Ложь; КонецЕсли; ИмяВидаОбъекта = ЧастиИмени[0]; Возврат ИмяВидаОбъекта = "ВнешнийОтчет" // @Non-NLS Или ИмяВидаОбъекта = "ВнешняяОбработка" // @Non-NLS Или ИмяВидаОбъекта = "ExternalReport" Или ИмяВидаОбъекта = "ExternalDataProcessor"; КонецФункции #КонецОбласти #КонецОбласти #Область ХранилищеНастроек Процедура ХранилищеСохранить(МенеджерХранилища, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения) Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Возврат; КонецЕсли; МенеджерХранилища.Сохранить(КлючОбъекта, КлючНастроек(КлючНастроек), Настройки, ОписаниеНастроек, ИмяПользователя); Если ОбновитьПовторноИспользуемыеЗначения Тогда ОбновитьПовторноИспользуемыеЗначения(); КонецЕсли; КонецПроцедуры Функция ХранилищеЗагрузить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя) Результат = Неопределено; Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Результат = МенеджерХранилища.Загрузить(КлючОбъекта, КлючНастроек(КлючНастроек), ОписаниеНастроек, ИмяПользователя); КонецЕсли; Если Результат = Неопределено Тогда Результат = ЗначениеПоУмолчанию; Иначе УстановитьПривилегированныйРежим(Истина); Если ОчиститьНесуществующиеСсылки(Результат) Тогда Результат = ЗначениеПоУмолчанию; КонецЕсли; КонецЕсли; Возврат Результат; КонецФункции // Удаляет из переданной коллекции ссылки, ссылающиеся на несуществующие данные в информационной базе. // Не очищает переданное значение, если в нем передана несуществующая ссылка, а возвращает Ложь. // // Параметры: // Значение - ЛюбаяСсылка // - Произвольный - проверяемое значение или коллекция. // // Возвращаемое значение: // Булево - Истина, если Значение ссылочного типа и объект не существует в информационной базе. // Ложь, если Значение не ссылочного типа или объект существует. // Функция ОчиститьНесуществующиеСсылки(Значение) Тип = ТипЗнч(Значение); Если Тип = Тип("Неопределено") Или Тип = Тип("Булево") Или Тип = Тип("Строка") Или Тип = Тип("Число") Или Тип = Тип("Дата") Тогда // Оптимизация - часто используемые примитивные типы. Возврат Ложь; // Не ссылка. ИначеЕсли Тип = Тип("Массив") Тогда Количество = Значение.Количество(); Для Номер = 1 По Количество Цикл ОбратныйИндекс = Количество - Номер; // @skip-check query-in-loop - выборка ссылок из разных таблиц. Если ОчиститьНесуществующиеСсылки(Значение[ОбратныйИндекс]) Тогда Значение.Удалить(ОбратныйИндекс); КонецЕсли; КонецЦикла; Возврат Ложь; // Не ссылка. ИначеЕсли Тип = Тип("Структура") Или Тип = Тип("Соответствие") Тогда Для Каждого КлючИЗначение Из Значение Цикл // @skip-check query-in-loop - выборка ссылок из разных таблиц. Если ОчиститьНесуществующиеСсылки(КлючИЗначение.Значение) Тогда Значение.Вставить(КлючИЗначение.Ключ, Неопределено); КонецЕсли; КонецЦикла; Возврат Ложь; // Не ссылка. ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип) Или Справочники.ТипВсеСсылки().СодержитТип(Тип) Или Перечисления.ТипВсеСсылки().СодержитТип(Тип) Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип) Или ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип) Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип) Или ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип) Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип) Или Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда // Ссылочный тип, исключая ТочкаМаршрутаБизнесПроцессаСсылка. Если Значение.Пустая() Тогда Возврат Ложь; // Ссылка пустая. КонецЕсли; Возврат ЗначениеРеквизитаОбъекта(Значение, "Ссылка") = Неопределено; Иначе Возврат Ложь; // Не ссылка. КонецЕсли; КонецФункции Процедура ХранилищеУдалить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ИмяПользователя) Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда МенеджерХранилища.Удалить(КлючОбъекта, КлючНастроек(КлючНастроек), ИмяПользователя); КонецЕсли; КонецПроцедуры // Возвращает строку ключа настроек, не превышающую допустимую длину 128 символов. // Если указанная строка превышает 128, тогда вместо символов сверх 96 символов // добавляется их хеш-сумма по алгоритму MD5 размером 32 символа. // // Параметры: // Строка - Строка - строка произвольной длины. // // Возвращаемое значение: // Строка - не более 128 символов. // Функция КлючНастроек(Знач Строка) Возврат СократитьСтрокуКонтрольнойСуммой(Строка, 128); КонецФункции #КонецОбласти #Область БезопасноеХранилище Функция ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных) ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанных"; ЗапросОбласти = (РазделениеВключено() И ОбщиеДанные <> Истина И (ДоступноИспользованиеРазделенныхДанных() Или ЗначениеЗаполнено(ОбластьДанных))); Если ЗапросОбласти Тогда ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных"; КонецЕсли; ТекстЗапроса = "ВЫБРАТЬ | БезопасноеХранилищеДанных.Владелец КАК ВладелецДанных, | БезопасноеХранилищеДанных.Данные КАК Данные |ИЗ | #ИмяБезопасногоХранилищаДанных КАК БезопасноеХранилищеДанных |ГДЕ | &Условие"; ТекстЗапроса = СтрЗаменить( ТекстЗапроса, "#ИмяБезопасногоХранилищаДанных", ИмяБезопасногоХранилищаДанных); ТекстЗапроса = ?((ЗначениеЗаполнено(ОбластьДанных) И ЗапросОбласти), СтрЗаменить( ТекстЗапроса, "&Условие", "БезопасноеХранилищеДанных.Владелец В (&Владельцы) |И БезопасноеХранилищеДанных.ОбластьДанныхВспомогательныеДанные = &ОбластьДанных"), СтрЗаменить( ТекстЗапроса, "&Условие", "БезопасноеХранилищеДанных.Владелец В (&Владельцы)")); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("Владельцы", Владельцы); Запрос.УстановитьПараметр("ОбластьДанных", ОбластьДанных); РезультатЗапроса = Запрос.Выполнить().Выбрать(); Результат = Новый Соответствие(); НаборДанныхКлюча = ?(ЗначениеЗаполнено(Ключи) И СтрНайти(Ключи, ","), Новый Структура(Ключи), Неопределено); Для Каждого ВладелецДанных Из Владельцы Цикл Результат.Вставить(ВладелецДанных, НаборДанныхКлюча); КонецЦикла; Пока РезультатЗапроса.Следующий() Цикл ДанныеВладельца = Новый Структура(Ключи); Если ЗначениеЗаполнено(РезультатЗапроса.Данные) Тогда СохраненныеДанные = РезультатЗапроса.Данные.Получить(); Если ЗначениеЗаполнено(СохраненныеДанные) Тогда Если ЗначениеЗаполнено(Ключи) Тогда ВладелецДанных = Результат[РезультатЗапроса.ВладелецДанных]; ЗаполнитьЗначенияСвойств(ДанныеВладельца, СохраненныеДанные); Иначе ДанныеВладельца = СохраненныеДанные; КонецЕсли; Если Ключи <> Неопределено И ДанныеВладельца <> Неопределено И ДанныеВладельца.Количество() = 1 Тогда ЗначениеПоКлючу = ?(ДанныеВладельца.Свойство(Ключи), ДанныеВладельца[Ключи], Неопределено); Результат.Вставить(РезультатЗапроса.ВладелецДанных, ЗначениеПоКлючу); Иначе Результат.Вставить(РезультатЗапроса.ВладелецДанных, ДанныеВладельца); КонецЕсли; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции #КонецОбласти #Область БезопасноеВыполнениеВнешнегоКода // Возвращает менеджер объекта по имени. // // Параметры: // Имя - Строка - имя например, "Справочники.Организации", "Справочник.Организации", "Справочники", "Справочник". // ЭтоПолноеИмя - Неопределено, Булево // ЭтоИмяМенеджера - Неопределено, Булево // ТребуетсяМодульМенеджера - Булево // ИмяВызывающейПроцедуры - Строка // ИмяПараметра - Строка // МенеджерПоТочномуИмени - Булево - если Ложь, // тогда для вложенных объектов (форм, реквизитов, ...) // возвращается менеджер основного объекта (по первым двум частям имени через точку), // при этом для перерасчетов возвращается менеджер перерасчета (по первым четырем частям имени через точку). // // Возвращаемое значение: // - см. МенеджерОбъектаПоПолномуИмени // - ПланыОбменаМенеджер // - КритерииОтбораМенеджер // - ХранилищаНастроекМенеджер // - WSСсылкиМенеджер // - СервисыИнтеграцииМенеджер // - КонстантыМенеджер // - СправочникиМенеджер // - ДокументыМенеджер // - ПоследовательностиМенеджер // - ЖурналыДокументовМенеджер // - ПеречисленияМенеджер // - ОтчетыМенеджер // - ОбработкиМенеджер // - ПланыВидовХарактеристикМенеджер // - ПланыСчетовМенеджер // - ПланыВидовРасчетаМенеджер // - РегистрыСведенийМенеджер // - РегистрыНакопленияМенеджер // - РегистрыБухгалтерииМенеджер // - РегистрыРасчетаМенеджер // - ПерерасчетыМенеджер // - БизнесПроцессыМенеджер // - ЗадачиМенеджер // - ВнешниеИсточникиДанныхМенеджер // - ВнешнийИсточникДанныхТаблицыМенеджер // - ВнешнийИсточникДанныхКубыМенеджер // - ВнешнийИсточникДанныхКубТаблицыИзмеренийМенеджер // Функция МенеджерОбъектаПоИмени(Имя, ЭтоПолноеИмя, ЭтоИмяМенеджера, ТребуетсяМодульМенеджера, ИмяВызывающейПроцедуры, ИмяПараметра, МенеджерПоТочномуИмени = Истина) ЧастиИмени = СтрРазделить(Имя, "."); ПерваяЧастьИмени = ЧастиИмени[0]; СвойстваВидовОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных(); Свойства = СвойстваВидовОбъектов.ПоКоллекциям.Получить(ВРег(ПерваяЧастьИмени)); НайденоПоКоллекциям = Истина; Если Свойства = Неопределено Тогда Свойства = СвойстваВидовОбъектов.ПоВидамОбъектов.Получить(ВРег(ПерваяЧастьИмени)); НайденоПоКоллекциям = Ложь; КонецЕсли; КодОшибки = "СтандартныеПодсистемы.БазоваяФункциональность.ЭтоОшибкаПолученияМодуляМенеджераПоИмени"; Если Свойства = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объектов ""%5"".'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; Если ЭтоИмяМенеджера = Истина И Не НайденоПоКоллекциям Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - начало имени объекта метаданных, а ожидается начало имени менеджера объекта.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); ИначеЕсли ЭтоИмяМенеджера = Ложь И НайденоПоКоллекциям Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - начало имени менеджера объекта, а ожидается начало имени объекта метаданных.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; Менеджер = Свойства.Менеджер; Если Менеджер = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. У объектов ""%5"" нет менеджера.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; ЕстьМодульМенеджера = Свойства.ЕстьМодульМенеджера; КоллекцияМетаданных = Метаданные[Свойства.ИмяКоллекции]; Индекс = 0; Если ЧастиИмени.Количество() > 2 И ( Свойства.ИмяВидаОбъекта = "РегистрРасчета" Или Свойства.ИмяВидаОбъекта = "ВнешнийИсточникДанных") Тогда Если Свойства.ИмяВидаОбъекта = "РегистрРасчета" Тогда УстановитьМенеджерВложенногоОбъекта("ПЕРЕРАСЧЕТЫ", "ПЕРЕРАСЧЕТ", Ложь, Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени, НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки); Иначе УстановитьМенеджерВложенногоОбъекта("КУБЫ", "КУБ", Истина, Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени, НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки); Если Индекс = 0 Тогда УстановитьМенеджерВложенногоОбъекта("ТАБЛИЦЫ", "ТАБЛИЦА", Истина, Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени, НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки); ИначеЕсли ЧастиИмени.Количество() > 4 Тогда УстановитьМенеджерВложенногоОбъекта("ТАБЛИЦЫИЗМЕРЕНИЙ", "ТАБЛИЦАИЗМЕРЕНИЯ", Истина, Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени, НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки); КонецЕсли; КонецЕсли; КонецЕсли; Если ЧастиИмени.Количество() = Индекс + 1 Тогда Если Не ЭтоПолноеИмя Тогда Возврат Менеджер; КонецЕсли; ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Ожидается полное имя объекта.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; Если ТребуетсяМодульМенеджера И Не ЕстьМодульМенеджера Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. У объектов ""%5"" нет модулей менеджера.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ЧастиИмени[Индекс]); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; ИмяОбъекта = ЧастиИмени[Индекс + 1]; Попытка Возврат Менеджер[ИмяОбъекта]; Исключение Если КоллекцияМетаданных.Найти(ИмяОбъекта) = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объект ""%5"".'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ИмяОбъекта); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; ВызватьИсключение; КонецПопытки; КонецФункции // АПК:134-выкл - Количество параметров более 7 для компактного описания и производительности (0-2 вызовов за раз). // Для функции МенеджерОбъектаПоИмени. Процедура УстановитьМенеджерВложенногоОбъекта(ИмяКоллекции, ИмяВидаОбъекта, ЕстьМодуль, Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени, НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки) ПерваяЧастьВложенногоИмени = ЧастиИмени[Индекс + 2]; Если ВРег(ПерваяЧастьВложенногоИмени) <> ИмяВидаОбъекта И ВРег(ПерваяЧастьВложенногоИмени) <> ИмяКоллекции Тогда Возврат; КонецЕсли; Если ВРег(ПерваяЧастьВложенногоИмени) = ИмяВидаОбъекта И НайденоПоКоллекциям Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - часть имени объекта метаданных, а ожидается часть имени менеджера объекта.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьВложенногоИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); ИначеЕсли ВРег(ПерваяЧастьВложенногоИмени) = ИмяКоллекции И Не НайденоПоКоллекциям Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - часть имени менеджера объекта, а ожидается часть имени объекта метаданных.'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьВложенногоИмени); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; ИмяОбъекта = ЧастиИмени[Индекс + 1]; Попытка Менеджер = Менеджер[ИмяОбъекта][ИмяКоллекции]; Исключение Если КоллекцияМетаданных.Найти(ИмяОбъекта) = Неопределено Тогда ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объект ""%5"".'"), Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ИмяОбъекта); ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки); КонецЕсли; ВызватьИсключение; КонецПопытки; ЕстьМодульМенеджера = ЕстьМодуль; КоллекцияМетаданных = КоллекцияМетаданных[ИмяОбъекта][ИмяКоллекции]; Индекс = Индекс + 2; КонецПроцедуры // АПК:134-вкл #КонецОбласти #Область ВнешниеКомпоненты Процедура ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение) Если МакетСуществует(Местоположение) Тогда Возврат; КонецЕсли; Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный"); МодульВнешниеКомпонентыСлужебный.ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение); Возврат; КонецЕсли; ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Указан несуществующий макет ""%1"" при подключении внешней компоненты ""%2"".'"), Местоположение, Идентификатор), КатегорияОшибки.ОшибкаКонфигурации); КонецПроцедуры Функция ОшибкаСовместимостиКомпонентыИзМакета(Местоположение) Если Не ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда Возврат ""; КонецЕсли; МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный"); Возврат МодульВнешниеКомпонентыСлужебный.ОшибкаСовместимостиКомпонентыИзМакета( Местоположение); КонецФункции Функция СистемнаяИнформацияДляЖурналаРегистрации() Возврат СтандартныеПодсистемыСервер.ИнформацияДляПоддержки(); КонецФункции Процедура ОтправитьСтатистикуПодключенияКомпоненты(Идентификатор, Местоположение) Если Не ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда Возврат; КонецЕсли; МодульЦентрМониторинга = ОбщийМодуль("ЦентрМониторинга"); МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики( "СтандартныеПодсистемы.ВнешниеКомпоненты." + Идентификатор + ".НаСервере." + ?(СтрНачинаетсяС(Местоположение, "e1cib"), "Справочник", "Макет"), 1); КонецПроцедуры #КонецОбласти #Область ТекущееОкружение Функция НомерСборкиПоТекущейВерсииПлатформы(НомераСборокСтрокой) НомераСборок = СтрРазделить(НомераСборокСтрокой, ";", Истина); СборкиПоВерсиям = Новый Соответствие; Для Каждого НомерСборки Из НомераСборок Цикл НомерВерсии = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(НомерСборки); СборкиПоВерсиям.Вставить(СокрЛП(НомерВерсии), СокрЛП(НомерСборки)); КонецЦикла; СистемнаяИнформация = Новый СистемнаяИнформация; ТекущаяВерсия = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения); Результат = СборкиПоВерсиям[ТекущаяВерсия]; Если Не ЗначениеЗаполнено(Результат) Тогда Результат = НомераСборок[0]; КонецЕсли; Возврат Результат; КонецФункции // Ниже этой версии платформы конфигурация может запуститься и показать окно с требованием обновить платформу, // если она выше, чем в СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляЗапуска. // Конкретные номера версий указаны в СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляИспользования. // Версии могут быть переопределены в ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности. // Функция МинимальнаяВерсияПлатформы() Экспорт // АПК:581 - экспортная, так как используется при тестировании. ВерсияРежимаСовместимости = ВерсияРежимаСовместимости(); МинимальныеВерсииПлатформы = СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляИспользования(); НайденнаяВерсия = МинимальныеВерсииПлатформы.НайтиПоЗначению(ВерсияРежимаСовместимости); Если НайденнаяВерсия = Неопределено Тогда НайденнаяВерсия = МинимальныеВерсииПлатформы[МинимальныеВерсииПлатформы.Количество() - 1]; КонецЕсли; Возврат НайденнаяВерсия.Представление; КонецФункции Функция ВерсияРежимаСовместимости() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация(); РежимСовместимости = Метаданные.РежимСовместимости; Если РежимСовместимости = Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда ВерсияРежимаСовместимости = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения); Иначе ВерсияРежимаСовместимости = СтрСоединить(СтрРазделить(РежимСовместимости, СтрСоединить(СтрРазделить(РежимСовместимости, "1234567890", Ложь), ""), Ложь), "."); КонецЕсли; Возврат ВерсияРежимаСовместимости; КонецФункции // Выполняет проверку правильности заполнения минимальной и рекомендуемой версии платформы. // // Параметры: // Минимальная - Строка - номер версия платформы. // Рекомендуемая - Строка - номер версия платформы. // // Возвращаемое значение: // Булево - Истина, если минимальная и рекомендуемая версия платформы заполнена неправильно. // Функция МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) // Минимальная версия платформы должна быть заполнена. Если ПустаяСтрока(Минимальная) Тогда Возврат Истина; КонецЕсли; // Минимальная версия платформы, заданная в конфигурации, не должна быть меньше минимальной версии платформы, // заданной в библиотеке. МинимальнаяБСП = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()); Если Не ЭтоВерсияЗащищенногоПрограммногоКомплекса(Минимальная) И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(МинимальнаяБСП, Минимальная) > 0 Тогда Возврат Истина; КонецЕсли; // Минимальная версия платформы не должны быть больше рекомендуемой. Возврат Не ПустаяСтрока(Минимальная) И Не ПустаяСтрока(Рекомендуемая) И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Рекомендуемая) > 0; КонецФункции Функция НедопустимыеВерсииПлатформы() Экспорт Возврат ""; КонецФункции Функция ЭтоВерсияЗащищенногоПрограммногоКомплекса(Версия) СистемнаяИнформация = Новый СистемнаяИнформация(); Возврат ЗначениеЗаполнено(СистемнаяИнформация.ВариантПриложения); КонецФункции // Для функции ОбщиеПараметрыБазовойФункциональности. Процедура УточнитьВерсиюПлатформы(ОбщиеПараметры) СистемнаяИнформация = Новый СистемнаяИнформация; НоваяСборка = СтандартныеПодсистемыСервер.НомерВерсииПлатформыВместоОтозванной(СистемнаяИнформация.ВерсияПриложения); Если Не ЗначениеЗаполнено(НоваяСборка) Тогда НоваяРекомендуемаяСборка = СтандартныеПодсистемыСервер.НомерВерсииПлатформыВместоОтозванной(ОбщиеПараметры.МинимальнаяВерсияПлатформы); Если ЗначениеЗаполнено(НоваяРекомендуемаяСборка) Тогда МинимальнаяСборка = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()); ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальнаяСборка; Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.РекомендуемаяВерсияПлатформы, НоваяРекомендуемаяСборка) < 0 Тогда ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяРекомендуемаяСборка; КонецЕсли; КонецЕсли; ИначеЕсли ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.МинимальнаяВерсияПлатформы, НоваяСборка) < 0 Тогда ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяСборка; ОбщиеПараметры.МинимальнаяВерсияПлатформы = НоваяСборка; КонецЕсли; КонецПроцедуры // Параметры: // ОбщиеПараметры - см. ОбщиеПараметрыБазовойФункциональности // Процедура УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры) МинимальнаяИзСервиса = ""; РекомендуемаяИзСервиса = ""; СтандартныеПодсистемыСерверЛокализация.ПриОпределенииМинимальнойИРекомендуемойВерсийПлатформы( МинимальнаяИзСервиса, РекомендуемаяИзСервиса); Если Не ЗначениеЗаполнено(МинимальнаяИзСервиса) И Не ЗначениеЗаполнено(РекомендуемаяИзСервиса) Тогда Возврат; КонецЕсли; Минимальная = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяИзСервиса); Рекомендуемая = НомерСборкиПоТекущейВерсииПлатформы(РекомендуемаяИзСервиса); Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда СтандартныеПодсистемыСерверЛокализация.ПриНеверномЗаполненииМинимальнойИРекомендуемойВерсийПлатформы( Минимальная, Рекомендуемая, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), ОбщиеПараметры); Возврат; КонецЕсли; ОбщиеПараметры.МинимальнаяВерсияПлатформы = Минимальная; ОбщиеПараметры.РекомендуемаяВерсияПлатформы = Рекомендуемая; КонецПроцедуры #КонецОбласти #Область ПроверкаАлгоритмов Функция НайденныеВызовы(Алгоритм, СтрокиПоиска, Окончание = Неопределено) НайденныеВызовы = Новый Массив; ПоискОбращенияЧерезТочку = Ложь; ПоискТаблицы = Ложь; Для Каждого Элемент Из СтрокиПоиска Цикл Если ТипЗнч(Элемент) = Тип("Структура") Тогда ПоискОбращенияЧерезТочку = Истина; СтрокаПоиска = Элемент.Коллекция; Иначе СтрокаПоиска = Элемент; КонецЕсли; ПозицияВызова = СтрНайти(Алгоритм, ВРег(СтрокаПоиска)); НомерВхождения = 1; Пока ПозицияВызова > 0 Цикл Если ПоискОбращенияЧерезТочку Тогда Окончание = "."; ПоискТаблицы = Ложь; КонецЕсли; ЧислоСимволов = СтрДлина(Окончание); ПозицияСимвола = ПозицияВызова + СтрДлина(СтрокаПоиска); Пока ПозицияСимвола + ЧислоСимволов < СтрДлина(Алгоритм) Цикл ЗначениеСимвола = СокрЛП(Сред(Алгоритм, ПозицияСимвола, ЧислоСимволов)); Если ВРег(СтрокаПоиска) = ВРег("Выполнить") Или ВРег(СтрокаПоиска) = ВРег("Execute") Тогда Если Не ЗначениеЗаполнено(ЗначениеСимвола) Тогда НайденныеВызовы.Добавить(СтрокаПоиска); Прервать; КонецЕсли; КонецЕсли; Если СтрДлина(ЗначениеСимвола) < СтрДлина(Окончание) Тогда ЧислоСимволов = ЧислоСимволов + 1; ИначеЕсли ПоискОбращенияЧерезТочку И ЗначениеСимвола = Окончание И Не ПоискТаблицы Тогда ПозицияСимвола = ПозицияСимвола + ЧислоСимволов; Окончание = ВРег(Элемент.Таблица); ЧислоСимволов = СтрДлина(Окончание); ПоискТаблицы = Истина; ИначеЕсли ЗначениеСимвола = Окончание Тогда Если ПоискОбращенияЧерезТочку Тогда НайденныеВызовы.Добавить(Элемент.Коллекция + "." + Элемент.Таблица); Иначе НайденныеВызовы.Добавить(СтрокаПоиска); КонецЕсли; Прервать; ИначеЕсли ЗначениеСимвола = "/" Тогда НайденныеВызовы.Добавить(СтрокаПоиска); Прервать; ИначеЕсли ЗначениеЗаполнено(СокрЛП(ЗначениеСимвола)) Тогда Прервать; КонецЕсли; КонецЦикла; НомерВхождения = НомерВхождения + 1; ПозицияВызова = СтрНайти(Алгоритм, ВРег(СтрокаПоиска), , , НомерВхождения); КонецЦикла; КонецЦикла; Возврат НайденныеВызовы; КонецФункции Функция НедопустимыеМетоды() Массив = Новый Массив; Массив.Добавить("Выполнить"); // @Non-NLS Массив.Добавить("Вычислить"); // @Non-NLS Массив.Добавить("Подключить"); // @Non-NLS Массив.Добавить("ЗафиксироватьТранзакцию"); // @Non-NLS Массив.Добавить("ОтменитьТранзакцию"); // @Non-NLS Массив.Добавить("НачатьТранзакцию"); // @Non-NLS Массив.Добавить("СократитьЖурналРегистрации"); // @Non-NLS Массив.Добавить("УстановитьИспользованиеСобытияЖурналаРегистрации"); // @Non-NLS Массив.Добавить("ЗапуститьПриложение"); // @Non-NLS Массив.Добавить("УстановитьМаксимальныйСрокДействияПаролейПользователей"); // @Non-NLS Массив.Добавить("УстановитьМинимальнуюДлинуПаролейПользователей"); // @Non-NLS Массив.Добавить("УстановитьМинимальныйСрокДействияПаролейПользователей"); // @Non-NLS Массив.Добавить("УстановитьОграничениеПовторенияПаролейПользователейСредиПоследних"); // @Non-NLS Массив.Добавить("УстановитьПроверкуСложностиПаролейПользователей"); // @Non-NLS Массив.Добавить("УстановитьНастройкиВосстановленияПароля"); // @Non-NLS Массив.Добавить("Base64Значение"); // @Non-NLS Массив.Добавить("ЗначениеИзСтрокиВнутр"); // @Non-NLS Массив.Добавить("XMLЗначение"); // @Non-NLS Массив.Добавить("Execute"); Массив.Добавить("Eval"); Массив.Добавить("Connect"); Массив.Добавить("CommitTransaction"); Массив.Добавить("RollbackTransaction"); Массив.Добавить("BeginTransaction"); Массив.Добавить("TruncateEventLog"); Массив.Добавить("SetEventLogEventUse"); Массив.Добавить("RunApp"); Массив.Добавить("SetUserPasswordMaxEffectivePeriod"); Массив.Добавить("SetUserPasswordMinLength"); Массив.Добавить("SetUserPasswordMinEffectivePeriod"); Массив.Добавить("SetUserPasswordReuseLimit"); Массив.Добавить("SetUserPasswordStrengthCheck"); Массив.Добавить("SetPasswordRecoverySettings"); Массив.Добавить("Base64Value"); Массив.Добавить("ValueFromStringInternal"); Массив.Добавить("XMLValue"); // Процедуры и функции БСП Массив.Добавить("ВыполнитьМетодОбъекта"); Массив.Добавить("ВыполнитьМетодКонфигурации"); Массив.Добавить("ВыполнитьФоновоеЗадание"); Массив.Добавить("ОбщийМодуль"); Массив.Добавить("ЗначениеИзСтрокиXML"); Возврат Массив; КонецФункции Функция ЗапрещенныеСвойстваГлобальногоКонтекста() Массив = Новый Массив; Массив.Добавить("ПользователиИнформационнойБазы"); // @Non-NLS Массив.Добавить("ДополнительныеНастройкиАутентификации"); // @Non-NLS Массив.Добавить("ПараметрыСеанса"); // @Non-NLS Массив.Добавить("ФоновыеЗадания"); // @Non-NLS Массив.Добавить("РасширенияКонфигурации"); // @Non-NLS Массив.Добавить("InfoBaseUsers"); Массив.Добавить("AdditionalAuthenticationSettings"); Массив.Добавить("SessionParameters"); Массив.Добавить("BackgroundJobs"); Массив.Добавить("ConfigurationExtensions"); Возврат Массив; КонецФункции Функция ЗапрещенныеМодули() Массив = Новый Массив; Массив.Добавить("ДлительныеОперации"); Возврат Массив; КонецФункции #КонецОбласти #Область ВспомогательныеПроцедурыВажныхСообщений Процедура ВывестиКонтекстноеВажноеСообщение(Форма, ВсегоВажныхСообщений) Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл ПараметрыСообщения = ЭлементСписка.Значение; Если Не ЗначениеЗаполнено(ПараметрыСообщения.Родитель) Тогда Продолжить; КонецЕсли; ВсегоВажныхСообщений = ВсегоВажныхСообщений - 1; РодительскаяГруппа = Форма.Элементы[ПараметрыСообщения.Родитель]; Если ЗначениеЗаполнено(ПараметрыСообщения.Идентификатор) Тогда ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ПараметрыСообщения.Идентификатор; Иначе ИмяГруппы = ПараметрыСообщения.Родитель + "_" + "БФ_ГруппаКонтекстноеСообщение"; КонецЕсли; Группа = Форма.Элементы.Найти(ИмяГруппы); Если Группа <> Неопределено Тогда // Повторный вывод сообщения. Форма.Элементы.Удалить(Группа); КонецЕсли; Элемент = Неопределено; Если ЗначениеЗаполнено(ПараметрыСообщения.Элемент) Тогда Элемент = Форма.Элементы[ПараметрыСообщения.Элемент]; КонецЕсли; ГруппаРазмещенияКонтекстногоСообщения = Форма.Элементы.Вставить(ИмяГруппы, Тип("ГруппаФормы"), РодительскаяГруппа, Элемент); ГруппаРазмещенияКонтекстногоСообщения.Вид = ВидГруппыФормы.ОбычнаяГруппа; ГруппаРазмещенияКонтекстногоСообщения.ОтображатьЗаголовок = Ложь; ГруппаРазмещенияКонтекстногоСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда; ГруппаРазмещенияКонтекстногоСообщения.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, ГруппаРазмещенияКонтекстногоСообщения); КонецЦикла; КонецПроцедуры Процедура ВывестиОдиночноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений) Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл Если ЗначениеЗаполнено(ЭлементСписка.Значение.Родитель) Тогда // Пропускаем контекстные сообщения. Продолжить; КонецЕсли; ПараметрыСообщения = ЭлементСписка.Значение; Прервать; КонецЦикла; Если ЗначениеЗаполнено(ПараметрыСообщения.Идентификатор) Тогда ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ПараметрыСообщения.Идентификатор; Иначе ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ГруппаРазмещенияВажныхСообщений.Имя + "_" + ПараметрыСообщения.ТипСообщения; КонецЕсли; ГруппаРазмещенияСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений); ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, ГруппаРазмещенияСообщения); КонецПроцедуры Процедура ВывестиАгрегированноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений, СгруппированныеСообщения, ЕстьСтатусы) ЦветаВажныхСообщений = ЦветаВажныхСообщений(); КартинкиВажныхСообщений = КартинкиВажныхСообщений(); ВыведеноСообщений = 0; ЛимитСообщений = 5; Если ЕстьСтатусы Тогда ВсегоСтатусов = Форма.БФ_ДобавляемыеСтатусы.Количество(); Если ВсегоСтатусов >= 3 Тогда ЛимитСообщений = 2; Иначе ЛимитСообщений = ЛимитСообщений - ВсегоСтатусов; КонецЕсли; КонецЕсли; Для Каждого СтрокаСообщение Из СгруппированныеСообщения Цикл Если ЗначениеЗаполнено(СтрокаСообщение.ПараметрыСообщения.Идентификатор) Тогда ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СтрокаСообщение.ПараметрыСообщения.Идентификатор; Иначе ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СгруппированныеСообщения.Индекс(СтрокаСообщение) + "_" + СтрокаСообщение.ТипСообщения; КонецЕсли; ГруппаВажноеСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений); ГруппаВажноеСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ДекорацияКартинка = Форма.Элементы.Добавить(ИмяГруппы + "_" + "КартинкаСообщения", Тип("ДекорацияФормы"), ГруппаВажноеСообщение); ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка; ДекорацияКартинка.Картинка = КартинкиВажныхСообщений[СтрокаСообщение.ТипСообщения]; ДекорацияКартинка.ЦветКартинки = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения]; ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений(); ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта; ИмяГруппы = ИмяГруппы + "_" + "Заголовок"; ГруппаЗаголовок = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаВажноеСообщение); ГруппаЗаголовок.Поведение = ПоведениеОбычнойГруппы.Всплывающая; ГруппаЗаголовок.Отображение = ОтображениеОбычнойГруппы.Нет; ГруппаЗаголовок.ОтображатьЗаголовок = Истина; КраткоеПредставление = СтрокаСообщение.ПараметрыСообщения.КраткоеПредставление; Если СтрДлина(КраткоеПредставление) > 38 Тогда КраткоеПредставление = Лев(КраткоеПредставление, 35) + "..."; КонецЕсли; ГруппаЗаголовок.Заголовок = КраткоеПредставление; Если Не ОбщегоНазначенияКлиентСервер.ЭтоВариантИнтерфейса85() Тогда ГруппаЗаголовок.ЦветТекстаЗаголовка = ЦветаПалитры.Синий; КонецЕсли; ИмяГруппы = ИмяГруппы + "_" + "Сообщение"; ГруппаСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаЗаголовок); ГруппаСообщение.Вид = ВидГруппыФормы.ОбычнаяГруппа; ГруппаСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаСообщение.Ширина = 40; ГруппаСообщение.ОтображатьКакКарточку = Истина; ГруппаСообщение.РастягиватьПоГоризонтали = Ложь; ГруппаСообщение.ЦветФона = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения]; ИмяГруппы = ИмяГруппы + "_" + "КонтентСообщения"; ГруппаКонтентСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаСообщение); ГруппаКонтентСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; ГруппаКонтентСообщения.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаКонтентСообщения.РастягиватьПоГоризонтали = Истина; ВывестиКонтентСообщения(Форма, ГруппаКонтентСообщения, СтрокаСообщение.ПараметрыСообщения); ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаСообщение, ГруппаВажноеСообщение, СтрокаСообщение.ПараметрыСообщения); ВыведеноСообщений = ВыведеноСообщений + 1; Если ВыведеноСообщений = ЛимитСообщений Тогда Прервать; КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ВывестиГруппуПоказатьВсеВажныеСообщения(Форма, СгруппированныеСообщения, ГруппаРазмещенияВажныхСообщений) ЦветаВажныхСообщений = ЦветаВажныхСообщений(); ИмяГруппы = ГруппаРазмещенияВажныхСообщений.Имя + "_" + "ПоказатьВсе"; ГруппаПоказатьВсе = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений); ГруппаПоказатьВсе.Заголовок = НСтр("ru = 'Показать все'"); ГруппаПоказатьВсе.ОтображатьЗаголовок = Истина; ГруппаПоказатьВсе.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; ГруппаПоказатьВсе.Поведение = ПоведениеОбычнойГруппы.Всплывающая; ГруппаПоказатьВсе.Отображение = ОтображениеОбычнойГруппы.Нет; ГруппаПоказатьВсе.ГоризонтальноеПоложениеВГруппе = ГоризонтальноеПоложениеЭлемента.Право; ГруппаПоказатьВсе.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаПоказатьВсе.ПутьКДаннымЗаголовка = "БФ_ВсегоВажныхСообщений"; Для Каждого СтрокаСообщение Из СгруппированныеСообщения Цикл Если ЗначениеЗаполнено(СтрокаСообщение.ПараметрыСообщения.Идентификатор) Тогда ИмяГруппыСообщения = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе() + ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СтрокаСообщение.ПараметрыСообщения.Идентификатор; Иначе ИмяГруппыСообщения = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе() + ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СгруппированныеСообщения.Индекс(СтрокаСообщение) + "_" + СтрокаСообщение.ТипСообщения; КонецЕсли; ГруппаСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппыСообщения, ГруппаПоказатьВсе); ГруппаСообщение.Вид = ВидГруппыФормы.ОбычнаяГруппа; ГруппаСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаСообщение.Ширина = 40; ГруппаСообщение.ОтображатьКакКарточку = Истина; ГруппаСообщение.РастягиватьПоГоризонтали = Ложь; ГруппаСообщение.ЦветФона = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения]; ИмяГруппыКонтент = ИмяГруппыСообщения + "_" + "КонтентСообщения"; ГруппаКонтентСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппыКонтент, ГруппаСообщение); ГруппаКонтентСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; ГруппаКонтентСообщения.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаКонтентСообщения.РастягиватьПоГоризонтали = Истина; ВывестиКонтентСообщения(Форма, ГруппаКонтентСообщения, СтрокаСообщение.ПараметрыСообщения, Истина); ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаСообщение, ГруппаСообщение, СтрокаСообщение.ПараметрыСообщения); КонецЦикла; КонецПроцедуры Процедура ВывестиСтатусыНаФорму(Форма, РодительскаяГруппа) // Упорядочивание статусов. ТаблицаСтатусов = Новый ТаблицаЗначений; ТаблицаСтатусов.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число")); ТаблицаСтатусов.Колонки.Добавить("ОписаниеСтатуса"); Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеСтатусы Цикл ПараметрыСтатуса = ЭлементСписка.Значение; Строка = ТаблицаСтатусов.Добавить(); Если ПараметрыСтатуса.Порядок = Неопределено Тогда Строка.Порядок = 9999; Иначе Строка.Порядок = ПараметрыСтатуса.Порядок; КонецЕсли; Строка.ОписаниеСтатуса = ПараметрыСтатуса; КонецЦикла; ТаблицаСтатусов.Сортировать("Порядок Возр"); Форма.БФ_ВсегоСтатусов = Форма.БФ_ДобавляемыеСтатусы.Количество(); // Группа для статусов. ГруппаРазмещенияСтатусов = Форма.Элементы.Найти("БФ_ГруппаСтатусы"); Если ГруппаРазмещенияСтатусов <> Неопределено Тогда // Повторный вывод сообщения. Форма.Элементы.Удалить(ГруппаРазмещенияСтатусов); КонецЕсли; ГруппаРазмещенияСтатусов = НоваяГруппаВажногоСообщения(Форма, "БФ_ГруппаСтатусы", РодительскаяГруппа); ГруппаРазмещенияСтатусов.ОтображатьКакКарточку = Истина; ВыводитьПоказатьВсе = Форма.БФ_ВсегоСтатусов > 6; Если ВыводитьПоказатьВсе Тогда ИмяГруппы = ГруппаРазмещенияСтатусов.Имя + "_" + "ПоказатьВсе"; ГруппаПоказатьВсе = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияСтатусов); ГруппаПоказатьВсе.Заголовок = НСтр("ru = 'Показать все'"); ГруппаПоказатьВсе.ОтображатьЗаголовок = Истина; ГруппаПоказатьВсе.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; ГруппаПоказатьВсе.Поведение = ПоведениеОбычнойГруппы.Всплывающая; ГруппаПоказатьВсе.Отображение = ОтображениеОбычнойГруппы.Нет; ГруппаПоказатьВсе.ГоризонтальноеПоложениеВГруппе = ГоризонтальноеПоложениеЭлемента.Право; ГруппаПоказатьВсе.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ГруппаПоказатьВсе.ПутьКДаннымЗаголовка = "БФ_ВсегоСтатусов"; КонецЕсли; Для Каждого Строка Из ТаблицаСтатусов Цикл ВывестиСтатус(Форма, Строка.ОписаниеСтатуса, ГруппаРазмещенияСтатусов); Если ВыводитьПоказатьВсе Тогда ПрефиксВсе = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе(); ВывестиСтатус(Форма, Строка.ОписаниеСтатуса, ГруппаПоказатьВсе, ПрефиксВсе); КонецЕсли; КонецЦикла; Если ВыводитьПоказатьВсе Тогда Форма.Элементы.Переместить(ГруппаПоказатьВсе, ГруппаРазмещенияСтатусов); КонецЕсли; КонецПроцедуры Процедура ВывестиСтатус(Форма, ПараметрыСтатуса, ГруппаРазмещенияСтатусов, ПрефиксВсе = "") ИмяГруппы = ПрефиксВсе + ОбщегоНазначенияКлиентСервер.ПрефиксГруппыСтатуса() + ПараметрыСтатуса.Идентификатор; ГруппаСтатус = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияСтатусов); ГруппаСтатус.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; Если ЗначениеЗаполнено(ПрефиксВсе) Тогда ГруппаСтатус.Ширина = 30; ГруппаСтатус.РастягиватьПоГоризонтали = Ложь; ГруппаСтатус.ОтображатьКакКарточку = Истина; КонецЕсли; Если ЗначениеЗаполнено(ПараметрыСтатуса.Картинка) Тогда ДекорацияКартинка = Форма.Элементы.Добавить(ГруппаСтатус.Имя + "_" + "КартинкаСтатуса", Тип("ДекорацияФормы"), ГруппаСтатус); ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка; ДекорацияКартинка.Картинка = ПараметрыСтатуса.Картинка; ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений(); ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта; КонецЕсли; ДекорацияНадпись = Форма.Элементы.Добавить(ОбщегоНазначенияКлиентСервер.ПрефиксСтатуса() + ПрефиксВсе + ПараметрыСтатуса.Идентификатор, Тип("ДекорацияФормы"), ГруппаСтатус); ДекорацияНадпись.Вид = ВидДекорацииФормы.Надпись; ДекорацияНадпись.Заголовок = ПараметрыСтатуса.Наименование; ДекорацияНадпись.Шрифт = ШрифтВажныхСообщений(); Если ЗначениеЗаполнено(ПараметрыСтатуса.Обработчик) Тогда ДекорацияНадпись.Гиперссылка = Истина; Если СтрРазделить(ПараметрыСтатуса.Обработчик, ".").Количество() = 1 Тогда ДекорацияНадпись.УстановитьДействие("Нажатие", ПараметрыСтатуса.Обработчик); Иначе ДекорацияНадпись.УстановитьДействие("Нажатие", "Подключаемый_ОбработатьДействиеИнформационногоСообщения"); КонецЕсли; Форма.БФ_ОбработчикиСтатусов.Вставить(ПараметрыСтатуса.Идентификатор, ПараметрыСтатуса.Обработчик); КонецЕсли; КонецПроцедуры Процедура ВывестиКонтентСообщения(Форма, ГруппаКонтент, ПараметрыСообщения, ПоказатьВсе = Ложь) ЕстьЗаголовок = ЗначениеЗаполнено(ПараметрыСообщения.Заголовок); ЕстьДействие = (ПараметрыСообщения.ПараметрыДействия <> Неопределено); Если ЕстьЗаголовок Тогда ДекорацияЗаголовок = Форма.Элементы.Добавить(ГруппаКонтент.Имя + "_" + "ЗаголовокВажногоСообщения", Тип("ДекорацияФормы"), ГруппаКонтент); ДекорацияЗаголовок.Вид = ВидДекорацииФормы.Надпись; ДекорацияЗаголовок.Заголовок = ПараметрыСообщения.Заголовок; ДекорацияЗаголовок.АвтоМаксимальнаяШирина = Ложь; УстановитьШрифтЗаголовкаВажныхСообщений(ДекорацияЗаголовок.Шрифт); КонецЕсли; ДекорацияНадпись = Форма.Элементы.Добавить(ГруппаКонтент.Имя + "_" + "НадписьВажногоСообщения", Тип("ДекорацияФормы"), ГруппаКонтент); ДекорацияНадпись.Вид = ВидДекорацииФормы.Надпись; ДекорацияНадпись.Заголовок = ПараметрыСообщения.Сообщение; ДекорацияНадпись.Шрифт = ШрифтВажныхСообщений(); ДекорацияНадпись.АвтоМаксимальнаяШирина = Ложь; Если ТипЗнч(ПараметрыСообщения.Сообщение) = Тип("ФорматированнаяСтрока") Тогда Если ЗначениеЗаполнено(ПараметрыСообщения.Обработчик) И СтрРазделить(ПараметрыСообщения.Обработчик, ".").Количество() = 1 Тогда ДекорацияНадпись.УстановитьДействие("ОбработкаНавигационнойСсылки", ПараметрыСообщения.Обработчик); Иначе ДекорацияНадпись.УстановитьДействие("ОбработкаНавигационнойСсылки", "Подключаемый_ОбработатьДействиеИнформационногоСообщения"); КонецЕсли; КонецЕсли; Если ЕстьДействие Тогда ПараметрыДействия = ПараметрыСообщения.ПараметрыДействия; Если ТипЗнч(ПараметрыДействия) <> Тип("Массив") Тогда ПараметрыДействия = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПараметрыДействия); КонецЕсли; ИмяГруппы = ГруппаКонтент.Имя + "_" + "КомандыДействия"; ГруппаКомандыДействия = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаКонтент); Для Каждого ОписаниеДействия Из ПараметрыДействия Цикл ИмяКоманды = ?(ПоказатьВсе, ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе(), "") + ОписаниеДействия.ИмяКоманды; КомандаДействие = Форма.Команды.Найти(ИмяКоманды); Если КомандаДействие = Неопределено Тогда КомандаДействие = Форма.Команды.Добавить(ИмяКоманды); КонецЕсли; КомандаДействие.Заголовок = ОписаниеДействия.Заголовок; Если СтрРазделить(ОписаниеДействия.Обработчик, ".").Количество() = 1 Тогда КомандаДействие.Действие = ОписаниеДействия.Обработчик; Иначе КомандаДействие.Действие = "Подключаемый_ОбработатьДействиеИнформационногоСообщения"; КонецЕсли; ИмяКнопки = ГруппаКомандыДействия.Имя + "_" + ОписаниеДействия.ИмяКоманды; КнопкаДействие = Форма.Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), ГруппаКомандыДействия); КнопкаДействие.Вид = ВидКнопкиФормы.Гиперссылка; КнопкаДействие.Заголовок = ОписаниеДействия.Заголовок; КнопкаДействие.ИмяКоманды = КомандаДействие.Имя; КонецЦикла; КонецЕсли; КонецПроцедуры Процедура ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаРазмещения, СкрываемаяГруппа, Параметры) Если Не Параметры.Скрываемый Тогда Возврат; КонецЕсли; Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия) И Не ЗначениеЗаполнено(Параметры.Идентификатор) Тогда ТекстИсключения = НСтр("ru = 'Для важного сообщения с заполненным свойством ""ОбработчикЗакрытия"" |должно быть заполнено свойство ""Идентификатор"". | |Текст проблемного сообщения: |%1'"); ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения, Параметры.Сообщение); КонецЕсли; ИмяКоманды = ОбщегоНазначенияКлиентСервер.ПрефиксКомандСкрытияВажногоСообщения() + СкрываемаяГруппа.Имя; КомандаЗакрытия = Форма.Команды.Найти(ИмяКоманды); Если КомандаЗакрытия = Неопределено Тогда КомандаЗакрытия = Форма.Команды.Добавить(ИмяКоманды); КонецЕсли; КомандаЗакрытия.Заголовок = НСтр("ru = 'Скрыть сообщение'"); КомандаЗакрытия.Подсказка = НСтр("ru = 'Скрыть сообщение'"); КомандаЗакрытия.Картинка = БиблиотекаКартинок.ВажноеСообщениеЗакрыть; Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия) И СтрРазделить(Параметры.ОбработчикЗакрытия, ".").Количество() = 1 Тогда КомандаЗакрытия.Действие = Параметры.ОбработчикЗакрытия; Иначе КомандаЗакрытия.Действие = "Подключаемый_ОбработатьДействиеИнформационногоСообщения"; КонецЕсли; КнопкаЗакрытие = Форма.Элементы.Добавить(СкрываемаяГруппа.Имя + "_" + "КнопкаЗакрыть", Тип("КнопкаФормы"), ГруппаРазмещения); КнопкаЗакрытие.Вид = ВидКнопкиФормы.Гиперссылка; КнопкаЗакрытие.ИмяКоманды = КомандаЗакрытия.Имя; КнопкаЗакрытие.Отображение = ОтображениеКнопки.Картинка; Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия) Тогда ПараметрыКоманды = Новый Структура(); ПараметрыКоманды.Вставить("Обработчик", Параметры.ОбработчикЗакрытия); ПараметрыКоманды.Вставить("Идентификатор", Параметры.Идентификатор); Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(ИмяКоманды, ПараметрыКоманды); КонецЕсли; КонецПроцедуры // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - Строка // * Значение - Цвет - цвет из палитры. // Функция ЦветаВажныхСообщений() Соответствие = Новый Соответствие; Соответствие.Вставить("Успех", ЦветаПалитры.Зеленый); Соответствие.Вставить("Информация", ЦветаПалитры.Голубой); Соответствие.Вставить("Предупреждение", ЦветаПалитры.Желтый); Соответствие.Вставить("Ошибка", ЦветаПалитры.Красный); Возврат Соответствие; КонецФункции // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - Строка // * Значение - Картинка // Функция КартинкиВажныхСообщений() Соответствие = Новый Соответствие; Соответствие.Вставить("Успех", БиблиотекаКартинок.ВажноеСообщениеУспешно); Соответствие.Вставить("Информация", БиблиотекаКартинок.ВажноеСообщениеИнформация); Соответствие.Вставить("Предупреждение", БиблиотекаКартинок.ВажноеСообщениеПредупреждение); Соответствие.Вставить("Ошибка", БиблиотекаКартинок.ВажноеСообщениеОшибка); Возврат Соответствие; КонецФункции Процедура УстановитьШрифтЗаголовкаВажныхСообщений(Шрифт) Шрифт = ШрифтыСтиля.ТекстВторогоУровня; КонецПроцедуры // Возвращаемое значение: // Шрифт // Функция ШрифтВажныхСообщений() Возврат ШрифтыСтиля.ТекстТретьегоУровня; КонецФункции // Возвращаемое значение: // ГруппаФормы // Функция НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, Родитель) Группа = Форма.Элементы.Добавить(ИмяГруппы, Тип("ГруппаФормы"), Родитель); Группа.Вид = ВидГруппыФормы.ОбычнаяГруппа; Группа.ОтображатьЗаголовок = Ложь; Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда; Возврат Группа; КонецФункции // Возвращаемое значение: // ТаблицаЗначений: // * ТипСообщения - Строка // * Количество - Число // * ПараметрыСообщения - Массив из см. ОбщегоНазначения.ПараметрыВажногоСообщения // Функция НоваяТаблицаСгруппированныхСообщений() СгруппированныеСообщения = Новый ТаблицаЗначений; СгруппированныеСообщения.Колонки.Добавить("ТипСообщения", Новый ОписаниеТипов("Строка")); СгруппированныеСообщения.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число")); СгруппированныеСообщения.Колонки.Добавить("ПараметрыСообщения", Новый ОписаниеТипов("Структура")); Возврат СгруппированныеСообщения; КонецФункции // Параметры: // СгруппированныеСообщения - см. ОбщегоНазначения.НоваяТаблицаСгруппированныхСообщений // ДобавляемыеСообщения - см. ОбщегоНазначения.ПараметрыВажногоСообщения // Процедура СгруппироватьСообщения(СгруппированныеСообщения, ДобавляемыеСообщения) Для Каждого ДобавляемоеСообщение Из ДобавляемыеСообщения.ВыгрузитьЗначения() Цикл Если ЗначениеЗаполнено(ДобавляемоеСообщение.Родитель) Тогда Продолжить; КонецЕсли; Строка = СгруппированныеСообщения.Добавить(); Строка.ТипСообщения = ДобавляемоеСообщение.ТипСообщения; Если ДобавляемоеСообщение.ТипСообщения = "Ошибка" Тогда Строка.Уровень = 0; ИначеЕсли ДобавляемоеСообщение.ТипСообщения = "Предупреждение" Тогда Строка.Уровень = 1; ИначеЕсли ДобавляемоеСообщение.ТипСообщения = "Информация" Тогда Строка.Уровень = 2; Иначе Строка.Уровень = 3; КонецЕсли; Строка.ПараметрыСообщения = ДобавляемоеСообщение; КонецЦикла; СгруппированныеСообщения.Сортировать("Уровень Возр"); КонецПроцедуры Процедура ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, Родитель) ЦветаВажныхСообщений = ЦветаВажныхСообщений(); КартинкиВажныхСообщений = КартинкиВажныхСообщений(); Родитель.ЦветФона = ЦветаВажныхСообщений[ПараметрыСообщения.ТипСообщения]; ДекорацияКартинка = Форма.Элементы.Добавить(Родитель.Имя + "_" + "КартинкаСообщения", Тип("ДекорацияФормы"), Родитель); ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка; ДекорацияКартинка.Картинка = КартинкиВажныхСообщений[ПараметрыСообщения.ТипСообщения]; ДекорацияКартинка.ЦветКартинки = ЦветаВажныхСообщений[ПараметрыСообщения.ТипСообщения]; Если ЗначениеЗаполнено(ПараметрыСообщения.Заголовок) Тогда УстановитьШрифтЗаголовкаВажныхСообщений(ДекорацияКартинка.Шрифт); Иначе ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений(); ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта; КонецЕсли; ИмяГруппы = Родитель.Имя + "_" + "БФ_ГруппаВажноеСообщение"; ГруппаВажноеСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, Родитель); ГруппаВажноеСообщение.РастягиватьПоГоризонтали = Истина; ГруппаВажноеСообщение.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная; ГруппаВажноеСообщение.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный; ВывестиКонтентСообщения(Форма, ГруппаВажноеСообщение, ПараметрыСообщения); ДобавитьКнопкуСкрытияСообщения(Форма, Родитель, Родитель, ПараметрыСообщения); КонецПроцедуры #КонецОбласти // См. СтандартныеПодсистемыСервер.ПриОпределенииМетодовРазрешенныхДляВызоваКакПроизвольныйКод Процедура ПриОпределенииМетодовРазрешенныхДляВызоваКакПроизвольныйКод(Методы) Экспорт Методы.Вставить("ЕстьСсылкиНаОбъект", Истина); КонецПроцедуры #КонецОбласти #КонецЕсли