unit uCalculosUtils;

interface

uses
   uDADataTable, uDAInterfaces;

const
  CAMPO_ID = 'ID';
  CAMPO_POSICION = 'POSICION';
  CAMPO_TIPO = 'TIPO_DETALLE';
  CAMPO_ID_ARTICULOS = 'ID_ARTICULO';
  CAMPO_CONCEPTO = 'CONCEPTO';
  CAMPO_CANTIDAD = 'CANTIDAD';
  CAMPO_IMPORTE_UNIDAD = 'IMPORTE_UNIDAD';
  CAMPO_IMPORTE_TOTAL = 'IMPORTE_TOTAL';
  CAMPO_DESCUENTO = 'DESCUENTO';
  CAMPO_IMPORTE_PORTE = 'IMPORTE_PORTE';

  function CalcularLineaConcepto (const ADataTable : TDADataTable): Double;
  procedure ValidarCamposLineaConcepto(DataTable: TDADataTable);

  procedure DesglosarPorte(ImportePorte: Currency; ADetalles: IDAStronglyTypedDataTable);
  function DarTotalPorte(ADetalles: IDAStronglyTypedDataTable): Double;


implementation

uses
  SysUtils, DB, Variants, cxControls;

function CalcularLineaConcepto (const ADataTable : TDADataTable): Double;
var
  ImporteTotal : Double;
  ImporteA: Double;
  ImporteB: Double;
begin
  with ADataTable do
  begin
    if (VarIsNull(FieldByName(CAMPO_DESCUENTO).AsVariant)) then
      ImporteTotal := FieldByName(CAMPO_CANTIDAD).asfloat * FieldByName(CAMPO_IMPORTE_UNIDAD).AsFloat
    else
    begin
      //Importe descuento con todos los decimales
      ImporteA := FieldByName(CAMPO_IMPORTE_UNIDAD).AsFloat * (FieldByName(CAMPO_DESCUENTO).AsFloat/100);
      //Importe descuento redondeado a solo dos decimales, porque en grandes cantidades hay fluctuación
      //(importe unidad - 0,6732 no es lo mismo que importe unidad - 0,67 sobre todo cuando trabajamos con grandes cantidades) 
      ImporteB := round(ImporteA*100)/100;
      ImporteTotal := FieldByName(CAMPO_CANTIDAD).asfloat * (FieldByName(CAMPO_IMPORTE_UNIDAD).AsFloat - ImporteB);
    end;

    if (VarIsNull(FieldByName(CAMPO_IMPORTE_PORTE).AsVariant)) then
      ImporteTotal := ImporteTotal
    else
      ImporteTotal := ImporteTotal + (FieldByName(CAMPO_CANTIDAD).asfloat * FieldByName(CAMPO_IMPORTE_PORTE).AsFloat);
  end;

  Result := ImporteTotal;
end;

procedure ValidarCamposLineaConcepto(DataTable: TDADataTable);
var
  AField: TDAField;
begin
  //Validamos la existencia de todos los campos necesarios
  AField := DataTable.FindField(CAMPO_DESCUENTO);
  if not Assigned(AField) then
     raise Exception.Create('Campo ' + CAMPO_DESCUENTO + ' no encontrado (validarCampos)');


  AField := DataTable.FindField(CAMPO_IMPORTE_PORTE);
  if not Assigned(AField) then
     raise Exception.Create('Campo ' + CAMPO_IMPORTE_PORTE + ' no encontrado (validarCampos)');
end;

procedure DesglosarPorte(ImportePorte: Currency; ADetalles: IDAStronglyTypedDataTable);
var
  Unidades: Double;
  ImporteUnidad: Currency;
  ImporteSobrante: Currency;
  ABookmark : TBookmark;

begin

  ImporteUnidad := 0;
  ImporteSobrante := 0;

  ABookmark := ADetalles.DataTable.GetBookMark;
  ADetalles.DataTable.DisableControls;
  ADetalles.DataTable.DisableEventHandlers;
  try
    ADetalles.DataTable.First;
    Unidades := 0;
    while not ADetalles.DataTable.eof do
    begin
      if (ADetalles.DataTable.FieldByName(CAMPO_ID_ARTICULOS).AsInteger > 0) then
         Unidades := Unidades + ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat;
      ADetalles.DataTable.Next;
    end;

    if Unidades > 0 then
    begin
       ImporteUnidad := StrToCurr(FormatFloat('0000000000.00', (ImportePorte / Unidades)));
       ImporteSobrante := ((ImportePorte / Unidades) - ImporteUnidad) * Unidades;
    end;

    ADetalles.DataTable.First;
    while not ADetalles.DataTable.eof do
    begin
      if (ADetalles.DataTable.FieldByName(CAMPO_ID_ARTICULOS).AsInteger > 0) then
      begin
        ADetalles.DataTable.Edit;
        ADetalles.DataTable.FieldByName(CAMPO_IMPORTE_PORTE).AsCurrency := ImporteUnidad;
        ADetalles.DataTable.Post;
      end;
      ADetalles.DataTable.Next;
    end;

    ADetalles.DataTable.Edit;
    ADetalles.DataTable.FieldByName(CAMPO_IMPORTE_PORTE).AsCurrency := ImporteUnidad + ImporteSobrante;
    ADetalles.DataTable.Post;

  finally
    ADetalles.DataTable.EnableEventHandlers;
    ADetalles.DataTable.GotoBookmark(ABookmark);
    ADetalles.DataTable.FreeBookmark(ABookmark);
    ADetalles.DataTable.EnableControls;
  end;
end;

function DarTotalPorte(ADetalles: IDAStronglyTypedDataTable): Double;
var
  ImporteTotal: Currency;
  AuxPosicionIni : Integer;
begin
  AuxPosicionIni := ADetalles.DataTable.FieldByName(CAMPO_POSICION).AsInteger;

  ShowHourglassCursor;
  try
    ADetalles.DataTable.DisableControls;
    ADetalles.DataTable.DisableEventHandlers;

    ADetalles.DataTable.First;
    ImporteTotal := 0;
    while not ADetalles.DataTable.eof do
    begin
      if (ADetalles.DataTable.FieldByName(CAMPO_ID_ARTICULOS).AsInteger > 0) then
         ImporteTotal := ImporteTotal + (ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat * ADetalles.DataTable.FieldByName(CAMPO_IMPORTE_PORTE).AsFloat);
      ADetalles.DataTable.Next;
    end;

  finally
    ADetalles.DataTable.Locate(CAMPO_POSICION, IntToStr(AuxPosicionIni), []);
    ADetalles.DataTable.EnableEventHandlers;
    ADetalles.DataTable.EnableControls;
    HideHourglassCursor;
  end;

  Result := ImporteTotal;
end;


end.
