{~DoExportKBK
  выгрузка КБК
  aBudgetID - бюджет
  aCfgOutListKbk - опция конфигурации: "выгружать в список"}
procedure DoExportKBK( aBudgetID: string; aCfgOutListKbk: boolean);
var
  xSLInc,xSLSrc,xSLExp: TStringList;
  xFileNameExport: string;
  xPacketNumber: integer;
begin

    try
      WriteLog( 'Экспорт КБК из справочников кодов расходов, доходов, источников...', TRUE);
      // проверяем необходимую версию АЦК Финансы и AZKExchange
      if NOT CompareVersionAZK_Finance( 'Выгрузка КБК', '2.28') then EXIT;
      if NOT CompareVersionAZK_Exchange( 'Выгрузка КБК', '5.0.3.48') then EXIT;
      // формируем списки для выбранных ID КБК: доходы, источники, расходы
      SelectionsKBKListCreate( xSLInc, xSLSrc, xSLExp);
      try
        
        { значение даты последней выгрузки КБК для текущего бюджета.
          получаем его из файла Send.dat для текущего бюджета.
          загрузка параметра даты в файле Send.Dat для бюджета aBudgetID.
          если даты не будет (или такого бюджета), дата должны быть указана
          на 1990/1/1 0:0:0:0}
        vCfgSelectorKBK_LastDate := DateTimeFromStr_YYYYMMDD_HHMMSS(
                                        LoadFromSendDat(
                                            'ВЫГРУЗКА_КБК',
                                            'БЮДЖЕТ_' + aBudgetID,
                                            '1990/01/01 00:00:00'));


        // заполнение нулевых кодов.
        // всвязи с переходом на символьные КБК, нулевые коды как раньше "<>0"
        // не прокатит. требуется по маске получить код, соответствующий длины.
        // предзагрузка кодов нужна для ускорения дальнейшей работы,
        // поскольку дает загрузку кодов один раз, а не при каждом запросе.
        // здесь не требуется получать код с разделителями (для отображения
        // на формах) - только по длине действительной части кода.
        // поэтому при вызове функции FormatKbk последний параметр =0 (по умолчанию).
        vKBK0_KADM := FormatKbk( 'KADM', '0', aBudgetID);
        vKBK0_KD   := FormatKbk( 'KD', '0', aBudgetID);
        vKBK0_KES  := FormatKbk( 'KES', '0', aBudgetID);
        vKBK0_KI   := FormatKbk( 'KI', '0', aBudgetID);
        vKBK0_KFSR := FormatKbk( 'KFSR', '0', aBudgetID);
        vKBK0_KCSR := FormatKbk( 'KCSR', '0', aBudgetID);
        vKBK0_KVR  := FormatKbk( 'KVR', '0', aBudgetID);


        //Загрузка схемы
        // exchange #2542 - переход на тфф11 + переработка модуля проверки версий схем
        LoadSchema( GetFileNameSchemaTFF( 'dk_txdk*'));
//        LoadSchema(DirIni + 'Schems\dk_txdk090925.xml');
        // выгрузка КБК
        if MakeFormatKBK( aBudgetID, xSLInc, xSLSrc, xSLExp, aCfgOutListKbk) then begin
          //валидация схем.
          if param_CtlValidOn then
            if not ValidateFormat then
              if Not ShowMessageValid( FileValidate) then begin
                WriteLog('Выгрузка прервана пользователем');
                Exit;
              end;
          
          // имя файла экспорта XML
          WriteLog('Формирование имени выгружаемого файла', True);
          // Чтение номера посылки.
          xPacketNumber := LoadSendDatPacketNumber( 'КБК');
          xFileNameExport :=
                DirOut + GetFileName( Fo.getAttribute('NAME'),
                                      'DK',
                                      Now,
                                      xPacketNumber,
                                      FileOutIsLocalNet,
                                      FileOutOrgCodeIsFk);
          
          // сохраняем XML в текстовом файле
          
          try
            WriteLog( FORMAT( 'Сохранение XML в файле "%s"...', [ xFileNameExport]), TRUE);
            XmlToTextFile( xFileNameExport);
            except
              ExceptionLog( 'Сбой сохранения XML');
          end;
          // фиксируем экспорт на сервере АЦК-финансы
          FixedExportedKBKList( xFileNameExport, xSLInc, xSLSrc, xSLExp);
          // сохраняем номер выгрузки
          SaveSendDatPacketNumber( 'КБК', xPacketNumber);
          { сохраняем дату выполнения операции как дату выгрузки КБК
            сохранение параметра в файле Send.Dat }
          SaveToSendDat(  'ВЫГРУЗКА_КБК',
                          'БЮДЖЕТ_' + aBudgetID,
                          DateTimeToStr_YYYYMMDD_HHMMSS( NOW));
        end;
        finally
          SelectionsKBKListFree( xSLInc, xSLSrc, xSLExp);
      end;

      except
        ExceptionProc( 'DoExportKBK');
    end;

end;


{~MakeFormatKBK
  главная функция выгрузки справочников КБК.
  здесь создается и запускается форма выбора КБК для выгрузки и выполняется
  формирование список КБК для выгрузки.}
function MakeFormatKBK( aBudgetID: string;
                        aSLInc,aSLSrc,aSLExp: TStringList;
                        aCfgOutListKbk: Boolean): Boolean;
var
  i: Integer;
  CodeList: TStringList; //содержит список выгруженных кодов
  XmlListCodeforCds: Variant; //содержит перечень кодов для выбора из списка.
  xForm: TFormCustomList;
  xCdsList: TClientDataSet;
  xDbGrid: TDBGridEh;
  xtlbFilterClear,
  xtlbFilter,
  xtlbRefresh: TToolButton;
  xPanelFilter: TPanel;
  xPanelFilterToolBar: TPanel;
  xRadioTypeKbk,
  xrgFilterKBK: TRadioGroup;
  xEdtCdsId, xedKesCode, xedKadmCode: TEdit;
  xspbKesCode, xspbKadmCode: TSpeedButton;

  { событие вызывается при включении/выключении панели фильтра.
    при этом выполняется лишь управление видимостью панели фильтра и больше ничего. }
  procedure OnKbkFilter_FilterKBK_Show(Sender: TObject);
  begin
    try

      xPanelFilter.Visible := xtlbFilter.Down;
      Application.ProcessMessages;

      except
        ExceptionLog( 'Сбой скрипта: "Exp_FK_KBK.MakeFormatKBK.OnKbkFilter_FilterKBK_Show".');
    end;
  end;

  { событие вызывается при любом изменении значения в контролах фильтра на
    форме. при этом описываются строки фильтра и обновляется список КБК.
    при больших объемах }
  procedure OnKbkFilter_FilterKBK(Sender: TObject);
  begin
    
    try
      // описание о дополнительных символах "," в строказ фильтра
      // есть в описании фильтра в подпрограмме InsertKBKListToCdsEx
      // (см. вложенную подпрограмму: DoFilterKBK)
      case xRadioTypeKbk.ItemIndex of
        0: vFilterKBK_TypeKBK := '10,';
        1: vFilterKBK_TypeKBK := '20,';
        2: vFilterKBK_TypeKBK := '31,32,';
      else vFilterKBK_TypeKBK := '';
      end;

      if (xedKadmCode.Text = '')
        then vFilterKBK_KadmCode := ''
        else vFilterKBK_KadmCode := ',' + xedKadmCode.Text + ',';
    
      if (xedKesCode.Text = '')
        then vFilterKBK_KesCode := ''
        else vFilterKBK_KesCode := ',' + xedKesCode.Text + ',';

      
        

      // exchange #2693
      // на время фильтрации блокируем панель фильтра
      xPanelFilter.Enabled := FALSE;
      xPanelFilterToolBar.Enabled := FALSE;
      try
        xDbGrid.BookmarkUnCheckAll;
        InsertKBKListToCds(
              xCdsList,
              xDbGrid,
              LoadKBKFromDictionaries( aBudgetID, xrgFilterKBK.ItemIndex),
              aBudgetID);
        finally
          xPanelFilter.Enabled := TRUE;
          xPanelFilterToolBar.Enabled := TRUE;
      end;

      
      except
        ExceptionLog( 'Сбой скрипта: "Exp_FK_KBK.MakeFormatKBK.OnKbkFilter_FilterKBK".');
    end;
  end;

  procedure OnKbkFilter_ClearFilterKBK(Sender: TObject);
  begin
    xRadioTypeKbk.ItemIndex := -1;
    xrgFilterKBK.ItemIndex := -1;
    xedKadmCode.Text := '';
    xedKesCode.Text := '';
    OnKbkFilter_FilterKBK( Sender);
  end;

  procedure OnspbKesCodeOnClick(Sender: TObject);
  begin
    xEdKesCode.Text := GetKbkForFilter('Kes');
  end;

  procedure OnspbKadmCodeOnClick(Sender: TObject);
  begin
    xEdKadmCode.Text := GetKbkForFilter('Kadm');
  end;

