// Запросы к АЦК для работы с КБК
Uses 'QueryKbkFormat';

var
  KbkCode: String;
  // exchange #3081
  // замена косгу для аубу
  // если =true, то нужно подставлять КВР вместо косгу.
  // реализовано тут, поскольку этот модуль есть везде: для импорта и
  // экспорта и используется для кбк. так удобнее чем выносить через
  // un_const/un_constref.
  // по умолчанию инициализируется =false.
  // после доработки задания этот параметр будет определяться из поля
  // AUBU_KVR_EXP_FLAG карточки орг., поэтому вместо переменной
  // v3081_ExchangeKES_for_aubu: boolean;
  // будет указан ид.орг., который будет заполняться при загрузке раздела файла


procedure InitializeQueryKBK;
begin

    try
      InitializeQueryKBKFormat;
//      v3081_ExchangeKES_for_aubu := FALSE;
      except
        ExceptionLog( 'Сбой QueryKbk.InitializeQueryKBK;');
    end;

end;

{~InitializeQueryKBK_ByConfig
  exchange #3081
  инициализация модуля с конфигурационными параметрами.
  здесь устанавливаем замену косгу-квр для эд аубу по конфигу.
  реализация здесь дает то, что это реализуется в одном месте вместе с
  описанием переменной хотя и добавляется новая сущность.}
procedure InitializeQueryKBK_ByConfig( aCfg: TStrings);
begin

    try
    (*
      v3081_ExchangeKES_for_aubu :=
            (UPPERCASE( aCfg.Values[ 'Работа по аналитическому коду расходов'])
              = 'КВР');

*)
      except
        ExceptionProc( 'InitializeQueryKBK_ByConfig');
    end;

end;


procedure FinalizeQueryKBK;
begin

    try
      FinalizeQueryKBKFormat;
      except
        ExceptionLog( 'Сбой QueryKbk.FinalizeQueryKBK;');
    end;

end;

{********************** KD - Классификатор видов дохода ***********************}

function KdCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kd Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0;
                        aCheckKES: boolean = TRUE): String;
begin

    try
      Result := CheckLengthCodeKD(
                          FormatKbk('KD', Code, Budget_Id, formatType),
                          aCheckKES);
      except
        ExceptionProc( 'KdCodeFormat');
    end;

end;

{********************** KDD - Дополнительный доходный код **********************}

function KddCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From KDD Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KddCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDD', Code, Budget_Id, formatType);
end;

{**************** KFSR - Функциональный классификатор расходов *****************}

function KfsrCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kfsr Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KfsrCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KFSR', Code, Budget_Id, formatType);
end;

{**************** KCSR - классификатор целевой статьи расходов *****************}

function KcsrCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kcsr Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KcsrCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0;
                        aCheckKES: boolean = TRUE): String;
begin

    try
      Result := CheckLengthCodeKCSR(
                          FormatKbk('KCSR', Code, Budget_Id, formatType),
                          aCheckKES);
      except
        ExceptionProc( 'KcsrCodeFormat');
    end;

end;

{********************* KVR - классификатор вида расходов ***********************}

function KvrCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kvr Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KvrCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KVR', Code, Budget_Id, formatType);
end;

{****************** KDF - дополнительный функциональный код ********************}

function KdfCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kdf Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdfCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDF', Code, Budget_Id, formatType);
end;

{****************** KDE - дополнительный экономический код *********************}

function KdeCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kde Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdeCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDE', Code, Budget_Id, formatType);
end;

{****************** KDR - дополнительный экономический код *********************}

function KdrCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kdr Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdrCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDR', Code, Budget_Id, formatType);
end;

{******************* KI - классификатор видов источников ***********************}

function KiCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Ki Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KiCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0;
                        aCheckKES: boolean = TRUE): String;
begin

    try
      Result := CheckLengthCodeKI(
                          FormatKbk('KI', Code, Budget_Id, formatType),
                          aCheckKES);
      except
        ExceptionProc( 'KiCodeFormat');
    end;

end;

{******************* KDI - дополнительный код источников ***********************}

function KdiCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kdi Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdiCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDI', Code, Budget_Id, formatType);
end;

{******************* KDT - дополнительный код источников ***********************}

function KdtCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kdt Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KdtCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KDT', Code, Budget_Id, formatType);
end;


{********* KADM - Классификатор администраторов поступлений и выбитий *********}

function KadmCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kadm Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end; {End KadmCode}

//function KadmFormat(Code: String;const Format = kbkMaskDefault): String;
function KadmCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KADM', Code, Budget_Id, formatType);
end; {End KadmCodeFormat}

{************* KES - экономический классификатор доходов/расходов **************}

function KesCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Kes Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end;
// Приводим к маске код
function KesCodeFormat( Code, Budget_Id: String;
                        const formatType: Integer = 0;
                        aCheckKES: boolean = TRUE): String;
begin

    try
      Result := CheckLengthCodeKES(
                          FormatKbk('KES', Code, Budget_Id, formatType),
                          aCheckKES);
      except
        ExceptionProc( 'KesCodeFormat');
    end;

end;
{==============================================================================}
{~KesRecord
  описание КОСГУ по коду КОСГУ и коду бюджета.
~params~
   aCode - КОСГУ.
   aBudget_Id - код бюджета.
~result~
   описание в виде XML - одна запись в корневом элементе или NULL.}
function KesRecord( aBudget_Id, aCode: Variant): Variant;
begin
  try
    
    try
      
      Result := QueryXml(
                    'Select * From Kes Where Budget_Id = ? And Code = ?',
                    [ aBudget_Id, aCode]);
      // возвращаем описание только одного КОСГУ. если найдено несколько
      // описаний, возвращаем NULL.
      if (Result.documentElement.ChildNodes.Length <> 1)
        then Result := NULL
        else Result := Result.documentElement.ChildNodes.item[ 0];

      
      except
        ExceptionLog( 'Сбой QueryKbk.KesRecord');
    end;
    finally
      
  end;
end;

{************************** KSD - Код подвида доходов **************************}

function KsdCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Ksd Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end; {End KsdCode}

function KsdCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KSD', Code, Budget_Id, formatType);
end; {End KsdCodeFormat}

{************************** KSI - Код вида источников **************************}

function KsiCode(Budget_Id, Code: Variant): String;
var
  sql: String;
begin
  sql := 'Select Code From Ksi Where Budget_Id = ? And Code = ?';
  Result := QueryField(sql, [Budget_Id, Code], 'CODE');
end; {End KsiCode}

function KsiCodeFormat(Code, Budget_Id: String; const formatType: Integer = 0): String;
begin
  Result := FormatKbk('KSI', Code, Budget_Id, formatType);
end; {End KsiCodeFormat}

{******************************* Код субсидии и инвестиции *********************************}
{~GetGrantInvestmentCodeByID
   Возвращает код субсидии и инвестиции из GrantInvestment.
   Если код отсутствует, тогда пусто.
   если aNullIsEmpty=true, то проверяется результат: если код субсидии =0
   (не указано), то в результате возвращается не 0 а пустая строка.
   подобная подпрограмме есть в QueryWork, но там запрос другой.}
function GetGrantInvestmentCodeByID(aID: String; aNullIsEmpty: boolean = FALSE): String;
begin

    try

      Result := '';
      if ( LENGTH( Trim(aID)) > 0) then begin
        Result := QueryField( 'Select Code From GrantInvestment Where Id = ?',
                              [ aID],
                              'CODE');
        if aNullIsEmpty then
          if (Result = '0')
            then Result := '';
      end;

      except
        ExceptionLog( 'Сбой QueryKbk.GetGrantInvestmentCodeByID');
    end;

end;

