<?xml version="1.0" encoding="windows-1251"?>
<registry>
	<node path="%root%\Ресурсы\Макросы\ЭкспортВРоспись">
		<value type="7" name="ПоддержкаЭкспортаВРоспись.abl">включить '\Библиотеки\LibRu.lib';
включить '\Библиотеки\Reports.lib';
включить '\Библиотеки\Layers.lib';
включить "\библиотеки\Versions.lib";
включить "\библиотеки\Output.lib";
включить "\библиотеки\Base.lib";
включить "\Макросы\Слои\ВспомогательныеФункции.abl";
включить '\Макросы\Слои\ПоддержкаСлойницы.abl';
включить "\Макросы\Слои\ПоддержкаВерсионности.abl";

константы
  алиасПоправки                = "РеестрПоправок.ПоправкиКЗакону.Поправки"; 
  алиасСписокПодключенийБД     = "АСБюджет.Экспорт.СписокПодключенийКБД";  
  алиасНастройкиЭкспорта       = "АСБюджет.Экспорт.ПараметрыЭкспорта";
  алиасНастройкиСинхронизации  = "АСБюджет.Экспорт.НастройкиСинхронизации"; 
  алиасТаблицаСинхронизации    = "АСБюджет.Экспорт.ТаблицаЗначенийСинхронизацииСправочников";  
  алиасТаблицаСоотвЛСиГРБС     = 'Планирование.ТаблицаСоответствияЛСиГРБС'; 
  алиасПодключенийКБазамДанных = "Платформа.БазыДанных.Подключения";
  алиасПользователейБД         = "Платформа.БазыДанных.Пользователи"; 
  
  ткРасходная    = 0;
  ткИсточниковая = 1;
  ткДоходная     = 2;
  
  нПоступление = 0;
  нВыбытие     = 1;

// Определяет год планирования по коду сборки
функция ОпределитьГодПланирования(КодСборки: Целое): Целое;
  переменные
    сп: Текст;
  начало
    сп := СоздатьТекст;
    сп.РазделенноеЗначение := ПолучитьКонтекстСборкиПоКодуСборки(КодСборки);
    Если сп.ЗначениеПараметра('ГодПланирования') = '' тогда
      ВозбудитьОшибку(Формат('В контексте сборки "%s" не указан параметр "год планирования"', Версионность.ПолучитьОписаниеСборки(КодСборки).Примечание));
    результат := СтрокаВЦелое(сп.ЗначениеПараметра('ГодПланирования'));  
  конец;

// Отбрасывает нули, стоящие спереди у строкового значения классификатора
функция ОтброситьНулиВНачале(Значение: строка): строка;
начало
  результат := ЦелоеВСтроку(СтрокаВЦелое(Значение));
конец;

// Количество значений в списке, заданным строкой через "|"
функция ПолучитьКоличествоЗаписей(ЗначенияВСтроку: строка): целое;
переменные
  СписокЗначений: текст;
начало
  СписокЗначений := СоздатьТекст;
  результат := 0;
  попытка
    СписокЗначений.РазделенноеЗначение("|") := ЗначенияВСтроку;
    результат := СписокЗначений.Количество;
  обязательно
    УдалитьОбъект(СписокЗначений);
  конец;
конец; 

функция ПреобразоватьДатуВЦелое(Дата: Целое): Целое;
переменные
  вр: целое;
начало
  результат := 0;
  вр := Дата цел 1000000;
  результат := вр;

  вр := (Дата ост 1000000) цел 10000;
  результат := результат + вр * 100;

  вр := Дата ост 10000;
  результат := результат + вр * 10000;
конец;

// Делает то же, что и стандартная функция, только не переустанавливая свойство IndexFieldNames 
// При этом предполагается, что данные уже отсортированы по этому полю!
функция ПолучитьСписокЗначенийПоляБезСортировки(сс: СтатическиеДанные; ИмяПоля, Разделитель: строка): строка;
переменные
  пп: Строка;
начало
  результат := '';
  пп := '';
  сс.DisableControls; 
  сс.ВНачало;
  попытка
    пока не сс.ВКонце делать
    начало
      если (пп &lt;&gt; сс.ПолеПоИмени(ИмяПоля).КакСтрока) тогда
      начало 
        результат := результат + сс.ПолеПоИмени(ИмяПоля).КакСтрока + Разделитель;
        пп := сс.ПолеПоИмени(ИмяПоля).КакСтрока; 
      конец;   
      сс.Следующая;
    конец;
    если (результат &lt;&gt; '') тогда результат := Подстрока(результат, 1, Длина(результат) - Длина(Разделитель));
  обязательно
    сс.EnableControls;
  конец;  
конец;

// Комментарий
функция ЭтоЦелое(Значение: строка): целое;
переменные
  инд: целое;
начало
  результат := да;
  от инд := 1 до Длина(Значение) делать
  начало
    если (Значение[инд] &lt; '0') или (Значение[инд] &gt; '9') тогда
      результат := нет;
  конец;
конец;


// Комментарий
функция МожноЗаполнятьИД(ИмяПоля, СтарыйИД, НовыйИД: строка): целое;
начало
  результат := да;
  если ИмяПоля = "ID" тогда
  начало    
    результат := нет;
    если (СтарыйИД = "") тогда
      результат := ЭтоЦелое(НовыйИД);
  конец;
конец;
  
  
//***************************************************************************************
//ОТКРЫТИЕ СЛОЕВ 

// Заменяет имя внешней БД в описании слоя
функция ПроставитьИмяБДВОписанииСлоя(Слой: ILayer; Подключение: строка);
переменные
  ОписаниеСлоя: ILayerDescription;
  ссОписаниеСлоя: СтатическиеДанные;
  ИмяВБД: Строка;
начало 
  ОписаниеСлоя := Слой.Description;
  ИмяВБД := ПолучитьИмяБДСлоя(ОписаниеСлоя);
  Если ИмяВБД &lt;&gt; '' тогда
  начало
    ссОписаниеСлоя := ОписаниеСлоя.Data;                               
    ссОписаниеСлоя.Поле('TableName').КакСтрока := Подключение + '.' + ПолучитьИмяТаблицыСлоя(ОписаниеСлоя);
  конец;
конец;  

// Создает и открывает слой с заданным номером сборки и именем внешней БД
функция СоздатьИОткрытьСлойПоСборке(Алиас : строка; НомерСборки : целое; Подключение: строка) : ILayer;
переменные
  Парам : Ivariables;
начало
  результат := ПолучитьМенеджерСлоев.CreateLayerByAlias(Алиас);
  ПроставитьИмяБДВОписанииСлоя(результат, Подключение);
  Парам := CreateVariables;
  Парам.Values("$Version.Сборка") := НомерСборки;
  //для возможности передачи имени подключения источникам запоминаем его в контекстных параметрах слоя
  Парам.Values("ИмяПодключения") := Подключение;
  //!!! нужно ли ограничивать по состоянию?
  Парам.Значение("$Layer.Сотояние") := 1;
  результат.SelectData(Парам);
конец; 


//***************************************************************************************
//РАБОТА С БАЗОЙ ДАННЫХ  

// Формирует строку подключения к внешней базе для использования в операциях открытия/закрытия транзакций
// и функции СоединитьБД
функция СформироватьАлиасБД(ИмяБазы: строка): строка;
переменные
  СлойБД, СлойПользователей: ILayer;
  ДанныеБД, ДанныеПользователей: СтатическиеДанные;
  ПараметрыБД: Текст;
  ИмяДрайвера, ИмяСервера, Схема, Логин, Пароль: строка;
