{
===============================================================================
  Copyright (©) 2001. Rodax Software.
===============================================================================
  Los contenidos de este fichero son propiedad de Rodax Software titular del
  copyright. Este fichero sólo podrá ser copiado, distribuido y utilizado,
  en su totalidad o en parte, con el permiso escrito de Rodax Software, o de
  acuerdo con los términos y condiciones establecidas en el acuerdo/contrato
  bajo el que se suministra.
  -----------------------------------------------------------------------------
  Web:  www.rodax-software.com
===============================================================================
  Fecha primera versión: 01-10-2001
  Versión actual: 1.0.7
  Fecha versión actual: 07-03-2004
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
    02-11-2001    Funcion 'EliminarArticulosAlmacen', que elimina todos
                  los artículos de un determinado almacen, es para la opcion
                  'Finalizar obra'.

    18-01-2002    Ordenar por descripción el grid de materiales.

    02-03-2002    Se ha añadido la funcion 'DarListaArticulos' para devolver
                  una lista de codigos de material a partir de un bookmark
                  de filas seleccionadas de la tabla de articulos.

    07-04-2002    Cambio de todos los procedimientos en los que se utiliza
                  una transaccion nueva, por una unica transacción.

                  Se ha eliminado el procedimiento darExistenciasArticuloAlmacen
                  sobrecargado que utilizaba una transaccion pasada por parametro

                  Se han modificado las funciones ModificarExistenciasEntrada,
                  ModificarExistenciasSalida, RealizarMovimiento para que no
                  utilicen transaccion pasada por parametro sino que cojan
                  la de la Base de datos general.

    11-08-2002    P223. Histórico de obras.

    16-11-2002    p250. Poner el número total de artículos dados de alta
                  en la inicialización del grid.

    07-03-2004    P272. Adaptación a multiempresa.                  
===============================================================================
}

unit TablaArticulosAlmacen;

interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, cxGrid,
  Dialogs, DBTables, DB, IBCustomDataSet, IBSQL, BaseDatos, IBDatabase,
  IBStoredProc, Mensajes, IB, StrFunc, cxGridDBTableView,

  //TablaArticulos es usada por el Tipo TDatosArticulo, TDatosAlmacen, TDatosMovimiento
  TablaArticulos, TablaAlmacenes, TablaMovimientos, TablaArticulosObraHistorica;

type
  TdmTablaArticulosAlmacen = class(TDataModule)
  private
    procedure IniciarSQL;
  public
    sqlConsultar : TStrings;
    sqlEliminar : TStrings;
    sqlGrid : TStrings;

    constructor Create (AOwner : TComponent); override;
    destructor Destroy; override;

    function ExisteArticuloEnAlmacen(CodigoEmpresa: Integer; CodigoArticulo: String): Boolean;
    function ArticuloAlmacenTieneExistencias(CodigoEmpresa, CodigoAlmacen: Integer; CodigoArticulo: String): Boolean;

    function ExisteArticuloAlmacen(CodigoEmpresa, CodigoAlmacen : Integer; CodigoArticulo: String): Boolean;
    function DarDatosArticuloAlmacen(CodigoEmpresa: Integer; var Datos: TDatosArticulo): Boolean;
    function DarListaArticulos(Grid : TcxGrid; Tabla: TPTabla) : TStringList;

    function DarExistenciasArticuloAlmacen(CodigoEmpresa, CodigoAlmacen: Integer;
      CodigoArticulo: String): String; overload;
    function DarUnidadesPendRecibirArticuloAlmacen(CodigoEmpresa, CodigoAlmacen: Integer;
      CodigoArticulo: String): String;

    function ModificarExistenciasEntrada(CodigoEmpresa: Integer; Datos: TDatosArticuloAlmacen): Boolean;
    function ModificarExistenciasSalida(CodigoEmpresa: Integer; Datos: TDatosArticuloAlmacen): Boolean;
    function RealizarMovimiento(CodigoEmpresa: Integer; Datos: TDatosArticuloAlmacen):Boolean;

    function EliminarArticulosAlmacen(CodigoEmpresa, CodigoAlmacen: Integer): Boolean;
    function FinalizarObra(CodigoEmpresa: Integer; CodigoObra: Integer; Fecha: String): Boolean;

    procedure InicializarTablaArticulosAlmacen(Tabla : TPTabla);
    procedure InicializarGridArticulosAlmacen(var Grid: TcxGrid);
  end;

