unit uRemesasProveedorController;

interface


uses
  Classes, SysUtils, uDADataTable, uControllerBase, uEditorDBItem,
  uIDataModuleRemesasProveedor, uBizRemesasProveedor, uProveedoresController,
  uBizContactos, uRecibosProveedorController;

type
  IRemesasProveedorController = interface(IControllerBase)
  ['{C14143FE-0806-4E64-93E2-A2C0170BBD41}']
    function Buscar(const ID: Integer): IBizRemesaProveedor;
    function BuscarTodos: IBizRemesaProveedor; overload;
    procedure Ver(ARemesaProveedor : IBizRemesaProveedor);
    procedure VerTodos(ARemesasProveedor: IBizRemesaProveedor);
    function Nuevo : IBizRemesaProveedor;
    procedure Anadir(ARemesaProveedor : IBizRemesaProveedor);
    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false): Boolean; overload;
    function Guardar(ARemesaProveedor : IBizRemesaProveedor; AIgnorarContabilidad : Integer = 1; ASubCuenta: Integer = 0): Boolean;
    procedure DescartarCambios(ARemesaProveedor : IBizRemesaProveedor);
    function Existe(const ID: Integer) : Boolean;

    procedure Preview(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false);
    procedure Print(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false);
    function EsModificable(ARemesaProveedor : IBizRemesaProveedor): Boolean;
    function EsEliminable(ARemesaProveedor : IBizRemesaProveedor): Boolean;

    function ElegirRecibosProveedor(ARemesaProveedor : IBizRemesaProveedor; AListaRecibosIniciales: TStringList): Boolean;
    procedure EliminarReciboProveedor(ARemesaProveedor : IBizRemesaProveedor);
    function GetRecibosProveedorController: IRecibosProveedorController;
    property RecibosProveedorController: IRecibosProveedorController read GetRecibosProveedorController;

    procedure RecuperarRecibos(ARemesaProveedor: IBizRemesaProveedor);
    function ExtraerSeleccionados(ARemesasProveedor: IBizRemesaProveedor) : IBizRemesaProveedor;
  end;

  TRemesasProveedorController = class(TControllerBase, IRemesasProveedorController)
  protected
    FDataModule : IDataModuleRemesasProveedor;
    FRecibosProveedorController: IRecibosProveedorController;
    function GetRecibosProveedorController: IRecibosProveedorController;

    procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override;
    procedure AsignarID(ARemesaProveedor: IBizRemesaProveedor; const IDNuevo: Integer); virtual;
    function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean;
    function _Vacio : IBizRemesaProveedor;

    procedure FiltrarEmpresa(ARemesaProveedor: IBizRemesaProveedor);
    function ValidarRemesaProveedor(ARemesaProveedor: IBizRemesaProveedor): Boolean; virtual;

    procedure RecuperarRecibos(ARemesaProveedor: IBizRemesaProveedor);
    procedure RecuperarObjetos(ARemesaProveedor: IBizRemesaProveedor); virtual;
    procedure AsignarDataModule; virtual;

  public
    property RecibosProveedorController: IRecibosProveedorController read GetRecibosProveedorController;

    constructor Create; override;
    destructor Destroy; override;

    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false): Boolean; overload;
    function Guardar(ARemesaProveedor : IBizRemesaProveedor; AIgnorarContabilidad : Integer = 1; ASubCuenta: Integer = 0): Boolean;
    procedure DescartarCambios(ARemesaProveedor : IBizRemesaProveedor); virtual;
    function Existe(const ID: Integer) : Boolean; virtual;
    procedure Anadir(ARemesaProveedor : IBizRemesaProveedor); virtual;
    function Buscar(const ID: Integer): IBizRemesaProveedor; virtual;
    function BuscarTodos: IBizRemesaProveedor; overload;
    function Nuevo : IBizRemesaProveedor; virtual;
    procedure Ver(ARemesaProveedor : IBizRemesaProveedor); virtual;
    procedure VerTodos(ARemesasProveedor: IBizRemesaProveedor); virtual;

    procedure Preview(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false); virtual;
    procedure Print(ARemesaProveedor : IBizRemesaProveedor; AllItems: Boolean = false); virtual;
    function EsModificable(ARemesaProveedor : IBizRemesaProveedor): Boolean;
    function EsEliminable(ARemesaProveedor : IBizRemesaProveedor): Boolean;

    function ExtraerSeleccionados(ARemesasProveedor: IBizRemesaProveedor) : IBizRemesaProveedor; virtual;
    function ElegirRecibosProveedor(ARemesaProveedor : IBizRemesaProveedor; AListaRecibosIniciales: TStringList): Boolean;
    procedure EliminarReciboProveedor(ARemesaProveedor : IBizRemesaProveedor);
  end;

