///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ОписаниеПеременных

Перем СтарыеЗаписи; // Заполняется ПередЗаписью для использования ПриЗаписи.

#КонецОбласти

#Область ОбработчикиСобытий

Процедура ПередЗаписью(Отказ, Замещение)
	
	// АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал.
	ПодготовитьЗаписьИзмененийВЖурналРегистрации(ЭтотОбъект, Замещение, СтарыеЗаписи);
	// АПК:75-вкл
	
	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

Процедура ПриЗаписи(Отказ, Замещение)
	
	// АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал.
	ЗаписатьИзмененияВЖурналРегистрации(ЭтотОбъект, Замещение, СтарыеЗаписи);
	// АПК:75-вкл
	
	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Процедура ПодготовитьЗаписьИзмененийВЖурналРегистрации(НаборЗаписей, Замещение, СтарыеЗаписи)
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	СтарыеЗаписи = ОбщегоНазначения.ЗаписиНабораИзБазыДанных(НаборЗаписей, Замещение, СписокПолей());
	
КонецПроцедуры

Процедура ЗаписатьИзмененияВЖурналРегистрации(НаборЗаписей, Замещение, СтарыеЗаписи)
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	Если ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) Тогда
		НовыеЗаписи = НаборЗаписей.Выгрузить(Новый Массив, СписокПолей());
	Иначе
		НовыеЗаписи = НаборЗаписей.Выгрузить(, СписокПолей());
	КонецЕсли;
	Для Каждого НоваяЗапись Из НовыеЗаписи Цикл
		Если СтарыеЗаписи.Найти(НоваяЗапись.Пользователь, "Пользователь") = Неопределено Тогда
			СтарыеЗаписи.Добавить().Пользователь = НоваяЗапись.Пользователь;
		КонецЕсли;
	КонецЦикла;
	
	Таблица = ОбщегоНазначения.ИзменениеЗаписейНабора(СтарыеЗаписи, НаборЗаписей, Замещение);
	
	Если НаборЗаписей.ДополнительныеСвойства.Свойство("СвойстваПользователя")
	   И ТипЗнч(НаборЗаписей.ДополнительныеСвойства.СвойстваПользователя) = Тип("Структура") Тогда
		
		СвойстваПользователя = НаборЗаписей.ДополнительныеСвойства.СвойстваПользователя;
	Иначе
		СвойстваПользователя = Новый Структура;
	КонецЕсли;
	
	СтрокиБезИзменений = Таблица.НайтиСтроки(Новый Структура("ВидИзмененияСтроки", 0));
	Если Таблица.Количество() = СтрокиБезИзменений.Количество()
	   И Не СвойстваПользователя.Свойство("ЗаписатьИзмененияВЖурнал") Тогда
		Возврат;
	КонецЕсли;
	
	Если СвойстваПользователя.Свойство("ИдентификаторПользователяИБ")
	   И ТипЗнч(СвойстваПользователя.ИдентификаторПользователяИБ) = Тип("УникальныйИдентификатор")
	   И НаборЗаписей.Количество() = 1 Тогда
		
		СвойстваПользователей = Новый ТаблицаЗначений;
		СвойстваПользователей.Колонки.Добавить("Пользователь");
		СвойстваПользователей.Колонки.Добавить("ИдентификаторПользователяИБ");
		СвойстваПользователей.Колонки.Добавить("ПометкаУдаления");
		СвойстваПользователей.Колонки.Добавить("Недействителен");
		СвойстваПользователей.Колонки.Добавить("Подразделение");
		СвойстваПользователей.Колонки.Добавить("ФизическоеЛицо");
		НоваяСтрока = СвойстваПользователей.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СвойстваПользователя);
		НоваяСтрока.Пользователь = НаборЗаписей[0].Пользователь;
		СтарыеЗначения = СвойстваПользователя.СтарыеЗначения;
	Иначе
		Запрос = Новый Запрос;
		Запрос.УстановитьПараметр("СписокПользователей", Таблица.ВыгрузитьКолонку("Пользователь"));
		Запрос.Текст =
		"ВЫБРАТЬ
		|	Пользователи.Ссылка КАК Пользователь,
		|	Пользователи.ИдентификаторПользователяИБ КАК ИдентификаторПользователяИБ,
		|	Пользователи.ПометкаУдаления КАК ПометкаУдаления,
		|	Пользователи.Недействителен КАК Недействителен,
		|	Пользователи.Подразделение КАК Подразделение,
		|	Пользователи.ФизическоеЛицо КАК ФизическоеЛицо
		|ИЗ
		|	Справочник.Пользователи КАК Пользователи
		|ГДЕ
		|	Пользователи.Ссылка В(&СписокПользователей)
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ
		|	ВнешниеПользователи.Ссылка,
		|	ВнешниеПользователи.ИдентификаторПользователяИБ,
		|	ВнешниеПользователи.ПометкаУдаления,
		|	ВнешниеПользователи.Недействителен,
		|	НЕОПРЕДЕЛЕНО,
		|	НЕОПРЕДЕЛЕНО
		|ИЗ
		|	Справочник.ВнешниеПользователи КАК ВнешниеПользователи
		|ГДЕ
		|	ВнешниеПользователи.Ссылка В(&СписокПользователей)";
		
		СвойстваПользователей = Запрос.Выполнить().Выгрузить();
		СвойстваПользователей.Индексы.Добавить("Пользователь");
		СтарыеЗначения = Неопределено;
	КонецЕсли;
	
	ОбработанныеПользователи = Новый Соответствие;
	ДополнительныеСвойстваПользователяИБ = "ПотребоватьСменуПароляПриВходе,
		|СрокДействияНеОграничен, СрокДействия, ПросрочкаРаботыВПрограммеДоЗапрещенияВхода";
	
	Для Каждого Строка Из Таблица Цикл
		Если Не ЗначениеЗаполнено(Строка.Пользователь)
		 Или ОбработанныеПользователи.Получить(Строка.Пользователь) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ОбработанныеПользователи.Вставить(Строка.Пользователь, Истина);
		
		Данные = Новый Структура;
		Данные.Вставить("ВерсияСтруктурыДанных", 2);
		Данные.Вставить("Ссылка", СериализованнаяСсылка(Строка.Пользователь));
		Данные.Вставить("ТипСсылки", Строка.Пользователь.Метаданные().ПолноеИмя());
		Данные.Вставить("ИдентификаторСсылки", НРег(Строка.Пользователь.УникальныйИдентификатор()));
		Данные.Вставить("ИдентификаторПользователяИБ");
		Данные.Вставить("Имя");
		Данные.Вставить("ПотребоватьСменуПароляПриВходе", Ложь);
		Данные.Вставить("СрокДействияНеОграничен", Ложь);
		Данные.Вставить("СрокДействия", '00010101');
		Данные.Вставить("ПросрочкаРаботыВПрограммеДоЗапрещенияВхода", 0);
		Данные.Вставить("ПометкаУдаления");
		Данные.Вставить("Недействителен");
		Данные.Вставить("Подразделение");
		Данные.Вставить("ПодразделениеПредставление");
		Данные.Вставить("ФизическоеЛицо");
		Данные.Вставить("ФизическоеЛицоПредставление");
		Данные.Вставить("СтарыеЗначенияСвойств", Новый Структура);
		
		ТекущиеЗначения = СвойстваПользователей.Найти(Строка.Пользователь, "Пользователь");
		Если ТекущиеЗначения <> Неопределено Тогда
			Данные.ИдентификаторПользователяИБ = НРег(ТекущиеЗначения.ИдентификаторПользователяИБ);
			Данные.ПометкаУдаления = ТекущиеЗначения.ПометкаУдаления;
			Данные.Недействителен  = ТекущиеЗначения.Недействителен;
			Данные.Подразделение   = СериализованнаяСсылка(ТекущиеЗначения.Подразделение);
			Данные.ФизическоеЛицо  = СериализованнаяСсылка(ТекущиеЗначения.ФизическоеЛицо);
			Данные.ПодразделениеПредставление  = ПредставлениеСсылки(ТекущиеЗначения.Подразделение);
			Данные.ФизическоеЛицоПредставление = ПредставлениеСсылки(ТекущиеЗначения.ФизическоеЛицо);
			ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(
				ТекущиеЗначения.ИдентификаторПользователяИБ);
			Если ПользовательИБ <> Неопределено Тогда
				Данные.Имя = ПользовательИБ.Имя;
			КонецЕсли;
		КонецЕсли;
		Если СтарыеЗначения <> Неопределено Тогда
			Если ТекущиеЗначения.ИдентификаторПользователяИБ <> СтарыеЗначения.ИдентификаторПользователяИБ Тогда
				Данные.СтарыеЗначенияСвойств.Вставить("ИдентификаторПользователяИБ",
					НРег(СтарыеЗначения.ИдентификаторПользователяИБ));
			КонецЕсли;
			Если ТекущиеЗначения.ПометкаУдаления <> СтарыеЗначения.ПометкаУдаления Тогда
				Данные.СтарыеЗначенияСвойств.Вставить("ПометкаУдаления", СтарыеЗначения.ПометкаУдаления);
			КонецЕсли;
			Если ТекущиеЗначения.Недействителен <> СтарыеЗначения.Недействителен Тогда
				Данные.СтарыеЗначенияСвойств.Вставить("Недействителен", СтарыеЗначения.Недействителен);
			КонецЕсли;
			Если ТекущиеЗначения.Подразделение <> СтарыеЗначения.Подразделение Тогда
				Данные.СтарыеЗначенияСвойств.Вставить("Подразделение",
					СериализованнаяСсылка(СтарыеЗначения.Подразделение));
				Данные.СтарыеЗначенияСвойств.Вставить("ПодразделениеПредставление",
					ПредставлениеСсылки(СтарыеЗначения.Подразделение));
			КонецЕсли;
			Если ТекущиеЗначения.ФизическоеЛицо <> СтарыеЗначения.ФизическоеЛицо Тогда
				Данные.СтарыеЗначенияСвойств.Вставить("ФизическоеЛицо",
					СериализованнаяСсылка(СтарыеЗначения.ФизическоеЛицо));
				Данные.СтарыеЗначенияСвойств.Вставить("ФизическоеЛицоПредставление",
					ПредставлениеСсылки(СтарыеЗначения.ФизическоеЛицо));
			КонецЕсли;
		КонецЕсли;
		
		Если Строка.ВидИзмененияСтроки >= 0 Тогда
			НоваяЗапись = НовыеЗаписи.Найти(Строка.Пользователь, "Пользователь");
			ЗаполнитьЗначенияСвойств(Данные, НоваяЗапись, ДополнительныеСвойстваПользователяИБ);
		КонецЕсли;
		Если Строка.ВидИзмененияСтроки <> 0 Тогда
			СтараяЗапись = СтарыеЗаписи.Найти(Строка.Пользователь, "Пользователь");
			СтруктураСвойств = Новый Структура(ДополнительныеСвойстваПользователяИБ);
			Для Каждого КлючИЗначение Из СтруктураСвойств Цикл
				Если Данные[КлючИЗначение.Ключ] <> СтараяЗапись[КлючИЗначение.Ключ] Тогда
					Данные.СтарыеЗначенияСвойств.Вставить(КлючИЗначение.Ключ, СтараяЗапись[КлючИЗначение.Ключ]);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
		ЗаписьЖурналаРегистрации(
			ПользователиСлужебный.ИмяСобытияИзменениеДополнительноДляЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Информация,
			Метаданные.РегистрыСведений.СведенияОПользователях,
			ОбщегоНазначения.ЗначениеВСтрокуXML(Данные),
			,
			РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная);
	КонецЦикла;
	
	УстановитьПривилегированныйРежим(Ложь);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