начало
  результат := "";
  //путь к базе получаем из слоя "Базы данных"
  СлойБД := ПолучитьМенеджерСлоев.CreateLayerByAlias(АлиасПодключенийКБазамДанных);
  СлойБД.SelectData(nil);
  ДанныеБД := СлойБД.LayerData;
  ДанныеБД.Локализовать("ИмяБазыДанных", ИмяБазы, 0);
  ИмяДрайвера := ДанныеБД.ПолеПоИмени("ИмяДрайвера").КакСтрока;  
  ПараметрыБД := СоздатьТекст;
  попытка
    ПараметрыБД.РазделенноеЗначение := ДанныеБД.ПолеПоИмени("ПараметрыБД").КакСтрока;
    ИмяСервера := ПараметрыБД.ЗначениеПараметра("AliasName");
    Схема := '';
    если ДанныеБД.ПолеПоИмени("ТипБазыДанных").КакСтрока = "Oracle" тогда
      Схема := 'schema='+ПараметрыБД.ЗначениеПараметра("Schema"); 
  обязательно
    УдалитьОбъект(ПараметрыБД);
  конец;
  результат := Формат("DatabaseName=%s"#13#10"DriverName=%s"#13#10"SERVER NAME=%s"#13#10"%s",
                                                    ИмяБазы, ИмяДрайвера, ИмяСервера, Схема);
  
  //логин и пароль хранятся в слое "Пользователи баз данных"
  СлойПользователей := ПолучитьМенеджерСлоев.CreateLayerByAlias(АлиасПользователейБД);
  СлойПользователей.SelectData(nil);
  ДанныеПользователей := СлойПользователей.LayerData;   
  ДанныеПользователей.Фильтр := "ИмяПользователяЛокальное='"+ТекущийПользователь+"'";
  если не ДанныеПользователей.Локализовать("ИмяБазыДанных", ИмяБазы, 0) тогда
    ВызватьОшибку("Не найдены параметры подключения к базе данных с именем '" + ИмяБазы +"' !");  
  Логин := ДанныеПользователей.ПолеПоИмени("ИмяПользователяУдаленное").КакСтрока;
  Пароль := ДанныеПользователей.ПолеПоИмени("ПарольУдаленный").КакСтрока;
  результат := Формат("%s"#13#10"USER NAME=%s"#13#10"PASSWORD=%s", результат, Логин, Пароль);
конец;

функция ПолучитьИмяДрайвераБД(ИмяБазы: строка): строка;
переменные
  ПараметрыПодключения: Текст;
начало
  ПараметрыПодключения := СоздатьТекст;
  попытка
    ПараметрыПодключения.РазделенноеЗначение := ИмяБазы;
    результат := ПараметрыПодключения.ЗначениеПараметра("DriverName");
  обязательно
    УдалитьОбъект(ПараметрыПодключения);
  конец;
  если результат = "" тогда
    ВызватьОшибку("Не задано имя драйвера в строке подключения к БД исполнения");
конец;

// Функции работы с генератором G_Shared внешней базы
функция СоздатьГенератор(ИмяБазы: строка): СтатическиеДанные;
начало
  результат := СоздатьСтатическиеДанные;
  результат.СоединитьБД(ИмяБазы);
  выбрать ПолучитьИмяДрайвераБД(ИмяБазы) из
    "ORACLE": результат.Запрос := '[PumpData]{select G_Shared.NextVal from Dual}';
    "INTRBASE": результат.Запрос := '[PumpData]{select Gen_Id(G_Shared, 1) NextVal from Single}'
    иначе ВызватьОшибку("Неизвестный тип драйвера БД исполнения");
  конец;
конец;

функция ПолучитьНовоеЗначениеГенератора(Данные: СтатическиеДанные): целое;
начало
  результат := 0;   
  Данные.Reopen;
  если Данные.ЧислоЗаписей &lt;&gt; 1 тогда
    ВызватьОшибку(Формат("Ошибка получения значения генератора для базы исполнения: получено %d значений", Данные.ЧислоЗаписей));
  Данные.First;
  результат := Данные.Поле("NextVal").КакЦелое;
конец;  


// Удаляет записи из таблицы внешней БД
функция УдалитьЗаписиИзТаблицыБД(Данные: СтатическиеДанные; Подключение, Таблица, УсловиеВыборки: строка);
начало
  Данные.СоединитьБД(Подключение);
  Данные.ДобавитьЦелоеПоле("ID");
  Данные.Запрос := Формат('[PumpData]{Select ID from %s where %s}', Таблица, УсловиеВыборки);   
  Данные.Открыть;  
  Данные.Запрос := Формат('[DeleteData]{Delete from %s where ID=@ID}', Таблица);
  Данные.First;
  пока не Данные.Eof делать
    Данные.Delete;  
  Данные.ApplyUpdates;
конец;


//***************************************************************************************
//РАБОТА С КОЛЛЕКЦИЕЙ ПАРАМЕТРОВ

// Вызывает ошибку в случае отсутствия параметра в коллекции 
функция ПроверитьНаличиеПараметра(ИмяПараметра, ТекстОшибки: строка; ПараметрыМакроса: IVariables);
переменные
  ПараметрСуществует: целое;
начало
  ПараметрСуществует := нет;
  если ПараметрыМакроса.ПараметрСуществует(ИмяПараметра) тогда
    если ПараметрыМакроса.Значение(ИмяПараметра) &lt;&gt; '' тогда
      ПараметрСуществует := да;
  если не ПараметрСуществует тогда
    ВызватьОшибку(ТекстОшибки);
конец; 

// Заполняет коллекцию параметров из настроек параметров экспорта
функция ЗаполнитьКоллекциюПараметров(ПараметрыМакроса: IVariables; ДанныеНастроек: СтатическиеДанные);
переменные
  пИмя, пЗначение, пЦелое, пСтроковое, пЛогическое: поле;  
начало
  пИмя := ДанныеНастроек.ПолеПоИмени("ИмяПараметра");
  пЗначение := ДанныеНастроек.ПолеПоИмени("ТипЗначения");
  пЦелое := ДанныеНастроек.ПолеПоИмени("ЗначениеЦелое");
  пСтроковое := ДанныеНастроек.ПолеПоИмени("ЗначениеСтроковое");
  пЛогическое := ДанныеНастроек.ПолеПоИмени("ЗначениеЛогическое");
  
  ДанныеНастроек.ВНачало;
  пока не ДанныеНастроек.ВКонце делать
    начало
      выбрать пЗначение.КакЦелое из
        1, 5: ПараметрыМакроса.Значение(пИмя.КакСтрока) := пЦелое.КакЦелое; 
        2: ПараметрыМакроса.Значение(пИмя.КакСтрока) := пСтроковое.КакСтрока; 
        3: ПараметрыМакроса.Значение(пИмя.КакСтрока) := пЛогическое.КакФлаг; 
        6: ПараметрыМакроса.Значение(пИмя.КакСтрока) := ПреобразоватьДатуВЦелое(пЦелое.КакЦелое); 
      конец;
      ДанныеНастроек.Следующая;
    конец;   
конец;


//***************************************************************************************
//РАБОТА С МАППИНГАМИ И СПИСКАМИ ПАРАМЕТРОВ

// Вырезает ключи из маппинга полей и формирует строку ключей через ","
функция ПолучитьКлючиПоМаппингу(Маппинг: строка): строка;
переменные
 МаппингТекст: Текст;
 Индекс: целое;
 Параметр: строка;    
начало                   
  МаппингТекст := СоздатьТекст;
  попытка
    МаппингТекст.РазделенноеЗначение(";") := Маппинг;
    результат := "";
    от Индекс := 0 до МаппингТекст.Количество - 1 делать
     начало
      Параметр := МаппингТекст.ИмяПараметра(Индекс);
      если результат = ""
        тогда результат := Параметр
        иначе результат := результат + "," + Параметр;
     конец; 
  обязательно
    УдалитьОбъект(МаппингТекст);
  конец;
конец;

// Складывает маппинги, взяв все параметры из обоих маппингов
функция СложитьМаппингиПоПринципуИли(Маппинг1, Маппинг2: строка): строка;
переменные
  Текст1, Текст2: Текст;
  Индекс: целое;
  Параметр: строка;
начало
  результат := "";
  попытка                   
    Текст1 := СоздатьТекст;
    Текст1.РазделенноеЗначение(";") := Маппинг1;
    
    Текст2 := СоздатьТекст;
    Текст2.РазделенноеЗначение(";") := Маппинг2;
    
    от Индекс := 0 до Текст2.Количество - 1 делать
      начало
        Параметр := Текст2.ИмяПараметра(Индекс);
        если Текст1.Поиск(Параметр) = -1 тогда
          Текст1.ЗначениеПараметра(Параметр) := Текст2.ЗначениеПараметра(Параметр);
      конец;
    результат := Текст1.РазделенноеЗначение(";");
  обязательно 
    УдалитьОбъект(Текст1, Текст2);
  конец; 
конец;

// Складывает списки, взяв все параметры из обоих списков
функция СложитьСтрокиПоПринципуИли(Строка1, Строка2: строка): строка;
переменные
  Текст1, Текст2: Текст;
  Индекс: целое;
  Параметр: строка;
начало
  результат := "";
  Текст1 := СоздатьТекст;
  Текст2 := СоздатьТекст;
  попытка                   
    Текст1.РазделенноеЗначение := Строка1;    
    Текст2.РазделенноеЗначение := Строка2;
    
    от Индекс := 0 до Текст2.Количество - 1 делать
      начало
        Параметр := Текст2.Стр(Индекс);
        если Текст1.Поиск(Параметр) = -1 тогда
          Текст1.Добавить(Параметр);
      конец;
    результат := Текст1.РазделенноеЗначение;
  обязательно 
    УдалитьОбъект(Текст1, Текст2);
  конец; 
конец;

// Извлекает из списка параметры, встречающиеся в обоих списках, исключая все остальные
функция СложитьСтрокиПоПринципуИ(Строка1, Строка2: строка): строка;
переменные
  Текст1, Текст2, Текст3: Текст;
  Индекс: целое;
  Параметр: строка;
начало
  результат := "";
  Текст1 := СоздатьТекст;
  Текст2 := СоздатьТекст;
  Текст3 := СоздатьТекст;
  попытка                      
    Текст1.РазделенноеЗначение := Строка1;
    Текст2.РазделенноеЗначение := Строка2;
    
    от Индекс := 0 до Текст1.Количество - 1 делать
      начало
        Параметр := Текст1.Стр(Индекс);
        если Текст2.Поиск(Параметр) &gt; -1 тогда
          Текст3.Добавить(Параметр);
      конец;
    результат := Текст3.РазделенноеЗначение;
  обязательно 
    УдалитьОбъект(Текст1, Текст2, Текст3);
  конец; 
конец;

// Подставляем агрегатную функцию sum в маппинг сумм 
функция СформироватьМаппингСумм(МаппингСумм: строка): строка;
начало
  результат := ЗаменитьСтроку(МаппингСумм, "=", "=sum(");
  результат := ЗаменитьСтроку(результат, ";", ");") + ")";
конец;


//***************************************************************************************
//РАБОТА С МАССИВОМ ЗНАЧЕНИЙ

// Создание массива значений
функция СоздатьМассив(МассивЗначений: переменная; КоличествоЗначений: целое);
начало
  если не МассивЗначений.Пусто тогда
    МассивЗначений.Очистить;
  МассивЗначений.СоздатьМассив(varVariant, 0, КоличествоЗначений)
конец;

// Заполнение массива значениями из данных по списку имен полей
функция ПолучитьМассивЗначенийКлючей(МассивЗначений: переменная; СписокКлючей: Текст; Данные: СтатическиеДанные);
переменные
  Индекс, КоличествоЗначений: целое;
начало
  КоличествоЗначений := СписокКлючей.Количество - 1;
  СоздатьМассив(МассивЗначений, КоличествоЗначений);
  от Индекс := 0 до КоличествоЗначений делать   
    МассивЗначений.КакСтрока(Индекс) := Данные.Поле(СписокКлючей.Стр(Индекс)).КакСтрока;
конец;

// Функции получения значений вышестоящего уровня, заданных маской уровня
функция ПолучитьЗначениеВышестоящегоУровня(МаскаУровня: строка; Значение: целое): целое;
переменные
  Маска, СтрокаНулей: строка;
  инд, ЧислоРазрядов: целое;
начало
  результат := 0;
  Маска := ЗаменитьПодстроку(МаскаУровня, ".", "", да);
  СтрокаНулей := "";
  от инд := 1 до Длина(Маска) делать
  начало
    если Маска[инд] = "0" тогда
      СтрокаНулей := СтрокаНулей + "0";
  конец;
  ЧислоРазрядов := СтрокаВЦелое("1"+СтрокаНулей);
  результат := (Значение цел ЧислоРазрядов) * ЧислоРазрядов;
конец;

// Комментарий
функция ПолучитьУровеньОбобщения(Маска: строка): целое;
переменные
  инд: целое;
начало
  результат := 0;
  инд := 1;
  пока (Маска[инд] &lt;&gt; '0') и (инд &lt; Длина(Маска)) делать
  начало
    если Маска[инд] = '.' тогда
      результат := результат + 1;
    инд := инд + 1;
  конец;
конец;


функция ПолучитьМассивЗначенийВышестоящегоУровня(Маска, МаскаУровня: строка; МассивЗначений, МассивЗначенийУровня: переменная);
переменные
  МаскаБуф, МаскаУровняБуф: строка;
  инд, НомерРазделителя: целое;
  СписокМасок, СписокМасокУровня: Текст;
начало
  МаскаБуф := Маска;
  МаскаУровняБуф := МаскаУровня;  
  СписокМасок := СоздатьТекст;
  СписокМасокУровня := СоздатьТекст;
  попытка
    пока МаскаБуф &lt;&gt; '' делать
    начало
      НомерРазделителя := Позиция(";", МаскаБуф);
      если НомерРазделителя &lt; 1 тогда
        НомерРазделителя := Длина(МаскаБуф) + 1;
      СписокМасок.Добавить(Подстрока(МаскаБуф, 1, НомерРазделителя - 1));
      СписокМасокУровня.Добавить(Подстрока(МаскаУровняБуф, 1, НомерРазделителя - 1));
      МаскаБуф := Подстрока(МаскаБуф, НомерРазделителя + 1, Длина(МаскаБуф) - НомерРазделителя);
      МаскаУровняБуф := Подстрока(МаскаУровняБуф, НомерРазделителя, Длина(МаскаУровняБуф) - НомерРазделителя + 1);
    конец;
    СоздатьМассив(МассивЗначенийУровня, СписокМасок.Количество-1);
    от инд := 0 до СписокМасок.Количество-1 делать
      МассивЗначенийУровня.КакСтрока(инд) := КлассификаторОпустить(МассивЗначений.КакСтрока(инд), ПолучитьУровеньОбобщения(СписокМасокУровня.Стр(инд)), СписокМасок.Стр(инд));
  обязательно
    УдалитьОбъект(СписокМасок, СписокМасокУровня);
  конец;
конец;

// Записывает значения массива строкой, отформатировав по маске
функция ФорматироватьКлассификаторПоМаске(МассивЗначений: переменная; Маска: строка): строка;
переменные
  СписокМасок, СписокЗначений: Текст;
  Индекс: целое;
начало
  результат := "";
  СписокМасок := СоздатьТекст;
  СписокЗначений := СоздатьТекст;
  попытка
    СписокМасок.РазделенноеЗначение(";") := Маска; 
    от Индекс := 0 до СписокМасок.Количество-1 делать
      СписокЗначений.Добавить(ФорматироватьКлассификатор(МассивЗначений.КакСтрока(Индекс), СписокМасок.Стр(Индекс)));
    результат := ЗаменитьПодстроку(СписокЗначений.РазделенноеЗначение, ",", ".", да);
  обязательно
    УдалитьОбъект(СписокМасок, СписокЗначений);
  конец;
конец;

// Форматирует значения в массиве по маске
функция ФорматироватьЗначенияВМассиве(МассивЗначений: переменная; Маска: строка);
переменные
  СписокМасок: Текст;
  Индекс: целое;
начало
  СписокМасок := СоздатьТекст;
  попытка
    СписокМасок.РазделенноеЗначение(";") := Маска;        
    от Индекс := 0 до СписокМасок.Количество-1 делать
      МассивЗначений.КакСтрока(Индекс) := ФорматироватьКлассификатор(МассивЗначений.КакСтрока(Индекс), ЗаменитьПодстроку(СписокМасок.Стр(Индекс), ".", "", да));
  обязательно
    УдалитьОбъект(СписокМасок);
  конец;
конец;


//***************************************************************************************
//РАБОТА С ЛОГОМ ОШИБОК

функция ОчиститьЛог;
переменные
  Лог: ОкноВывода;
начало
  Лог := OutPut;
  Лог.Очистить;
конец;

функция ВывестиВЛог(ЛогТекст: Текст);
переменные
  Лог: ОкноВывода;
  счетчик : целое;
начало
  если ЛогТекст.Количество &gt; 0  тогда 
  начало
    Лог := OutPut;
    от счетчик := 0 до ЛогТекст.Количество - 1 делать
      Лог.Вывести(ЛогТекст.Стр(счетчик));
  конец;
конец;

функция ДобавитьВЛог(ТекстСообщения: строка; ЛогТекст: Текст);
начало
  если ЛогТекст.Поиск(ТекстСообщения) = -1 тогда
    ЛогТекст.Добавить(ТекстСообщения);
конец;


//***************************************************************************************
//СИНХРОНИЗАЦИЯ СПРАВОЧНИКОВ ПЛАНИРОВАНИЯ И ИСПОЛНЕНИЯ

функция НайтиРазличияВСправочниках(ВходныеДанные, ВыходныеДанные: СтатическиеДанные; МаппингПолей: строка): целое;
переменные
  СписокПолей : Текст;
  Индекс : целое;
  ИмяПоля : строка;
начало
  результат := 0;
  СписокПолей := СоздатьТекст;
  попытка
    СписокПолей.РазделенноеЗначение(";") := МаппингПолей;  
    от Индекс := 0 до СписокПолей.Количество - 1 делать
      начало
        ИмяПоля := СписокПолей.ИмяПараметра(Индекс);
        если ВыходныеДанные.ПолеПоИмени(ИмяПоля).КакСтрока &lt;&gt; ВходныеДанные.ПолеПоИмени(СписокПолей.ЗначениеПараметра(ИмяПоля)).КакСтрока 
          тогда результат := 1;
      конец;
  обязательно
    УдалитьОбъект(СписокПолей);
  конец;
конец;

// Добавляет строку с различающимися значениями справочников в таблицу синхронизации
функция ДобавитьЗаписьВТаблицуСинхронизации(МассивЗначений: переменная; Справочник: строка; НастройкиСинхронизации, ДанныеТаблицыСинхронизации: СтатическиеДанные; КэшСлоев: IVariables);
переменные
  СправочникИст, СправочникПрием: ILayer;
  ДанныеИсточника, ДанныеПриемника: СтатическиеДанные;
  АлиасИсточника, КлючИст, КлючПрием, Маска, 
  МаппингНеобязатПолей, ИмяИст, ИмяПрием, Код: строка;
  ID: целое;
начало
  АлиасИсточника := НастройкиСинхронизации.Поле("Источник").КакСтрока;
  СправочникИст := КэшСлоев.Значение(АлиасИсточника);
  ДанныеИсточника := СправочникИст.LayerData;
  СправочникПрием := КэшСлоев.Значение(НастройкиСинхронизации.Поле("Приемник").КакСтрока);
  ДанныеПриемника := СправочникПрием.LayerData;
  КлючИст := НастройкиСинхронизации.Поле("КлючИсточника").КакСтрока;
  КлючПрием := НастройкиСинхронизации.Поле("КлючПриемника").КакСтрока;
  Маска := НастройкиСинхронизации.Поле("Маска").КакСтрока;
  МаппингНеобязатПолей := НастройкиСинхронизации.Поле("МаппингНеобязатПараметров").КакСтрока;
  ИмяИст := НастройкиСинхронизации.Поле("ИмяИсточника").КакСтрока;
  ИмяПрием := НастройкиСинхронизации.Поле("ИмяПриемника").КакСтрока;
  
  // для синхронизации КЦС, чтобы значения ID потом совпадали
  // не очень хорошо, потому что зависит от реализации Locate: на данный момент
  // курсор устанавливается на первую запись, удовлетворяющую условиям поиска
  ДанныеПриемника.IndexFieldNames := КлючПрием+';ID';

  Код := ФорматироватьКлассификаторПоМаске(МассивЗначений, Маска);
  ФорматироватьЗначенияВМассиве(МассивЗначений, Маска);
  если не ДанныеИсточника.Locate(КлючИст, МассивЗначений, 0) тогда 
    ВозбудитьОшибку("Код "+Код+" не был найден в слое "+АлиасИсточника);
  если ДанныеПриемника.Locate(КлючПрием, МассивЗначений, 0) тогда
  начало
    ID := ДанныеПриемника.Поле("ID").КакЦелое;
    если (не ДанныеТаблицыСинхронизации.Locate("ИД; Справочник", МассивИз(ID, Справочник), 0)) и 
      НайтиРазличияВСправочниках(ДанныеИсточника, ДанныеПриемника, МаппингНеобязатПолей) тогда
    начало
      ДанныеТаблицыСинхронизации.Append;
      ДанныеТаблицыСинхронизации.ПолеПоИмени("Справочник").КакСтрока := Справочник;
      ДанныеТаблицыСинхронизации.ПолеПоИмени("ИД").КакЦелое := ID;
      ДанныеТаблицыСинхронизации.ПолеПоИмени("Код").КакСтрока := Код;
      ДанныеТаблицыСинхронизации.ПолеПоИмени("Имя_Планирование").КакСтрока := ДанныеИсточника.ПолеПоИмени(ИмяИст).КакСтрока;
      ДанныеТаблицыСинхронизации.ПолеПоИмени("Имя_Исполнение").КакСтрока := ДанныеПриемника.ПолеПоИмени(ИмяПрием).КакСтрока;
      ДанныеТаблицыСинхронизации.Post;
    конец;
  конец;
конец;

// Создает слои справочников планирования и исполнения и помещает их в кэш
функция СоздатьИПоместитьВКэшСправочники(КэшСлоев: IVariables; НастройкиСинхронизации: СтатическиеДанные; НомерСборки: целое; Подключение: строка);
переменные
  СправочникИст, СправочникПрием: ILayer;
  пАлиасИст, пАлиасПрием: поле;
начало
  пАлиасИст := НастройкиСинхронизации.Поле("Источник");
  пАлиасПрием := НастройкиСинхронизации.Поле("Приемник");
  
  НастройкиСинхронизации.ВНачало;
  пока не НастройкиСинхронизации.ВКонце делать
  начало
    если пАлиасИст.КакСтрока &lt;&gt; '' тогда
    начало
      СправочникИст := СоздатьИОткрытьСлойПоСборке(пАлиасИст.КакСтрока, НомерСборки, Подключение);
      КэшСлоев.Значение(пАлиасИст.КакСтрока) := СправочникИст;
    конец;
    если пАлиасПрием.КакСтрока &lt;&gt; '' тогда
    начало
      СправочникПрием := СоздатьИОткрытьСлойПоСборке(пАлиасПрием.КакСтрока, 0, Подключение);
      КэшСлоев.Значение(пАлиасПрием.КакСтрока) := СправочникПрием;
    конец;
    НастройкиСинхронизации.Следующая;
  конец;
конец;

// Выводит на экран таблицу синхронизации
функция ПоказатьТаблицуСинхронизации(ТаблицаСинхронизации: ILayer);
переменные
  ДанныеТаблицыСинхронизации: СтатическиеДанные;
  Парам: IVariables;
начало
  ДанныеТаблицыСинхронизации := ТаблицаСинхронизации.LayerData;
  если ДанныеТаблицыСинхронизации.ЧислоЗаписей &gt; 0 тогда начало
    ДанныеТаблицыСинхронизации.ApplyUpdates;
    Парам := СоздатьКоллекцию;
    Парам.Значение("ReadOnly") := 0;
    ТаблицаСинхронизации.EditMode := 2;
    ТаблицаСинхронизации.ShowModal('', Парам);
  конец;
конец;

функция ОбновитьЗначенияПолей(МаппингПолей: строка; ДанныеИст, ДанныеПрием: СтатическиеДанные): целое;
переменные
  СписокПолей: Текст;
  Индекс: целое;
  ПолеИст, ПолеПрием: строка;
начало
  Результат := 0;
  
  СписокПолей := СоздатьТекст;
  попытка
    СписокПолей.РазделенноеЗначение := МаппингПолей;
    ДанныеПрием.Редактировать;
    от Индекс := 0 до СписокПолей.Количество - 1 делать
    начало 
      ПолеПрием := СписокПолей.ИмяПараметра(Индекс);   
      ПолеИст := СписокПолей.ЗначениеПараметра(ПолеПрием);
      если ДанныеПрием.ПолеПоИмени(ПолеПрием).КакСтрока &lt;&gt; ДанныеИст.ПолеПоИмени(ПолеИст).КакСтрока тогда
      начало
        ДанныеПрием.ПолеПоИмени(ПолеПрием).КакСтрока := ДанныеИст.ПолеПоИмени(ПолеИст).КакСтрока;
        Результат := 1;
      конец;
    конец;
    ДанныеПрием.Сохранить;
  обязательно
    УдалитьОбъект(СписокПолей);
  конец;
конец;

// Заполнение ключевых полей внешнего справочника при вставке записи
функция ЗаполнитьКлючевыеПоля(Данные: СтатическиеДанные; Поля: строка; МассивЗначений: переменная);
переменные
  СписокПолей : Текст;
  Индекс : целое;
начало
  СписокПолей := СоздатьТекст;
  попытка
    СписокПолей.РазделенноеЗначение(";") := Поля;   
    от Индекс := 0 до СписокПолей.Количество - 1 делать
      Данные.Поле(СписокПолей.Стр(Индекс)).КакСтрока := МассивЗначений.КакСтрока(Индекс);
  обязательно
    УдалитьОбъект(СписокПолей);
  конец;
конец;


// Заполнение неключевых полей внешнего справочника из планирования по маппингу
функция ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные: СтатическиеДанные; МаппингПолей: строка);
переменные
  СписокПолей : Текст;
  Индекс : целое;
  ИмяПоля, СтароеЗначение, НовоеЗначение : строка;
начало
  СписокПолей := СоздатьТекст;
  попытка
    СписокПолей.РазделенноеЗначение(";") := МаппингПолей;  
    от Индекс := 0 до СписокПолей.Количество - 1 делать
      начало
        ИмяПоля := СписокПолей.ИмяПараметра(Индекс);
        СтароеЗначение := ВыходныеДанные.ПолеПоИмени(ИмяПоля).КакСтрока;
        НовоеЗначение := ВходныеДанные.ПолеПоИмени(СписокПолей.ЗначениеПараметра(ИмяПоля)).КакСтрока;
        если МожноЗаполнятьИД(ИмяПоля, СтароеЗначение, НовоеЗначение) тогда
          если СтароеЗначение &lt;&gt; НовоеЗначение 
            тогда ВыходныеДанные.ПолеПоИмени(ИмяПоля).КакСтрока := НовоеЗначение;
      конец;
  обязательно
    УдалитьОбъект(СписокПолей);
  конец;
конец;

// Проверка наличия значения во внешнем справочнике, вставка записей, заполнение доп. полей
функция ПроверитьКлассификаторыСтандартно(МассивЗначений: переменная; НастройкиСинхронизации: СтатическиеДанные; КэшСлоев: IVariables; Генератор: СтатическиеДанные): целое;
переменные
  Источник, Приемник, ТаблицаСинхронизации: ILayer;
  ВходныеДанные, ВыходныеДанные, ДанныеТаблицыСинхронизации: СтатическиеДанные;
  МаппингПолей, МаппингНеобязатПолей, ПолеКодИст, ПолеКодПрием : строка;
начало
  результат := 0;
  // получаем датасеты обоих слоев
  Источник := КэшСлоев.Значение(НастройкиСинхронизации.Поле("Источник").КакСтрока);
  ВходныеДанные := Источник.LayerData;
  Приемник := КэшСлоев.Значение(НастройкиСинхронизации.Поле("Приемник").КакСтрока);
  ВыходныеДанные := Приемник.LayerData;
  МаппингПолей := НастройкиСинхронизации.Поле("МаппингПараметров").КакСтрока;
  МаппингНеобязатПолей := НастройкиСинхронизации.Поле("МаппингНеобязатПараметров").КакСтрока;
  ПолеКодИст := НастройкиСинхронизации.Поле("КлючИсточника").КакСтрока;
  ПолеКодПрием := НастройкиСинхронизации.Поле("КлючПриемника").КакСтрока;
  
  // получаем из слоя-источника описание нужного классификатора
  если ВходныеДанные.Locate(ПолеКодИст, МассивЗначений, 0) тогда
  начало 
    // ищем данный классификатор в слое-приемнике
    // возможно перед локейтом надо оставлять закладки, дабы сохранить исходное положение курсора (если нужно)
    если ВыходныеДанные.Locate(ПолеКодПрием, МассивЗначений, 0) тогда
    начало
      ТаблицаСинхронизации := КэшСлоев.Значение(алиасТаблицаСинхронизации);
      ДанныеТаблицыСинхронизации := ТаблицаСинхронизации.LayerData;
      // если нашли - нужно проапдейтить запись
      ВыходныеДанные.Редактировать;
      ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные, МаппингПолей);
      если ДанныеТаблицыСинхронизации.Locate("ИД; Справочник", МассивИз(ВыходныеДанные.Поле("ID").КакЦелое, НастройкиСинхронизации.Поле("Классификатор").КакСтрока), 0) 
        тогда если ДанныеТаблицыСинхронизации.ПолеПоИмени("Синхронизировать").КакЦелое = 1 
          тогда ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные, МаппингНеобязатПолей);
      ВыходныеДанные.Сохранить;   
    конец
    иначе
    начало
      // если не нашли - добавляем
      ВыходныеДанные.Вставить;
      ЗаполнитьКлючевыеПоля(ВыходныеДанные, ПолеКодПрием, МассивЗначений);
      ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные, СложитьМаппингиПоПринципуИли(МаппингПолей, МаппингНеобязатПолей));
      // в случае, если у классификатора ID должно проставляться автоматически генератором, тогда 
      // генерим ID с помощью генератора базы исполнения
      // это нужно, чтобы проставить ID классификатора в росписи
      если ВыходныеДанные.Поле("ID").Пустое тогда
        ВыходныеДанные.Поле("ID").КакЦелое := ПолучитьНовоеЗначениеГенератора(Генератор);
      ВыходныеДанные.Сохранить;  
    конец;
    //возвращаем ID записи во внешнем справочнике
    результат := ВыходныеДанные.Поле("ID").КакЦелое;
  конец
  иначе  начало
    CreateException("Код " + ФорматироватьКлассификаторПоМаске(МассивЗначений, НастройкиСинхронизации.Поле("Маска").КакСтрока) +
                     " не был найден в слое " + НастройкиСинхронизации.Поле("Источник").КакСтрока);
  конец;
конец;
 
функция ПолучитьНаправлениеДенежныхСредствПоТипуКлассификации(Данные: СтатическиеДанные): целое;
переменные
  ТипКлассификации: целое;
