unit uActualizarClientesUtils;

interface

uses
  Forms, Classes, Windows, SysUtils,
  uBizTiendaWeb, JSDialog, ExtCtrls;

function ActualizarClientesTienda(ATiendaWeb : IBizTiendaWeb): Boolean;

implementation

uses
  uClientesController, uOscAddressBookController, uDireccionesContactoController,
  uOscCustomersController, uBizOscAddressBook, uBizOscCustomers,
  uPasswordUtils, schTiendaWebClient_Intf, uDADataTable, uBizContactos, uBizDireccionesContacto,
  schContactosClient_Intf, JSDialogs, uDialogUtils, StrUtils, uIntegerListUtils;

const
  OSC_CUSTOMER_GENDER = 'm';
  OSC_CUSTOMER_COUNTRY_ID = 195;  // España
  OSC_CUSTOMER_ZONE_ID = 161; // Madrid

function AnadirOSCAddressBook(AOSCAddressBook : IBizOscAddressBook; ACliente : IBizCliente; ADireccionContacto : IBizDireccionesContacto) : Boolean;
begin
  Result := False;

  if not Assigned(AOSCAddressBook) then
    raise Exception.Create ('OSCAddressBook no asignado (AnadirOSCAddressBook)');

  if not Assigned(ACliente) then
    raise Exception.Create ('Cliente no asignado (AnadirOSCAddressBook)');

  if not Assigned(ADireccionContacto) then
    raise Exception.Create ('Dirección no asignada (AnadirOSCAddressBook)');

  ACliente.DataTable.Active := True;
  ADireccionContacto.DataTable.Active := True;
  AOSCAddressBook.DataTable.Active := True;

  with AOSCAddressBook do
  begin
    Insert;
    rdx_address_book_id_local := ADireccionContacto.ID;
    entry_company := ACliente.NOMBRE_COMERCIAL;
    entry_gender := OSC_CUSTOMER_GENDER; // No puede ser nulo
    entry_firstname := ACliente.NOMBRE;
    entry_lastname := ''; // No puede ser nulo
    entry_street_address := ADireccionContacto.CALLE;
    entry_postcode := ADireccionContacto.CODIGO_POSTAL;
    entry_city := ADireccionContacto.POBLACION;
    entry_state := ADireccionContacto.PROVINCIA;
    entry_telephone := ADireccionContacto.TELEFONO;
    entry_country_id := OSC_CUSTOMER_COUNTRY_ID; // No puede ser nulo
    entry_zone_id := OSC_CUSTOMER_ZONE_ID; // No puede ser nulo
    Post;
  end;

  Result := True;
end;


function ActualizarOSCAddressBook(AOSCAddressBook : IBizOscAddressBook; ACliente : IBizCliente; ADireccionContacto : IBizDireccionesContacto): Boolean;
begin
  Result := False;
  
  if not Assigned(AOSCAddressBook) then
    raise Exception.Create ('OSCAddressBook no asignado (ActualizarOSCAddressBook)');

  if not Assigned(ACliente) then
    raise Exception.Create ('Cliente no asignado (ActualizarOSCAddressBook)');
    
  if not Assigned(ADireccionContacto) then
    raise Exception.Create ('Dirección no asignada (ActualizarOSCAddressBook)');

  ACliente.DataTable.Active := True;
  ADireccionContacto.DataTable.Active := True;
  AOSCAddressBook.DataTable.Active := True;

  with AOSCAddressBook do
  begin
    Edit;
    entry_company := ACliente.NOMBRE_COMERCIAL;
    entry_gender := OSC_CUSTOMER_GENDER; // No puede ser nulo
    entry_firstname := ACliente.NOMBRE;
    entry_lastname := ''; // No puede ser nulo
    entry_street_address := ADireccionContacto.CALLE;
    entry_postcode := ADireccionContacto.CODIGO_POSTAL;
    entry_city := ADireccionContacto.POBLACION;
    entry_state := ADireccionContacto.PROVINCIA;
    entry_telephone := ADireccionContacto.TELEFONO;    
    entry_country_id := OSC_CUSTOMER_COUNTRY_ID; // No puede ser nulo
    entry_zone_id := OSC_CUSTOMER_ZONE_ID; // No puede ser nulo
    Post;
  end;

  Result := True;  
end;


function AnadirOSCCustomer(AOSCCustomers : IBizOscCustomer; ACliente : IBizCliente): Boolean;
var
  AOSCCustomerController : IOscCustomersController;
  i : Integer;
  Resultado : Boolean;
  s : string;
