//uses 'Un_CheckTolyati', 'Version.inc';
uses
  'Un_CheckKOMI',     // exchange #2520
                      // обязательно сверху, поскольку этот модуль
                      // основан на функцияю ОБЩЕГО алгоритма (Un_CheckGeneral).
  'Un_CheckChelObl',
  'Un_CheckGeneral',
  'Un_CheckKrasnoyarskKray',
  'Un_CheckPermKray',
  'Un_CheckRyazanObl',
  'Un_CheckTolyati',
  'Un_CheckEkaterinburg',
  'Un_GrantInvestmentChoose',
  'Un_GrantInvestmentList',
  'Un_ToolsEnrolments',       // exchange #3036
  'Un_Twins',                 // exchange #3036
  'Un_Tools',
  'Un_DataSetPost',           // exchange #3036
  'Un_Log',
  'Un_Debug',
  'Version.inc';

const
    cnUn_checkekaterinburg          = 'un_checkekaterinburg.pfe';
    cnUn_checkgeneral               = 'un_checkgeneral.pfe';
    cnUn_checkryazanobl             = 'un_checkryazanobl.pfe';
    cnUn_checkkrasnoyarskkray       = 'un_checkkrasnoyarskkray.pfe';
    cnUn_checkchelobl               = 'un_checkchelobl.pfe';
    cnUn_checkpermrray              = 'un_checkpermkray.pfe';
    cnUn_checktolyati               = 'un_checktolyati.pfe';
    cnUn_checkkomi                  = 'un_checkkomi.pfe';

    cnUn_checkIDekaterinburg          = 1;
    cnUn_checkIDgeneral               = 2;
    cnUn_checkIDryazanobl             = 3;
    cnUn_checkIDkrasnoyarskkray       = 4;
    cnUn_checkIDchelobl               = 5;
    cnUn_checkIDpermrray              = 6;
    cnUn_checkIDtolyati               = 7;
    cnUn_checkIDkomi                  = 8;

var
  FmList, FmDoc: TFormCustom;
  ProgressBar: TProgressBar;
  dtmDate, dtmBankDate: TDateTimeEh;
  cbOrgAccount: TComboBox;
  Timer, PlayTimer: TTimer;
  actCheck, actEdit, actExecute, actBreak: TAction;
  fsScript: TfsScript;
  Account, Industry_Code, Grantinvestment_Code, Kesr_Code, Fsr_Id: TDBEdit;
  FAzkIsLogin: Boolean;
  FileLog, FileInfo, FModuleName, IniPath, PanelText: String;
  FDebuger, DateEnabled, BankDateEnabled, OrgAccountEnabled: Boolean;
  PanelTextIdx, sortidx: Integer;
  vModuleNameID: integer;
  vBreak: boolean;

  // добавлен при доработке по exchange #3036
  // в этот журнал пишется все как и в FileLog, но этот файл начинается
  // заново как FileInfo.
  vFileJournal: String;


{~ExceptionHandler
  главный обработчик исключений.
  именно этим методом нужно завершать обработку исключений в главной программе!
  подпрограмма логирует текст исключения в логе, а так же системную информацию
  о текущем скрипте.
  подпрограмма работает только с определенными версиями AZK exchange.}
procedure ExceptionHandler;
var
  xExceptMsg: string;
begin
  xExceptMsg := LastException.Message;
  try
    // сохраняем файл со сбоем
    WriteLogFile( IniPath + 'сбой_скрипта.txt', xExceptMsg);
    ShowMessage( 'Сбой выполнения скрипта.'#13#10
                 + FORMAT( 'В каталоге "%s" создан файл: сбой_скрипта.txt',
                            [ IniPath]));
    except
      ShowMessage( 'Системный сбой ExceptionHandler.'#13#10 + LastException.Message);
  end;
end;


procedure Main(Xml: Variant);
begin
  CheckWorkAppVersion;
  with Xml.documentElement do
  if getAttribute('TESTED') = 'True' then
  begin
    setAttribute('TESTED', 'False');
    Xml.save('C:\Temp\MoneyTransferOrder.Xml');
    ShowMessage('Тестовый пример приготовлен: C:\Temp\MoneyTransferOrder.Xml');
    Exit;
  end;

  FAzkIsLogin := AzkIsLogin;
  if not AzkIsLogin then
    if not AzkLogin then Exit;

  try
    try
      initialization(Xml);
      // инициализация модуля DataSetPost
      InitializeDataSetPost;
      // инициализация модуля выбора отр кода.
      // обязательно после initialization !
      GrantInvestmentExInitialize( IniPath);
      // exchange #3036 - инициализация модуля зачислений
      InitializeEnrolment;

      try
        if FileExists(FileInfo) then DeleteFile(FileInfo);
        WriteLog('===========================================================');
        WriteLog( 'Старт скрипта.');
        if FDebuger then begin
          FmList.Show;
          repeat
            Application.handleMessage;
          until(not FmList.Visible);
        end else begin
          FmList.ShowModal;
        end;
        DBGrid.SaveLayout;
        WriteLog( 'Завершение скрипта.');
        finally
          GrantInvestmentExFinalize;
      end;
      except
        ExceptionHandler;
    end;
    finally
      // exchange #3036 - инициализация модуля зачислений
      FinalizeEnrolment;
      finalization;
      if not FAzkIsLogin
        then AzkLogout;
      ShowFileInfo;
  end;
end; {End Main}

procedure initialization(Xml: Variant);
var
  FileStream: TFileStream;
begin
    try
      FmList := TFormCustom.Create(Application);
      FmDoc := TFormCustom.Create(FmList);

      Xml := Xml.documentElement;
      IniPath := ExtractFilePath(Xml.getAttribute('INI_FILE'));
      FileLog := IniPath + 'FileLog.Log';
      FileInfo := IniPath + 'FileInfo.Log';

      // exchange #3036
      // начинаем новый журнал операций
      vFileJournal := IniPath + 'журнал.log';
      if FileExists( vFileJournal)
        then DeleteFile( vFileJournal);

      with TStringList.Create do
      try
        CommaText := Xml.getAttribute('CONFIG');
        // какой модуль проверки будет выполняться
        FModuleName := LowerCase( {IniPath + }Values['Модуль проверки']);
        DateEnabled := Values['Дата'] = 'Да';
        BankDateEnabled := Values['Дата по банку'] = 'Да';
        OrgAccountEnabled := Values['Счёт'] = 'Да';

        // exchange #2615
        // если настройка =Да - ищем по старому, иначе - по новому
        if (Values[ 'Искать отр.код в ИДП'] = 'Да')
          then vCfgModeSearchOtrKod:= ''
          else vCfgModeSearchOtrKod:= '#2615';
          
        vCfgModeSameMethodKesrAndKDMA := Values['Возможность одинакового определения значений КОСГУ и Ан. группа'] = 'Да';

        // exchange #3053
        // обрамляем запятыми, поскольку будем искать код такой: ",000,"
        // а не просто "000".
        vCfg_KES_HBC := TRIM( Values[ 'Значение КОСГУ для зачисления на НВС']);
        if (LENGTH( vCfg_KES_HBC) > 0)
          then vCfg_KES_HBC := ',' + vCfg_KES_HBC + ',';
          
        // Exchange, #3215
        vCfg_FindGrInvCodeBySymbols := TRIM( Values[ 'Определять значение кода субсидии по символам:']);
        if (LENGTH( vCfg_FindGrInvCodeBySymbols) = 0) then
          vCfg_FindGrInvCodeBySymbols := 'Код субсидии, КС';
        //обрамляем кавычками (" ") отдельные значения, иначе TStringList потом не распарсит из-за возможных пробелов
        vCfg_FindGrInvCodeBySymbols := '"' + StringReplace(vCfg_FindGrInvCodeBySymbols, ',', '","') + '"';
        
      finally
        Free;
      end;

      case FModuleName of
        cnUn_checkgeneral         : vModuleNameID := cnUn_checkIDgeneral;
        cnUn_checkekaterinburg    : vModuleNameID := cnUn_checkIDekaterinburg;
        cnUn_checkryazanobl       : vModuleNameID := cnUn_checkIDryazanobl;
        cnUn_checkkrasnoyarskkray : vModuleNameID := cnUn_checkIDkrasnoyarskkray;
        cnUn_checkchelobl         : vModuleNameID := cnUn_checkIDchelobl;
        cnUn_checkpermrray        : vModuleNameID := cnUn_checkIDpermrray;
        cnUn_checktolyati         : vModuleNameID := cnUn_checkIDtolyati;
        cnUn_checkkomi            : vModuleNameID := cnUn_checkIDkomi;
        else                        vModuleNameID := cnUn_checkIDgeneral;
      end;//case//

      // exchange 3036
      // оптимизация проверки версии АЦК - делаем это один раз.
      vIsAzkVersion2_29 := (AzkCompareVersion('2.29') >= 0);
      vIsAzkVersion2_26_46_1 := (AzkCompareVersion('2.26.46.1') >= 0);
      case vModuleNameID of
        cnUn_checkIDkomi: vIsAzkVersion2_30 := (AzkCompareVersion('2.30') >= 0);

        cnUn_checkIDgeneral,
        cnUn_checkIDryazanobl: vIsAzkVersion2_26_42_11 := (AzkCompareVersion('2.26.42.11') >= 0);

        cnUn_checkIDekaterinburg,
        cnUn_checkIDchelobl,
        cnUn_checkIDkrasnoyarskkray,
        cnUn_checkIDpermrray,
        cnUn_checkIDtolyati: vIsAzkVersion2_26_46_11 := (AzkCompareVersion('2.26.46.11') >= 0);
      end;//case//


      // только для версий ниже 2.28.
      // по Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368 это не используется.
      fsScript := NIL;
      if NOT vIsAzkVersion2_29 then begin
        fsScript := TFsScript.create(FmList);
        fsScript.Parent := fsGlobalUnit;
        FileStream := TFileStream.Create( GetFModuleNameScriptFull, fmOpenRead);
        try
          if not fsScript.SetILCode(FileStream) then
            raise(fsScript.ErrorMsg);
          if not fsScript.Find('ObjectName') then
            raise('В модуле: ' + FModuleName + ' не найдена функция: ObjectName');
          if not fsScript.Find('CheckPayOrder') then
            raise('В модуле: ' + FModuleName + ' не найдена функция: CheckPayOrder');
        finally
          FileStream.Free;
        end;
      end;

      try
        FmList.LoadDfm(IniPath + 'Fm_PayOrderList.dfm');
        FmList.Name := 'FmMoneyTransferOrderDocList';
        with TStatusBar(FmList.FindComponent('StatusInfo')).Panels do begin
          Items[0].Text := 'Сборка ' + Version;
          // Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368
          if vIsAzkVersion2_29 //(AzkCompareVersion('2.29') >= 0)
            then PanelText := 'Модуль проверки - ' + ObjectNameEx
            else PanelText := 'Модуль проверки - '
                                + fsScript.CallFunction(
                                      GetFModuleNameScript,
                                      'ObjectName',
                                      nil);
          Items[1].Text := '';
        end;
        PanelTextIdx := 1;
        FmList.actRefresh.OnExecute := @actRefreshExecute;
        ProgressBar := TProgressBar(FmList.FindComponent('ProgressBar'));
        cdsList := TClientDataSet(FmList.FindComponent('cdsList'));
        cdsList.CreateDataSet;
        DBGrid := TDBGridEh(FmList.FindComponent('DBGrid'));
        DBGrid.SaveRestoreLayout;
        DBGrid.onBookmarkCheckEvents := @BookmarkCheckEvents;
        DBGrid.OnDblClick := @PayOrderEdit;
        dtmDate := TDateTimeEh(FmList.FindComponent('dtmDate'));
        dtmDate.OnChange := @actRefreshExecute;
        dtmDate.Date := Work_Date;
        dtmBankDate := TDateTimeEh(FmList.FindComponent('dtmBankDate'));
        dtmBankDate.OnChange := @actRefreshExecute;
        dtmBankDate.Date := Work_Date;
        cbOrgAccount := TComboBox(FmList.FindComponent('cbOrgAccount'));
        cbOrgAccount.OnChange := @actRefreshExecute;
        actCheck := TAction(FmList.FindComponent('actCheck'));
        actCheck.OnExecute := @actCheckExecute;
        actEdit := TAction(FmList.FindComponent('actEdit'));
        actEdit.OnExecute := @PayOrderEdit;
        actExecute := TAction(FmList.FindComponent('actExecute'));
        actExecute.OnExecute := @actExecuteExecute;

        // экшен "прервать"
        actBreak := TAction(FmList.FindComponent('actBreak'));
        if (actBreak <> NIL) then begin
          actBreak.OnExecute := @onExecuteBreak;
          actBreak.Enabled := FALSE;
        end;

        FmDoc.LoadDfm(IniPath + 'Fm_PayOrder.dfm');
        FmDoc.Name := 'FmMoneyTransferOrderDoc';
        TDataSource(FmDoc.FindComponent('DataSource')).DataSet := cdsList;
        TAction(FmDoc.FindComponent('actCheck')).OnExecute := @actCheckExecute;
        Account := TDBEdit(FmDoc.FindComponent('Account'));
        Industry_Code := TDBEdit(FmDoc.FindComponent('Industry_Code'));
        Grantinvestment_Code := TDBEdit(FmDoc.FindComponent('Grantinvestment_Code'));
        Kesr_Code := TDBEdit(FmDoc.FindComponent('Kesr_Code'));
        Fsr_Id := TDBEdit(FmDoc.FindComponent('Fsr_Id'));
        if not FDebuger then
          FmList.AppEvents.onMessage := @AppEventsMessage;
        LoadcbOrgAccount;
        Timer := TTimer(FmList.FindComponent('Timer'));
        Timer.onTimer := @actRefreshExecute;
        Timer.Enabled := True;
        PlayTimer := TTimer(FmList.FindComponent('PlayTimer'));
        PlayTimer.onTimer := @onPlayTimer;
        PlayTimer.Enabled := True;
        finally
          FmList.Enabled := TRUE;
          FmDoc.Enabled := TRUE;
          FmList.SimpleText := '';
      end;
      except
        ExceptionProc( 'initialization');
    end;
end; {End initialization}

procedure finalization;
begin
  FmList.Free
end; {End finalization}

{~GetFModuleNameScript
  возвращает имя модуля, выбранного в качестве функционального модуля
  проверки из опции FModuleName: "Модуль проверки".
  функция актуальна только для версий ниже 2.29 (до доработки по задачам
  Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368).
  у старых модулей в имени файла добавлен суффикс "_v2_28.
  для новых версий 2.29 и выше, функционал сделан как главный-подниченный
  скрипт, без вызова скриптов как функциональный модуль, а вызов как обычную
  подпрограмму.}
function GetFModuleNameScript: string;
begin
  Result := ChangeFileExt(ExtractFileName(FModuleName), '') + '_v2_28';
end;

{~GetFModuleNameScriptFull
  возвращает полное имя выполняемого скрипта (с путем и расширением pfe).
  используется только для версий ниже 2.29.}
function GetFModuleNameScriptFull: string;
begin
  Result := IniPath + GetFModuleNameScript + '.pfe';
end;

procedure onExecuteBreak(Sender: TObject);
begin
  vBreak := TRUE;
  Application.processMessages;
end;

procedure onPlayTimer(Sender: TObject);
begin
{не удалять эту строку!}
  with TStatusBar(FmList.FindComponent('StatusInfo')).Panels do
  begin
    PlayTimer.Enabled := not (Length(Items[1].Text) = Length(PanelText));
    if not PlayTimer.Enabled then Exit;
    Items[1].Text := Items[1].Text + PanelText[PanelTextIdx];
    Inc(PanelTextIdx);
  end;
end;

procedure actRefreshExecute(Sender: TObject);
var
  sql: String;
begin
  Timer.Enabled := False;
  FmList.Enabled := FALSE;
  FmDoc.Enabled := FALSE;
  FmList.SimpleText := 'Обновление кредитовых документов ...';
  cdsList.DisableControls;
  if Sender = actCheck then
    DBGrid.FieldColumns['Restext'].Title.SortMarker := smNoneEh;
  DBGrid.BookmarkUnCheckAll;
  DBGrid.Enabled := False;
  DBGrid.SavePosition;
  SetAppDisable;
  try
    sql := 'Select P.Id, P.Version, P.Document_Id, P.Budget_Id, P.DocumentClass_Id, P.DispStatus_Id' +
      ', P.Doc_Date, P.Carry_Date, LTrim(P.Doc_Number) Doc_Number, P.Amount, P.Pi_Budget_Code' +
      ', P.Pay_Account, P.Pay_Bic, P.Pay_CorAccount, P.Pay_Name, P.Pay_TaxCode, P.Pay_Kpp' +
      ', P.Rec_Account, P.Rec_Bic, P.Rec_CorAccount, P.Rec_Name, P.Rec_Ufk_Account' +
      ', P.Org_Name, P.Org_TaxCode, P.Org_Kpp , P.Rec_TaxCode, P.Rec_Kpp, P.Org_Id' +
      ', P.Pay_Id, P.Description, ''Не проверялся'' ResText' +
      ' From PayOrder P' +
      ' Left Join Document D On D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1' +
      ' Left Join OrgAccount Oa on Oa.Id = P.Rec_Acc_Id' +
      ' Join Budget B on ((Oa.Org_Id = B.Org_Id and P.Budget_Id = B.Id)' +
          ' or (Oa.Org_Id = B.Executor_Id and P.Budget_Id = B.Id))' +
      ' Where P.Budget_Id = ? and P.DocumentClass_Id = 24 And P.DispStatus_Id = 9';
    Query.AddStr(Budget_Id);
    if DateEnabled then
    begin
      sql := sql + ' And P.Doc_Date = ?';
      Query.AddDate(dtmDate.Date);
    end;
    if BankDateEnabled then
    begin
      sql := sql + ' And P.Carry_Date = ?';
      Query.AddDate(dtmBankDate.Date);
    end;
    if OrgAccountEnabled then
    begin
      sql := sql + ' And P.Rec_Account = ?';
      Query.AddStr(cbOrgAccount.Text);
    end;
    sql := sql +  ' Group By P.Id, P.Version, P.Document_Id, P.Budget_Id' +
      ', P.DocumentClass_Id, P.DispStatus_Id, P.Doc_Date, P.Carry_Date' +
      ', P.Doc_Number, P.Amount, P.Pi_Budget_Code, P.Pay_Account, P.Pay_Bic' +
      ', P.Pay_CorAccount, P.Pay_Name, P.Pay_TaxCode, P.Pay_Kpp, P.Rec_Account' +
      ', P.Rec_Bic, P.Rec_CorAccount, P.Rec_Name, P.Rec_Ufk_Account, P.Org_Name' +
      ', P.Org_TaxCode, P.Org_Kpp, P.Rec_TaxCode, P.Rec_Kpp, P.Org_Id, P.Pay_Id, P.Description' +
      ' Having Coalesce(P.Amount - Sum(Case When D.DispStatus_Id > -1 Then D.Amount Else 0.00 End), 0.00) <> 0.00';
    Query.RunCds(cdsList, sql);
  finally
    cdsList.EnableControls;
    DBGrid.RestorePosition;
    DBGrid.DefaultApplySorting;
    DBGrid.Enabled := True;
    FmList.Enabled := TRUE;
    FmDoc.Enabled := TRUE;
    FmList.SimpleText := '';
    FmList.ActiveControl := DBGrid;
    SetAppEnable;
  end;
end; {End actRefreshExecute}

{~ObjectNameEx
  для доработки по Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368
  названия для выбранного функционального модуля определяются не из функции
  внешнего скрипта, а сразу по названию значения из параметра конфигурации.
  функция названа по другому чтобы не дублировать название подпрограммы
  "ObjectName" которые реализованы в скриптах для старых версий. иначе в
  работе скриптов возможны сбои.}
function ObjectNameEx: string;
begin
  case vModuleNameID of
    cnUn_checkIDekaterinburg      : Result := 'ДФ г. Екатеринбурга';
    cnUn_checkIDgeneral           : Result := 'Общий';
    cnUn_checkIDryazanobl         : Result := 'Минфин Рязанской области';
    cnUn_checkIDkrasnoyarskkray   : Result := 'МФ Красноярского края';
    cnUn_checkIDchelobl           : Result := 'МФ Челябинской области';
    cnUn_checkIDpermrray          : Result := 'МФ Пермского края';
    cnUn_checkIDtolyati           : Result := 'ДФ Тольятти';
    cnUn_checkIDkomi              : Result := 'КОМИ';
    else                            Result := FORMAT( 'Модуль "%s" не распознан.',
                                                      [ FModuleName]);
  end;//case//
end;

procedure actCheckExecute(Sender: TObject);
var
  Control: TWinControl;
  SortMark: TSortMarkerEh;
  // exchange #2431
  // при сбросе сортировки нужно запомнить состояние колонок грида, чтобы
  // восстановить сортировку колонок после сброса.
  // чтобы не заморачиваться с количеством полей грида назначаем максимально
  // возможное число полей в гриде - 1024 как статический массив.
  // это проще чем создавать массив, потом разрушать его.
  xFieldName: string;                         // название поля
  i,i2,imax: integer;
  a_sm: array[1..1024] of TSortMarkerEh;      // маркер направления сортировки
  a_si: array[1..1024] of integer;            // индекс поля
  // exchange #3036
  xExistsGrantInvestmentID_SystemNull: boolean;
  xDoc24Info: string;
  n1,n2,n3: integer;
  d1,d2: TDateTime;


  function CheckPayOrderLocal_v2_29: Boolean;
  begin
      try
        // exchange #3036
        // оптимизируем проверку: если системный код найден - выполняем проверку эд.
        // если не найден - пишем сообщение по #2362,#2363,#2364,#2365,#2366...
        if xExistsGrantInvestmentID_SystemNull then begin
    //  for testing
    //      Result := CheckPayOrder(cdsList, IniPath);
          // Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368
          // вместо вызова скрипта через объект скрипта, переделаны скрипты на
          // вызов подпрограмм. в результате получился этот модуль главным, а
          // остальные - подчиненными. это связано с тем, что много кода одинавого,
          // и при перечисленных доработках потребовалось бы много дублировать.
          // exchange #3036
          // оптимизация производительности
          CDSListReset;
          case vModuleNameID of
            cnUn_checkIDekaterinburg:
                    Result := CheckPayOrder_Ekaterinburg;//( cdsList, IniPath);
            cnUn_checkIDgeneral:
                    Result := CheckPayOrder_General;//( cdsList, IniPath);
            cnUn_checkIDryazanobl:
                    Result := CheckPayOrder_RyazanObl;//( cdsList, IniPath);
            cnUn_checkIDkrasnoyarskkray:
                    Result := CheckPayOrder_KrasnoyarskKray;//( cdsList, IniPath);
            cnUn_checkIDchelobl:
                    Result := CheckPayOrder_ChelObl;//( cdsList, IniPath);
            cnUn_checkIDpermrray:
                    Result := CheckPayOrder_PermKray;//( cdsList, IniPath);
            cnUn_checkIDtolyati:
                    Result := CheckPayOrder_Tolyati;//( cdsList, IniPath);
            // exchange #2520
            cnUn_checkIDkomi:
                    Result := CheckPayOrder_KOMI;//( cdsList, IniPath);
          end;//case//
          CDSListPost;
        end else begin
          // Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368
          // если системный кода субсидии "Не указано" из справочника не распознан,
          // то записи не анализируем и сразу возвращаем ошибку.
          // это дает возможность убрать лишний код из вызываемых подпрограмм
          cdsList.Edit;
          cdsList.FieldByName('ResText').AsString :=
                         'Контроль не пройден. '
                        +'Причина: Не найден системный код субсидии "Не указано" '
                        +'с кодом 0, типом 3 и учредитель "Не указано" для текущего бюджета.';
          cdsList.Post;
          Result := FALSE;
        end;
        except
          ExceptionProc( 'CheckPayOrderLocal_v2_29');
      end;
  end;

  function CheckPayOrderLocal_v2_28: Boolean;
  begin
    try
      // exchange #2520
      // для 2.28 вариант КОМИ не работает, поэтому тут выдаем сбой
      case LowerCase( FModuleName) of
        cnUn_checkkomi:
            raise( 'Реализация КОМИ для версии 2.28 не работает.');
      end;//case//
      // старый вариант - запускаем скрипт в отдельном объекте
      // фактически это работа изолированного скрипта
      Result := fsScript.CallFunction(
                    GetFModuleNameScript,
                    'CheckPayOrder',
                    [ cdsList,
                      IniPath]);
    except
      raise('Ошибка при исполнении функции: ' + FModuleName +
        ' в модуле: CheckPayOrder - ' + LastException.Message);
    end;
  end;

  function CheckPayOrderLocal: Boolean;
  begin
    if vIsAzkVersion2_29
      then Result := CheckPayOrderLocal_v2_29
      else Result := CheckPayOrderLocal_v2_28;
  end;

begin
    try
      if cdsList.recordCount = 0 then Exit;

      n1 := 0;
      n2 := 0;
      n3 := 0;

      // Exchange #2362,#2363,#2364,#2365,#2366,#2367,#2368
      // получение системного кода субсидии "Не указано" из справочника "субсидии
      // и инвестиции" перед началом проверки. это ускорит работу скриптов и
      // упростит код. вряд ли так важно это проверять по ходу проверки по каждой
      // записи. проще это сделать единожды в начале операции.
      // exchange #3036
      // сохраняем флаг найденного кода. вместо проверки длины проверяем флаг.
      // флаг = true, если код найден.
      xExistsGrantInvestmentID_SystemNull :=
                                      GetGrantInvestmentID_SystemNull( Budget_Id);

      if Sender <> actCheck then
      begin
        // exchange #2786
        // на время проверки блокируем главную форму
        FmList.Enabled := FALSE;
        FmDoc.Enabled := FALSE;

        Control := FmDoc.ActiveControl;
        FmDoc.SimpleText := 'Проверка соответствия правилам ...';
        DBGrid.Enabled := False;
        SetAppDisable;
        Application.processMessages;
        try
          if CheckPayOrderLocal then
            DBGrid.BookmarkCheck
          else
            DBGrid.BookmarkUnCheck;
        finally
          FmDoc.SimpleText := '';
          DBGrid.Enabled := True;
          // exchange #2786
          // разблокируем главную форму
          FmList.Enabled := TRUE;
          FmDoc.Enabled := TRUE;
          SetAppEnable;
          FmDoc.ActiveControl := Control;
        end;
      end else
      begin
        // exchange #3036
        // если кнопка прерывания есть на форме - то оставляем форму
        // разблокированной. закрыть все равно не получится, а прервать
        // проверку можно будет.
        if (actBreak = NIL)
          then FmList.Enabled := FALSE;
        FmDoc.Enabled := FALSE;

        FmList.SimpleText := 'Проверка соответствия правилам ...';
        WriteLog('-----------------------------------------------------------');
        WriteLog('Проверка соответствия правилам...');

        { exchange #2431
         сохраняем параметры сортировки полей: индекс сортировки для каждого поля
         и маркер сортировки (вверх/книз)
         в начале определяем, сколько полей задействовано в сортировки, т.е.
         для этого получаем максимальный индекс сортируемого поля.
         в гриде, для каждого поля, есть два поля для сортиовки: SortIndex и SortMarker.
         например: пусть имееется грид с 3-мя полями: F1,F2,F3.
         когда выполняют сортировку по полю F1 (вниз), описание колонок будет таким:

                           F1    F2   F3
          SortIndex         1     0    0
          SortMarker        1     0    0

         когда выполняют сортировку по полю F1 (вниз) и полю F3 (вверх), причем,
         поле F3 сортируется первым (F1, соответственно, вторым), описание колонок
         будет таким:

                           F1    F2   F3
          SortIndex         2     0    1
          SortMarker        1     0    2

          когда нужно будет восстановить сортировку обратно, нужно восстановить
          поле SortMarker в порядке упорядования SortIndex, т.е. по последнему
          примеру, нужно в начале установить SortMarker для поля F3, а потом для F1.

          поэтому нужно сохранить SortMarker в порядке указания полей сортировки.
          для этого в начале определяем число полей, участвующих в сортировке,
          и сохраняем в массивах: a_sm - значения SortMarker, а в a_si - номера
          полей. порядок индексов в этих массивах определяет порядок полей сортировки.

          так для второго примера число элементах в массиве = 2 (в сортировке участвуют
          два поля: F1 и F2), а значения в массивх будут такими:
            SortMarker[1] = 2, SortMarker[2]=1
            SortIndex[1]=index(F3), SortIndex[2]=index(F1).}
        // определяем число полей, участвующих в сортировке
        imax := 0;
        for i:=0 to DBGrid.Columns.Count -1 do begin
          i2:= DBGrid.FieldColumns[ DBGrid.Columns.Items[i].FieldName ].Title.SortIndex;
          if (i2>imax) then imax:= i2;
        end;
        // сохраняем описание параметров сортировки полей в таблице
        for i2:=1 to imax do
          for i:=0 to DBGrid.Columns.Count -1 do begin
            xFieldName := DBGrid.Columns.Items[i].FieldName;
            if (i2=DBGrid.FieldColumns[ xFieldName ].Title.SortIndex) then begin
              a_sm[i2]:= DBGrid.FieldColumns[ xFieldName ].Title.SortMarker;
              a_si[i2]:= i;
            end;
          end;//for//

        // exchange #2431
        // сохраняем позицию до момента пересортировки таблицы
        DBGrid.SavePosition;

        // exchange #2431
        // сбрасываем сортировку с грида. это нужно делать пока контрол еще активен.
        // если делать после cdsList.DisableControls и DBGrid.Enabled := False
        // то эффекта не будет.
        for i:=0 to DBGrid.Columns.Count -1
          do DBGrid.FieldColumns[
                  DBGrid.Columns.Items[i].FieldName ].Title.SortMarker := smNoneEh;
        DBGrid.DefaultApplySorting;

        cdsList.DisableControls;
        DBGrid.Enabled := False;
        if (actBreak = NIL)
          then SetAppDisable;
        CursorDisable;

        d1 := NOW;
        try
          vBreak := FALSE;
          if (actBreak <> NIL)
            then actBreak.Enabled := TRUE;

          ProgressBar.Max := cdsList.recordCount;
          cdsList.First;

          while not cdsList.Eof do begin
            ProgressBar.Position := cdsList.RecNo;
            INC( n1);

            // exchange #3036
            // проверка прерывания проверки
            if vBreak then BREAK;

            xDoc24Info :=
                    FORMAT( 'Проверка ЭД № %s  Дата: %s Сумма = %s',
                            [ cdsList.FieldByName('Doc_Number').asString,
                              cdsList.FieldByName('Doc_Date').asString,
                              cdsList.FieldByName('Amount').asString]);
            try
              CheckPayOrderLocal;
              INC( n2);
              WriteLog(
                  FORMAT( '%s выполнена - %s',
                          [ xDoc24Info,
                            cdsList.FieldByName('ResText').asString]));
              except
                WriteInfo(
                    FORMAT( '%s не выполнена. Сбой: %s',
                            [ xDoc24Info,
                              LastException.Message]));
                INC( n3);
            end;

            cdsList.Next;
          end;
        finally
          d2 := NOW - d1;   // продолжительность операции

          WriteLog('Проверка выполнена.');
          WriteLog( FORMAT( 'Проверено ЭД: %s.', [ INTTOSTR( n1)]));
          WriteLog( FORMAT( 'Успешно проверено ЭД: %s.', [ INTTOSTR( n2)]));
          WriteLog( FORMAT( 'Сбоев во время проверки ЭД: %s.', [ INTTOSTR( n3)]));
          WriteLog( format('Продолжительность операции: %s',
                      [ formatdatetime('hh час(ов) mm мин. ss сек. zzz мсек.', d2)]));

          if (actBreak <> NIL)
            then actBreak.Enabled := FALSE;

          DBGrid.Enabled := True;
          cdsList.EnableControls;
          ProgressBar.Position := 0;
          CursorEnable;
          DBGrid.BookmarkCheckAll;

          // exchange #2431
          // восстанавливаем параметры сортировки полей и пересортируем таблицу
          for i:=1 to imax do begin
            i2 := a_si[i];
            xFieldName := DBGrid.Columns.Items[i2].FieldName;
            // особенность в том, что в начале нужно восстановить индекс,
            // и только потом порядок сортировки поля (вверх/вниз)
            DBGrid.FieldColumns[ xFieldName ].Title.SortIndex  := i2;
            DBGrid.FieldColumns[ xFieldName ].Title.SortMarker := a_sm[i];
          end;//for//
          DBGrid.DefaultApplySorting;
          DBGrid.RestorePosition;
          // exchange #2786
          // разблокируем главную форму
          FmList.Enabled := TRUE;
          FmDoc.Enabled := TRUE;
          FmList.SimpleText := '';
          SetAppEnable;
        end;
      end;

      // в случае ошибок открываем журнал info
      if (n3 > 0) then ShowFileInfo;
      except
        ExceptionProc( 'actCheckExecute');
    end;
end; {End actCheckExecute}

procedure LoadcbOrgAccount;
var
  i: Integer;
  Xml: Variant;
begin
    try
      cbOrgAccount.Items.Clear;
      Query.AddStr( Budget_Id);
      Xml := CreateOleObject('Microsoft.XmlDom');
      Xml.loadXML(
            Query.Run( 'Select distinct P.Rec_Account From PayOrder P' +
                      ' Left Join OrgAccount Oa on Oa.Id = P.Rec_Acc_Id' +
                      ' Join Budget B on ((Oa.Org_Id = B.Org_Id and P.Budget_Id = B.Id)' +
                        ' or (Oa.Org_Id = B.Executor_Id and P.Budget_Id = B.Id))' +
                      ' Where P.Budget_Id = ? and P.DocumentClass_Id = 24'));
      Xml := Xml.documentElement.childNodes;
      for i := 0 to Xml.length - 1
        do cbOrgAccount.Items.Add(Xml.items[i].attributes.item[0].nodeValue);
      if cbOrgAccount.ItemIndex < 0
        then cbOrgAccount.ItemIndex := 0;
      except
        ExceptionProc( 'LoadcbOrgAccount');
    end;
end; {End LoadcbOrgAccount}

procedure AppEventsMessage;
begin
  dtmDate.Enabled := DateEnabled And AppEnable;
  dtmBankDate.Enabled := BankDateEnabled And AppEnable;
  cbOrgAccount.Enabled := OrgAccountEnabled And AppEnable;
  FmList.actRefresh.Enabled := AppEnable;
  actCheck.Enabled := AppEnable And (cdsList.recordCount <> 0);
  actEdit.Enabled := AppEnable And (cdsList.recordCount <> 0);
  actExecute.Enabled := AppEnable And (DBGrid.bookmark.Count <> 0);
  Account.Enabled := AppEnable;
  Industry_Code.Enabled := AppEnable;
  Grantinvestment_Code.Enabled := AppEnable;
  Kesr_Code.Enabled := AppEnable;
  Fsr_Id.Enabled := AppEnable;
  DBGrid.SortLocal := AppEnable;
end; {End AppEventsMessage}

function BookmarkCheckEvents: Boolean;
begin
  try
    Result := (cdsList.FieldByName('Enroll').Value <> Null)
      or (DBGrid.Bookmark.IndexOf(cdsList.FieldByName('ID').AsString) >= 0);
    except
      raise ('Сбой BookmarkCheckEvents: '+ LastException.Message);
  end;
end; {End BookmarkCheckEvents}

procedure PayOrderEdit(Sender: TObject);
begin
    try
      if cdsList.recordCount = 0 then Exit;

      if VarIsNULL( cdsList.FieldByName('Enroll').Value){ = Null} then
        actCheckExecute(nil);


      if FmDoc.ActiveControl = nil then
        FmDoc.ActiveControl := Account;

      if FDebuger then
      begin
        FmDoc.Show;
        repeat
          Application.handleMessage;
        until(not FmDoc.Visible);
      end else
        FmDoc.ShowModal;

      if cdsList.isEdit
        then actCheckExecute(nil);

      FmList.ActiveControl := DBGrid;
      except
        ExceptionProc( 'PayOrderEdit');
    end;
end; {End PayOrderEdit}

procedure actExecuteExecute(Sender: TObject);
var
  xDoc24Info: string;
  n1,n2,n3: integer;
  d1,d2: TDateTime;
  xMakeOk: boolean;
begin
    try
      n1 := 0;    // всего
      n2 := 0;    // успешно зачислено
      n3 := 0;    // сбоев

      // exchange #2786
      // на время операции блокируем главную форму
      FmList.Enabled := FALSE;
      FmDoc.Enabled := FALSE;
      FmList.SimpleText := 'Создание распоряжений на зачисление средств на л/с ...';
      WriteLog('-----------------------------------------------------------');
      WriteLog( 'Создание распоряжений на зачисление средств на л/с ...');
      cdsList.DisableControls;
      DBGrid.Enabled := False;
      CursorDisable;
      if (actBreak = NIL)
        then SetAppDisable;
      ProgressBar.Max := DBGrid.bookmark.Count;

      d1 := NOW;
      try
        vBreak := FALSE;
        if (actBreak <> NIL)
          then actBreak.Enabled := TRUE;

        // exchange #3036
        // переделан алгоритм зачислений
        // вместо медленной операции locate используется перебор по dataset
        // с проверкой на галку в закладках.
        if (DBGrid.Bookmark.Count > 0) then begin
          // exchange #3036
          // формируем данные для зачисления
          DoMakeListEnrolments;
          // зачисляем по каждой отмеченной записи
          cdsList.First;
          while NOT cdsList.EOF do begin
            // exchange #3036
            // проверка прерывания проверки
            if vBreak then BREAK;

            xMakeOk := FALSE;  // не зачислен
            if (DBGrid.Bookmark.IndexOf( cdsList.FieldByName('ID').AsString) <> -1)
              then begin
                INC( n1);     // всего
                xDoc24Info :=
                        FORMAT( 'Зачисление для ЭД № %s  Дата: %s Сумма = %s',
                                [ cdsList.FieldByName('Doc_Number').asString,
                                  cdsList.FieldByName('Doc_Date').asString,
                                  cdsList.FieldByName('Amount').asString]);
                try
                  WriteLog(
                      FORMAT( '%s выполнено. %s',
                              [ xDoc24Info,
                                MakeMoneyTransferOrder]));
                  INC( n2);
                  xMakeOk := TRUE;  // зачислен
                  except
                    WriteInfo(
                        FORMAT( '%s не выполнено. Причина: %s',
                                [ xDoc24Info,
                                  LastException.Message]));
                    //xErrors := TRUE;
                    INC( n3);
                end;

                ProgressBar.Position := ProgressBar.Position + 1;
                // дополнительная проверка, чтобы не доходить до конца списка
                // если обработаны все закладки.
                // это на случай, если последняя закладка не в конце записей.
                if (DBGrid.Bookmark.Count <= 0)
                  then BREAK;
              end;

            // exchange 3128
            // проблема связана с тем, что при удалении записи курсор
            // автоматически позицируется на след.запись, поэтому переход
            // к след.записи делать не нужно. в результате, если операция
            // зачисления выполнена - удаляем запись, иначе переходим к след.
            if xMakeOk then begin
              DBGrid.BookmarkUnCheck;
              cdsList.Delete;
            end else begin
              cdsList.Next;
            end;
          end;//while//
          // освобождаем память после зачисления
          DoClearEnrolments;
        end;
        finally
          d2 := NOW - d1;   // продолжительность операции

          WriteLog( 'Зачисление выполнено.');
          WriteLog( FORMAT( 'Обработано ЭД: %s.', [ INTTOSTR( n1)]));
          WriteLog( FORMAT( 'Успешно зачислено ЭД: %s.', [ INTTOSTR( n2)]));
          WriteLog( FORMAT( 'Ошибок зачислений ЭД: %s.', [ INTTOSTR( n3)]));
          WriteLog( format('Продолжительность операции: %s',
                      [ formatdatetime('hh час(ов) mm мин. ss сек. zzz мсек.', d2)]));

          if (actBreak <> NIL)
            then actBreak.Enabled := FALSE;

          ProgressBar.Position := 0;
          cdsList.EnableControls;
          DBGrid.Enabled := True;
          // exchange #2786
          // разблокируем главную форму
          FmList.Enabled := TRUE;
          FmDoc.Enabled := TRUE;
          FmList.SimpleText := '';
          CursorEnable;
          SetAppEnable;
      end;

      // в случае ошибок открываем журнал info
      if (n3 > 0) then ShowFileInfo;
      except
        ExceptionProc( 'actExecuteExecute');
    end;
end; {End actExecuteExecute}

function MakeMoneyTransferOrder: string;
var
  sql: String;
  XmlLink, Xml, KesrXml: Variant;
  xDoc203ID: string;
  xDoc24_ID: string;
  xRecID: string;
  xRecInfo: Variant;
  xKESR_Code, xDescription: string;
  xKESR_TYPE, xKESR_DIRECTION: string;
begin
    try
      Result := '';
      // exchange #3036
      // в результате оптимизации запросов проверяем, если есть ассоциация
      // эд24 - эд203, то линкуем документ 203-й с главным 24-м
      xDoc203ID := DoSearch_ED203_by_ED24( cdsList.FieldByName('Id').AsString);
      if (LENGTH( xDoc203ID) > 0) then begin
          // линкуем документ 203-й с главным 24-м
          WriteLog( FORMAT( 'Линковка ЭД 203го (%s) с 24м (%s).',
                            [ xDoc203ID,
                              cdsList.FieldByName('Id').AsString]));
          ExecProc( 'DOCUMENT',
                    [ 'action', 'link',
                      'class', '203',
                      'ID', xDoc203ID,
                      'PARENT_ID', cdsList.FieldByName('Document_Id').AsString],
                    cdsList.FieldByName('Budget_Id').AsString);
          Result := 'Слинкован с ЭД 203м.';
          EXIT;
        end;

      WriteLog( FORMAT( 'Зачисление ЭД 24го (%s).',
                        [ cdsList.FieldByName('Id').AsString]));

      XmlLink := CreateOleObject('Microsoft.XmlDom');
      // выполняется экшен - в результате формируется слинкованный эд 193й
      // с эд 24м
      XmlLink.LoadXml(
          ExecProc(
              'DOCUMENT',
              [ 'action', 'spawn_money_transfer_order',
                'class', 24,
                'ID', cdsList.FieldByName('Id').AsString,
                'VERSION', cdsList.FieldByName('Version').AsString],
              cdsList.FieldByName('Budget_Id').AsString));

      // ищем этот 193й
      Query.addLong(cdsList.FieldByName('Document_Id').AsString);
      XmlLink.LoadXML(
          Query.Run(
               ' Select P.Id From MoneyTransferOrder P'
              +' Left Join Document D On (D.Id = P.Document_Id)'
              +' Where D.Parent_Id = ? And D.DocumentClass_Id = 193'
              +' And D.DispStatus_Id <> -1'));
      // загружаем его
      XmlLink.LoadXML(
          ExecProc(
              'DOCUMENT',
              [ 'action', 'read',
                'class', 193,
                'ID', XmlLink.documentElement.childNodes.item[0].getAttribute('ID')],
              cdsList.FieldByName('Budget_Id').AsString));

      // обновляем 193й
      XmlLink := XmlLink.documentElement;
      XmlLink.setAttribute('action', 'update');
      XmlLink.setAttribute('class', 193);
      XmlLink.setAttribute('DOC_DATE', GetNodeAttributeEx( XmlLink, 'CARRY_DATE'));
      XmlLink.setAttribute('OPERTYPE_ID', 0);
      XmlLink.setAttribute('PAY_ID', cdsList.FieldByName('Pay_Id').AsString);
      XmlLink.setAttribute('PAY_TAXCODE', cdsList.FieldByName('Pay_Taxcode').AsString);
      XmlLink.setAttribute('PAY_KPP', cdsList.FieldByName('Pay_Kpp').AsString);
      XmlLink.setAttribute('PAY_NAME', cdsList.FieldByName('Pay_Name').AsString);
      
            { exchange #3108
        у всех разборщиков: Общий, Красноярск, Челябинск, Тольяти, Рязань,
        Екатеренбург, Пермь) обновить эд 193й следующим образом:
          1) Поле "Тип классификации" заполнять значением бюджетной
              классификации карточки кода "Экономическая классификация",
              значение которого указано в поле "КОСГУ".
                Если значение бюджетной классификации для кода равно "Нет" И
              значение КОСГУ отлично от "Не указана" (000),
              то поле "Тип классификации" заполнять значением "Доходы";
                Если значение КОСГУ ="Не указана", то поле "Тип классификации"
              заполнять значением "Расходы".
          2. Поле "Направление операции" заполнять значением:
              "Восстановление выплат" для типа классификации "Расходы" ;
              "Поступление" для типа  классификации "Доходы";
              "Восстановление выплат" для типа классификации "Источники",
              если значение поля "КОСГУ"=610;
              "Поступление" для типа классификации "Источники",
              если значение поля "КОСГУ"=510.
              Если источники не равны 610 или 510 (что мало вероятно),
              то ставить тип классификации "Источники" и направление
              операции "Поступление".
          не забываем, что косгу = 000 это есть "не указано"}
      xKESR_Code := cdsList.FieldByName('Kesr_Code').AsString;

      XmlLink.setAttribute('KESR_CODE', xKESR_Code);
      if (LENGTH( StringReplace( xKESR_Code, '0', '')) <= 0)
        then xKESR_TYPE := '2'    // расходы
        else begin
          KesrXML := QueryXml( ' select ANAL_KIND, DIRECTION from kes where code=?'
                                   +' and budget_id=?',
                                    [ xKESR_Code,
                                      cdsList.FieldByName('Budget_Id').AsString]);
          if(KesrXML.documentElement.ChildNodes.length > 0) then
          begin
            xKESR_TYPE := KesrXML.documentElement.ChildNodes[0].getAttribute('ANAL_KIND');
            xKESR_DIRECTION := KesrXML.documentElement.ChildNodes[0].getAttribute('DIRECTION');
          end
          else
          begin
            xKESR_TYPE := '';
            xKESR_DIRECTION := '';
          end;
          if (xKESR_TYPE = '0')
            then xKESR_TYPE := '1';  // доходы
        end;
      XmlLink.setAttribute('CR_ANAL_KIND', xKESR_TYPE);
      case xKESR_TYPE of
        // доходы
        '1': XmlLink.setAttribute('CR_DIRECTION', '2');   // поступления
        // расходы
        '2': XmlLink.setAttribute('CR_DIRECTION', '3');  // восст выплат
        // источники
        '3': case xKESR_Code of
               '610': XmlLink.setAttribute('CR_DIRECTION', '3'); // восст выплат
               '510': XmlLink.setAttribute('CR_DIRECTION', '2'); // поступления
               else   XmlLink.setAttribute('CR_DIRECTION', '2'); // поступления
             end;//case//
      end;//case//


      XmlLink.setAttribute('KVR_CODE', cdsList.FieldByName('Kvr_Code').AsString);
      XmlLink.setAttribute('KSDA_CODE', cdsList.FieldByName('Ksda_Code').AsString);

      //неклассифицированные поступления
      if (cdsList.FieldByName('Unclassified').AsInteger = 1) then
      begin
        //    if AzkCompareVersion('2.26.46.1') >= 0 then
        //IF TRUE THEN begin
        if vIsAzkVersion2_26_46_1 then begin
          XmlLink.setAttribute('REC_ID', cdsList.FieldByName('Unclass_Org_Id').AsString);
          XmlLink.setAttribute('REC_TAXCODE', cdsList.FieldByName('Unclass_Org_Taxcode').AsString);
          XmlLink.setAttribute('REC_KPP', cdsList.FieldByName('Unclass_Org_Kpp').AsString);
          XmlLink.setAttribute('REC_NAME', cdsList.FieldByName('Unclass_Org_Name').AsString);
        end else begin
          XmlLink.setAttribute('REC_ID', cdsList.FieldByName('Rec_Id').AsString);
          XmlLink.setAttribute('REC_TAXCODE', cdsList.FieldByName('Rec_Taxcode').AsString);
          XmlLink.setAttribute('REC_KPP', cdsList.FieldByName('Rec_Kpp').AsString);
          XmlLink.setAttribute('REC_NAME', cdsList.FieldByName('Rec_Name').AsString);
        end;
      end else begin //классифицированные поступления
        XmlLink.setAttribute('REC_ID', cdsList.FieldByName('Org_Id').AsString);
        XmlLink.setAttribute('REC_TAXCODE', cdsList.FieldByName('Org_Taxcode').AsString);
        XmlLink.setAttribute('REC_KPP', cdsList.FieldByName('Org_Kpp').AsString);
        XmlLink.setAttribute('REC_NAME', cdsList.FieldByName('Org_Name').AsString);
      end;

      // exchange #2584
      // если получатель известен, то инн, кпп и название берем из карточки
      // организации.
      // но учредитель
      xRecID := GetNodeAttributeEx( XmlLink, 'REC_ID');
      if (LENGTH( xRecID) > 0) then begin
        xRecInfo := CreateOleObject('Microsoft.XmlDom');
        try
          Query.AddStr( xRecID);
          xRecInfo.LoadXML(
              Query.Run( ' select o.*, o.manager_id GRBS_ID, i.description GRBS_NAME'
                        +' from org o left join org i on i.id=o.manager_id where o.id=?'));
          xRecInfo := xRecInfo.documentElement.childNodes;
          if (xRecInfo.Length = 1) then begin
            xRecInfo := xRecInfo.Item[0];
            // вышестоящая организация (учредитель)
            if (LENGTH( VarToStr( xRecInfo.GetAttribute( 'GRBS_ID'))) > 0) then begin
              XmlLink.setAttribute( 'GRBS_ID'  , GetNodeAttributeEx( xRecInfo, 'GRBS_ID'));
              XmlLink.setAttribute( 'GRBS_NAME', GetNodeAttributeEx( xRecInfo, 'GRBS_NAME'));
            end;
          end;
          finally
            xRecInfo := NULL;
        end;
      end;

      XmlLink.setAttribute('REC_ACC_ID', cdsList.FieldByName('LS_Id').AsString);
      XmlLink.setAttribute('REC_ACCOUNT', cdsList.FieldByName('LS_Number').AsString);

      XmlLink.setAttribute('FSR_ID', cdsList.FieldByName('Fsr_Id').AsString);
      XmlLink.setAttribute('INDUSTRYCODE_ID',
        cdsList.FieldByName('Industrycode_Id').AsString);
      XmlLink.setAttribute('GRANTINVESTMENT_ID',
        cdsList.FieldByName('Grantinvestment_Id').AsString);
      XmlLink.setAttribute('DESCRIPTION',
        cdsList.FieldByName('Description').AsString);
      XmlLink.setAttribute('UNKNOWN_LAST_YEAR_FLAG', 0);

      XmlLink := XmlLink.ownerDocument;
      XmlLink.LoadXml(ExecXML(XmlLink.xml, cdsList.FieldByName('Budget_Id').AsString));

      Result := 'Создан и обновлен ЭД 193й.';
      except
        ExceptionProc( 'MakeMoneyTransferOrder');
    end;