начало
  ТипКлассификации := ткРасходная;
  если не Данные.Поле("CLSTYPE").Пустое тогда
    ТипКлассификации := Данные.Поле("CLSTYPE").КакЦелое;

  выбрать ТипКлассификации из
    ткРасходная: Результат := нВыбытие;
    ткДоходная: Результат := нПоступление
  иначе
    ВызватьОшибку("Невозможно определить код целевых средств для типа классификации: "+ ЦелоеВСтроку(ТипКлассификации));
  конец;
конец;

// Для проверки кода целевых средств отдельная функция
// Важно, чтобы к этому моменту было заполнено поле "Тип классификации"
функция ПроверитьКЦС(МассивЗначений: переменная; НастройкиСинхронизации: СтатическиеДанные; КэшСлоев: IVariables; ДанныеПриемника: СтатическиеДанные): целое;
переменные
  Источник, Приемник, ТаблицаСинхронизации: ILayer;
  ВходныеДанные, ВыходныеДанные, ДанныеТаблицыСинхронизации, Буфер: СтатическиеДанные;
  МаппингПолей, МаппингНеобязатПолей, ПолеКодИст, ПолеКодПрием : строка;
  Вставить, ОбновитьДопПоля: целое;
  Направление: целое;
  ПолныйМаппинг: строка;
начало
  результат := 0;
  // получаем датасеты обоих слоев
  Источник := КэшСлоев.Значение(НастройкиСинхронизации.Поле("Источник").КакСтрока);
  ВходныеДанные := Источник.LayerData;
  Приемник := КэшСлоев.Значение(НастройкиСинхронизации.Поле("Приемник").КакСтрока);
  ВыходныеДанные := Приемник.LayerData;
  
  МаппингПолей := НастройкиСинхронизации.Поле("МаппингПараметров").КакСтрока;
  МаппингНеобязатПолей := НастройкиСинхронизации.Поле("МаппингНеобязатПараметров").КакСтрока;
  ПолеКодИст := НастройкиСинхронизации.Поле("КлючИсточника").КакСтрока;
  ПолеКодПрием := НастройкиСинхронизации.Поле("КлючПриемника").КакСтрока;
  ВыходныеДанные.IndexFieldNames := ПолеКодПрием+';ID';
  
  Направление := ПолучитьНаправлениеДенежныхСредствПоТипуКлассификации(ДанныеПриемника);
  
  если ВходныеДанные.Locate(ПолеКодИст, МассивЗначений, 0) тогда
  начало 
    Вставить := да;
    ОбновитьДопПоля := да;
    Буфер := СоздатьСтатическиеДанные(ВыходныеДанные);
    Буфер.Открыть;
    //фильтруем данные приемника по коду
    ВыходныеДанные.SetScope(МассивЗначений);
    попытка
      если ВыходныеДанные.ЧислоЗаписей &gt; 0 тогда
      начало
        ТаблицаСинхронизации := КэшСлоев.Значение(алиасТаблицаСинхронизации);
        ДанныеТаблицыСинхронизации := ТаблицаСинхронизации.LayerData;
        
        ВыходныеДанные.ВНачало;
        //копируем значения полей в буфер
        Буфер.СкопироватьЗапись(нет, ВыходныеДанные);
        
        //обязательные поля обновляем в любом случае, необязательные - только если поставлена галка 
        //в таблице синхронизации 
        ПолныйМаппинг := МаппингПолей;
        если ДанныеТаблицыСинхронизации.Locate("ИД; Справочник", МассивИз(ВыходныеДанные.Поле('ID').КакЦелое, НастройкиСинхронизации.Поле("Классификатор").КакСтрока), 1) 
          тогда если ДанныеТаблицыСинхронизации.ПолеПоИмени("Синхронизировать").КакЦелое = 1 
            тогда ПолныйМаппинг := СложитьМаппингиПоПринципуИли(ПолныйМаппинг, МаппингНеобязатПолей)
            иначе ОбновитьДопПоля := нет;
     
        //если записи различаются хотя бы одним полем, меняем значения у всех записей с таким кодом
        если ОбновитьЗначенияПолей(ПолныйМаппинг, ВходныеДанные, ВыходныеДанные) &lt;&gt; 0      тогда
        начало
          ВыходныеДанные.Следующая;
          пока не ВыходныеДанные.ВКонце делать
          начало
            ОбновитьЗначенияПолей(ПолныйМаппинг, ВходныеДанные, ВыходныеДанные);
            ВыходныеДанные.Следующая;
          конец;
        конец;
        //если запись отсутствует в справочнике, добавляем ее   
        //может получиться так, что эта запись в справочнике окажется лишней
        если Направление = 1 тогда                 
          Вставить := не ВыходныеДанные.Locate("TargetMeansSign;TransferKVSR;TransferKFSR;TransferKVR;TransferKCSR;TransferKESR", МассивИз(Направление, 0,0,0,0,0), 0)
        иначе 
          Вставить := не ВыходныеДанные.Locate("TargetMeansSign;ReceiveKD", МассивИз(Направление, 0), 0);
      конец;
      
      //если справочник не содержит записей с таким кодом, добавляем одну запись
      если Вставить тогда
      начало
        ВыходныеДанные.Вставить;
        //заполняем поля новой записи, чтобы все записи с одинаковым кодом были идентичны 
        если Буфер.ЧислоЗаписей = 1 тогда
          КопироватьЗначенияПолейПоМаппингу(ВыходныеДанные, Буфер, "Code=Code,Name=Name,TargetCls=TargetCls,BudgetRef=BudgetRef");
        ЗаполнитьКлючевыеПоля(ВыходныеДанные, ПолеКодПрием, МассивЗначений);
        ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные, МаппингПолей);
        если ОбновитьДопПоля тогда
          ЗаполнитьДополнительныеПоля(ВходныеДанные, ВыходныеДанные, МаппингНеобязатПолей);
        ВыходныеДанные.ПолеПоИмени("TargetMeansSign").КакЦелое := Направление;
        ВыходныеДанные.Сохранить;  
      конец;
      
      Буфер.Очистить;
      //так как ID заполняется только во время операции Commit, временно проставляем значение кода в форму
      результат := ВыходныеДанные.Поле("CODE").КакЦелое;
      
    обязательно
      ВыходныеДанные.CancelRange;
    конец;    
  конец
  иначе  начало
    CreateException("Код " + ФорматироватьКлассификаторПоМаске(МассивЗначений, НастройкиСинхронизации.Поле("Маска").КакСтрока) +
                     " не был найден в слое " + НастройкиСинхронизации.Поле("Источник").КакСтрока);
  конец;
конец;

функция ПроверитьКлассификаторы(МассивЗначений: переменная; НастройкиСинхронизации: СтатическиеДанные; КэшСлоев: IVariables; Генератор: СтатическиеДанные; ДанныеПриемника: СтатическиеДанные): целое;
переменные
  ПолеИст: строка;
начало
  ПолеИст := НастройкиСинхронизации.Поле("ИмяПоляИсточника").КакСтрока;
  //для КЦС специальная обработка
  если ПолеИст = "Код_ЦелевыхСредств" тогда
    результат := ПроверитьКЦС(МассивЗначений, НастройкиСинхронизации, КэшСлоев, ДанныеПриемника)
  иначе 
    результат := ПроверитьКлассификаторыСтандартно(МассивЗначений, НастройкиСинхронизации, КэшСлоев, Генератор)
конец;

функция ПустоеЗначениеКлассификатора(СписокКлючей: Текст; Данные: СтатическиеДанные): целое;
переменные
  Индекс: целое;
начало
  результат := да;
  Индекс := 0;
  пока результат и (Индекс &lt; СписокКлючей.Количество) делать
  начало
   если не Данные.Поле(СписокКлючей.Стр(Индекс)).Пустое тогда
     результат := нет;
   Индекс := Индекс + 1;
  конец;
конец;

// Синхронизация справочников на уровне заголовка или детализации
функция СкопироватьЗначенияКлассификаторов(Уровень: целое; КэшСлоев: IVariables; ДанныеИсточника, ДанныеПриемника: СтатическиеДанные; ЛогТекст: Текст; Генератор: СтатическиеДанные);
переменные
  СлойНастроек, СправИсточник, СправПриемник: ILayer;
  НастройкиСинхронизации, ДанныеСправИст, ДанныеСправПрием: СтатическиеДанные;
  пИмя, пИмяПоляИсточника, пИмяПоляПриемника, пМаппингИст, пМаппингПрием, пСинхронизировать, 
      пАлиасИсхСправочника, пАлиасВнешСправочника, пКодИст, пКодПрием, пПроверкаУровней, пМаска: поле;
  ID, инд: целое;
  СписокЗначений, СписокКлючей: Текст;
  МассивЗначенийКлючей, МассивЗначенийУровня: Переменная;
  Сортировка: строка;
начало
  СлойНастроек := КэшСлоев.Значение(алиасНастройкиСинхронизации);
  НастройкиСинхронизации := СлойНастроек.LayerData;
  НастройкиСинхронизации.Фильтр := Формат("(Использовать=1)and(УровеньДетализации=%d)", Уровень);
  пИмя := НастройкиСинхронизации.Поле("Классификатор");
  пИмяПоляИсточника := НастройкиСинхронизации.Поле("ИмяПоляИсточника");
  пИмяПоляПриемника := НастройкиСинхронизации.Поле("ИмяПоляРосписи");
  пМаппингИст := НастройкиСинхронизации.Поле("МаппингДопПолейИст");
  пМаппингПрием := НастройкиСинхронизации.Поле("МаппингДопПолейПрием");
  пСинхронизировать := НастройкиСинхронизации.Поле("Синхронизировать");
  пАлиасИсхСправочника := НастройкиСинхронизации.Поле("Источник");
  пАлиасВнешСправочника := НастройкиСинхронизации.Поле("Приемник");
  пКодИст := НастройкиСинхронизации.Поле("КлючИсточника");
  пКодПрием := НастройкиСинхронизации.Поле("КлючПриемника");
  пПроверкаУровней := НастройкиСинхронизации.Поле("ПроверкаУровней");
  пМаска := НастройкиСинхронизации.Поле("Маска");
  
  //сортируем по полю росписи, чтобы код ЦС заполнялся после типа классификации
  Сортировка := НастройкиСинхронизации.IndexFieldNames;
  НастройкиСинхронизации.IndexFieldNames := "ИмяПоляРосписи";
  
  СписокЗначений := СоздатьТекст;
  СписокКлючей := СоздатьТекст;
  МассивЗначенийКлючей := CreateVariant;
  МассивЗначенийУровня := CreateVariant;
  попытка  
  НастройкиСинхронизации.ВНачало;
  пока не НастройкиСинхронизации.ВКонце делать
  начало
    СписокКлючей.РазделенноеЗначение(";") := пИмяПоляИсточника.КакСтрока;
    если не ПустоеЗначениеКлассификатора(СписокКлючей, ДанныеИсточника) тогда
    начало
      ПолучитьМассивЗначенийКлючей(МассивЗначенийКлючей, СписокКлючей, ДанныеИсточника);
      ФорматироватьЗначенияВМассиве(МассивЗначенийКлючей, пМаска.КакСтрока);
      если пСинхронизировать.КакФлаг тогда начало
        ID := ПроверитьКлассификаторы(МассивЗначенийКлючей, НастройкиСинхронизации, КэшСлоев, Генератор, ДанныеПриемника);
        если пПроверкаУровней.КакСтрока &lt;&gt; '' 
          тогда начало
            СписокЗначений.РазделенноеЗначение(";") := пПроверкаУровней.КакСтрока;
            от инд := 0 до СписокЗначений.Количество-1 делать
            начало
              ПолучитьМассивЗначенийВышестоящегоУровня(пМаска.КакСтрока, СписокЗначений.Стр(инд), МассивЗначенийКлючей, МассивЗначенийУровня);
              ФорматироватьЗначенияВМассиве(МассивЗначенийУровня, пМаска.КакСтрока);
              ПроверитьКлассификаторы(МассивЗначенийУровня, НастройкиСинхронизации, КэшСлоев, Генератор, ДанныеПриемника);
            конец;     
          конец;
        // в слое-приемнике проставляем не код классификатора, а его ID в базе исполнения 
        ДанныеПриемника.Поле(пИмяПоляПриемника.КакСтрока).КакЦелое := ID; 
      конец
      иначе 
        если пАлиасВнешСправочника.КакСтрока &lt;&gt; "" тогда
        начало
          СправПриемник := КэшСлоев.Значение(пАлиасВнешСправочника.КакСтрока);    
          ДанныеСправПрием := СправПриемник.LayerData;
          если ДанныеСправПрием.Локализовать(пКодПрием.КакСтрока, МассивЗначенийКлючей, 0) 
            // в слое-приемнике проставляем не код классификатора, а его ID в базе исполнения
            тогда ДанныеПриемника.Поле(пИмяПоляПриемника.КакСтрока).КакЦелое := ДанныеСправПрием.Поле("ID").КакЦелое
            иначе ДобавитьВЛог("Во внешнем справочнике '"+пИмя.КакСтрока+"' отсутствует запись с кодом " + 
              ФорматироватьКлассификаторПоМаске(МассивЗначенийКлючей, пМаска.КакСтрока), ЛогТекст);
        конец
        иначе 
          ДанныеПриемника.Поле(пИмяПоляПриемника.КакСтрока).КакСтрока := МассивЗначенийКлючей.КакСтрока(0);
      если пМаппингИст.КакСтрока &lt;&gt; '' тогда
      начало
        СправИсточник := КэшСлоев.Значение(пАлиасИсхСправочника.КакСтрока);
        ДанныеСправИст := СправИсточник.LayerData;
        если ДанныеСправИст.Локализовать(пКодИст.КакСтрока, МассивЗначенийКлючей, 0) тогда
          ЗаполнитьДополнительныеПоля(ДанныеСправИст, ДанныеПриемника, пМаппингИст.КакСтрока);
      конец;
      если пМаппингПрием.КакСтрока &lt;&gt; '' тогда
      начало
        СправПриемник := КэшСлоев.Значение(пАлиасВнешСправочника.КакСтрока);
        ДанныеСправПрием := СправПриемник.LayerData;
        если ДанныеСправПрием.Локализовать(пКодПрием.КакСтрока, МассивЗначенийКлючей, 0) тогда
          ЗаполнитьДополнительныеПоля(ДанныеСправПрием, ДанныеПриемника, пМаппингПрием.КакСтрока);
      конец;
    конец;
    НастройкиСинхронизации.Следующая;
  конец;
  НастройкиСинхронизации.Фильтр := "";
  обязательно
    НастройкиСинхронизации.IndexFieldNames := Сортировка;
    УдалитьОбъект(СписокЗначений, СписокКлючей, МассивЗначенийКлючей, МассивЗначенийУровня);
  конец;