{******************************* Код субсидии *********************************}
{~GetPurposeFulgrantCodeOld
  Возвращает код субсидии. Если код отсутствует, тогда пусто.

  если aNullIsEmpty=true, то проверяется результат: если код субсидии =0
  (не указано), то в результате возвращается не 0 а пустая строка.

  это вариант до exchange #2412 - старый. }
function GetPurposeFulgrantCodeOld( aID: String;
                                   aNullIsEmpty: boolean = FALSE): String;
begin

    try
      Result := '';
      if Trim(aID) <> '' then begin
        Result := QueryField('Select Code From PurposeFulgrant Where Id = ?', [ aID], 'CODE');
        if aNullIsEmpty then
          if (Result = '0') then Result := '';
      end;

      except
        ExceptionLog( 'Сбой QueryKbk.GetPurposeFulgrantCodeOld');
    end;

end;

{~GetPurposeFulgrantCodeEx
  Возвращает код цели по идентификатору.
  Если идентификатор не указан (= пустая строка), тогда пусто.
  В этом варианте код цели =0 заменяется на пустую строку всегда (см.условие
  ниже).
  это новый вариант - доработка exchange #2412

  параметры
    aID - идентификатор кода цели в БД;
    aDop1,aDop2,aDop3 - доп коды (причем не важно какой доп.код в каком
                        параметре будет указан):
                           доп.ФК, доп.ЭК, доп.КР - расходы
                           0,0,доп.КД - доходы
                           0,0,доп.КИ - источники

ФТ 1.1. Если включен режим "Всегда", то всегда выгружать значение кода цели
  в соответствии с текущей реализацией скриптов в текстовые файлы.
ФТ 1.2. Если включен режим "Никогда", то по скриптам оставлять пустыми
  соответствующие поля в текстовых файлах.
ФТ 1.3. Если включен режим "С контролем в ФК", то при формировании текстового
  файла проверять в справочнике кодов целей (Справочники-Бюджет-Целевые
  назначения) для каждого PURPOSEFULGRANT_ID документа (строки документа,
  строки расшифровки документа) параметр "Контроль в ФК".
  Если параметр "Контроль в ФК" выключен, то  по скриптам соответствующие поля
  в текстовых файлах оставлять пустыми, иначе значение кода цели по
  PURPOSEFULGRANT_ID выгружать в соответствующее по скрипту поле текстового файла.
ФТ 1.4. Если включен режим "Указаны допкоды", то проверять значение доп. кодов
  в документе (строке документа) и если хотя бы один не равен 0
  (не равен "Не указан"), то выгружать значение кода цели в соответствии
  с текущей реализацией скриптов в текстовые файлы.
ФТ 1.5. Если включен режим "Не указаны допкоды", то если все доп. коды
  в документе (строке документа) равны 0 ("Не указан"), выгружать значение
  кода цели в соответствии с текущей реалиацией скриптов в текстовые файлы.}
function GetPurposeFulgrantCodeEx( aID: String; aDop1,aDop2,aDop3: string): String;
//aNullIsEmpty: boolean = FALSE): String;
var
  xSysParam: integer;
  xSQL: string;
  xDopCodesIsNull: boolean;
begin

    try
      Result := '';
(*
      case GetSysParam_PurposefulgrantFromZOR of
        //- всегда
        0: xResult := GetPurposeFulgrantCodeEx( aPurposefullGrandID,
                                                  aDop1,aDop2,aDop3);
        // никогда;
        1: xResult := '';

        // с контролем в ФК;
        2: if (QueryField( ' select count( * ) N from purposefulgrant pg'
                          +' where pg.controlfk_flag<>0 and pg.id=?',
                           [ aPurposefullGrandID],
                           'N') = '1')
             then xResult := GetPurposeFulgrantCodeEx( aPurposefullGrandID,
                                                        aDop1,aDop2,aDop3)
             else xResult := '';

        // - указаны допкоды;
        3: if (     (NOT (aDop1 in [ '', '0']))
                OR  (NOT (aDop2 in [ '', '0']))
                OR  (NOT (aDop3 in [ '', '0'])))
             then xResult := GetPurposeFulgrantCodeEx( aPurposefullGrandID,
                                                        aDop1,aDop2,aDop3)
             else xResult := '';

        // не указаны допкоды.
        4: if (     (aDop1 in [ '', '0'])
                AND (aDop2 in [ '', '0'])
                AND (aDop3 in [ '', '0']))
             then xResult := GetPurposeFulgrantCodeEx( aPurposefullGrandID,
                                                        aDop1,aDop2,aDop3)
             else xResult := '';

        else raise Exception.Create( 'Значение системного параметра "Выгружать код цели"'
                                    +' находится вне допустимого значения.');
      end;//case//
*)

      // системный параметр: «Передавать код цели из заявки на оплату расходов»
      // в разделе « Сервис - Системные параметры -Платежное поручение»
      xSysParam := GetSysParam_PurposefulgrantFromZOR;
      // проверка всех доп кодов на 0
      if (    (VarToStr( aDop1) = '0')
          AND (VarToStr( aDop2) = '0')
          AND (VarToStr( aDop3) = '0'))
        then xDopCodesIsNull := TRUE
        else xDopCodesIsNull := FALSE;

      case xSysParam of
        1: EXIT;      // ФТ 1.2
        3: if xDopCodesIsNull then EXIT; // ФТ 1.4
        4: if NOT xDopCodesIsNull then EXIT;  // ФТ 1.5
      end;//case//

      if (Trim( aID) <> '') then begin
        xSQL := 'Select Code From PurposeFulgrant Where Id = ?';
        // ФТ 1.3
        if (xSysParam = 2)
          then xSQL := xSQL + ' and controlfk_flag<>0';
        Result := QueryField( xSQL, [ aID], 'CODE');

        //if aNullIsEmpty then
          if (Result = '0') then Result := '';
      end;
      except
        ExceptionLog( 'Сбой QueryKbk.GetPurposeFulgrantCodeEx');
    end;

end;


{~GetPurposeFulgrantCodeExKBK
  возвращает код цели с учетом системного параметра и доп.кодов строки ЭД.
  при этом идентификатор кода цели определяется в зависимости от типа КБК
  из строки ЭД:
    PURPOSEFULGRANT_ID - для расходов
    PURPOSEFULGRANTD_ID - для доходов
    PURPOSEFULGRANTI_ID - для источников.
  параметры:
    aDocLine - строка ЭД;
    aTypeKBK - тип КБК:
                =10 - расходы;
                =20 - доходы;
                =31 или =32 - источники.
                прочее - вызывает исключение.
  результат
    код цели выполняется через функцию GetPurposeFulgrantCodeEx с полями
    доп.кодов в зависимости от типа КБК.}
function GetPurposeFulgrantCodeExKBK( aDocLine: variant; aTypeKBK: string): String;
begin

    try
      case aTypeKBK of
        // расходы
        '10': Result := GetPurposeFulgrantCodeEx(
                                    aDocLine.getAttribute('PURPOSEFULGRANT_ID'),
                                    aDocLine.getAttribute( 'KDR_CODE' ),
                                    aDocLine.getAttribute( 'KDE_CODE' ),
                                    aDocLine.getAttribute( 'KDF_CODE' ));
        // доходы
        '20': Result := GetPurposeFulgrantCodeEx(
                                    aDocLine.getAttribute('PURPOSEFULGRANTD_ID'),
                                    aDocLine.getAttribute( 'KDD_CODE' ),
                                    '0',
                                    '0');
        // источники
        '31','32': Result := GetPurposeFulgrantCodeEx(
                                    aDocLine.getAttribute('PURPOSEFULGRANTI_ID'),
                                    aDocLine.getAttribute( 'KDI_CODE' ),
                                    '0',
                                    '0');
        else Raise('не распознан тип КБК.');
      end;//case//

      except
        ExceptionLog( 'Сбой QueryKbk.GetPurposeFulgrantCodeExKBK');
    end;

end;

function GetPurposeFulgrantCodeExAnalKind( aDocLine: variant;
                                            aPrefix: string = ''): String;
begin

    try
      case aDocLine.getAttribute(aPrefix + 'ANAL_KIND') of
        '0': Result := GetPurposeFulgrantCodeExKBK( aDocLine, '10');
        '1': Result := GetPurposeFulgrantCodeExKBK( aDocLine, '20');
        '2': Result := GetPurposeFulgrantCodeExKBK( aDocLine, '31');
        else Raise('не распознано значение AnalKind.');
      end;//case//

      except
        ExceptionLog( 'Сбой QueryKbk.GetPurposeFulgrantCodeExAnalKind');
    end;

end;


//Возвращает ID субсидии по коду. Если код отсутствует, тогда пусто.
function GetPurposeFulgrantId(BudgetId, Code: String): String;
var
  Xml: Variant;
begin

    try
      Result := '';
      if Length(Code) > 20 then
        Raise(Format('%s неверное значение кода субсидии. Код субсидии не может' +
            ' быть больше 20 знаков.', [Code]));
      Xml := QueryXml('Select * From PurposeFulgrant Where Budget_Id = ?' +
        ' and code = ? and Block_Flag = 0', [BudgetId, Code]);
      if Xml.documentElement.ChildNodes.Length = 1 then
        Result := Xml.documentElement.ChildNodes.item[0].getAttribute('ID');
      except
        ExceptionProc( 'GetPurposeFulgrantId');
    end;

end;

{********************* Доп. функции работы с КБК ******************************}
//проверка нахождения кода в базе.
function KbkExists(BudgetId, Code, Table: String): Boolean;
begin

    try
      if (LENGTH( Code) <= 0)
        then Result := FALSE
        else Result := (QueryField( ' Select * From ' + Table
                                   +' Where Budget_Id = ? and Code = ?',
                                    [BudgetId, Code],
                                    'ID') <> '');
      except
        ExceptionLog( 'Сбой QueryKbk.KbkExists');
    end;

end;


{~GetKbkID
  получение идентификатора кода КБК (Code) из таблицы Table для бюджета BudgetId.
  результат:
    идентификатор или пустая строка.
  параметры
    aBudgetId - ид.бюджнта
    aCode - код
    aTable - таблица (КАДМ КД КОСГУ КИ КФСР КВСР КВР):
               Kadm - КАДМ
               Kd - КД
               Kes - КОСГУ
               Ki - КИ
               Kfsr - КФСР
               Kcsr - КЦСР
               Kvr - КВР}
function GetKbkID(aBudgetId, aCode, aTable: String): string;
var
  xTable: string;
begin

    try
      case UPPERCASE( aTable) of
        'КАДМ'  : xTable := 'Kadm';
        'КД'    : xTable := 'Kd';
        'КОСГУ' : xTable := 'Kes';
        'КИ'    : xTable := 'Ki';
        'КФСР'  : xTable := 'Kfsr';
        'КВСР'  : xTable := 'Kcsr';
        'КВР'   : xTable := 'Kvr';
        else raise( FORMAT( 'Таблица "%s" не распознана.', [ aTable]));
      end;//case//
      Result := QueryField(
                    FORMAT( 'Select ID From %s Where Budget_Id = ? and Code = ?',
                            [ xTable]),
                    [ aBudgetId, aCode],
                    'ID');

      except
        ExceptionLog( 'Сбой QueryKbk.GetKbkID');
    end;

end;


//КБК из ДЧБ
function Bk_Doh(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar): Variant;
var
  i, cnt: Integer;
  sql, kadm, kd, kes: String;
begin
  sql := 'Select C.Kadmd_Code, C.Kd_Code, C.Kesd_Code, KL.Description, KL.Begin_Date,' +
    ' KL.End_Date, KL.Change_Date, KadmL.Begin_Date Begin_Date1,' +
    ' KadmL.End_Date End_Date1, KadmL.Change_Date Change_Date1,' +
    ' KeL.Begin_Date Begin_Date2, KeL.End_Date End_Date2,' +
    ' KeL.Change_Date Change_Date2' +
    ' From IncBudget C' +
    ' Join Kd On (Kd.Code = C.Kd_Code And Kd.Budget_Id = ?)' +
    ' Join Kd_Lines KL on (KL.Master_Id = Kd.Id and KL.Unapproved = 0)' +
    ' Join Kadm on (Kadm.Code = C.Kadmd_Code And Kadm.Budget_Id = ?)' +
    ' Join Kadm_Lines KadmL on (KadmL.Master_Id = Kadm.Id and KadmL.Unapproved = 0)' +
    ' Join Kes on (Kes.Code = C.Kesd_Code And Kes.Budget_Id = ?)' +
    ' Join Kes_Lines KeL on (KeL.Master_Id = Kes.Id and KeL.Unapproved = 0)' +
    ' Where C.Budget_Id = ?' +
    ' Group By C.Kadmd_Code, C.Kd_Code, C.Kesd_Code, KL.Description, KL.Begin_Date,' +
    '   KL.End_Date, KL.Change_Date, KadmL.Begin_Date, KadmL.End_Date,' +
    '   KadmL.Change_Date, KeL.Begin_Date, KeL.End_Date, KeL.Change_Date' +
    ' Order By 1';
  Result := QueryXml(sql, [BudgetId, BudgetId, BudgetId, BudgetId]);
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kadm := CacheFormatKbk.Values['Kadm' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KADMD_CODE')];
    if Kadm = '' then
    begin
      Kadm := KadmCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMD_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kadm' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMD_CODE') +
          '=' + Kadm);
    end;
    Kd := CacheFormatKbk.Values['Kd' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KD_CODE')];
    if Kd = '' then
    begin
      Kd := KdCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KD_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kd' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KD_CODE') +
          '=' + Kd);
    end;
    Kes := CacheFormatKbk.Values['Kes' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KESD_CODE')];
    if Kes = '' then
    begin
      Kes := KesCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KESD_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kes' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KESD_CODE') +
          '=' + Kes);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kadm + Kd +
      Kes);
  end;
  ProgressBar.Position := 0;