begin
  {
    CUIDADITO CON EL MYSQL Y LOS CAMPOS AUTOINC

    Orden para insertar los datos:

    1º -> Guardar la ficha del cliente
    2º -> Guardar todas las direcciones
    3ª -> Actualizar la ficha del cliente con la dirección de entrega por defecto.
  }

  Result := True;

  if not Assigned(AOSCCustomers) then
    raise Exception.Create ('OSCCustomers no asignado (AnadirOSCCustomer)');

  if not Assigned(ACliente) then
    raise Exception.Create ('Cliente no asignado (AnadirOSCCustomer)');

  ACliente.DataTable.Active := True;

  AOSCCustomerController := TOscCustomersController.Create;
  AOSCCustomers.DataTable.Active := True;

  try
    AOSCCustomerController.Anadir(AOSCCustomers);
    with AOSCCustomers do
    begin
      customers_firstname := ACliente.NOMBRE;
      customers_lastname := ''; // No puede ser nulo
      customers_email_address := ACliente.EMAIL_1;
      customers_telephone := ACliente.TELEFONO_1;
      customers_fax := ACliente.FAX;
      customers_password := EncriptarPasswordOSC(ACliente.NIF_CIF);
      rdx_customers_id_local := ACliente.ID;
      Post;
    end;
    // Guardo el customer
    AOSCCustomerController.Guardar(AOSCCustomers);

    ACliente.Direcciones.DataTable.First;
    for i := 0 to ACliente.Direcciones.DataTable.RecordCount - 1 do
    begin
      Resultado := AnadirOSCAddressBook(AOSCCustomers.AddressBook, ACliente, ACliente.Direcciones);
      Result := Result AND Resultado;
      ACliente.Direcciones.DataTable.Next;
    end;
    // Guardo todas sus direcciones
    AOSCCustomerController.Guardar(AOSCCustomers);

    AOSCCustomers.AddressBook.DataTable.First;
    with AOSCCustomers do
    begin
      Edit;
      customers_default_address_id := AOSCCustomers.AddressBook.address_book_id;
      Post;
    end;
    // Guardo la dirección de entrega por defecto en la ficha del customer
    AOSCCustomerController.Guardar(AOSCCustomers);

    {s := AOSCCustomers.customers_firstname + #10#13 + 'AOSCCustomers.customers_id -> ' + IntToStr(AOSCCustomers.customers_id) +
      #10#13 + #10#13 + 'AOSCCustomers.AddressBook:' + #10#13;

    AOSCCustomers.AddressBook.DataTable.First;
    for i := 0 to AOSCCustomers.AddressBook.DataTable.RecordCount - 1 do
    begin
      s := s + Format('     [%d] -> %d', [i, AOSCCustomers.AddressBook.address_book_id]) + #10#13;
      AOSCCustomers.AddressBook.DataTable.Next;
    end;

    ShowMessage(s);}


  finally
    AOSCCustomerController := NIL;
  end;
end;


function ActualizarOSCCustomer(AOSCCustomers : IBizOscCustomer; ACliente : IBizCliente) : Boolean;
var
  AOSCCustomerController : IOscCustomersController;
  AOSCAddressController : IOscAddressBookController;
  ADireccionesController : IDireccionesContactoController;
  i : Integer;
  Resultado : Boolean;  
