unit uArticulosController;

interface


uses
  Classes, SysUtils, uDADataTable, uControllerBase, uEditorDBItem,
  uIDataModuleArticulos, uBizArticulos, uProveedoresController,
  uBizContactos;

type
  IArticulosController = interface(IControllerBase)
  ['{C7EA6486-7BE4-468E-A27A-621E1BA13430}']
    function Buscar(const ID: Integer; AClienteID: Integer = -1): IBizArticulo; overload;
    function BuscarInventariables: IBizArticulo;
    function BuscarTodos: IBizArticulo; overload;
    function BuscarTodosPorProveedor: IBizArticulo; overload;    
    function BuscarTodos(ACliente: IBizCliente): IBizArticulo; overload;
    function BuscarTodos(AProveedor: IBizProveedor): IBizArticulo; overload;
    function BuscarReferencia(const Ref: String; AClienteID: Integer): IBizArticulo;
    function BuscarReferenciaProveedor(const Ref: String; AClienteID: Integer): IBizArticulo;
    procedure Ver(AArticulo : IBizArticulo);
    procedure VerTodos;
    function Nuevo : IBizArticulo;
    procedure Anadir(AArticulo : IBizArticulo);
    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AArticulo : IBizArticulo): Boolean; overload;
    function Guardar(AArticulo : IBizArticulo): Boolean;
    procedure DescartarCambios(AArticulo : IBizArticulo);
    function Existe(const ID: Integer) : Boolean;
    function Duplicar(AArticulo: IBizArticulo): IBizArticulo;
    procedure Preview(AArticulo : IBizArticulo);
    procedure Print(AArticulo : IBizArticulo);

    procedure ElegirProveedor(AArticulo : IBizArticulo);
    procedure AnadirProveedor(AArticulo : IBizArticulo);
    procedure VerProveedor(AArticulo : IBizArticulo);
    function DarListaProveedoresConArticulos: TStringList;

    function ExtraerSeleccionados(AArticulos: IBizArticulo) : IBizArticulo;
    function ElegirArticulos(AArticulos : IBizArticulo; AMensaje: String; AMultiSelect: Boolean): IBizArticulo;
    procedure CalcularPrecioNeto(AArticulos: IBizArticulo);

    function GetProveedoresController: IProveedoresController;
    property ProveedoresController: IProveedoresController read GetProveedoresController;
    function DarPrecioPVPVenta(IdArticulo: Integer): TStringList;
  end;

  TArticulosController = class(TControllerBase, IArticulosController)
  protected
    FDataModule : IDataModuleArticulos;
    FProveedoresController: IProveedoresController;
    function GetProveedoresController: IProveedoresController;

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

    procedure FiltrarEmpresa(AArticulo: IBizArticulo);
    function ValidarArticulo(AArticulo: IBizArticulo): Boolean; virtual;

    procedure RecuperarObjetos(AArticulo: IBizArticulo); virtual;
    procedure AsignarDataModule; virtual;

  public
    property ProveedoresController: IProveedoresController read GetProveedoresController;

    constructor Create; override;
    destructor Destroy; override;

    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AArticulo : IBizArticulo): Boolean; overload;
    function Guardar(AArticulo : IBizArticulo): Boolean;
    procedure DescartarCambios(AArticulo : IBizArticulo); virtual;
    function Existe(const ID: Integer) : Boolean; virtual;
    procedure Anadir(AArticulo : IBizArticulo); virtual;
    function Buscar(const ID: Integer; AClienteID: Integer = -1): IBizArticulo; virtual;
    function BuscarTodos: IBizArticulo; overload;
    function BuscarTodosPorProveedor: IBizArticulo; overload;
    function BuscarInventariables: IBizArticulo;
    function BuscarTodos(ACliente: IBizCliente): IBizArticulo; overload;
    function BuscarTodos(ACliente: Integer): IBizArticulo; overload;
    function BuscarTodos(AProveedor: IBizProveedor): IBizArticulo; overload;
    function BuscarReferencia(const Ref: String; AClienteID: Integer = -1): IBizArticulo; virtual;
    function BuscarReferenciaProveedor(const Ref: String; AClienteID: Integer): IBizArticulo; virtual;
    function Nuevo : IBizArticulo; virtual;
    procedure Ver(AArticulo : IBizArticulo); virtual;
    procedure VerTodos; virtual;
    function Duplicar(AArticulo: IBizArticulo): IBizArticulo; virtual;
    procedure Preview(AArticulo : IBizArticulo); virtual;
    procedure Print(AArticulo : IBizArticulo); virtual;
    function ExtraerSeleccionados(AArticulos: IBizArticulo) : IBizArticulo; virtual;
    function ElegirArticulos(AArticulos : IBizArticulo; AMensaje: String; AMultiSelect: Boolean): IBizArticulo; virtual;
    procedure CalcularPrecioNeto(AArticulos: IBizArticulo);

    procedure ElegirProveedor(AArticulo : IBizArticulo);
    procedure AnadirProveedor(AArticulo : IBizArticulo);
    procedure VerProveedor(AArticulo : IBizArticulo);
    function DarListaProveedoresConArticulos: TStringList;
    function DarPrecioPVPVenta(IdArticulo: Integer): TStringList;
  end;

