Página 1 de 2

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 09:08
por luiz53
Alguém fez a função de arredondamento ABNT ???

ARREDONDAMENTO ABNT (SAT)

Enviado: 21 Set 2016 10:14
por Kapiaba
http://www.projetoacbr.com.br/forum/top ... ento-abnt/

Código: Selecionar todos

FUNCTION Round_ABNT(nValor,nDecimais)


   LOCAL nRetorno:=nValor, cDecimais:=SubStr(Str(nValor),At('.',Str(nValor))+1), nSubsequente:=nDecimais+1
   
   if nDecimais<1
      RETURN Int(nRetorno)
   endif


   if Len(cDecimais) <= nDecimais
      RETURN nRetorno
   endif
   
   if SubStr(cDecimais,nSubsequente,1)>'5' .or. SubStr(cDecimais,nSubsequente,1)<'5' //Se a casa decimal SUBSEQUENTE for DIFERENTE de 5
      nRetorno:=Round(nValor,nDecimais)                                              //ARREDONDA
    elseif SubStr(cDecimais,nSubsequente,1)=='5'                                     //Se a casa decimal SUBSEQUENTE for IGUAL a 5
      if Mod(Val(SubStr(cDecimais,nDecimais,1)),2) <> 0                              //Se a casa decimal que será CONSERVADA, for IMPAR
         nRetorno:=Round(nValor,nDecimais)                                           //ARREDONDA
       else                                                                          //se a casa decimal que será CONSERVADA, for PAR
         if Val(SubStr(cDecimais,nSubsequente+1,1)) > 0                                //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
            nRetorno:=Round(nValor,nDecimais)                                        //ARREDONDA
          else                                                                       //Se APÓS a casa decimal SUBSEQUENTE, não houver NENHUM outro algarismo ou TODOS forem iguais a ZERO
            nRetorno:=Truncate(nValor,nDecimais)                                     //TRUNCA (Esse é o único momento em que o "arredondamento ABNT" se diferencia do "arredondamento normal")
         endif
      endif
   endif
   
RETURN nRetorno

FUNCTION Truncate(nValor,nDecimais)


   LOCAL nRetorno:=nValor, cDecimais:=SubStr(Str(nValor),At('.',Str(nValor))+1)
   
   if nDecimais<1
      RETURN Int(nRetorno)
   endif
   
   if Len(cDecimais) <= nDecimais
      RETURN nRetorno
   endif
   
   nRetorno:=Val( Str(Int(nValor))+'.'+SubStr(cDecimais,1,nDecimais) )


RETURN nRetorno

ARREDONDAMENTO ABNT (SAT)

Enviado: 21 Set 2016 10:36
por luiz53
Como sempre o Kapiada é muito prestativo, Obrigado ...

Fiz um teste com essa rotina e com a minha que havia feito e ambas estão truncando o valor desse calculo. :
0.299 x 8.98 = 2,68502 (2.68)
só que no SAT o valor aceito é de 2.69


Minha rotina de Arredondamento :

Código: Selecionar todos


*******************************************************************************
FUNCTION NewROUND(f_val,f_dec)
*******************************************************************************
local dig18
local dig19
local dig20

local valor

default f_dec    := 2
if valtype(f_val) # "N"
   return f_val
endif

        valor := str(f_val,20,4)
        if right(valor,2) != '00'
            dig18 := substr(valor,18,1)
            dig19 := substr(valor,19,1)
            dig20 := substr(valor,20,1)
            if dig19 == '5' .and. isPar(val(dig18))
               if dig20 == '0'
                  valor := str(xround(f_val,f_dec),20,f_dec)
               else
                  valor := str( round(f_val,f_dec),20,f_dec)
               endif
            else
               valor := str( round(f_val,f_dec),20,f_dec)
            endif
        endif

return val(valor)
*******************************************************************************
FUNCTION isPar(VALOR)
*******************************************************************************
RETURN if( valor % 2 == 0,.t.,.f.)


ARREDONDAMENTO ABNT (SAT)

Enviado: 21 Set 2016 11:12
por Kapiaba

Código: Selecionar todos

#include "FiveWin.ch"  // I LOVE THIS
 
static oWnd
 
#xtranslate round(<nVal>,<nDec>) => val(str(<nVal>,20,<nDec>))
 
FUNCTION Main()
 
   local oBar
 
   DEFINE WINDOW oWnd TITLE "TestE Round() Harbour and xHarbour: Perfect!"
 
   DEFINE BUTTONBAR oBar _3D OF oWnd
 
   DEFINE BUTTON OF oBar ACTION Test_Round()
 
   SET MESSAGE OF oWnd TO "TestE Round()" NOINSET CLOCK DATE KEYBOARD
 
   ACTIVATE WINDOW oWnd
 
RETURN NIL
 
FUNCTION Test_Round()
 
   LOCAL nImp, qt, preco, nNewImp, nNewValor
 
   nNewValor := 0
   nImp      := 0.00
   qt        := 0.299
   preco     := 8.98
 
   //nImp := Round(  (qt * preco) , 2 )
 
   nImp := ( ROUND( qt, 2 ) ) * ( ROUND( preco, 2 ) )
 
   ? ROUND( nImp, 2 )
 
   ? Str( Round( nImp, 2 ), 12, 6 )  // veja como apresenta aqui
 
   nImp := Round(Val(StrZero(preco*qt,12,2)),4)
 
   ? ROUND( nImp, 2)
 
   nNewImp := PADR( nImp, 6 )
 
   nImp := VAL( PADR( nNewImp, 6 ) )
 
   nNewValor := ROUND( nImp, 2 )
 
   ? nNewValor  // assim retorna correto
 
RETURN NIL

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 14:49
por asimoes
Olá,

Temos estas funções em C, não sei se vai lhe atender

Código: Selecionar todos

#include "extend.api"
#include "stdlib.h"
#include "string.h"
#include "math.h"


#define SOMA          0
#define SUBTRACAO     1
#define MULTIPLICACAO 2
#define DIVISAO       3
#define PRECISAO     20

double par1, par2;
int decimal;
char result[21];

void do_oper(int oper)
  {double r1, err;
   int dec, sig, aux;
   char err_c[PRECISAO+1];
   strcpy(err_c, "0.");
   aux = decimal;
   while(aux != 0)
     {strcat(err_c, "0");
      aux--;
     }
   strcat(err_c, "1");
   err = atof(err_c);
   switch(oper)
     {case SOMA:
        r1 = par1 + par2;
        break;
      case SUBTRACAO:
        r1 = par1 - par2;
        break;
      case MULTIPLICACAO:
        r1 = (par1 * par2);
        break;
      case DIVISAO:
        r1 = (par1 / par2);
        break;
     }
   if(r1 > 0)
      r1 += err;
   else
      r1 -= err;
   strcpy(result, ecvt(r1, PRECISAO, &dec, &sig));
   if(dec<1)
     {char ret[PRECISAO+1];
      if( ((sig!=0)&&(dec<2-PRECISAO)) || ((sig==0)&&(dec<1-PRECISAO)) || (dec<=-(decimal)) )
        {strcpy(ret, "0.");
         if(decimal>0)
           {aux = decimal;
            while(aux>0)
              {strcat(ret, "0");
               aux--;}
           }
         strcpy(result, ret);
        }
      else
        {strcpy(ret, "0.");
         aux = dec;
         while(aux<0)
           {strcat(ret, "0");
            aux++;
           }
         strncat(ret, result, decimal+dec);
         strcpy(result, ret);
         if(sig!=0)
           {strcpy(ret, "-");
            strncat(ret, result, PRECISAO-1);
            strcpy(result, ret);
           }
        }
     }
   else
     {if( ((sig==0)&&(dec>PRECISAO)) || ((sig!=0)&&(dec>PRECISAO-1)) )
        {strcpy(result, "*");
         aux = PRECISAO-1;
         while(aux>0)
           {strcat(result, "*");
            aux--;
           }
        }
      else
        {char ret1[PRECISAO+1], ret2[PRECISAO+1];
         strcpy(ret1, "");
         strncat(ret1, result, dec);
         if((sig==0)&&(dec>(PRECISAO-2)) || ((sig!=0)&&(dec>(PRECISAO-3))))
            strcpy(result, ret1);
         else
           {strcat(ret1, ".");
            strcpy(ret2, " ");
            strncat(ret2, result, PRECISAO-1);
            memmove(ret2, ret1, dec+1);
            strcpy(result, "");
            strncat(result, ret2, dec+1+decimal);
           }
         if(sig!=0)
           {strcpy(ret1, "-");
            strncat(ret1, result, PRECISAO-1);
            strcpy(result, ret1);
           }
        }
     }
   return;
  }

