uses '..\Version\CheckVersion', '..\Tools\Un_Query';

var
  Form: TFormCustom;
  FormKdt, FormTer: TFormCustomTree;
  FormKadmd, FormKd, FormKes: TFormKbk;
  FormFsd: TFormCustomList;
  ProgressBar: TProgressBar;
  dtDate: TDateTimeEh;
  edtDir, edtKdt, edtTer, edtKadmd, edtKd, edtKes, edtFsd: TEdit;
  btnDir, btnKdt, btnTer, btnKadmd, btnKd, btnKes, btnFsd: TSpeedButton;
  cdsOrg, cdsTerritory, cdsReceiver: TClientDataSet;
  FileLog, FileInfo: String;
  FDebuger, FFormatXML: Boolean;
  FAzkIsLogin: Boolean;
  // exchange #2465
  // форма кода цели с контролами
  vFormPurpFulGr: TFormKbk;
  vBtnPurpFulGr: TSpeedButton;
  vEdtPurpFulGr: TEdit;

const
  FFileVer = '1.1';
  FFileGuid = '{049EFEDC-2115-44AD-A667-7B1A67F80324}';


procedure Main(Xml: Variant);
begin
  CheckWorkAppVersion;
  with Xml.documentElement do
  if getAttribute('TESTED') = 'True' then
  begin
    setAttribute('TESTED', 'False');
    Xml.save('C:\Temp\PlanIncomExport.Xml');
    ShowMessage('Тестовый пример приготовлен: C:\Temp\PlanIncomExport.Xml');
    Exit;
  end;
  FAzkIsLogin := AzkIsLogin;
  if not AzkIsLogin then
    if not AzkLogin then
      Exit;
  try
    try
      initialization(Xml);
      if FDebuger then
      begin
        Form.Show;
        repeat
          Application.handleMessage;
        until(not Form.Visible);
      end
      else
        Form.ShowModal;
    except
      WriteLog(LastException.Message);
      raise(LastException.Message);
    end;
  finally
    finalization;
    if not FAzkIsLogin then
      AzkLogout;
  end;
end; {End Main}

procedure initialization(Xml: Variant);
var
  IniPath: String;
