{~GetSelectionsCodesFromList
 формируются списки выбранных КБК в таблице aDBGrid (aCdsList)
  в соответствующих объектах:
    aSLInc-доходы
    aSLSrc-источники
    aSLExp-расходы}
function GetSelectionsCodesFromList(
                    var aCdsList: TClientDataSet;
                    var aDBGrid: TDBGridEh;
                    var aListID: TStringList;
                    aSelected: boolean): variant;

  procedure DoSelected( xRoot: variant);
  var
    xNode: variant;
  begin
    // префикс (PREFIXID) определяет, к какому справочнику относится запись,
    // поскольку в результате в одном списке кодов могут быть идентификаторы
    // из разных таблиц (например KSI и KSD). если это поле не указано,
    // считается что все идентификаторы относятся к одной таблице.
    // можно было воспользоваться полем TYPE_KBK, но поскольку код доработан,
    // то не известно как он обрабатывается, и к тому же поле числовое,
    // что менее удобно чем строковое.
    // поле добавлено в контрол cdsData в файле Forms\Fm_KbkListNew.pas.
    aListID.Add( VarToStr( aCdsList.FieldByName('PREFIXID').AsString)
                + aCdsList.FieldByName('LINE_ID').AsString);

    xNode := xRoot.appendChild( Result.createElement('ROW'));

    // добавлено поле CODE_COPY
    // в нем содержится неформатированный код - его и выгружаем
    // если это поле пустое - выгружаем из осноного поля: CODE.
    if (aCdsList.FieldByName('CODE_COPY').AsString = '')
      then xNode.setAttribute( 'CODE', aCdsList.FieldByName('CODE').AsString)
      else xNode.setAttribute( 'CODE', aCdsList.FieldByName('CODE_COPY').AsString);

    xNode.setAttribute( 'CAPTION'    , aCdsList.FieldByName('CAPTION').AsString);
    xNode.setAttribute( 'DESCRIPTION', aCdsList.FieldByName('DESCRIPTION').AsString);
    xNode.setAttribute( 'BEGIN_DATE' , DateTimeToXml(
                                        aCdsList.FieldByName('BEGIN_DATE').AsDateTime));
    xNode.setAttribute( 'CHANGE_DATE', DateTimeToXml(
                                        aCdsList.FieldByName('CHANGE_DATE').AsDateTime));
{    xNode.setAttribute( 'UNLOAD_DATE', DateTimeToXml(
                                        aCdsList.FieldByName('UNLOAD_DATE').AsDateTime));}
    xNode.setAttribute( 'END_DATE'   , IfThen(
                                        aCdsList.FieldByName('END_DATE').AsString <> '',
                                        DateTimeToXml(aCdsList.FieldByName('END_DATE').AsDateTime),
                                        ''));
    xNode.setAttribute( 'TYPE_KBK'   , aCdsList.FieldByName('TYPE_KBK').AsString);
    xNode.setAttribute( 'LIMIT'      , aCdsList.FieldByName('LIMIT').AsString);
    // exchange #2396
    xNode.setAttribute( 'LIMITED_FLAG', aCdsList.FieldByName('LIMITED_FLAG').AsString);
  end;

var
  i: integer;
  xRoot: variant;
  xEmpty: boolean;
begin

    try
      if aSelected then begin
        
        xEmpty := (aDBGrid.Bookmark.Count <= 0);
      end else begin
        
        aCdsList.First;
        xEmpty := aCdsList.EOF;
      end;
      if xEmpty then begin
        
        Result := NULL;
        EXIT;
      end;

      
      Result := CreateOleObject('Microsoft.XmlDom');
      Result.appendChild(Result.createElement('EXCHQUERY'));
      xRoot := Result.documentElement;

      
      if aSelected then begin
        
        for i:= 0 to aDBGrid.Bookmark.Count-1 do
          if aCdsList.Locate( aDBGrid.FieldKey.FieldName,
                              aDBGrid.Bookmark[i],
                              nil)
            then DoSelected( xRoot);
      end else begin
        
        while NOT aCdsList.EOF do begin
          DoSelected( xRoot);
          aCdsList.Next;
        end;//while//
      end;

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

end;


function BuildFormSelectCodes( aCaption: string;
                               var aXmlSourceDoc: variant;
                               var aListID: TStringList;
                               aCfgOutListKbk: boolean;
                               aKbkDataCaption: string;
                               aKbkDataTopic: string;
                               aBudgetID: string): boolean;