конец;

// Сохранение данных справочников в базе исполнения
функция СохранитьВнешниеСправочники(КэшСлоев: IVariables);
переменные
  НастройкиСинхронизации: СтатическиеДанные;
  пИмяСправочника: поле;
  Справочник, СлойНастроек: ILayer;
начало  
  СлойНастроек := КэшСлоев.Значение(алиасНастройкиСинхронизации);
  НастройкиСинхронизации := СлойНастроек.LayerData;
  НастройкиСинхронизации.Фильтр := "(Использовать=1)and(Синхронизировать=1)";
  пИмяСправочника := НастройкиСинхронизации.Поле("Приемник");
  
  НастройкиСинхронизации.ВНачало;
  пока не НастройкиСинхронизации.ВКонце делать
  начало
    Справочник := КэшСлоев.Значение(пИмяСправочника.КакСтрока);
    Справочник.Commit;
    НастройкиСинхронизации.Следующая;
  конец;
  НастройкиСинхронизации.Фильтр := "";
конец;

// Получение данных справочника целевых средств после сохранения его в базу
функция ПолучитьСлойКЦС(НастройкиСинхронизации: СтатическиеДанные; Подключение: строка; Направление: целое): ILayer;
переменные
  ДанныеКЦС: СтатическиеДанные;
  Алиас: строка;
  Парам: IVariables;
  пКВСР, пКФСР, пКВР, пКЦСР, пКЭСР, пПриоритет: поле;
начало
  если НастройкиСинхронизации.Локализовать("ИмяПоляИсточника", "Код_ЦелевыхСредств", 1) тогда
    Алиас := НастройкиСинхронизации.Поле("Приемник").КакСтрока;

  результат := ПолучитьМенеджерСлоев.CreateLayerByAlias(Алиас);
  ПроставитьИмяБДВОписанииСлоя(результат, Подключение);
  
  ДанныеКЦС := результат.LayerData;
  //добавляем поле, которое будет обозначать приоритет записи в справочнике
  //чем больше полей классификации заполнено, тем больше приоритет
  если Направление = нВыбытие тогда
    ДанныеКЦС.ДобавитьЦелоеПоле("Priority");
  
  Парам := CreateVariables;
  //для возможности передачи имени подключения источникам запоминаем его в контекстных параметрах слоя
  Парам.Values("ИмяПодключения") := Подключение;
  //для расходной классификации нам нужны только записи, имеющие тип Выбытие (передача)
  Парам.Значение("$Layer.TargetMeansSign") := Направление;
  результат.SelectData(Парам);
  
  если Направление = нВыбытие тогда
  начало
    пКВСР := ДанныеКЦС.Поле("TransferKVSR");
    пКФСР := ДанныеКЦС.Поле("TransferKFSR");
    пКВР := ДанныеКЦС.Поле("TransferKVR");
    пКЦСР := ДанныеКЦС.Поле("TransferKCSR");
    пКЭСР := ДанныеКЦС.Поле("TransferKESR");
    пПриоритет := ДанныеКЦС.Поле("Priority");
    ДанныеКЦС.ВНачало;
    пока не ДанныеКЦС.ВКонце делать
    начало
      пПриоритет.КакЦелое := (пКВСР.КакЦелое = 0) + (пКФСР.КакЦелое = 0) + (пКВР.КакЦелое = 0) + (пКЦСР.КакЦелое = 0) + (пКЭСР.КакЦелое = 0);
      ДанныеКЦС.Следующая;
    конец;
  
    //сразу же сортируем все записи по приоритету
    ДанныеКЦС.IndexFieldNames := "Priority";
  конец
  иначе
    ДанныеКЦС.IndexFieldNames := "Code;ReceiveKD";
конец;

// Получение данных справочника КД
функция ПолучитьСлойКД(НастройкиСинхронизации: СтатическиеДанные; Подключение: строка): ILayer;
переменные
  ДанныеКД: СтатическиеДанные;
  Алиас: строка;
  Парам: IVariables;
начало
  если НастройкиСинхронизации.Локализовать("ИмяПоляРосписи", "KD", 1) тогда
    Алиас := НастройкиСинхронизации.Поле("Приемник").КакСтрока;

  результат := ПолучитьМенеджерСлоев.CreateLayerByAlias(Алиас);
  ПроставитьИмяБДВОписанииСлоя(результат, Подключение);
  
  ДанныеКД := результат.LayerData;  
  Парам := CreateVariables;
  //для возможности передачи имени подключения источникам запоминаем его в контекстных параметрах слоя
  Парам.Values("ИмяПодключения") := Подключение;
  результат.SelectData(Парам);
  
конец;

// Получение ID КЦС по расходной классификации
функция ПолучитьИДЦелевыхСредствПоКодуИКлассификации(ДанныеКЦС, ДанныеРосписи, КэшЗначенийИД: СтатическиеДанные): целое;
переменные
  Значения : Variant;
  КодЦС, КВСР, КФСР, КВР, КЦСР, КЭСР: целое;
начало
  результат := 0;
  Значения := CreateVariant;
  
  КодЦС := ДанныеРосписи.Поле("TransfertCLS").КакЦелое;
  КВСР := ДанныеРосписи.Поле("KVSR").КакЦелое;
  КФСР := ДанныеРосписи.Поле("KFSR").КакЦелое;
  КВР := ДанныеРосписи.Поле("KVR").КакЦелое;
  КЦСР := ДанныеРосписи.Поле("KCSR").КакЦелое;
  КЭСР := ДанныеРосписи.Поле("KESR").КакЦелое;
  
  Значения.VarArrayOf(КодЦС, КВСР, КФСР, КВР, КЦСР, КЭСР);
  
  если КэшЗначенийИД.FindKey(Значения) тогда
    результат := КэшЗначенийИД.Поле("ID").КакЦелое
  иначе начало
    //оставляем в справочнике только записи с требуемым кодом и подходящей классификацией
    ДанныеКЦС.Фильтр := Формат("(Code=%d) and ((TransferKVSR=%d) or (TransferKVSR=0)) 
           and ((TransferKFSR=%d) or (TransferKFSR=0)) and ((TransferKVR=%d) or (TransferKVR=0)) 
           and ((TransferKCSR=%d) or (TransferKCSR=0)) and ((TransferKESR=%d) or (TransferKESR=0))", 
           КодЦС, КВСР, КФСР, КВР, КЦСР, КЭСР);
    если ДанныеКЦС.ЧислоЗаписей &gt; 0 тогда
    начало
      ДанныеКЦС.ВНачало;
      результат := ДанныеКЦС.Поле("ID").КакЦелое;
      //запоминаем запись в кэше
      КэшЗначенийИД.ВставитьЗапись(МассивИз(результат, КодЦС, КВСР, КФСР, КВР, КЦСР, КЭСР));
    конец;
  конец;
конец;

// Получение ID КЦС по доходной классификации
функция ПолучитьИДЦелевыхСредствПоКодуИКД(ДанныеКЦС, ДанныеКД, ДанныеРосписи, КэшЗначенийИД: СтатическиеДанные): целое;
переменные
  Значения, ЗначенияКД : Variant;
  КодЦС, КД: целое;
  ФильтрКД: строка;
начало
  результат := 0;
  Значения := CreateVariant;
  
  КодЦС := ДанныеРосписи.Поле("TransfertCLS").КакЦелое;
  КД := ДанныеРосписи.Поле("KD").КакЦелое;
                                                                
  Значения.VarArrayOf(КодЦС, КД);
  
  если КэшЗначенийИД.FindKey(Значения) тогда
    результат := КэшЗначенийИД.Поле("ID").КакЦелое
  иначе начало
    если ДанныеКЦС.FindKey(Значения) тогда
      результат := ДанныеКЦС.Поле("ID").КакЦелое
    иначе начало
      ДанныеКД.Локализовать("ID", КД, 0);
      ЗначенияКД := CreateVariant;
      ЗначенияКД.VarArrayOf(ДанныеКД.Поле("DescriptionCode").КакСтрока, ДанныеКД.Поле("ProgramCode").КакЦелое, ДанныеКД.Поле("KESR").КакЦелое);
      
      ДанныеКЦС.SetScope(МассивИз(КодЦС));
      ФильтрКД := Формат("ID in (%s)", ПолучитьСписокЗначенийПоляБезСортировки(ДанныеКЦС, "ReceiveKD", ","));
      ДанныеКД.Фильтр := ФильтрКД; 
      попытка
        если ДанныеКД.Локализовать("DescriptionCode;ProgramCode;KESR", ЗначенияКД, 0) тогда
          ДанныеКЦС.FindKey(МассивИз(КодЦС, ДанныеКД.Поле("ID").КакЦелое))
        иначе
          ДанныеКЦС.FindKey(МассивИз(КодЦС, 0));
        результат := ДанныеКЦС.Поле("ID").КакЦелое;
      обязательно
        ДанныеКД.Фильтр := "";
      конец;
    конец;
      
      //запоминаем запись в кэше
    КэшЗначенийИД.ВставитьЗапись(МассивИз(результат, КодЦС, КД));
  конец;
конец;

// Заполнение ID целевых средств в детализации росписи
функция ЗаполнитьКодЦелевыхСредств(ДанныеРосписи: СтатическиеДанные; КэшСлоев: IVariables; Подключение: строка);
переменные
  СлойКЦС, СлойНастроек, СлойКД: ILayer;
  ДанныеКЦС, КэшЗначенийИД, НастройкиСинхронизации, ДанныеКД: СтатическиеДанные;
  Направление: целое;
начало
  СлойНастроек := КэшСлоев.Значение(алиасНастройкиСинхронизации);
  НастройкиСинхронизации := СлойНастроек.LayerData;    
  Направление := ПолучитьНаправлениеДенежныхСредствПоТипуКлассификации(ДанныеРосписи);  

  //открываем справочник целевых средств
  СлойКЦС := ПолучитьСлойКЦС(НастройкиСинхронизации, Подключение, Направление);
  ДанныеКЦС := СлойКЦС.LayerData;
  
  если Направление = нПоступление тогда
  начало
    СлойКД := ПолучитьСлойКД(НастройкиСинхронизации, Подключение);
    ДанныеКД := СлойКД.LayerData;
  конец;
  
  //значения ID для различных кодов ЦС и классификации будем кэшировать
  КэшЗначенийИД := СоздатьСтатическиеДанные;
  КэшЗначенийИД.ДобавитьЦелоеПоле("ID");
  КэшЗначенийИД.ДобавитьЦелоеПоле("TransfertCls");
  если Направление = нВыбытие тогда
  начало
    КэшЗначенийИД.ДобавитьЦелоеПоле("KVSR");
    КэшЗначенийИД.ДобавитьЦелоеПоле("KFSR");
    КэшЗначенийИД.ДобавитьЦелоеПоле("KVR");
    КэшЗначенийИД.ДобавитьЦелоеПоле("KCSR");
    КэшЗначенийИД.ДобавитьЦелоеПоле("KESR");
  конец
  иначе
    КэшЗначенийИД.ДобавитьЦелоеПоле("KD");
  КэшЗначенийИД.Открыть;
  если Направление = нВыбытие тогда
    КэшЗначенийИД.IndexFieldNames := "TransfertCls;KVSR;KFSR;KVR;KCSR;KESR"
  иначе
    КэшЗначенийИД.IndexFieldNames := "TransfertCls;KD";
  
  //заменяем код КЦС на его ID  
  ДанныеРосписи.ВНачало;
  пока не ДанныеРосписи.ВКонце делать
  начало
    ДанныеРосписи.Редактировать;
    если Направление = нВыбытие тогда
      ДанныеРосписи.Поле("TransfertCls").КакЦелое := ПолучитьИДЦелевыхСредствПоКодуИКлассификации(ДанныеКЦС, ДанныеРосписи, КэшЗначенийИД)
    иначе 
      ДанныеРосписи.Поле("TransfertCls").КакЦелое := ПолучитьИДЦелевыхСредствПоКодуИКД(ДанныеКЦС, ДанныеКД, ДанныеРосписи, КэшЗначенийИД);
    ДанныеРосписи.Сохранить;
    ДанныеРосписи.Следующая;
  конец;