begin
  Result := True;

  if not Assigned(AOSCCustomers) then
    raise Exception.Create ('OSCCustomers no asignado (ActualizarOSCCustomer)');

  if not Assigned(ACliente) then
    raise Exception.Create ('Cliente no asignado (ActualizarOSCCustomer)');

  ACliente.DataTable.Active := True;

  AOSCCustomerController := TOscCustomersController.Create;
  AOSCAddressController := TOscAddressBookController.Create;
  ADireccionesController := TDireccionesContactoController.Create;

  AOSCCustomers.DataTable.Active := True;
  try
    if not AOSCCustomerController.Localizar(AOSCCustomers, ACliente.ID) then
      raise Exception.CreateFmt('No se ha localizado el customer con ID = %d', [ACliente.ID]);

    with AOSCCustomers do
    begin
      Edit;
      customers_firstname := ACliente.NOMBRE;
      customers_lastname := ''; // No puede ser nulo
      customers_email_address := ACliente.EMAIL_1;
      customers_telephone := ACliente.TELEFONO_1;
      customers_fax := ACliente.FAX;
      Post;
    end;
    AOSCCustomerController.Guardar(AOSCCustomers);

    // Comprobar si hay que borrar algún address
    AOSCCustomers.AddressBook.Last;
    for i := 0 to AOSCCustomers.AddressBook.RecordCount - 1 do
    begin
      if (AOSCCustomers.AddressBook.rdx_address_book_id_local > 0) and
        not ADireccionesController.Localizar(ACliente.Direcciones, AOSCCustomers.AddressBook.rdx_address_book_id_local)
      then
        AOSCCustomers.AddressBook.Delete
      else
        AOSCCustomers.AddressBook.Prior;
    end;

    ACliente.Direcciones.DataTable.First;
    for i := 0 to ACliente.Direcciones.DataTable.RecordCount - 1 do
    begin

      if not AOSCAddressController.Localizar(AOSCCustomers.AddressBook, ACliente.Direcciones.ID) then
        Resultado := AnadirOSCAddressBook(AOSCCustomers.AddressBook, ACliente, ACliente.Direcciones)
      else
        Resultado := ActualizarOSCAddressBook(AOSCCustomers.AddressBook, ACliente, ACliente.Direcciones);

      Result := Result AND Resultado;
      ACliente.Direcciones.DataTable.Next;
    end;
    AOSCCustomerController.Guardar(AOSCCustomers);

    //ShowMessage(AOSCCustomers.customers_firstname + #10#13 + 'AOSCCustomers.customers_id -> ' + IntToStr(AOSCCustomers.customers_id));

    AOSCCustomers.AddressBook.DataTable.First;
    with AOSCCustomers do
    begin
      Edit;
      customers_default_address_id := AOSCCustomers.AddressBook.address_book_id;
      Post;
    end;
    // Guardo la dirección de entrega por defecto en la ficha del customer
    AOSCCustomerController.Guardar(AOSCCustomers);
    
  finally
    AOSCCustomerController := NIL;
    AOSCAddressController := NIL;
    ADireccionesController := NIL;
  end;
end;

function HayCambiosPendientes(ACliente : IBizCliente; AOSCCustomer : IBizOscCustomer;
  const UltimaSincro : TDateTime): Boolean;
var
  i : integer;
  Cambiado : Boolean;
  ANumAddr : Integer;
begin
  {
    Casos:
     1 -> El cliente ha cambiado en FactuGES
     2 -> Se ha dado de alta una dirección
     3 -> Se han cambiado los datos de una dirección
     4 -> Se ha eliminado una dirección
  }

  if not Assigned(ACliente) then
    raise Exception.Create ('Cliente no asignado (HayCambiosPendientes)');

  if not Assigned(AOSCCustomer) then
    raise Exception.Create ('Customer no asignado (HayCambiosPendientes)');

  ACliente.DataTable.Active := True;
  AOSCCustomer.DataTable.Active := True;

  // 1 -> ¿El cliente ha cambiado en FactuGES?
  Cambiado := (ACliente.FECHA_MODIFICACION > UltimaSincro);
  if not Cambiado then
  begin
    ACliente.Direcciones.First;

    {
      2 -> ¿Se ha dado de alta una dirección?
      4 -> ¿Se ha eliminado una dirección?
    }
    ANumAddr := 0;
    AOSCCustomer.AddressBook.First;
    for i := 0 to AOSCCustomer.AddressBook.RecordCount - 1 do
    begin
      // Saber el número de address que tienen relleno el campo rdx_address_book_id_local.
      // Si lo tienen relleno quiere decir que provienen de FactuGES y no
      // que el cliente las ha dado de alta desde OSC. Esas se ignoran.
      if (AOSCCustomer.AddressBook.rdx_address_book_id_local > 0) then
      begin
        Inc(ANumAddr);
      end;
      AOSCCustomer.AddressBook.Next;
    end;
    // Si no coincide el número de calles es que algo ha cambiado
    Cambiado := ACliente.Direcciones.RecordCount <> ANumAddr;

    {
      3 -> ¿Se han cambiado los datos de una dirección?
    }
    if not Cambiado then
    begin
      for i := 0 to ACliente.Direcciones.RecordCount - 1 do
      begin
        Cambiado := ((ACliente.Direcciones.FECHA_MODIFICACION > UltimaSincro) or
            (ACliente.Direcciones.FECHA_ALTA > UltimaSincro));
        if Cambiado then
          Break
        else
          ACliente.Direcciones.Next;
      end;
    end;
  end;

  Result := Cambiado;
end;