var
  i: Integer;
  CodeList: TStringList; //содержит список выгруженных кодов
  XmlListCodeforCds: Variant; //содержит перечень кодов для выбора из списка.
  xForm: TFormCustomList;
  xCdsList: TClientDataSet;
  xDbGrid: TDBGridEh;
  xtlbFilterClear,
  xtlbFilter,
  xtlbRefresh: TToolButton;
  xPanelFilter: TPanel;
  xPanelToolBar: TPanel;
  xRadioTypeKbk,
  xrgFilterKBK: TRadioGroup;
  xEdtCdsId, xedKesCode, xedKadmCode: TEdit;
  xspbKesCode, xspbKadmCode: TSpeedButton;
  xBoxKbk: TGroupBox;

  function DoFilterCodes: boolean;
  var
    i,n,n2: Integer;
    xNode: variant;
    xCondition: boolean;
    xFilter_KBK_Detail: boolean;
    xFilter_KBK_KADM: boolean;
    xFilter_KBK_KES: boolean;
    xKBK: string;
    xFilter_Found: boolean;
  begin
  
      try
        // на время выполнения фильтрации блокируем панель фильтра и управления
        xPanelFilter.Enabled := FALSE;
        xPanelToolBar.Enabled := FALSE;
        try
          xCdsList.DisableControls;
          xDbGrid.BookmarkUnCheckAll;
          xDBGrid.Enabled := False;
          xCdsList.First;

          // exchange #2895
          // проверяем, нужно ли фильтровать по КАДМ/КОСГУ.
          // в начале определяем конкретную фильтрацию по полю, а потом
          // общую фильтрацию. это немного ускорит проверку на каждой итерации.
          xFilter_KBK_KADM  := (LENGTH( xEdKadmCode.Text) > 0);
          // exchange #3049
          // фильтрация по косгу допустима только если настройка конфига =нет.
          xFilter_KBK_KES   := ((LENGTH( xEdKesCode.Text) > 0) AND (vCfg_3049 = FALSE));
          xFilter_KBK_Detail:= (xFilter_KBK_KADM OR xFilter_KBK_KES);


          try
  
            xCdsList.First;
            while not xCdsList.Eof do begin
              xCdsList.Delete;
              xCdsList.First;
            end;
            except
              ExceptionLog( 'Сбой чистки списка');
          end;

          n := 0;   // число отфильтрованных записей
          try
  
            for i := 0 to aXmlSourceDoc.childNodes.Length - 1 do  begin
              xNode := aXmlSourceDoc.childNodes.Item[i];

              { условие для выгруженных записей:
                    +'    and ((~.unload_date is not null) and'// /* дата выгрузки указана (был выгружен) */
                    +'        (~.change_date<=~.unload_date)))',//  /* и небыло изменений после выгрузки */
                }
              xCondition := FALSE;
              if (xNode.getAttribute('UNLOAD_DATE') <> '') then
                if (xNode.getAttribute('CHANGE_DATE') <> '') then
                  if (XmlToDateTime( xNode.getAttribute('CHANGE_DATE'))
                       <= XmlToDateTime( xNode.getAttribute('UNLOAD_DATE')))
                    then xCondition := TRUE;

              // фильтр из контрола
              case xrgFilterKBK.ItemIndex of
                // выгруженные
                1: if NOT xCondition then CONTINUE;
                // не выгруженные.
                2: if xCondition then CONTINUE;
              end;//case//

              // exchange #2895
              // добавлен фильтр кбк по КАДМ/КОСГУ.
              // если фильтр по кбк выполняется, проверяем, входит ли
              // подстрока кбк в строки фильтра. если не входит - тек.строку
              // не добавляем в список.
              if xFilter_KBK_Detail then begin
                xKBK := xNode.getAttribute('CODE');
                xFilter_Found := FALSE;
