unit uSubCuentasController;

interface


uses
  Classes, SysUtils, uDADataTable, uControllerBase,
  uBizSubCuentas, uBizSubCuentasContacto, uIDataModuleContabilidad;

const
  // (REF_CUENTA = 430 SOLO CUENTAS DE CLIENTES)
  // (REF_CUENTA = 400 SOLO CUENTAS DE PROVEEDORES)
  // (REF_CUENTA = 570 SOLO CUENTAS DE CAJA)
  // (REF_CUENTA = 572 SOLO CUENTAS DE BANCO)

  CTE_CUENTASCLIENTE = 430;
  CTE_CUENTASPROVEEDOR = 400;
  CTE_CUENTASCAJA = 570;
  CTE_CUENTASBANCO = 572;
  CTE_CUENTASVENTA = 7;
  CTE_CUENTASCOMPRA = 6;

type
  TEnumTipoSubCuenta = (tTodas, tClientes, tProveedores, tCompras, tVentas, tCajas);

  ISubCuentasController = interface(IControllerBase)
  ['{94E5F2B6-64C8-4331-B9CB-3ED730478529}']
    function BuscarTodos: IBizSubCuenta;
    function Buscar(ID: Integer): IBizSubCuenta;
    procedure VerTodos(ASubCuentas: IBizSubCuenta);
    procedure Ver(ASubCuenta: IBizSubCuenta);
    procedure Anadir(ASubCuenta : IBizSubCuenta);
    function Nuevo : IBizSubCuenta;
    function Eliminar(ASubCuenta : IBizSubCuenta): Boolean;
    function Guardar(ASubCuenta : IBizSubCuenta): Boolean;
    procedure DescartarCambios(ASubCuenta : IBizSubCuenta);
    function Localizar(ASubCuentas: IBizSubCuenta; ADescripcion:String): Boolean;

    function ExtraerSeleccionados(ASubCuentas: IBizSubCuenta) : IBizSubCuenta;
    function ElegirSubCuenta(ASubCuentas : IBizSubCuenta; AMensaje: String; AMultiSelect: Boolean): IBizSubCuenta;
    procedure ElegirCuenta(ASubCuenta: IBizSubCuenta);

    procedure ElegirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
    procedure VerSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);
    procedure AnadirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
    procedure EliminarSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);

    function DarLista(Const TipoSubCuenta: TEnumTipoSubCuenta): TStringList;
    function Duplicar(ASubCuenta: IBizSubCuenta): IBizSubCuenta;    
  end;

  TSubCuentasController = class(TControllerBase, ISubCuentasController)
  private
    function BuscarCuentas(const REF_CUENTA: Integer): IBizSubCuenta;
    function BuscarCuentasLibres(TipoCuenta: Integer): IBizSubCuenta;
    procedure AsignarSubCuentaAContacto(ASubCuenta: IBizSubCuenta; ASubCuentaContacto: IBizSubCuentasContacto);

  protected
    FDataModule : IDataModuleContabilidad;

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

    function ValidarSubCuenta(ASubCuenta: IBizSubCuenta): Boolean;
    procedure AsignarDataModule;
    procedure FiltrarEjercicio(ASubCuenta: IBizSubCuenta);
    function _Vacio : IBizSubCuenta; virtual;

  public
    constructor Create; override;
    destructor Destroy; override;

    function EsModificable(ASubCuenta : IBizSubCuenta): Boolean;
    function EsEliminable(ASubCuenta : IBizSubCuenta): Boolean;

    function Eliminar(ASubCuenta : IBizSubCuenta): Boolean;
    function Guardar(ASubCuenta : IBizSubCuenta): Boolean; virtual;
    procedure DescartarCambios(ASubCuenta : IBizSubCuenta); virtual;
    procedure Anadir(ASubCuenta : IBizSubCuenta);
    function Nuevo : IBizSubCuenta;
    function BuscarTodos: IBizSubCuenta;
    function BuscarCajasBancos: IBizSubCuenta;
    function BuscarVentas: IBizSubCuenta;
    function BuscarCompras: IBizSubCuenta;
    function Buscar(ID: Integer): IBizSubCuenta;
    procedure VerTodos(ASubCuentas: IBizSubCuenta);
    procedure Ver(ASubCuenta: IBizSubCuenta);
    function Localizar(ASubCuentas: IBizSubCuenta; ADescripcion:String): Boolean;

    function ExtraerSeleccionados(ASubCuentas: IBizSubCuenta) : IBizSubCuenta;
    function ElegirSubCuenta(ASubCuentas : IBizSubCuenta; AMensaje: String; AMultiSelect: Boolean): IBizSubCuenta;
    procedure ElegirCuenta(ASubCuenta: IBizSubCuenta);

    procedure ElegirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
    procedure VerSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);
    procedure AnadirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
    procedure EliminarSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);

    function DarLista(Const TipoSubCuenta: TEnumTipoSubCuenta): TStringList;
    function Duplicar(ASubCuenta: IBizSubCuenta): IBizSubCuenta;
  end;