КонецПроцедуры

// Для процедур ПодготовитьЗаписьИзмененийВЖурналРегистрации, ЗаписатьИзмененияВЖурналРегистрации.
Функция СписокПолей()
	
	МетаданныеРегистра = Метаданные();
	
	Поля = Новый Массив;
	Поля.Добавить(МетаданныеРегистра.Измерения.Пользователь.Имя);
	Поля.Добавить(МетаданныеРегистра.Ресурсы.ПотребоватьСменуПароляПриВходе.Имя);
	Поля.Добавить(МетаданныеРегистра.Ресурсы.СрокДействияНеОграничен.Имя);
	Поля.Добавить(МетаданныеРегистра.Ресурсы.СрокДействия.Имя);
	Поля.Добавить(МетаданныеРегистра.Ресурсы.ПросрочкаРаботыВПрограммеДоЗапрещенияВхода.Имя);
	
	Возврат СтрСоединить(Поля, ",");
	
КонецФункции

// См. ПользователиСлужебный.СериализованнаяСсылка
Функция СериализованнаяСсылка(Ссылка)
	Возврат ПользователиСлужебный.СериализованнаяСсылка(Ссылка);
КонецФункции

// См. ПользователиСлужебный.ПредставлениеСсылки
Функция ПредставлениеСсылки(Ссылка)
	Возврат ПользователиСлужебный.ПредставлениеСсылки(Ссылка);
КонецФункции

#КонецОбласти

#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли