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...
The popup will be closed in 10 segundos...