implementation
{$INCLUDE ..\..\..\FactuGES.inc}

uses
  cxControls, DB, uEditorRegistryUtils, schRemesasProveedorClient_Intf, uFactuGES_App,
  schRecibosProveedorClient_Intf, uIEditorRemesasProveedor, uIEditorRemesaProveedor,
  Dialogs, uDataModuleRemesasProveedor, uDataModuleUsuarios, uDAInterfaces,
  uDataTableUtils, uDateUtils, uROTypes, DateUtils, Controls, Windows,
  uBizRecibosProveedor, Variants, uRemesasProveedorReportController;

{ TRemesasProveedorController }

procedure TRemesasProveedorController.Anadir(ARemesaProveedor: IBizRemesaProveedor);
begin
  ARemesaProveedor.Insert;
end;

procedure TRemesasProveedorController.EliminarReciboProveedor(ARemesaProveedor: IBizRemesaProveedor);
var
  ARecibosRemesa : IBizRecibosProveedor;
begin
  inherited;
  ARecibosRemesa := ARemesaProveedor.Recibos;
  RecibosProveedorController.QuitarRemesa(ARecibosRemesa);
  //Quitamos el recibo de la remesa sin que el servidor se entere para que no elimine el recibo
  DesconectarTabla(ARecibosRemesa.DataTable);
  ARecibosRemesa.DataTable.Delete;
  ConectarTabla(ARecibosRemesa.DataTable);
  ARecibosRemesa := Nil;
end;

function TRemesasProveedorController.EsEliminable(ARemesaProveedor: IBizRemesaProveedor): Boolean;
begin
  Result := True;
end;

function TRemesasProveedorController.EsModificable(ARemesaProveedor: IBizRemesaProveedor): Boolean;
begin
  Result := True;
end;

procedure TRemesasProveedorController.AsignarDataModule;
begin
  FDataModule := TDataModuleRemesasProveedor.Create(Nil);
  FRecibosProveedorController := TRecibosProveedorController.Create;
end;

procedure TRemesasProveedorController.AsignarID(ARemesaProveedor: IBizRemesaProveedor; const IDNuevo: Integer);
begin
  if not Assigned(ARemesaProveedor) then
    raise Exception.Create ('RemesaProveedor no asignado');

  ARemesaProveedor.Edit;
  ARemesaProveedor.ID := IDNuevo;
  ARemesaProveedor.Post;
end;

function TRemesasProveedorController.Buscar(const ID: Integer): IBizRemesaProveedor;
begin
  Result := (FDataModule as IDataModuleRemesasProveedor).GetItem(ID);
  FiltrarEmpresa(Result);
end;

function TRemesasProveedorController.BuscarTodos: IBizRemesaProveedor;
begin
  Result := FDataModule.GetItems;
  FiltrarEmpresa(Result);
end;

constructor TRemesasProveedorController.Create;
begin
  inherited;
  AsignarDataModule;
end;

function TRemesasProveedorController.CreateEditor(const AName: String;
  const IID: TGUID; out Intf): Boolean;
begin
  Result := Supports(EditorRegistry.CreateEditor(AName), IID, Intf);
end;

procedure TRemesasProveedorController.DescartarCambios(ARemesaProveedor: IBizRemesaProveedor);
begin
  if not Assigned(ARemesaProveedor) then
    raise Exception.Create ('RemesaProveedor no asignado');

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

    ARemesaProveedor.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TRemesasProveedorController.Destroy;
begin
  FDataModule := Nil;
  FRecibosProveedorController := Nil;  
  inherited;
end;

function TRemesasProveedorController.ValidarRemesaProveedor(ARemesaProveedor: IBizRemesaProveedor): Boolean;
begin
  Result := False;

  if not Assigned(ARemesaProveedor) then
    raise Exception.Create ('Remesa no asignada');

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

  if ARemesaProveedor.DataTable.FieldByName(fld_RemesasProveedorFECHA_REMESA).IsNull then
     raise Exception.Create('Debe indicar la fecha de esta remesa.');

  {$IFDEF CONTABILIDAD}
  {$ELSE}
    if ARemesaProveedor.ID_DATOS_BANCO < 1 then
       raise Exception.Create('Debe la cuenta bancaria sobre la que realizará la remesa.');
  {$ENDIF}

  // Asegurarse de valores en campos "automáticos"
  ARemesaProveedor.Edit;
  try
    ARemesaProveedor.USUARIO := AppFactuGES.UsuarioActivo.UserName;

    Result := True;
  finally
    ARemesaProveedor.Post;
  end;
