Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Otra vez fallos de redondeos. (https://www.clubdelphi.com/foros/showthread.php?t=97250)

afxe 27-02-2025 12:54:24

Otra vez fallos de redondeos.
 
Hola grupo. Tengo FB 3.0 y dialect 3.

Hago una consulta para sacar la suma por bases imponibles, la cuota y el total de una factura a partir de los detalles que la componen:

Código SQL [-]

SELECT A.CODIGO, D.PORC_IVA, 
                 SUM(D.IMPORTE_VENTA)                      AS BASE,
                 SUM(D.IMPORTE_VENTA) * D.PORC_IVA/100      AS CUOTA_1,
                 round( SUM(D.IMPORTE_VENTA) * D.PORC_IVA/100, 2)       AS CUOTA_2,
                 round (SUM(D.IMPORTE_VENTA) * D.PORC_IVA/100 + sum(importe_venta), 2)   AS Total_Factura
FROM CAB_VENTAS A LEFT JOIN DET_MOVIMIENTOS D ON A.TIPO_DOCUMENTO = D.TIPO_CABECERA AND A.CODIGO = D.COD_CABECERA
where a.codigo = 939006
GROUP BY A.CODIGO, D.PORC_IVA

Y este es el resultado:
Código:

CODIGO        PORC_IVA              BASE                  CUOTA_1                CUOTA_2          TOTAL_FACTURA
939006        10.000000        174.55                17.455000                17.450000              192.010000

Podéis observar que CUOTA_2 no hace correctamente el redondeo, debería dar 17.46. IMPORTE_VENTA es un Numeric(15,2) y he probado todas las maneras de hacer el ROUND y CAST, incluso cambiado los campos a Double Precision.

He buscado por el foro pero no he encontrado una solución a esto, y creo que no debe ser el único que lucha con los redondeos. El problema es que me genera gran cantidad de descuadres en contabilización y totalizaciones. ¿Una ayudita?

Neftali [Germán.Estévez] 27-02-2025 13:19:43

A ver si esto te ayuda:
https://docwiki.embarcadero.com/RADS...nding_Routines

Hay otros redondeos en Delphi.

Si buscas en los foros también encontrarás hilos antiguos donde hemos hablado de esto.

afxe 27-02-2025 13:55:33

Gracias Neftali.

Todas las operaciones en delphi están controladas. Los rendondeos los hace correctamente. El problema lo tengo en una vista de firebird, (CREATE VIEW) en SQL. La vista saca totalizada las bases, descuentos, cuotas de iva, cuotas de recargo y el total de la linea. Necesito que la vista saque correctamente el redondeo. Cuando hay un importe con #.#5 y le aplico un 10% de descuento, o un 10% de IVA, el redondeo lo hace como quiere, probad esto:

Código SQL [-]
select ROUND(174.55 * 10/100, 2) from rdb$database

Devuelve 17.45. No puedo usar las librerías de delphi en SQL. (bajo programa los redondeos están controlados, uso math.simpleRoundTo, o la funcion MyRound que copie de "Casimiro" ).

El problema lo tengo en las consultas estadísticas y ahora en contabilidad, que no me coincide la base + iva con el total. Antes tenía grabada la cuota de iva calculada por delphi.... un campo por cada base, porc_iva, cuota, porc_rec y recargo: con 3 tipos de IVA tenía 15 campos... lo quité cuando empezaron con el 5%, 2%, 7.5%.... demasiados campos inútiles a la larga.... ahora sólo tengo base_imponible y total_Factura. Cuando necesito el desglose de IVA lo saco de una VIEW.... EMPEZARON LOS PROBLEMAS. El total de la vista no coincide con el total factura.

chenech 27-02-2025 14:31:38

Prueba así a ver:
Código:

CAST(SUM(PVP * UNIDADES) AS NUMERIC(9, 2)) AS BASE,
CAST(SUM((PVP * UNIDADES) * IVA / 100) AS NUMERIC(9, 2)) AS IMPIVA,
CAST(CAST(SUM(PVP * UNIDADES) AS NUMERIC(9, 2)) + CAST(SUM((PVP * UNIDADES) * IVA / 100) AS NUMERIC(9, 2)) AS NUMERIC(9, 2)) AS TOTAL


Casimiro Notevi 27-02-2025 15:03:58

Sería necesario saber exactamente qué datos tienes en ese campo, porque no me cuadra que no redondee correctamente, jamás tuve ese problema.

fjcg02 28-02-2025 08:11:50

Prueba esto....

Código SQL [-]
SELECT
TOT.CODIGO,
TOT.PORC_IVA,
TOT.BASE * TOT.PORC_IVA/100 AS CUOTA_1,
round( TOT.BASE * TOT.PORC_IVA/100, 2) AS CUOTA_2,
FROM
  (
    SELECT 
    A.CODIGO, 
    D.PORC_IVA, 
    SUM(D.IMPORTE_VENTA) AS BASE
    FROM CAB_VENTAS A LEFT JOIN DET_MOVIMIENTOS D ON A.TIPO_DOCUMENTO = D.TIPO_CABECERA AND A.CODIGO = D.COD_CABECERA
    where a.codigo = 939006
    GROUP BY A.CODIGO, D.PORC_IVA
   ) TOT

Saludos

mamcx 28-02-2025 15:24:15

Cita:

Empezado por afxe (Mensaje 562326)
Código SQL [-]
select ROUND(174.55 * 10/100, 2) from rdb$database

Sqlite da 17.45, Postgres 17.46.

Esto es algo que hay considerar:

* No asumas que tipo de datos es un literal ('174.55') sin leer la documentación
* Hacer a ciegas ` AS NUMERIC(9, 2)` hace un `cast` que cuando es de `alto a bajo` es un `corte`. Osea es malo. No es redondear!
* Cuando tienes datos que se trabajan en multiples lenguajes/bd asegurare que *realmente* estan verdaderamente alineados. que son tipos realmente *equivalentes* en vez de ser *similares*. Fíjate en los docs que tengan los mismo exactos rangos.


Por ultimo, yo considero que siempre tienes que tener una UNICA fuente de LA VERDAD. O haces redondeos siempre en Firebird, o siempre en Delphi. En mi caso, yo guardo todo los datos calculados en la bd (ie: Los cálculos los hago siempre en Rust, en vez de en Postgres), ya que hay reglas dinámicas para determinar cuando se aplica o no los impuestos (antes o después de los descuentos por ejemplo), así que no puedo hacer cálculos simples en la bd:



Código SQL [-]
    price       DECIMAL NOT NULL DEFAULT 0,
    cost        DECIMAL NOT NULL DEFAULT 0,
    qty         DECIMAL NOT NULL DEFAULT 0,

    tax_percent   DECIMAL NOT NULL DEFAULT 0,
    tax_total   DECIMAL NOT NULL DEFAULT 0,

    discount_percent    DECIMAL NOT NULL DEFAULT 0,
    discount_value DECIMAL NOT NULL DEFAULT 0,

    sub_total   DECIMAL NOT NULL DEFAULT 0,
    total       DECIMAL NOT NULL DEFAULT 0,

Y nunca hago `ROUND` en la bd, porque eso es en mi opinion 'presentacional', ósea, es algo que se configura similar a cual idioma y cual símbolo de moneda se usa. Todo es exacto en la bd (nota como yo no pongo un corte de cuantos decimales aquí, que es un problema el día que tengas que manejar varios países. Japón por ejemplo no usa decimales!) y a la hora de `reportes` se toma esa decisión.

afxe 03-03-2025 14:39:01

Cita:

Empezado por fjcg02 (Mensaje 562342)
Prueba esto....

Código SQL [-]
SELECT
TOT.CODIGO,
TOT.PORC_IVA,
TOT.BASE * TOT.PORC_IVA/100 AS CUOTA_1,
round( TOT.BASE * TOT.PORC_IVA/100, 2) AS CUOTA_2,
FROM
  (
    SELECT 
    A.CODIGO, 
    D.PORC_IVA, 
    SUM(D.IMPORTE_VENTA) AS BASE
    FROM CAB_VENTAS A LEFT JOIN DET_MOVIMIENTOS D ON A.TIPO_DOCUMENTO = D.TIPO_CABECERA AND A.CODIGO = D.COD_CABECERA
    where a.codigo = 939006
    GROUP BY A.CODIGO, D.PORC_IVA
   ) TOT

Saludos

Sigue sin funcionar....

afxe 03-03-2025 15:05:21

Cita:

Empezado por mamcx (Mensaje 562347)
Sqlite da 17.45, Postgres 17.46.

Por ultimo, yo considero que siempre tienes que tener una UNICA fuente de LA VERDAD. O haces redondeos siempre en Firebird, o siempre en Delphi. En mi caso, yo guardo todo los datos calculados en la bd (ie: Los cálculos los hago siempre en Rust, en vez de en Postgres), ya que hay reglas dinámicas para determinar cuando se aplica o no los impuestos (antes o después de los descuentos por ejemplo), así que no puedo hacer cálculos simples en la bd:

Y nunca hago `ROUND` en la bd, porque eso es en mi opinion 'presentacional', ósea, es algo que se configura similar a cual idioma y cual símbolo de moneda se usa. Todo es exacto en la bd (nota como yo no pongo un corte de cuantos decimales aquí, que es un problema el día que tengas que manejar varios países. Japón por ejemplo no usa decimales!) y a la hora de `reportes` se toma esa decisión.

Supongo que tienes razón, tendré que totalizar en delphi cada vez que necesite las totalizaciones o crear nuevas tablas para grabar esas totalizaciones y no penalizar en tiempo. Tenía un Store Procedure (proc_totaliza_cab_ventas) que me devolvía una tabla con los totales por bases (bases, descuento, cuotas de iva, cuotas de recargo y total). Obtenía la información bastante rápido... pero con esos descuadres de céntimos. A currar....

Gracias a todos por vuestro interés.


La franja horaria es GMT +2. Ahora son las 15:24:20.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi