unit uInventarioController;

interface


uses
  Classes, SysUtils, uDADataTable, uControllerBase, uEditorDBItem,
  uIDataModuleInventario, uBizInventario, uArticulosInventarioController,
  uAlmacenesController, uPresupuestosClienteController, uBizPresupuestosCliente,
  uPedidosProveedorController, uBizPedidosProveedor, uBizArticulos,
  uBizAlmacenes;

type
  IInventarioController = interface(IControllerBase)
  ['{FB1DE6BA-ADCC-4A83-B4D4-37DC5892766B}']


    function Eliminar(AInventario : IBizInventario; Todos: Boolean; ApplyUpdates: Boolean): Boolean;
    function Trasladar(AInventario : IBizInventario; Todos: Boolean): Boolean;
//    procedure RecibirArticulos(Const APedido: IBizPedidoProveedor; Const CodigoAlmacenDes: Integer); overload;
//    procedure RecibirPedidos(Const CodigoAlmacenDes: Integer);
    procedure Reservar(AInventario : IBizInventario);
    function Liberar(AInventario : IBizInventario): Boolean;

    function Ver(AArticulos: IBizInventario; AInventario : IBizInventario; APedido: IBizPedidoProveedor = Nil): Boolean;
    procedure VerTodos(AInventario: IBizInventario);
    procedure VerReservas(AArticulo: IBizInventario);

    function BuscarTodos: IBizInventario;
    function Buscar(const ID_ALMACEN: Integer): IBizInventario;
    function BuscarDetalleReservas: IBizDetalleReservas;
    function ExtraerSeleccionados(AArticulos: IBizInventario) : IBizInventario;

    procedure Anadir(AArticulos, AInventario : IBizInventario);
    function Guardar(AArticulos : IBizInventario; const FechaMovimiento: TDateTime; const CausaMovimiento: String): Boolean;

    procedure EntradaArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenDestino: Integer);
    procedure SalidaArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer);
    procedure TrasladarArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer; Const CodigoAlmacenDestino: Integer);
    function EntradaPedido(AInventario: IBizInventario; APedido: IBizPedidoProveedor; ADetalles: IDAStronglyTypedDataTable; var ADetallesFinal: IBizInventario): Boolean;
    function SalidaAlbaran(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer; ADetalles: IDAStronglyTypedDataTable): Boolean;

    function GetAlmacenesController: IAlmacenesController;
    procedure SetAlmacenesController(const Value: IAlmacenesController);
    property AlmacenesController: IAlmacenesController read GetAlmacenesController write SetAlmacenesController;

    procedure Copiar(AArticulos: IBizInventario; ADetalles: IDAStronglyTypedDataTable; AInventario: IBizInventario); overload;
  end;

  TInventarioController = class(TControllerBase, IInventarioController)
  private
    FAlmacenesController: IAlmacenesController;
    FArticulosController : IArticulosInventarioController;
    FPresupuestosClienteController : IPresupuestosClienteController;
    FPedidosProveedorController : IPedidosProveedorController;
    function GetAlmacenesController: IAlmacenesController;
    function GetArticulosController: IArticulosInventarioController;
    function GetPresupuestosClienteController: IPresupuestosClienteController;
    function GetPedidosProveedorController: IPedidosProveedorController;
    procedure SetAlmacenesController(const Value: IAlmacenesController);
    procedure SetArticulosController(const Value: IArticulosInventarioController);
    procedure SetPresupuestosClienteController(const Value: IPresupuestosClienteController);
    procedure SetPedidosProveedorController(const Value: IPedidosProveedorController);

    function Reservar(AInventario : IBizInventario; Todos: Boolean; Const APedido: IBizPresupuestoCliente): Boolean; overload;
    function Liberar(AInventario : IBizInventario; Todos: Boolean): Boolean; overload;

    function EntradaSalidaArticulos(AArticulos, AInventario : IBizInventario; APedido: IBizPedidoProveedor = Nil): Boolean; overload;

    procedure Copiar(AArticulos: IBizInventario; ADetalles: IDAStronglyTypedDataTable; AInventario: IBizInventario); overload;
    function GuardarMovimientos(AArticulos : IBizInventario; const FechaMovimiento: TDateTime; const CausaMovimiento: String): Boolean;

  protected
    FDataModule : IDataModuleInventario;

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

    procedure FiltrarEmpresa(AInventario: IBizInventario); overload;
    procedure FiltrarEmpresa(ADetalleReservas: IBizDetalleReservas); overload;
    procedure DeshabilitarOnCalcFields(Sender: TDADataTable);
    function ValidarCantidades(AArticulos: IBizInventario): Boolean;
    function Validar(AArticulos: IBizInventario): Boolean;

    //Estos son los tres métodos a sobre escribir si se desea heredar toda la logica de
    //este controller
    procedure AsignarDataModule; virtual;

  public
    property AlmacenesController: IAlmacenesController read GetAlmacenesController write SetAlmacenesController;
    property ArticulosController: IArticulosInventarioController read GetArticulosController write SetArticulosController;
    property PresupuestosClienteController: IPresupuestosClienteController read GetPresupuestosClienteController write SetPresupuestosClienteController;
    property PedidosProveedorController: IPedidosProveedorController read GetPedidosProveedorController write SetPedidosProveedorController;

    constructor Create; override;
    destructor Destroy; override;

    function Trasladar(AInventario : IBizInventario; Todos: Boolean): Boolean;

