unit uAsientosController;

interface


uses
  Classes, SysUtils, uDADataTable, uControllerBase,
   uBizAsientos, uBizDiario, uIDataModuleContabilidad;
type
  IAsientosController = interface(IControllerBase)
  ['{94E5F2B6-64C8-4331-B9CB-3ED730478529}']
    function BuscarAsientos(IdSubCuenta: Integer = -1): IBizDiario;
    function Buscar(const ID: Integer): IBizAsiento;
    procedure VerDiario(ADiario: IBizDiario);
    procedure VerExtracto;
    procedure Ver(AAsiento: IBizAsiento);
    function Anadir: IBizAsiento; overload;
    function Anadir(IdSubcuenta:Integer): IBizAsiento; overload;
    function CerrarCajaBanco(IdSubcuenta:Integer): Boolean;
    function Eliminar(IDAsiento : Integer): Boolean; overload;
    function Eliminar(AAsiento : IBizAsiento): Boolean; overload;
    function Guardar(AAsiento : IBizAsiento): Boolean;
    procedure DescartarCambios(AAsiento : IBizAsiento);
  end;

  TAsientosController = class(TControllerBase, IAsientosController)
  protected
    FDataModule : IDataModuleContabilidad;

    procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override;
    function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean;

    function ValidarAsiento(AAsiento: IBizAsiento): Boolean;
    procedure AsignarDataModule;
    procedure FiltrarEjercicio(ADiario: IBizDiario);

  public
    constructor Create; override;
    destructor Destroy; override;

    function BuscarAsientos(IdSubCuenta: Integer = -1): IBizDiario;

    function Eliminar(IDAsiento : Integer): Boolean; overload;
    function Eliminar(AAsiento : IBizAsiento): Boolean; overload;
    function Guardar(AAsiento : IBizAsiento): Boolean; virtual;
    procedure DescartarCambios(AAsiento : IBizAsiento); virtual;
    function Anadir: IBizAsiento; overload;
    function Anadir(IdSubcuenta:Integer): IBizAsiento; overload;
    function CerrarCajaBanco(IdSubcuenta:Integer): Boolean;

    function Buscar(const ID: Integer): IBizAsiento;
    procedure VerDiario(ADiario: IBizDiario);
    procedure VerExtracto;
    procedure Ver(AAsiento: IBizAsiento);
  end;

implementation

uses
  cxControls, DB, uEditorRegistryUtils, schContabilidadClient_Intf,
  uIEditorDiario, uIEditorExtractoMovimientos, uIEditorAsiento,
  uDataModuleContabilidad, uDAInterfaces, uDataTableUtils, uDialogUtils,
  uFactuGES_App, uDateUtils, uROTypes, DateUtils, Controls, Windows,
  uApuntesController;

{ TAsientosController }

function TAsientosController.Anadir: IBizAsiento;
var
  AAsiento : IBizAsiento;
begin
  AAsiento := FDataModule.GetAsientoItem(ID_NULO);
  AAsiento.DataTable.Active := True;
  AAsiento.Insert;
  Result := AAsiento;
end;

function TAsientosController.Anadir(IdSubcuenta: Integer): IBizAsiento;
begin
  Result := Anadir;

  //Creamos el primer apunte del asiento con la cuenta pasada por parametro
  with TApuntesController.Create do
  try
    Anadir(Result.Apuntes, IdSubcuenta);
  finally
    Free;
  end;
end;

procedure TAsientosController.AsignarDataModule;
begin
  FDataModule := TDataModuleContabilidad.Create(Nil);
end;

function TAsientosController.Buscar(const ID: Integer): IBizAsiento;
begin
  Result := FDataModule.GetAsientoItem(ID);
end;

function TAsientosController.BuscarAsientos(IdSubCuenta: Integer = -1): IBizDiario;
var
  Condicion: TDAWhereExpression;

begin
  // En el caso de no definir cuenta lo que queremos es el diario
  if (IdSubcuenta < 0) then
     Result := FDataModule.GetAsientosDiarioItems
  // En el caso de querer solo los movimientos de una cuenta lo que queremos es un extracto de movimientos
  else
     Result := FDataModule.GetExtractoMovimientosItems;

  //Filtramos por empresa
  FiltrarEjercicio(Result);

  // Filtrar los asientos por la subcuenta elegida
  if (IdSubcuenta > 0) then
  begin
    if Result.DataTable.Active then
       Result.DataTable.Active := False;

    with Result.DataTable.DynamicWhere do
    begin
        // (ID_SUBCUENTA = IdSubcuenta)
        Condicion := NewBinaryExpression(NewField('', fld_DiarioID_SUBCUENTA), NewConstant(IdSubCuenta, datInteger), dboEqual);

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

function TAsientosController.CerrarCajaBanco(IdSubcuenta: Integer): Boolean;
var
  AAsiento: IBizAsiento;