begin

    try
      Result := False;
      xForm := NIL;

      Data := Data.documentElement;
      //создаем xml c текущей историей из базы
      CurrHistory := CreateOleObject('Microsoft.XmlDom');
      CurrHistory := CurrHistory.appendChild(CurrHistory.createElement('HISTORY'));
      CurrHistory := CurrHistory.appendChild(CurrHistory.ownerDocument.createElement('KBK'));

      //ищем node KBK
      NodeXmlList := OldKbk.selectNodes('KBK');
      if NodeXmlList.Length = 0
        then OldKbk := OldKbk.appendChild(OldKbk.ownerDocument.createElement('KBK'))
        else OldKbk := NodeXmlList.Item[0];
      
      Data := Data.appendChild(FillElementBySchema(Fo, 'FK'));
      Data.setAttribute('FORM_VER', AppVersion);
      Data := Data.parentNode;
      Data := Data.appendChild(FillElementBySchema(Fo, 'FROM'));
      Data.setAttribute('BUDG_LEVEL', GetBudgLevel(aBudgetID));
      Data := Data.parentNode;
      Data.appendChild(FillElementBySchema(Ufk, 'TO'));
      Data := Data.appendChild(FillElementBySchema(Fo, 'DK'));
      Data.setAttribute('NAME_BUD', QueryField(sqlBudgId, [aBudgetID], 'CAPTION'));
      Data.setAttribute('DATE_FORM', FormatDateTime('dd.mm.yyyy', Now));
      Data.setAttribute('DOL_ISP', DolIsp);
      Data.setAttribute('NAME_ISP', FioIsp);
      Data.setAttribute('TEL_ISP', TelIsp);
      Data := Data.parentNode;
      CodeXmlList := null;

      XmlListCodeforCds := LoadKBKFromDictionaries( aBudgetID);
      if (XmlListCodeforCds.documentElement.ChildNodes.Length <= 0)
        then EXIT;

      try
        try
          
          xForm := TFormCustomList.Create(Application);
          
          LoadForm(DirIni + 'Forms\Fm_KbkListNew.dfm', xForm);
          
          xCdsList := TClientDataSet(xForm.FindComponent('CdsData'));
          xDbGrid := TDBGridEh(xForm.FindComponent('DbGrid'));

          xtlbFilterClear := TToolButton(xForm.FindComponent('tlbFilterClear'));
          xtlbFilter := TToolButton(xForm.FindComponent('tlbFilter'));
          xtlbRefresh := TToolButton(xForm.FindComponent('tlbRefresh'));

          xtlbFilterClear.OnClick := @OnKbkFilter_ClearFilterKBK;
          xtlbFilter.OnClick := @OnKbkFilter_FilterKBK_Show;

          // показываем панель тулбара
          xPanelFilterToolBar := TPanel( xForm.FindComponent('pnlTollBar'));
          if NOT xPanelFilterToolBar.Visible then xPanelFilterToolBar.Show;
          // показываем панель фильтра
          xPanelFilter := TPanel(xForm.FindComponent('PanelFilter'));
          if NOT xPanelFilter.Visible then xPanelFilter.Show;

          xedKesCode := TEdit(xForm.FindComponent('edKesCode'));
          xedKadmCode := TEdit(xForm.FindComponent('edKadmCode'));

          xspbKesCode := TSpeedButton(xForm.FindComponent('spbKesCode'));
          xspbKesCode.OnClick := @OnspbKesCodeOnClick;

          xspbKadmCode := TSpeedButton(xForm.FindComponent('spbKadmCode'));
          xspbKadmCode.OnClick := @OnspbKadmCodeOnClick;

          // exchange #3049
          // блокируем фильтрацию по косгу, если настройка =да.
          xedKesCode.Enabled := (vCfg_3049 = FALSE);
          xspbKesCode.Enabled := (vCfg_3049 = FALSE);

          xRadioTypeKbk := TRadioGroup(xForm.FindComponent('RadioTypeKbk'));
          xRadioTypeKbk.OnClick := @OnKbkFilter_FilterKBK;//@OnKbkFilter_TypeKBK;//@RadioTypeKbkOnClick;//Ex;

          xrgFilterKBK := TRadioGroup( xForm.FindComponent('rgFilterKBK'));
          xrgFilterKBK.OnClick := @OnKbkFilter_FilterKBK;//@RadioTypeKbkOnClick;

          xedKesCode.OnChange := @OnKbkFilter_FilterKBK;//@edKesCodeOnChange;
          xedKadmCode.OnChange := @OnKbkFilter_FilterKBK;//@edKadmCodeOnChange;

          xEdtCdsId := TEdit.Create(xForm);
          xForm.Edit := xEdtCdsId;
          xForm.SQLText := '';
          //