HB_FUNC (C_SUM)
  {if(HB_ISCHAR(1))
      par1 = atof(_parc(1));
   else
      par1 = _parnd(1);

   if(HB_ISCHAR(2))
      par2 = atof(_parc(2));
   else
      par2 = _parnd(2);

   if(PCOUNT == 3)
     {decimal = _parni(3);
      if(decimal > 10)
         decimal = 10;
      else if(decimal < 0)
         decimal = 0;
     }
   else
      decimal = 2;

   do_oper(SOMA);

   _retc(result);}

HB_FUNC (C_SUB)
  {if(HB_ISCHAR(1))
      par1 = atof(_parc(1));
   else
      par1 = _parnd(1);

   if(HB_ISCHAR(2))
      par2 = atof(_parc(2));
   else
      par2 = _parnd(2);

   if(PCOUNT == 3)
     {decimal = _parni(3);
      if(decimal > 10)
         decimal = 10;
      else if(decimal < 0)
         decimal = 0;
     }
   else
      decimal = 2;

   do_oper(SUBTRACAO);

   _retc(result);}

HB_FUNC (C_MULT)
  {if(HB_ISCHAR(1))
      par1 = atof(_parc(1));
   else
      par1 = _parnd(1);

   if(HB_ISCHAR(2))
      par2 = atof(_parc(2));
   else
      par2 = _parnd(2);

   if(PCOUNT == 3)
     {decimal = _parni(3);
      if(decimal > 10)
         decimal = 10;
      else if(decimal < 0)
         decimal = 0;
     }
   else
      decimal = 2;

   do_oper(MULTIPLICACAO);

   _retc(result);}

HB_FUNC ( C_DIV )
  {if(HB_ISCHAR(1))
      par1 = atof(_parc(1));
   else
      par1 = _parnd(1);

   if(HB_ISCHAR(2))
      par2 = atof(_parc(2));
   else
      par2 = _parnd(2);

   if(par2==0)
     {printf("Erro de divisao por zero!");
      exit(0);
     }
   else
     {if(PCOUNT == 3)
        {decimal = _parni(3);
         if(decimal > 10)
            decimal = 10;
         else if(decimal < 0)
            decimal = 0;
        }
      else
         decimal = 2;

      do_oper(DIVISAO);

      _retc(result);
     }
  }

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 16:44
por Jairo Maia
Olá Pessoal,

O SAT trabalha com as duas formas: Arredondamento e Truncamento.

Para Combustíveis, a tag indRegra no grupo do produto deve ser T, e o truncamento com 3 casas. Para todos os demais produtos a tag indRegra será A e o arredondamento com 2 casas. Para isso basta como já foi dito usar: Round( ( nValorUnitario X nQuantidade ), 2 ).

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 16:55
por luiz53
OBRIGADO PELA AJUDA A TODOS....

JAIRO
O produtos que estou vendendo é PRODUTO de AÇOUGUE, feirinha COM 3 casas decimais APENAS NAS QUANTIDADE ( indRegra = 'A' )
SÓ que se uso o arredondamento ABNT para este valor 0.299 x 8.98 = (2,68 ABNT) mas o SAT ACEITA APENAS 2.69
entendeu ????

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 17:18
por Jairo Maia
Olá Luiz,

Penso que entendi, mas acho que há confusão ai. Pela ABNT, arredondamentos entre 0 a 4 arredonda para baixo, 5 a 9 arredonda para cima. Exatamente isso que essa função faz: Round( ( nValorUnitario X nQuantidade ), 2 ):

Código: Selecionar todos

Function Main()
 
 Local nValorItem := 0.299
 Local nQuantidade := 8.98
 
 ? Round( ( nValorItem * nQuantidade ), 2 )  // retorna 2.69
 
Return Nil

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 18:05
por luiz53
Jairo muito Obrigado pela atenção...
Conversei com a DIMEP e consegui a solução....
Usando a função do KAPIABA apenas com uma alterção

Código: Selecionar todos

