unit uContactosController;

interface


uses
  Windows, Forms, Classes, Controls, Contnrs, SysUtils, uDADataTable,
  uBizContactos, uBizContactosDatosBancarios, uIDataModuleContactos,
  uBizDireccionesContacto, uDireccionesContactoController,
  uControllerBase, uBizContactosPersonal, uBizContactosDirecciones;

type
  IContactosController = interface(IControllerBase)
    ['{E91C24EB-D4D9-4203-809B-0AF90F41B32E}']
    function Buscar(const ID: Integer): IBizContacto;
    function BuscarTodos: IBizContacto;
    procedure Ver(AContacto : IBizContacto);
    procedure VerTodos(AContactos: IBizContacto);
    function Nuevo : IBizContacto;
    procedure Anadir(AContacto : IBizContacto);
    procedure Eliminar(const ID : Integer); overload;
    function Eliminar(AContacto : IBizContacto): Boolean; overload;
    function Guardar(AContacto : IBizContacto): Boolean;
    procedure DescartarCambios(AContacto : IBizContacto);
    function Existe(const ID: Integer) : Boolean;
    function Duplicar(AContacto : IBizContacto) : IBizContacto;
    function Localizar(AContactos: IBizContacto; const ID : Integer): Boolean;
    function ElegirContacto(AContactos : IBizContacto;
      AMensaje: String; AMultiSelect: Boolean): IBizContacto;

    function ExtraerSeleccionados(AContactos: IBizContacto) : IBizContacto;
//    procedure SetID_Tienda (AContacto: IBizContacto; const ID_Tienda: Integer);
    function ElegirDireccion(AContacto: IBizContacto; AMensaje: String): IBizDireccionesContacto;
    function ElegirPersonaContacto(APersonal: IBizContactoPersonal;
      AMensaje: String): IBizContactoPersonal;
    function DarDireccionSocial(AContacto : IBizContacto): IBizDireccionesContacto;
    function DarTodasDirecciones(const IDContacto : Integer): IBizContactosDirecciones;
  end;

  TContactosController = class(TControllerBase, IContactosController)
  protected
    FDataModule : IDataModuleContactos;
    procedure FiltrarEmpresa(AContacto : IBizContacto); virtual;
    function _Vacio : IBizContacto; virtual;
    function ValidarContacto(AContacto : IBizContacto): Boolean; virtual;
  public
    constructor Create; override;
    destructor Destroy; override;

    procedure Eliminar(const ID : Integer); overload; virtual;
    function Eliminar(AContacto : IBizContacto): Boolean; overload; virtual;
    function Guardar(AContacto : IBizContacto): Boolean; virtual;
    procedure DescartarCambios(AContacto : IBizContacto); virtual;
    function Existe(const ID: Integer) : Boolean; virtual;
    procedure Anadir(AContacto : IBizContacto); virtual;
    function Duplicar(AContacto: IBizContacto): IBizContacto; virtual;
    function ExtraerSeleccionados(AContactos: IBizContacto) : IBizContacto; virtual;
    function Localizar(AContactos: IBizContacto; const ID : Integer): Boolean;

    // Se implementa en los controladores hijos
    function Buscar(const ID: Integer): IBizContacto; virtual; abstract;
    function BuscarTodos: IBizContacto; virtual; abstract;
    function Nuevo : IBizContacto; virtual; abstract;
    procedure Ver(AContacto : IBizContacto); virtual; abstract;
    procedure VerTodos(AContactos: IBizContacto); virtual; abstract;
    function ElegirContacto(AContactos : IBizContacto;
      AMensaje: String; AMultiSelect: Boolean): IBizContacto; virtual; abstract;
//    procedure SetID_Tienda (AContacto: IBizContacto; const ID_Tienda: Integer);
    function ElegirDireccion(AContacto: IBizContacto; AMensaje: String): IBizDireccionesContacto;
    function ElegirPersonaContacto(APersonal: IBizContactoPersonal;
      AMensaje: String): IBizContactoPersonal;
    function DarDireccionSocial(AContacto : IBizContacto): IBizDireccionesContacto;
    function DarTodasDirecciones(const IDContacto : Integer): IBizContactosDirecciones;
  end;

implementation

uses
  uStringsUtils, Dialogs, uEditorRegistryUtils, cxControls, DB, uDAInterfaces, uDataTableUtils,
  schContactosClient_Intf, uFactuGES_App, Variants, JSDialogs, JSDialog,
  uIEditorElegirPersonaContacto;

{ TContactosController }

procedure TContactosController.Anadir(AContacto: IBizContacto);
begin
  AContacto.Insert;
end;

function TContactosController.Duplicar(AContacto: IBizContacto): IBizContacto;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(AContacto.DataTable, Result.DataTable, mdrActual);
    DuplicarRegistros(AContacto.DatosBancarios.DataTable, Result.DatosBancarios.DataTable, mdrTodos);
    if Assigned(AContacto.Direcciones) then
       DuplicarRegistros(AContacto.Direcciones.DataTable, Result.Direcciones.DataTable, mdrTodos);

    // Hay que dejar algunos campos como si fuera un contacto nuevo
    Result.Edit;
    with Result do
    begin
      ID_EMPRESA := AppFactuGES.EmpresaActiva.ID;
      USUARIO := AppFactuGES.UsuarioActivo.UserName;
      REFERENCIA := '';
    end;

    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;

constructor TContactosController.Create;
begin
  inherited;
  FDataModule := NIL;
end;

function TContactosController.DarDireccionSocial(
  AContacto: IBizContacto): IBizDireccionesContacto;
var
  ADireccionesController :  IDireccionesContactoController;
begin
  if not Assigned(AContacto) then
    raise Exception.Create ('Contacto no asignado');

  ADireccionesController := TDireccionesContactoController.Create;
  try
    Result := ADireccionesController.Nuevo;
    with Result do
    begin
      ClearField('ID');
      NOMBRE := AContacto.NOMBRE;
      CALLE := AContacto.CALLE;
      POBLACION := AContacto.POBLACION;
      CODIGO_POSTAL := AContacto.CODIGO_POSTAL;
      PROVINCIA := AContacto.PROVINCIA;
      TELEFONO := AContacto.TELEFONO_1;
      FAX := AContacto.FAX;
      MOVIL := AContacto.MOVIL_1;
      EMAIL := AContacto.EMAIL_1;
      PERSONA_CONTACTO := AContacto.PERSONA_CONTACTO;
    end;
  finally
    ADireccionesController := NIL;
  end;
end;

function TContactosController.DarTodasDirecciones(
  const IDContacto : Integer): IBizContactosDirecciones;
begin
  Result := FDataModule.GetContactoDirecciones(IDContacto);
end;

procedure TContactosController.DescartarCambios(AContacto: IBizContacto);
begin
  if not Assigned(AContacto) then
    raise Exception.Create ('Contacto no asignado');

  ShowHourglassCursor;
  try
    if (AContacto.State in dsEditModes) then
      AContacto.Cancel;

    AContacto.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TContactosController.Destroy;
begin
  FDataModule := NIL;
  inherited;
end;

function TContactosController.ElegirDireccion(AContacto: IBizContacto; AMensaje: String): IBizDireccionesContacto;
var
  JsDialog: TJSDialog;
begin
  Result := NIL;
  JsDialog := TJSDialog.Create(nil);
  try
    JsDialog.Content.Add(AMensaje);
    JsDialog.Instruction.Text := 'Elija una direcci'#243'n.';
    JsDialog.DialogOptions := [doCommandLinks, doModal];
    JsDialog.ButtonBar.Buttons := [cbOk];
    JsDialog.Width := 600;

    //Añadimos la direccion principal del contacto
    with JsDialog.CustomButtons.Add do
    begin
       Caption := AContacto.NOMBRE + '     ' + AContacto.NIF_CIF;
       Info.Add(AContacto.CALLE);
       Info.Add(AContacto.CODIGO_POSTAL + '  ' + AContacto.POBLACION + '  ' + AContacto.PROVINCIA);
       Value := -1;
       Default := True;
    end;

    //Añadimos el resto de direcciones
    AContacto.Direcciones.Datatable.First;
    while not AContacto.Direcciones.Datatable.eof do
    begin
      with JsDialog.CustomButtons.Add do
      begin
         Caption := AContacto.Direcciones.NOMBRE + '     ' + AContacto.Direcciones.NIF_CIF;
         Info.Add(AContacto.Direcciones.CALLE);
         Info.Add(AContacto.Direcciones.CODIGO_POSTAL + '  ' + AContacto.Direcciones.POBLACION + '  ' + AContacto.Direcciones.PROVINCIA);
         Value := AContacto.Direcciones.ID;
      end;
      AContacto.Direcciones.DataTable.Next;
    end;
    AContacto.Direcciones.DataTable.First;

    if JsDialog.Execute <> IDCANCEL then
       if JsDialog.CustomButtonResult > 0 then
       begin
          if AContacto.Direcciones.DataTable.Locate(fld_DireccionesContactoID, JsDialog.CustomButtonResult, []) then
             Result := AContacto.Direcciones;
       end
       else begin
         // Se ha elegido la dirección de la razón social
         Result := DarDireccionSocial(AContacto)
       end;

  finally
    FreeAndNIL(JsDialog);
  end;
end;

function TContactosController.ElegirPersonaContacto(
  APersonal: IBizContactoPersonal; AMensaje: String): IBizContactoPersonal;
var
  AEditor : IEditorElegirPersonaContacto;
begin
  Result := NIL;

  CreateEditor('EditorElegirPersonaContacto', IEditorElegirPersonaContacto, AEditor);
  if Assigned(AEditor) then
  begin
    try
      AEditor.Personas := APersonal;
      AEditor.TextoComentarios := AMensaje;
      if IsPositiveResult(AEditor.ShowModal) then
        Result := AEditor.PersonaSeleccionada;
    finally
      AEditor.Release;
      AEditor := NIL;
      Application.ProcessMessages;
    end;
  end;
end;

function TContactosController.Eliminar(AContacto: IBizContacto): Boolean;
begin
  Result := False;

  if not Assigned(AContacto) then
    raise Exception.Create ('Contacto no asignado');

  ShowHourglassCursor;
  try
    if (AContacto.State in dsEditModes) then
      AContacto.Cancel;

    AContacto.Delete;
    AContacto.DataTable.ApplyUpdates;
    HideHourglassCursor;
    Result := True;
  except
    on E: Exception do
    begin
      AContacto.DataTable.CancelUpdates;
      HideHourglassCursor;
      if (Pos('FOREIGN KEY', E.Message) > 0) then
         MessageBox(0, 'No se puede borrar este contacto porque tiene documentos dados de alta (como presupuestos, albaranes, facturas, etc)', 'Atención', MB_ICONWARNING or MB_OK);
    end;
  end;
end;

procedure TContactosController.Eliminar(const ID: Integer);
var
  AContacto : IBizContacto;
begin
  AContacto := Buscar(ID);

  if not Assigned(AContacto) then
    raise Exception.Create(Format('No se ha encontrado el contacto con ID = %d', [ID]));

  Eliminar(AContacto);
  AContacto := NIL;
end;

function TContactosController.Existe(const ID: Integer): Boolean;
var
  AContacto : IBizContacto;
begin
  try
    AContacto := Buscar(ID);
    Result := Assigned(AContacto) and (AContacto.ID = ID);
  finally
    AContacto := NIL;
  end;
end;

function TContactosController.ExtraerSeleccionados(AContactos: IBizContacto): IBizContacto;
var
  ASeleccionados : IBizContacto;
begin
  ASeleccionados := Self.Buscar(ID_NULO);
  CopyDataTableDA5(AContactos.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

function TContactosController.Guardar(AContacto: IBizContacto): Boolean;
var
  dtDetails : TList;
  i : integer;
begin
  Result := False;

  if ValidarContacto(AContacto) then
  begin
    ShowHourglassCursor;

    if AContacto.EsNuevo then
    begin
      AContacto.Edit;
      AContacto.ID_EMPRESA := AppFactuGES.EmpresaActiva.ID;
      AContacto.Post;
    end;

    dtDetails := AContacto.DataTable.GetDetailDataTables;
    for i := 0 to dtDetails.Count - 1 do
    begin
      if (TDADataTable(dtDetails.Items[i])).State in dsEditModes then
        (TDADataTable(dtDetails.Items[i])).Post;
    end;

    try
      AContacto.DataTable.ApplyUpdates;
      Result := True;      
    finally
      HideHourglassCursor;
    end;
  end;
end;

function TContactosController.Localizar(AContactos: IBizContacto;
  const ID: Integer): Boolean;
begin
  Result := True;
  ShowHourglassCursor;
  try
    with AContactos.DataTable do
    begin
      DisableControls;
      First;
      if not Locate(fld_ContactosID, ID, []) then
         Result := False;
      EnableControls;
    end;
  finally
    HideHourglassCursor;
  end;
end;

{procedure TContactosController.SetID_Tienda(AContacto: IBizContacto; const ID_Tienda: Integer);
var
  EnEdicion: Boolean;
begin
  if Assigned(AContacto) then
  begin
    EnEdicion := AContacto.DataTable.Editing;
    if not AContacto.DataTable.Editing then
       AContacto.DataTable.Edit;

    if ID_Tienda < 0 then
       AContacto.DataTable.FieldByName(fld_ContactosID_TIENDA).AsVariant := Null
    else
       AContacto.ID_TIENDA := ID_Tienda;

    AContacto.DataTable.Post;

    if EnEdicion then
       AContacto.DataTable.Edit;
  end;
end;}

function TContactosController.ValidarContacto(AContacto: IBizContacto): Boolean;
var
  NifCifTratado: String;
  NifValido: Boolean;
  CifValido: Boolean;

begin
  NifValido:= false;
  CifValido:= false;

  if not Assigned(AContacto) then
    raise Exception.Create ('Contacto no asignado');

  if (AContacto.DataTable.State in dsEditModes) then
    AContacto.DataTable.Post;

  if Length(AContacto.NOMBRE) = 0 then
    raise Exception.Create('Debe indicar al menos el nombre de este contacto.');

  if Length(AContacto.NIF_CIF) = 0 then
    raise Exception.Create('Debe indicar el NIF/CIF del este contacto.')
  else
  begin
    NifCifTratado := uStringsUtils.CadLimpiaCar(AContacto.NIF_CIF);
    NifValido := uStringsUtils.comprobarLetraNIF(NifCifTratado);
    if not NifValido then
       CifValido := uStringsUtils.validarCIF(NifCifTratado);

    if not (NifValido or CifValido) then
       raise Exception.Create('El DNI/NIF/CIF introducido no es correcto.')
  end;

  // Asegurarse de valores en campos "automáticos"
  AContacto.Edit;
  AContacto.USUARIO := AppFactuGES.UsuarioActivo.UserName;
  AContacto.NIF_CIF := NifCifTratado;
  AContacto.Post;
  
  Result := True;
end;

function TContactosController._Vacio: IBizContacto;
begin
  Result := Buscar(ID_NULO);
end;

procedure TContactosController.FiltrarEmpresa(AContacto: IBizContacto);
var
  Condicion: TDAWhereExpression;
begin
  if AContacto.DataTable.Active then
    AContacto.DataTable.Active := False;

  // Filtrar los presupuestos actuales por empresa
  with AContacto.DataTable.DynamicWhere do
  begin
    // (ID_EMPRESA >= ID)
    Condicion := NewBinaryExpression(NewField('', fld_ContactosID_EMPRESA), NewConstant(AppFactuGES.EmpresaActiva.ID, datInteger), dboEqual);

    if IsEmpty then
       Expression := Condicion
    else
       Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
  end;
end;

end.