implementation

uses
  cxControls, DB, uEditorRegistryUtils, schContabilidadClient_Intf, uBizEjercicios,
  uIEditorSubCuentas, uIEditorSubCuenta, uIEditorElegirSubCuentas, uDataModuleContabilidad,
  uBizCuentas, uCuentasController, Dialogs, Variants,
  uDAInterfaces, uDataTableUtils, uDialogUtils, uFactuGES_App,
  uDateUtils, uROTypes, DateUtils, Controls, Windows;

{ TSubCuentasController }

procedure TSubCuentasController.Anadir(ASubCuenta: IBizSubCuenta);
begin
  ASubCuenta.Insert;
end;

procedure TSubCuentasController.AnadirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
var
  ASubCuenta: IBizSubCuenta;
begin
  ASubCuenta := Nuevo;
  Ver(ASubCuenta);
  if not ASubCuenta.IsEmpty then
     AsignarSubCuentaAContacto(ASubCuenta, ASubCuentaContacto);
end;

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

procedure TSubCuentasController.AsignarSubCuentaAContacto(ASubCuenta: IBizSubCuenta; ASubCuentaContacto: IBizSubCuentasContacto);
begin
  if Assigned(ASubCuenta) then
  begin
     EliminarSubCuentaContacto(ASubCuentaContacto);

     ASubCuentaContacto.Insert;
     ASubCuentaContacto.ID := ASubCuenta.ID;
     ASubCuentaContacto.REF_SUBCUENTA := ASubCuenta.REF_SUBCUENTA;
     ASubCuentaContacto.DESCRIPCION := ASubCuenta.DESCRIPCION;
     ASubCuentaContacto.post;
  end;
end;

function TSubCuentasController.Buscar(ID: Integer): IBizSubCuenta;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

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

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

  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.BuscarCajasBancos: IBizSubCuenta;
var
  Condicion: TDAWhereExpression;
  Condicion1: TDAWhereExpression;
  Condicion2: TDAWhereExpression;

begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // (REF_CUENTAS = 570 cajas)
      Condicion1 := NewBinaryExpression(NewField('', fld_SubCuentasREF_CUENTA), NewConstant(CTE_CUENTASCAJA, datInteger), dboEqual);
      // (REF_CUENTAS = 572 bancos)
      Condicion2 := NewBinaryExpression(NewField('', fld_SubCuentasREF_CUENTA), NewConstant(CTE_CUENTASBANCO, datInteger), dboEqual);
      Condicion := NewBinaryExpression(Condicion1, Condicion2, dboOr);

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

  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.BuscarCompras: IBizSubCuenta;
var
  Condicion: TDAWhereExpression;

begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // (REF_EPIGRAFE_PADRE = 6 compras)
      Condicion := NewBinaryExpression(NewField('', fld_SubCuentasREF_EPIGRAFE_PADRE), NewConstant(CTE_CUENTASCOMPRA, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.BuscarCuentas(const REF_CUENTA: Integer): IBizSubCuenta;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // (REF_CUENTA = 430 CLIENTES/400 PROVEEDORES/570 CAJAS/572 BANCOS)
      Condicion := NewBinaryExpression(NewField('', fld_SubCuentasREF_CUENTA), NewConstant(REF_CUENTA, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.BuscarCuentasLibres(TipoCuenta: Integer): IBizSubCuenta;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;//BuscarCuentas(TipoCuenta);

    with Result.DataTable.DynamicWhere do
    begin
      Condicion := NewBinaryExpression(NewField('', fld_SubCuentasID_CONTACTO), NewNull(), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.BuscarTodos: IBizSubCuenta;
begin
  Result := FDataModule.GetSubCuentaItems;
  FiltrarEjercicio(Result);
end;

function TSubCuentasController.BuscarVentas: IBizSubCuenta;
var
  Condicion: TDAWhereExpression;

begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // (REF_EPIGRAFE_PADRE = 7 ventas)
      Condicion := NewBinaryExpression(NewField('', fld_SubCuentasREF_EPIGRAFE_PADRE), NewConstant(CTE_CUENTASVENTA, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

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

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

function TSubCuentasController.DarLista(Const TipoSubCuenta: TEnumTipoSubCuenta): TStringList;
var
  ASubCuentas: IBizSubCuenta;
begin
  case TipoSubCuenta of
  // tClientes, tProveedores, tCompras, tVentas,
    tTodas : ASubCuentas := BuscarTodos;
    tCajas : ASubCuentas := BuscarCajasBancos;
    tVentas : ASubCuentas := BuscarVentas;
    tCompras : ASubCuentas := BuscarCompras;
  end;

  ASubCuentas.DataTable.Active := True;

  Result := TStringList.Create;
  try
    with Result do
    begin
      ASubCuentas.DataTable.First;
      while not ASubCuentas.DataTable.EOF do
      begin
        case TipoSubCuenta of
      // tClientes, tProveedores
        tTodas : Add(ASubCuentas.DESCRIPCION);
        tCajas, tCompras, tVentas : Add(Format('%s=%d', [ASubCuentas.DESCRIPCION, ASubCuentas.ID]));
        end;
        ASubCuentas.DataTable.Next;
      end;
    end;
  finally
    ASubCuentas := NIL;
  end;
end;


procedure TSubCuentasController.DescartarCambios(ASubCuenta: IBizSubCuenta);
begin
  if not Assigned(ASubCuenta) then
    raise Exception.Create ('SubCuenta no asignado');

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

    ASubCuenta.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

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

function TSubCuentasController.Duplicar(ASubCuenta: IBizSubCuenta): IBizSubCuenta;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(ASubCuenta.DataTable, Result.DataTable, mdrActual);
    // Hay que dejar algunos campos como si fuera una subcuenta nueva
    Result.Edit;
    with Result do
      Result.DataTable.FieldByName(fld_SubCuentasID_CONTACTO).AsVariant := Null;
    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.ValidarSubCuenta(ASubCuenta: IBizSubCuenta): Boolean;
begin
  Result := False;
  
  if not Assigned(ASubCuenta) then
    raise Exception.Create ('SubCuenta no asignado');

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

  if Length(ASubCuenta.REF_SUBCUENTA) = 0 then
    raise Exception.Create('Debe indicar una referencia para esta subcuenta.');

  if Length(ASubCuenta.DESCRIPCION) = 0 then
    raise Exception.Create('Debe indicar una descripcion para esta subcuenta.');

  Result := True;
end;

procedure TSubCuentasController.Ver(ASubCuenta: IBizSubCuenta);
var
  AEditor : IEditorSubCuenta;
begin
  AEditor := NIL;

  CreateEditor('EditorSubCuenta', IEditorSubCuenta, AEditor);
  if Assigned(AEditor) then
    try
       AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
       AEditor.SubCuenta := ASubCuenta;

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

       AEditor.ShowModal;

      //MODO CONSULTAR (Se deja la tabla como estaba)
      if AEditor.ReadOnly then
         SetDataTableReadOnly(ASubCuenta.DataTable, False);

    finally
       AEditor.Release;
       AEditor := NIL;
    end;
end;

procedure TSubCuentasController.VerSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);
var
  ASubCuenta: IBizSubCuenta;
begin
  if Assigned(ASubCuentaContacto) then
  begin
     ASubCuenta := Buscar(ASubCuentaContacto.ID);
     Ver(ASubCuenta);
  end;

  if Assigned(ASubCuenta) then
  begin
     if Assigned(ASubCuentaContacto)
     and (ASubCuentaContacto.DataTable.RecordCount > 0) then
         ASubCuentaContacto.DataTable.Delete;

     ASubCuentaContacto.Insert;
     ASubCuentaContacto.ID := ASubCuenta.ID;
     ASubCuentaContacto.REF_SUBCUENTA := ASubCuenta.REF_SUBCUENTA;
     ASubCuentaContacto.DESCRIPCION := ASubCuenta.DESCRIPCION;
     ASubCuentaContacto.post;
  end;

end;

procedure TSubCuentasController.VerTodos(ASubCuentas: IBizSubCuenta);
var
  AEditor : IEditorSubCuentas;
begin
  AEditor := NIL;

  CreateEditor('EditorSubCuentas', IEditorSubCuentas, AEditor);
  if Assigned(AEditor) then
     with AEditor do
     begin
       Controller := Self; //OJO ORDEN MUY IMPORTANTE
       SubCuentas := ASubCuentas;
       ShowEmbedded;
     end;
end;

function TSubCuentasController._Vacio: IBizSubCuenta;
begin
  Result := Buscar(ID_NULO);
end;

procedure TSubCuentasController.ElegirCuenta(ASubCuenta: IBizSubCuenta);
var
  ACuenta : IBizCuenta;
  AController : ICuentasController;
begin
  inherited;
  try
    AController := TCuentasController.Create;
    ACuenta := (AController.ElegirCuenta(AController.BuscarTodos, 'Debe elegir una cuenta asociada a la subcuenta', False) as IBizCuenta);

    if Assigned(ACuenta) then
    begin
      if Assigned(ASubCuenta) then
      begin
        if not ASubCuenta.DataTable.Editing then
           ASubCuenta.DataTable.Edit;

        ASubCuenta.ID_CUENTA := ACuenta.ID;
        ASubCuenta.CUENTA := ACuenta.DESCRIPCION;
        ASubCuenta.Post;
      end;
    end;
  finally
    AController := Nil;
    ACuenta := Nil;
  end;
end;

function TSubCuentasController.ElegirSubCuenta(ASubCuentas: IBizSubCuenta; AMensaje: String; AMultiSelect: Boolean): IBizSubCuenta;
var
  AEditor : IEditorElegirSubCuentas;
begin
  Result := NIL;

  CreateEditor('EditorElegirSubCuentas', IEditorElegirSubCuentas, AEditor);
  if Assigned(AEditor) then
    try
      AEditor.SubCuentas := ASubCuentas;
      AEditor.Controller := Self;
      AEditor.Mensaje := AMensaje;
      if IsPositiveResult(AEditor.ShowModal) then
        Result := AEditor.SubCuentasSeleccionados;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

procedure TSubCuentasController.ElegirSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto; TipoCuenta: Integer);
var
  ASubCuenta: IBizSubCuenta;
begin
  ASubCuenta := BuscarCuentasLibres(TipoCuenta);

  if (TipoCuenta = CTE_CUENTASCLIENTE) then
     ASubCuenta := ElegirSubCuenta(ASubCuenta, 'El cliente debe tener una subcuenta asociada', False)
  else
     ASubCuenta := ElegirSubCuenta(ASubCuenta, 'El proveedor debe tener una subcuenta asociada', False);

  AsignarSubCuentaAContacto(ASubCuenta, ASubCuentaContacto);
end;

function TSubCuentasController.Eliminar(ASubCuenta: IBizSubCuenta): Boolean;
begin
  if not Assigned(ASubCuenta) then
    raise Exception.Create ('SubCuenta no asignado');

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

    //Siempre eliminaremos el seleccionado
    if EsEliminable(ASubCuenta) then
    begin
      ASubCuenta.Delete;
      ASubCuenta.DataTable.ApplyUpdates;
    end;

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

procedure TSubCuentasController.EliminarSubCuentaContacto(ASubCuentaContacto: IBizSubCuentasContacto);
begin
  if Assigned(ASubCuentaContacto)
  and (not ASubCuentaContacto.DataTable.IsEmpty) then
      ASubCuentaContacto.DataTable.Delete;
end;

function TSubCuentasController.EsEliminable(ASubCuenta: IBizSubCuenta): Boolean;
begin
  if not Assigned(ASubCuenta) then
     raise Exception.Create ('SubCuenta no asignada: EsEliminable');

  Result := (ASubCuenta.ESTADO = CTE_ABIERTO);
end;

function TSubCuentasController.EsModificable(ASubCuenta: IBizSubCuenta): Boolean;
begin
  if not Assigned(ASubCuenta) then
     raise Exception.Create ('SubCuenta no asignada: EsModificable');

  Result := (ASubCuenta.ESTADO = CTE_ABIERTO);
end;

function TSubCuentasController.ExtraerSeleccionados(ASubCuentas: IBizSubCuenta): IBizSubCuenta;
var
  ASeleccionados : IBizSubCuenta;
begin
  ASeleccionados := Self.Buscar(ID_NULO);
  CopyDataTableDA5(ASubCuentas.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TSubCuentasController.FiltrarEjercicio(ASubCuenta: IBizSubCuenta);
var
  Condicion: TDAWhereExpression;
begin
  if ASubCuenta.DataTable.Active then
    ASubCuenta.DataTable.Active := False;

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

  // Filtrar los SubCuentas actuales por SubCuenta activo
  with ASubCuenta.DataTable.DynamicWhere do
  begin
    // (ID_Ejercicio = ID)
    Condicion := NewBinaryExpression(NewField('', fld_SubCuentasID_Ejercicio), NewConstant(AppFactuGES.EjercicioActivo.ID, datInteger), dboEqual);

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

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

function TSubCuentasController.Guardar(ASubCuenta: IBizSubCuenta): Boolean;
begin
  Result := False;

  if ValidarSubCuenta(ASubCuenta) then
  begin
    ShowHourglassCursor;
    try
      ASubCuenta.DataTable.ApplyUpdates;
      Result := True;
    finally
      HideHourglassCursor;
    end;
  end;
end;

function TSubCuentasController.Localizar(ASubCuentas: IBizSubCuenta; ADescripcion: String): Boolean;
begin
  Result := True;
  ShowHourglassCursor;
  try
    with ASubCuentas.DataTable do
    begin
      DisableControls;
      First;
      if not Locate(fld_SubCuentasDESCRIPCION, ADescripcion, []) then
         Result := False;
      EnableControls;   
    end;
  finally
    HideHourglassCursor;
  end;
end;

function TSubCuentasController.Nuevo: IBizSubCuenta;
var
  ASubCuenta : IBizSubCuenta;
begin
  ASubCuenta := FDataModule.NewSubCuentaItem;
  FiltrarEjercicio(ASubCuenta);
  ASubCuenta.DataTable.Active := True;
  ASubCuenta.Insert;
  Result := ASubCuenta;
end;

end.
