{
===============================================================================
  Copyright (©) 2005. Rodax Software.
===============================================================================
  Los contenidos de este fichero son propiedad de Rodax Software titular del
  copyright. Este fichero sólo podrá ser copiado, distribuido y utilizado,
  en su totalidad o en parte, con el permiso escrito de Rodax Software, o de
  acuerdo con los términos y condiciones establecidas en el acuerdo/contrato
  bajo el que se suministra.
  -----------------------------------------------------------------------------
  Web:  www.rodax-software.com
===============================================================================
  Fecha primera versión: 01-02-2005
  Versión actual: 1.0.1
  Fecha versión actual: 03-03-2005
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
    03-03-2005    Se ha quitado en FormCreate la validación de tener instalado
                  el activeSync de microsoft.
===============================================================================
}

unit Sincronizacion;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, RdxBotones, RdxBarras, ExtCtrls, RdxPaneles, OleServer,
  DB, IBCustomDataSet, StdCtrls, TablaProveedores,
  TablaClientes, Outlook2000;

type
  tContactos = (tcProveedores, tcClientes);

  TfSincronizacion = class(TForm)
    BarraContadores: TRdxBarraSuperior;
    imgSombra: TImage;
    brInferior: TRdxBarraInferior;
    bCerrar: TRdxBoton;
    Label1: TLabel;
    eProgress1: TLabel;
    eFechaUltimaSinc: TLabel;
    Label2: TLabel;
    eProgress2: TLabel;
    Image1: TImage;
    Image2: TImage;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormActivate(Sender: TObject);
  private
    olOutlook: _Application;
    olContactsFolder: MAPIFolder;
    olNmSpace: _NameSpace;

    FTablaContactos : TIBDataSet;
    FUltimaSincronizacion : TDateTime;
    function DarUltimaSincronizacion : TDateTime;
    procedure ActualizarFechaSincronizacion;
    procedure SincronizarContactos (TipoContacto : tContactos);
    procedure AnadirClientesNuevos;
    procedure AnadirProveedoresNuevos;
    procedure EliminarClientesSobrantes;
    procedure EliminarProveedoresSobrantes;
    procedure InsertarProveedorBD (Contacto : ContactItem;
                        Proveedor : TDatosProveedor);
    procedure InsertarClienteBD (Contacto : ContactItem;
                        Cliente : TDatosCliente);
    procedure ActualizarProveedorOutlook (Contacto : ContactItem;
                        Proveedor : TDatosProveedor);
    procedure ActualizarProveedorBD (Contacto : ContactItem;
                        Proveedor : TDatosProveedor);
    procedure ActualizarClienteOutlook (Contacto : ContactItem;
                        Cliente : TDatosCliente);
    procedure ActualizarClienteBD (Contacto : ContactItem;
                        Cliente : TDatosCliente);
  end;

var
  fSincronizacion: TfSincronizacion;

implementation

{$R *.dfm}

uses
  IBSQL, Framework, BaseDatos, Mensajes, StrFunc, RdxEmpresaActiva, IBQuery;

const
  CATEGORIA_CLIENTES = 'Clientes FactuGES';
  CATEGORIA_PROVEEDORES = 'Proveedores FactuGES';


procedure TfSincronizacion.ActualizarClienteBD(Contacto: ContactItem;
  Cliente: TDatosCliente);
var
  Cadena : String;
begin
  with Contacto, Cliente do
  begin
    if FullName <> Nombre then
      Nombre := FullName;
    if not EsCadenaVacia(Calle) then
    begin
      Cadena := Calle;
      if not EsCadenaVacia(Numero) then
        Cadena := Cadena + ', ' + Numero;
      if not EsCadenaVacia(Piso) then
        Cadena := Cadena + ' ' + Piso;
    end;
    if Cadena <> BusinessAddressStreet then
    begin
      Calle := BusinessAddressStreet;
      Piso := '';
      Numero := '';
    end;

    if BusinessAddressPostalCode <> CodigoPostal then
      CodigoPostal := BusinessAddressPostalCode;

    if BusinessAddressCity <> Poblacion then
      Poblacion := BusinessAddressCity;

    if BusinessAddressState <> Provincia then
      Provincia := BusinessAddressState;

    if Email1Address <> Correo then
      Correo := Email1Address;

    if BusinessTelephoneNumber <> Telefono1 then
      Telefono1 := BusinessTelephoneNumber;

    if Business2TelephoneNumber <> Telefono2 then
      Telefono2 := Business2TelephoneNumber;

    if BusinessFaxNumber <> Fax then
      Fax := BusinessFaxNumber;

    if Body <> Observaciones then
      Observaciones := Body;

    SalvarDatos;
  end;