end;

procedure TRemesasProveedorController.Ver(ARemesaProveedor: IBizRemesaProveedor);
var
  AEditor : IEditorRemesaProveedor;
begin
  AEditor := NIL;

  RecuperarObjetos(ARemesaProveedor);
  CreateEditor('EditorRemesaProveedor', IEditorRemesaProveedor, AEditor);
  if Assigned(AEditor) then
      try
        AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
        AEditor.RemesaProveedor := ARemesaProveedor;

        //MODO CONSULTAR
        if not EsModificable(ARemesaProveedor) then
        begin
           SetDataTableReadOnly(ARemesaProveedor.DataTable, True);
           AEditor.ReadOnly := True;
        end;

        AEditor.ShowModal;

        //MODO CONSULTAR (Se deja la tabla como estaba)
        if AEditor.ReadOnly then
           SetDataTableReadOnly(ARemesaProveedor.DataTable, False);
      finally
        AEditor.Release;
        AEditor := NIL;
      end;
end;

procedure TRemesasProveedorController.VerTodos(ARemesasProveedor: IBizRemesaProveedor);
var
  AEditor : IEditorRemesasProveedor;
begin
  AEditor := NIL;

  CreateEditor('EditorRemesasProveedor', IEditorRemesasProveedor, AEditor);
  if Assigned(AEditor) then
    with (AEditor as IEditorRemesasProveedor) do
    begin
      Controller := Self; //OJO ORDEN MUY IMPORTANTE
      RemesasProveedor := ARemesasProveedor;
      MultiSelect := True;
      ShowEmbedded;
    end;
end;

function TRemesasProveedorController._Vacio: IBizRemesaProveedor;
begin
  Result := Buscar(ID_NULO);
end;

function TRemesasProveedorController.Eliminar(const ID: Integer): Boolean;
var
  ARemesaProveedor : IBizRemesaProveedor;
begin
  ARemesaProveedor := Buscar(ID);

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

  Result := Eliminar(ARemesaProveedor);
  ARemesaProveedor := NIL;
end;

function TRemesasProveedorController.ElegirRecibosProveedor(ARemesaProveedor: IBizRemesaProveedor; AListaRecibosIniciales: TStringList): Boolean;
var
  ARecibosRemesa : IBizRecibosProveedor;
  ARecibosSeleccionados : IBizRecibosProveedor;
  ListaRecibosVisibles: TStringList;
  ListaRecibosNoVisibles: TStringList;
  i: Integer;

begin
  Result := False;


  ListaRecibosVisibles := TStringList.Create;
  ListaRecibosNoVisibles := TStringList.Create;

  //Todos los recibos que tenga la remesa no deben de visualizarse en la lista de seleccion
  ARemesaProveedor.Recibos.DataTable.First;
  while not ARemesaProveedor.Recibos.DataTable.eof do
  begin
    ListaRecibosNoVisibles.Add(IntToStr(ARemesaProveedor.Recibos.ID));
    ARemesaProveedor.Recibos.DataTable.Next;
  end;
  ARemesaProveedor.Recibos.DataTable.First;

  //Si de la lista inicial hay alguno que no se encuentre en la lista de recibos de la
  //remesa que tenemos en memoria dicho recibo debería verse por lo que lo añadimos a la lista de visibles
  for i := 0 to AListaRecibosIniciales.Count - 1 do
  begin
    ARemesaProveedor.Recibos.DataTable.First;
    if not ARemesaProveedor.Recibos.DataTable.Locate(fld_RecibosProveedorID, AListaRecibosIniciales.strings[i], []) then
       ListaRecibosVisibles.Add(AListaRecibosIniciales.strings[i]);
  end;
  ARemesaProveedor.Recibos.DataTable.First;

  ARecibosSeleccionados := (FRecibosProveedorController.ElegirRecibos(FRecibosProveedorController.BuscarRecibosARemesar(ListaRecibosVisibles, ListaRecibosNoVisibles), 'Elija uno o más recibos para incluirlos en esta remesa', True) as IBizRecibosProveedor);
  if Assigned(ARecibosSeleccionados) then
  begin
     ShowHourglassCursor;
     try
       ARecibosRemesa := ARemesaProveedor.Recibos;
       //Copia los recibos seleccionados a los recibos de la remesa sin que el servidor se entere de
       //las inserciones
       DuplicarRegistros(ARecibosSeleccionados.DataTable,ARecibosRemesa.DataTable, mdrTodos, False, False, True);
       FRecibosProveedorController.SetSituacionCobrados(ARecibosRemesa);
       Result := True;
     finally
       HideHourglassCursor;
     end;
  end;

  ListaRecibosVisibles.Free;
  ListaRecibosNoVisibles.Free;
  ARecibosRemesa := Nil;
  ARecibosSeleccionados := Nil;