end;

//КБК из ИЧБ
function Bk_Ist(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar): Variant;
var
  i, cnt: Integer;
  sql, kadm, ki, kes: String;
begin
  sql := 'Select C.Kadmi_Code, C.Ki_Code, C.Kesi_Code, KL.Description, KL.Begin_Date,' +
      '   KL.End_Date, KL.Change_Date, KadmL.Begin_Date Begin_Date1,' +
      '   KadmL.End_Date End_Date1, KadmL.Change_Date Change_Date1,' +
      '   KeL.Begin_Date Begin_Date2, KeL.End_Date End_Date2,' +
      '   KeL.Change_Date Change_Date2' +
      ' From SrcBudget C' +
      ' Join Ki On (Ki.Code = C.Ki_Code And Ki.Budget_Id = ?)' +
      ' Join Ki_Lines KL on (KL.Master_Id = Ki.Id and KL.Unapproved = 0)' +
      ' Join Kadm on (Kadm.Code = C.Kadmi_Code And Kadm.Budget_Id = ?)' +
      ' Join Kadm_Lines KadmL on (KadmL.Master_Id = Kadm.Id and KadmL.Unapproved = 0)' +
      ' Join Kes on (Kes.Code = C.Kesi_Code And Kes.Budget_Id = ?)' +
      ' Join Kes_Lines KeL on (KeL.Master_Id = Kes.Id and KeL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Group By C.Kadmi_Code, C.Ki_Code, C.Kesi_Code, KL.Description, KL.Begin_Date,' +
      '   KL.End_Date, KL.Change_Date, KadmL.Begin_Date, KadmL.End_Date,' +
      '   KadmL.Change_Date, KeL.Begin_Date, KeL.End_Date, KeL.Change_Date' +
      ' Order By 1';
  Result := QueryXml(Sql, [BudgetId, BudgetId, BudgetId, BudgetId]);
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kadm := CacheFormatKbk.Values['Kadm' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KADMI_CODE')];
    if Kadm = '' then
    begin
      Kadm := KadmCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMI_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kadm' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMI_CODE') +
          '=' + Kadm);
    end;
    Ki := CacheFormatKbk.Values['Ki' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KI_CODE')];
    if Ki = '' then
    begin
      Ki := KiCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KI_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Ki' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KI_CODE') +
          '=' + Ki);
    end;
    Kes := CacheFormatKbk.Values['Kes' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KESI_CODE')];
    if Kes = '' then
    begin
      Kes := KesCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KESI_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kes' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KESI_CODE') +
          '=' + Kes);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kadm + Ki +
      Kes);
  end;
  ProgressBar.Position := 0;
end;

//КБК из РЧБ
function Bk_Ras(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar): Variant;
var
  i, cnt: Integer;
  sql, plan: String;
  Kadm, Kfsr, Kcsr, Kvr, Kes: String;
  Xml: Variant;