end;

procedure TfSincronizacion.ActualizarClienteOutlook(Contacto: ContactItem;
  Cliente: TDatosCliente);
begin
  with Contacto, Cliente do
  begin
    CustomerID := Codigo;
    FullName := Nombre;
    FileAs := FullName;
    if not EsCadenaVacia(Calle) then
    begin
      BusinessAddressStreet := Calle;
      if not EsCadenaVacia(Numero) then
        BusinessAddressStreet := BusinessAddressStreet + ', ' + Numero;
      if not EsCadenaVacia(Piso) then
        BusinessAddressStreet := BusinessAddressStreet + ' ' + Piso;
    end;
    BusinessAddressPostalCode := CodigoPostal;
    BusinessAddressCity := Poblacion;
    BusinessAddressState := Provincia;
    Email1Address := Correo;
    BusinessTelephoneNumber := Telefono1;
    Business2TelephoneNumber := Telefono2;
    BusinessFaxNumber := Fax;
    Body := Observaciones;
    Categories := CATEGORIA_CLIENTES;
    Save;
  end;
end;

procedure TfSincronizacion.ActualizarProveedorBD(Contacto: ContactItem;
  Proveedor: TDatosProveedor);
var
  Cadena : String;
begin
  with Contacto, Proveedor do
  begin
    if FullName <> Nombre then
      Nombre := FullName;
    if not EsCadenaVacia(Calle) then
    begin
      Cadena := Calle;
      if not EsCadenaVacia(Numero) then
        Cadena := Cadena + ', ' + Numero;
      if not EsCadenaVacia(Piso) then
        Cadena := Cadena + ' ' + Piso;
    end;
    if Cadena <> BusinessAddressStreet then
    begin
      Calle := BusinessAddressStreet;
      Piso := '';
      Numero := '';
    end;

    if BusinessAddressPostalCode <> CodigoPostal then
      CodigoPostal := BusinessAddressPostalCode;

    if BusinessAddressCity <> Poblacion then
      Poblacion := BusinessAddressCity;

    if BusinessAddressState <> Provincia then
      Provincia := BusinessAddressState;

    if Email1Address <> Correo then
      Correo := Email1Address;

    if BusinessTelephoneNumber <> Telefono1 then
      Telefono1 := BusinessTelephoneNumber;

    if Business2TelephoneNumber <> Telefono2 then
      Telefono2 := Business2TelephoneNumber;

    if BusinessFaxNumber <> Fax then
      Fax := BusinessFaxNumber;

    if Body <> Observaciones then
      Observaciones := Body;

    SalvarDatos;
  end;
end;

procedure TfSincronizacion.ActualizarProveedorOutlook(Contacto: ContactItem;
    Proveedor : TDatosProveedor);
begin
  with Contacto, Proveedor do
  begin
    CustomerID := Codigo;
    FullName := Nombre;
    FileAs := FullName;
    if not EsCadenaVacia(Calle) then
    begin
      BusinessAddressStreet := Calle;
      if not EsCadenaVacia(Numero) then
        BusinessAddressStreet := BusinessAddressStreet + ', ' + Numero;
      if not EsCadenaVacia(Piso) then
        BusinessAddressStreet := BusinessAddressStreet + ' ' + Piso;
    end;
    BusinessAddressPostalCode := CodigoPostal;
    BusinessAddressCity := Poblacion;
    BusinessAddressState := Provincia;
    Email1Address := Correo;
    BusinessTelephoneNumber := Telefono1;
    Business2TelephoneNumber := Telefono2;
    BusinessFaxNumber := Fax;
    Body := Observaciones;
    Categories := CATEGORIA_PROVEEDORES;
    Save;
  end;
end;

procedure TfSincronizacion.FormCreate(Sender: TObject);
var
  DLLHandle: THandle;
