unit uControllerDetallesArticulos;

interface

uses Classes, Variants, uDACDSDataTable, uDADataTable, uControllerDetallesBase,
     uBizArticulos, uArticulosController;

const
  CAMPO_REFERENCIA = 'REFERENCIA'; //Campo ficticio
  CAMPO_REFERENCIA_PROVEEDOR = 'REFERENCIA_PROVEEDOR'; //Campo ficticio

type
  TEnumReferencia = (tCliente, tProveedor);

  IControllerDetallesArticulos = interface(IControllerDetallesBase)
  ['{6E156796-DB1F-4727-BBFB-FBAEF2E5C098}']
    procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True);
    function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload;
    function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload;
    procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
    procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = True);
    procedure AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String);
    function DarPrecioPVPVenta(IdArticulo: Integer): TStringList;
  end;

  TControllerDetallesArticulos = class (TControllerDetallesBase, IControllerDetallesArticulos)
  protected
    FArticulosController: IArticulosController;

    procedure EliminarArticulosProveedor(ADetalles: IDAStronglyTypedDataTable);
    procedure AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); virtual;
    procedure RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual;
    procedure RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual;
    procedure RellenarGenerales(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual;
    procedure RellenarCantidad(ADetalles: IDAStronglyTypedDataTable; const ACantidad: Float); virtual;
    procedure RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float = 1); virtual;
    procedure Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float = 1); overload;

    procedure AsignarController; virtual;

  public
    function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload;
    function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload;
    procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); virtual;
    procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
    procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = True);
    procedure AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String);
    function DarPrecioPVPVenta(IdArticulo: Integer): TStringList;

    constructor Create; override;
    destructor Destroy; override;
  end;


implementation

{ TControllerDetallesArticulos }

uses
  DB, Dialogs, cxControls, SysUtils, uDAInterfaces, uCalculosUtils, schArticulosClient_Intf;

const
  CAMPO_UNIDADMEDIDA = 'UNIDAD_MEDIDA';


{ TControllerDetallesArticulos }

procedure TControllerDetallesArticulos.ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
var
  ACantidad: Float;
begin
  if (Assigned(ADetalles) and Assigned(AArticulos)) then
  begin
    if not AArticulos.DataTable.Active then
       AArticulos.DataTable.Active := True;

    BeginUpdate(ADetalles);
    try
      ADetalles.DataTable.First;
      with ADetalles.DataTable do
      begin
        while not EOF do
        begin
          Edit;
          AArticulos.DataTable.First;
          try
            if AArticulos.DataTable.Locate(CAMPO_ID, FieldByName(CAMPO_ID_ARTICULOS).AsVariant, []) then
            begin
              //Para mantener la cantidad que ya tuviera el detalle se debe guardar y volver a poner
              ACantidad := ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat;
              RellenarDetalle(ADetalles, AArticulos, ACantidad);
            end;
          except
            on E: Exception do
              ShowMessage(E.Message);
          end;
          Next;
        end;
        //Volvemos a dejarlo al principio
        ADetalles.DataTable.First;
      end;
    finally
      EndUpdate(ADetalles);
    end;
  end;
end;

procedure TControllerDetallesArticulos.Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float);
begin
  if Assigned(ADetalles) and Assigned(AArticulos) then
  begin
    try
      ShowHourglassCursor;
      BeginUpdate(ADetalles);

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

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

      with AArticulos.DataTable do
      begin
        First;
        while not EOF do
        begin
          Self.Add(ADetalles, TIPO_DETALLE_CONCEPTO);
          RellenarDetalle(ADetalles, AArticulos, ACantidad);
          Next;
        end;
      end;
    finally
      EndUpdate(ADetalles);
      HideHourglassCursor;
    end;
  end;
end;

function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo, AClienteID: Integer;
  const ACantidad: Float): Boolean;
var
  AArticulo: IBizArticulo;
begin
{
  Añade el artículo con la referencia pasada por parametro a los detalles pasados por parametro
  En el caso de asignar un AClienteID el articulo debe contener el descuento para ese cliente
}
  Result := False;
  BeginUpdate(ADetalles);
  ShowHourglassCursor;
  try
    AArticulo := FArticulosController.Buscar(IDArticulo, AClienteID);

    if Assigned(AArticulo) then
    begin
      AArticulo.DataTable.Active := True;
      if (AArticulo.RecordCount > 0) then
      begin
        RellenarDetalle(ADetalles, AArticulo, ACantidad);
        Result := True;
      end;
    end;
  finally
    EndUpdate(ADetalles);
    HideHourglassCursor;
  end;
end;

procedure TControllerDetallesArticulos.AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila: Boolean);
var
  AArticulos: IBizArticulo;
begin
  if Assigned(ADetalles) then
  begin
    try
      AArticulos := (FArticulosController.BuscarTodos as IBizArticulo);
      //Si nueva fila es false, quiere decir que se sustituye un determinado artículo, por ello la lista a seleccionar no debe ser multiselect
      if ANuevaFila then
      begin
        AArticulos := FArticulosController.ElegirArticulos(AArticulos, 'Elija los artículos que desea añadir', True);
        Add(ADetalles, AArticulos)
      end
      else
      begin
        AArticulos := FArticulosController.ElegirArticulos(AArticulos, 'Elija el artículo que desea añadir', False);
        RellenarDetalle(ADetalles, AArticulos);
      end;
    finally
      AArticulos := Nil;
    end;
  end;
end;