implementation

uses
  cxControls, DB, uEditorRegistryUtils, schArticulosClient_Intf, uFactuGES_App,
  uIEditorArticulos, uIEditorArticulo, uIEditorElegirArticulos,
  uDataModuleArticulos, uDataModuleUsuarios, uDAInterfaces, Dialogs,
  uDataTableUtils, uDateUtils, uROTypes, DateUtils, Controls, Windows;

{ TArticulosController }

procedure TArticulosController.Anadir(AArticulo: IBizArticulo);
begin
  AArticulo.Insert;
end;

procedure TArticulosController.AnadirProveedor(AArticulo: IBizArticulo);
var
  AProveedor : IBizContacto;
begin
  inherited;
{  AProveedor := (FProveedoresController.Nuevo as IBizProveedor);
  FProveedoresController.Ver(AProveedor);
  if Assigned(AProveedor) then
  begin
     if not AArticulo.DataTable.Editing then
        AArticulo.Edit;
     AArticulo.ID_PROVEEDOR := AProveedor.ID;
     AArticulo.NOMBRE_PROVEEDOR := AProveedor.NOMBRE;
  end;
  AProveedor := Nil;
}  
end;

procedure TArticulosController.AsignarDataModule;
begin
  FDataModule := TDataModuleArticulos.Create(Nil);
  FProveedoresController := TProveedoresController.Create;  
end;

function TArticulosController.Buscar(const ID: Integer; AClienteID: Integer = -1): IBizArticulo;
begin
//Quitamos la funcionalidad de poder dar una lista de articulos particular de los clientes
//  if (AClienteID = -1) then
    Result := (FDataModule as IDataModuleArticulos).GetItem(ID);
//  else
//    Result := (FDataModule as IDataModuleArticulos).GetItem(ID, AClienteID);

//Los articulos serán comunes para todas las empresas.
//  FiltrarEmpresa(Result);
end;