begin
  FTablaContactos := NIL;

  olOutlook := CoOutlookApplication.Create;
  olNmSpace := olOutlook.GetNamespace('MAPI');
  olContactsFolder := olNmSpace.GetDefaultFolder(olFolderContacts);

  FTablaContactos := TIBDataSet.Create(Self);
  with FTablaContactos do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
  end;

  FUltimaSincronizacion := DarUltimaSincronizacion;
end;

procedure TfSincronizacion.FormDestroy(Sender: TObject);
begin
  dmBaseDatos.Rollback;
  if Assigned (FTablaContactos) then
  begin
    FTablaContactos.Close;
    FTablaContactos.Free;
  end;
  FTablaContactos := NIL;
end;

procedure TfSincronizacion.FormShow(Sender: TObject);
begin
  eFechaUltimaSinc.Caption := 'Ultima sincronización: ' + VarToStr(FUltimaSincronizacion);
end;

procedure TfSincronizacion.EliminarClientesSobrantes;
var
  Contacto : ContactItem;
  Filter: Widestring;
  Id: IDispatch;
  Total : Integer;
  Contador : Integer;
  DatosContacto : TObjeto;
  Clientes : Items;
begin
  Clientes := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_CLIENTES);
  FTablaContactos.Open;
  FTablaContactos.Last;
  try
    Total := Clientes.Count - FTablaContactos.RecordCount;
    Id := Clientes.GetLast;
    if Total > 0 then
    begin
      Contador := 0;
      while (Contador < Total) and Assigned(Id)
        and (Sysutils.Supports(Id, ContactItem, Contacto)) do
      begin
        FTablaContactos.First;
        if not FTablaContactos.Locate('CODIGO', Contacto.CustomerID, []) then
        begin
          Contacto.Delete;
          Contador := Contador + 1;
        end;
        Id := Clientes.GetPrevious;
      end;
    end;
  finally
    FTablaContactos.Close;
  end;
end;


procedure TfSincronizacion.SincronizarContactos(TipoContacto : tContactos);
var
    Contacto : ContactItem;
    Filter: Widestring;
    Id: IDispatch;
    Contador : Integer;
    DatosContacto : TObjeto;
    Contactos : Items;
begin
  Contador := 0;

  FTablaContactos.Open;
  with FTablaContactos do
  begin
    Last;
    First;
    while not EOF do
    begin
      if TipoContacto = tcProveedores then
        eProgress1.Caption := IntToStr(Contador) + ' proveedores de ' + IntToStr(RecordCount) + ' sincronizados.'
      else
        eProgress2.Caption := IntToStr(Contador) + ' clientes de ' + IntToStr(RecordCount) + ' sincronizados.';

      Self.Refresh;
      Application.ProcessMessages;

      Filter :='[CustomerID] = "' + FieldByName('CODIGO').AsString + '"';
      if TipoContacto = tcProveedores then
        Contactos := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_PROVEEDORES)
      else
        Contactos := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_CLIENTES);

      Id := Contactos.Find(Filter);
      if (Id = nil) then
      begin
        Id := ContactItem(Contactos.Add(olContactItem));
        if Sysutils.Supports(Id, ContactItem, Contacto) then
        begin
          // El contacto no existe
          try
            if TipoContacto = tcProveedores then
            begin
              DatosContacto := TDatosProveedor.Create(FieldByName('CODIGO').AsString);
              ActualizarProveedorOutlook(Contacto, DatosContacto as TDatosProveedor);
            end
            else begin
              DatosContacto := TDatosCliente.Create(FieldByName('CODIGO').AsString);
              ActualizarClienteOutlook(Contacto, DatosContacto as TDatosCliente);
            end;
          finally
            DatosContacto.Free;
          end;
        end;
      end
      else begin
        if Sysutils.Supports(Id, ContactItem, Contacto) then
        begin
          if (Contacto.LastModificationTime > FUltimaSincronizacion) or
              (FTablaContactos.FieldByName('ULTIMOCAMBIO').AsDateTime > FUltimaSincronizacion) then
          begin
            Contador := Contador + 1;

            if TipoContacto = tcProveedores then
            begin
              DatosContacto := TDatosProveedor.Create(FieldByName('CODIGO').AsString);
              if (Contacto.LastModificationTime > FieldByName('ULTIMOCAMBIO').AsDateTime) then
                ActualizarProveedorBD(Contacto, DatosContacto as TDatosProveedor)
              else
                ActualizarProveedorOutlook(Contacto, DatosContacto as TDatosProveedor);
            end
            else begin
              DatosContacto := TDatosCliente.Create(FieldByName('CODIGO').AsString);
              if (Contacto.LastModificationTime > FieldByName('ULTIMOCAMBIO').AsDateTime) then
                ActualizarClienteBD(Contacto, DatosContacto as TDatosCliente)
              else
                ActualizarClienteOutlook(Contacto, DatosContacto as TDatosCliente);
            end;
            DatosContacto.Free;
          end;
        end;
      end;
      Contador := Contador + 1;
      Next;
    end;
  end;

  if TipoContacto = tcProveedores then
    eProgress1.Caption := IntToStr(Contador) + ' proveedores sincronizados.'
  else
    eProgress2.Caption := IntToStr(Contador) + ' clientes sincronizados.';
  FTablaContactos.Close;
