{
===============================================================================
  Copyright (©) 2007. 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:
  Versión actual: 1.0.0
  Fecha versión actual:
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
===============================================================================
}

unit uRecibosClienteController;

interface

uses
  Classes, SysUtils, uDADataTable, uControllerBase,
	uPagosClienteController, uClientesController, uBizDireccionesContacto,
  uBizRecibosCliente, uIDataModuleRecibosCliente;

type
  IRecibosClienteController = interface(IControllerBase)
  ['{CBC8BDB8-FBE0-4D54-B2F1-A9330E8339EB}']
    function GetClienteController: IClientesController;
    procedure SetClienteController(const Value: IClientesController);
    property ClienteController: IClientesController read GetClienteController write SetClienteController;

    function GetPagosController: IPagosClienteController;
    procedure SetPagosController(const Value: IPagosClienteController);
    property PagosController: IPagosClienteController read GetPagosController write SetPagosController;

    procedure Anadir(ARecibosCliente : IBizRecibosCliente);
    function Eliminar(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false): Boolean;

    function AnadirPago(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = ''): Boolean;
    function AnadirPagos(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = ''): Boolean;
    procedure ModificarPago(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = '');
    function EliminarPago(ARecibosCliente : IBizRecibosCliente): Boolean;
    function EliminarTodo(ARecibosCliente : IBizRecibosCliente): Boolean;

    function Guardar(ARecibosCliente : IBizRecibosCliente): Boolean;
    procedure DescartarCambios(ARecibosCliente : IBizRecibosCliente);
		function Duplicar(ARecibosCliente: IBizRecibosCliente): IBizRecibosCliente;
    function Nuevo : IBizRecibosCliente;

    procedure RecuperarCliente(AReciboCliente : IBizRecibosCliente);

    function Buscar(const ID: Integer): IBizRecibosCliente;
  	function BuscarTodos: IBizRecibosCliente;

    function BuscarRecibosRemesa(const ID_REMESA: Integer): IBizRecibosCliente;
  	function BuscarRecibosFactura(const ID_FACTURA: Integer): IBizRecibosCliente;
  	function BuscarRecibosContrato(const ID_CONTRATO: Integer): IBizRecibosCliente;    
    function BuscarRecibosACompensar(const Recibo: IBizRecibosCliente): IBizRecibosCliente;
  	function BuscarRecibosARemesar(const AListaVisibles, AListaNoVisibles: TStringList): IBizRecibosCliente;

    procedure VerTodos(ARecibosCliente: IBizRecibosCliente);
    procedure Ver(ARecibosCliente: IBizRecibosCliente);

    function ExtraerSeleccionados(ARecibosCliente: IBizRecibosCliente) : IBizRecibosCliente;
    function ElegirRecibos(ARecibos : IBizRecibosCliente; AMensaje: String; AMultiSelect: Boolean): IBizRecibosCliente;

    procedure CopiarDireccion (const ADireccionEnvio: IBizDireccionesContacto; ARecibo: IBizRecibosCliente);

    procedure AsignarRemesa(ARecibos : IBizRecibosCliente; ID_REMESA: Integer; AIgnorarContabilidad : Integer; ASubCuenta: Integer);
    procedure QuitarRemesa(ARecibos : IBizRecibosCliente);
    procedure SetSituacionCobrados(ARecibos : IBizRecibosCliente; WithDeltas: Boolean=False);

    function ElegirRecibosCompensados(ARecibo : IBizRecibosCliente): Boolean;
    procedure QuitarReciboCompensado(ARecibo : IBizRecibosCliente);

    function EsEliminable(ARecibo : IBizRecibosCliente): Boolean;

    procedure Preview(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false);
    procedure Print(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false);

    function DarListaAnosRecibos: TStringList;
    procedure FiltrarAno(ARecibo: IBizRecibosCliente; ADynWhereDataTable: WideString; const Ano: String);

  end;

  TRecibosClienteController = class(TControllerBase, IRecibosClienteController)
  private
    function ImporteTotalModificado(ARecibosCliente: IBizRecibosCliente;
      var ImporteRestante: Currency): Boolean;

    procedure FiltrarEmpresa(ARecibo: IBizRecibosCliente);

  protected
    FDataModule : IDataModuleRecibosCliente;
    FPagosController : IPagosClienteController;
    FClienteController : IClientesController;

    function GetClienteController: IClientesController;
    procedure SetClienteController(const Value: IClientesController);

    function GetPagosController: IPagosClienteController;
    procedure SetPagosController(const Value: IPagosClienteController);

  	function _Vacio : IBizRecibosCliente;

    function ValidarReciboCliente(ARecibosCliente: IBizRecibosCliente): Boolean;
    procedure AsignarDataModule;
    function DarNuevaReferencia(ID_FACTURA : Integer; REFERENCIA: String): String;

  public
    property ClienteController: IClientesController read GetClienteController write SetClienteController;
    property PagosController: IPagosClienteController read GetPagosController write SetPagosController;
    constructor Create; override;
    destructor Destroy; override;

    procedure RecuperarCliente(AReciboCliente : IBizRecibosCliente);
    procedure Anadir(ARecibosCliente : IBizRecibosCliente);
    function AnadirPago(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = ''): Boolean;
    function AnadirPagos(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = ''): Boolean;    
    procedure ModificarPago(ARecibosCliente : IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = '');
    function Eliminar(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false): Boolean;
    function EliminarPago(ARecibosCliente : IBizRecibosCliente): Boolean;
    function EliminarTodo(ARecibosCliente : IBizRecibosCliente): Boolean;
    function Guardar(ARecibosCliente : IBizRecibosCliente): Boolean;
    procedure DescartarCambios(ARecibosCliente : IBizRecibosCliente);
    function Duplicar(ARecibosCliente: IBizRecibosCliente): IBizRecibosCliente;
    function Nuevo : IBizRecibosCliente;

  	function Buscar(const ID: Integer): IBizRecibosCliente;
    function BuscarTodos: IBizRecibosCliente;

    function BuscarRecibosRemesa(const ID_REMESA: Integer): IBizRecibosCliente;
  	function BuscarRecibosFactura(const ID_FACTURA: Integer): IBizRecibosCliente;
  	function BuscarRecibosContrato(const ID_CONTRATO: Integer): IBizRecibosCliente;
    function BuscarRecibosACompensar(const Recibo: IBizRecibosCliente): IBizRecibosCliente;
  	function BuscarRecibosARemesar(const AListaVisibles, AListaNoVisibles: TStringList): IBizRecibosCliente;

    procedure VerTodos(ARecibosCliente: IBizRecibosCliente);
    procedure Ver(ARecibosCliente: IBizRecibosCliente);

    function ExtraerSeleccionados(ARecibosCliente: IBizRecibosCliente) : IBizRecibosCliente;
    function ElegirRecibos(ARecibos : IBizRecibosCliente; AMensaje: String; AMultiSelect: Boolean): IBizRecibosCliente;
    function ElegirRecibosCompensados(ARecibo : IBizRecibosCliente): Boolean;

    procedure CopiarDireccion (const ADireccionEnvio: IBizDireccionesContacto; ARecibo: IBizRecibosCliente);

    procedure AsignarRemesa(ARecibos : IBizRecibosCliente; ID_REMESA: Integer; AIgnorarContabilidad : Integer; ASubCuenta: Integer);
    procedure QuitarRemesa(ARecibos : IBizRecibosCliente);
    procedure QuitarReciboCompensado(ARecibo : IBizRecibosCliente);

    procedure SetSituacionCobrados(ARecibos : IBizRecibosCliente; WithDeltas: Boolean=False);

    function EsEliminable(ARecibo : IBizRecibosCliente): Boolean;

    procedure Preview(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false);
    procedure Print(ARecibosCliente : IBizRecibosCliente; AllItems: Boolean = false);

    function DarListaAnosRecibos: TStringList;
    procedure FiltrarAno(ARecibo: IBizRecibosCliente; ADynWhereDataTable: WideString; const Ano: String);


  end;