//          xForm.OnHide := @xFormOnHide;
          xForm.Caption := 'Список выгружаемых кодов бюджетной классификации...';

          // вызываем проверку видимости панели фильтра после создания формы.
          // это дает возможность правильно отобразить/скрыть панель по
          // состоянию кнопки видимости фильтра.
          OnKbkFilter_FilterKBK_Show( NIL);

          xForm.Show;
          xForm.Close;
          except
            ExceptionLog( 'Сбой создания формы выбора КБК.');
        end;

        // запихиваем на форму все загруженные КБК без учета фильтра
        InsertKBKListToCds( xCdsList, xDbGrid, XmlListCodeforCds, aBudgetID, FALSE);

        // если включена опция "выгружать КБК из списка" - открываем форму и
        // ждем выбора. если опции нет - выгружаем все загруженные КБК.
        
        if aCfgOutListKbk
          then begin
            xForm.Caption := 'Список выгружаемых кодов бюджетной классификации...';
            xtlbFilterClear.Visible := True;
            xtlbFilter.Visible := True;
            xtlbFilterClear.Show;
            xtlbFilter.Show;
            xtlbRefresh.Show;
            if (xForm.ShowModal = MrOk)
              then Kbk := GetSelectionsKBKFromList( xCdsList, xDbGrid, aSLInc, aSLSrc, aSLExp, TRUE)
              else EXIT;
          end else begin
            
            Kbk := GetSelectionsKBKFromList( xCdsList, xDbGrid, aSLInc, aSLSrc, aSLExp, FALSE);
          end;
        finally
          // разрушаем форму
          try
            if (xForm <> NIL) then xForm.Free;
            except
              ExceptionLog( 'Сбой разрушения формы');
          end;
    end;

    if VarIsNull( Kbk) then begin
      
      EXIT;
    end;
    //    InsertDataToCds(xCdsList, xDbGrid, XmlListCodeforCds.ownerDocument, True);
    //      if not VarIsNull(Kbk) then begin
      Kbk := Kbk.documentElement;
      ProgressBar.Max := Kbk.ChildNodes.Length;
      WriteLog('Формирование данных по КБК к выгрузке...', True);
      for i := 0 to Kbk.ChildNodes.Length - 1 do
      begin
        ProgressBar.Position := i + 1 ;
        Kbk := Kbk.ChildNodes.Item[i];
        Data := Data.appendChild(FillElementBySchema(Kbk, 'DKST'));

        // exchange #2629 - замена кавычек
        Data.setAttribute( 'NAME',
                           ExchangeQuoteChars2629(
                                            'DK',
                                            Kbk.getAttribute('DESCRIPTION')));

        // exchange #2392
        // добавлена выгрузка краткого названия кода
        // exchange #2629 - замена кавычек
        Data.setAttribute( 'CNAME',
                           ExchangeQuoteChars2629(
                                            'DK',
                                            Kbk.getAttribute('CAPTION')));

        Data.setAttribute('DATE_BEGIN', IfThen(Kbk.getAttribute('BEGIN_DATE') <> '',
          FormatDateTime('dd.mm.yyyy', XmlToDateTime(Kbk.getAttribute('BEGIN_DATE'))), ''));
        Data.setAttribute('DATE_END', IfThen(Kbk.getAttribute('END_DATE') <> '',
          FormatDateTime('dd.mm.yyyy', XmlToDateTime(Kbk.getAttribute('END_DATE'))), ''));
        Data.setAttribute('DATE_CHANGE', IfThen(Kbk.getAttribute('CHANGE_DATE') <> '',
          FormatDateTime('dd.mm.yyyy hh:nn:ss',
            XmlToDateTime(Kbk.getAttribute('CHANGE_DATE'))), ''));
        Data.setAttribute('TYPE_KBK', Kbk.getAttribute('TYPE_KBK'));



        { exchange #2396
          При выгрузке справочника кбк (DK) выгружать поле DKST.LIMIT из поля
          "Признак использования для лимитуемых расходов" шапки записи
          справочника "Коды расходов бюджета" - соответсвенно 0 или 1 в каждую
          строку DKST. Для строк доходов, источников поле в файле не заполнять.
          задача #2396 полностью заменяет #2393.
          exchange #2415
          выбор выгрузки значение в поле LIMIT определяется по опции в
          конфигурации.}
        if (Data.GetAttribute('TYPE_KBK') <> '10')
          then Data.setAttribute( 'LIMIT', '')
          else
            case vCfg_KBK_DKST_LIMIT_Option of
              1: Data.setAttribute( 'LIMIT', '1');
              2: Data.setAttribute( 'LIMIT', VarToStr(
                                                Kbk.getAttribute('LIMITED_FLAG')));
            else Data.setAttribute( 'LIMIT', '');   // на всякий случай
            end;//case//

        Data := Data.parentNode;
        Kbk := Kbk.parentNode;
      end;

      Result := Data.SelectNodes('DKST').length > 0;
      if not Result then OldKbk := OldKbk.parentNode;
      Data := Data.ownerDocument;

      except
        ExceptionProc( 'MakeFormatKBK');
    end;

end;

begin
end.