begin
  sql := 'Select C.Kadmr_Code, C.Kfsr_Code, C.Kcsr_Code, C.Kvr_Code, C.Kesr_Code,' +
      '   KadmL.Caption Kadmr_Desc, KfL.Caption Kfsr_Desc,' +
      '   KcL.Caption Kcsr_Desc, KvL.Caption Kvr_Desc,' +
      '   KeL.Caption Kesr_Desc, KcL.Begin_Date,' +
      '   KcL.End_Date, KcL.Change_Date, KvL.Begin_Date Begin_Date1,' +
      '   KvL.End_Date End_Date1, KvL.Change_Date Change_Date1,' +
      '   KfL.Begin_Date Begin_Date2, KfL.End_Date End_Date2,' +
      '   KfL.Change_Date Change_Date2, KeL.Begin_Date Begin_Date3,' +
      '   KeL.End_Date End_Date3, KeL.Change_Date Change_Date3,' +
      '   KadmL.Begin_Date Begin_Date4, KadmL.End_Date End_Date4,' +
      '   KadmL.Change_Date Change_Date4,' +
      '   (case when C.Bring_Lim_Ass in (1,3) then 1 else 0 end) Lim' +
      ' From ExpBudget C' +
      ' Join Kcsr On (Kcsr.Code = C.Kcsr_Code And Kcsr.Budget_Id = ?)' +
      ' Join Kcsr_Lines KcL on (KcL.Master_Id = Kcsr.Id and KcL.Unapproved = 0)' +
      ' Join Kvr On (Kvr.Code = C.Kvr_Code And Kvr.Budget_Id = ?)' +
      ' Join Kvr_Lines KvL on (KvL.Master_Id = Kvr.Id and KvL.Unapproved = 0)' +
      ' Join Kadm on (Kadm.Code = C.Kadmr_Code And Kadm.Budget_Id = ?)' +
      ' Join Kadm_Lines KadmL on (KadmL.Master_Id = Kadm.Id and KadmL.Unapproved = 0)' +
      ' Join Kfsr on (Kfsr.Code = C.Kfsr_Code And Kfsr.Budget_Id = ?)' +
      ' Join Kfsr_Lines KfL on (KfL.Master_Id = Kfsr.Id and KfL.Unapproved = 0)' +
      ' Join Kes on (Kes.Code = C.Kesr_Code And Kes.Budget_Id = ?)' +
      ' Join Kes_Lines KeL on (KeL.Master_Id = Kes.Id and KeL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Group By C.Kadmr_Code, C.Kfsr_Code, C.Kcsr_Code, C.Kvr_Code, C.Kesr_Code,' +
      '   KadmL.Caption, KfL.Caption, KcL.Caption, KvL.Caption,' +
      '   KeL.Caption, KcL.Begin_Date, KcL.End_Date,' +
      '   KcL.Change_Date, KvL.Begin_Date, KvL.End_Date, KvL.Change_Date,' +
      '   KadmL.Begin_Date, KadmL.End_Date, KadmL.Change_Date, KfL.Begin_Date,' +
      '   KfL.End_Date, KfL.Change_Date, KeL.Begin_Date, KeL.End_Date,' +
      '   KeL.Change_Date, C.Bring_Lim_Ass' +
      ' Order By 1';
  if AzkDb = '2' then
  begin
    plan := 'PLAN (SORT (Join (C Index' +
      ' (FK_EXPBUDGET_BUDGET), Kes Index (UQ_KES),Kfsr Index (UQ_KFSR),' +
      ' Kadm Index (UQ_KADM),Kcsr Index (UQ_KCSR), Kvr Index (UQ_KVR),' +
      ' Kcl Index (FK_KCSR_LINES_KCSR), Kvl INDEX (FK_KVR_LINES_KVR),' +
      ' Kadml Index (FK_KADM_LINES_KADM), Kfl Index (FK_KFSR_LINES_KFSR),' +
      ' Kel Index (FK_KES_LINES_KES))))';
    Xml := QueryXml('Select R.RDB$CONSTRAINT_NAME CONSTRAINT_NAME,' +
      ' R.RDB$INDEX_NAME REFINDEXNAME' +
      ' From RDB$RELATION_CONSTRAINTS R' +
      ' Where R.RDB$CONSTRAINT_NAME in (''FK_EXPBUDGET_BUDGET'', ''UQ_KES'',' +
      ' ''UQ_KFSR'', ''UQ_KADM'', ''UQ_KCSR'', ''UQ_KVR'', ''FK_KCSR_LINES_KCSR'',' +
      ' ''FK_KVR_LINES_KVR'', ''FK_KADM_LINES_KADM'', ''FK_KFSR_LINES_KFSR'',' +
      ' ''FK_KES_LINES_KES'')');
    Xml := Xml.documentElement;
    // запрос должен вернуть 11 индексов
    if Xml.ChildNodes.Length = 11 then
    begin
      for i := 0 to Xml.ChildNodes.Length - 1 do
      begin
        Xml := Xml.childNodes.item[i];
        Xml.setAttribute('CONSTRAINT_NAME',
          Trim(Xml.getAttribute('CONSTRAINT_NAME')));
        Xml.setAttribute('REFINDEXNAME',
          Trim(Xml.getAttribute('REFINDEXNAME')));
        plan := StringReplace(plan, Xml.getAttribute('CONSTRAINT_NAME'),
          Xml.getAttribute('REFINDEXNAME'));
        Xml := Xml.parentNode;
      end;
      sql := StringReplace(sql, 'Order By 1',  plan + ' Order By 1');
    end
    else
      WriteLog('Не все индексы, используемые в плане запроса, найдены в БД.' +
        ' План запроса оставлен по умолчанию.');
  end;
  Result := QueryXml(Sql, [BudgetId, BudgetId, BudgetId, BudgetId, BudgetId,
    BudgetId]);
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kadm := CacheFormatKbk.Values['Kadm' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE')];
    if Kadm = '' then
    begin
      Kadm := KadmCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kadm' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE') +
          '=' + Kadm);
    end;
    Kfsr := CacheFormatKbk.Values['Kfsr' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KFSR_CODE')];
    if Kfsr = '' then
    begin
      Kfsr := KfsrCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KFSR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kfsr' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KFSR_CODE') +
          '=' + Kfsr);
    end;
    Kcsr := CacheFormatKbk.Values['Kcsr' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE')];
    if Kcsr = '' then
    begin
      Kcsr := KcsrCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kcsr' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE') +
          '=' + Kcsr);
    end;
    Kvr := CacheFormatKbk.Values['Kvr' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE')];
    if Kvr = '' then
    begin
      Kvr := KvrCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kvr' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE') +
          '=' + Kvr);
    end;
    Kes := CacheFormatKbk.Values['Kes' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KESR_CODE')];
    if Kes = '' then
    begin
      Kes := KesCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KESR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kes' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KESR_CODE') +
          '=' + Kes);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kadm + Kfsr +
      Kcsr + Kvr + Kes);
  end;
  ProgressBar.Position := 0;
end;

//Данные по КЦСР
function Bk_Kcsr(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar; Ref: Boolean = False): Variant;
var
  i, cnt: Integer;
  sql, kcsr: String;
begin
  if not Ref then
  begin
    sql := 'Select C.Kcsr_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date' +
      ' From ExpBudget C' +
      ' Join Kcsr On (Kcsr.Code = C.Kcsr_Code And Kcsr.Budget_Id = ?)' +
      ' Join Kcsr_Lines KL on (KL.Master_Id = Kcsr.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Group By C.Kcsr_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date';
    Result := QueryXml(Sql, [BudgetId, BudgetId]);
  end
  else begin
    sql := 'Select distinct C.Code Kcsr_Code, KL.Description, KL.Caption,' +
      ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
      ' From Kcsr C' +
      ' Join Kcsr_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?';
    Result := QueryXml(Sql, [BudgetId]);
  end;
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kcsr := CacheFormatKbk.Values['Kcsr' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE')];
    if Kcsr = '' then
    begin
      Kcsr := KcsrCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kcsr' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KCSR_CODE') +
          '=' + Kcsr);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kcsr);
  end;
  ProgressBar.Position := 0;
end;

//Данные по КВР
function Bk_Kvr(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar; Ref: Boolean = False): Variant;
var
  i, cnt: Integer;
  sql, Kvr: String;
begin
  if not Ref then
  begin
    sql := 'Select C.Kvr_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date' +
      ' From ExpBudget C' +
      ' Join Kvr On (Kvr.Code = C.Kvr_Code And Kvr.Budget_Id = ?)' +
      ' Join Kvr_Lines KL on (KL.Master_Id = Kvr.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Group By C.Kvr_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date';
    Result := QueryXml(Sql, [BudgetId, BudgetId]);
  end
  else begin
    sql := 'Select distinct C.Code Kvr_Code, KL.Description, KL.Caption,' +
      ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From Kvr C' +
        ' Join Kvr_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?';
    Result := QueryXml(Sql, [BudgetId]);
  end;
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kvr := CacheFormatKbk.Values['Kvr' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE')];
    if Kvr = '' then
    begin
      Kvr := KvrCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kvr' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KVR_CODE') +
          '=' + Kvr);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kvr);
  end;
  ProgressBar.Position := 0;