//    procedure RecibirArticulos(Const APedido: IBizPedidoProveedor; Const CodigoAlmacenDes: Integer); overload;

//    procedure RecibirPedidos(Const CodigoAlmacenDes: Integer);

    function Buscar(const ID_ALMACEN: Integer): IBizInventario;
    function BuscarTodos: IBizInventario;
    function BuscarDetalleReservas: IBizDetalleReservas;
    function ElegirArticulos(AArticulos : IBizInventario; AMensaje: String; AMultiSelect: Boolean): IBizInventario;
    function ExtraerSeleccionados(AArticulos: IBizInventario) : IBizInventario;

    procedure Anadir(AArticulos, AInventario : IBizInventario);
    function Eliminar(AInventario : IBizInventario; Todos: Boolean; ApplyUpdates: Boolean): Boolean;

    procedure EntradaArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenDestino: Integer);
    procedure SalidaArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer);
    procedure TrasladarArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer; Const CodigoAlmacenDestino: Integer);
    function EntradaPedido(AInventario: IBizInventario; APedido: IBizPedidoProveedor; ADetalles: IDAStronglyTypedDataTable; var ADetallesFinal: IBizInventario): Boolean;
    function SalidaAlbaran(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer; ADetalles: IDAStronglyTypedDataTable): Boolean;

    procedure VerTodos(AInventario: IBizInventario);
    function Ver(AArticulos: IBizInventario; AInventario : IBizInventario; APedido: IBizPedidoProveedor = Nil): Boolean;

    procedure VerReservas(AArticulo: IBizInventario);

    function Guardar(AArticulos : IBizInventario; const FechaMovimiento: TDateTime; const CausaMovimiento: String): Boolean;

    function Liberar(AInventario : IBizInventario): Boolean; overload;
    procedure Reservar(AInventario : IBizInventario); overload;
  end;

implementation

uses
  Forms, cxControls, DB, schInventarioClient_Intf, uEditorRegistryUtils,
  uIEditorInventario, uDataModuleInventario,
  uDataModuleUsuarios, uDAInterfaces, uDataTableUtils,
  uDateUtils, uROTypes, DateUtils, Controls, Windows,
  dialogs, Variants, schPedidosProveedorClient_Intf,
  uControllerDetallesBase, uDialogUtils, uFactuGES_App,
  uIEditorEntradaSalidaArticulos, schArticulosClient_Intf,
  uIEditorElegirArticulosAlmacen, uInventarioUtils,
  uIEditorDetalleReservas;

{ TInventarioController }

{
procedure TInventarioController.Anadir(AArticulo: IBizArticulo);
begin
  AArticulo.Insert;
end;
}

procedure TInventarioController.Anadir(AArticulos, AInventario: IBizInventario);
var
  AArticulosSeleccionados: IDAStronglyTypedDataTable;
begin
  AArticulosSeleccionados := Nil;

  case AArticulos.TipoMovimiento of
    tEntradaLibre: begin
      //IBizArticulo
      AArticulosSeleccionados := FArticulosController.ElegirArticulos(FArticulosController.BuscarInventariables, '', True);
    end;

    tSalidaLibre, tTraslado: begin
      //IBizInventario
      AArticulosSeleccionados := ElegirArticulos(Buscar(AArticulos.IDAlmacenOrigen), '', True);
    end;
  end;

  if Assigned(AArticulosSeleccionados) then
     Copiar(AArticulos, AArticulosSeleccionados,  AInventario)
end;

procedure TInventarioController.AsignarDataModule;
begin
  FDataModule := TDataModuleInventario.Create(Nil);
end;