конец;


//***************************************************************************************
//РАБОТА С ДИАЛОГОМ

// Определяет уровень параметра по заданной позиции при выводе его в диалоге
функция ОпределитьУровень(Позиция: целое): целое;
начало
  если (Позиция ост 100) &gt; 0 
    тогда результат := 2
    иначе если (Позиция ост 10000) &gt; 0 
      тогда результат := 1
      иначе результат := 0
конец;

// Настраивает диалог согласно настройкам параметров экспорта
функция ПостроитьДиалог(СлойНастроек: ILayer; ПараметрыМакроса: IVariables);
переменные
  Настройки: СтатическиеДанные;
  ПараметрДиалога: ДиалоговыйПараметр;
  пИмя, пЗаголовок, пПозиция, пЗначение, пЦелое, пСтроковое, пЛогическое, пСтиль,
  пМаска, пРасширение, пЗначПоУмолчанию, пОбработчик: поле; 
  УровеньЗаголовка, Уровень: целое;
  ИменаЗаголовков, СписокЗначений: Текст;
  инд: целое;
  ИмяПараметра: строка;
начало
  Настройки := СлойНастроек.LayerData;
  Настройки.Фильтр := "ДиалогИспользовать=1";
  Настройки.IndexFieldNames := "Позиция";

  пИмя := Настройки.ПолеПоИмени("ИмяПараметра");
  пЗаголовок := Настройки.ПолеПоИмени("ЗаголовокПараметра");
  пПозиция := Настройки.ПолеПоИмени("Позиция");
  пЗначение := Настройки.ПолеПоИмени("ТипЗначения");
  пЦелое := Настройки.ПолеПоИмени("ЗначениеЦелое");
  пСтроковое := Настройки.ПолеПоИмени("ЗначениеСтроковое");
  пЛогическое := Настройки.ПолеПоИмени("ЗначениеЛогическое");
  пСтиль := Настройки.ПолеПоИмени("ДиалогСтиль");
  пМаска := Настройки.ПолеПоИмени("ДиалогМаска");
  пРасширение := Настройки.ПолеПоИмени("ДиалогРасширение");
  пЗначПоУмолчанию := Настройки.ПолеПоИмени("ДиалогЗнПоУмолч");
  пОбработчик := Настройки.ПолеПоИмени("ДиалогОбработчик");
  
  ИменаЗаголовков := СоздатьТекст;
  СписокЗначений := СоздатьТекст;
  попытка
  Настройки.ВНачало;
  пока не Настройки.ВКонце делать
  начало
    Уровень := ОпределитьУровень(пПозиция.КакЦелое);
    УровеньЗаголовка := ИменаЗаголовков.Количество-1;
    если Уровень = УровеньЗаголовка тогда
    начало
      Диалог.Параметр(ИменаЗаголовков.Стр(УровеньЗаголовка)).Захлопнут := да;
      ИменаЗаголовков.Удалить(УровеньЗаголовка);
    конец;
    ПараметрДиалога := Диалог.Добавить(пЗаголовок.КакСтрока, пИмя.КакСтрока, Уровень, 0, пМаска.КакСтрока, "");
    /*выбрать пСтиль.КакЦелое из
        2: ПараметрДиалога.Стиль := Проверка;
        8: ПараметрДиалога.Стиль := ТолькоЧтение;
        10: ПараметрДиалога.Стиль := Проверка + ТолькоЧтение;
        12: ПараметрДиалога.Стиль := Список + ТолькоЧтение;
     конец;*/
    выбрать пЗначение.КакЦелое из
      1: если пМаска.КакСтрока &lt;&gt; ''
           тогда ПараметрДиалога.Значение := ФорматироватьКлассификатор(пЦелое.КакЦелое, пМаска.КакСтрока)
           иначе ПараметрДиалога.Значение := пЦелое.КакЦелое;
      2: если пМаска.КакСтрока &lt;&gt; ''
           тогда ПараметрДиалога.Значение := ФорматироватьКлассификатор(пСтроковое.КакСтрока, пМаска.КакСтрока)
           иначе ПараметрДиалога.Значение := пСтроковое.КакСтрока;
      3: начало
           ПараметрДиалога.Стиль := Проверка + ТолькоЧтение;
           ПараметрДиалога.Флаг := пЛогическое.КакФлаг;
         конец;
      4: начало
           ИменаЗаголовков.Добавить(пИмя.КакСтрока);
           ПараметрДиалога.ТолькоЧтение := 1; 
         конец;
      5: начало
           ПараметрДиалога.Стиль := Список + ТолькоЧтение;
           СписокЗначений.РазделенноеЗначение(";") := ЗаменитьПодстроку(пСтроковое.КакСтрока, " ", "$", да);
           от инд := 0 до СписокЗначений.Количество-1 делать
           начало
             ИмяПараметра := СписокЗначений.ИмяПараметра(инд);
             если (СтрокаВЦелое(СписокЗначений.ЗначениеПараметра(ИмяПараметра))) = пЦелое.КакЦелое тогда
               ПараметрДиалога.Значение := ЗаменитьПодстроку(ИмяПараметра, "$", " ", да);
             ПараметрДиалога.Список := ПараметрДиалога.Список + ЗаменитьПодстроку(ИмяПараметра, "$", " ", да);// + "#13#10";
           конец;
         конец;
      6: начало
           ПараметрДиалога.Стиль := Календарь;         
           если пМаска.КакСтрока &lt;&gt; ''
             тогда ПараметрДиалога.Значение := ФорматироватьКлассификатор(пЦелое.КакЦелое, пМаска.КакСтрока)
             иначе ПараметрДиалога.Значение := пЦелое.КакЦелое;
         конец;
    конец;
    
    если пОбработчик.КакСтрока &lt;&gt; '' тогда
    начало
      //ПараметрДиалога.Обработчик := Адрес('ОбработчикПараметра');
      ПараметрыМакроса.Значение("ОбработчикПараметра"+пИмя.КакСтрока) := пОбработчик.КакСтрока;
    конец;
    Настройки.Следующая;
  конец;
  Настройки.Фильтр := "";
  обязательно
    УдалитьОбъект(ИменаЗаголовков, СписокЗначений);
  конец;
конец;

// Сохраняет измененные в диалоге настройки
функция СохранитьНастройки(СлойНастроек: ILayer);
переменные
  Настройки: СтатическиеДанные;
  пИмя, пЗначение, пЦелое, пСтроковое, пЛогическое: поле; 
  СписокЗначений: Текст;
  ЗначениеПараметра: целое;
  ИмяПараметра, Имя: строка;
начало
  Настройки := СлойНастроек.LayerData;
  Настройки.Фильтр := "(ДиалогИспользовать=1)and not(ЗначениеПараметра=4)";
  
  пИмя := Настройки.ПолеПоИмени("ИмяПараметра");
  пЗначение := Настройки.ПолеПоИмени("ТипЗначения");
  пЦелое := Настройки.ПолеПоИмени("ЗначениеЦелое");
  пСтроковое := Настройки.ПолеПоИмени("ЗначениеСтроковое");
  пЛогическое := Настройки.ПолеПоИмени("ЗначениеЛогическое");
  
  СписокЗначений := СоздатьТекст;
  попытка
  Настройки.ВНачало;
  пока не Настройки.ВКонце делать
  начало
    Имя := пИмя.КакСтрока;
    выбрать пЗначение.КакЦелое из
      1, 6: если пЦелое.КакЦелое &lt;&gt; КлассификаторВЧисло(Диалог.Параметр(Имя).Значение, Диалог.Параметр(Имя).Маска) тогда
         начало
           Настройки.Редактировать;
           пЦелое.КакЦелое := СтрокаВЦелое(Диалог.Параметр(Имя).Значение);
           Настройки.Сохранить;
         конец;
      2: если пСтроковое.КакСтрока &lt;&gt; Диалог.Параметр(Имя).Значение тогда
         начало
           Настройки.Редактировать;
           пСтроковое.КакСтрока := Диалог.Параметр(Имя).Значение;
           Настройки.Сохранить;
         конец;
      3: если пЛогическое.КакФлаг &lt;&gt; Диалог.Параметр(Имя).Флаг тогда
         начало
           Настройки.Редактировать;
           пЛогическое.КакФлаг := Диалог.Параметр(Имя).Флаг;
           Настройки.Сохранить;
         конец;
      5: начало
           СписокЗначений.РазделенноеЗначение(";") := ЗаменитьПодстроку(пСтроковое.КакСтрока, " ", "$", да);
           ИмяПараметра := ЗаменитьПодстроку(Диалог.Параметр(Имя).Значение, " ", "$", да);
           ЗначениеПараметра := СтрокаВЦелое(СписокЗначений.ЗначениеПараметра(ИмяПараметра));
           если пЦелое.КакЦелое &lt;&gt; ЗначениеПараметра тогда
           начало
             Настройки.Редактировать;
             пЦелое.КакЦелое := ЗначениеПараметра;
             Настройки.Сохранить;
           конец;
         конец;
    конец;
    Настройки.Следующая;
  конец;
  Настройки.Фильтр := "";
  обязательно
    УдалитьОбъект(СписокЗначений);
  конец;  
  СлойНастроек.Commit;  
конец;

// Добавляет в диалог поправки к выгружаемому проекту закона
функция ДобавитьПараметрПоправки(Документ_ИД: целое);
переменные
  ПараметрДиалога : ДиалоговыйПараметр;
  СлойПоправок : ILayer;
  ДанныеСлояПоправок : СтатическиеДанные;
  пИД, пНомерПоправки, пПроект_ИД, пИмяПоправки, пПроект_Имя: поле; 
  Контекст: IVariables;
начало
  Диалог.Добавить('Поправки', "Поправки", 0, 0, '', '');
  Диалог.Параметр("Поправки").ТолькоЧтение := 1;
  
  СлойПоправок := ПолучитьМенеджерСлоев.CreateLayerByAlias(алиасПоправки);
  Контекст := CreateVariables;
  Контекст.Значение("$Layer.Сотояние") := 2;
  СлойПоправок.SelectData(Контекст);
  ДанныеСлояПоправок := СлойПоправок.LayerData;
  ДанныеСлояПоправок.Фильтр := "Проект_ИД in (" + ЦелоеВСтроку(Документ_ИД) + ")";
  ДанныеСлояПоправок.IndexFieldNames := "Проект_ИД;НомерПоправки";
  пИД := ДанныеСлояПоправок.ПолеПоИмени("ИД");
  пПроект_ИД := ДанныеСлояПоправок.ПолеПоИмени("Проект_ИД");
  пНомерПоправки := ДанныеСлояПоправок.ПолеПоИмени("НомерПоправки");
  пИмяПоправки := ДанныеСлояПоправок.ПолеПоИмени("ИмяПоправки");
  пПроект_Имя := ДанныеСлояПоправок.ПолеПоИмени("Проект_Имя");
  ДанныеСлояПоправок.ВНачало;
  если ДанныеСлояПоправок.ЧислоЗаписей = 0 тогда
    Диалог.Параметр("Поправки").Значение := "нет";
  пока не ДанныеСлояПоправок.ВКонце делать
  начало
    ПараметрДиалога := Диалог.Добавить(пНомерПоправки.КакСтрока+" - "+пИмяПоправки.КакСтрока, "Поправка_"+пИД.КакСтрока, 1, Проверка+ТолькоЧтение, '', '');
    ПараметрДиалога.Флаг := нет;
    ДанныеСлояПоправок.Следующая;
  конец;
  Диалог.Параметр("Поправки").Захлопнут := 1;
конец;

// Получает ИД выбранных в диалоге поправок
функция ПолучитьНомераПоправок: строка;
переменные
  инд: целое;
  ИмяПараметра: строка;
начало
    результат := "";
    от инд := 0 до Диалог.ЧислоПараметров-1 делать  
    начало
      ИмяПараметра := Диалог.ПараметрПоНомеру(инд).Идентификатор;
      если (Позиция("Поправка_", ИмяПараметра) = 1) и Диалог.ПараметрПоНомеру(инд).Флаг тогда
        результат := результат + "," + ЗаменитьПодстроку(ИмяПараметра, "Поправка_", "", нет);
    конец;
    результат := ЗаменитьПодстроку(результат, ",", "", нет);
конец;