end;

//Данные по Кадм
function Bk_Kadm(BudgetId: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar; Ref: Boolean = False): Variant;
var
  i, cnt: Integer;
  sql, Kadm: String;
begin
  if not Ref then
  begin
    sql := 'Select C.Kadmr_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date' +
      ' From ExpBudget C' +
      ' Join Kadm On (Kadm.Code = C.Kadmr_Code And Kadm.Budget_Id = ?)' +
      ' Join Kadm_Lines KL on (KL.Master_Id = Kadm.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Union' +
      ' Select C.Kadmd_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date' +
      ' From IncBudget C' +
      ' Join Kadm On (Kadm.Code = C.Kadmd_Code And Kadm.Budget_Id = ?)' +
      ' Join Kadm_Lines KL on (KL.Master_Id = Kadm.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?' +
      ' Union' +
      ' Select C.Kadmi_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
      ' KL.Change_Date, KL.End_Date' +
      ' From SrcBudget C' +
      ' Join Kadm On (Kadm.Code = C.Kadmi_Code And Kadm.Budget_Id = ?)' +
      ' Join Kadm_Lines KL on (KL.Master_Id = Kadm.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?';
    Result := QueryXml(Sql, [BudgetId, BudgetId, BudgetId, BudgetId, BudgetId,
      BudgetId]);
  end
  else begin
    sql := 'Select distinct C.Code Kadmr_Code, KL.Description, KL.Caption,' +
      ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
      ' From Kadm C' +
      ' Join Kadm_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
      ' Where C.Budget_Id = ?';
    Result := QueryXml(Sql, [BudgetId]);
  end;
  cnt := Result.documentElement.ChildNodes.Length;
  ProgressBar.Max := cnt;
  for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
  begin
    ProgressBar.Position := i + 1;
    StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
      IntToStr(i + 1) + ' из ' + IntToStr(cnt);
    Kadm := CacheFormatKbk.Values['Kadm' +
      Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE')];
    if Kadm = '' then
    begin
      Kadm := KadmCodeFormat(
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE'),
          BudgetId);
      CacheFormatKbk.Add('Kadm' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KADMR_CODE') +
          '=' + Kadm);
    end;
    Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Kadm);
  end;
  ProgressBar.Position := 0;
end;

//данные по подвидам доходов и видам источников.
function Bk_Ksdi(BudgetId: String; Mode: String; StatusBar: TStatusBar;
  ProgressBar: TProgressBar; Ref: Boolean = False): Variant;
var
  i, cnt: Integer;
  sql, Ksd, Ksi: String;
  Xml: Variant;