begin
  IniPath := ExtractFilePath(Xml.documentElement.getAttribute('INI_FILE'));
  FileLog := IniPath + 'System_PlanIncomExport.Log';
  FileInfo := IniPath + 'User_PlanIncomExport.Log';

  Form := TFormCustom.Create(Application);
  Form.LoadDfm(IniPath + 'Fm_PlanIncomExport.dfm');
  Form.Name := 'FmPlanIncomExport';
  Form.actExecute.OnExecute := @actExecuteExecute;
  TLabel(Form.FindComponent('lblVersion')).Caption := 'Версия формата: ' + FFileVer;;
  ProgressBar := TProgressBar(Form.FindComponent('ProgressBar'));
  // Отчётная дата
  dtDate := TDateTimeEh(Form.FindComponent('dtDate'));
  dtDate.Date := Work_Date;
  // Каталог экспорта
  edtDir := TEdit(Form.FindComponent('edtDir'));
  btnDir := TSpeedButton(Form.FindComponent('btnDir'));
  btnDir.OnClick := @OnbtnDirClick;
  // Типы доходов
  FormKdt := TFormCustomTree.Create(Form);
  FormKdt.LoadDfm(IniPath + '..\Forms\Fm_Kdt.dfm');

  // exchange #2715
  // поправлен запрос при переходе на символьные БК
  FormKdt.SQLText :=
    ' Select Cast(Null As VarChar(15)) Code, Cast('#39'.'#39'  As VarChar(15)) Parent_Code,'
   +' Cast(''Код типа дохода'' As VarChar(1000)) Description'
   +' From Kdt K Where K.Budget_Id = ' + Budget_Id + ' And K.Code = 0' +
    ' Union Select cast(K.Code  As VarChar(15)), Cast(K.Parent_Code As VarChar(15)),'
   +' Cast(K.Description As VarChar(1000)) Description'
   +' From Kdt K Where K.Budget_Id = ' + Budget_Id;

  FormKdt.EditResFieldName := 'Description';

  // exchange #2715
  // изменен код корневого узла и шаблон отображения кодов на дереве
  FormKdt.ValueRoot := '.';
  FormKdt.FilterFormatStr := #39'%s'#39;

  FormKdt.RootSelect := False;
  edtKdt := TEdit(Form.FindComponent('edtKdt'));
  FormKdt.Edit := edtKdt;
  btnKdt := TSpeedButton(Form.FindComponent('btnKdt'));
  FormKdt.SpeedButton := btnKdt;
  // Территории (Иерархия территорий)
  FormTer := TFormCustomTree.Create(Form);
  FormTer.LoadDfm(IniPath + '..\Forms\Fm_Territory.dfm');

  // exchange #2715
  // поправлен запрос при переходе на символьные БК
  FormTer.SQLText :=
    ' Select Cast(Null As VarChar(15)) Id, Cast('#39'.'#39'  As VarChar(15)) Parent_Id,'
   +' Cast(''Территории'' As VarChar(255)) Caption'
   +' From Territory T Where T.Id = 0 Union' +
    ' Select cast(T.Id As VarChar(15)), cast(T.Parent_Id As VarChar(15)),'
   +' Cast(T.Caption As VarChar(255)) Caption From Territory T';

  FormTer.EditResFieldName := 'Caption';

  // exchange #2715
  // изменен код корневого узла и шаблон отображения кодов на дереве
  FormTer.ValueRoot := '.';
  FormTer.FilterFormatStr := #39'%s'#39;

  FormTer.RootSelect := False;
  edtTer := TEdit(Form.FindComponent('edtTer'));
  FormTer.Edit := edtTer;
  btnTer := TSpeedButton(Form.FindComponent('btnTer'));
  FormTer.SpeedButton := btnTer;
  // Администратор (Классификатор администраторов поступлений и выбытий)
  FormKadmd := TFormKbk.Create(Form);
  FormKadmd.Kbk_Code := KADMD_CODE;
  edtKadmd := TEdit(Form.FindComponent('edtKadmd'));
  FormKadmd.Edit := edtKadmd;
  btnKadmd := TSpeedButton(Form.FindComponent('btnKadmd'));
  FormKadmd.SpeedButton := btnKadmd;
  // КВД (Классификатор вида доходов)
  FormKd := TFormKbk.Create(Form);
  FormKd.Kbk_Code := Kd_Code;
  edtKd := TEdit(Form.FindComponent('edtKd'));
  FormKd.Edit := edtKd;
  btnKd := TSpeedButton(Form.FindComponent('btnKd'));
  FormKd.SpeedButton := btnKd;
  // КЭС (Экономический классификатор доходов)
  FormKes := TFormKbk.Create(Form);
  FormKes.Kbk_Code := KESD_CODE;
  edtKes := TEdit(Form.FindComponent('edtKes'));
  FormKes.Edit := edtKes;
  btnKes := TSpeedButton(Form.FindComponent('btnKes'));
  FormKes.SpeedButton := btnKes;
  // КИФ (Источники финансирования)
  FormFsd := TFormCustomList.Create(Form);
  FormFsd.LoadDfm(IniPath + '..\Forms\Fm_Kif.dfm');
  FormFsd.SQLText := 'Select F.Id, F.Caption From FinSource F';
  edtFsd := TEdit(Form.FindComponent('edtFsd'));
  FormFsd.Edit := edtFsd;
  btnFsd := TSpeedButton(Form.FindComponent('btnFsd'));
  FormFsd.SpeedButton := btnFsd;

  // exchange #2465
  // код цели
  vFormPurpFulGr:= TFormKbk.Create( Form);
  vFormPurpFulGr.Columns := 'CAPTION|Код субсидии'#13#10'DESCRIPTION|Наименование';
  // это поле определяет название выбранных (bookmark) кодов целей в таблице.
  // id храняться в vEdtPurpFulGr.hint, а список кодов (caption)
  // в vEdtPurpFulGr.text.
  // не забываем, чтобы сохранились параметры этих контролов при закрытии
  // формы, нужно открыть форму в delphi и дописать сохраняемые свойства
  // в контроле TPropertyNamesEh (grbParams/grbFiltr/edtPurposefulgrant свойства
  // text и hint). так же и контрол btnPurposefulgrant - в свойстве hint
  // хранится ID записи курсора в таблице.
  // версия АЦК-exchange должна быть не ниже
  vFormPurpFulGr.EditResFieldName := 'Caption';
  vFormPurpFulGr.Kbk_Code := PURPFULGR_CODE;