//***************************************************************************************
//ПОЛУЧЕНИЕ ЗНАЧЕНИЙ ПОЛЕЙ ИЗ ВНЕШНИХ СПРАВОЧНИКОВ ПО ЗАДАННОМУ ЗНАЧЕНИЮ ПОЛЯ

// получает лицевой счет по заданному коду ГРБС из таблицы соответствия
функция ПолучитьЛицевойСчетИзТаблицыСоответствия(Код_ГРБС, ЛицевойСчет: целое; КэшСлоев: IVariables): целое;
переменные
  ТаблицаСоответствияЛСиГРБС: ILayer;
  ДанныеТаблицыСоответствия: СтатическиеДанные;
начало
  результат := нет;
  если не КэшСлоев.ПараметрСуществует(алиасТаблицаСоотвЛСиГРБС) 
    тогда начало
      ТаблицаСоответствияЛСиГРБС := ПолучитьМенеджерСлоев.CreateLayerByAliasEx(алиасТаблицаСоотвЛСиГРБС, 1);
      ТаблицаСоответствияЛСиГРБС.Open;      
      КэшСлоев.Значение(алиасТаблицаСоотвЛСиГРБС) := ТаблицаСоответствияЛСиГРБС;
    конец
    иначе 
      ТаблицаСоответствияЛСиГРБС := КэшСлоев.Значение(алиасТаблицаСоотвЛСиГРБС);
  ДанныеТаблицыСоответствия := ТаблицаСоответствияЛСиГРБС.LayerData;
  если ДанныеТаблицыСоответствия.Локализовать("Код_ГРБС", Код_ГРБС, 0)
    тогда начало
      ЛицевойСчет := ДанныеТаблицыСоответствия.ПолеПоИмени("Код_ЛицевойСчет").КакЦелое;
      результат := да;
    конец;
конец;

// получает организацию, лицевой счет по заданному коду ГРБС
функция ПолучитьДанныеГРБС(Код_ГРБС, Код_Организации, ЛицевойСчет: целое; СписокКВСР, ЛогТекст: Текст; СправочникКВСРПрием, СправочникЛСПрием: ILayer; КэшСлоев: IVariables);
переменные
  ДанныеСправочникаКВСР, ДанныеСправочникаЛС: СтатическиеДанные;  
  КодМетода: строка;
начало
  ЛицевойСчет := 0;
  Код_Организации := 0;
  если СписокКВСР.Поиск(ЦелоеВСтроку(Код_ГРБС)) = -1
    тогда начало
      // получаем лицевой счет
      КодМетода := ГлобальныеКонстанты.ПолучитьЗначение('Планирование.МетодОпределенияЛСпоГРБС', '3');
      выбрать КодМетода из
      '1': ЛицевойСчет := Код_ГРБС*1000000;
      '2': если не ПолучитьЛицевойСчетИзТаблицыСоответствия(Код_ГРБС, ЛицевойСчет, КэшСлоев) тогда
           ДобавитьВЛог('В слое "Таблица соответствия ЛС и ГРБС" не определен лицевой счет для ГРБС с кодом '+ЦелоеВСтроку(Код_ГРБС), ЛогТекст);
      '3': если не ПолучитьЛицевойСчетИзТаблицыСоответствия(Код_ГРБС, ЛицевойСчет, КэшСлоев) тогда
           ЛицевойСчет := Код_ГРБС*1000000;
      иначе
        ДобавитьВЛог('Неверно задан параметр "Планирование.МетодОпределенияЛСпоГРБС" в слое "Настройки планирования": значение параметра должно быть целым числом в диапазоне от 1 до 3.', ЛогТекст);
      конец;
      
      // проверяем лицевой счет на наличие в справочнике
      ДанныеСправочникаЛС := СправочникЛСПрием.LayerData;
      если не ДанныеСправочникаЛС.Locate("ID", ЛицевойСчет, 0) тогда
      начало
        ДобавитьВЛог("Во внешнем справочнике 'Лицевые счета' отсутствует запись с кодом " + ФорматироватьКлассификатор(ЛицевойСчет, "000.00.000.0"), ЛогТекст);
        ЛицевойСчет := 0;
      конец;   

      // организацию получаем из внешнего справочника КВСР
      ДанныеСправочникаКВСР := СправочникКВСРПрием.LayerData;
      если ДанныеСправочникаКВСР.Locate("ID", Код_ГРБС, 0) 
        тогда Код_Организации := ДанныеСправочникаКВСР.ПолеПоИмени("ORG_REF").КакЦелое;
        СписокКВСР.ЗначениеПараметра(Код_ГРБС) := ЦелоеВСтроку(Код_Организации) + "|" + ЦелоеВСтроку(ЛицевойСчет);
    конец
    иначе начало
      Код_Организации := СтрокаВЦелое(ВырезатьПараметр(СписокКВСР.ЗначениеПараметра(Код_ГРБС)));
      ЛицевойСчет := СтрокаВЦелое(ВырезатьПараметр(СписокКВСР.ЗначениеПараметра(Код_ГРБС)));
    конец;    
конец;

// получает организацию по заданному коду ГРБС
функция ПолучитьОрганизациюПоГРБС(Код_ГРБС: целое; СписокКВСР: Текст; СправочникКВСРПрием: ILayer): целое;                         
переменные
  ДанныеСправочникаКВСР: СтатическиеДанные;  
начало
  результат := 0;
  если СписокКВСР.Поиск(ЦелоеВСтроку(Код_ГРБС)) = -1
    тогда начало
      ДанныеСправочникаКВСР := СправочникКВСРПрием.LayerData;
      если ДанныеСправочникаКВСР.Locate("ID", Код_ГРБС, 0) 
        тогда результат := ДанныеСправочникаКВСР.ПолеПоИмени("ORG_REF").КакЦелое;
        СписокКВСР.ЗначениеПараметра(Код_ГРБС) := результат;
    конец
    иначе 
      результат := СтрокаВЦелое(СписокКВСР.ЗначениеПараметра(Код_ГРБС));   
конец;

функция ПолучитьГРБСпоЛицевомуСчету(Код_ЛС: целое; СправочникЛицевыеСчетаПрием: ILayer; ЛогТекст: Текст): целое;
переменные 
  ДанныеСправочникаЛС: СтатическиеДанные; 
начало
  результат := -1;
  ДанныеСправочникаЛС := СправочникЛицевыеСчетаПрием.LayerData;
  если ДанныеСправочникаЛС.Локализовать("ID", Код_ЛС, 0)
    тогда результат := ДанныеСправочникаЛС.ПолеПоИмени("KVSR").КакЦелое
    иначе ДобавитьВЛог("Во внешнем справочнике 'Лицевые счета' отсутствует запись с кодом " + ФорматироватьКлассификатор(Код_ЛС,"000.00.000.0"), ЛогТекст);   
конец; 

функция ПолучитьКодОрганизацииПоЛицевомуСчету(Код_ЛС: целое; СправочникЛицевыеСчетаПрием: ILayer; ЛогТекст: Текст): целое;
переменные 
  ДанныеСправочникаЛС: СтатическиеДанные; 
начало
  результат := -1;
  ДанныеСправочникаЛС := СправочникЛицевыеСчетаПрием.LayerData;
  если ДанныеСправочникаЛС.Локализовать("ID", Код_ЛС, 0)
    тогда результат := ДанныеСправочникаЛС.ПолеПоИмени("ORG_REF").КакЦелое
    иначе ДобавитьВЛог("Во внешнем справочнике 'Лицевые счета' отсутствует запись с кодом " + ФорматироватьКлассификатор(Код_ЛС,"000.00.000.0"), ЛогТекст);   
конец;


//***************************************************************************************
//ПРОСТАВЛЕНИЕ ОШИБОК В ДОКУМЕНТЕ

// Показ модального окна интерфейса ошибок
функция СоздатьИПоказатьИнтерфейсОшибок(ПараметрыИнициализации: IVariables; ИмяИнтерфейса, ЗаголовокФормы, СписокАспектов: строка);
переменные
  ПараметрыФормы: IVariables;
начало
  //создаем интерфейс ошибок    
  ПараметрыФормы := CreateVariables;
  ПараметрыФормы.Values("ИмяИнтерфейса") := ИмяИнтерфейса;
  ПараметрыФормы.Values("Параметры") := ПараметрыИнициализации;
  ВызватьКонтроллер("Платформа.Интерфейсы.СоздатьИнтерфейсПоИмени", ПараметрыФормы);  
  //показываем модальное окно
  попытка
    ПараметрыФормы.Values("ОбъектПредставления") := ПараметрыФормы.Values("Представление");
    ПараметрыФормы.Values("ЗаголовокФормы") := ЗаголовокФормы;
    ПараметрыФормы.Values("ИмяФормы") := "Платформа.Интерфейсы.ИнтерфейсМодальногоОкна"; 
    ПараметрыФормы.Values("СписокАспектов") := СписокАспектов; 
    ВызватьКонтроллер("Платформа.Интерфейсы.МодальнаяФорма.ПоказатьПредставление", ПараметрыФормы);
  обязательно
    //финализируем интерфейс
    ПараметрыФормы.Values("Объект") := ПараметрыФормы.Values("Представление");
    ВызватьКонтроллер("Платформа.ФинализироватьОбъект", ПараметрыФормы);
  конец;
конец; 

// Заполняет поля результата контроля и сообщения об ошибке у документа
функция ДобавитьОшибкуВДокумент(Документ: Сущность; ТекстОшибки: строка);
начало
  если Документ.АтрибутПустой("ControlMessage") 
    тогда начало
      Документ.Атрибут("ControlResult") := 3;
      Документ.Атрибут("ControlMessage") := ТекстОшибки;
    конец
    иначе Документ.Атрибут("ControlMessage") := Документ.Атрибут("ControlMessage")+"; "+ТекстОшибки
конец;

// Проставляет зеленый кружок у документа
функция СтеретьОшибкиВДокументе(Документ: Сущность);
начало
  Документ.Атрибут("ControlResult") := 1;
  Документ.Атрибут("ControlMessage") := Null;
конец;

// Заполняет поля результата контроля и сообщения об ошибке у записи слоя
функция ДобавитьОшибкуВСлой(Данные: СтатическиеДанные; ТекстОшибки: строка);
начало
  //Данные := Слой.LayerData;
  если Данные.ПолеПоИмени("ControlMessage").Пустое 
    тогда начало
      Данные.ПолеПоИмени("ControlMessage").КакСтрока := ТекстОшибки;
      //СписокДокументов.Добавить(СоздатьАдаптерЗаписиСлоя(Слой));
    конец
    иначе
      Данные.ПолеПоИмени("ControlMessage").КакСтрока := Данные.ПолеПоИмени("ControlMessage").КакСтрока+ "; "+ТекстОшибки;
конец;


//***************************************************************************************
//РАБОТА С ТАБЛИЦЕЙ СООТВЕТСТВИЯ ЗАЯВОК И УВЕДОМЛЕНИЙ

// Проверяет, возведен ли флаг выгрузки заявки в бюджет на определенный интерфейс
функция ЗаявкаВыгруженаВБюджет(ИДЗаявки: целое; КодИнтерфейса: строка; Вариант: целое; ДанныеУведомлений: СтатическиеДанные): целое;
начало
  результат := нет;
  если КодИнтерфейса = "" 
    тогда результат := ДанныеУведомлений.Локализовать("Заявка_ИД; ПризнакВыгрузки", МассивИз(ИДЗаявки, 1), 0) 
    иначе 
      если не ДанныеУведомлений.Локализовать("Заявка_ИД; ИДИнтерфейса; Вариант; ПризнакВыгрузки", МассивИз(ИДЗаявки, КодИнтерфейса, Вариант, 1), 0) тогда
        результат := ДанныеУведомлений.Локализовать("Заявка_ИД; ИДИнтерфейса; Вариант; ПризнакВыгрузки", МассивИз(ИДЗаявки, КодИнтерфейса, Null, 1), 0)
      иначе результат := да;
конец;

// Получает строку ИД уведомлений для заявки и интерфейса росписи
функция ПолучитьСписокУведомленийДляЗаявки(ИДЗаявки: целое; КодИнтерфейса: строка; ДанныеУведомлений: СтатическиеДанные): строка;
начало
  результат := ПолучитьСписокЗначенийПоляСФильтрацией(ДанныеУведомлений, Формат("(ИД_Уведомления&lt;&gt;0)and(Заявка_ИД=%d)and(ИДИнтерфейса='%s')", ИДЗаявки, КодИнтерфейса), "ИД_Уведомления", ",");
конец;

// Удаляет старые данные о выгрузке заявки на определенный интерфейс бюджета и вставляет новую запись,
// соответствующую уведомлению 
функция ПроставитьНовыеИДУведомлений(ИДЗаявки, ИДУведомления, ProgIndex: целое; КодИнтерфейса: строка; Вариант: целое; ДанныеУведомлений: СтатическиеДанные): строка;
переменные
  пИДУведомления: поле;