var
  dmTablaArticulosAlmacen: TdmTablaArticulosAlmacen;

implementation
{$R *.DFM}

uses
  Excepciones, RdxEmpresaActiva, Literales, Constantes,
  cxGridCustomTableView, Variants, cxCustomData;

constructor TdmTablaArticulosAlmacen.Create (AOwner : TComponent);
begin
  inherited;
  sqlConsultar := TStringList.Create;
  sqlEliminar := TStringList.Create;
  sqlGrid := TStringList.Create;
  IniciarSQL;
end;

destructor TdmTablaArticulosAlmacen.Destroy;
begin
  sqlConsultar.Free;
  sqlEliminar.Free;
  sqlGrid.Free;
  inherited;
end;

procedure TdmTablaArticulosAlmacen.IniciarSQL;
begin
  with sqlConsultar do
  begin
    Add('select CODIGOALMACEN, CODIGOARTICULO, ');
    Add('FAMILIA, DESCRIPCION, UNIDADESMEDIDA, PRECIO, OBSERVACIONES, ');
    Add('EXISTENCIAS, STOCKMAX, STOCKMIN ');
    Add('from ESTADOALMACEN , ARTICULOS ');
    Add('where (CODIGOALMACEN = :CODIGOALMACEN) and ');
    Add('(CODIGOEMPRESA = :CODIGOEMPRESA) and ');
    Add('(CODIGOARTICULO = :CODIGOARTICULO) and ');
    Add('(CODIGOARTICULO = CODIGO)');
  end;

  with sqlEliminar do
  begin
    Add('delete from ESTADOALMACEN ');
    Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
  end;

  with sqlGrid do
  begin
    Add('select CODIGOALMACEN, CODIGOARTICULO, FAMILIA, DESCRIPCION, ');
    Add('UNIDADESMEDIDA, EXISTENCIAS, (EXISTENCIAS * PRECIORECEPCION) as TOTAL');
    Add('from ESTADOALMACEN, ARTICULOS ');
    Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    Add('and (CODIGO = CODIGOARTICULO) ');
    Add('order by DESCRIPCION');
  end;
end;

{ Tanto ExisteArticulosAlmacen como DarDatosArticuloAlmacen esta bien que
tengan su propia transaccion ya que se hace una consulta en un momento
determinado, sin dependencia de otras operaciones}

function TdmTablaArticulosAlmacen.ExisteArticuloAlmacen(CodigoEmpresa,
  CodigoAlmacen : Integer; CodigoArticulo: String): Boolean;
{Comprueba si existe un articulo en un determinado almacen, pasandole por
 parametro el codigo de articulo y el del almacen, devuelve true o false
 dependiendo si existe o no}
var
  oSQL : TIBSQL;
  Codigo : String;