end;

function TRemesasProveedorController.Eliminar(ARemesaProveedor: IBizRemesaProveedor; 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(ARemesaProveedor) then
    raise Exception.Create ('ARemesaProveedor no asignada');

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

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

    //Siempre eliminaremos el seleccionado
    if EsEliminable(ARemesaProveedor) then
    begin
      //Si la llamada a eliminar es por el editor RemesasProveedor, debo recuperar los recibos
      //de la remesa a eliminar, en caso de venir por el editor RemesaProveedor ya los tengo
      if not Assigned(ARemesaProveedor.Recibos) then
         RecuperarRecibos(ARemesaProveedor);
      //Eliminaremos la remesa de los recibos asociados
      With ARemesaProveedor.Recibos.DataTable do
      begin
        First;
        While not Eof do
        begin
          RecibosProveedorController.QuitarRemesa(ARemesaProveedor.Recibos);
          Next;
        end;
      end;

      //Como no están declarados como maestro-detalles debemos hacer el applyupdates nosotros
      ARemesaProveedor.Recibos.DataTable.ApplyUpdates;

      ARemesaProveedor.Delete;
      bEliminado := True;
    end;

    //En el caso de querer eliminar todos los items del objeto AAlbaran
    if AllItems then
    begin
       with ARemesaProveedor.DataTable do
       begin
         First;
         while not EOF do
         begin
           if EsEliminable(ARemesaProveedor) then
           begin
              //Si la llamada a eliminar es por el editor RemesasProveedor, debo recuperar los recibos
              //de la remesa a eliminar, en caso de venir por el editor RemesaProveedor ya los tengo
              if not Assigned(ARemesaProveedor.Recibos) then
                 RecuperarRecibos(ARemesaProveedor);
              //Eliminaremos la remesa de los recibos asociados
              With ARemesaProveedor.Recibos.DataTable do
              begin
                First;
                While not Eof do
                begin
                  RecibosProveedorController.QuitarRemesa(ARemesaProveedor.Recibos);
                  Next;
                end;
              end;

              //Como no están declarados como maestro-detalles debemos hacer el applyupdates nosotros
              ARemesaProveedor.Recibos.DataTable.ApplyUpdates;

              ARemesaProveedor.Delete;
              bEliminado := True
           end
           else Next;
         end;
       end;
    end;

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

    HideHourglassCursor;
  except
    //Hay algun recibo de la remesa que tiene movimientos (Cobros/Devoluciones) posteriores al cobro inicial de la remesa
    on E: Exception do
    begin
      ARemesaProveedor.Recibos.DataTable.CancelUpdates;
      ARemesaProveedor.DataTable.CancelUpdates;
      HideHourglassCursor;
      MessageBox(0, 'Exiten movimientos (Cobros/Devoluciones) en los recibos posteriores al cobro inicial de la remesa', 'Atención', MB_ICONWARNING or MB_OK);
    end;
  end;
end;

procedure TRemesasProveedorController.RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable);
begin
  inherited;
//
end;

procedure TRemesasProveedorController.RecuperarObjetos(ARemesaProveedor: IBizRemesaProveedor);
begin
  RecuperarRecibos(ARemesaProveedor);
end;

procedure TRemesasProveedorController.RecuperarRecibos(ARemesaProveedor: IBizRemesaProveedor);
begin
  ARemesaProveedor.Recibos := RecibosProveedorController.BuscarRecibosRemesa(ARemesaProveedor.ID);
end;

function TRemesasProveedorController.Existe(const ID: Integer): Boolean;
var
  ARemesaProveedor : IBizRemesaProveedor;