*******************************************************************************
FUNCTION Round_ABNT(nValor,nDecimais)
*******************************************************************************
LOCAL nRetorno    := nValor
LOCAL cDecimais   := SubStr(Str(nValor),At('.',Str(nValor))+1)
LOCAL nSubsequente:= nDecimais+1

if nDecimais<1
   RETURN Int(nRetorno)
endif

if Len(cDecimais) <= nDecimais
   RETURN nRetorno
endif

if     SubStr(cDecimais,nSubsequente,1)>'5' .or. SubStr(cDecimais,nSubsequente,1)<'5' //Se a casa decimal SUBSEQUENTE for DIFERENTE de 5
       nRetorno:=nRound(nValor,nDecimais)                                             //ARREDONDA
elseif SubStr(cDecimais,nSubsequente,1)=='5'                                          //Se a casa decimal SUBSEQUENTE for IGUAL a 5
       if Mod(Val(SubStr(cDecimais,nDecimais,1)),2) <> 0                              //Se a casa decimal que será CONSERVADA, for IMPAR
          nRetorno:=nRound(nValor,nDecimais)                                          //ARREDONDA
       else
//        if Val(SubStr(cDecimais,nSubsequente+1,1)) > 0                              //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
          if Val(SubStr(cDecimais,nSubsequente+1)) > 0                                //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
             nRetorno:=nRound(nValor,nDecimais)                                       //ARREDONDA
          else                                                                        //Se APÓS a casa decimal SUBSEQUENTE, não houver NENHUM outro algarismo ou TODOS forem iguais a ZERO
             nRetorno:=Truncate(nValor,nDecimais)                                     //TRUNCA (Esse é o único momento em que o "arredondamento ABNT" se diferencia do "arredondamento normal")
          endif
       endif
endif

RETURN nRetorno


Imagem

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 18:30
por Jairo Maia
Olá Luiz,

Permita-me um pouco mais nesse assunto, pois é interessante.

Na figura que você postou, na célula 3, valia na normatização ABNT de 1977. Ocorre que para compatibilidade com a realidade de computadores, foi alterada pela ABNT a norma de Arredondamento em dezembro de 2014, com vigor a partir de janeiro 2015, já que era a realidade principalmente em planilhas.

Assim, na nova normatização se arredondar 4,885000 será 4,89, pois o ultimo digito após o digito verificador 8 é 5.

Arredondamento ABNT (SAT)

Enviado: 21 Set 2016 19:23
por luiz53
Agradeço pela ajuda...
VOU FAZER UM TESTE NO SAT para verificar essa possibilidade...
ai EU POSTO aqui o RESULTADO....

Arredondamento ABNT (SAT)

Enviado: 22 Set 2016 10:21
por luiz53
Jairo...
Acabei de fazer TESTE NO SAT DIMEP - ELGIN - KRYPTUS...
todos eles fizeram o arredondamento ABNT igual esta na IMAGEM..
EXEMPLO 3
4.885000 - ficou 4.88

Imagem

Arredondamento ABNT (SAT)

Enviado: 22 Set 2016 11:57
por asimoes
Essa regra de arredondamento é muito esquisita, enfim no brasil as coisas são estranhas mesmo.

Arredondamento ABNT (SAT)

Enviado: 22 Set 2016 12:14
por Jairo Maia
Olá Pessoal,
asimoes escreveu:Essa regra de arredondamento é muito esquisita, enfim no brasil as coisas são estranhas mesmo.
rs... Pois é. Em se tratando de aplicativo fiscal então nem se fala...
luiz53 escreveu:todos eles fizeram o arredondamento ABNT igual esta na IMAGEM..
Não entendi essa parte. o SAT não faz arredondamento nenhum, ele apenas verifica se os valores da soma dos itens estão corretos com o valor total do cupom, e se a forma de pagamento foi com valor igual ou superior a soma do cupom.

Quando você monta o XML, é seu sistema que arredonda ou trunca os valores, e envia para o SAT. Então o SAT verifica conforme o Schema.

Você usa o ACBrMonitor ou seu módulo para emissão do SAT é próprio?

Arredondamento ABNT (SAT)

Enviado: 22 Set 2016 13:39
por luiz53
JAIRO
Nao uso ACBR ... uso UMA CLASSE PRÓPRIA.
Quis dizer que se eu usar o arredondamento ROUND( ) o valor a ser pago sera diferente do valor calculado pelo SCHEMA do SAT....