function TInventarioController.Buscar(const ID_ALMACEN: Integer): IBizInventario;
begin
  Result := (FDataModule as IDataModuleInventario).GetItems(ID_ALMACEN);
  FiltrarEmpresa(Result);
end;

function TInventarioController.BuscarDetalleReservas: IBizDetalleReservas;
begin
  Result := FDataModule.GetDetalleReservas;
  FiltrarEmpresa(Result);
end;

function TInventarioController.BuscarTodos: IBizInventario;
begin
  Result := FDataModule.GetItems;
  FiltrarEmpresa(Result);
end;

procedure TInventarioController.Copiar(AArticulos: IBizInventario; ADetalles: IDAStronglyTypedDataTable; AInventario: IBizInventario);
{
  Procedimiento que copia en AArticulos, todos los detalles pasados por parametro ADetalles
  añadiendo además el stock de cada uno de los detalles datos, siempre y cuando dichos
  detalles existan en AInventario pasado por parámetro.

  ADetalles será una interfaz genérica porque pueden venir dos tipos de elementos a añadir:
  - 1 Articulos de catálogo: IBizArticulo
  - 2 Artículos de un almacén: IBizInventario
  - 3 Detalles de un pedido de proveedor u albaran de cliente: IDAStronglyTypedDataTable (cumple con los tipos de controller detalles base
}
var
  StockArticulo: Double;

begin
  if (not Assigned(AArticulos))
  or (not Assigned(ADetalles)) then
     exit;

  if not AArticulos.DataTable.Active then
     AArticulos.DataTable.Active := True;

  if not ADetalles.DataTable.Active then
     ADetalles.DataTable.Active := True;

  if not Assigned(AInventario) then
  begin
    AInventario := BuscarTodos;
    AInventario.DataTable.Active := True;
  end;

  //Hacemos el recorrido de los detalles para insertarlos en AArticulos
  with ADetalles.DataTable do
  begin
    First;
    while not EOF do
    begin
      AArticulos.DataTable.Insert;

      //Estos campos serán comunes para todos los tipos de ADetalles a recibir
      AArticulos.REFERENCIA := FieldByName(fld_INVENTARIOREFERENCIA).AsString;

      //Caso 1 ADetalles = IBizArticulo
      if Supports(ADetalles, IBizArticulo) then
      begin
        AArticulos.ID_ARTICULO := FieldByName(fld_ArticulosID).AsInteger;
        AArticulos.REFERENCIA_PROVEEDOR := FieldByName(fld_ArticulosREFERENCIA_PROV).AsString;
        AArticulos.DESCRIPCION := FieldByName(fld_INVENTARIODESCRIPCION).AsString;
        AArticulos.CANTIDAD := 1;
      end
      //Casos 2, 3  ADetalles = IBizInventario, IDAStronglyTypedDataTable
      else
      begin
        AArticulos.ID_ARTICULO := FieldByName(fld_INVENTARIOID_ARTICULO).AsInteger;
        AArticulos.REFERENCIA_PROVEEDOR := FieldByName(fld_INVENTARIOREFERENCIA_PROVEEDOR).AsString;
        if Supports(ADetalles, IBizInventario) then
        begin
          AArticulos.DESCRIPCION := FieldByName(fld_INVENTARIODESCRIPCION).AsString;
          AArticulos.CANTIDAD := 1;
        end
        else
        begin
          AArticulos.DESCRIPCION := FieldByName(fld_PedidosProveedor_DetallesCONCEPTO).AsString;
          AArticulos.CANTIDAD := FieldByName(fld_INVENTARIOCANTIDAD).AsFloat;
        end;
      end;

      //Localizamos el stock en AInventario por cada uno de los ADetalles a copiar
      AInventario.DataTable.First;
      if AInventario.DataTable.Locate(fld_INVENTARIOID_ALMACEN + ';' + fld_INVENTARIOID_ARTICULO, VarArrayOf([AArticulos.ID_ALMACEN, AArticulos.ID_ARTICULO]), [])
      then StockArticulo := AInventario.STOCK
      else StockArticulo := 0;
      //Asignamos el Stock al articulo añadido
      if not AArticulos.DataTable.Editing then
         AArticulos.DataTable.Edit;
      AArticulos.STOCK := StockArticulo;

      AArticulos.DataTable.Post;
      Next;
    end;
  end;
end;

constructor TInventarioController.Create;
begin
  inherited;
  AsignarDataModule;
  FArticulosController := TArticulosInventarioController.Create;
  FAlmacenesController := TAlmacenesController.Create;
  FPresupuestosClienteController := TPresupuestosClienteController.Create;
  FPedidosProveedorController := TPedidosProveedorController.Create;
end;

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

{
procedure TInventarioController.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 TInventarioController.Destroy;
begin
  FDataModule := Nil;
  FArticulosController := Nil;
  FAlmacenesController := Nil;
  FPresupuestosClienteController := Nil;
  FPedidosProveedorController := Nil;    
  inherited;
end;

function TInventarioController.ElegirArticulos(AArticulos: IBizInventario; AMensaje: String; AMultiSelect: Boolean): IBizInventario;
var
  AEditor : IEditorElegirArticulosAlmacen;
begin
  Result := NIL;

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

function TInventarioController.Eliminar(AInventario: IBizInventario; Todos: Boolean; ApplyUpdates: Boolean): Boolean;
begin
  Result := False;
  if Assigned(AInventario) then
  begin
    ShowHourglassCursor;
    try
      if Todos
      then AInventario.DataTable.ClearRows
      else AInventario.DataTable.Delete;

      if ApplyUpdates then
         AInventario.DataTable.ApplyUpdates;
      Result := True;
    finally
      HideHourglassCursor;
    end;
  end;
end;

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

procedure TInventarioController.FiltrarEmpresa(ADetalleReservas: IBizDetalleReservas);
var
  Condicion: TDAWhereExpression;
begin
  if ADetalleReservas.DataTable.Active then
    ADetalleReservas.DataTable.Active := False;

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

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

function TInventarioController.Validar(AArticulos: IBizInventario): Boolean;
begin
  Result := True;

  if not Assigned(AArticulos) then
     raise Exception.Create ('Articulos no asignados');

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

  case AArticulos.TipoMovimiento of
     tSalidaLibre, tSalidaAlbaranCliente, tTraslado: 
     begin
       Result := ValidarCantidades(AArticulos);
       if not Result then
          raise Exception.Create ('Revise las cantidades');
     end;
  end;
end;

function TInventarioController.ValidarCantidades(AArticulos: IBizInventario): Boolean;
var
  ListaArticulos: TStringList;
begin
  Result := False;
  if Assigned(AArticulos) then
  begin
    ShowHourglassCursor;
    try
      ListaArticulos := TStringList.Create;
      With AArticulos.DataTable do
      begin
        First;
        while not eof do
        begin
          if (AArticulos.CANTIDAD > AArticulos.STOCK) then
             ListaArticulos.Add(AArticulos.REFERENCIA + ' - ' + AArticulos.DESCRIPCION);
          next;
        end;
        if ListaArticulos.Count > 0 then
          Result := (ShowConfirmMessage_ArticulosSinStock(ListaArticulos) = IDYES)
        else
          Result := True;
       end;
    finally
      FreeAndNil(ListaArticulos);
      HideHourglassCursor;
    end;
  end;
end;

function TInventarioController.Ver(AArticulos: IBizInventario; AInventario: IBizInventario; APedido: IBizPedidoProveedor = Nil): Boolean;
var
  AEditor : IEditorEntradaSalidaArticulos;
begin
  Result := False;
  AEditor := NIL;

  CreateEditor('EditorEntradaSalidaArticulos', IEditorEntradaSalidaArticulos, AEditor);
  if Assigned(AEditor) then
    try
       AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
       AEditor.Articulos := AArticulos;
       AEditor.Inventario := AInventario;
       if Assigned(APedido) then
          AEditor.PedidoProveedor := APedido;
       AEditor.ShowModal;
       Result := AEditor.ResultadoModalOK;
    finally
       AEditor.Release;
       AEditor := NIL;
    end;
end;

procedure TInventarioController.VerReservas(AArticulo: IBizInventario);
var
  AEditor : IEditorDetalleReservas;
begin
  AEditor := NIL;

  CreateEditor('EditorDetalleReservas', IEditorDetalleReservas, AEditor);
  if Assigned(AEditor) then
    try
 //      AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
       AEditor.DetalleReservas := FDataModule.GetDetalleReservas;
       AEditor.Articulo := AArticulo;
 //      AEditor.MultiSelect := False;
       AEditor.ShowModal;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

procedure TInventarioController.VerTodos(AInventario: IBizInventario);
var
  AEditor : IEditorInventario;
begin
  AEditor := NIL;

  CreateEditor('EditorInventario', IEditorInventario, AEditor);
  if Assigned(AEditor) then
     with AEditor do
     begin
       Controller := Self; //OJO ORDEN MUY IMPORTANTE
       Inventario := AInventario;
       MultiSelect := False;
       ShowEmbedded;
     end;
end;

function TInventarioController._Vacio: IBizInventario;
begin
  Result := Buscar(ID_NULO);
end;

{
procedure TInventarioController.Eliminar(const ID: Integer);
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]));

  Eliminar(AArticulo);
  AArticulo := NIL;
