-
Total de ítens
100 -
Registro em
-
Última visita
Tipo de Conteúdo
Blocks
Notes ACBrLibNFe
Fóruns
Downloads
Calendário
Posts postados por Gabriel Franciscon
-
-
Olá pessoal! tudo bem?
Na unidade ACBrNFSeXDANFSeFPDFClass (Fontes\ACBrDFe\ACBrNFSeX\DANFSE\FPDF) está dando uses em "Forms". Porém não está sendo utilizado para nada...
Seria possível remover esse uses desnecessário? -
13 horas atrás, Daniel Paixao disse:
E como vocÊ faz com o banco de dados?
Opa!
Após a atualização no primeiro computador. O sistema rodará os scritps. Esses scripts estão dentro Instalador do InstallShield. Por tanto ao concluir a instalação é criado uma pasta contendo todos os scripts necessários. E após o usuário abrir o programa e informar o login os scripts daquela pasta são executados (através do componente do FireDac - FDScript).
Após rodar os scripts no banco os demais computadores mostra uma mensagem informando que é necessário realizar um atualização... Aí o instalador com o update é rodado e quando o usuário abrir o sistema nesses outros PC's, não será executado nenhum script pois dentro do banco de dados tem uma tabela que guarda a versão do banco. e antes de rodar eu verifico se a versão do executável é compatível com a versão do banco
- 1
-
4 minutos atrás, centuryinf disse:
resolvi criando criando um numero sequencia em cNfe.
Não é correto usar um número sequencial e sim um número randômico de 8 dígitos. Pois pode acontecer que o seu número sequencial seja um dos números inválidos.
Aconselho utilizar a função mencionada no tópico do Ítalo GerarCodigoDFe e armazenando esse código junto a nota fiscal no seu banco de dados.
-
Já tentou passar 0 (zero) para o parâmetro NSU? Informando zero retorna todos os NSU's dos últimos 90 dias.
Exemplo:
DistribuicaoDFePorUltNSU(41, '12345678000100', '0')
Outra dica importante é verificar o ambiente nas configurações do ACBr (homologação - produção) para cada ambiente há uma sequencia diferente de NSU.
- 1
-
Boa tarde,
2 horas atrás, Phelipe Silva disse:Sendo bem direto na pergunta,eu gostaria de saber,qual é a regra do SEFAZ para liberar o download de uma nota?
Quando o fornecedor emite uma nota fiscal, essa nota é enviada para SEFAZ do estado e a mesma se encarrega de enviar para o ambiente nacional*. Feito isso, o ambiente nacional criará um NSU com o resumo dessa nota fiscal e disponibiliza através do Web-Service de DistribuicaoDFe. O seu software irá localizar esse resumo através do método DistribuicaoDFePorUltNSU. Com o resumo em mãos seu software irá realizar a manifestação do destinatário... Ao fazer isso, o ambiente nacional irá criar um novo NSU, agora com a nota completa. E novamente você executará o método DistribuicaoDFePorUltNSU ou DistribuicaoDFePorChaveNFe.
*O tempo entre a SEFAZ do estado enviar a nota e o Ambiente Nacional receber e disponibilizar varia muito... Aqui no Paraná vejo um média de 2 horas. mas já vi relatos aqui no fórum que pode levar até 24 horas.
Vou deixar um tópico abaixo que detalha melhor o funcionamento:
- 2
- 1
-
Infelizmente a versão oficial dos schemas disponibilizados não permite a visualização do status atual da manifestação. Porém...
Se observarmos o software gratuito da SEFAZ, percebemos que ao "baixar" uma nota já vem o status atual da manifestação. Mesmo se a manifestação do destinatário tenha sido realizada em outro software.
Isso acontece pois o software gratuito utiliza uma versão mais recente dos schemas (v.135). Nessa versão existe uma tag chamada: cSitConf. (se olhar a nota técnica até existe a menção dessa tag)
Mas como essa não é uma versão oficial, digo, disponibilizada pela SEFAZ. Creio que ACBr não irá utilizar. De qualquer forma vou deixar aqui o link para download desses schemas.
Com uma simples alteração na unit pcnRetDistDFeInt você adiciona uma nova property e na sequencia pode ler o valor desse campo.
Nessa versão infelizmente o método DistribuicaoDFePorChaveNFe não funciona. (Mas é possível contornar isso alterando algumas linhas)
--Se for DistribuicaoDFePorChaveNFe utiliza 1.02 caso contrário, utiliza a 1.35
- 3
-
5 minutos atrás, ALA disse:
Então a regra e gravar o numero aleatorio no BD ?
Exatamente... Pois aí você terá todas as informações que são necessárias para gerar a mesma chave de acesso novamente
-
5 minutos atrás, ALA disse:
mas como vcs estão procedendo quando perde a chave da NFe/NFC-e e tem a necessidade de criar a mesma chave que ja foi enviada para SEFAZ..?
Você deve armazenar o cNF no seu banco de dados. Dessa forma se precisar gerar a chave novamente, você utiliza o mesmo cNF da primeira vez.
-
42 minutos atrás, ALA disse:
"Erro ao Gerar NFC-e Código Numérico inválido, Chave não Gerada" o que devo passar para função para não acontecer esse erro.
Isso acontece pois você está passando para o campo cNF o mesmo valor de nNF.
De uma olhada para mais detalhes:
- 1
- 1
-
6 minutos atrás, New Standard Software disse:
Certo, mas fica a mesma dúvida que escrevi acima, como vejo se foi manifestada, deveria ter um evento associado a ela? E outro detalhe, quem deve fazer a manifestação, o gerador da nota, ou o destinatário?
A manifestação é feita pelo destinatário da nota fiscal.
E a SEFAZ não envia uma informação se foi realizado a manifestação ou não para o destinatário. Apenas para o emitente. Pois entende-se que como o destinatário realizou a manifestação. O mesmo não precisa saber, pois foi ele mesmo quem fez. Ou seja, quando o seu cliente realizar a manifestação você deverá armazenar essa informação.
E como citado acima o método DistribuicaoDFePorChaveNFe só retorna informação caso a nota em questão já tiver um registro de manifestação vinculado a ela.
-
2 horas atrás, New Standard Software disse:
Mas o problema já ocorre no primeiro passo, ele não localiza nada e retorna o cStat 137
O ideal seria utilizar o método DistribuicaoDFePorUltNSU.
Pois o método DistribuicaoDFePorChaveNFe retorna informações apenas se a nota já estiver com um registro de manifestação pelo destinatário.
Então na teoria ficaria assim
- DistribuicaoDFePorUltNSU (trará: Nota resumida, Nota completa, Eventos resumido e Eventos completo)
- Realizar a manifestação
- Executar o método DistribuicaoDFePorUltNSU novamente (ou o DistribuicaoDFePorChaveNFe)
- 1
-
Realizar a manifestação do destinatário apenas com a Ciência e não concluir posteriormente pode sim acarretar em algum tipo de multa...
A manifestação do destinatário está "amarrada" ao DistribuiçãoDFe. Porém os objetivos são diferentes... Então a ideia de "só baixar o XML" não funciona muito já que seu cliente se torna obrigado a realizar a manifestação.
Aqui eu trato da seguinte maneira:
- Aplicativo configurado para realizar a manifestação do destinatário automaticamente com a Ciência da operação ao encontrar um novo documento.
- Usuário realiza o recebimento de mercadorias no sistema: Disparo a Confirmação da operação
- Desconhecimento ou Operação não realizada fica por conta do usuário.
- Caso fique notas sem a "conclusão" da manifestação por parte do destinatário, alerto o mesmo através de notificações.
- 3
-
Como você não mencionou a mensagem exata de erro que está dando, vou dar outra sugestão;
Limpar o componente antes de criar um evento. (Se tiver uma nota fiscal carregada no ACBr e você tentar criar um evento, terá a mensagem abaixo)
Por tanto, certifique-se de limpar as notas fiscais e eventos que estão previamente carregados no ACBr.
with ACBrNFe1 do begin NotasFiscais.Clear; EventoNFe.Evento.Clear; with EventoNFe.Evento.New do begin InfEvento.cOrgao := 91; //91 - Ambiente Nacional. No caso de evento de manifestação, sempre será 91 InfEvento.chNFe := ''; //Chave de acesso da NFe InfEvento.CNPJ := ''; //CNPJ da empresa que está emitindo o evento (o mesmo do certificado digital) InfEvento.dhEvento := now; //Data do evento InfEvento.tpEvento := ''; //teManifDestCiencia, teManifDestConfirmacao, teManifDestOperNaoRealizada, teManifDestDesconhecimento InfEvento.detEvento.xJust := ''; //Justificativa, caso seja desconhecimento ou op não realizada end; EnviarEvento(IdLote); end;
- 3
- 1
-
4 horas atrás, nildglan disse:
erro é que não vincula o evento
Se a mensagem for: Evento registrado mas não vinculado a NF-e
Pode significar que:
- A chave de acesso pertence a uma nota fiscal emitida no ambiente de homologação e o evento está sendo enviando em produção (ou vise-versa)
- A chave de acesso está incorreta.
Lembrando ainda que o campo CNPJ é o CNPJ da empresa que está enviando o Evento, no caso o mesmo do certificado digital.
E uma observação, dependendo da sua versão do Delphi, considere substituir o método .add para .new. Visto que o add é um método depreciado e que em versões futuras da Embarcadero será descontinuado.
-
Em 06/06/2019 at 16:25, picuuai disse:
Chave Correta da NFe: 35190401186408000162550010000399001000285142
Chave que o ACBr gerou: 35190401186408000162550010000399001577940241
O valor em negrito contem a informação do campo cNF. Esse campo compõe a chave de acesso.
O ACbr atribui um valor aleatório automaticamente pra esse campo, caso você não preencha. Ou seja, quando estiver montando o XML, você vai precisar utilizar um Copy da chave de acesso correta, copiando essa informação e informando no campo cNF do ACBr.
- 1
-
Boa noite, tente assim:
ACBrNFe1.EventoNFe.Evento.Clear; with ACBrNFe1.EventoNFe.Evento.New do begin InfEvento.cOrgao := 91; //91 - Ambiente Nacional. No caso de evento de manifestação, sempre será 91 InfEvento.chNFe := ''; //Chave de acesso da NFe InfEvento.CNPJ := ''; //CNPJ da empresa que está emitindo o evento (o mesmo do certificado digital) InfEvento.dhEvento := now; //Data do evento InfEvento.tpEvento := ''; //teManifDestCiencia, teManifDestConfirmacao, teManifDestOperNaoRealizada, teManifDestDesconhecimento InfEvento.detEvento.xJust := ''; //Justificativa, caso seja desconhecimento ou op não realizada end; ACBrNFe1.EnviarEvento(IdLote);
- 1
-
1 hora atrás, AlexBecker disse:
Testando o exemplo que me passou se eu deixo o array completo como acima ele me diz que não é um objeto válido
Isso acontece pois você colocou apenas uma parte do JSON de retorno do iFood. Como eu criei uma classe que lê todos os campos de retorno. Você precisa colocar o JSON de retorno completo. (e funciona caso um item tenha subitems e o outro item não tenha)
Ou seja, eu não preciso ficar desmembrando o JSON. Em apenas uma linha converto para um objeto (no caso a classe que eu criei - Essa classe deve contem todos os campos retornados).
Depois eu vou acessando esse objeto. Em tese é a mesma coisa que o ACBr para ler um XML. A única diferença é que o ACBr vai montando o objeto com o retorno da SEFAZ e no meu caso eu utilizo uma função do Próprio Delphi (JsonToObject) para montar o meu objeto.
Acredito que seja melhor você criar um objeto como falei na primeira resposta. Pois assim, ficará bem mais fácil pra dar manutenção depois. Além de que pra acessar os dados fica de forma simples.
-
5 horas atrás, AlexBecker disse:
o problema ali é que a primeira linha dos itens não retorna a estrutura completa do objeto/array itens se o mesmo não tem subitens
Sim, quando o iFood monta o JSON, eles ignoram arrays, strings, números, objetos em branco. Deixando assim o retorno somente com o que é necessário.
Como eu citei acima, aqui eu criei um unit com todos os retornos possível do JSON (property). Depois eu só converto o JSON para um ObjectList usando generics.
Fiz um exemplo bem simples, só pra mostrar que de um lado eu tenho um memo com o JSON do iFOOD e do outro o meu ObjectList.
Vou deixar o código aqui.
var MyPedidoiFood: TiFoodPedido; x, i: Integer; begin MyPedidoiFood := TJSON.JsonToObject<TiFoodPedido>(MemoJSON.Lines.Text); //Memo com o JSON do iFood try for x := 0 to Length(MyPedidoiFood.items) - 1 do begin MemoClasseDelphi.Lines.Add('Nome mercadoria base: '+MyPedidoiFood.Items[x].name); for i := 0 to Length(MyPedidoiFood.items[x].subItems) - 1 do MemoClasseDelphi.Lines.Add('Nome subitem: '+MyPedidoiFood.Items[x].subItems[i].name); MemoClasseDelphi.Lines.Add(''); end; finally MyPedidoiFood.Free; end; end;
E o link do exemplo compilado caso queira testar com um JSON seu.
5 horas atrás, AlexBecker disse:jsontodataset cria automaticamente um campo com 255 caracteres e não entra todo o valor
Se estiver utilizando TCustomJSONDataSetAdapter. Você pode aumentar o tamanho da string por essa propriedade: StringFieldSize (antes de criar os campos).
- 1
-
JsonToDataset não leva em consideração o "detail" de um objeto ou array do json...
A melhor forma de você tratar isso é convertendo um JSON para um Object usando Generics
Em resumo, você cria uma classe no Delphi igual ao JSON que recebe do iFood.
TPayments = class private Fname: string; Fcode: string; Fvalue: Extended; public property name: string read Fname write Fname; property code: string read Fcode write Fcode; property value: Extended read Fvalue write Fvalue; end; TArrayPayments = array of TPayments; TiFoodPedido = class private Fid: string; Freference: string; Fpayments: TArrayPayments; public property id: string read Fid write Fid; property reference: string read Freference write Freference; property payments: TArrayPayments read Fpayments write Fpayments; end; TiFoodPedidos = TObjectList<TiFoodPedido>;
No caso do payments é um array. Mas terá casos onde serão objetos (merchant, address, customer...). Sendo assim não esqueça de criar constructor e destructor para criar e destruir esses objetos.
constructor TiFoodPedido.Create; begin FCustomer := TCustomer.Create; FDeliveryAddress := TDeliveryAddress.Create; end; destructor TiFoodPedido.Destrtoy; begin FCustomer.Free; FDeliveryAddress.Free; end;
Depois você pode simplesmente chamar assim:
var PedidoiFood: TiFoodPedido; begin PedidoiFood := TJSON.JsonToObject<TiFoodPedido>('JSON de retorno do iFood'); try //dessa forma você consegue ler os items dentro de um array PedidoiFood.payments[0].name; PedidoiFood.payments[0].code; PedidoiFood.payments[0].value; finally PedidoiFood.Free; end; end;
Caso queira adicionar mais pedidos na sua lista:
var Pedidos: TiFoodPedidos; PedidoiFood: TiFoodPedido; x: Integer; begin Pedidos := TiFoodPedidos.Create; try for x := 0 to 5 do begin PedidoiFood := TJSON.JsonToObject<TiFoodPedido>('JSON de retorno do iFood'); Pedidos.Add(PedidoiFood); end; //No final poderá acessar assim Pedidos.Items[0].payments[0].name; finally Pedidos.Free; end; end;
- 2
- 1
-
Você pode converter o JSON em DataSet, eu particularmente acho bem mais fácil.
- client_id e client_secret: Obtido através do cadastro da SoftHouse no site do iFood.
- username e password: Obtido através do cadastro do seu cliente no site do IFood. Ou seja, devem ser variáveis no seu software.
var IdHTTPConexao: TidHTTP; aArg: TStringList; begin IdHTTPConexao := TidHTTP.Create; aArg := TStringList.Create; try aArg.Add('client_id='+FClientID); aArg.Add('client_secret='+FClientSecret); aArg.Add('grant_type=password'); aArg.Add('username='+FUsername); aArg.Add('password='+FPassword); with IdHTTPConexao do begin Request.Accept := 'application/json'; JsonToDataset(FDMemTable1, Post('https://pos-api.ifood.com.br/oauth/token', aArg)); end; FDMemTable1.First; FToken := FDMemTable1.FieldByName('access_token').AsString; //<-Guada esse token para as demais requisições FExpires := FDMemTable1.FieldByName('expires_in').AsString; //<-Deve executar esse método novamente quando expirar finally IdHTTPConexao.Free; aArg.Free; end;
- Após obter o Token é necessário dar GET no endpoint /events:polling a cada 30 segundos. É aqui que você recebe um resumo dos pedidos ainda não capturados.
var IdHTTPConexao: TidHTTP; JSONRetorno: TStringStream; begin IdHTTPConexao := TidHTTP.Create; JSONRetorno := TStringStream.Create('', TEncoding.UTF8); try with IdHTTPConexao do begin Request.Clear; Request.ContentType := 'application/json'; Request.Charset := 'UFT-8'; Request.BasicAuthentication := False; Request.CustomHeaders.Clear; Request.CustomHeaders.AddValue('Content-Type', 'application/json'); Request.CustomHeaders.AddValue('Authorization', 'bearer'+FToken); Request.CustomHeaders.AddValue('cache-control', 'no-cache'); Request.Accept := 'application/json'; Get('https://pos-api.ifood.com.br/v1.0/events%3Apolling', JSONRetorno); JsonToDataset(FDMemTableResumo, JSONRetorno.DataString); end; with FDMemTableResumo do begin First; while not Eof do begin FieldByName('id').AsString; //<-Id do evento. Necessário guardar para limpar a fila depois de processar esse evento. FieldByName('code').AsString; //<-Status retornado para o pedido (Confirmado, cancelado...). FieldByName('correlationId').AsString; //<-Código do pedido. Com esse código que você obtem o detalhamento do pedido. FieldByName('createdAt').AsString; //<-Data de criação do evento. Next; end; end; finally IdHTTPConexao.Free; JSONRetorno.Free; end; end;
- O próximo passo é executar o endpoints /orders/{reference} através do método GET (https://pos-api.ifood.com.br/v1.0/orders/reference). Substituindo o valor "reference" pelo o correlationId. Ou seja do pedido que deseja.
Não vou postar um exemplo pois aqui o código fica grande e cada aplicação tratará diferente os resultados... Mas a lógica é a mesma. Não esqueça de alterar o status do pedido quando processar ele. O status integration é obrigatório.
- Após processar todos os pedidos, chegou a hora de limpar a fila... Alguns limpam a fila no final do dia. Mas particularmente eu prefiro limpar a fila a cada execução do polling.
IdHTTPConexao: TidHTTP; aArg: TStringStream; FIds: string; begin FIds := ''; with FDMemTableResumo do begin while not Eof do begin if FIds <> '' then FIds := FIds + ', '; FIds := FIds + '{"id":"'+FieldByName('id').AsString+'"}'; Next; end; end; if FIds <> '' then begin FIds := '['+FIds+']'; IdHTTPConexao := TidHTTP.Create; aArg := TStringStream.Create(FIds, TEncoding.UTF8); try with IdHTTPConexao do begin Request.Clear; Request.ContentType := 'application/json'; Request.Charset := 'UFT-8'; Request.BasicAuthentication := False; Request.CustomHeaders.Clear; Request.CustomHeaders.AddValue('Content-Type', 'application/json'); Request.CustomHeaders.AddValue('Authorization', 'bearer'+FToken); Request.CustomHeaders.AddValue('cache-control', 'no-cache'); Request.Accept := 'application/json'; Post('https://pos-api.ifood.com.br/v1.0/events/acknowledgment', aArg); end; finally aArg.Free; IdHTTPConexao.Free; end; end;
Enfim, é mais ou menos isso... Claro, da pra otimizar muito esse código. Deixei da forma mais simples possível. Uma outra solução seria utilizar RestClient ao invés do Indy..
Vou deixar alguns links bem legais explicando com mais detalhes o funcionamento:
A função JsonToDataSet pode ser encontrada aqui.
Palestra do Kleberson Toro para o CodeRage Brasil 2019
Ah, uma observação... Na documentação do iFood já podemos notar que existe uma versão 2.0 para a API. A mesma está liberada apenas para /orders. Então caso for integrar, já use o novo endrpoints
- 1
-
Estranho só conseguir o XML completo com a confirmação da operação. Nos testes que acabei de fazer aqui, com a ciência da operação já consegui ter acesso ao XML completo.
Pode existir um delay entre a manifestação do destinatário e o A.N disponibilizar o XML completo. Já presenciei casos onde esse tempo foi de mais de 1 hora. Assim como no mesmo segundo já obtive o XML completo.
Aqui após o evento de manifestação do destinatário, eu executo o método DistribuicaoDFePorChaveNFe. Caso o retorno seja 137 - nenhum documento localizado, eu sei que o A.N ainda não disponibilizou o XML completo. Dessa forma eu trato isso com tentativas. Ou seja, tento por X vezes (com um tempo de espera de alguns segundos entre cada tentativa). Caso esgote as tentativas, aviso o usuário que o XML ainda não foi disponibilizado e pra tentar novamente...
- 3
-
Boa noite,
Você precisa incrementar um número na propriedade nItem a cada item adicionado.
Então ficará mais ou menos assim:
var NotaF: NotaFiscal; Produto: TDetCollectionItem; iNumItem: Integer; begin NotaF := ACBrNFe1.NotasFiscais.Add; {...} iNumItem := 0; while not Query.Eof do begin iNumItem := iNumItem + 1; Produto := NotaF.NFe.Det.New; Produto.Prod.nItem := iNumItem; //<-Número sequencial, para cada item deve ser incrementado {...} Query.Next; end; end;
Parte do código acima foi retirado do exemplo do ACBr.
- 2
-
17 minutos atrás, JHONLENON disse:
manifesta tudo certinho.......mais na hora do dawlods as vezes dá erro...
Você está tentando ler o item 0 porém não existe o item zero. Isso acontece porque provavelmente o Ambiente Nacional ainda não disponibilizou o XML completo da nota fiscal. (sim pode existir um delay grande entre a manifestação do destinatário e o A.N disponibilizar o XML)
O que você deve fazer é primeiro verificar se existe items retornados pelo A.N. Através da propriedade "count".
if ACBrNFe1.WebServices.DistribuicaoDFe.retDistDFeInt.docZip.Count > 0 then
E um detalhe importante; é retornado também em uma propriedade o código de retorno. Ou seja, dependendo do código de retorno, você saberá se tem alguma informação que precisa ser lida.
cStat := ACBrNFe1.WebServices.DistribuicaoDFe.retDistDFeInt.cStat; cStat = 137 (Nenhum documento localizado) cStat = 138 (Documentos encontrados)
Verificações como essa devem ser feitas antes de ler algum "item" pois pode acontecer exatamente o que mencionou acima.
- 1
-
4 minutos atrás, Suporte AZ disse:
Obrigado pela ajuda! Só mais uma questão, por exemplo essa nova tag do Responsável Técnico, se ela aparecer em todos os estados, até os que ainda não estão obrigatórios ocorre algum problema ou não faz mal?
Terá problemas (rejeição)... Já que o estado ainda não está preparado para receber essa informação.
- 2
Alteração na unit ACBrPIXPSPMercadoPago
em Dúvidas sobre PIX
Postado
Olá pessoal! tudo bem?
Na unidade ACBrPIXPSPMercadoPago (Fontes\ACBrPIXCD) está dando uses em "Dialogs". Porém não está sendo utilizado para nada...
Seria possível remover esse uses desnecessário?
ACBrPIXPSPMercadoPago.pas