begin
  Result := False;
  if (Length(Trim(CodigoArticulo)) = 0) then
    Exit;

  oSQL := TIBSQL.Create(Self);

  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select CODIGOARTICULO ');
    SQL.Add('from ESTADOALMACEN ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    ParamByName('CODIGOALMACEN').AsInteger := CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := CodigoArticulo;
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;

    try
      Prepare;
      ExecQuery;

      Codigo := FieldByName('CODIGOARTICULO').AsString;
      Result := (CodigoArticulo = Codigo);
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.existeArticuloEnAlmacen(CodigoEmpresa: Integer;
  CodigoArticulo: String): Boolean;
{Comprueba si existe un articulo en un determinado almacen, pasandole por
 parametro el codigo de articulo y el del almacen, devuelve true o false
 dependiendo si existe o no}
var
  oSQL : TIBSQL;
  Codigo : String;
begin
  Result := True;
  if (Length(Trim(CodigoArticulo)) = 0) then
    Exit;

  oSQL := TIBSQL.Create(Self);

  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select CODIGOARTICULO ');
    SQL.Add('from ESTADOALMACEN ');
    SQL.Add('where (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOARTICULO').AsString := CodigoArticulo;
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;

    try
      Prepare;
      ExecQuery;

      if (RecordCount = 0) then
        Result := False;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.DarDatosArticuloAlmacen(CodigoEmpresa: Integer; var Datos: TDatosArticulo): Boolean;
{Devuelve los datos del articulo pasado por parametro si este existe en el
 almacen correspondiente, en caso de no existir devuelve false y rellena
 dichos datos con 0,0 y 1000 respectibamente}
var
  oSQL : TIBSQL;
begin
  Result := False;
  { ¡¡¡ REVISAR ¡¡¡
  if (length(Datos.Codigo) = 0) or VarIsNull(Datos.CodigoAlmacen) then
  begin
    //Para que cuando un articulo libre que no encuentra las existencias en
    //el almacen esten a cero
    Datos.Existencias := '0';
    Datos.PrecioRecepcion := '0';
    Datos.FechaRecepcion := '';
    Exit;
  end;

  oSQL := TIBSQL.Create(Self);

  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select * ');
    SQL.Add('from ESTADOALMACEN ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := Datos.CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := Datos.Codigo;

    try
      Prepare;
      ExecQuery;

      if (RecordCount > 0) then
      begin
        Datos.Existencias := FieldByName('EXISTENCIAS').AsString;
        Datos.StockMin := FieldByName('STOCKMIN').AsString;
        Datos.StockMax := FieldByName('STOCKMAX').AsString;
        Datos.PrecioRecepcion := FieldByName('PRECIORECEPCION').AsString;
        Datos.FechaRecepcion := FieldByName('FECHARECEPCION').AsString;
        Result := True;
      end
      else
      begin
        Datos.Existencias := '0';
        Datos.StockMin := '0';
        Datos.StockMax := '1000';
        Datos.PrecioRecepcion := '0';
        Datos.FechaRecepcion := '';        
      end;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;}
end;

{ Las operaciones de Insertar, ModificarIncrementar, ModificarDecrementar,
dependenran en sus llamadas de otras operaciones por lo tanto se les pasará
la transaccion por parámetro}

function TdmTablaArticulosAlmacen.ModificarExistenciasEntrada(CodigoEmpresa: Integer; Datos: TDatosArticuloAlmacen): Boolean;
{Además de Modificar las existencias del articulo dado por parametro incrementandolas,
 también restablece los StockMin y StockMax con los nuevos dados por parametro,
 si algo sale mal devuelve false}
var
  oSQL : TIBSQL;
begin
  Result := False;

  //Aunque ya lo compruebo fuera, y siempre va ha ser <> 0 asi es más robusto
  if length(Datos.Codigo)= 0 then
    Exit;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('update ESTADOALMACEN ');
    SQL.Add('set EXISTENCIAS = EXISTENCIAS + :CANTIDAD, ');
    SQL.Add('STOCKMIN = :STOCKMIN, ');
    SQL.Add('STOCKMAX = :STOCKMAX, ');
    SQL.Add('PRECIORECEPCION = :PRECIORECEPCION, ');
    SQL.Add('FECHARECEPCION = :FECHARECEPCION ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := Datos.CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := Datos.Codigo;
    ParamByName('CANTIDAD').AsFloat := StrToFloat(Datos.Existencias);
    ParamByName('STOCKMIN').AsInteger := StrToInt(Datos.StockMin);
    ParamByName('STOCKMAX').AsInteger := StrToInt(Datos.StockMax);
    ParamByName('PRECIORECEPCION').AsFloat := StrToFloat(Datos.PrecioRecepcion);
    ParamByName('FECHARECEPCION').AsString := Datos.FechaRecepcion;

    try
      Prepare;
      ExecQuery;
      if RowsAffected = 0 then
      begin
        SQL.Clear;
        SQL.Add('insert into ESTADOALMACEN ');
        SQL.Add('(CODIGOEMPRESA, CODIGOALMACEN, CODIGOARTICULO, EXISTENCIAS, STOCKMIN,');
        SQL.Add('STOCKMAX, PRECIORECEPCION, FECHARECEPCION) ');
        SQL.Add('values (:CODIGOEMPRESA, :CODIGOALMACEN, :CODIGOARTICULO, :EXISTENCIAS, ');
        SQL.Add(':STOCKMIN, :STOCKMAX, :PRECIORECEPCION, :FECHARECEPCION)');
        ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
        ParamByName('CODIGOALMACEN').AsInteger := Datos.CodigoAlmacen;
        ParamByName('CODIGOARTICULO').AsString := Datos.Codigo;
        ParamByName('EXISTENCIAS').AsFloat := StrToFloat(Datos.Existencias);
        ParamByName('STOCKMIN').AsInteger := StrToInt(Datos.StockMin);
        ParamByName('STOCKMAX').AsInteger := StrToInt(Datos.StockMax);
        ParamByName('PRECIORECEPCION').AsFloat := StrToFloat(Datos.PrecioRecepcion);
        ParamByName('FECHARECEPCION').AsString := Datos.FechaRecepcion;
        Prepare;
        ExecQuery;
      end;
      if RealizarMovimiento(CodigoEmpresa, Datos) then
        Result := True;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

procedure TdmTablaArticulosAlmacen.InicializarGridArticulosAlmacen(var Grid: TcxGrid);
var
  Columna : TcxGridDBColumn;
begin
  with (Grid.ActiveView as TcxGridDBTableView) do
  begin
    ClearItems;
    OptionsView.Footer := True;

    {Columna CODIGO}
    Columna := CreateColumn;
    Columna.DataBinding.FieldName := 'CODIGOARTICULO';
    Columna.Caption := 'Código';
    Columna.Width := tamColCodigo;
    Columna.Summary.FooterKind := skCount;
    Columna.Summary.FooterFormat := 'Total: 0 artículos';
    {Columna FAMILIA}
    Columna := CreateColumn;
    Columna.DataBinding.FieldName := 'FAMILIA';
    Columna.Caption := 'Familia';
    Columna.Width := tamColNombreCorto;
    Columna.Visible := False;
    {Columna DESCRIPCION}
    Columna := CreateColumn;
    Columna.SortOrder := soAscending;
    Columna.DataBinding.FieldName := 'DESCRIPCION';
    Columna.Caption := 'Descripción';
    Columna.Width := tamColDescripcion;
    {Columna UNIDADESMEDIDA}
    Columna := CreateColumn;
    Columna.DataBinding.FieldName := 'UNIDADESMEDIDA';
    Columna.Caption := 'Unidades de medida';
    Columna.Width := tamColNombreCorto;
    {Columna EXISTENCIAS}
    Columna := CreateColumn;
    Columna.DataBinding.FieldName := 'EXISTENCIAS';
    Columna.Caption := 'Existencias';
    Columna.Width := tamColCantidad;
    {Columna TOTAL}
    Columna := CreateColumn;
    Columna.DataBinding.FieldName := 'TOTAL';
    Columna.Caption := 'Coste total';
    Columna.Width := tamColImporte;
    Columna.Summary.FooterKind := skSum;
    Columna.Summary.FooterFormat := 'Total: 0.00 €';
    {Columna PENDIENTESRECIBIR}
{    Columna := Add;
    Columna.Visible := True;
    Columna.DataBinding.FieldName := '';
    Columna.Title.Caption := 'U. pendientes recibir';}
  end;
end;

function TdmTablaArticulosAlmacen.DarExistenciasArticuloAlmacen(CodigoEmpresa, CodigoAlmacen: Integer;
   CodigoArticulo: String): String;
{ Esta funcion devuelve las existencias actuales del articulo en el almacen pasados
  por parametro, si el articulo no existe devuelve -1}
var
  oSQL : TIBSQL;
begin
  Result := '-1';

  if (length(CodigoArticulo)= 0) then
    Exit;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select EXISTENCIAS ');
    SQL.Add('from ESTADOALMACEN ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := CodigoArticulo;

    try
      Prepare;
      ExecQuery;

      if (RecordCount > 0) then
        Result := FieldByName('EXISTENCIAS').AsString;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.ArticuloAlmacenTieneExistencias(CodigoEmpresa, CodigoAlmacen: Integer; CodigoArticulo: String): Boolean;
var
  oSQL : TIBSQL;
begin
  Result := True;
  if (length(CodigoArticulo)= 0) then
    Exit;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select EXISTENCIAS ');
    SQL.Add('from ESTADOALMACEN ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := CodigoArticulo;

    try
      Prepare;
      ExecQuery;

      if (RecordCount > 0) and (FieldByName('EXISTENCIAS').AsString = '0') then
        Result := False;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;


function TdmTablaArticulosAlmacen.DarUnidadesPendRecibirArticuloAlmacen(CodigoEmpresa, CodigoAlmacen: Integer;
  CodigoArticulo: String): String;
var
  oSQL : TIBSQL;
begin
  if (length(CodigoArticulo)= 0) then
    Exit;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select distinct E.CODIGOARTICULO, sum(PENDIENTES) as "PENDIENTE" ');
    SQL.Add('from  ESTADOALMACEN E ');
    SQL.Add('left outer join PEDIDOSPROVEEDOR P ');
    SQL.Add('on ((P.CODIGOALMACEN = E.CODIGOALMACEN) and (P.CODIGOEMPRESA = E.CODIGOEMPRESA)) ');
    SQL.Add('left outer join DETALLESPEDIDOSPROVEEDOR D ');
    SQL.Add('on ((D.CODIGOPEDIDO = P.CODIGO) and (D.CODIGOEMPRESA = P.CODIGOEMPRESA) and (D.CODIGOARTICULO = E.CODIGOARTICULO)) ');
    SQL.Add('where E.CODIGOALMACEN = :CODIGOALMACEN ');
    SQL.Add('and E.CODIGOARTICULO = :CODIGOARTICULO ');
    SQL.Add('and E.CODIGOEMPRESA = :CODIGOEMPRESA ');
    SQL.Add('group by E.CODIGOARTICULO ');
    SQL.Add('order by E.CODIGOARTICULO ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := CodigoArticulo;

    try
      Prepare;
      ExecQuery;

      if (RecordCount <> 0) then
        if EsCadenaVacia(FieldByName('PENDIENTE').AsString) then
          Result := '0'
        else
          Result := FieldByName('PENDIENTE').AsString;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.EliminarArticulosAlmacen(CodigoEmpresa, CodigoAlmacen: Integer): Boolean;
var
  oSQL : TIBSQL;
begin
  Result := False;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('delete from ESTADOALMACEN ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    SQL.Add('and CODIGOALMACEN in ');
    SQL.Add('(select CODIGO from ALMACENES ');
    SQL.Add('where (TIPO = ''O'') ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA)) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := CodigoAlmacen;
    try
      Prepare;
      ExecQuery;
      Result := True;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.FinalizarObra(CodigoEmpresa: Integer; CodigoObra: Integer; Fecha: String): Boolean;
var
  oSQL : TIBSQL;
begin
  Result := False;
  if not dmTablaArticulosObraHistorica.InsertarObraHistorica(CodigoEmpresa, CodigoObra, Fecha) then
    Exit;

  if not dmTablaArticulosObraHistorica.InsertarPresupuestosObraHistorica(CodigoEmpresa, CodigoObra, Fecha) then
    Exit;

  if not dmTablaArticulosObraHistorica.EliminarPresupuestosObra(CodigoEmpresa, CodigoObra) then
    Exit;

  if not dmTablaArticulosObraHistorica.InsertarArticulosObraHistorica(CodigoEmpresa, CodigoObra, Fecha) then
    Exit;

  if not EliminarArticulosAlmacen(CodigoEmpresa, CodigoObra) then
    Exit;

  Result := True;
end;

function TdmTablaArticulosAlmacen.RealizarMovimiento(CodigoEmpresa: Integer; Datos: TDatosArticuloAlmacen): Boolean;
var
  DatosMovimiento : TDatosMovimiento;
  DatosArticulo : TDatosArticulo;
  DatosAlmacen : TDatosAlmacen;

begin
  Result := False;

  try
    DatosArticulo := TDatosArticulo.Create;
    DatosArticulo.Codigo := Datos.Codigo;
    //Aprovechamos y de paso tratamos si el articulo ya no existe
    if not dmTablaArticulos.darDatosArticulo(DatosArticulo) then
      raise Exception.CreateFmt(msgMovNoExisteArticulo, [DatosArticulo.Codigo]);

    DatosAlmacen := TDatosAlmacen.Create;
    DatosAlmacen.Codigo := Datos.CodigoAlmacen;
    DatosAlmacen.CodigoEmpresa := EmpresaActiva.Codigo;

    //Aprovechamos y de paso tratamos si el almacen ya no existe
    if not dmTablaAlmacenes.darDatosAlmacen(DatosAlmacen) then
      raise Exception.CreateFmt(msgMovNoExisteAlmacen, [DatosAlmacen.Codigo]);

    DatosMovimiento := TDatosMovimiento.Create;
    DatosMovimiento.CodigoAlmacen := DatosAlmacen.Codigo;
    DatosMovimiento.NombreAlmacen := DatosAlmacen.Nombre;

    DatosMovimiento.CodigoArticulo := DatosArticulo.Codigo;
    DatosMovimiento.DescripcionArticulo := DatosArticulo.Descripcion;
    DatosMovimiento.Familia := DatosArticulo.Familia;
    DatosMovimiento.Unidades := DatosArticulo.Unidadesmedida;

    DatosMovimiento.Cantidad := Datos.Existencias;
    DatosMovimiento.TipoOperacion := Datos.TipoOperacion;
    DatosMovimiento.TipoMovimiento := Datos.TipoMovimiento;
    DatosMovimiento.Causa := Datos.Causa;
    DatosMovimiento.NombreCliente := Datos.NombreCliente;

    //Aqui ya esta bloqueado el registro de este articulo en estado almacen
    DatosMovimiento.StockNuevo := DarExistenciasArticuloAlmacen(CodigoEmpresa, Datos.CodigoAlmacen, Datos.Codigo);
    if DatosMovimiento.TipoOperacion = etiMovEntrada then
      DatosMovimiento.StockAntiguo := FloatToStr(StrToFloat(DatosMovimiento.StockNuevo) - StrToFloat(DatosMovimiento.Cantidad))
    else
      DatosMovimiento.StockAntiguo := FloatToStr(StrToFloat(DatosMovimiento.StockNuevo) + StrToFloat(DatosMovimiento.Cantidad));

    //Si las unidades de entrada o salida son 0, o el articulo a tratar es
    //libre no quedará registrado el movimiento
    if (DatosMovimiento.StockAntiguo <> DatosMovimiento.StockNuevo) and
       (length(DatosMovimiento.CodigoArticulo) <> 0)  then
    begin
      DatosMovimiento.Codigo := dmTablaMovimientos.DarNuevoCodigo;
      dmTablaMovimientos.InsertarMovimiento(DatosMovimiento);
      dmTablaMovimientos.IncrementarCodigo
    end;
    Result := True;
  finally
    DatosMovimiento.Free;
    DatosArticulo.Free;
    DatosAlmacen.Free;
  end;
end;

function TdmTablaArticulosAlmacen.ModificarExistenciasSalida(CodigoEmpresa: Integer;
  Datos: TDatosArticuloAlmacen): Boolean;
{Además de Modificar las existencias del articulo dado por parametro incrementandolas,
 también restablece los StockMin y StockMax con los nuevos dados por parametro,
 si algo sale mal devuelve false}
var
  oSQL : TIBSQL;
begin
  Result := False;

  //Aunque ya lo compruebo fuera, y siempre va ha ser <> 0 asi es más robusto
  if length(Datos.Codigo)= 0 then
    Exit;

  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('update ESTADOALMACEN ');
    SQL.Add('set EXISTENCIAS = EXISTENCIAS - :CANTIDAD, ');
    SQL.Add('STOCKMIN = :STOCKMIN, ');
    SQL.Add('STOCKMAX = :STOCKMAX ');
    SQL.Add('where (CODIGOALMACEN = :CODIGOALMACEN) ');
    SQL.Add('and (CODIGOARTICULO = :CODIGOARTICULO) ');
    SQL.Add('and (EXISTENCIAS - :CANTIDAD >= 0) ');
    SQL.Add('and (CODIGOEMPRESA = :CODIGOEMPRESA) ');
    ParamByName('CODIGOEMPRESA').AsInteger := CodigoEmpresa;
    ParamByName('CODIGOALMACEN').AsInteger := Datos.CodigoAlmacen;
    ParamByName('CODIGOARTICULO').AsString := Datos.Codigo;
    ParamByName('CANTIDAD').AsFloat := StrToFloat(Datos.Existencias);
    ParamByName('STOCKMIN').AsInteger := StrToInt(Datos.StockMin);
    ParamByName('STOCKMAX').AsInteger := StrToInt(Datos.StockMax);

    try
      Prepare;
      ExecQuery;
      if RowsAffected = 0 then
        raise Exception.Create(msgMovNoExisteArtExistencias);

      if RealizarMovimiento(CodigoEmpresa, Datos) then
        Result := True;
    finally
      Close;
      Transaction := NIL;
      Free;
    end;
  end;
end;

function TdmTablaArticulosAlmacen.DarListaArticulos(Grid : TcxGrid; Tabla: TPTabla): TStringList;
var
  i: integer;
  ListaArticulos : TStringList;
begin
  ListaArticulos := Nil;

  // ¡¡¡ REVISAR !!!
{  if Grid.SelectedCount = 0 then
  begin
    Result := ListaArticulos;
    exit
  end;

  ListaArticulos := TStringList.Create;
  Tabla^.DisableControls;
  for i:=0 to Grid.SelectedCount-1 do
  begin
    Tabla^.GotoBookmark(Pointer(Grid.SelectedRows[i]));
    ListaArticulos.Add(Tabla^.FieldByName('CODIGOARTICULO').AsString);
  end;
  Tabla^.EnableControls;}
  Result := ListaArticulos;
end;

procedure TdmTablaArticulosAlmacen.InicializarTablaArticulosAlmacen(
  Tabla: TPTabla);
begin
  with Tabla^.Fields do
  begin
    with (FieldByName('TOTAL') as TFloatField) do begin
      DisplayFormat := DISPLAY_EUROS2;
      EditFormat := EDIT_EUROS2;
    end;
  end;
end;

end.