end;

procedure TfSincronizacion.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TfSincronizacion.FormActivate(Sender: TObject);
begin
  OnActivate := NIL;

  Screen.Cursor := crHourGlass;
  Self.Refresh;
  Application.ProcessMessages;

  // Sincronizar los contactos
  AnadirProveedoresNuevos;
  AnadirClientesNuevos;

  with FTablaContactos do
  begin
    Close;
    SelectSQL.Clear;
    SelectSQL.Add('select * from PROVEEDORES order by CODIGO desc');
    Prepare;
  end;
  SincronizarContactos(tcProveedores);
  EliminarProveedoresSobrantes;

  Image1.Visible := True;
  Self.Refresh;
  Application.ProcessMessages;

  with FTablaContactos do
  begin
    Close;
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SelectSQL.Clear;
    SelectSQL.Add('select * from CLIENTES order by CODIGO desc');
    Prepare;
  end;
  SincronizarContactos(tcClientes);
  EliminarClientesSobrantes;

  Image2.Visible := True;

  // Fin
  ActualizarFechaSincronizacion;
  FUltimaSincronizacion := DarUltimaSincronizacion;
  dmBaseDatos.Commit;
  bCerrar.Enabled := True;
  Self.Refresh;
  Application.ProcessMessages;

  Screen.Cursor := crDefault;
end;

procedure TfSincronizacion.AnadirClientesNuevos;
var
  Contacto : ContactItem;
  Id: IDispatch;
  DatosContacto : TObjeto;
  Clientes : Items;
  DatosCliente : TDatosCliente;
begin
  Clientes := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_CLIENTES);
  Id := Clientes.GetFirst;
  while Assigned(Id) and (Sysutils.Supports(Id, ContactItem, Contacto)) do
  begin
    if EsCadenaVacia(Contacto.CustomerID) then
    begin
      DatosCliente := TDatosCliente.Create;
      try
        InsertarClienteBD(Contacto, DatosCliente);
        ActualizarClienteOutlook(Contacto, DatosCliente);
      finally
        DatosCliente.Free;
      end;
    end;
    Id := Clientes.GetNext;
  end;
end;

procedure TfSincronizacion.InsertarClienteBD(Contacto: ContactItem;
  Cliente: TDatosCliente);
begin
  with Contacto, Cliente do
  begin
    Nombre := FullName;
    Calle := BusinessAddressStreet;
    Piso := '';
    Numero := '';
    CodigoPostal := BusinessAddressPostalCode;
    Poblacion := BusinessAddressCity;
    Provincia := BusinessAddressState;
    Correo := Email1Address;
    Telefono1 := BusinessTelephoneNumber;
    Telefono2 := Business2TelephoneNumber;
    Fax := BusinessFaxNumber;
    Observaciones := Body;
    SalvarDatos;
  end;
end;

procedure TfSincronizacion.InsertarProveedorBD(Contacto: ContactItem;
  Proveedor: TDatosProveedor);
begin
  with Contacto, Proveedor do
  begin
    Nombre := FullName;
    Calle := BusinessAddressStreet;
    Piso := '';
    Numero := '';
    CodigoPostal := BusinessAddressPostalCode;
    Poblacion := BusinessAddressCity;
    Provincia := BusinessAddressState;
    Correo := Email1Address;
    Telefono1 := BusinessTelephoneNumber;
    Telefono2 := Business2TelephoneNumber;
    Fax := BusinessFaxNumber;
    Observaciones := Body;
    SalvarDatos;
  end;
end;

procedure TfSincronizacion.AnadirProveedoresNuevos;
var
  Contacto : ContactItem;
  Id: IDispatch;
  DatosContacto : TObjeto;
  Proveedores : Items;
  DatosProveedor : TDatosProveedor;
begin
  Proveedores := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_PROVEEDORES);
  Id := Proveedores.GetFirst;
  while Assigned(Id) and (Sysutils.Supports(Id, ContactItem, Contacto)) do
  begin
    if EsCadenaVacia(Contacto.CustomerID) then
    begin
      DatosProveedor := TDatosProveedor.Create;
      try
        InsertarProveedorBD(Contacto, DatosProveedor);
        ActualizarProveedorOutlook(Contacto, DatosProveedor);
      finally
        DatosProveedor.Free;
      end;
    end;
    Id := Proveedores.GetNext;
  end;
end;

procedure TfSincronizacion.EliminarProveedoresSobrantes;
var
  Contacto : ContactItem;
  Filter: Widestring;
  Id: IDispatch;
  Total : Integer;
  Contador : Integer;
  DatosContacto : TObjeto;
  Proveedores : Items;
begin
  Proveedores := olContactsFolder.Items.Restrict('[Categorías] = ' + CATEGORIA_PROVEEDORES);
  FTablaContactos.Open;
  FTablaContactos.Last;
  try
    Total := Proveedores.Count - FTablaContactos.RecordCount;
    Id := Proveedores.GetLast;
    if Total > 0 then
    begin
      Contador := 0;
      while (Contador < Total) and Assigned(Id)
        and (Sysutils.Supports(Id, ContactItem, Contacto)) do
      begin
        FTablaContactos.First;
        if not FTablaContactos.Locate('CODIGO', Contacto.CustomerID, []) then
        begin
          Contacto.Delete;
          Contador := Contador + 1;
        end;
        Id := Proveedores.GetPrevious;
      end;
    end;
  finally
    FTablaContactos.Close;
  end;
end;

function TfSincronizacion.DarUltimaSincronizacion: TDateTime;
var
  oSQL : TIBQuery;
begin
  oSQL := TIBQuery.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select ULTIMASINCRONIZACION ');
    SQL.Add('from USUARIOS ');
    SQL.Add('where UPPER(USUARIO) = UPPER(:USUARIO)');
    ParamByName('USUARIO').AsString := dmBaseDatos.Usuario;

    try
      Prepare;
      Open;
      Result := FieldByName('ULTIMASINCRONIZACION').AsDateTime;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

procedure TfSincronizacion.ActualizarFechaSincronizacion;
var
  oSQL : TIBSQL;
  bInsertar : Boolean;
begin
  bInsertar := False;
  oSQL := TIBSQL.Create(nil);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('update USUARIOS set ');
    SQL.Add('ULTIMASINCRONIZACION = CURRENT_TIME ');
    SQL.Add('where UPPER(USUARIO) = UPPER(:USUARIO)');
    ParamByName('USUARIO').AsString := dmBaseDatos.Usuario;
    try
      Prepare;
      ExecQuery;
      if RowsAffected = 0 then
        bInsertar := True;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;

  if bInsertar then
  begin
    oSQL := TIBSQL.Create(nil);
    with oSQL do
    begin
      Database := dmBaseDatos.BD;
      Transaction := dmBaseDatos.Transaccion;
      SQL.Add('insert into USUARIOS ');
      SQL.Add('(USUARIO, ULTIMASINCRONIZACION) values ');
      SQL.Add('(:USUARIO, CURRENT_TIME) ');
      ParamByName('USUARIO').AsString := dmBaseDatos.Usuario;
      try
        Prepare;
        ExecQuery;
      finally
        Close;
        Transaction := NIL;
        Free;
      end;
    end;
  end;
end;


end.