begin
  if Mode = 'коды подвидов доходов и коды видов источников' then
    if Ref then
    begin
      //получаем подвиды доходов.
      sql := 'Select C.Code Ksd_Code, KL.Description, KL.Caption,' +
        ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From Ksd C' +
        ' Join Ksd_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?';
      Result := QueryXml(sql, [BudgetId]);
      cnt := Result.documentElement.ChildNodes.Length;
      ProgressBar.Max := cnt;
      for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
      begin
        ProgressBar.Position := i + 1;
        StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
          IntToStr(i + 1) + ' из ' + IntToStr(cnt);
        Ksd := CacheFormatKbk.Values['Ksd' +
          Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE')];
        if Ksd = '' then
        begin
          Ksd := KsdCodeFormat(
            Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE'),
              BudgetId);
          CacheFormatKbk.Add('Ksd' +
            Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE') +
              '=' + Ksd);
         end;
        Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksd);
      end;
      ProgressBar.Position := 0;
      //получаем коды видов источников, которые не пересеклись с кодами
      //подвидов доходов
      sql := 'Select C.Code Ksi_Code, KL.Description, KL.Caption,' +
        ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From Ksi C' +
        ' Join Ksi_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ? and ' +
        '   not exists (Select 1 From Ksd Where C.code = Ksd.code)';
      Xml := QueryXml(sql, [BudgetId]);
      cnt := Xml.documentElement.ChildNodes.Length;
      ProgressBar.Max := cnt;
      for i := 0 to Xml.documentElement.ChildNodes.Length - 1 do
      begin
        ProgressBar.Position := i + 1;
        StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
          IntToStr(i + 1) + ' из ' + IntToStr(cnt);
        Ksi := CacheFormatKbk.Values['Ksi' +
          Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE')];
        if Ksi = '' then
        begin
          Ksi := KsiCodeFormat(
            Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE'),
              BudgetId);
          CacheFormatKbk.Add('Ksi' +
            Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE') +
              '=' + Ksi);
        end;
        Xml.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksi);
      end;
      ProgressBar.Position := 0;
      //добавляем коды видов источников в выборку подвидов доходов
      for i := 0 to Xml.documentElement.ChildNodes.Length - 1 do
        Result.documentElement.appendChild(Xml.documentElement.childNodes.Item[i].CloneNode(False));
    end
    else begin
      //получаем подвиды доходов из ДЧБ
      sql := ' Select Ksd.Code Ksd_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        ' KL.Change_Date, KL.End_Date' +
        ' From IncBudget C' +
        ' Join Kd On (Kd.Code = C.Kd_Code And Kd.Budget_Id = ?)' +
        ' Join Ksd On (Ksd.Code = Kd.Ksd_code and Ksd.Budget_id = ?)' +
        ' Join Ksd_Lines KL on (KL.Master_Id = Ksd.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?' +
        ' Group By Ksd.Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        '   KL.Change_Date, KL.End_Date';
      Result := QueryXml(sql, [BudgetId, BudgetId, BudgetId]);
      cnt := Result.documentElement.ChildNodes.Length;
      ProgressBar.Max := cnt;
      for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
      begin
        ProgressBar.Position := i + 1;
        StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
          IntToStr(i + 1) + ' из ' + IntToStr(cnt);
        Ksd := CacheFormatKbk.Values['Ksd' +
          Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE')];
        if Ksd = '' then
        begin
          Ksd := KsdCodeFormat(
            Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE'),
              BudgetId);
          CacheFormatKbk.Add('Ksd' +
            Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE') +
              '=' + Ksd);
         end;
        Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksd);
      end;
      ProgressBar.Position := 0;
      //получаем коды видов источников из ИБ, которые не пересеклись с кодами
      //подвидов доходов из ДЧБ
      sql := 'Select Ksi.Code Ksi_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        ' KL.Change_Date, KL.End_Date' +
        ' From SrcBudget C' +
        ' Join Ki On (Ki.Code = C.Ki_Code And Ki.Budget_Id = ?)' +
        ' Join Ksi On (Ksi.Code = Ki.Ksi_code and Ksi.Budget_id = ?)' +
        ' Join Ksi_Lines KL on (KL.Master_Id = Ksi.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ? and not exists' +
        '   (Select 1 ' +
        '   From IncBudget Ib' +
        '   Join Kd on (Kd.Code = Ib.Kd_Code and Kd.Budget_Id = ?)' +
        '   Join Ksd on Kd.Ksd_Code = Ksd.Code and Ksd.Budget_Id = ?' +
        '   Where Ksd.Code = Ksi.Code)' +
        ' Group By Ksi.Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        ' KL.Change_Date, KL.End_Date';
      Xml := QueryXml(sql, [BudgetId, BudgetId, BudgetId, BudgetId, BudgetId]);
      cnt := Xml.documentElement.ChildNodes.Length;
      ProgressBar.Max := cnt;
      for i := 0 to Xml.documentElement.ChildNodes.Length - 1 do
      begin
        ProgressBar.Position := i + 1;
        StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
          IntToStr(i + 1) + ' из ' + IntToStr(cnt);
        Ksi := CacheFormatKbk.Values['Ksi' +
          Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE')];
        if Ksi = '' then
        begin
          Ksi := KsiCodeFormat(
            Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE'),
              BudgetId);
          CacheFormatKbk.Add('Ksi' +
            Xml.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE') +
              '=' + Ksi);
        end;
        Xml.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksi);
      end;
      ProgressBar.Position := 0;
      //добавляем коды видов источников в выборку подвидов доходов
      for i := 0 to Xml.documentElement.ChildNodes.Length - 1 do
        Result.documentElement.appendChild(Xml.documentElement.childNodes.Item[i].CloneNode(False));
    end;
  if Mode = 'коды подвидов доходов' then
  begin
    if Ref then
    begin
      sql := 'Select C.Code Ksd_Code, KL.Description, KL.Caption,' +
        ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From Ksd C' +
        ' Join Ksd_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?';
      Result := QueryXml(sql, [BudgetId]);
    end
    else begin
      sql := ' Select Ksd.Code Ksd_Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        ' KL.Change_Date, KL.End_Date' +
        ' From IncBudget C' +
        ' Join Kd On (Kd.Code = C.Kd_Code And Kd.Budget_Id = ?)' +
        ' Join Ksd On (Ksd.Code = Kd.Ksd_code and Ksd.Budget_id = ?)' +
        ' Join Ksd_Lines KL on (KL.Master_Id = Ksd.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?' +
        ' Group By Ksd.Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        '   KL.Change_Date, KL.End_Date';
      Result := QueryXml(sql, [BudgetId, BudgetId, BudgetId]);
    end;
    cnt := Result.documentElement.ChildNodes.Length;
    ProgressBar.Max := cnt;
    for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
    begin
      ProgressBar.Position := i + 1;
      StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
        IntToStr(i + 1) + ' из ' + IntToStr(cnt);
      Ksd := CacheFormatKbk.Values['Ksd' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE')];
      if Ksd = '' then
      begin
        Ksd := KsdCodeFormat(
          Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE'),
            BudgetId);
        CacheFormatKbk.Add('Ksd' +
          Result.documentElement.ChildNodes.item[i].getAttribute('KSD_CODE') +
            '=' + Ksd);
      end;
      Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksd);
    end;
    ProgressBar.Position := 0;
  end;
  if Mode = 'коды видов источников' then
  begin
    if Ref then
    begin
      sql := 'Select C.Code Ksi_Code, KL.Description, KL.Caption,' +
        ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From Ksi C' +
        ' Join Ksi_Lines KL on (KL.Master_Id = C.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?';
       Result := QueryXml(sql, [BudgetId]);
    end
    else begin
      sql := 'Select Ksi.Code Ksi_Code, KL.Description, KL.Caption,' +
        ' KL.Begin_Date, KL.Change_Date, KL.End_Date' +
        ' From SrcBudget C ' +
        ' Join Ki On (Ki.Code = C.Ki_Code And Ki.Budget_Id = ?)' +
        ' Join Ksi On (Ksi.Code = Ki.Ksi_Code and Ksi.Budget_id = ?)' +
        ' Join Ksi_Lines KL on (KL.Master_Id = Ksi.Id and KL.Unapproved = 0)' +
        ' Where C.Budget_Id = ?' +
        ' Group By Ksi.Code, KL.Description, KL.Caption, KL.Begin_Date,' +
        '   KL.Change_Date, KL.End_Date';
      Result := QueryXml(sql, [BudgetId, BudgetId, BudgetId]);
    end;
    cnt := Result.documentElement.ChildNodes.Length;
    ProgressBar.Max := cnt;
    for i := 0 to Result.documentElement.ChildNodes.Length - 1 do
    begin
      ProgressBar.Position := i + 1;
      StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
        IntToStr(i + 1) + ' из ' + IntToStr(cnt);
      Ksi := CacheFormatKbk.Values['Ksi' +
        Result.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE')];
      if Ksi = '' then
      begin
        Ksi := KsiCodeFormat(
          Result.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE'),
            BudgetId);
        CacheFormatKbk.Add('Ksi' +
          Result.documentElement.ChildNodes.item[i].getAttribute('KSI_CODE') +
            '=' + Ksi);
      end;
      Result.documentElement.ChildNodes.item[i].setAttribute('CODE', Ksi);
    end;
    ProgressBar.Position := 0;
  end;
end;

{~Bk_GrantInvestment
//данные по подвидам доходов и видам источников.
// xFilterGrantInvestment - фильтр выбора субсидий и инвестиций.
// это перечень ID (GrantInvesment) через запятую или пустая строка.
  exchange #3081
  добавлен вариант выгрузки с косгу или без.}
function Bk_GrantInvestment( BudgetId, Org_Id: String; StatusBar: TStatusBar;
                              aProgressBar: TProgressBar;
                              xFilterGrantInvestment: string;
                              aWorkDate: TDateTime;
                              aCheckKES: boolean): Variant;
var
  i, cnt, j: Integer;
  sql, Kadm, Kfsr, Kcsr, Kvr, Kes: String;
  Xml: Variant;
  xID: string;
  xResultNode: Variant;
  xQuery: TRunQuery;    // exchange #2724
  xNPA_ID: string;
begin

    try
      // exchange #2741
      // для определения НПА добавлено поле NPA_ID
      // в результате получается объединение строк с названием НПА.
      // когда НПА будет несколько то строк результата будет *НПА.
      // останется проверить для строк с кодом ID наличие нескольких значений
      // в поле NPA_ID.
      Sql := ' Select G.ID, G.Code, G.Caption, L.Caption Npa_Caption, L.Act_Date,'
       +' L.Act_Number, Gline.Kfsr_Code,L.ID NPA_ID,' +
        ' Gline.Kcsr_Code, Gline.Kvr_Code, Gline.Kesr_Code, Gline.Kadmr_Code, '
       +' G.Org_id, F.Code FAIP_Code'
       +' From Grantinvestment G' +
        ' Left Join Grantinv_Lawact Gl on Gl.GrantInvestment_Id = G.Id' +
        ' Left Join Pl_Lawact L on Gl.Lawact_Id = L.Id' +
        ' Left Join Grantinv_Line Gline on Gline.GrantInvestment_Id = G.Id'
      // exchange #2807
      // выгрузка кода ФАИП (F.Code FAIP_Code) из справочника ФАИП pl_faip_obj
      // по ссылке из поля кода субсидии (pl_faip_obj_id)
      // совместимость с АЦК-Ф не ниже 2.34.0.177
       +' left join pl_faip_obj F on F.id = G.pl_faip_obj_id'
       +' Where G.Budget_Id = ? and (G.Org_id = ?'

       +')'
        // exchange #2645
        // добавлена проверка даты закрытия и открытия строк НПА
        // допускается выгружать только одну строку, вот и приходится проверять
        // какую из нескольких выбрать.
       +' and (L.start_date is null or L.start_date<=?)'
       +' and (L.end_date is null or L.end_date>?)';// or G.Org_id = 0)';
      // Exchange #2334
      // добавлен фильтр строк субсидий и инвестиций.
      // exchange #2782
      // поправлен фильтр в запросе
      if (xFilterGrantInvestment <> '')
        then Sql := Sql + BuildQueryByIDListString( xFilterGrantInvestment,
                                                    'G.ID',
                                                    ' and %s');
        //(G.ID in (' + xFilterGrantInvestment + '))';

      // exchange #2724
      // из-за проблем перевода даты из variant, приходится вместо QueryXml
      // делать запрос через TRunQuery.
      xQuery:= TRunQuery.Create;
      try
        xQuery.AddStr( BudgetId);
        xQuery.AddStr( Org_Id);
        xQuery.AddDate( aWorkDate);
        xQuery.AddDate( aWorkDate);
        Result := QueryRun( xQuery, sql);

        {
      Result := QueryXml( sql,
                          [ BudgetId,
                            Org_Id,
                            // дату передаем не как дату а как строку
                            // аналог: Tat_impbank.pfs
                            FormatDateTime('yyyy-mm-dd 00:00:00', aWorkDate),
                            FormatDateTime('yyyy-mm-dd 00:00:00', aWorkDate)]);
                            }
        finally
          xQuery.Free;
      end;
      cnt := Result.documentElement.ChildNodes.Length;
      if (cnt > 0) then begin
        aProgressBar.Max := cnt;
        for i := 0 to Result.documentElement.ChildNodes.Length - 1 do begin
          xResultNode := Result.documentElement.ChildNodes.item[i];
          aProgressBar.Position := i + 1;
          StatusBar.SimpleText := 'Приведение КБК в соответсвие с маской. Обработано: ' +
            IntToStr(i + 1) + ' из ' + IntToStr(cnt);

          // exchange #2645
          // пробуем найти еще строку (помимо текущей), имеющей разный НПА
          // относящийся к одному коду
          // если нашли - прерываем загрузку и даем сообщение.
          // exchange #2471
          // для каждой строки сохраняем ID кода и ID кода НПА.
          // если будет несколько НПА для кодов субсидий, то будем искать до
          // первого отличного NPA_ID от текущей строки кода.
          xID := xResultNode.getAttribute('ID');
          xNPA_ID := xResultNode.getAttribute('NPA_ID');
          for j := 0 to Result.documentElement.ChildNodes.Length - 1 do
            if (j <> i) then
              if ( xID = Result.documentElement.ChildNodes.item[j].getAttribute('ID')) then
                if ( xNPA_ID <> Result.documentElement.ChildNodes.item[j].getAttribute('NPA_ID'))
                  then begin
                    WriteLog( FORMAT( 'Для кода целевой субсидии %s нет возможности определить НПА.',
                                        [ xResultNode.getAttribute('CODE')]));
                    ShowMessage( FORMAT( 'Для кода целевой субсидии %s нет возможности определить НПА.',
                                        [ xResultNode.getAttribute('CODE')]));
                    Result := NULL;
                    EXIT;
                  end;

          // exchange #3081 - унификация кода
          xResultNode.setAttribute(
                    'CODE_KBK',
                    GetRuleKBKLine_R(
                        xResultNode.getAttribute('KADMR_CODE'),
                        xResultNode.getAttribute('KFSR_CODE'),
                        xResultNode.getAttribute('KCSR_CODE'),
                        xResultNode.getAttribute('KVR_CODE'),
                        xResultNode.getAttribute('KESR_CODE'),
                        BudgetId,
                        aCheckKES));
          {
          Kadm := KadmCodeFormat( xResultNode.getAttribute('KADMR_CODE'), BudgetId);
          Kfsr := KfsrCodeFormat( xResultNode.getAttribute('KFSR_CODE'), BudgetId);
          Kcsr := KcsrCodeFormat( xResultNode.getAttribute('KCSR_CODE'), BudgetId);
          Kvr := KvrCodeFormat( xResultNode.getAttribute('KVR_CODE'), BudgetId);
          Kes := KesCodeFormat( xResultNode.getAttribute('KESR_CODE'), BudgetId);
          xResultNode.setAttribute('CODE_KBK', Kadm + Kfsr + Kcsr + Kvr + Kes);
          }
        end;
        aProgressBar.Position := 0;
      end;
      except
        ExceptionProc( 'Bk_GrantInvestment');
    end;

end;


//проверяет присутсвие указанного kif в базе, если киф не найден и заполнен
//параметр def (def не проверяется на присутсвие в базе), то возвращает его
//значение, иначе пусто. Если kif есть в базе, то возвращает его.
function KifExists(Kif: String; Def: String = ''): String;
begin
  if Kif <> '' then
    Result := IfThen(QueryField('Select Id From Finsource Where Id = ?',
      [Kif], 'ID') <> '', Kif, Def)
  else Result := Def;
end;


{~KBKExtend
  дополняем КБК до 20-ти символов нулями слева.
  exchange #3081
  из ацк-ф значение FK_BUDGET_CODE может приезжать 23 символа,
  поэтому значение обрезается по первым 20 знакам.
  соответственно справа 3 цифры (КОСГУ) будут отсечены.}
function KBKExtend( aKBK: string): string;
begin

    try
      if (LENGTH( aKBK) = 20)
        then Result := aKBK
        else
          if (LENGTH( aKBK) > 20)
            then Result := COPY( aKBK, 1, 20)
            else Result := COPY( '0000000000000000000000',
                                 1, 20 - LENGTH( aKBK)) + aKBK;
//    while (LENGTH( Result) < 20) do Result := '0' + Result;
      except
        ExceptionProc( 'KBKExtend');
    end;

end;
{------------------------------------------------------------------------------}
function SearchUnicalIndustryCodeNull( aBudgetID: string): string;
var
  xXml: Variant;
begin

    try
      Result := QueryField(   ' select i.ID from INDUSTRYCODE i '
                             +' where i.code=? and lower(i.caption) '
                             +' like ? and i.budget_id=?',
                               // exchange #3081
                               // здесь нужно указывать полный код
                               // с учетом маски!
                             [ FormatKbk( 'INDUSTRYCODE', '0', aBudgetID),
                                'не указан%',
                                aBudgetID],
                             'ID');

      except
        ExceptionLog( 'Сбой QueryKbk.SearchUnicalIndustryCodeNull');
    end;

end;
{------------------------------------------------------------------------------}
{~SearchUnicalIndustryCode
  поиск аналитической строки.
  exchange #3100
  косгу может быть незаполнен, поэтому, если указано что косгу заполнен
  (aFillKES=true), проверяем, если поле aKES пустое, то ищем аналит.строку
  только по КИФ.}
function SearchUnicalIndustryCode( aBudgetID, aKIF, aKES, aLS_ID: string;
                                   aKVR: string;
                                   aFillKES, aFillKVR: boolean): string;
var
  xXml: Variant;
begin

    try
      xXml := NULL;

      if aFillKES then
        {if (LENGHT( aKES) > 0)
          then} xXml := QueryXml2(
                           ' select distinct aubub.industrycode_id ID '
                          +' from aububudget aubub '
                          +' where aubub.budget_id=? and aubub.fsr_id=? '
                          +' and aubub.kesr_code=? and aubub.pay_acc_id=? ',
                          [ aBudgetID,
                            aKIF,
                            aKES,
                            aLS_ID])
{          else xXml := QueryXml(
                           ' select distinct aubub.industrycode_id ID '
                          +' from aububudget aubub '
                          +' where aubub.budget_id=? and aubub.fsr_id=? '
                          +' and aubub.pay_acc_id=? ',
                          [ aBudgetID,
                            aKIF,
                            aLS_ID])};
      if aFillKVR
        then xXml := QueryXml2(
                         ' select distinct aubub.industrycode_id ID '
                        +' from aububudget aubub '
                        +' where aubub.budget_id=? and aubub.fsr_id=? '
                        +' and aubub.kvr_code=? and aubub.pay_acc_id=? ',
                        [ aBudgetID,
                          aKIF,
                          aKVR,
                          aLS_ID]);

      if VarIsNULL( xXml)
        then Result := SearchUnicalIndustryCodeNull( aBudgetID)
        else
          if (xXml.childNodes.Length = 1)
            then Result := xXml.childNodes.Item[0].GetAttribute( 'ID')
            else Result := SearchUnicalIndustryCodeNull( aBudgetID);

      except
        ExceptionLog( 'Сбой QueryKbk.SearchUnicalIndustryCode');
    end;

end;


function SearchUnicalGrantinvestmentCodeNull( aBudgetID: string): string;
var
  xXml: Variant;
begin

    try
      Result := QueryField(   ' select i.ID from GRANTINVESTMENT i '
                             +' where i.code=? and lower(i.caption) '
                             +' like ? and i.budget_id=?',
                             // для символьных КБК нужно учитывать длину маски
                             // а не просто код ='0'
                             [  FormatKbk( 'GRANTINVESTMENT', '0', aBudgetID),
                                'не указан%',
                                aBudgetID],
                             'ID');

      except
        ExceptionLog( 'Сбой QueryKbk.SearchUnicalGrantinvestmentCodeNull');
    end;

end;


function SearchUnicalGrantinvestmentCode( aBudgetID, aKIF, aKES, aLS_ID: string;
                                           aKVR: string;
                                           aFillKES, aFillKVR: boolean): string;
var
  xXml: Variant;
begin

    try
      if aFillKES
        then xXml := QueryXml(
                         ' select distinct aubub.grantinvestment_id ID '
                        +' from aububudget aubub '
                        +' where aubub.budget_id=? and aubub.fsr_id=? '
                        +' and aubub.kesr_code=? and aubub.pay_acc_id=? ',
                        [ aBudgetID,
                          aKIF,
                          aKES,
                          aLS_ID]);
      if aFillKVR
        then xXml := QueryXml(
                         ' select distinct aubub.grantinvestment_id ID '
                        +' from aububudget aubub '
                        +' where aubub.budget_id=? and aubub.fsr_id=? '
                        +' and aubub.kvr_code=? and aubub.pay_acc_id=? ',
                        [ aBudgetID,
                          aKIF,
                          aKVR,
                          aLS_ID]);
      if (xXml.documentElement.childNodes.Length <> 1)
        then Result := SearchUnicalGrantinvestmentCodeNull( aBudgetID)
        else Result := xXml.documentElement.childNodes.Item[0].GetAttribute( 'ID');

      except
        ExceptionLog( 'Сбой QueryKbk.SearchUnicalGrantinvestmentCode');
    end;

end;


{~SearchGrandinvestmentCodeEx
  Искать в справочнике субсидий по коду только среди кодов,
  у которых учредитель равен Учредителю документа, либо Не указан.
  Если не заполнено, заполнять системным значением 0 (код 0,
   тип «Не указан», учредитель «Не указан»).

  exchange #2952
  помимо кода субсидии возвращается результат определяения кода
  в параметре aResFound:
    пусто - если код субсидии не указан (aCode=пусто)
    N (0 или другое число) - количество найденных кодов в справочнике.

  exchange #2987
  если параметр aMsgInfo=true, отображается сообщение в журнале, если
  код не найден в бд и заменен на 0.
  если код не указан - сообщение в журнале не отображается.

  exchange #3014
  пропущена привязка с учредителем.}
function SearchGrandinvestmentCodeEx( aBudgetID, aCode: string;
                                      var aResFound: string;
                                      aMsgInfo: boolean = TRUE;
                                      aOrgID: string = ''): string;
var
  xCode: string;
  xSQL: string;
  xSQL_sub: string;
  xParams: variant;
  xParams_copy: variant;
begin

    try
      { делаем так: если поле aCode не пустое, проверяем
       код в бд. если однозначно код не находим, то сбрасываем
       значение строки, если находим - заполняем значением строки ид.кода.}
      xCode := TRIM( aCode);

      if (LENGTH( xCode) <= 0)
        then aResFound := ''
        else begin
          xSQL := ' from GRANTINVESTMENT i where i.code=? and i.budget_id=?';
          xParams := NULL;
          VarArrayUnion( xParams, xCode);
          VarArrayUnion( xParams, aBudgetID);

          if (LENGTH( aOrgID) <= 0)
            then xSQL_sub := ''
            else begin
              xParams_copy := xParams;      // сохраняем копию параметров
              xSQL_sub := ' and ORG_ID=?';
              VarArrayUnion( xParams, aOrgID);
            end;

          // в начале ищем с конкретным учредителем или без него
          aResFound := QueryField( 'select count( * ) N ' + xSQL + xSQL_sub, xParams, 'N');

          case aResFound of
            '1': xCode := QueryField( 'select i.ID ID ' + xSQL + xSQL_sub, xParams, 'ID');
            '0': xCode := '';
            else
              if (LENGTH( aOrgID) <= 0)
                then xCode := ''
                else begin
                  // пробуем найти с учетом учредителя = 0 (не указан)
                  xSQL := xSQL + ' and (ORG_ID=? or ORG_ID is null)';
                  // здесь придется обновить список параметров к запросу
                  xParams := xParams_copy;
                  VarArrayUnion( xParams, '0');
                  aResFound := QueryField( 'select count( * ) N ' + xSQL, xParams, 'N');
                  if (aResFound = '1')
                    then xCode := QueryField( 'select i.ID ID ' + xSQL, xParams, 'ID')
                    else xCode := '';
                end;
          end;//case//

          // если не нашли: если нужно сообщить об этом, то пишем в журнал info
          // (ошибка)
          if (xCode = '') then
            if aMsgInfo then
              if (aResFound = '0')
                then WriteInfo( FORMAT( 'Код субсидии %s не найден в БД. Значение будет заменено на «0».',
                                        [ aCode]))
                else WriteInfo( FORMAT( 'Найдено несколько (%s) кодов субсидий %s в БД. Значение будет заменено на «0».',
                                        [ aResFound,
                                          aCode]));
        end;

      // если строка не пустая, значит ид.кода найден и подставляем это
      // значение. если строка пустая - значт либо поле файла пустое,
      // либо код не найден, поэтому ищем в бд код =0.
      if (LENGTH( xCode) > 0)
        then Result := xCode
        else Result := SearchUnicalGrantinvestmentCodeNull( aBudgetID);

      except
        ExceptionLog( 'Сбой QueryKbk.SearchGrandinvestmentCodeEx');
    end;

end;


{~SearchGrandinvestmentCode
  Искать в справочнике субсидий по коду только среди кодов,
  у которых учредитель равен Учредителю документа, либо Не указан.
  Если не заполнено, заполнять системным значением 0 (код 0,
   тип «Не указан», учредитель «Не указан»).
   exchange #3014
  пропущена привязка с учредителем.
  чтобы не дублировать код, вызываем скрипт поиска кода без сообщений
  в журнале info.}
function SearchGrandinvestmentCode( aBudgetID, aCode: string;
                                    aOrgID: string = ''): string;
var
  xResFound: string;
begin

    try
      Result := SearchGrandinvestmentCodeEx( aBudgetID,
                                             aCode,
                                             xResFound,
                                             FALSE,
                                             aOrgID);

      except
        ExceptionLog( 'Сбой QueryKbk.SearchGrandinvestmentCode');
    end;

end;


function FormatKbkEx( aCodeName, aCode, aBudget_Id: String;
                      aCheckKES: boolean = TRUE;
                      const aFormatType: Integer = 0): String;
begin

    try
      case UPPERCASE( aCodeName) of
        'KES':   Result := KesCodeFormat( aCode, aBudget_Id, aFormatType, aCheckKES);
        'KI':    Result := KiCodeFormat( aCode, aBudget_Id, aFormatType, aCheckKES);
        'KD':    Result := KdCodeFormat( aCode, aBudget_Id, aFormatType, aCheckKES);
        'KCSR':  Result := KcsrCodeFormat( aCode, aBudget_Id, aFormatType, aCheckKES);
        else     Result := FormatKbk( aCodeName, aCode, aBudget_Id, aFormatType);
      end;
      except
        ExceptionProc( 'FormatKbkEx');
    end;

end;

{~KBK_is_0
  проверка кбк на все нули.
  добавлено по доработке exchange #3081 для унификации кода.
  результат:
    =true - код пустой или содержит все нули;
    =false - код не пустой и не нулевой.}
function KBK_is_0( aKBK: string): boolean;
begin

    try
      Result := (LENGTH( StringReplace( aKBK, '0', '')) <= 0);
      except
        ExceptionProc( 'KBK_is_0');
    end;

end;
{------------------------------------------------------------------------------}
{~CheckField_PI_BUDGET_CODE
  exchange #3081
  проверка поля ид.платежа с узле описания раздела выгружаемого
  файла aXmlFileTopic, чтобы код был не длиннее 20 знаков.

  проблема в том, что с 2016г. косгу отменяется а кцср расширяется и
  код может выйти за 20знаков, поэтому отсекаются все символы после 20го.

  проверка может пригодится и для импорта и для экспорта.

  если выгружается нулевой код - выгружать нужно пустое поле}
procedure CheckField_PI_BUDGET_CODE( aXmlFileTopic: Variant;
                                     aFieldName: string;
                                     aFieldValue: String = '');
var
  s: string;
begin

    try
      s := GetNodeAttributeEx( aXmlFileTopic, aFieldName);
      //Бывает такое, что значение может быть '0' и 19 пробелов :)
      if (LENGTH( s) <> LENGTH( Trim(s))) then
      begin
        aXmlFileTopic.SetAttribute( aFieldName, Trim(s));
        s := Trim(s);
      end;
      if (LENGTH( s) > 20)
        then aXmlFileTopic.SetAttribute( aFieldName, COPY( s, 1, 20));
      // Если параметр конфина "Позволять выгружать 0 в КБК ИДП" = "Да" и значение "0", то ничего не делаем
      if ((aFieldValue = 'Y') and (s = '0')) then
        exit;
      // exchange #3081
      // если выгружается нулевой код - выгружать нужно пустое поле, но при условии Exchange, #3118
      // Если параметр конфина "Позволять выгружать 0 в КБК ИДП" = "Нет", то проверяем на ноль
      if ((aFieldValue <> 'V') and (KBK_is_0( s)))
        then aXmlFileTopic.SetAttribute( aFieldName, '');
      except
        ExceptionProc( 'CheckField_PI_BUDGET_CODE');
    end;

end;

begin
end.