(*

*)


                { exchange #3049
                  коды подстраиваем по длине масок.}
                if xFilter_KBK_KADM then begin
                  n2 := LENGTH( FormatKbk( 'KADM', '0', aBudgetID));
                  if ( POS( #39+Copy( xKBK, 1, n2)+#39,
                            xEdKadmCode.Text) > 0)
                    then xFilter_Found := TRUE;
                end;
                if xFilter_KBK_KES then begin
                  n2 := LENGTH( FormatKbk( 'KES', '0', aBudgetID));
                  if ( POS( #39+Copy( xKBK, LENGTH( xKBK) - (n2 - 1), n2)+#39,
                            xEdKesCode.Text) > 0)
                    then xFilter_Found := TRUE;
                end;

                if NOT xFilter_Found then CONTINUE;
              end;

              xCdsList.Append;
              xCdsList.FieldByName('CDSID'       ).AsInteger := i;
              xCdsList.FieldByName('LINE_ID'     ).AsString :=
                  xNode.getAttribute('LINE_ID');
              xCdsList.FieldByName('CODE'        ).AsString :=
                  xNode.getAttribute('CODE');

              // добавлено доп.поле - CODE_COPY
              // в нем будет содержаться неформатированное (по маске) значение
              // кода. его и надо будет выгружать.
              // для тех строк, где это поле не указано, код будет выгружаться
              // из поля CODE (по старому).
              xCdsList.FieldByName('CODE_COPY'   ).AsString :=
                  VarToStr( xNode.getAttribute('CODE_COPY'));

              xCdsList.FieldByName('CAPTION'     ).AsString :=
                  IfThen( xNode.getAttribute('CAPTION') <> '',
                          xNode.getAttribute('CAPTION'),
                          '');
              xCdsList.FieldByName('DESCRIPTION' ).AsString :=
                  IfThen( xNode.getAttribute('DESCRIPTION') <> '',
                          xNode.getAttribute('DESCRIPTION'),
                          '');
              if (VarToStr( xNode.getAttribute('BEGIN_DATE')) <> '')
                then xCdsList.FieldByName('BEGIN_DATE').AsDateTime :=
                        XmlToDateTime( xNode.getAttribute('BEGIN_DATE'));
              if (VarToStr( xNode.getAttribute('CHANGE_DATE')) <> '')
                then xCdsList.FieldByName('CHANGE_DATE').AsDateTime :=
                        XmlToDateTime( xNode.getAttribute('CHANGE_DATE'));
              if (VarToStr( xNode.getAttribute('UNLOAD_DATE')) <> '')
                then xCdsList.FieldByName('UNLOAD_DATE').AsDateTime :=
                        XmlToDateTime( xNode.getAttribute('UNLOAD_DATE'));
              if (VarToStr( xNode.getAttribute('END_DATE')) <> '')
                then xCdsList.FieldByName('END_DATE').AsDateTime :=
                        XmlToDateTime( xNode.getAttribute('END_DATE'));
              if not VarIsNull( xNode.getAttribute('TYPE_KBK'))
                then xCdsList.FieldByName('TYPE_KBK').AsString :=
                        xNode.getAttribute('TYPE_KBK');
              if not VarIsNull( xNode.getAttribute('LIMIT'))
                then xCdsList.FieldByName('LIMIT').AsString :=
                        xNode.getAttribute('LIMIT');
              // эти поля используются для выгрузки КБК. здесь не существенны
              xCdsList.FieldByName('KADMCODE').AsString := '';//Copy( xCode, 1, 3);
              xCdsList.FieldByName('KESCODE' ).AsString := '';//Copy( xCode, 18, 3);

              // exchange #2396
              // если поля нет - заполняем значение нулем
              xCdsList.FieldByName('LIMITED_FLAG'     ).AsString:=
                  IfThen( VarToStr( xNode.getAttribute('LIMITED_FLAG')) <> '',
                          xNode.getAttribute('LIMITED_FLAG'),
                          '0');
              // префикс идентификаторов
              xCdsList.FieldByName('PREFIXID').AsString :=
                          VarToStr( xNode.getAttribute('PREFIXID'));

              xCdsList.Post;
              INC( n);
            end;//for//
            except
              ExceptionLog( 'Сбой заполнения таблицы');
          end;
          finally
    //        aCdsList.First;
            xDBGrid.Enabled := True;
            xCdsList.EnableControls;
            // разблокируем панель фильтра и управления
            xPanelFilter.Enabled := TRUE;
            xPanelToolBar.Enabled := TRUE;
        end;
        if (n > 0)
          then Result := TRUE
          else Result := FALSE;
          except
          ExceptionLog( 'Сбой Un_Kbk3.DoFilterCodes');
      end;
  
  end;

{~DoFilterCodesChange
  обработка события изменения фильтра в контроле.
  здесь выполняем выборку данных на форме.}
  procedure DoFilterCodesChange( aSender: TObject);
  begin
    
        try
          DoFilterCodes;
          except
            ExceptionLog( 'Сбой Un_Kbk3.DoFilterCodesChange');
        end;
    
  end;

{~DoPrepareXmlKBK
  формирование XML выгруженных данных из формы.
  глобальная переменная Data должна быть предустановленна на раздел
  данных в XML результата. в этом разделе будут создаваться узлы для
  каждой выгружаемой строки справочника.
  aKbkDataCaption - название узла в XML результата.
  aKbkDataTopic - название схемы выгрузки (код раздела, например: FC или WN)}
  procedure DoPrepareXmlKBK( aKbkDataCaption, aKbkDataTopic: string);
  var
    xXmlKbkDoc: variant;
    xXmlKbkNode: variant;
    xXmlDataNode: variant;
  begin
    
        try
          xXmlKbkDoc := Kbk.documentElement;
          ProgressBar.Max := xXmlKbkDoc.ChildNodes.Length;
          WriteLog('Формирование данных к выгрузке...', True);
          for i := 0 to xXmlKbkDoc.ChildNodes.Length - 1 do
          begin
            ProgressBar.Position := i + 1 ;
            xXmlKbkNode := xXmlKbkDoc.ChildNodes.Item[i];
            xXmlDataNode := Data.appendChild(FillElementBySchema( xXmlKbkNode,
                                        aKbkDataCaption));

            // exchange #2629 - замена кавычек
            xXmlDataNode.SetAttribute( 'NAME',
                           ExchangeQuoteChars2629(
                                          aKbkDataTopic,
                                          xXmlDataNode.GetAttribute( 'NAME')));
            // exchange #2629 - замена кавычек
            xXmlDataNode.SetAttribute( 'CNAME',
                           ExchangeQuoteChars2629(
                                          aKbkDataTopic,
                                          xXmlDataNode.GetAttribute( 'CNAME')));

            xXmlDataNode.setAttribute(
                  'DATE_BEGIN',
                  IfThen( xXmlDataNode.getAttribute('DATE_BEGIN') <> '',
                          FormatDateTime(
                                'dd.mm.yyyy',
                                XmlToDateTime(
                                      xXmlDataNode.getAttribute('DATE_BEGIN'))),
                          ''));
            xXmlDataNode.setAttribute(
                  'DATE_END',
                  IfThen( xXmlDataNode.getAttribute('DATE_END') <> '',
                          FormatDateTime(
                                'dd.mm.yyyy',
                                XmlToDateTime(
                                      xXmlDataNode.getAttribute('DATE_END'))),
                          ''));
            xXmlDataNode.setAttribute(
                  'DATE_CHANGE',
                  IfThen( xXmlDataNode.getAttribute('DATE_CHANGE') <> '',
                          FormatDateTime(
                                'dd.mm.yyyy hh:nn:ss',
                                XmlToDateTime(
                                      xXmlDataNode.getAttribute('DATE_CHANGE'))),
                          ''));
          end;//for//
          except
            ExceptionLog( 'Сбой Un_Kbk32.DoPrepareXmlKBK');
        end;
        Data := Data.ownerDocument;
    
  end;


  procedure OnKbkFilter_ClearFilterKBK(Sender: TObject);
  begin

      try
//        xCdsList.Filter := '';
    //    RadioTypeKbk.ItemIndex := -1;
        xEdKesCode.Text := '';
        xEdKadmCode.Text := '';

//        if xDBGrid.Visible
//          then xDBGrid.SetFocus;

    //    xDBGrid.SumList.Active := False;
    //    xDBGrid.SumList.Active := True;

        DoFilterCodes;
        except
          ExceptionLog( 'Сбой OnKbkFilter_ClearFilterKBK');
      end;

  end; {End tlbFilterClearOnClick}

  (*
  //метод для установления фильтров.
  procedure DoSetKbkFilter_;
//  var
//    PFilter, Filter: String;
  begin
*
    try
      xDBGrid.BookmarkUnCheckAll;
      xCdsList.Filter := '';
      Filter := '';
      case RadioTypeKbk.ItemIndex of
        0: PFilter := 'Type_Kbk = 10';
        1: PFilter := 'Type_Kbk = 20';
        2: PFilter := 'Type_Kbk in (31, 32)';
      else PFilter := '';
      end;

      if edKesCode.Text <> '' then begin
        Filter := 'KesCode in (' + edKesCode.Text + ')';
        if edKadmCode.Text <> '' then
          Filter := Filter + ' and KadmCode in (' + edKadmCode.Text + ')';
      end else
        if edKadmCode.Text <> ''
          then Filter := 'KadmCode in (' + edKadmCode.Text + ')';

      if (PFilter <> '') and (Filter <> '')
        then Filter := Filter + ' and ' + PFilter
        else
          if PFilter <> '' then Filter := PFilter;

      xCdsList.Filter := Filter;
    except
      MessageDlg('Ошибка при установлении фильтра. Количество данных фильтра' +
        ' превышает допустимое значение', mtError, mbOk, 0);
      xCdsList.Filter := '';
      OnKbkFilter_ClearFilterKBK(nil);
    end;
    xDBGrid.SumList.Active := False;
    xDBGrid.SumList.Active := True;
    *
  end;*)

  procedure OnKbkFilter_FilterKBK(Sender: TObject);
  begin

      try
        DoFilterCodes;
        except
          ExceptionLog( 'Сбой OnKbkFilter_FilterKBK');
      end;

  end;

begin

    try
      WriteLog( FORMAT( 'Экспорт кодов "%s".', [aCaption]),
                TRUE);
      try
        
        xForm := TFormCustomList.Create(Application);
        try
          
          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;

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

          xBoxKbk:= TGroupBox(xForm.FindComponent('BoxKbk'));
  //          if xBoxKbk.Visible then xBoxKbk.Hide;

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

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

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

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

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

          // фильтр с предустановленным значением "ВСЕ"
          xrgFilterKBK := TRadioGroup( xForm.FindComponent('rgFilterKBK'));
          xrgFilterKBK.ItemIndex := 0;//vFilterCodes_Selector;
          xrgFilterKBK.OnClick := @DoFilterCodesChange;
          //@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 := aCaption;//'Список выгружаемых кодов бюджетной классификации...';
          xForm.Show;
          xForm.Close;
          except
            ExceptionLog( 'Сбой создания формы выбора кодов.');
        end;

        // запихиваем на форму все загруженные КБК без учета фильтра
        if NOT DoFilterCodes then begin
          WriteLog('Список кодов для выгрузки пуст.', TRUE);
          Result := FALSE;
          EXIT;
        end;

      // если включена опция "выгружать КБК из списка" - открываем форму и
      // ждем выбора. если опции нет - выгружаем все загруженные КБК.
      

      if aCfgOutListKbk
        then begin
  
          // при выгрузке справочников отображается только один фильтр:
          // все/выгружнные/не выгруженные. прочие - скрываем.
          // тулбар с кнопками тоже скрываем.
          xtlbFilterClear.Visible := TRUE;
          xtlbFilter.Visible := TRUE;
          xtlbFilterClear.show;
          xtlbFilter.show;
          xtlbRefresh.show;
          xBoxKbk.Hide;
          xRadioTypeKbk.Hide;
          xPanelToolBar.Hide;
          xPanelFilter.Show;
          if (xForm.ShowModal = MrOk)
            then Kbk := GetSelectionsCodesFromList(xCdsList, xDbGrid, aListID, TRUE)
            else begin
              WriteLog('Выполнена отмена выгрузки кодов из формы.', TRUE);
              Result := FALSE;
              EXIT;
            end;
        end else begin
  
          Kbk := GetSelectionsCodesFromList(xCdsList, xDbGrid, aListID, FALSE);
        end;
        finally
          xForm.Free;
      end;



      if VarIsNull( Kbk) then begin
        WriteLog( 'Не выбрано кодов для выгрузки.', TRUE);
        Result := FALSE;
        EXIT;
      end;

      // выгрузка выбранных КБК в конечный XML: глобальную переменную Data
      DoPrepareXmlKBK( aKbkDataCaption, aKbkDataTopic);
      Result := TRUE;
      except
        ExceptionLog( 'Сбой Un_Kbk32.BuildFormSelectCodes');
    end;

end;


{~FixedExportedListIDEx
  фиксируем список идентификаторов экспортируемых кодов КБК.
  здесь отсылается задание на сервер.
  если на сервере фиксация КБК не выполняется, то удаляется выгруженный файл КБК.
  если задание (aAction) будет указано как неопределенное, то задание
  определяется по префиксам строк в списке идентификаторов.
  при этом допускается указывать идентификаторы в списке с разными префиксами,
  а в этой подпрограмме будет выполнена группировка таких идентификаторов
  и выполнения задания для каждой группы. }
procedure FixedExportedListIDEx( aFileOut: string;
                                  var aListID: TStringList;
                                  aAction: string);
var
  xRaiseMsg: string;
  i: integer;
  SL: TStringList;
  s: string;
  xAction,xPrefix: string;
  xFound: boolean;
begin
  try

    try
      // на всякий случай
      if (aListID.Count <= 0) then EXIT;
      // если операция заранее не определена, то разбираем список идентификаторов
      // возможно там ид.от разных таблиц, поэтому разделяем ид. на группы
      // и формируем отдельные подзапросы для каждой из таблиц.
      if (aAction = cnExportActionUndefined) then
        try

          repeat
            // берем первую строку из списка и для нее ищем все ид с таким префиксом
            s := aListID.Strings[0];

            if (POS( cnPrefixID_KSI, s) = 1)
              then xPrefix := cnPrefixID_KSI
              else
            if (POS( cnPrefixID_KSD, s) = 1)
              then xPrefix := cnPrefixID_KSD
              else raise( format( 'Неопределенный префикс в строке ID: "%s".', [ s]));
            // теперь проверяем, остались ли идентификаторы, отличные от
            // найденного в первой строке.  это даст то, что если в списке
            // остались ID только с одним префиксом - остается только удалить
            // эти префиксы из строк списка, без выделения строк в отдельном списке
            xFound := FALSE;
            for i := aListID.Count - 1 downto 0 do begin
              s := aListID.Strings[i];
              if (POS( xPrefix, s) <> 1) then begin
                xFound := TRUE;
                BREAK;
              end;
            end;//for//
            SL:= TStringList.Create;
            try
              if xFound then begin
                // в списке имеются ид. с различными префиксами.
                // начинаем с конца списка, поскольку подходящие
                // строки будем удалять из исходного списка
                for i := aListID.Count - 1 downto 0 do begin
                  s := aListID.Strings[i];
                  if (POS( xPrefix, s) = 1) then begin
                    DELETE( s, 1, LENGTH( xPrefix));
                    SL.Add( s);
                    aListID.Delete( i);
                  end;
                end;//for//
              end else begin
                // меняем строки в текущем списке
                for i := aListID.Count - 1 downto 0 do begin
                  s := aListID.Strings[i];
                  if (POS( xPrefix, s) = 1) then begin
                    DELETE( s, 1, LENGTH( xPrefix));
                    SL.Add( s);
                  end;
                end;//for//
                aListID.Clear;   // список полностью обработан
              end;
              // вызываем операцию рекурсивно
              case xPrefix of
                cnPrefixID_KSI: FixedExportedListIDEx( aFileOut, SL, 'ksi');
                cnPrefixID_KSD: FixedExportedListIDEx( aFileOut, SL, 'ksd');
              end;//case//
              finally
                SL.Free;
            end;
            // повторяем операцию, пока весь исходный список идентификаторов
            // не будет разобран
          until (aListID.Count <= 0);

          EXIT;
        except
          ExceptionLog( 'Сбой в операции фильтрации списка идентификаторов.');
      end;

      // выполняем операцию обновления дат выгрузки
      ExecProc( 'KBKEXPORTFROMEXCHANGE',
                    [ 'action', 'export', aAction, aListID.CommaText]);

      except
        begin
          xRaiseMsg := LastException.Message;
          if FileExists( aFileOut) then DeleteFile( aFileOut);
          RaiseLog( FORMAT(       'Сбой фиксации выгруженных КБК.'
                           +#13#10'Файл с выгруженными КБК "%s" удален.',
                           [ aFileOut]),
                    xRaiseMsg);
        end;
    end;
    
    except
      ExceptionLog( 'Сбой скрипта: "Un_Kbk1.FixedExportedListIDEx".');
  end;
end;



begin
end.