begin
  try
    ARemesaProveedor := Buscar(ID);
    Result := Assigned(ARemesaProveedor) and (ARemesaProveedor.ID = ID);
  finally
    ARemesaProveedor := NIL;
  end;
end;

function TRemesasProveedorController.ExtraerSeleccionados(ARemesasProveedor: IBizRemesaProveedor): IBizRemesaProveedor;
var
  ASeleccionados : IBizRemesaProveedor;
begin
  ASeleccionados := (Self.Buscar(ID_NULO) as IBizRemesaProveedor);
  CopyDataTableDA5(ARemesasProveedor.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TRemesasProveedorController.FiltrarEmpresa(ARemesaProveedor: IBizRemesaProveedor);
var
  Condicion: TDAWhereExpression;
begin
  if ARemesaProveedor.DataTable.Active then
    ARemesaProveedor.DataTable.Active := False;

  // Filtrar las remesas actuales por empresa
  with ARemesaProveedor.DataTable.DynamicWhere do
  begin
    // (ID_EMPRESA >= ID)
    Condicion := NewBinaryExpression(NewField('', fld_RemesasProveedorID_EMPRESA), NewConstant(AppFactuGES.EmpresaActiva.ID, datInteger), dboEqual);

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

function TRemesasProveedorController.GetRecibosProveedorController: IRecibosProveedorController;
begin
  Result := FRecibosProveedorController;
end;

function TRemesasProveedorController.Guardar(ARemesaProveedor: IBizRemesaProveedor; AIgnorarContabilidad : Integer = 1; ASubCuenta: Integer = 0): Boolean;
var
  bEsNuevo: Boolean;
begin
  Result := False;

  if ValidarRemesaProveedor(ARemesaProveedor) then
  begin
    ShowHourglassCursor;
    try
      bEsNuevo := ARemesaProveedor.EsNuevo;
      //Si es nuevo debemos hacer el applyupdates por la integridad referencial de BD
      if bEsNuevo then
         ARemesaProveedor.DataTable.ApplyUpdates;

      //Si todo ha ido bien, asignamos la remesa a los recibos asociados
      //Como no están declarados como maestro-detalles debemos hacer el applyupdates nosotros
      RecibosProveedorController.AsignarRemesa(ARemesaProveedor.Recibos, ARemesaProveedor.ID, AIgnorarContabilidad, ASubCuenta);
      ARemesaProveedor.Recibos.DataTable.ApplyUpdates; //En este applyupdates tambien se realizarán todos los cambios acumulados sobre los recibos asociados (EliminarReciboProveedor/ ElegirRecibosProveedor)

      //Es necesario ya que no se refrescan bien los deltas y despues del applyupdates siguen
      //existiendo deltas, de esta forma los limpiamos
      if ARemesaProveedor.Recibos.DataTable.HasDelta then
         ARemesaProveedor.Recibos.DataTable.Refresh;

      ARemesaProveedor.DataTable.ApplyUpdates;
      
      Result := True;
    finally
      HideHourglassCursor;
    end;
  end;
end;

function TRemesasProveedorController.Nuevo: IBizRemesaProveedor;
var
  ARemesaProveedor : IBizRemesaProveedor;
begin
  ARemesaProveedor := FDataModule.NewItem;
  FiltrarEmpresa(ARemesaProveedor);
  ARemesaProveedor.DataTable.Active := True;
  ARemesaProveedor.Insert;
  Result := ARemesaProveedor;
end;

procedure TRemesasProveedorController.Preview(ARemesaProveedor: IBizRemesaProveedor; AllItems: Boolean = false);
var
  AReportController : IRemesasProveedorReportController;
  ID_Remesas: TStringList;

begin
  AReportController := TRemesasProveedorReportController.Create;
  try
   ID_Remesas := TStringList.Create;

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

    AReportController.Preview(ID_Remesas.CommaText);

  finally
    AReportController := NIL;
    ID_Remesas.Free;
  end;
end;

procedure TRemesasProveedorController.Print(ARemesaProveedor: IBizRemesaProveedor; AllItems: Boolean = false);
var
  AReportController : IRemesasProveedorReportController;
  ID_Remesas: TStringList;

begin
  AReportController := TRemesasProveedorReportController.Create;
  try
   ID_Remesas := TStringList.Create;

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

    AReportController.Print(ID_Remesas.CommaText);

  finally
    AReportController := NIL;
    ID_Remesas.Free;
  end;
end;

end.
