jerrivaldo
Membros-
Total de ítens
14 -
Registro em
-
Última visita
Tipo de Conteúdo
Blocks
Notes ACBrLibNFe
Fóruns
Downloads
Calendário
Tudo que jerrivaldo postou
-
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.
-
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.
-
Erro ao ler xml de NFe: Não foi possível carregar a biblioteca LibXml2
jerrivaldo replied to jerrivaldo's tópico in ACBrNFSe
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 -
Erro ao ler xml de NFe: Não foi possível carregar a biblioteca LibXml2
um tópico no fórum postou jerrivaldo ACBrNFSe
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. -
Alteração no Fator de Vencimento dos Boletos
jerrivaldo replied to jerrivaldo's tópico in ACBrBoleto
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; -
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.
-
Boleto híbrido com pix (BolePix) banco Inter
jerrivaldo replied to jerrivaldo's tópico in ACBrBoleto
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 -
Boleto híbrido com pix (BolePix) banco Inter
jerrivaldo replied to jerrivaldo's tópico in ACBrBoleto
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... -
Boleto híbrido com pix (BolePix) banco Inter
jerrivaldo replied to jerrivaldo's tópico in ACBrBoleto
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. -
Boleto híbrido com pix (BolePix) banco Inter
jerrivaldo replied to jerrivaldo's tópico in ACBrBoleto
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. -
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
-
Recebi um comunicado do Banco Inter de que a partir de 31/10/2024 a API Cobrança V2 será descontinuada.
-
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
- 5 replies
-
- consulta cnpj
- firemonkey
- (e 1 mais)
-
[ Correção ] - ACBrConsultaCNPJ "Consulta CNPJ"
jerrivaldo replied to Pedro Henrique Oliveira's tópico in ACBrTCP
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