//  vFormPurpFulGr.Name := vFormPurpFulGr.Name + '_Filtr_' + vFormPurpFulGr.Name;
  vEdtPurpFulGr := TEdit(Form.FindComponent('edtPurposefulgrant'));
  vFormPurpFulGr.Edit := vEdtPurpFulGr;
  vBtnPurpFulGr := TSpeedButton(Form.FindComponent('btnPurposefulgrant'));
  vFormPurpFulGr.SpeedButton := vBtnPurpFulGr;

  cdsOrg := TClientDataSet(Form.FindComponent('cdsOrg'));
  cdsOrg.CreateDataSet;
  cdsTerritory := TClientDataSet(Form.FindComponent('cdsTerritory'));
  cdsTerritory.CreateDataSet;
  cdsReceiver := TClientDataSet(Form.FindComponent('cdsReceiver'));
  cdsReceiver.CreateDataSet;

  with tStringList.Create do
  try
    CommaText := Xml.documentElement.getAttribute('CONFIG');
    FFormatXML := Trim(Values['Форматировать XML']) = 'Да';
  finally
    Free;
  end;
end; {End initialization}

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

procedure OnbtnDirClick(Sender: TObject);
begin
  ChooseFolder('Укажите каталог экспорта', edtDir.Text);
end; {End OnbtnDirClick}

procedure OnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_DELETE then
  begin
    TEdit(Sender).Hint := '';
    TEdit(Sender).Text := '';
  end;
end; {End OnKeyDown}

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

procedure WriteInfo(Message: String; aParam: boolean = FALSE);
begin
  WriteLogFile(FileInfo, Message);
  WriteLogFile(FileLog, Message);
end; {End WriteInfo}

procedure GetBudgetTerritoryOKATO(var aTerritory, aOKATO: string);
var
 sql: string;
 XML: variant;
begin
 sql :=
 ' select ' +
 '  t.ID, t.OKATO ' +
 ' from ' +
 '  budget b join territory t on t.id = b.territory_id ' +
 ' where ' +
 '  b.id = ' + Budget_ID;
 Xml := CreateOleObject('Microsoft.XmlDom');
 XML.LoadXml(Query.Run(sql));
 if (XML.firstChild.hasChildNodes) then
 begin
   aTerritory := XML.firstChild.childNodes.items[0].getAttribute('ID');
   aOKATO := XML.firstChild.childNodes.items[0].getAttribute('OKATO');
 end;
end;

function GetBudgetPeriod:string;
var
 sql: string;
 XML: variant;
begin
 Result := '';
 sql := ' select period from budget where id = ' + Budget_ID;
 Xml := CreateOleObject('Microsoft.XmlDom');
 XML.LoadXml(Query.Run(sql));
 if (XML.firstChild.hasChildNodes) then
   Result := XML.firstChild.childNodes.items[0].getAttribute('PERIOD');
end;

procedure actExecuteExecute(Sender: TObject);
var
  i: Integer;
  FileXml: String;
  PlanXml, Xml, Node: Variant;
  _terr, _ok: string;