function TArticulosController.BuscarInventariables: IBizArticulo;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    // Filtrar los articulos inventariables
    with Result.DataTable.DynamicWhere do
    begin
      // (ID_EMPRESA >= ID)
      Condicion := NewBinaryExpression(NewField('', fld_ArticulosINVENTARIABLE), NewConstant(1, datInteger), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TArticulosController.BuscarReferencia(const Ref: String; AClienteID: Integer = -1): IBizArticulo;
{var
  Condicion: TDAWhereExpression;}
begin
  ShowHourglassCursor;
  try
//En tecsitel se desactiva el sacar una lista de articulos personalizada por cliente
//    if (AClienteID = -1)  then
       Result := BuscarTodos;
//    else
//       Result := BuscarTodos(AClienteID);

    // Filtrar por referencia, se cambia por el where anterior porque luego no nos reconoce bien la cadena, al contener UPPER
    with Result.DataTable.Where do
    begin
      AddText(Format('UPPER(%s) = ''%s''', [fld_ArticulosREFERENCIA, UpperCase(Ref)]));
    end;


    {    with Result.DataTable.DynamicWhere do
    begin
      // (REFERENCIA >= Ref)
      Condicion := NewBinaryExpression(NewField('', fld_ArticulosREFERENCIA), NewConstant(UpperCase(Ref), datString), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TArticulosController.BuscarReferenciaProveedor(const Ref: String; AClienteID: Integer): IBizArticulo;
{var
  Condicion: TDAWhereExpression;}
begin
  ShowHourglassCursor;
  try
//En tecsitel se desactiva el sacar una lista de articulos personalizada por cliente
//    if (AClienteID = -1)  then
       Result := BuscarTodosPorProveedor;
//    else
//       Result := BuscarTodos(AClienteID);

    // Filtrar por referencia, se cambia por el where anterior porque luego no nos reconoce bien la cadena, al contener UPPER
    with Result.DataTable.Where do
    begin
      AddText(Format('UPPER(%s) = ''%s''', [fld_ArticulosREFERENCIA_PROV, UpperCase(Ref)]));
    end;

    {with Result.DataTable.DynamicWhere do
    begin
      // (REFERENCIA >= Ref)
      Condicion := NewBinaryExpression(NewField('', fld_ArticulosREFERENCIA_PROV), NewConstant(UpperCase(Ref), datString), dboEqual);

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

  finally
    HideHourglassCursor;
  end;
end;

function TArticulosController.BuscarTodos(ACliente: Integer): IBizArticulo;
begin
  Result := FDataModule.GetItems(txArticulo); //ACliente);
//Los articulos serán comunes para todas las empresas.
//  FiltrarEmpresa(Result);
end;

function TArticulosController.BuscarTodos(ACliente: IBizCliente): IBizArticulo;
begin
//En tecsitel se desactiva el sacar una lista de articulos personalizada por cliente
//  if not Assigned(ACliente) then
//     raise Exception.Create('Falta ACliente: BuscarTodos');

  Result := BuscarTodos; //(ACliente.ID);
end;

function TArticulosController.BuscarTodos(AProveedor: IBizProveedor): IBizArticulo;
var
  Condicion: TDAWhereExpression;
begin
  if Assigned(AProveedor) then
  begin
    ShowHourglassCursor;
    try
      Result := BuscarTodosPorProveedor;

      // Filtrar los articulos del proveedor
      with Result.DataTable.DynamicWhere do
      begin
        // (ID_PROVEEDOR = ID)
        Condicion := NewBinaryExpression(NewField('', fld_ArticulosParaCompraID_PROVEEDOR), NewConstant(AProveedor.ID, datInteger), dboEqual);

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

function TArticulosController.BuscarTodosPorProveedor: IBizArticulo;
begin
  Result := FDataModule.GetItems(txProveedor);
//Los articulos serán comunes para todas las empresas.  
//  FiltrarEmpresa(Result);
end;

function TArticulosController.BuscarTodos: IBizArticulo;
begin
  Result := FDataModule.GetItems(txArticulo);
//Los articulos serán comunes para todas las empresas.
//  FiltrarEmpresa(Result);
end;

procedure TArticulosController.CalcularPrecioNeto(AArticulos: IBizArticulo);
var
  lPrecioNeto: Double;
begin
{
  if Assigned(AArticulos) then
  begin
    with AArticulos do
    begin
      try
        ShowHourglassCursor;
        DataTable.DisableControls;
        if not DataTable.Active then
           DataTable.Active := True;
        //Calcular precio neto
        lPrecioNeto := PRECIO_COSTE - ((PRECIO_COSTE * DESCUENTO)/100);
        if (PRECIO_NETO <> lPrecioNeto) then
        begin
          if not DataTable.Editing then
             DataTable.Edit;
          PRECIO_NETO := lPrecioNeto;
        end;
      finally
        DataTable.EnableControls;
        HideHourglassCursor;
      end;
    end;
  end;
}  
end;

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

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

function TArticulosController.DarListaProveedoresConArticulos: TStringList;
begin
  Result := (FDataModule as IDataModuleArticulos).DarListaProveedoresConArticulos(AppFactuGES.EmpresaActiva.ID);
end;

function TArticulosController.DarPrecioPVPVenta(IdArticulo: Integer): TStringList;
var
  AArticulo: IBizArticulo;
begin
  AArticulo := Buscar(IdArticulo);
  AArticulo.DataTable.Active := True;
  Result := TStringList.Create;
  try
    with Result do
    begin
      Add(CurrToStr(AArticulo.PRECIO_PVP_TOTAL));
      Add(CurrToStr(AArticulo.PRECIO_PVP_VENTA));
    end;
  finally
    AArticulo := NIL;
  end;
end;

procedure TArticulosController.DescartarCambios(AArticulo: IBizArticulo);
begin
  if not Assigned(AArticulo) then
    raise Exception.Create ('Articulo no asignado');

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

    AArticulo.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TArticulosController.Destroy;
begin
  FDataModule := Nil;
  FProveedoresController := Nil;  
  inherited;
end;

function TArticulosController.Duplicar(AArticulo: IBizArticulo): IBizArticulo;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(AArticulo.DataTable, Result.DataTable, mdrActual);

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

    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;

function TArticulosController.ValidarArticulo(AArticulo: IBizArticulo): Boolean;
begin
  Result := False;

  if not Assigned(AArticulo) then
    raise Exception.Create ('Artículo no asignado');

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

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

  if Length(AArticulo.DESCRIPCION) = 0 then
    raise Exception.Create('Debe indicar al menos la descripción de este artículo.');

  // Asegurarse de valores en campos "automáticos"
  AArticulo.Edit;
  try
	  AArticulo.USUARIO := AppFactuGES.UsuarioActivo.UserName;
    Result := True;
  finally
    AArticulo.Post;
  end;
end;

procedure TArticulosController.Ver(AArticulo: IBizArticulo);
var
  AEditor : IEditorArticulo;
begin
  AEditor := NIL;

  RecuperarObjetos(AArticulo);

  CreateEditor('EditorArticulo', IEditorArticulo, AEditor);
  if Assigned(AEditor) then
    try
      AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
      AEditor.Articulo := AArticulo;
      AEditor.ShowModal;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

procedure TArticulosController.VerProveedor(AArticulo: IBizArticulo);
var
  AProveedor : IBizContacto;
begin
{
  AProveedor := FProveedoresController.Buscar(AArticulo.ID_PROVEEDOR);
  FProveedoresController.Ver(AProveedor);
  if Assigned(AProveedor) then
  begin
     if not AArticulo.DataTable.Editing then
        AArticulo.Edit;
     AArticulo.ID_PROVEEDOR := AProveedor.ID;
     AArticulo.NOMBRE_PROVEEDOR := AProveedor.NOMBRE;
  end;
  AProveedor := Nil;
}  
end;

procedure TArticulosController.VerTodos;
var
  AEditor : IEditorArticulos;
begin
  AEditor := NIL;

  CreateEditor('EditorArticulos', IEditorArticulos, AEditor);
  if Assigned(AEditor) then
     with (AEditor as IEditorArticulos) do
     begin
        Controller := Self; //OJO ORDEN MUY IMPORTANTE
        ShowEmbedded;
     end;
end;

function TArticulosController._Vacio: IBizArticulo;
begin
  Result := Buscar(ID_NULO);
end;

function TArticulosController.Eliminar(const ID: Integer): Boolean;
var
  AArticulo : IBizArticulo;
begin
  AArticulo := Buscar(ID);

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

  AArticulo.DataTable.Active := True;    
  Result := Eliminar(AArticulo);
  AArticulo := NIL;
end;

function TArticulosController.ElegirArticulos(AArticulos: IBizArticulo; AMensaje: String; AMultiSelect: Boolean): IBizArticulo;
var
  AEditor : IEditorElegirArticulos;
begin
  Result := NIL;

  CreateEditor('EditorElegirArticulos', IEditorElegirArticulos, AEditor);
  if Assigned(AEditor) then
    try
       AEditor.Controller := Self;
       AEditor.Articulos := AArticulos;
       AEditor.MultiSelect := AMultiSelect;
       AEditor.Mensaje := AMensaje;
       if IsPositiveResult(AEditor.ShowModal) then
          Result := AEditor.ArticulosSeleccionados;
    finally
       AEditor.Release;
       AEditor := NIL;
    end;
end;

procedure TArticulosController.ElegirProveedor(AArticulo: IBizArticulo);
var
  AProveedor : IBizContacto;
begin
  inherited;
{
  AProveedor := (FProveedoresController.ElegirContacto(FProveedoresController.BuscarTodos, '', False) as IBizProveedor);
  if Assigned(AProveedor) then
  begin
     if not AArticulo.DataTable.Editing then
        AArticulo.Edit;
     AArticulo.ID_PROVEEDOR := AProveedor.ID;
     AArticulo.NOMBRE_PROVEEDOR := AProveedor.NOMBRE;
  end;
  AProveedor := Nil;
}  
end;

function TArticulosController.Eliminar(AArticulo: IBizArticulo): Boolean;
begin
  Result := False;

  if not Assigned(AArticulo) then
    raise Exception.Create ('Articulo no asignada');

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

    AArticulo.Delete;
    AArticulo.DataTable.ApplyUpdates;
    HideHourglassCursor;
    Result := True;
  except
    on E: Exception do
    begin
      AArticulo.DataTable.CancelUpdates;
      HideHourglassCursor;
      if (Pos('FOREIGN KEY', E.Message) > 0) then
         MessageBox(0, 'No se puede borrar este artículo porque tiene artículos', 'Atención', MB_ICONWARNING or MB_OK);
    end;
  end;
end;

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

procedure TArticulosController.RecuperarObjetos(AArticulo: IBizArticulo);
begin
  //
end;

function TArticulosController.Existe(const ID: Integer): Boolean;
var
  AArticulo : IBizArticulo;
begin
  try
    AArticulo := Buscar(ID);
    Result := Assigned(AArticulo) and (AArticulo.ID = ID);
  finally
    AArticulo := NIL;
  end;
end;

function TArticulosController.ExtraerSeleccionados(AArticulos: IBizArticulo): IBizArticulo;
var
  ASeleccionados : IBizArticulo;
begin
  ASeleccionados := (Self.Buscar(ID_NULO) as IBizArticulo);
  CopyDataTableDA5(AArticulos.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TArticulosController.FiltrarEmpresa(AArticulo: IBizArticulo);
var
  Condicion: TDAWhereExpression;
begin
  if AArticulo.DataTable.Active then
    AArticulo.DataTable.Active := False;

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

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

function TArticulosController.GetProveedoresController: IProveedoresController;
begin
  Result := FProveedoresController;
end;

function TArticulosController.Guardar(AArticulo: IBizArticulo): Boolean;
begin
  Result := False;

  if ValidarArticulo(AArticulo) then
  begin
    ShowHourglassCursor;
    try
      //Para que no salten los eventos de calculo de PVP que daría un pete importante
      AArticulo.DataTable.DisableControls;
      AArticulo.Proveedores.DataTable.DisableControls;
      AArticulo.DataTable.DisableEventHandlers;
      AArticulo.Proveedores.DataTable.DisableEventHandlers;

      AArticulo.DataTable.ApplyUpdates;

      Result := True;
    finally
      //Para que no salten los eventos de calculo de PVP que daría un pete importante
      AArticulo.DataTable.EnableControls;
      AArticulo.DataTable.EnableEventHandlers;
      AArticulo.Proveedores.Datatable.EnableControls;
      AArticulo.Proveedores.Datatable.EnableEventHandlers;

      HideHourglassCursor;
    end;
  end;
end;

function TArticulosController.Nuevo: IBizArticulo;
var
  AArticulo : IBizArticulo;
begin
  AArticulo := FDataModule.NewItem;
//Los articulos serán comunes para todas las empresas.  
//  FiltrarEmpresa(AArticulo);
  AArticulo.DataTable.Active := True;
  AArticulo.Insert;
  Result := AArticulo;
end;

procedure TArticulosController.Preview(AArticulo: IBizArticulo);
//var
//  AReportController : IArticulosReportController;
begin
{  AReportController := TArticulosReportController.Create;
  try
    AReportController.Preview(AArticulo.ID);
  finally
    AReportController := NIL;
  end;
}
end;

procedure TArticulosController.Print(AArticulo: IBizArticulo);
//var
//  AReportController : IArticulosReportController;
begin
{  AReportController := TArticulosReportController.Create;
  try
    AReportController.Print(AArticulo.ID);
  finally
    AReportController := NIL;
  end;
}
end;

end.