начало
  результат := "";
  пИДУведомления := ДанныеУведомлений.Поле("ИД_Уведомления");
  ДанныеУведомлений.Фильтр := Формат("(Заявка_ИД=%d)and(ИДИнтерфейса='%s')and((Вариант=%d)or(Вариант is null))", ИДЗаявки, КодИнтерфейса, Вариант);
  ДанныеУведомлений.ВНачало;
  //удаляем старые данные об уведомлениях в бюджете, ИД запоминаем, чтобы потом удалить уведомления из росписи
  пока не ДанныеУведомлений.ВКонце делать
  начало
    если (ДанныеУведомлений.СтатусЗаписи &lt;&gt; usDeleted) и (ДанныеУведомлений.СтатусЗаписи &lt;&gt; usInserted) тогда
    начало
      если (пИДУведомления.КакЦелое &gt; 0) тогда    
        результат := результат + "," + пИДУведомления.КакСтрока;
      ДанныеУведомлений.Удалить;
    конец
    иначе
      ДанныеУведомлений.Следующая;
  конец; 
  //вставляем запись с новым ИД уведомления
  ДанныеУведомлений.Вставить;
  ДанныеУведомлений.Поле("Заявка_ИД").КакЦелое := ИДЗаявки;
  ДанныеУведомлений.Поле("ИДИнтерфейса").КакСтрока := КодИнтерфейса;
  ДанныеУведомлений.Поле("КодИнтерфейса").КакСтрока := ProgIndex;
  ДанныеУведомлений.Поле("Вариант").КакЦелое := Вариант;
  ДанныеУведомлений.Поле("ИД_Уведомления").КакЦелое := ИДУведомления;
  ДанныеУведомлений.Поле("ПризнакВыгрузки").КакФлаг := да;
  ДанныеУведомлений.Сохранить;
  если результат &lt;&gt; "" тогда
    результат := Подстрока(результат, 2, Длина(результат) - 1);
  ДанныеУведомлений.Фильтр := "";
конец;


//***************************************************************************************
//ДРУГИЕ ФУНКЦИИ ЭКСПОРТА В РОСПИСЬ

// Формирует и показывает меню выбора интерфейса росписи
функция ПолучитьТипИнтерфейсаИзМеню(СлойТиповЭкспорта: ILayer): строка;
переменные
  СписокИмен: IVariables;       
  ПараметрыКонтроллера: IVariables;  
  Индекс: целое; 
  пКод, пИмя: поле;
  СписокТиповЭкспорта: Текст;
  СлойКонтролей: ILayer;
  ДанныеТиповЭкспорта, ДанныеКонтролей: СтатическиеДанные;
начало
  результат := "";
  ДанныеТиповЭкспорта := СлойТиповЭкспорта.LayerData;
  
  ДанныеТиповЭкспорта.Индекс := "Номер"; 
  пКод := ДанныеТиповЭкспорта.ПолеПоИмени("ТипИнтерфейса");
  пИмя := ДанныеТиповЭкспорта.ПолеПоИмени("Имя");
        
  СписокИмен := CreateVariables;
  СписокТиповЭкспорта := СоздатьТекст;
 попытка
  Индекс := 0;
  ДанныеТиповЭкспорта.ВНачало;
  пока не ДанныеТиповЭкспорта.ВКонце делать
  начало
    СлойКонтролей := СлойТиповЭкспорта.GetDetail("Контроли");
    ДанныеКонтролей := СлойКонтролей.LayerData;
    если ДанныеКонтролей.ЧислоЗаписей &gt; 0 тогда
    начало
      СписокИмен.Значение(Индекс) := пИмя.КакСтрока;
      СписокТиповЭкспорта.Добавить(пКод.КакСтрока);
      Индекс := Индекс + 1;
    конец;
    ДанныеТиповЭкспорта.Следующая;
  конец;
    
  ПараметрыКонтроллера := CreateVariables;
  ПараметрыКонтроллера.Значение("СписокИмен") := СписокИмен;
  ВызватьКонтроллер("Платформа.Представления.Меню.СоздатьИПоказатьМенюСНаборомСтрок", ПараметрыКонтроллера);
  Индекс := ПараметрыКонтроллера.Значение("Индекс"); 
  если Индекс = -1
    тогда Выход;
  результат := СписокТиповЭкспорта.Стр(Индекс); 
 обязательно
   УдалитьОбъект(СписокТиповЭкспорта);
 конец;  
конец;

// Получает слой типов интерфейсов
функция ПолучитьТипыИнтерфейсов(НомерСборки, ГодПланирования: целое; Подключение: строка; ПараметрыЭкспортаОбщие: IVariables): ILayer;
переменные
  СлойБД, СлойОбщихНастроек: ILayer;
  ДанныеБД, ДанныеОбщихНастроек: СтатическиеДанные;
начало
  результат := nil;
  СлойБД := ПолучитьМенеджерСлоев.CreateLayerByAlias(алиасСписокПодключенийБД);
  СлойБД.Open;
  ДанныеБД := СлойБД.LayerData; 
  ГодПланирования := ОпределитьГодПланирования(НомерСборки);
  если не ДанныеБД.Локализовать("Год", ГодПланирования, 0)
    тогда ВызватьОшибку(Формат("Не найдено подключение к внешней базе данных %d года в настройках экспорта!", ГодПланирования));
  Подключение := ДанныеБД.Поле("ИмяБазы").КакСтрока;
  
  СлойОбщихНастроек := СлойБД.GetDetail("Настройки");
  ДанныеОбщихНастроек := СлойОбщихНастроек.LayerData;
  ПараметрыЭкспортаОбщие := СоздатьКоллекцию;
  ЗаполнитьКоллекциюПараметров(ПараметрыЭкспортаОбщие, ДанныеОбщихНастроек);
  
  результат := СлойБД.GetDetail("ТипыЭкспорта");
конец;

// Создает таблицу ИД заголовков уведомлений
функция СоздатьТаблицуУведомлений(ПараметрыМакроса: IVariables; СписокКлючейГруппировкиУведомлений: Текст; СлойИсточникДанные: СтатическиеДанные; ТипДетализации: целое): СтатическиеДанные;
переменные
  инд: целое;
  Ключи, Маппинг, ТекущийКлюч, ИмяПараметра: строка;
начало
  результат := СоздатьСтатическиеДанные;
  результат.ДобавитьЦелоеПоле("ИДМастера");
 
  если ТипДетализации = 2 
    тогда ИмяПараметра := "КлючиГруппировкиУведомлений"
    иначе ИмяПараметра := "КлючиГруппировки_"+ЦелоеВСтроку(ТипДетализации);

  // разрез классификации, определяющий количество записей заголовка, задается в настройках
  если ПараметрыМакроса.ПараметрСуществует(ИмяПараметра) тогда
    если ПараметрыМакроса.Значение(ИмяПараметра) &lt;&gt; "" 
      тогда СписокКлючейГруппировкиУведомлений.РазделенноеЗначение(";") := ПараметрыМакроса.Значение(ИмяПараметра);
  выбрать ТипДетализации из
    0: СписокКлючейГруппировкиУведомлений.Добавить("КВСР");
    1: СписокКлючейГруппировкиУведомлений.Добавить("ЛицевойСчет");
    2: СписокКлючейГруппировкиУведомлений.Добавить("UpdateGroupIndex");
        // если СписокКлючейГруппировкиУведомлений.Поиск("КВСР") = -1 тогда       изменено Shishka99
          // СписокКлючейГруппировкиУведомлений.Добавить("КВСР");                   изменено Shishka99
  конец;
  
  // для каждого ключа создаем поле в таблице   
  от инд := 0 до СписокКлючейГруппировкиУведомлений.Количество - 1 делать
  начало
    ТекущийКлюч := СписокКлючейГруппировкиУведомлений.Стр(инд);
    результат.ДобавитьЦелоеПоле(ТекущийКлюч);
    Ключи := Ключи + "," + ТекущийКлюч;
    Маппинг := Маппинг + ";" + ТекущийКлюч + "=" + ТекущийКлюч; 
  конец;
  
  если СписокКлючейГруппировкиУведомлений.Количество &gt; 0 тогда
  начало
    Ключи := Подстрока(Ключи, 2, Длина(Ключи)-1);
    Маппинг := Подстрока(Маппинг, 2, Длина(Маппинг)-1);
    // заполняем значения ключей
    результат.Открыть;
    результат.Группировать(СлойИсточникДанные, "insert=true;keys="+Ключи+";"+Маппинг);
  конец;
конец;

// Заполнение полей росписи постоянными значениями, указанными в настройках параметров
функция ЗаполнитьКонстантныеПоля(Уровень: целое; КэшСлоев: IVariables; ДанныеПриемника: СтатическиеДанные);
переменные
  Настройки: СтатическиеДанные;
  пИмяПоля, пТипПоля, пЦелое, пСтроковое, пФлаг: поле;
  СлойНастроек: ILayer;
начало
  СлойНастроек := КэшСлоев.Значение(алиасНастройкиЭкспорта);
  Настройки := СлойНастроек.LayerData;
  Настройки.Фильтр := Формат("(УровеньДетализации=%d)and(ИмяПоляРосписи&lt;&gt;'')", Уровень);
  /*если Уровень = 0
     тогда ДанныеПриемника := СлойПриемникМастерДанные
     иначе ДанныеПриемника := СлойПриемникДетальДанные;  */
 
  пИмяПоля := Настройки.Поле("ИмяПоляРосписи");
  пТипПоля := Настройки.Поле("ТипЗначения");
  пЦелое := Настройки.Поле("ЗначениеЦелое");
  пСтроковое := Настройки.Поле("ЗначениеСтроковое");
  пФлаг := Настройки.Поле("ЗначениеЛогическое");
  
  Настройки.ВНачало;
  пока не Настройки.ВКонце делать
  начало
    выбрать пТипПоля.КакЦелое из
      1, 5: ДанныеПриемника.Поле(пИмяПоля.КакСтрока).КакЦелое := пЦелое.КакЦелое;
      2:    ДанныеПриемника.Поле(пИмяПоля.КакСтрока).КакСтрока := пСтроковое.КакСтрока;
      3:    ДанныеПриемника.Поле(пИмяПоля.КакСтрока).КакФлаг := пФлаг.КакФлаг;
      6:    ДанныеПриемника.Поле(пИмяПоля.КакСтрока).КакЦелое := ПреобразоватьДатуВЦелое(пЦелое.КакЦелое);
    конец;
    Настройки.Следующая;
  конец;
  Настройки.Фильтр := "";
конец;

// Проставление типа классификации записи согласно параметрам экспорта
функция ЗаполнитьТипКлассификации(КэшСлоев: IVariables; ДанныеПриемника: СтатическиеДанные);
переменные
  Настройки: СтатическиеДанные;
  СлойНастроек: ILayer;
начало
  СлойНастроек := КэшСлоев.Значение(алиасНастройкиЭкспорта);
  Настройки := СлойНастроек.LayerData;
  если Настройки.Локализовать("УровеньДетализации;ИмяПоляРосписи", МассивИз(1, "CLSTYPE"), 1) тогда
    если не Настройки.Поле("ЗначениеЦелое").Пустое тогда
      ДанныеПриемника.Поле("CLSTYPE").КакЦелое := Настройки.Поле("ЗначениеЦелое").КакЦелое;
конец;

// Удаление записей из заголовка росписи, не содержащих данные в детализации
функция УдалитьЗаписиСПустымиДетализациями(Мастер, Деталь: СтатическиеДанные);
переменные
  полеИД: поле;
начало
  полеИД := Мастер.ПолеПоИмени("ID");
  Мастер.ВНачало;
  пока не Мастер.ВКонце делать
  начало
    Деталь.Фильтр := "RECORDINDEX="+полеИД.КакСтрока;
    если Деталь.ЧислоЗаписей = 0 тогда
      Мастер.Удалить
    иначе Мастер.Следующая;
    Деталь.Фильтр := "";
  конец;
конец;

// Преобразует нулевые значения классификаторов в пустые
функция ФорматироватьСубсидииИЦелевыеСредства(БазисПланирования: СтатическиеДанные);
переменные
  п_Субс, п_ЦелСред: Поле;
начало
  п_Субс := БазисПланирования.Поле("Код_Субс");
  п_ЦелСред := БазисПланирования.Поле("Код_ЦелевыхСредств");
  
  БазисПланирования.ВНачало;
  пока не БазисПланирования.ВКонце делать
  начало
    если не п_Субс.Пустое тогда
      если п_Субс.КакЦелое = 0 тогда
        п_Субс.Очистить;
    если не п_ЦелСред.Пустое тогда
      если п_ЦелСред.КакЦелое = 0 тогда
        п_ЦелСред.Очистить;
    БазисПланирования.Следующая;
  конец;
конец;


</value>
		<param value="ПоддержкаЭкспортаВРоспись.abl" type="1" name="AccessCount">537</param>
		<param value="ПоддержкаЭкспортаВРоспись.abl" type="2" name="AccessDate">41656,3892943287</param>
		<param value="ПоддержкаЭкспортаВРоспись.abl" type="3" name="installversion">1.0</param>
		<param value="ПоддержкаЭкспортаВРоспись.abl" type="3" name="Export">SHISHKIND-NEW\shishkind\17.01.2014 9:27:40</param>
	</node>
</registry>