begin
  AAsiento:= Anadir(IdSubCuenta);
  try
    AAsiento.TIPO := 'X'; //CIERRE DE CAJA
    AAsiento.Post;

    //Creamos el primer apunte del asiento con la cuenta pasada por parametro
    with TApuntesController.Create do
    try
      AnadirCierre(AAsiento.Apuntes);
    finally
      Free;
    end;

    Guardar(AAsiento);
    Result := True;

  finally
    AAsiento := Nil;
  end;
end;

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

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

procedure TAsientosController.DescartarCambios(AAsiento: IBizAsiento);
begin
  if not Assigned(AAsiento) then
    raise Exception.Create ('Asiento no asignado');

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

    AAsiento.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

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

function TAsientosController.Eliminar(IDAsiento: Integer): Boolean;
var
  AAsiento : IBizAsiento;
begin
  AAsiento := Buscar(IDAsiento);
  AAsiento.DataTable.Active := True;
  
  if not Assigned(AAsiento) then
    raise Exception.Create(Format('No se ha encontrado el asiento con ID = %d', [IDAsiento]));

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

function TAsientosController.ValidarAsiento(AAsiento: IBizAsiento): Boolean;
begin
  Result := False;
  
  if not Assigned(AAsiento) then
    raise Exception.Create ('Asiento no asignado');

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

  if AAsiento.FECHA_ASIENTOIsNull then
     raise Exception.Create('Debe indicar una fecha para este Asiento.');

//  if AAsiento.ORDENIsNull then
//     raise Exception.Create('Debe indicar un número de orden para este Asiento.');

  //Tambien validamos los detalles del asiento
  with TApuntesController.Create do
  begin
    ValidarApunte(AAsiento.Apuntes);
    Free;
  end;

//  if Length(AAsiento.CONCEPTO) = 0 then
//    raise Exception.Create('Debe indicar un concepto para este Asiento.');

  Result := True;
end;

procedure TAsientosController.Ver(AAsiento: IBizAsiento);
var
  AEditor : IEditorAsiento;
begin
  AEditor := NIL;

  CreateEditor('EditorAsiento', IEditorAsiento, AEditor);
  if Assigned(AEditor) then
    try
      AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
      AEditor.Asiento := AAsiento;
      AEditor.ShowModal;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

procedure TAsientosController.VerDiario(ADiario: IBizDiario);
var
  AEditor : IEditorDiario;
begin
  AEditor := NIL;

  CreateEditor('EditorDiario', IEditorDiario, AEditor);
  if Assigned(AEditor) then
     with AEditor do
     begin
       Controller := Self; //OJO ORDEN MUY IMPORTANTE
       Diario := ADiario;
       ShowEmbedded;
     end;
end;

procedure TAsientosController.VerExtracto;
var
  AEditor : IEditorExtractoMovimientos;
begin
  AEditor := NIL;

  CreateEditor('EditorExtractoMovimientos', IEditorExtractoMovimientos, AEditor);
  if Assigned(AEditor) then
     with AEditor do
     begin
       Controller := Self; //OJO ORDEN MUY IMPORTANTE
       //En este caso el objeto de negocio recae sobre la vista
       ShowEmbedded;
     end;
end;

function TAsientosController.Eliminar(AAsiento: IBizAsiento): Boolean;
begin
  if not Assigned(AAsiento) then
    raise Exception.Create ('Asiento no asignado');

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

    AAsiento.Delete;
    AAsiento.DataTable.ApplyUpdates;
    HideHourglassCursor;
    Result := True;
  finally
    HideHourglassCursor;
  end;
end;

procedure TAsientosController.FiltrarEjercicio(ADiario: IBizDiario);
var
  Condicion: TDAWhereExpression;
begin
  if ADiario.DataTable.Active then
     ADiario.DataTable.Active := False;

  if not Assigned(AppFactuGES.EjercicioActivo) then
    raise Exception.Create('No se ha definido ningún ejercicio activo');

  // Filtrar los asientos por la empresa activa
  with ADiario.DataTable.DynamicWhere do
  begin
    // (ID_EJERCICIO = ID)
    Condicion := NewBinaryExpression(NewField('', fld_DiarioID_EJERCICIO), NewConstant(AppFactuGES.EjercicioActivo.ID, datInteger), dboEqual);

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

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

function TAsientosController.Guardar(AAsiento: IBizAsiento): Boolean;
begin
  Result := False;

  if not Assigned(AAsiento) then
    raise Exception.Create ('Factura no asignada');

  if ValidarAsiento(AAsiento) then
  begin
    ShowHourglassCursor;

    // Asegurarnos de que todos los importes están bien.
//    RecalcularImportes(AFactura);

    try
      AAsiento.DataTable.ApplyUpdates;

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

end.
