Ir para conteúdo
  • Cadastre-se

dev botao

ACBrNFSeX - erro "Unexpected character ' ' (code 32)" no provedor BHISS (POA/RS)


Ver Solução Respondido por Italo Giurizzato Junior,
  • Este tópico foi criado há 389 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

  • Membros Pro

Prezados boa tarde.

Ao enviar um lote de RPS para prefeitura de Porto Alegre/RS, onde a razão social do tomador contém "&" (E comercial), o webservice do provedor retorna o erro:

<MensagemRetorno>
  <Codigo>0</Codigo>
  <Mensagem>Ocorreu um erro Inesperado. (Unexpected character ' ' (code 32) (missing name?) at [row,col {unknown-source}]: [1,882])</Mensagem>
</MensagemRetorno>

O problema aqui é que o conteúdo do campo <nfseDadosMsg> é escapado, onde os caracteres "<" e ">" são substituídos por "&lt;" e "&gt;", mas o caractere "&" não é escapado, e portanto causa erro na desserialização do XML no servidor.

Encontramos um erro semelhante sendo reportado para o ACBrNFSe em 2014:

Corrigimos o problema na unit BHISS.Provider.pas, em anexo. Para não afetar outros municípios (ex.: BH), deixamos retrocompatível com a introdução do param EscaparSoapDadosMsg, configurado no ACBrNFSeXServicos.ini (em anexo) para Porto Alegre/RS. Caso achem esse param desnecessário, e preferirem que o caractere & seja sempre escapado nesse provedor, me avisem que eu removo o param.

Poderiam avaliar e integrar as alterações no trunk, por gentileza?

 

ACBrNFSeXServicos.ini BHISS.Provider.pas

logoDW.png.043cb4b50e3275dc9614c728eb3fa617.png

Guilherme Costa

 

Link para o comentário
Compartilhar em outros sites

  • Consultores

Boa tarde.

Primeiro de tudo, muito obrigado pela contribuição! Toda colaboração é e sempre será mais do que bem vinda!

Em sua contribuição, você adiciona uma função que faz o seguinte:

image.png

Se conferirmos na unit ACBrNFSeXGravarXml_ABRASFv1(classe base para a BHISS.GravarXml), é possível observar que ela insere no XML a Razão Social assim:

Result.AppendChild(AddNode(tcStr, '#38', 'RazaoSocial', 1, 115, 0,
                                       NFSe.Tomador.RazaoSocial, DSC_XNOME));

Conferindo dentro da estrutura de AddNode temos o seguinte trecho:

  // Grava a tag no arquivo - Quando existir algum conteúdo
  if ((ocorrencias = 1) or (not EstaVazio)) then
  begin
    Result := CreateElement(Tag);

    if ParseTextoXML then
      Result.Content := FiltrarTextoXML(FOpcoes.RetirarEspacos,
        ConteudoProcessado, FOpcoes.RetirarAcentos, True, FOpcoes.FQuebraLinha)
    else
      Result.Content := ConteudoProcessado;

    if (Atributo <> '') and (Result <> nil) then
    begin
      AttSplit := Split('=', Atributo);
      Result.SetAttribute(Trim(AttSplit[0]), Trim(AttSplit[1]));
    end;
  end;

Pela forma com é feita a chamada da AddNode, o parâmetro ParseTextoXML é igual a True, então ele vai passar pela function FiltrarTextoXML.

Dentro dela, temos o seguinte: 

function FiltrarTextoXML(const RetirarEspacos: boolean; aTexto: String;
  RetirarAcentos: boolean; SubstituirQuebrasLinha: Boolean;
  const QuebraLinha: String): String;
begin
  if RetirarAcentos then
     aTexto := TiraAcentos(aTexto);

  aTexto := ParseText(AnsiString(aTexto), False );

  if RetirarEspacos then
  begin
    while pos('  ', aTexto) > 0 do
      aTexto := FaststringReplace(aTexto, '  ', ' ', [rfReplaceAll]);
  end;

  if SubstituirQuebrasLinha then
    aTexto := ChangeLineBreak( aTexto, QuebraLinha);

  Result := Trim(aTexto);
