Ir para conteúdo
  • Cadastre-se

jerrivaldo

Membros
  • Total de ítens

    14
  • Registro em

  • Última visita

Tudo que jerrivaldo postou

  1. Consegui muitas informações no ChatGPT. Inclusive a Inteligência Artificial me deu comandos prontos em Delphi já para rodar e conectar com a CERC/B3 abaixo está um módulo Delphi pronto que implementa OAuth2 (client_credentials e refresh_token) com exemplos de uso, tratamento de erros, thread-safety e dicas de segurança. Pressuposições que fiz (comuns para registradoras como CERC/B3): você usará client_credentials (mais comum para sistemas server-to-server); o token_endpoint retorna JSON com access_token, expires_in e possivelmente refresh_token. Cole este unit no seu projeto e adapte TokenURL, ClientID, ClientSecret e Scope conforme a registradora. unit OAuth2Client; interface uses System.SysUtils, System.Classes, System.SyncObjs, System.DateUtils, System.Generics.Collections, System.JSON, System.Net.HttpClient, System.Net.URLClient; type EOAuth2Error = class(Exception); TOAuth2Token = record AccessToken: string; RefreshToken: string; ExpiresAt: TDateTime; // UTC Scope: string; TokenType: string; function IsValid: Boolean; end; TOAuth2Client = class private FTokenURL: string; FClientID: string; FClientSecret: string; FScope: string; FHTTP: TNetHTTPClient; FToken: TOAuth2Token; FLock: TObject; FLastError: string; procedure ParseTokenResponse(const JSONText: string); function RequestToken_ClientCredentials: TOAuth2Token; function RequestToken_WithRefresh(const ARefreshToken: string): TOAuth2Token; procedure SecureEraseClientSecret; public constructor Create(const ATokenURL, AClientID, AClientSecret, AScope: string; AHTTP: TNetHTTPClient = nil); destructor Destroy; override; { Retorna authorization header, garantindo que o token está válido. Exemplo: 'Bearer <token>' } function GetAuthorizationHeader: string; { Força obtenção de token (útil para testes) } procedure AcquireToken; { Se houver refresh_token, tenta renovar; caso contrário, pede novo token via client_credentials } procedure EnsureTokenValid; property LastError: string read FLastError; end; implementation { TOAuth2Token } function TOAuth2Token.IsValid: Boolean; begin // considera válido com 60s de margem Result := (AccessToken <> '') and (MinutesBetween(NowToUTC, ExpiresAt) > 0); end; { TOAuth2Client } constructor TOAuth2Client.Create(const ATokenURL, AClientID, AClientSecret, AScope: string; AHTTP: TNetHTTPClient); begin inherited Create; FTokenURL := ATokenURL; FClientID := AClientID; FClientSecret := AClientSecret; FScope := AScope; if AHTTP = nil then begin FHTTP := TNetHTTPClient.Create(nil); // ajustar timeouts se desejar: FHTTP.ConnectionTimeout := 30000; FHTTP.ResponseTimeout := 30000; end else FHTTP := AHTTP; FLock := TObject.Create; FToken := Default(TOAuth2Token); end; destructor TOAuth2Client.Destroy; begin SecureEraseClientSecret; FHTTP.Free; FreeAndNil(FLock); inherited; end; procedure TOAuth2Client.SecureEraseClientSecret; begin // Limpa a string do client secret (melhor do que deixar em memória) FClientSecret := StringOfChar(#0, Length(FClientSecret)); FClientSecret := ''; end; procedure TOAuth2Client.ParseTokenResponse(const JSONText: string); var J: TJSONValue; jobj: TJSONObject; expires_in: Integer; s: string; begin J := TJSONObject.ParseJSONValue(JSONText); if not Assigned(J) then raise EOAuth2Error.Create('Resposta do token não é JSON válido'); try if not (J is TJSONObject) then raise EOAuth2Error.Create('Resposta do token inesperada'); jobj := J as TJSONObject; if jobj.GetValue('error') <> nil then begin s := jobj.GetValue<string>('error_description', jobj.GetValue<string>('error', 'erro desconhecido')); raise EOAuth2Error.CreateFmt('OAuth2 error: %s', [s]); end; FToken.AccessToken := jobj.GetValue<string>('access_token', ''); FToken.TokenType := jobj.GetValue<string>('token_type', 'Bearer'); FToken.Scope := jobj.GetValue<string>('scope', FScope); FToken.RefreshToken := jobj.GetValue<string>('refresh_token', ''); expires_in := jobj.GetValue<Integer>('expires_in', 0); // ExpiresAt em UTC: NowToUTC + expires_in segundos if expires_in > 0 then FToken.ExpiresAt := IncSecond(NowToUTC, expires_in) else // default para 5 minutos se não informado (evitar ficar inválido) FToken.ExpiresAt := IncMinute(NowToUTC, 5); finally J.Free; end; end; function TOAuth2Client.RequestToken_ClientCredentials: TOAuth2Token; var Resp: IHTTPResponse; Body: TStringStream; Params: TStringList; Headers: TNetHeaders; Encoded: string; sBody: string; begin Params := TStringList.Create; try // Form-encoded body (application/x-www-form-urlencoded) Params.Add('grant_type=client_credentials'); if FScope <> '' then Params.Add('scope=' + TNetEncoding.URL.Encode(FScope)); Body := TStringStream.Create(Params.DelimitedText.Replace(#13#10,'&',[rfReplaceAll]), TEncoding.UTF8); try Headers := [ TNameValuePair.Create('Content-Type', 'application/x-www-form-urlencoded') ]; // credencial via Authorization basic (recomendado) Encoded := TNetEncoding.Base64.Encode(FClientID + ':' + FClientSecret); Headers := Headers + [TNameValuePair.Create('Authorization', 'Basic ' + Encoded)]; Resp := FHTTP.Post(FTokenURL, Body, nil, Headers); sBody := Resp.ContentAsString(TEncoding.UTF8); if not (Resp.StatusCode in [200,201]) then raise EOAuth2Error.CreateFmt('Token endpoint retornou %d: %s', [Resp.StatusCode, sBody]); // parseia e popula FToken ParseTokenResponse(sBody); Result := FToken; finally Body.Free; end; finally Params.Free; end; end; function TOAuth2Client.RequestToken_WithRefresh(const ARefreshToken: string): TOAuth2Token; var Body: TStringStream; Params: TStringList; Headers: TNetHeaders; Resp: IHTTPResponse; sBody: string; Encoded: string; begin Params := TStringList.Create; try Params.Add('grant_type=refresh_token'); Params.Add('refresh_token=' + TNetEncoding.URL.Encode(ARefreshToken)); Body := TStringStream.Create(Params.DelimitedText.Replace(#13#10,'&',[rfReplaceAll]), TEncoding.UTF8); try Headers := [ TNameValuePair.Create('Content-Type','application/x-www-form-urlencoded') ]; Encoded := TNetEncoding.Base64.Encode(FClientID + ':' + FClientSecret); Headers := Headers + [TNameValuePair.Create('Authorization', 'Basic ' + Encoded)]; Resp := FHTTP.Post(FTokenURL, Body, nil, Headers); sBody := Resp.ContentAsString(TEncoding.UTF8); if not (Resp.StatusCode in [200,201]) then raise EOAuth2Error.CreateFmt('Refresh token endpoint retornou %d: %s', [Resp.StatusCode, sBody]); ParseTokenResponse(sBody); Result := FToken; finally Body.Free; end; finally Params.Free; end; end; procedure TOAuth2Client.AcquireToken; var TokenLocal: TOAuth2Token; begin TMonitor.Enter(FLock); try FLastError := ''; try // tenta via client_credentials TokenLocal := RequestToken_ClientCredentials; FToken := TokenLocal; except on E: Exception do begin FLastError := E.Message; raise; end; end; finally TMonitor.Exit(FLock); end; end; procedure TOAuth2Client.EnsureTokenValid; var tokenCopy: TOAuth2Token; begin TMonitor.Enter(FLock); try // se token válido, nada a fazer if FToken.IsValid then Exit; // se temos refresh token, tente renovar if FToken.RefreshToken <> '' then begin try RequestToken_WithRefresh(FToken.RefreshToken); Exit; except // se falhar, limpa e tenta client_credentials FToken := Default(TOAuth2Token); end; end; // pede novo token via client_credentials RequestToken_ClientCredentials; finally TMonitor.Exit(FLock); end; end; function TOAuth2Client.GetAuthorizationHeader: string; begin EnsureTokenValid; if FToken.AccessToken = '' then raise EOAuth2Error.Create('Nenhum access_token disponível'); Result := FToken.TokenType + ' ' + FToken.AccessToken; end; end. Como usar (exemplo simples) var OAuth: TOAuth2Client; AuthHeader: string; Client: TNetHTTPClient; Resp: IHTTPResponse; begin Client := TNetHTTPClient.Create(nil); try OAuth := TOAuth2Client.Create( 'https://registradora.exemplo/oauth2/token', 'seu_client_id', 'seu_client_secret', 'scope-necessario', Client); try // pode chamar EnsureTokenValid antes de cada requisição AuthHeader := OAuth.GetAuthorizationHeader; // 'Bearer <token>' // Exemplo de chamada à API de consulta usando o token Resp := Client.Get('https://registradora.exemplo/api/duplicata/consultar', nil, [TNameValuePair.Create('Authorization', AuthHeader)]); // tratar Resp.ContentAsString... finally OAuth.Free; end; finally Client.Free; end; end; Dicas e pontos importantes Fluxo mais comum: client_credentials (server-to-server). Alguns provedores podem exigir MTLS (client certificate) — nesse caso a autenticação muda e você precisa configurar certificado no HTTP client. Armazenamento seguro do client_secret: não guarde em texto claro. Use DPAPI (Windows CryptoAPI), arquivo criptografado, ou HSM/KeyVault. Timeouts e retry: implemente re-tries exponenciais para chamadas de token e trate códigos 5xx. Logs e compliance: armazene respostas cruas (somente em ambiente seguro) para auditoria — mas não registre client_secret. Rate limits: confira limites da registradora e implemente backoff. Testes: rode em homologação da registradora e simule expiração de tokens. MTLS: se a registradora exigir certificado do cliente, o TNetHTTPClient precisa ser configurado com o certificado PFX (TLS client cert). Eu posso te mostrar o snippet se precisar. Quer que eu: adapte este módulo para MTLS (client cert) em vez de Basic auth? gere uma classe pronta que também faça a chamada da API /duplicata/consultar e parseie o retorno em registros Delphi? Escolhe uma opção e eu já preparo.
  2. jerrivaldo

    Duplicata Escritural

    O Banco Central (BC) está lançando a duplicata escritural, uma versão eletrônica e totalmente rastreável da duplicata física, para modernizar e dar mais segurança ao mercado de crédito. A transição está em andamento, com testes ocorrendo até novembro de 2025 e o sistema com funcionalidades restritas até outubro de 2026, quando se prevê o pleno funcionamento a partir dessa data. A adoção será gradual, começando por grandes empresas e expandindo para outras até abril de 2028, com o objetivo de reduzir custos, fraudes e aumentar a oferta de crédito.
  3. Já consegui resolver o problema. Para resolver o problema, reinstalei o ACBr e desmarquei a opção "Não utilizar MsXML (Recomendado)", na tela em anexo
  4. O erro "Não foi possível carregar a biblioteca LibXml2" acontece ao executar a seguinte linha de código: TACBrNFe.NotasFiscais.LoadFromFile(ArquivoXML); O que eu já fiz para tentar resolver o problema: copiei o arquivo libxml2.dll para a pasta do executável copiei o arquivo libxml2.dll para a pasta C:\WINDOWS\SYSTEM32 copiei o arquivo libxml2.dll para a pasta C:\WINDOWS\SYSWOW64 copiei o arquivo libxml2-2.dll para a pasta do executável copiei o arquivo libxml2-2.dll para a pasta C:\WINDOWS\SYSTEM32 copiei o arquivo libxml2-2.dll para a pasta C:\WINDOWS\SYSWOW64 Incluí a diretiva de compilação {$DEFINE UseMSXML} no projeto Editei o arquivo Acbr.inc e removi o comentário da linha {$DEFINE USE_MINGW} Estou usando Delphi 12.3 e baixei o ACBr semana passada, agora no mes de agosto de 2025.
  5. Para resolver o problema, agora vai ter que testar a data function CalcularFatorVencimento(DataDesejada : TDateTime) : string; begin if (DataDesejada < StrToDate('22/02/2025')) then Result := IntToStr( Trunc(DataDesejada - EncodeDate(1997,10,07))) else Result := IntToStr(Trunc(DataDesejada) - 44710); end;
  6. O "Fator de Vencimento" das linhas digitáveis dos Boletos de Cobrança, atingirá o seu limite máximo em 21/02/2025. A partir dessa data, a sequência do fator de vencimento deverá ser reiniciada para o algoritmo 1000 para os boletos com vencimento a partir de 22/02/2025, somando uma unidade para cada dia subsequente, a fim de não impactar a emissão dos boletos. Veja o exemplo: Vencimento 21/02/2025 = 9999 Vencimento 22/02/2025 = 1000 Vencimento 23/02/2025 = 1001 Vencimento 24/02/2025 = 1002 Essa adequação no sistema do cliente é importante para que os bancos possam processar os pagamentos corretamente quando o cliente for realizá-los.
  7. Tem algum video ou tutorial de como posso fazer para ter o QRCode na impressão local? Realmentel não consegui imprimir o boleto local com QRCode
  8. Sim, tenho a impressão local mas sem o QRCode, por isso fiz a modificação pois o Pix domina os meios de pagamentos e precisamos oferecer essa praticidade para os nossos clientes. Vou continuar usando a versão modificada por mim. Só disponibilizei aqui para deixar isso disponível para todos que usam o componente. Posso fazer uma modificação para usar uma propriedade que o componente já tem sem ter que criar uma propriedade nova...
  9. para ficar compatível com o lazarus pode salvar o boleto em qualquer variável (propriedade) string que já tem no componente. Vi que tem uma propriedade para uso do banco. Pode colocar o pdf em nessa variável para uso do banco para ficar compatível com o lazarus. Isso aí é simples de resolver. Se não quiser criar uma propriedade nova, a classe TACBrBoletoTituloRet tem uma propriedade chamada UsoBanco Na Unit ACBrBoletoRet_Inter_API a procedure TRetornoEnvio_Inter_API.LerRetornoPix() poderia ficar assim procedure TRetornoEnvio_Inter_API.LerRetornoPix(const ARetornoWS: TACBrBoletoRetornoWS; AIndex: Integer); ARetornoWS.DadosRet.TituloRet.UsoBanco := LJsonObjectItem.asstring['pdf']; O importante é ter essa função que elimina a necessidade de imprimir o boleto localmente.
  10. Mas foi exatamente a baixa do PDF que eu acrescentei. O registro do boleto já estava corrreto. Fiz umas correções no momento em que dava erro de boleto já registrado e a pessoa estava tentando registrar novamente e o componente não retornava a mensagem de erro retornada pela Api pois dava access violation. para ficar compatível com o lazarus pode salvar o boleto em qualquer variável (propriedade) string que já tem no componente. Vi que tem uma propriedade para uso do banco. Pode colocar o pdf em nessa variável para uso do banco para ficar compatível com o lazarus.
  11. Fiz modificações no componente ACBr boleto para funcionar com a nova versão da API do banco Inter e já imprimir o boleto com QRCode para pagamento com pix. ACBrBoletoRet_Inter_API.pas ACBrBoletoW_Inter_API.pas ACBrBoletoRetorno.pas
  12. Recebi um comunicado do Banco Inter de que a partir de 31/10/2024 a API Cobrança V2 será descontinuada.
  13. Não compila no Firemonkey. Fiz uma modificação para compilar no Fiemonkey mas só funciona no Windows. Quando tenta rodar no Android não funciona
  14. Eu tive a idéia de recriar essa função de pegar os dados da empresa no site da receita federal refazendo tudo do zero. A idéia seria usar TWebBrowser para carregar a página. Depois era só ler o HTML de resultado no TWebBrowser e pegar as informações da empresa como nome, endereço, etc. Só que o TWebBrowser deu erro ao carregar a página. Segue código-fonte em anexo. Parece que tem que habilitar Cookies no TWebBrowser mas não sei como se faz isso. ConsultaCNPJ.rar
×
×
  • 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.