Ir para conteúdo
  • Cadastre-se

Recommended Posts

Postado

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;  

 

Postado (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 por ANDERSON JUNIOR GADO DA SILVA
Complementação
  • 2 semanas depois ...
Postado
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.

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 conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • 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.

The popup will be closed in 10 segundos...