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.