end;

function TInventarioController.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;
}

function TInventarioController.EntradaSalidaArticulos(AArticulos, AInventario : IBizInventario; APedido: IBizPedidoProveedor = Nil): Boolean;
begin
  Result := False;
  if not Assigned(AArticulos) then
     Exit;

  if not AArticulos.DataTable.Active then
     AArticulos.DataTable.Active := True;

  Result := Ver(AArticulos, AInventario, APedido);
end;

{procedure TInventarioController.RecibirArticulos(const APedido: IBizPedidoProveedor; const CodigoAlmacenDes: Integer);
{var
  AArticulos: IBizInventario;
//  ADetalles: IBizDetallesPedidoProveedor;
begin

  try
    if APedido.DataTable.FieldByName(fld_PedidosProveedorID_ALMACEN).IsNull then
    begin
      MessageBox(0, 'En el pedido que ha elegido no figura ningún almacén como destino.' + #10#13 +
          'Si desea recibir este pedido en algún almacén'  + #10#13 +
          'modifique antes el pedido para indicarlo.', 'Atención', MB_ICONWARNING or MB_OK);

      Exit;
    end;

    AArticulos := Buscar(ID_NULO);
    if not AArticulos.DataTable.Active then
       AArticulos.DataTable.Active := True;

    if Assigned(APedido.Detalles) then
    begin
      APedido.Detalles.First;
      while not APedido.Detalles.EOF do
      begin
        //Solo aquellos artículos que esten dados de alta en nuestro catálogo
        if (APedido.Detalles.ID_ARTICULO > 0) then
        begin
          AArticulos.Insert;
          if not APedido.DataTable.FieldByName(fld_PedidosProveedorID_ALMACEN).IsNull then
             AArticulos.ID_ALMACEN := APedido.ID_ALMACEN;
          if not APedido.DataTable.FieldByName(fld_PedidosProveedorID).IsNull then
             AArticulos.ID_PEDIDO_PROVEEDOR := APedido.ID;
          AArticulos.ID_ARTICULO := APedido.Detalles.ID_ARTICULO;
          AArticulos.REFERENCIA_CLIENTE := APedido.Detalles.REFERENCIA;
          AArticulos.REFERENCIA_PROVEEDOR := APedido.Detalles.REFERENCIA_PROVEEDOR;
          AArticulos.DESCRIPCION := APedido.Detalles.CONCEPTO;
          AArticulos.CANTIDAD := APedido.Detalles.CANTIDAD;
          AArticulos.Post;
        end;
        APedido.Detalles.Next;
      end;
    end;

    if RecibirArticulos(AArticulos, CodigoAlmacenDes) then
       PedidosProveedorController.CambiarSituacion(APedido);

  finally
    AArticulos := Nil;
  end;
end;}

procedure TInventarioController.EntradaArticulosLibre(AInventario: IBizInventario; const CodigoAlmacenDestino: Integer);
var
  AArticulos: IBizInventario;
begin
  try
    AArticulos := Buscar(ID_NULO);

    //Se queda en la clase de negocio para así todos y cada uno de los artículos que
    //se agreguen se asigne automáticamente el codigo de almacen destino en OnNewRecord
    AArticulos.TipoMovimiento := tEntradaLibre;
    AArticulos.IDAlmacenDestino := CodigoAlmacenDestino;
    EntradaSalidaArticulos(AArticulos, AInventario);
  finally
    AArticulos := Nil;
  end;
end;

function TInventarioController.EntradaPedido(AInventario: IBizInventario; APedido: IBizPedidoProveedor; ADetalles: IDAStronglyTypedDataTable; var ADetallesFinal: IBizInventario): Boolean;
var
  AArticulos: IBizInventario;
begin
  Result := False;
  AArticulos := Buscar(ID_NULO);

  //Se queda en la clase de negocio para así todos y cada uno de los artículos que
  //se agreguen se asigne automáticamente el codigo de almacen destino en OnNewRecord
  AArticulos.TipoMovimiento := tEntradaPedidoProveedor;
  AArticulos.IDAlmacenDestino := APedido.ID_ALMACEN;

  //Inicializamos los articulos a hacer salida con los dados por parametro
  Copiar(AArticulos, ADetalles, AInventario);

  ADetallesFinal:= AArticulos;
  Result := EntradaSalidaArticulos(AArticulos, AInventario, APedido);
end;

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

{procedure TInventarioController.RecibirPedidos(const CodigoAlmacenDes: Integer);
var
  APedido: IBizPedidoProveedor;
begin
  try
    APedido := FPedidosProveedorController.BuscarPendientesRecepcion;
    APedido := FPedidosProveedorController.ElegirPedidos(APedido, '', False);

    if Assigned(APedido) then
       RecibirArticulos(APedido, CodigoAlmacenDes);

  finally
    APedido := Nil;
  end;

end;}

procedure TInventarioController.Reservar(AInventario : IBizInventario);
var
  APresupuesto: IBizPresupuestoCliente;
begin
  if not Assigned(AInventario) then
     exit;

  try
//    APresupuesto := FPresupuestosClienteController.BuscarPendientes;
//    APresupuesto := FPresupuestosClienteController.ElegirPresupuestos(APresupuesto, '', False);

//    if Assigned(APresupuesto) then
//       Reservar(AInventario, False, APresupuesto);

  finally
    APresupuesto := Nil;
  end;
end;

function TInventarioController.Reservar(AInventario : IBizInventario; Todos: Boolean; const APedido: IBizPresupuestoCliente): Boolean;
begin
{
  Result := False;
  if not Assigned(AInventario) then
     exit;

  try
    with AInventario.DataTable do
    begin
      if not Active then
         Active := True;

      if Todos then
      begin
        First;
        while not EOF do
        begin
          Edit;
          AInventario.ID_PEDIDO_CLIENTE := APedido.ID;
          AInventario.REFERENCIA_PED_CLI := APedido.REFERENCIA;
          Post;
          Next;
        end;
      end
      else
      begin
        Edit;
        AInventario.ID_PEDIDO_CLIENTE := APedido.ID;
        AInventario.REFERENCIA_PED_CLI := APedido.REFERENCIA;
        Post;
      end;

      ApplyUpdates;
      Result := True;
    end;
  except
    on E: EDAApplyUpdateFailed do
    begin
      AInventario.DataTable.CancelUpdates;
      showmessage('Error al reservar para el pedido');
    end;
  end;
}
end;

function TInventarioController.SalidaAlbaran(AInventario: IBizInventario; const CodigoAlmacenOrigen: Integer; ADetalles: IDAStronglyTypedDataTable): Boolean;
var
  AArticulos: IBizInventario;
begin
  try
    Result := False;
    AArticulos := Buscar(ID_NULO);

    //Se queda en la clase de negocio para así todos y cada uno de los artículos que
    //se agreguen se asigne automáticamente el codigo de almacen destino en OnNewRecord
    AArticulos.TipoMovimiento := tSalidaAlbaranCliente;
    AArticulos.IDAlmacenOrigen := CodigoAlmacenOrigen;

    //Inicializamos los articulos a hacer salida con los dados por parametro
    Copiar(AArticulos, ADetalles, AInventario);
    Result := EntradaSalidaArticulos(AArticulos, AInventario);
  finally
    AArticulos := Nil;
  end;
end;

procedure TInventarioController.SalidaArticulosLibre(AInventario: IBizInventario; Const CodigoAlmacenOrigen: Integer);
var
  AArticulos: IBizInventario;
begin
  try
    AArticulos := Buscar(ID_NULO);

    //Se queda en la clase de negocio para así todos y cada uno de los artículos que
    //se agreguen se asigne automáticamente el codigo de almacen destino en OnNewRecord
    AArticulos.TipoMovimiento := tSalidaLibre;
    AArticulos.IDAlmacenOrigen := CodigoAlmacenOrigen;
    EntradaSalidaArticulos(AArticulos, AInventario);
  finally
    AArticulos := Nil;
  end;
end;

procedure TInventarioController.SetAlmacenesController(const Value: IAlmacenesController);
begin
  FAlmacenesController := Value;
end;

procedure TInventarioController.SetArticulosController(const Value: IArticulosInventarioController);
begin
  FArticulosController := Value
end;

procedure TInventarioController.SetPresupuestosClienteController(const Value: IPresupuestosClienteController);
begin
  FPresupuestosClienteController := Value
end;

procedure TInventarioController.SetPedidosProveedorController(const Value: IPedidosProveedorController);
begin
  FPedidosProveedorController := Value
end;

function TInventarioController.Trasladar(AInventario: IBizInventario; Todos: Boolean): Boolean;
var
  AAlmacenes : IBizAlmacen;
begin
  Result := False;
  if Assigned(AInventario) then
  begin
    ShowHourglassCursor;
    try
      //Seleccionamos almacén
      AAlmacenes := FAlmacenesController.BuscarTodos;
      if not AAlmacenes.DataTable.Active then
         AAlmacenes.DataTable.Active := True;

      AAlmacenes := FAlmacenesController.VerLista(AAlmacenes);

      //Aginamos el nuevo almacén
      if Assigned(AAlmacenes) then
      begin
        if not AInventario.DataTable.Editing then
           AInventario.Edit;
        AInventario.ID_ALMACEN := AAlmacenes.ID;
        AInventario.Post;

      AInventario.DataTable.ApplyUpdates;
      Result := True;
//      if Todos
//      then AInventario.DataTable.ClearRows
//      else AInventario.DataTable.Delete;
      end;

    finally
      HideHourglassCursor;
    end;
  end;
end;

procedure TInventarioController.TrasladarArticulosLibre(AInventario: IBizInventario; const CodigoAlmacenOrigen: Integer; Const CodigoAlmacenDestino: Integer);
var
  AArticulos: IBizInventario;
begin
  try
    AArticulos := Buscar(ID_NULO);

    //Se queda en la clase de negocio para así todos y cada uno de los artículos que
    //se agreguen se asigne automáticamente el codigo de almacen destino en OnNewRecord
    AArticulos.TipoMovimiento := tTraslado;
    AArticulos.IDAlmacenOrigen := CodigoAlmacenOrigen;
    AArticulos.IDAlmacenDestino := CodigoAlmacenDestino;
    EntradaSalidaArticulos(AArticulos, AInventario);
  finally
    AArticulos := Nil;
  end;
end;

{
function TInventarioController.Trasladar: Boolean;
begin

end;

function TInventarioController.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;
}

procedure TInventarioController.FiltrarEmpresa(AInventario: IBizInventario);
var
  Condicion: TDAWhereExpression;
begin
  if AInventario.DataTable.Active then
    AInventario.DataTable.Active := False;

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

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

function TInventarioController.GetAlmacenesController: IAlmacenesController;
begin
  Result := FAlmacenesController;
end;

function TInventarioController.GetArticulosController: IArticulosInventarioController;
begin
  Result := FArticulosController;
end;

function TInventarioController.GetPresupuestosClienteController: IPresupuestosClienteController;
begin
  Result := FPresupuestosClienteController;
end;

function TInventarioController.GetPedidosProveedorController: IPedidosProveedorController;
begin
  Result := FPedidosProveedorController;
end;

{procedure TInventarioController.GuardarArticulos(AInventario : IBizInventario);
var
  AArticulos: IBizInventario;
  i: Integer;
begin

  AArticulosUnitarios := Buscar(ID_NULO);
  if not AArticulosUnitarios.DataTable.Active then
     AArticulosUnitarios.DataTable.Active := True;

  with AInventario do
  begin
    DataTable.First;
    while not DataTable.EOF do
    begin
      for i:=0 to (CANTIDAD - 1) do
      begin
        AArticulosUnitarios.Insert;
        AArticulosUnitarios.ID_ALMACEN := ID_ALMACEN;
        AArticulosUnitarios.ID_ARTICULO := ID_ARTICULO;
        if not DataTable.FieldByName(fld_INVENTARIOID_PEDIDO_PROVEEDOR).IsNull then
           AArticulosUnitarios.ID_PEDIDO_PROVEEDOR := ID_PEDIDO_PROVEEDOR;
        if not DataTable.FieldByName(fld_INVENTARIOID_PEDIDO_CLIENTE).IsNull then
           AArticulosUnitarios.ID_PEDIDO_CLIENTE := ID_PEDIDO_CLIENTE;
        AArticulosUnitarios.DESCRIPCION := DESCRIPCION;
        AArticulosUnitarios.Post;

        AssignarID(AArticulosUnitarios, (FDataModule as IDataModuleInventario));
      end;
      DataTable.Next;
    end;

  DataTable.CancelUpdates;
  AArticulosUnitarios.DataTable.ApplyUpdates;
  end;

end;}

function TInventarioController.Liberar(AInventario: IBizInventario; Todos: Boolean): Boolean;
begin
{
  Result := False;
  if not Assigned(AInventario) then
     exit;

  try
    with AInventario.DataTable do
    begin
      if not Active then
         Active := True;

      if Todos then
      begin
        First;
        while not EOF do
        begin
          Edit;
          FieldByName(fld_INVENTARIOID_PEDIDO_CLIENTE).AsVariant := Null;
          Post;
          Next;
        end;
      end
      else
      begin
        Edit;
        FieldByName(fld_INVENTARIOID_PEDIDO_CLIENTE).AsVariant := Null;
        Post;
        Next;
      end;

      ApplyUpdates;
      Result := True;
    end;
  except
    on E: EDAApplyUpdateFailed do
    begin
      AInventario.DataTable.CancelUpdates;
      showmessage('Error al liberar los artículos seleccionados');
    end;
  end;
}
end;

function TInventarioController.Liberar(AInventario : IBizInventario): Boolean;
begin
  Result := False;
  if Assigned(AInventario) then
     Result := Liberar(AInventario, False);
end;


procedure TInventarioController.DeshabilitarOnCalcFields(Sender: TDADataTable);
begin
// Deshabilita el devolver RECID para la localización unica de tuplas de inventario
// Para así poder utiliza ID para la inserción de movimientos
end;

function TInventarioController.Guardar(AArticulos: IBizInventario; const FechaMovimiento: TDateTime; const CausaMovimiento: String): Boolean;
begin
  Result := False;

  if not Assigned(AArticulos) then
    raise Exception.Create ('Artículos no asignados');

  if Validar(AArticulos) then
  begin
    ShowHourglassCursor;
    try
      case AArticulos.TipoMovimiento of
        tEntradaLibre, tSalidaLibre, tTraslado: Result := GuardarMovimientos(AArticulos, FechaMovimiento, CausaMovimiento);
        tSalidaAlbaranCliente : begin
                                  AArticulos.DataTable.CancelUpdates;
                                  Result := True;
                                end;
        tEntradaPedidoProveedor : Result := True; //Dar de alta el albarán

      end;
    finally
      HideHourglassCursor;
    end;
  end
  else
    AArticulos.DataTable.CancelUpdates;
end;

function TInventarioController.GuardarMovimientos(AArticulos: IBizInventario; const FechaMovimiento: TDateTime; const CausaMovimiento: String): Boolean;
var
  AArticulosTraslado : IBizInventario;
begin
  Result := False;
  if Assigned(AArticulos) then
  begin
    //Deshabilitamos el calculo de ID (RECID) para poderlo usar para la inserción de movimientos
    AArticulos.DataTable.OnCalcFields := DeshabilitarOnCalcFields;
    with AArticulos.DataTable do
    begin
      First;
      while not EOF do
      begin
        if not Editing then
           Edit;

        //Realmente son los campos de la tabla movimientos los que estamos asignando
        //que luego por comandos se realizarán las inserciones
        AArticulos.FECHA_MOVIMIENTO := FechaMovimiento;
        AArticulos.CAUSA := CausaMovimiento;
        case AArticulos.TipoMovimiento of
          tEntradaLibre: AArticulos.TIPO := CTE_TIPO_ENTRADA;
          tSalidaLibre, tTraslado: AArticulos.TIPO := CTE_TIPO_SALIDA;
        end;

        Post;
        Next;
      end;

      //Solo para traslados, realizaremos los mismos movimientos, pero en este caso
      //de entrada en el almacén destino
      if (AArticulos.TipoMovimiento = tTraslado) then
      begin
        AArticulosTraslado := Buscar(ID_NULO);
        //Deshabilitamos el calculo de ID (RECID) para poderlo usar para la inserción de movimientos
        AArticulosTraslado.DataTable.OnCalcFields := DeshabilitarOnCalcFields;
        AArticulosTraslado.DataTable.Active := True;
        First;
        while not EOF do
        begin
          AArticulosTraslado.Insert;
          AArticulosTraslado.ID_ALMACEN := AArticulos.IDAlmacenDestino;
          AArticulosTraslado.ID_ARTICULO := AArticulos.ID_ARTICULO;
          AArticulosTraslado.FECHA_MOVIMIENTO := AArticulos.FECHA_MOVIMIENTO;
          AArticulosTraslado.CAUSA := AArticulos.CAUSA;
          AArticulosTraslado.TIPO := CTE_TIPO_ENTRADA;
          AArticulosTraslado.CANTIDAD := AArticulos.CANTIDAD;
          AArticulosTraslado.Post;
          Next;
        end;

        AArticulosTraslado.DataTable.ApplyUpdates;
      end;

      ApplyUpdates;
      Result := True;
    end;
  end;
end;

{function TInventarioController.Nuevo: IBizArticulo;
var
  AArticulo : IBizArticulo;
begin
  AArticulo := FDataModule.NewItem;
  FiltrarEmpresa(AArticulo);
  AArticulo.DataTable.Active := True;
  AArticulo.Insert;
  Result := AArticulo;
end;
}

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

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

end.
