ANDERSON JUNIOR GADO DA SILVA Postado 11 Junho Postado 11 Junho Ao tentar enviar um boleto pelo banco inter via api, ele precisa fazer uma consulta, essa consulta precisa alterar o scopo para *.read em vez de write, fiz uma justes vou enviar abaixo. function TBoletoW_Inter_API.Enviar: boolean; var LJsonObject : TACBrJSONObject; LOrigScope : String; begin Result := inherited Enviar; (* Tratamento automatico qdo tpINCLUI com pix. Entao ele vai enviar capturar a reposta para pegar o codigoSolicitacao e realizar uma consulta detalhe automaticamente para retornar o boleto com QrCODE *) if (Boleto.Cedente.CedenteWS.IndicadorPix) and (Boleto.Configuracoes.WebService.Operacao = tpInclui) then begin LJsonObject := TACBrJSONObject.Parse( FRetornoWS ); try if NaoEstaVazio(LJsonObject.AsString['codigoSolicitacao']) then begin ATitulo.NossoNumeroCorrespondente := LJsonObject.AsString['codigoSolicitacao']; Boleto.Configuracoes.WebService.Operacao := tpConsultaDetalhe; // Salva o scope original (boleto-cobranca.write) usado na criacao do boleto LOrigScope := Boleto.Cedente.CedenteWS.Scope; // Troca para scope de leitura: a API v3 do Inter exige boleto-cobranca.read // no endpoint GET de consulta detalhe, rejeitando tokens com scope write (HTTP 401) Boleto.Cedente.CedenteWS.Scope := 'boleto-cobranca.read'; try GerarDados; Result := inherited Enviar; finally // Restaura o scope original para nao afetar proximas operacoes Boleto.Cedente.CedenteWS.Scope := LOrigScope; end; end; finally LJsonObject.Free; Boleto.Configuracoes.WebService.Operacao := tpInclui; end; end; end;
Antonio Gomes Postado 12 Junho Postado 12 Junho Interessante, eu coloco ele todos de uma vez só e não gera problema, voce tentou?
ANDERSON JUNIOR GADO DA SILVA Postado 12 Junho Autor Postado 12 Junho (editado) eu fiz um teste com um boleto só, não sei se entendi a sua colocação, o erro que tive ao enviar apenas um registro foi falha na autenticação ao tentar executar a consulta, não tenho o log do acbr, mas basicamente reclamada da autenticação do scopo, ao fazer o ajuste foi resolvido, abaixou vou postar a minha rotina. function TBoletoEnviaWS.About: IDataStream; Var VBanco: IJSONValue; VCedente: IJSONValue; VTitulos: IJSONValue; VRequizicao: IJSONObject; VReturn: IReturn; VApelido: String; VRetry: Integer; begin try VRequizicao:=TJSONObject.New(FRequisicao); VBanco:=VRequizicao.Path('Banco'); VCedente:=VRequizicao.Path('Cedente'); VTitulos:=VRequizicao.Path('Titulos'); VApelido:=VRequizicao['banco_apelido'].AsString; VRetry := 0; repeat with TBoleto.Create(FPerfil, VApelido) do try VReturn:=RegistrarBoletosWS(VBanco, VCedente, VTitulos, VRequizicao.Get('scope', ''), FGeraPDF); if Assigned(FLogger) then FLogger.LogDebug(VReturn.AsString, 'TBoletoEnviaWS.About'); if VReturn.Fail and TemRateLimitNaResposta(VReturn) and (VRetry < C_INTER_RATE_LIMIT_MAX_RETRY) then begin Inc(VRetry); if Assigned(FLogger) then FLogger.LogDebug( Format('Rate limit detectado (HTTP 429). Aguardando %ds antes de retentar (tentativa %d/%d)...', [C_INTER_RATE_LIMIT_SLEEP_MS div 1000, VRetry, C_INTER_RATE_LIMIT_MAX_RETRY]), 'TBoletoEnviaWS.About' ); Sleep(C_INTER_RATE_LIMIT_SLEEP_MS); end else Break; finally Free; end; until VRetry >= C_INTER_RATE_LIMIT_MAX_RETRY; if VReturn.Fail then raise Exception.Create(VReturn.AsString); Result:=VReturn.Content; Except on E: Exception do begin if Assigned(FLogger) then FLogger.LogError(E.Message, 'TBoletoEnviaWS.About'); raise Exception.CreateFmt('Erro ao enviar por WS: %s', [E.Message]); end; end; end; e aqui a outra function TBoleto.RegistrarBoletosWS(const ABanco, ACedente, ATitulos: IJSONValue; const AScope: String; const ARetPDF: Boolean): IReturn; Var VSucesso: Boolean; VRetorno: IJSONObject; VRejeicao: IJSONObject; VListaBoletos: IJSONArray; I,J,Y: Integer; VPDF: IDataStream; begin VRetorno:=TJSONObject.New(); VListaBoletos:=TJSONArray.New(); ConfigInicial((ABanco as IJSONObject), (ACedente as IJSONObject)); Cedente.CedenteWS.Scope:=AScope; try case ATitulos.JSONType of TEnumJSONType.ejtArray: begin CriarTitulos(ATitulos as IJSONArray); end; TEnumJSONType.ejtObject: begin CriarTitulo(ATitulos as IJSONObject); end; end; Configuracoes.WebService.Operacao:=tpInclui; VSucesso:=Enviar; if TotalListaRetornoWeb > 0 then begin for I:= 0 to TotalListaRetornoWeb -1 do begin VRetorno:=TJSONObject.New(); VRetorno.Put('Cod_Retorno', ListaRetornoWeb[I].CodRetorno); VRetorno.Put('Msg_Retorno', ListaRetornoWeb[I].MsgRetorno); VRetorno.Put('Ori_Retorno', ListaRetornoWeb[I].OriRetorno); VRetorno.Put('HTTP_Result', ListaRetornoWeb[I].HTTPResultCode); VRetorno.Put('JSON', ListaRetornoWeb[I].JSON); VRejeicao:=TJSONObject.New(); for J:= 0 to ListaRetornoWeb[I].ListaRejeicao.Count - 1 do begin VRejeicao.Put(J.ToString, TJSONObject.New() .Put('Campo', ListaRetornoWeb[i].ListaRejeicao[j].Campo) .Put('Codigo', ListaRetornoWeb[i].ListaRejeicao[j].Codigo) .Put('Versao', ListaRetornoWeb[i].ListaRejeicao[j].Versao) .Put('Mensagem', ListaRetornoWeb[i].ListaRejeicao[j].Mensagem) .Put('Ocorrencia', ListaRetornoWeb[i].ListaRejeicao[j].Ocorrencia) .Put('Valor', ListaRetornoWeb[i].ListaRejeicao[j].Valor) ); end; VRetorno.Put('Rejeicao', VRejeicao); VRetorno.Put('Header', TJSONObject.New() .Put('Versao', ListaRetornoWeb[i].Header.Versao) .Put('Autenticacao', ListaRetornoWeb[i].Header.Autenticacao) .Put('Usuario_Servico', ListaRetornoWeb[i].Header.Usuario_Servico) .Put('Usuario', ListaRetornoWeb[i].Header.Usuario) .Put('Operacao', TipoOperacaoToStr(ListaRetornoWeb[i].Header.Operacao)) .Put('Indice', ListaRetornoWeb[i].Header.Indice) .Put('Sistema_Origem', ListaRetornoWeb[i].Header.Sistema_Origem) .Put('Agencia', ListaRetornoWeb[i].Header.Agencia) .Put('ID_Origem', ListaRetornoWeb[i].Header.Id_Origem) .Put('Data_Hora', ListaRetornoWeb[i].Header.Data_Hora) .Put('ID_Processo', ListaRetornoWeb[i].Header.Id_Processo) .Put('Excessao', ListaRetornoWeb[i].DadosRet.Excecao) .Put('Origem_Retorno', ListaRetornoWeb[i].DadosRet.ControleNegocial.OriRetorno) .Put('NSU', ListaRetornoWeb[i].DadosRet.ControleNegocial.NSU) .Put('Cod_Retorno', ListaRetornoWeb[i].DadosRet.ControleNegocial.CodRetorno) .Put('Msg_Retorno', ListaRetornoWeb[i].DadosRet.ControleNegocial.Retorno) .Put('Data', ListaRetornoWeb[i].DadosRet.Comprovante.Data) .Put('Hora', ListaRetornoWeb[i].DadosRet.Comprovante.Hora) .Put('Codigo_Barras', ListaRetornoWeb[i].DadosRet.IDBoleto.CodBarras) .Put('Linha_Digitavel', ListaRetornoWeb[i].DadosRet.IDBoleto.LinhaDig) .Put('Nosso_Numero', ListaRetornoWeb[i].DadosRet.IDBoleto.NossoNum) .Put('URL', ListaRetornoWeb[i].DadosRet.IDBoleto.URL) .Put('Numero_Documento', ListaRetornoWeb[i].DadosRet.TituloRet.NumeroDocumento) .Put('Data_Vencimento', ListaRetornoWeb[i].DadosRet.TituloRet.Vencimento) .Put('Valor', ListaRetornoWeb[i].DadosRet.TituloRet.ValorDocumento) ); if not ListaRetornoWeb[i].DadosRet.TituloRet.CodBarras.IsEmpty then begin VRetorno.Put('Titulo', TJSONObject.New() .Put('vencimento_titulo', ListaRetornoWeb[i].DadosRet.TituloRet.Vencimento) .Put('tipo_carteira_titulo', ListaRetornoWeb[i].DadosRet.TituloRet.Carteira) .Put('nosso_numero', ListaRetornoWeb[i].DadosRet.TituloRet.NossoNumero) .Put('seu_numero', ListaRetornoWeb[i].DadosRet.TituloRet.SeuNumero) .Put('especie', ListaRetornoWeb[i].DadosRet.TituloRet.EspecieDoc) .Put('codigo_barras', ListaRetornoWeb[i].DadosRet.TituloRet.CodBarras) .Put('numero_linha_digitavel', ListaRetornoWeb[i].DadosRet.TituloRet.LinhaDig) .Put('local_pagamento', ListaRetornoWeb[i].DadosRet.TituloRet.Mensagem.Text) .Put('data_processamento', ListaRetornoWeb[i].DadosRet.TituloRet.DataProcessamento) .Put('data_emissao', ListaRetornoWeb[i].DadosRet.TituloRet.DataDocumento) .Put('uso_banco', ListaRetornoWeb[i].DadosRet.TituloRet.UsoBanco) .Put('valor_titulo', ListaRetornoWeb[i].DadosRet.TituloRet.ValorDocumento) .Put('valor_desconto', ListaRetornoWeb[i].DadosRet.TituloRet.ValorDesconto) .Put('valor_outra_deducao', ListaRetornoWeb[i].DadosRet.TituloRet.ValorDespesaCobranca) .Put('valor_juro_multa', ListaRetornoWeb[i].DadosRet.TituloRet.ValorMoraJuros) .Put('valor_outro_acrescimo', ListaRetornoWeb[i].DadosRet.TituloRet.ValorOutrosCreditos) .Put('valor_total_cobrado', ListaRetornoWeb[i].DadosRet.TituloRet.ValorPago) .Put('texto_informacao_cliente_beneficiario', ListaRetornoWeb[i].DadosRet.TituloRet.Informativo.Text) ); //localizar o titulo na lista de retornos e alterar a propriedade nosso numero, no momento isso só testado no banco inter if Banco.TipoCobranca = cobBancoInter then begin Y:=ListadeBoletos.IndexOfSeuNumero(ListaRetornoWeb[i].DadosRet.TituloRet.SeuNumero); if Y > -1 then begin ListadeBoletos[Y].NossoNumero:=ListaRetornoWeb[i].DadosRet.TituloRet.NossoNumero; end; end; end; VListaBoletos.Put(VRetorno); end; end; VPDF:=TDataStream.New; if ARetPDF then begin GeraBoletoPDF(VPDF, FLayoutImpressao); end; Result:=TReturn.New( VSucesso, TJSONObject.New() .Put('Retorno', VListaBoletos) .Put('PDF', VPDF) ); except on E: Exception do begin Result:=TReturn.New(False, 'Erro ao enviar boletos ws: '+E.Message); raise Exception.CreateFmt('Erro ao enviar boletos ws: %s', [E.Message]); end; end; end; Editado 12 Junho por ANDERSON JUNIOR GADO DA SILVA Complementação
ANDERSON JUNIOR GADO DA SILVA Postado 24 Junho Autor Postado 24 Junho @Antonio Gomes uma pergunta, quando o boleto retorna com status "EM_PROCESSAMENTO" como você procede ? Att.
Antonio Gomes Postado 25 Junho Postado 25 Junho 15 horas atrás, ANDERSON JUNIOR GADO DA SILVA disse: @Antonio Gomes uma pergunta, quando o boleto retorna com status "EM_PROCESSAMENTO" como você procede ? Att. então, na primeira batida da api eu ja vou no titulo a receber e gravo o codigo de solicitação. A partir dai, se tem esse codigo, eu entro no bloco de envio antes mando consultar, e analiso o retorno, e nao entra mais no bloco de enviar, somente se tiver um retorno negativo lá, tipo, boleto cancelado (usuario pode entrar no portal e cancelar o boleto), entao eu cancelo meu processo dentro do titulo, e sigo para emissao normal. Ao terminar o bloco de enviar, se o banco pede consulta (eu parametrizo no cadastro da conta, se tem consulta apos enviar) eu já mando consultar se teve o boleto gerado, pois nem sempre vem no mesmo comando de envio. Costuma dar uns timeout brabo nessas api. Trate seu codigo pelo codigo do banco: 756 (sicoob), 001 (bb) vc gera o nosso numero, a consulta já nao é pelo codigo correspondente, mas pelo numero do boleto que voce incrementou e salvou no seu receber. Os que retornam um codigo antes, como em inclusao, inter e C6, são esses 4 api que trato. Valeria a pena até haver isso no documento que tem no acbr. Qual retorna codigo correspondente, para mandar consultar correto. Ou vai esse codigo ou vai o nosso numero.
Recommended Posts
Crie uma conta ou entre para comentar
Você precisar ser um membro para fazer um comentário
Criar uma conta
Crie uma nova conta em nossa comunidade. É fácil!
Crie uma nova contaEntrar
Já tem uma conta? Faça o login.
Entrar Agora