end; {End MakeMoneyTransferOrder}

const
  WorkAppVersion = '5.0.3.37';

procedure CheckWorkAppVersion;
begin
  if CompareVersion(AppVersion, WorkAppVersion) < 0 then
    raise('Скрипты работают с AzkEchange.Exe начиная с версии: ' + WorkAppVersion +
      ''#13#10'Текущая версия AzkEchange.Exe: ' + AppVersion);
end; {End CheckWorkAppVersion}

procedure DoWriteJournal_( aMessage: String);
begin
  if (vFileJournal <> '')
    then WriteLogFile( vFileJournal, aMessage);
end; {End WriteLog}

procedure WriteLog(Message: String);
begin
  DoWriteJournal_( Message);
  if FileLog <> '' then
    WriteLogFile(FileLog, Message);
end; {End WriteLog}

procedure WriteInfo(Message: String);
begin
  DoWriteJournal_( Message);
  WriteLogFile(FileInfo, Message);
  WriteLogFile(FileLog, Message);
end; {End WriteInfo}


{~ShowFileInfo
  если есть журнал fileInfo - открываем вместо него vFileJournal.
  в журнале vFileJournal содержится вся информация, а в журнал info
  записываются только ошибки!}
procedure ShowFileInfo;
begin
  if FileExists( FileInfo) then
    if FileExists( vFileJournal)
      then ShellExecute('NotePad', vFileJournal, False)
      else ShellExecute('NotePad', FileInfo, False);
end;

var
  Xml: Variant;

begin
  FAzkIsLogin := AzkIsLogin;
  FDebuger := True;
  Xml := CreateOleObject('Microsoft.XmlDom');
  if not FileExists('C:\Temp\MoneyTransferOrder.Xml') then
  begin
    ShowMessage('Не найден тестовый пример: C:\Temp\MoneyTransferOrder.Xml');
    Exit;
  end;
  if not Xml.Load('C:\Temp\MoneyTransferOrder.Xml') then
  begin
    ShowMessage('Ошибка при загрузке: C:\Temp\MoneyTransferOrder.Xml');
    Exit;
  end;
  if not AzkIsLogin then
    if not AzkLogin then
      Exit;
  try
    Main(Xml);
  finally
    if not FAzkIsLogin then
      AzkLogout;
  end;
end.