procedure TControllerDetallesArticulos.AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String);
begin
  if Assigned(ADetalles) then
  begin
    With ADetalles.DataTable do
    begin
      First;
      Add(ADetalles, TIPO_DETALLE_TITULO);
      Edit;
      FieldByName(CAMPO_CONCEPTO).AsString := AConcepto;
      Post;
      //Subimos la linea insertada al inicio de los detalles
      Self.Mover(ADetalles.DataTable, 1, -1);
      //Añadimos linea en blanco
      Add(ADetalles, TIPO_DETALLE_CONCEPTO);
      Edit;
      FieldByName(CAMPO_CONCEPTO).AsString := '';
      Post;
//      First;
    end;
  end;
end;

procedure TControllerDetallesArticulos.AsignarController;
begin
  FArticulosController := TArticulosController.Create;
end;

procedure TControllerDetallesArticulos.AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer);
begin
//
end;

procedure TControllerDetallesArticulos.CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean);
begin
//Cambia de signo los detalles de la pasados por parámetro
  if Assigned(ADetalles) then
  begin
    try
      BeginUpdate(ADetalles);

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

      with ADetalles.DataTable do
      begin
        //Cambia el signo a todos
        if AAll then
        begin
          First;
          while not EOF do
          begin
            if (FieldByName(CAMPO_CANTIDAD).AsFloat <> 0) then
            begin
              Edit;
              FieldByName(CAMPO_CANTIDAD).AsFloat := (-1) * FieldByName(CAMPO_CANTIDAD).AsFloat;
            end;
            Next;
          end;
        end
        //Solo cambia el signo al seleccionado
        else
        begin
          if (FieldByName(CAMPO_CANTIDAD).AsFloat <> 0) then
          begin
            Edit;
            FieldByName(CAMPO_CANTIDAD).AsFloat := (-1) * FieldByName(CAMPO_CANTIDAD).AsFloat;
          end;
        end;
      end;
    finally
      EndUpdate(ADetalles);
    end;
  end;
end;

constructor TControllerDetallesArticulos.Create;
begin
  inherited;
  AsignarController;
end;

function TControllerDetallesArticulos.DarPrecioPVPVenta(IdArticulo: Integer): TStringList;
begin
  Result := FArticulosController.DarPrecioPVPVenta(IdArticulo);
end;

destructor TControllerDetallesArticulos.Destroy;
begin
  FArticulosController := Nil;
  inherited;
end;

procedure TControllerDetallesArticulos.EliminarArticulosProveedor(ADetalles: IDAStronglyTypedDataTable);
begin
  if Assigned(ADetalles) then
  begin
    with ADetalles.DataTable do
    begin
      First;
      while not Eof do
        if not FieldByName(CAMPO_ID_ARTICULOS).IsNull then
          Delete
        else
          Next;
    end;
  end;
end;

function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean;
var
  AArticulo: IBizArticulo;
begin
{
  Añade el artículo con la referencia pasada por parametro a los detalles pasados por parametro
  En el caso de asignar un AClienteID el articulo debe contener el descuento para ese cliente
}
  Result := False;
  BeginUpdate(ADetalles);
  ShowHourglassCursor;
  try
    case TipoReferencia of
      tCliente: AArticulo := FArticulosController.BuscarReferencia(Referencia, AClienteID);
      tProveedor: AArticulo := FArticulosController.BuscarReferenciaProveedor(Referencia, AClienteID)
    end;

    if Assigned(AArticulo) then
    begin
      AArticulo.DataTable.Active := True;
      if (AArticulo.RecordCount > 0) then
      begin
        RellenarDetalle(ADetalles, AArticulo, ACantidad);
        Result := True;
      end;
    end;
  finally
    EndUpdate(ADetalles);
    HideHourglassCursor;
  end;
end;

procedure TControllerDetallesArticulos.RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
begin
//   Procedimiento que en los hijos se sobreescribirá para rellenar otros campos según necesidades
end;

procedure TControllerDetallesArticulos.RellenarCantidad(ADetalles: IDAStronglyTypedDataTable; const ACantidad: Float);
begin
  if Assigned(ADetalles) then
  begin
    ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat := ACantidad;
  end;
end;

procedure TControllerDetallesArticulos.RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float);
begin
  if Assigned(ADetalles)
  and Assigned(AArticulos) then
  begin
    BeginUpdate(ADetalles);
    try
      if not ADetalles.DataTable.Editing then
         ADetalles.DataTable.Edit;

      RellenarGenerales(ADetalles, AArticulos);
      RellenarCantidad(ADetalles, ACantidad);
      RellenarImportes(ADetalles, AArticulos);
      RellenarOtros(ADetalles, AArticulos);

      if ADetalles.DataTable.Editing then
         ADetalles.DataTable.Post;
    finally
      EndUpdate(ADetalles);
    end;
  end;
end;

procedure TControllerDetallesArticulos.RellenarGenerales(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
begin
  if Assigned(AArticulos) then
  begin
    ADetalles.DataTable.FieldByName(CAMPO_ID_ARTICULOS).AsVariant := AArticulos.ID;
    ADetalles.DataTable.FieldByName(CAMPO_REFERENCIA).AsVariant := AArticulos.REFERENCIA;
    ADetalles.DataTable.FieldByName(CAMPO_REFERENCIA_PROVEEDOR).AsVariant := AArticulos.REFERENCIA_PROV;
    ADetalles.DataTable.FieldByName(CAMPO_CONCEPTO).AsVariant := AArticulos.DESCRIPCION;
    ADetalles.DataTable.FieldByName(CAMPO_UNIDADMEDIDA).AsVariant := AArticulos.UNIDAD_MEDIDA;
  end;
end;

procedure TControllerDetallesArticulos.RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo);
begin
//   Procedimiento que en los hijos se sobreescribirá para rellenar el campo importe según necesidades
end;

end.