begin
  if Trim(edtDir.Text) = '' then
  begin
    MessageDlg('Не указан каталог выгрузки', mtError, mbOk, 0);
    Exit;
  end;
  FileXml := StringReplace(edtDir.Text + '\', '\\', '\');
  if not DirectoryExists(FileXml) then
    raise('Отсутствует каталог: ' + FileXml);
  CdsQuery(cdsOrg, 'Select O.Id, O.TaxCode, O.Kpp, O.Okato From Org O');
  CdsQuery(cdsTerritory, 'Select T.Id, T.Okato From Territory T');
  CdsQuery(cdsReceiver, 'Select R.Id, O.Id Org_Id, O.Caption Org_Caption' +
    ', O.Description Org_Description, O.TaxCode, O.Kpp, O.Okato From Receiver R' +
    ' Left Join Org O On (O.Id = R.Org_Id) Where R.Budget_Id Is Null' +
    ' Or R.Budget_Id = ' + Budget_Id);
  FileXml := GetUniqueFileName(FileXml + 'PlanIncomExport.xml');
  PlanXml := CreateOleObject('Microsoft.XmlDom');
  SetAppDisable;
  try
    PlanXml := PlanXml.appendChild(PlanXml.createElement('EXCHINCOMDATA'));
    PlanXml.setAttribute('action', 'planexport');
    PlanXml.setAttribute('BEGIN_DATE', FormatDateTime('yyyy-01-01', dtDate.Date));
    PlanXml.setAttribute('END_DATE', FormatDateTime('yyyy-mm-dd', dtDate.Date));
    if edtKdt.Hint <> '' then PlanXml.setAttribute('KDT_CODE', edtKdt.Hint);
    if edtTer.Hint <> '' then PlanXml.setAttribute('TERRITORY_ID', edtTer.Hint);
    if edtKadmd.Hint <> '' then PlanXml.setAttribute('KADMD_CODE', edtKadmd.Text);
    if edtKd.Hint <> '' then  PlanXml.setAttribute('KD_CODE', edtKd.Text);
    if edtKes.Hint <> '' then PlanXml.setAttribute('KESD_CODE', edtKes.Text);
    if edtFsd.Hint <> '' then PlanXml.setAttribute('FSD_ID', edtFsd.Hint);

    // exchange #2465
    // добавлено поле кода цели в отчетный сервер EXCHINCOMDATA
    // тут нужно передавать список идентификаторов, а он лежит в свойстве Hint!
    if vEdtPurpFulGr.Hint <> ''
      then PlanXml.setAttribute('PURPOSEFULGRANTD_ID', vEdtPurpFulGr.Hint);

    PlanXml := PlanXml.ownerDocument;
    Form.SimpleText := 'Запрос к серверу приложений ...';
    PlanXml.loadXml(ExecXml(PlanXml.xml));

{отладка
PlanXml.save('c:\Temp\fin-exp\test_PlanIncomExport.xml');
{отладка}

    PlanXml := PlanXml.documentElement.childNodes;
    ProgressBar.Max := PlanXml.length;
    if PlanXml.length = 0 then
    begin
      MessageDlg('Нет данных по условиям', mtInformation, mbOK, 0);
      Exit;
    end;

    Form.SimpleText := 'Формирование файла экспорта ...';
    GetBudgetTerritoryOKATO(_terr, _ok);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml := Xml.appendChild(Xml.createElement('PLANINCOMEXPORT'));
    Xml.setAttribute('FINYEAR', FormatDateTime('yyyy', dtDate.Date));
    Xml.setAttribute('FILEDATE', FormatDateTime('yyyy-mm-dd', dtDate.Date));
    Xml.setAttribute('FILEVER', FFileVer);
    Xml.setAttribute('FILEGUID', FFileGuid);
    Xml.setAttribute('DATE', DateToStr(dtDate.Date) );
    Xml.setAttribute('PERIOD', getBudgetPeriod );
    Xml.setAttribute('TERRITORY_ID', _terr );
    Xml.setAttribute('OKATO', _ok );

    for i := 0 to PlanXml.length - 1 do
    begin
      Node := PlanXml.item[i];
      Xml := Xml.appendChild(Xml.parentNode.createElement('PLANINCOM'));
      Xml := Xml.appendChild(Xml.parentNode.parentNode.createElement('RECEIVER'));
      Xml.setAttribute('ID', Node.getAttribute('receiver_id'));
      Xml.setAttribute('CAPTION', Node.getAttribute('receiver_caption'));
      if cdsReceiver.Locate('Id', Node.getAttribute('receiver_id'), nil) then
      begin
        Xml.setAttribute('ORG_ID', cdsReceiver.FieldByName('Org_Id').AsString);
        Xml.setAttribute('ORG_CAPTION', cdsReceiver.FieldByName('Org_Caption').AsString);
        Xml.setAttribute('ORG_DESCRIPTION', cdsReceiver.FieldByName('Org_Description').AsString);
        Xml.setAttribute('TAXCODE', cdsReceiver.FieldByName('TaxCode').AsString);
        Xml.setAttribute('KPP', cdsReceiver.FieldByName('Kpp').AsString);
        Xml.setAttribute('OKATO', cdsReceiver.FieldByName('Okato').AsString);
      end;
      Xml := Xml.parentNode;
      Xml := Xml.appendChild(Xml.parentNode.parentNode.createElement('PAYER'));
      Xml.setAttribute('ID', Node.getAttribute('payer_id'));
      Xml.setAttribute('CAPTION', Node.getAttribute('payer_caption'));
      if cdsOrg.Locate('Id', Node.getAttribute('payer_id'), nil) then
      begin
        Xml.setAttribute('TAXCODE', cdsOrg.FieldByName('TaxCode').AsString);
        Xml.setAttribute('KPP', cdsOrg.FieldByName('Kpp').AsString);
        Xml.setAttribute('OKATO', cdsOrg.FieldByName('Okato').AsString);
      end;
      Xml := Xml.parentNode;
      Xml := Xml.appendChild(Xml.parentNode.parentNode.createElement('TERRITORY'));
      Xml.setAttribute('ID', Node.getAttribute('territory_id'));
      Xml.setAttribute('CODE', Node.getAttribute('territory_code'));
      Xml.setAttribute('CAPTION', Node.getAttribute('territory_caption'));
      if cdsTerritory.Locate('Id', Node.getAttribute('territory_id'), nil) then
        Xml.setAttribute('OKATO', cdsTerritory.FieldByName('Okato').AsString);
      Xml := Xml.parentNode;
      Xml := Xml.appendChild(Xml.parentNode.parentNode.createElement('KBK'));
      Xml.setAttribute('KDT_CODE', Node.getAttribute('kdt_code'));
      Xml.setAttribute('KADM_CODE', Node.getAttribute('kadmd_code'));
      Xml.setAttribute('KD_CODE', Node.getAttribute('kd_code'));
      Xml.setAttribute('KDD_CODE', Node.getAttribute('kdd_code'));
      Xml.setAttribute('KDT_CODE', Node.getAttribute('kdt_code'));
      Xml.setAttribute('KESD_CODE', Node.getAttribute('kesd_code'));
      Xml.setAttribute('FSD_ID', Node.getAttribute('fsd_id'));

      // exchange #2465
      // добавлено поле кода цели. на всякий случай, если версия отчетов
      // не совпадет с нужной, это поле не будет заполнено, но сбоя быть
      // не должно. конкретно для доходов, атрибут указан в нижнем регистре!
      Xml.setAttribute( 'PURPOSEFULGRANTD_ID',
                            VarToStr( Node.getAttribute('purposefulgrantd_id')));

      Xml := Xml.parentNode;
      Xml := Xml.appendChild(Xml.parentNode.parentNode.createElement('AMOUNT'));
      {Xml.setAttribute('PLAN', Node.getAttribute('planInc'));
      Xml.setAttribute('PLANQUART1', Node.getAttribute('planIncQuart1'));
      Xml.setAttribute('PLANQUART2', Node.getAttribute('planIncQuart2'));
      Xml.setAttribute('PLANQUART3', Node.getAttribute('planIncQuart3'));
      Xml.setAttribute('PLANQUART4', Node.getAttribute('planIncQuart4'));
      Xml.setAttribute('UPDATE', Node.getAttribute('planIncUpdate'));
      Xml.setAttribute('UPDATEQUART1', Node.getAttribute('planIncUpdateQuart1'));
      Xml.setAttribute('UPDATEQUART2', Node.getAttribute('planIncUpdateQuart2'));
      Xml.setAttribute('UPDATEQUART3', Node.getAttribute('planIncUpdateQuart3'));
      Xml.setAttribute('UPDATEQUART4', Node.getAttribute('planIncUpdateQuart4'));
      Xml.setAttribute('PLANONDATE', Node.getAttribute('planIncOnDate'));
      Xml.setAttribute('UPDATEONDATE', Node.getAttribute('planIncUpdateOnDate'));}
      Xml.setAttribute('EXEC', Node.getAttribute('exec'));
      Xml.setAttribute('PLANINC_YEAR1', Node.getAttribute('planIncYear1'));
      Xml.setAttribute('PLANINC_YEAR2', Node.getAttribute('planIncYear2'));
      Xml.setAttribute('PLANINC_YEAR3', Node.getAttribute('planIncYear3'));
      Xml.setAttribute('PLANINC_UPDATE_YEAR1', Node.getAttribute('planIncUpdateYear1'));
      Xml.setAttribute('PLANINC_UPDATE_YEAR2', Node.getAttribute('planIncUpdateYear2'));
      Xml.setAttribute('PLANINC_UPDATE_YEAR3', Node.getAttribute('planIncUpdateYear3'));
      Xml.setAttribute('PLANINC_ONDATE', Node.getAttribute('planIncOnDate'));
      Xml.setAttribute('PLANINC_UPDATE_ONDATE', Node.getAttribute('planIncUpdateOnDate'));

      Xml := Xml.parentNode;
      Xml := Xml.parentNode;
      ProgressBar.Position := i + 1;
    end;
    Xml := Xml.parentNode;
    Form.SimpleText := 'Сохранение файла экспорта ...';
    if FFormatXML then
      Xml.loadXml('<?xml version="1.0" encoding="Windows-1251"?>' + FormatXmlData(Xml.xml));
    Xml.save(FileXml);
    MessageDlg('Файл экспорта: ' + FileXml, mtInformation, mbOK, 0);
  finally
    Form.SimpleText := '';
    ProgressBar.Position := 0;
    SetAppEnable;
  end;
end; {End actExecuteExecute}

var
  Xml: Variant;

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