implementation

uses
  Forms, uNumUtils, cxControls, DB, uEditorRegistryUtils, Dialogs,
  uDAInterfaces, uDataTableUtils, uDataModuleUsuarios, uFactuGES_App,
  uDateUtils, uROTypes, DateUtils, Controls, Windows, Variants,
  uRecibosClienteReportController, uBizContactos, uDADelta, uIntegerListUtils,
  schRecibosClienteClient_Intf, uIEditorRecibosCliente, uIEditorReciboCliente,
  uIEditorElegirRecibosCliente, uDataModuleRecibosCliente, uIEditorFechaPago;

{ TRecibosClienteController }

procedure TRecibosClienteController.Anadir(ARecibosCliente: IBizRecibosCliente);
begin
  ARecibosCliente.Insert;
end;

function TRecibosClienteController.AnadirPago(ARecibosCliente: IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad: Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = ''): Boolean;
begin
  Result := False;

  // Se cancela la operación
  if Length(FechaPago) = 0 then
     raise Exception.Create('Debe indicar la fecha del pago.');

  //Liberamos el recibo aunque ya este libre
  if not ARecibosCliente.DataTable.Editing then
     ARecibosCliente.DataTable.Edit;

  ARecibosCliente.ID_REMESA := 0;
  ARecibosCliente.REFERENCIA_REMESA := '';
  ARecibosCliente.DataTable.Post;


  //Finalmente añadimos el pago (cobro o devolucion)
  if PagosController.Anadir(ARecibosCliente.Pagos, FechaPago, AIgnorarContabilidad, AIdSubcuenta, ASubCuenta) then
  begin
    ARecibosCliente.Edit;
    ARecibosCliente.SITUACION := CTE_COBRADO;
    Result := True;
  end
  //Podremos modificar si anulamos el cobro mediante una devolución
  else
  begin
    ARecibosCliente.Edit;
    ARecibosCliente.SITUACION := CTE_DEVUELTO;
    Result := False;
  end;
end;

function TRecibosClienteController.AnadirPagos(
  ARecibosCliente: IBizRecibosCliente; FechaPago: String; AIgnorarContabilidad,
  AIdSubCuenta: Integer; ASubCuenta: String): Boolean;
begin
  if Assigned(ARecibosCliente) then
     with ARecibosCliente.DataTable do
     begin
       First;
       while not EOF do
       begin
         if (ARecibosCliente.SITUACION = CTE_PENDIENTE) then
            Self.AnadirPago(ARecibosCliente, FechaPago, AIgnorarContabilidad, AIdSubCuenta, ASubCuenta);
         Next;
       end;
     end;
end;

procedure TRecibosClienteController.AsignarDataModule;
begin
  FDataModule := TDataModuleRecibosCliente.Create(Nil);
end;

procedure TRecibosClienteController.AsignarRemesa(ARecibos: IBizRecibosCliente; ID_REMESA: Integer; AIgnorarContabilidad : Integer; ASubCuenta: Integer);
begin
  if Assigned(ARecibos) then
  begin
    With ARecibos.DataTable do
    begin
      First;
      While not EOF do
      begin
        if (ARecibos.ID_REMESA <> ID_REMESA) then
        begin
          ARecibos.Edit;
          //Añadimos el cobro automatico por la remesa y volvemos a asignar ID
          //para que asigne un ID nuevo para el pago, porque aqui si hay maestro-detalle
          AnadirPago(ARecibos, DateToStr(Date), AIgnorarContabilidad, ASubCuenta); //->Ojo el orden es importante
          ARecibos.ID_REMESA := ID_REMESA;
        end;
        Next;
      end;
    end;
  end;
end;

function TRecibosClienteController.BuscarTodos: IBizRecibosCliente;
begin
  Result := FDataModule.GetItems;
  FiltrarEmpresa(Result);
end;

function TRecibosClienteController.BuscarRecibosACompensar(const Recibo: IBizRecibosCliente): IBizRecibosCliente;
var
  Condicion: TDAWhereExpression;
begin
  if not Assigned(Recibo) then
     raise Exception.Create ('IBizReciboCliente no asignado (BuscarRecibosACompensar)');

  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      //No podrá compensarse un recibo a si mismo
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID), NewConstant(Recibo.ID, datInteger), dboNotEqual);

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

    with Result.DataTable.DynamicWhere do
    begin
      //Solo podrá compensar recibos del mismo cliente
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_CLIENTE), NewConstant(Recibo.ID_CLIENTE, datInteger), dboEqual);

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

    with Result.DataTable.DynamicWhere do
    begin
      //Omitimos los recibos compensados
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_RECIBO_COMPENSADO), NewNull, dboEqual);

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

    with Result.DataTable.DynamicWhere do
    begin
      //No podrá compensarse recibos que estan cobrados
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteSITUACION), NewConstant(CTE_COBRADO, datString), dboNotEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

procedure TRecibosClienteController.CopiarDireccion(const ADireccionEnvio: IBizDireccionesContacto; ARecibo: IBizRecibosCliente);
var
  bEnEdicion : Boolean;