end;

Conferindo o conteúdo da ParseText, a mesma já faz a substituição.

  if Decode then
  begin
    Astr := DecodeToString( Texto, IsUTF8 ) ;

    Astr := InternalStringReplace(AStr, '&amp;'   , '&');
    AStr := InternalStringReplace(AStr, '&lt;'    , '<');
    AStr := InternalStringReplace(AStr, '&gt;'    , '>');
    AStr := InternalStringReplace(AStr, '&quot;'  , '"');
    AStr := InternalStringReplace(AStr, '&#39;'   , #39);
    AStr := InternalStringReplace(AStr, '&#45;'   , '-');
    AStr := InternalStringReplace(AStr, '&aacute;', 'á');
    AStr := InternalStringReplace(AStr, '&Aacute;', 'Á');
    AStr := InternalStringReplace(AStr, '&acirc;' , 'â');
    AStr := InternalStringReplace(AStr, '&Acirc;' , 'Â');
    AStr := InternalStringReplace(AStr, '&atilde;', 'ã');
    AStr := InternalStringReplace(AStr, '&Atilde;', 'Ã');
    AStr := InternalStringReplace(AStr, '&agrave;', 'à');
    AStr := InternalStringReplace(AStr, '&Agrave;', 'À');
    AStr := InternalStringReplace(AStr, '&eacute;', 'é');
    AStr := InternalStringReplace(AStr, '&Eacute;', 'É');
    AStr := InternalStringReplace(AStr, '&ecirc;' , 'ê');
    AStr := InternalStringReplace(AStr, '&Ecirc;' , 'Ê');
    AStr := InternalStringReplace(AStr, '&iacute;', 'í');
    AStr := InternalStringReplace(AStr, '&Iacute;', 'Í');
    AStr := InternalStringReplace(AStr, '&oacute;', 'ó');
    AStr := InternalStringReplace(AStr, '&Oacute;', 'Ó');
    AStr := InternalStringReplace(AStr, '&otilde;', 'õ');
    AStr := InternalStringReplace(AStr, '&Otilde;', 'Õ');
    AStr := InternalStringReplace(AStr, '&ocirc;' , 'ô');
    AStr := InternalStringReplace(AStr, '&Ocirc;' , 'Ô');
    AStr := InternalStringReplace(AStr, '&uacute;', 'ú');
    AStr := InternalStringReplace(AStr, '&Uacute;', 'Ú');
    AStr := InternalStringReplace(AStr, '&uuml;'  , 'ü');
    AStr := InternalStringReplace(AStr, '&Uuml;'  , 'Ü');
    AStr := InternalStringReplace(AStr, '&ccedil;', 'ç');
    AStr := InternalStringReplace(AStr, '&Ccedil;', 'Ç');
    AStr := InternalStringReplace(AStr, '&apos;'  , '''');
  end
  else
  begin
    AStr := string(Texto);
    AStr := StringReplace(AStr, '&', '&amp;' , [rfReplaceAll]); //Aqui ele substitui o "e" comercial;
    AStr := StringReplace(AStr, '<', '&lt;'  , [rfReplaceAll]);
    AStr := StringReplace(AStr, '>', '&gt;'  , [rfReplaceAll]);
    AStr := StringReplace(AStr, '"', '&quot;', [rfReplaceAll]);
    AStr := StringReplace(AStr, #39, '&#39;' , [rfReplaceAll]);
    AStr := StringReplace(AStr, '''','&apos;', [rfReplaceAll]);
  end;

  Result := AStr;

Por favor, isso não está ocorrendo?

É possível fazer um teste? Se abrir o XML gerado no navegador e também em um editor de texto como o bloco de notas ou notepad++ ele ainda tem o & ?

  • Curtir 2
Consultor SAC ACBr

Diego Folieni
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil


Participe de nosso canal no Discord e fique ainda mais próximo da Comunidade !!

Link para o comentário
Compartilhar em outros sites

  • Consultores

Boa tarde Guilherme,

O erro esta ocorrendo ao enviar o XML do Rps ou ao tentar ler o XML de retorno?

Se o problema é o retorno, a linha para tratar o "&" você deve incluir na function: TratarXmlRetornado que se encontra na unit BHISS.Provider

  • Curtir 2
Consultor SAC ACBr

Italo Giurizzato Junior
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr

Analista de Sistemas / e-mail: [email protected] / Fone: (16) 9-9701-5030 / Araraquara-SP

Araraquara - A era dos Trólebus

Link para o comentário
Compartilhar em outros sites

  • Membros Pro

Obrigado pelo retorno rápido pessoal! :-)

Perdão se não fui claro...

1 hour ago, Diego Foliene said:

Se conferirmos na unit ACBrNFSeXGravarXml_ABRASFv1(classe base para a BHISS.GravarXml), é possível observar que ela insere no XML a Razão Social assim:

Diego, esse tratamento de escape está funcionando corretamente, na composição do XML do <GerarNfseEnvio>. O problema é na composição do SOAP envelope, onde esse XML é escapado (ou melhor dizendo, codificado) novamente, convertendo os "<" e ">" em "&lt;" e "&gt;", mas não convertendo o "&" em "&amp;". Minha alteração adiciona essa conversão do "&amp;" no XML do GerarNfseEnvio escapado, que fica contido na tag <nfseDadosMsg> do <soapenv:Body>.

 

8 minutes ago, Italo Giurizzato Junior said:

O erro esta ocorrendo ao enviar o XML do Rps ou ao tentar ler o XML de retorno?

É ao compor o XML do SOAP envelope, conforme descrevi acima.

 

Eis um exemplo de dois XML GerarNfseRequest, de um RPS com discriminação do serviço "TREINAMENTO P&D".

O XML da esquerda foi gerado com a minha correção. O XML da direita foi gerado sem ela.

clipboard-202303300343-hb9xk.thumb.png.4faf42b668898148e9b3afb82268ae59.png

Quando o webservice tenta decodificar o XML da direita, ele converte o "&amp;" para "&", e o parser do XML interpreta aquele "&" como se fosse o início de uma sequência de escape do XML (ex.: &nbsp;), mas na verdade é só o &.

  • Curtir 1

logoDW.png.043cb4b50e3275dc9614c728eb3fa617.png

Guilherme Costa

 

Link para o comentário
Compartilhar em outros sites

  • Consultores
  • Solution

Guilherme,

Experimenta trocar o XmlToStr que se encontra nas funções que montam o conteúdo do grupo Body por IncluirCDATA.

  • Curtir 2
Consultor SAC ACBr

Italo Giurizzato Junior
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr

Analista de Sistemas / e-mail: [email protected] / Fone: (16) 9-9701-5030 / Araraquara-SP

Araraquara - A era dos Trólebus

Link para o comentário
Compartilhar em outros sites

  • Membros Pro

Funcionou Italo! 😀

Seguindo essa abordagem, achas necessário criar um param extra no provedor (ex.: Param=SoapDadosMsgCdata:), para setar somente para POA/RS? Ou faço a alteração para todos os provedores?

Verifiquei no arquivo INI, e esse provedor é usado por Porto Alegre/RS e Belo Horizonte/MG.

  • Curtir 1

logoDW.png.043cb4b50e3275dc9614c728eb3fa617.png

Guilherme Costa

 

Link para o comentário
Compartilhar em outros sites

  • Consultores

Bom dia Guilherme,

Muito obrigado pelo retorno, já inclui na minha lista de tarefas para realizar a troca, pois acredito que não vai gerar efeito colateral para as outras cidades atendidas pelo mesmo provedor.

TK-3803

  • Curtir 1
Consultor SAC ACBr

Italo Giurizzato Junior
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr

Analista de Sistemas / e-mail: [email protected] / Fone: (16) 9-9701-5030 / Araraquara-SP

Araraquara - A era dos Trólebus

Link para o comentário
Compartilhar em outros sites

  • Este tópico foi criado há 389 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.
Visitante
Este tópico está agora fechado para novas respostas
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.