



Fala galera do Show Delphi, tudo beleza?
Este dias estava tendo problemas com o uma nota de consumidor emitida e os dados salvos.
Percebi que tinha um caso em que o valor total do item era 1,365.
Para a NFC-e ia 1,36 e para o banco 1,37.
As configurações era para arredondar.
Ai estudando percebi que o arredondamento interno utilizado era conforme a ABNT e neste caso 1,345 fica 1,34.
Exemplo
de 0 a 4 na segunda casa, 5 na terceira arredonda para baixo,
5 a 9 na segunda casa, 5 arredonda para cima.
Como meu procedimento estava no banco, precisei uma forma de fazer este arredondamento via SQL.
E no caso estava utilizando o Firebird.
Para minha sorte encontrei uma function para firebird 3.0 e uma stored procedure para firebird 2.5.
Então vamos ao código!
FUNCTION – PARA FIREBIRD 3.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | CREATE OR ALTER FUNCTION ROUNDABNT ( AVALOR DOUBLE PRECISION, ADECIMAIS SMALLINT) RETURNS DOUBLE PRECISION AS DECLARE variable cDecimais VARCHAR(100); DECLARE variable vlrstr VARCHAR(100); DECLARE variable nSubsequente SMALLINT; DECLARE variable posponto SMALLINT; BEGIN vlrstr = CAST(AVALOR AS VARCHAR(100)); posponto = POSITION('.',vlrstr); cDecimais = SUBSTRING(vlrstr FROM posponto+1 FOR CHAR_LENGTH(vlrstr)); nSubsequente = ADECIMAIS+1; IF (:ADECIMAIS < 1) THEN RETURN TRUNC(AVALOR); ELSE IF (CHAR_LENGTH(cDecimais) <= :ADECIMAIS) THEN RETURN AVALOR; ELSE BEGIN IF ((CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1) AS INTEGER) > 5) OR (CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1)AS DOUBLE PRECISION) < 5)) THEN RETURN ROUND(AVALOR,ADECIMAIS); ELSE IF (CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1)AS DOUBLE PRECISION) = 5) THEN IF (MOD(CAST(SUBSTRING(cDecimais FROM ADECIMAIS FOR 1)AS DOUBLE PRECISION) ,2) <> 0) THEN RETURN ROUND(AVALOR,ADECIMAIS); ELSE IF (CAST(SUBSTRING(cDecimais FROM nSubsequente+1 FOR 1)AS DOUBLE PRECISION) > 0) THEN RETURN ROUND(AVALOR,ADECIMAIS); ELSE RETURN TRUNC(AVALOR,ADECIMAIS); END END |
Exemplo de uso da function em firebird 3.0
1 2 3 4 5 6 7 8 9 10 | SELECT roundabnt(1.645, 2) AS exemplo1, roundabnt(1.655, 2) AS exemplo2, roundabnt(1.605, 2) AS exemplo3, roundabnt(1.605, 2) AS exemplo4 FROM rdb$database |
STORED PROCEDURE – PARA FIREBIRD 2.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | CREATE OR ALTER PROCEDURE SP_ROUNDABNT ( AVALOR DOUBLE PRECISION, ADECIMAIS SMALLINT) RETURNS ( VALOR DOUBLE PRECISION ) AS DECLARE VARIABLE CDECIMAIS VARCHAR(100); DECLARE VARIABLE VLRSTR VARCHAR(100); DECLARE VARIABLE NSUBSEQUENTE SMALLINT; DECLARE VARIABLE POSPONTO SMALLINT; BEGIN VLRSTR = CAST(AVALOR AS VARCHAR(100)); POSPONTO = POSITION('.',VLRSTR); CDECIMAIS = SUBSTRING(VLRSTR FROM POSPONTO+1 FOR CHAR_LENGTH(VLRSTR)); NSUBSEQUENTE = ADECIMAIS+1; IF (:ADECIMAIS < 1) THEN BEGIN VALOR = TRUNC(AVALOR); SUSPEND; exit; END ELSE IF (CHAR_LENGTH(CDECIMAIS) <= :ADECIMAIS) THEN BEGIN VALOR = AVALOR; SUSPEND; exit; END ELSE BEGIN IF ((CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1) AS INTEGER) > 5) OR (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) < 5)) THEN BEGIN VALOR = ROUND(AVALOR,ADECIMAIS); SUSPEND; exit; END ELSE IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) = 5) THEN BEGIN IF (MOD(CAST(SUBSTRING(CDECIMAIS FROM ADECIMAIS FOR 1)AS DOUBLE PRECISION) ,2) <> 0) THEN BEGIN VALOR = ROUND(AVALOR,ADECIMAIS); SUSPEND; exit; END ELSE IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE+1 FOR 1)AS DOUBLE PRECISION) > 0) THEN BEGIN VALOR = ROUND(AVALOR,ADECIMAIS); SUSPEND; exit; END ELSE BEGIN VALOR = TRUNC(AVALOR,ADECIMAIS); SUSPEND; exit; END END END END |
Fonte Base: https://www.projetoacbr.com.br/forum/topic/9709-minha-pequena-contribui%C3%A7%C3%A3o-arredondamento-abnt/
Exemplo de uso da stored procedure em firebird 2.5
1 2 3 4 5 6 7 8 9 10 | SELECT (SELECT a.valor FROM SP_ROUNDABNT(1.645, 2) a) AS exemplo1, (SELECT a.valor FROM SP_ROUNDABNT(1.655, 2) a) AS exemplo2, (SELECT a.valor FROM SP_ROUNDABNT(1.605, 2) a) AS exemplo3, (SELECT a.valor FROM SP_ROUNDABNT(1.605, 2) a) AS exemplo4 FROM rdb$database |
Pessoal, os códigos acima foram muito úteis para mim e espero que ajude a todos.
Um abraço e até a próxima.
Valeu!