begin
  if not Assigned(ARecibo) then
    raise Exception.Create ('Recibo no asignado (CopiarDireccion)');

  if not Assigned(ADireccionEnvio) then
    raise Exception.Create ('No se ha indicado la dirección (CopiarDireccion)');

  if ARecibo.DataTable.Active then
    ARecibo.DataTable.Active := True;

  if ADireccionEnvio.DataTable.Active then
    ADireccionEnvio.DataTable.Active := True;

  bEnEdicion := (ARecibo.DataTable.State in dsEditModes);
  if not bEnEdicion then
    ARecibo.Edit;

  ShowHourglassCursor;
  ARecibo.Edit;
  try
    ARecibo.CALLE := ADireccionEnvio.CALLE;
    ARecibo.POBLACION := ADireccionEnvio.POBLACION;
    ARecibo.CODIGO_POSTAL := ADireccionEnvio.CODIGO_POSTAL;
    ARecibo.PROVINCIA := ADireccionEnvio.PROVINCIA;
    ARecibo.NIF_CIF := ADireccionEnvio.NIF_CIF;
    ARecibo.NOMBRE := ADireccionEnvio.NOMBRE;

    if not bEnEdicion then
      ARecibo.Post;
  finally
    HideHourglassCursor;
  end;
end;

constructor TRecibosClienteController.Create;
begin
  inherited;
  AsignarDataModule;
  FPagosController := TPagosClienteController.Create;
  FClienteController := TClientesController.Create;
//  FPagosController.addObservador(Self);   //PETA NO SE PORQUE
end;

function TRecibosClienteController.Buscar(const ID: Integer): IBizRecibosCliente;
begin
  Result := (FDataModule as IDataModuleRecibosCliente).GetItem(ID);
  FiltrarEmpresa(Result);  
end;

function TRecibosClienteController.BuscarRecibosFactura(const ID_FACTURA: Integer): IBizRecibosCliente;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // (ID = :ID)
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_FACTURA), NewConstant(ID_FACTURA, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TRecibosClienteController.BuscarRecibosARemesar(const AListaVisibles, AListaNoVisibles: TStringList): IBizRecibosCliente;
var
  Condicion: TDAWhereExpression;
  i: Integer;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      //No podrá compensarse un recibo ya compensado
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_RECIBO_COMPENSADO), NewNull(), dboEqual);

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

    with Result.DataTable.DynamicWhere do
    begin
      //Solo dejaremos remesar aquellos recibos que no esten cobrados (Pendientes/Devueltos)
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteSITUACION), NewConstant(CTE_COBRADO, datString), dboNotEqual);

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

    //En este caso vamos a quitar de la lista de recibos pendientes aquellos que ya hemos
    //añadido a la remesa pero que estan en memoria ya que todavia no se ha guarado en BD
    for i := 0 to AListaNoVisibles.Count - 1 do
      with Result.DataTable.DynamicWhere do
      begin
        //Solo dejaremos remesar aquellos recibos que no esten cobrados (Pendientes/Devueltos)
        Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID), NewConstant(AListaNoVisibles.Strings[i], datString), dboNotEqual);

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

      //En el caso contrario no hacemos nada, porque si se elimina un recibo de la remesa
      //y sin guardar los cambios damos a añadir el recibo todavia está cobrado y no se que efectos
      //secundarios puede provocar
      //AListaVisibles
    
  finally
    HideHourglassCursor;
  end;
end;

function TRecibosClienteController.BuscarRecibosContrato(const ID_CONTRATO: Integer): IBizRecibosCliente;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // Recibos no asociados a ninguna factura
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_FACTURA), NewNull(), dboEqual);

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

    with Result.DataTable.DynamicWhere do
    begin
      // Recibos asociados a un contrato
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_CONTRATO), NewConstant(ID_CONTRATO, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;

end;

function TRecibosClienteController.BuscarRecibosRemesa(const ID_REMESA: Integer): IBizRecibosCliente;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    // Filtrar los recibos de una remesa determinada
    with Result.DataTable.DynamicWhere do
    begin
      // (ID_REMESA >= ID)
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteID_REMESA), NewConstant(ID_REMESA, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TRecibosClienteController._Vacio: IBizRecibosCliente;
begin
  Result := Buscar(ID_NULO);
end;

function TRecibosClienteController.DarListaAnosRecibos: TStringList;
begin
  Result := FDataModule.GetAnosItems;
end;

function TRecibosClienteController.DarNuevaReferencia(ID_FACTURA: Integer; REFERENCIA: String): String;
var
  ARecibosCliente: IBizRecibosCliente;
  NumReferencia : Integer;
  Cadena : String;
begin
  try
    ARecibosCliente := BuscarRecibosFactura(ID_FACTURA);
    ARecibosCliente.DataTable.Active := True;
    NumReferencia := ARecibosCliente.DataTable.RecordCount;
    Cadena := Copy(REFERENCIA, 0, Pos('-', REFERENCIA));
    Result := Cadena + ' ' + IntToStr((NumReferencia + 1));
  finally
    ARecibosCliente := Nil;
  end;
end;

procedure TRecibosClienteController.DescartarCambios(ARecibosCliente: IBizRecibosCliente);
begin
  if not Assigned(ARecibosCliente) then
    raise Exception.Create ('IBizRecibosCliente no asignado');

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

    ARecibosCliente.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TRecibosClienteController.Destroy;
begin
  FDataModule := NIL;
  FPagosController := NIL;
  FClienteController := NIL;
  inherited;
end;


function TRecibosClienteController.Duplicar(ARecibosCliente: IBizRecibosCliente): IBizRecibosCliente;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(ARecibosCliente.DataTable, Result.DataTable, mdrActual);
    
    // Descomentar esto si hay detalles
    // (EN ESTE CASO NO NOS INTERESA COPIAR LOS PAGOS DEL RECIBO DUPLICADO)
    // DuplicarRegistros(ARecibosCliente.Detalles.DataTable, Result.Detalles.DataTable, mdrTodos);

    // ¡CUIDADO! Hay que dejar algunos campos como si fuera todo nuevo
    Result.Edit;
    with Result do
    begin
    	// Ejemplos
      // ID_EMPRESA := dmUsuarios.IDEmpresaActual;
      // USUARIO := dmUsuarios.LoginInfo.Usuario;
      // REFERENCIA := ''; //Para que se asigne una nueva
      // FECHA_FACTURA := DateOf(Now);
      // SITUACION := SITUACION_PENDIENTE;
    end;

    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;


function TRecibosClienteController.ValidarReciboCliente(ARecibosCliente: IBizRecibosCliente): Boolean;
var
  ImporteRestante: Double;

begin
  Result := False;

  if not Assigned(ARecibosCliente) then
    raise Exception.Create ('IBizRecibosCliente no asignado');

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

  // Tambien hacemos post de sus tablas hija
  if (ARecibosCliente.Pagos.DataTable.State in dsEditModes) then
      ARecibosCliente.Pagos.DataTable.Post;

  if ARecibosCliente.DataTable.FieldByName(fld_RecibosClienteFECHA_EMISION).IsNull then
     raise Exception.Create('Debe indicar la fecha de emisión del recibo.');

  if ARecibosCliente.DataTable.FieldByName(fld_RecibosClienteFECHA_VENCIMIENTO).IsNull then
     raise Exception.Create('Debe indicar la fecha de vencimiento del recibo.');

  { Asegurarse de valores en campos "automáticos" tanto
    en MODIFICACIÓN como en INSERCIÓN. }
  ARecibosCliente.Edit;
  try
    ARecibosCliente.USUARIO := AppFactuGES.UsuarioActivo.UserName;
    Result := True;
  finally
    ARecibosCliente.Post;
  end;

  Result := True;
end;

procedure TRecibosClienteController.Ver(ARecibosCliente: IBizRecibosCliente);
var
  AEditor : IEditorReciboCliente;
begin
  AEditor := NIL;

  RecuperarCliente(ARecibosCliente);
  CreateEditor('EditorReciboCliente', IEditorReciboCliente, AEditor);
  if Assigned(AEditor) then
    try
       AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
       AEditor.Recibo := ARecibosCliente;
       AEditor.ShowModal;
    finally
       AEditor.Release;
       AEditor := NIL;
    end;
end;

procedure TRecibosClienteController.VerTodos(ARecibosCliente: IBizRecibosCliente);
var
  AEditor : IEditorRecibosCliente;
begin
  AEditor := NIL;

  CreateEditor('EditorRecibosCliente', IEditorRecibosCliente, AEditor);
  if Assigned(AEditor) then
    with AEditor do
    begin
      Controller := Self; //OJO ORDEN MUY IMPORTANTE
      RecibosCliente := ARecibosCliente;
      MultiSelect := True;
      ShowEmbedded;
    end;
end;

function TRecibosClienteController.ElegirRecibos(ARecibos: IBizRecibosCliente; AMensaje: String; AMultiSelect: Boolean): IBizRecibosCliente;
var
  AEditor : IEditorElegirRecibosCliente;
begin
  Result := NIL;

  CreateEditor('EditorElegirRecibosCliente', IEditorElegirRecibosCliente, AEditor);
  if Assigned(AEditor) then
    try
      AEditor.Controller := Self;
      AEditor.RecibosCliente := ARecibos;
      AEditor.MultiSelect := AMultiSelect;
      AEditor.Mensaje := AMensaje;
      if IsPositiveResult(AEditor.ShowModal) then
        Result := AEditor.RecibosClienteSeleccionados;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

function TRecibosClienteController.ElegirRecibosCompensados(ARecibo: IBizRecibosCliente): Boolean;
var
  ARecibosACompensar: IBizRecibosCliente;
begin
  ARecibosACompensar := Self.ElegirRecibos(BuscarRecibosACompensar(ARecibo), 'Elija los recibos que desea compensar', True);

  if Assigned(ARecibosACompensar) then
  begin
     ShowHourglassCursor;
     try
      DuplicarRegistros(ARecibosACompensar.DataTable, ARecibo.RecibosCompensados.DataTable, mdrTodos, True, True, False);
      Result := True;
     finally
       HideHourglassCursor;
       ARecibosACompensar := Nil;
     end;
  end;
end;

function TRecibosClienteController.Eliminar(ARecibosCliente: IBizRecibosCliente; AllItems: Boolean = false): Boolean;
//En el caso de eliminar almenos un elemento del conjunto se devuelve true
var
  bEliminado: Boolean;

begin
  bEliminado := False;

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

  ShowHourglassCursor;
  try
    if not ARecibosCliente.DataTable.Active then
       ARecibosCliente.DataTable.Active := True;

    if (ARecibosCliente.State in dsEditModes) then
      ARecibosCliente.Cancel;

    //Siempre eliminaremos el seleccionado
    if EsEliminable(ARecibosCliente) then
    begin
      ARecibosCliente.Delete;
      bEliminado := True;
    end;

    //En el caso de querer eliminar todos los items del objeto ARecibosCliente
    if AllItems then
    begin
       with ARecibosCliente.DataTable do
       begin
         First;
         while not EOF do
         begin
           if EsEliminable(ARecibosCliente) then
           begin
              ARecibosCliente.Delete;
              bEliminado := True
           end
           else Next;
         end;
       end;
    end;

    if bEliminado then
    begin
       ARecibosCliente.DataTable.ApplyUpdates;
       Result := True;
    end
    else
       Result := False;

  finally
    HideHourglassCursor;
  end;
end;

function TRecibosClienteController.EliminarPago(ARecibosCliente: IBizRecibosCliente): Boolean;
begin
  Result := PagosController.Eliminar(ARecibosCliente.Pagos);
end;

function TRecibosClienteController.EliminarTodo(ARecibosCliente: IBizRecibosCliente): Boolean;
begin
  if Assigned(ARecibosCliente) then
  begin
    if not ARecibosCliente.DataTable.Active then
       ARecibosCliente.DataTable.Active := True;
    ARecibosCliente.DataTable.ClearRows;
    ARecibosCliente.DataTable.ApplyUpdates;
    Result := True;
  end;
end;

function TRecibosClienteController.EsEliminable(ARecibo: IBizRecibosCliente): Boolean;
begin
  if not Assigned(ARecibo) then
     raise Exception.Create ('Recibo no asignado: EsEliminable');

  Result := (ARecibo.SITUACION = CTE_PENDIENTE) AND (ARecibo.ID_FACTURA < 1);
end;

procedure TRecibosClienteController.RecuperarCliente(AReciboCliente: IBizRecibosCliente);
begin
  AReciboCliente._Cliente := (FClienteController.Buscar(AReciboCliente.ID_Cliente) as IBizCliente);
end;

function TRecibosClienteController.GetClienteController: IClientesController;
begin
  Result := FClienteController;
end;

function TRecibosClienteController.GetPagosController: IPagosClienteController;
begin
  Result := FPagosController;
end;

procedure TRecibosClienteController.SetClienteController(const Value: IClientesController);
begin
  FClienteController := Value;
end;

procedure TRecibosClienteController.SetPagosController(const Value: IPagosClienteController);
begin
  FPagosController := Value;
end;

procedure TRecibosClienteController.SetSituacionCobrados(ARecibos: IBizRecibosCliente; WithDeltas: Boolean);
begin
  if Assigned(ARecibos) then
  begin
    ARecibos.DataTable.DisableControls;
    try
      DesconectarTabla(ARecibos.DataTable);
      with ARecibos.DataTable do
      begin
        First;
        while not Eof do
        begin
          if not Editing then Edit;
          ARecibos.SITUACION := CTE_COBRADO;
          Post;
          Next;
        end;
        First;
      end;
    finally
      ConectarTabla(ARecibos.DataTable);
      ARecibos.DataTable.EnableControls;
    end;
  end;
end;

function TRecibosClienteController.ImporteTotalModificado(ARecibosCliente : IBizRecibosCliente; var ImporteRestante: Currency) : Boolean;
var
  HayCambio: TDADeltaChange;
begin
  Result := False;
  ImporteRestante := 0;
  HayCambio := ARecibosCliente.DataTable.Delta.FindChange(ARecibosCliente.RecNo);
  if  (Assigned(HayCambio)) and
    (HayCambio.OldValueByName[fld_RecibosClienteIMPORTE] <> 0) then
  begin
    ImporteRestante := HayCambio.OldValueByName[fld_RecibosClienteIMPORTE] - ARecibosCliente.IMPORTE;
    if ImporteRestante <> 0 then
      Result := True;
  end;
end;

function TRecibosClienteController.Guardar(ARecibosCliente: IBizRecibosCliente): Boolean;
var
  NuevoID : Integer;
  ANuevoReciboCliente : IBizRecibosCliente;
  ImporteRestante : Currency;
begin
  Result := False;

  if ARecibosCliente.EsNuevo then
  begin
    if ValidarReciboCliente(ARecibosCliente) then
    begin
    ShowHourglassCursor;
    try
      ARecibosCliente.DataTable.ApplyUpdates;
      Result := True;
    finally
      HideHourglassCursor;
    end;
    end;
  end
  else
  begin
    ANuevoReciboCliente := NIL;
    ImporteRestante := 0;

    if ValidarReciboCliente(ARecibosCliente) then
    begin
      ShowHourglassCursor;
      try
        //Si el recibo está asociado a una factura y el importe ha cambiado se debe hacer un recibo nuevo con el importe restante
        if (ARecibosCLiente.ID_FACTURA > 0) and (ImporteTotalModificado(ARecibosCliente, ImporteRestante)) then
        begin
          ANuevoReciboCliente := Duplicar(ARecibosCliente);
          ANuevoReciboCliente.Edit;
          ANuevoReciboCliente.REFERENCIA := DarNuevaReferencia(ARecibosCliente.ID_FACTURA, ARecibosCliente.REFERENCIA);
          ANuevoReciboCliente.IMPORTE := ImporteRestante;
          ANuevoReciboCliente.DESCRIPCION := 'RECIBO ' + ANuevoReciboCliente.REFERENCIA + ' - ' + CifraToLetras(ImporteRestante);
          ANuevoReciboCliente.Post;

          ARecibosCliente.Edit;
          ARecibosCliente.DESCRIPCION := 'RECIBO ' + ARecibosCliente.REFERENCIA + ' - ' + CifraToLetras(ARecibosCliente.IMPORTE);
          ARecibosCliente.Post;
        end;

        //Primero debemos hacer el ApplyUpdates del recibo inicial por si fallase
        //Así no se haría el nuevo
        ARecibosCliente.DataTable.ApplyUpdates;

        if Assigned(ANuevoReciboCliente) then
           ANuevoReciboCliente.DataTable.ApplyUpdates;

        Result := True;
      finally
        ANuevoReciboCliente := NIL;
        HideHourglassCursor;
      end;
    end;
  end;
end;

procedure TRecibosClienteController.ModificarPago(ARecibosCliente: IBizRecibosCliente; FechaPago: String =''; AIgnorarContabilidad : Integer = 1; AIdSubCuenta: Integer = 0; ASubCuenta: String = '');
begin
  if Length(FechaPago) > 0 then
     PagosController.Modificar(ARecibosCliente.Pagos, FechaPago, AIgnorarContabilidad, AIdSubCuenta, ASubCuenta);
end;

function TRecibosClienteController.Nuevo: IBizRecibosCliente;
var
  ARecibo : IBizRecibosCliente;
begin
  ARecibo := Buscar(ID_NULO);
  ARecibo.DataTable.Active := True;
  Anadir(ARecibo);
  Result := ARecibo;
end;

procedure TRecibosClienteController.QuitarReciboCompensado(ARecibo: IBizRecibosCliente);
var
  IdRecibo: Variant;
begin
  IdRecibo := ARecibo.RecibosCompensados.ID;

  ARecibo.RecibosCompensados.DataTable.First;
  while ARecibo.RecibosCompensados.DataTable.Locate('ID', IdRecibo,[]) do
  begin
    ARecibo.RecibosCompensados.DataTable.Delete;
    ARecibo.RecibosCompensados.DataTable.First;
  end;
end;

procedure TRecibosClienteController.QuitarRemesa(ARecibos: IBizRecibosCliente);
begin
  if Assigned(ARecibos) then
  begin
    if ARecibos.Pagos.DataTable.RecordCount = 0 then
       Exit;

    //Eliminamos el cobro generado por la remesa y quitamos el ID_REMESA del recibo
    ARecibos.Pagos.DataTable.Last;
    ARecibos.Pagos.Delete;

    ARecibos.DataTable.Edit;
    ARecibos.ID_REMESA := 0;
    ARecibos.DataTable.Post;
  end;
end;

function TRecibosClienteController.ExtraerSeleccionados(ARecibosCliente: IBizRecibosCliente): IBizRecibosCliente;
var
  ASeleccionados : IBizRecibosCliente;
begin
  ASeleccionados := (Self.Buscar(ID_NULO) as IBizRecibosCliente);
  CopyDataTableDA5(ARecibosCliente.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TRecibosClienteController.FiltrarAno(ARecibo: IBizRecibosCliente; ADynWhereDataTable: WideString; const Ano: String);
var
  Condicion: TDAWhereExpression;
  FechaIni: String;
  FechaFin: String;

begin
  ARecibo.DataTable.DynamicWhere.Clear;
  ARecibo.DataTable.DynamicWhere.Xml := ADynWhereDataTable;

  if (Ano <> 'Todos') then
  begin
    // Filtrar las facturas actuales por empresa
    FechaIni := '01/01/' + Ano;
    FechaFin := '31/12/' + Ano;
    with ARecibo.DataTable.DynamicWhere do
    begin
      // (FECHA_INICIO between FECHA_FIN)
      Condicion := NewBinaryExpression(NewField('', fld_RecibosClienteFECHA_EMISION), NewConstant(FechaIni, datString), dboGreaterOrEqual);
      Condicion := NewBinaryExpression(NewBinaryExpression(NewField('', fld_RecibosClienteFECHA_EMISION), NewConstant(FechaFin, datString), dboLessOrEqual), Condicion, dboAnd);

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

procedure TRecibosClienteController.FiltrarEmpresa(ARecibo: IBizRecibosCliente);
var
  Condicion: TDAWhereExpression;
begin
  if ARecibo.DataTable.Active then
    ARecibo.DataTable.Active := False;

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

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

procedure TRecibosClienteController.Preview(ARecibosCliente: IBizRecibosCliente; AllItems: Boolean = false);

var
  AReportController : IRecibosClienteReportController;
  ID_Recibos: TIntegerList;

begin
  AReportController := TRecibosClienteReportController.Create;
  ID_Recibos := TIntegerList.Create;

  try
   //Si deseamos previsualizar todos los items del objeto albaran
   if AllItems then
   begin
     with ARecibosCliente.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Recibos.Add(ARecibosCliente.ID);
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Recibos.Add(ARecibosCliente.ID);

    AReportController.Preview(ID_Recibos);
  finally
    AReportController := NIL;
    FreeANDNil(ID_Recibos);
  end;
end;

procedure TRecibosClienteController.Print(ARecibosCliente: IBizRecibosCliente; AllItems: Boolean = false);
var
  AReportController : IRecibosClienteReportController;
  ID_Recibos: TIntegerList;

begin
  AReportController := TRecibosClienteReportController.Create;
  ID_Recibos := TIntegerList.Create;

  try
   //Si deseamos previsualizar todos los items del objeto albaran
   if AllItems then
   begin
     with ARecibosCliente.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Recibos.Add(ARecibosCliente.ID);
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Recibos.Add(ARecibosCliente.ID);

    AReportController.Print(ID_Recibos);
  finally
    AReportController := NIL;
    FreeANDNil(ID_Recibos);
  end;
end;

end.