function ActualizarClientesTienda(ATiendaWeb : IBizTiendaWeb): Boolean;
var
  AClientesController : IClientesController;
  AClientes : IBizCliente;

  AOSCCustomerController : IOscCustomersController;
  AOSCCustomers : IBizOscCustomer;

  i : Integer;
  j : Integer;

  //ADlg : TJSDialog;
  Resultado : Boolean;
  s : String;

  ACustomerList : TIntegerList;
  AIndex : Integer;
begin
  Result := False;
  if not Assigned(ATiendaWeb) then
    raise Exception.Create ('TiendaWeb no asignada');

  try
    AClientesController := TClientesController.Create;
    AOSCCustomerController := TOscCustomersController.Create;

    ACustomerList := TIntegerList.Create;
        
    {ADlg := TJSDialog.Create(Application);
    with ADlg do
    begin
      Title := 'Actualización de clientes';
      DialogOptions := [doProgressBar, doTopMost];
      ButtonBar.Buttons := [];
      Instruction.Text := 'Actualizando clientes...';
      Content.Text := Format('Progreso: %d%%', [0]);
      Expando.Visible := True;
      Expando.MoreHeight := 200;
      Expando.ShowInFooter := True;
      Expando.ShowText := 'Ver más detalles...';
      Expando.HideText := 'Ocultar detalles...';
      Progress.Max := 100;      
    end;}

    AClientes := (AClientesController.BuscarTodosTiendaWeb as IBizCliente);
    AClientes.DataTable.Active := True;
    AClientes.DataTable.First;

    AOSCCustomers := AOSCCustomerController.BuscarTodos;
    AOSCCustomers.DataTable.Active := True;
    AOSCCustomers.DataTable.First;

    {if AClientes.DataTable.RecordCount > 0 then
      ADlg.Progress.Max := AClientes.DataTable.RecordCount;

    ADlg.Execute;
    }

    {s := '';
    AOSCCustomers.DataTable.First;
    for I := 0 to AOSCCustomers.DataTable.RecordCount - 1 do
    begin
      s := s + AOSCCustomers.customers_firstname + ' -> ' + IntToStr(AOSCCustomers.rdx_customers_id_local) + #10#13;
      AOSCCustomers.DataTable.Next;
    end;
    ShowMessage(s);}

    for I := 0 to AClientes.DataTable.RecordCount - 1 do
    begin
      Application.ProcessMessages;
      {with ADlg do
      begin
        Content.Text := Format('Progreso: %d%%', [Progress.Position*100 div ADlg.Progress.Max]);
        UpdateProgress;
        Application.ProcessMessages;
      end;}

      if not AOSCCustomerController.Localizar(AOSCCustomers, AClientes.ID) then
      begin
        s := Format('Añadiendo %s... ', [AClientes.NOMBRE]);
        Resultado := AnadirOSCCustomer(AOSCCustomers, AClientes);
        if Resultado then
          s := s + 'OK'
        else
          s := s + 'Fallo';
      end
      else begin
        if HayCambiosPendientes(AClientes, AOSCCustomers, ATiendaWeb.ULTIMA_ACTUALIZACION) then
        begin
          s := Format('Actualizando %s... ', [AClientes.NOMBRE]);
          Resultado := ActualizarOSCCustomer(AOSCCustomers, AClientes);
          if Resultado then
            s := s + 'OK'
          else
            s := s + 'Fallo';
        end
        else
          s := Format('%s sin cambios', [AClientes.NOMBRE]);
      end;

      //ADlg.Expando.Lines.Add(s);
      ACustomerList.Add(AClientes.ID);
      AClientes.DataTable.Next;
    end;

    // Ahora hay que eliminar de OSC los clientes que sobran
    AOSCCustomers.Last;
    for I := (AOSCCustomers.DataTable.RecordCount - 1) downto 0 do
    begin
      Application.ProcessMessages;
      if not ACustomerList.Find(AOSCCustomers.rdx_customers_id_local, AIndex) then
      begin
        s := Format('Eliminado %s... ', [AOSCCustomers.customers_firstname]);
        //ADlg.Expando.Lines.Add(s);
        AOSCCustomers.Delete;
      end;
      AOSCCustomers.Prior;
    end;
    AOSCCustomerController.Guardar(AOSCCustomers);


    Application.ProcessMessages;
    Result := True;
  finally
    {ADlg.Close;
    FreeAndNIL(ADlg);}

    FreeAndNIL(ACustomerList);

    AClientesController := NIL;
    AOSCCustomerController := NIL;
    AOSCCustomers := NIL;
  end;
end;

end.
