Skip to content

Commit 372554e

Browse files
Adicionado QrCode NFC-e V3.
1 parent 4cddbdb commit 372554e

File tree

3 files changed

+109
-34
lines changed

3 files changed

+109
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# Notas de versão
22
- Atualizado WebServices NFCe Ceara
3-
- Atualizado CACERT
3+
- Atualizado CACERT
4+
- Adicionado QrCode NFC-e V3

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ ________________________________________________________________________________
4242
## v4.00.39 - 20/06/2025 - Schemas PL.009p1
4343
- Atualizado WebServices NFCe Ceara
4444
- Atualizado CACERT
45+
- Adicionado QrCode NFC-e V3
4546

4647
## v4.00.38 - 06/05/2025 - Schemas PL.009p1
4748
- Atualizado URL Consulta Cadastro RS
Lines changed: 106 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
package br.com.swconsultoria.nfe.util;
22

3-
import java.security.InvalidParameterException;
4-
import java.security.MessageDigest;
5-
import java.security.NoSuchAlgorithmException;
6-
7-
/**
8-
*
9-
* @author Samuel Oliveira
10-
*/
3+
import br.com.swconsultoria.certificado.Certificado;
4+
import br.com.swconsultoria.certificado.CertificadoService;
5+
import br.com.swconsultoria.nfe.exception.NfeException;
6+
7+
import java.nio.charset.StandardCharsets;
8+
import java.security.*;
9+
import java.util.Base64;
10+
import java.util.Optional;
11+
12+
/**
13+
* @author Samuel Oliveira
14+
*/
1115
public class NFCeUtil {
1216

1317
/**
14-
*
1518
* Funcao Responsavel por Devolver o QrCode já no padrão da Nota.
1619
*
17-
* @param chave : Chave de Acesso da NFCe
18-
* @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
19-
* @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
20-
* @param CSC : Código de Segurança do Contribuinte (antigo Token)
20+
* @param chave : Chave de Acesso da NFCe
21+
* @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
22+
* @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
23+
* @param CSC : Código de Segurança do Contribuinte (antigo Token)
2124
* @param urlConsulta : Url De Consulta da Nfc-e do Estado
22-
*
25+
* <p>
26+
* A NT 2025-001 define que deve ser utilizado o padrao v3 para o QrCode da NFC-e.
27+
* Essa funcao será deletada em breve, e a nova funcao getCodeQRCodeV3 deve ser utilizada.
2328
* @return String do QrCode
2429
*/
30+
@Deprecated
2531
public static String getCodeQRCode(String chave, String ambiente, String idToken, String CSC, String urlConsulta) throws NoSuchAlgorithmException {
2632

2733
StringBuilder value = new StringBuilder();
@@ -34,6 +40,21 @@ public static String getCodeQRCode(String chave, String ambiente, String idToken
3440
return urlConsulta + "?p=" + value + "|" + cHashQRCode;
3541
}
3642

43+
/**
44+
* Funcao Responsavel por Devolver o QrCode V3 já no padrão da Nota.
45+
*
46+
* @param chave : Chave de Acesso da NFCe
47+
* @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
48+
* @param urlConsulta : Url De Consulta da Nfc-e do Estado
49+
*
50+
* Para NFC-e emitida “on-line”: https://endereco-consulta-QRCode?p=<chave_acesso>|<versao_qrcode>|<tpAmb>
51+
*
52+
* @return String do QrCode
53+
*/
54+
public static String getCodeQRCodeV3(String chave, String ambiente, String urlConsulta) {
55+
return String.format("%s?p=%s|3|%s", urlConsulta, chave, ambiente);
56+
}
57+
3758
/**
3859
* Funcao Responsavel por Devolver o QrCode já no padrão da Nota.
3960
*
@@ -42,8 +63,13 @@ public static String getCodeQRCode(String chave, String ambiente, String idToken
4263
* @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
4364
* @param CSC : Código de Segurança do Contribuinte (antigo Token)
4465
* @param urlConsulta : Url De Consulta da Nfc-e do Estado
66+
* <p>
67+
* A NT 2025-001 define que deve ser utilizado o padrao v3 para o QrCode da NFC-e.
68+
* Essa funcao será deletada em breve, e a nova funcao getCodeQRCodeV3 deve ser utilizada.
69+
*
4570
* @return String do QrCode
4671
*/
72+
@Deprecated
4773
public static String getCodeQRCodeContingencia(String chave, String ambiente, String dhEmi, String valorNF, String digVal, String idToken, String CSC, String urlConsulta) throws NoSuchAlgorithmException {
4874

4975
StringBuilder value = new StringBuilder();
@@ -57,16 +83,46 @@ public static String getCodeQRCodeContingencia(String chave, String ambiente, St
5783
String cHashQRCode = getHexa(getHash(value.toString() + CSC)).toUpperCase();
5884

5985
return urlConsulta + "?p=" + value + "|" + cHashQRCode;
86+
6087
}
6188

6289
/**
90+
* Funcao Responsavel por Devolver o QrCode V3 de contingencia já no padrão da Nota.
91+
*
92+
* @param chave : Chave de Acesso da NFCe
93+
* @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
94+
* @param dhEmi : Campo dhEmi (B09) da NFCe
95+
* @param valorNF : Campo de Valor da Nota (W16)
96+
* @param tpDestinatario : 1=CNPJ; 2=CPF; 3=idEstrangeiro; Caso Destinatário estrangeiro ou não identificado, informar apenas nulo ou vazio
97+
* @param identDest : Identificação do Destinatário CPF ou CNPJ na NFC-e.; Caso Destinatário estrangeiro ou não identificado, informar apenas nulo ou vazio
98+
* @param urlConsulta : Url De Consulta da Nfc-e do Estado
99+
*
100+
* Para NFC-e emitida em contingência “off-line”:
101+
* https://endereco-consultaQRCode?p=<chave_acesso>|<versao_qrcode>|<tpAmb>|<dia_data_emissao>|<vNF>|<tp_idDest>|<idDest>|<assinatura>
63102
*
103+
* @return String do QrCode
104+
*/
105+
public static String getCodeQRCodeContingenciaV3(String chave, String ambiente, String dhEmi, String valorNF,
106+
String tpDestinatario, String identDest, String urlConsulta,
107+
Certificado certificado) throws NfeException {
108+
109+
String valor = String.format("%s?p=%s|3|%s|%s|%s|%s|%s",
110+
urlConsulta, chave, ambiente, dhEmi.substring(8, 10), valorNF,
111+
Optional.ofNullable(tpDestinatario).orElse(""),
112+
Optional.ofNullable(identDest).orElse(""));
113+
114+
String assinatura = "";
115+
return valor + "|" + assinarQrCodeV3(valor,certificado);
116+
117+
}
118+
119+
/**
64120
* Função responsável por gerar o hashCSRT conforme definições da NT2018.005 v1.40.
65121
*
66122
* @param chave Chave da nota fiscal com 44 caracteres.
67-
* @param csrt Token/Código de Segurança do Responsável Técnico, fornecido pela Sefaz de da estado.
123+
* @param csrt Token/Código de Segurança do Responsável Técnico, fornecido pela Sefaz de da estado.
68124
* @return bytes conforme definição da NF2018.005 v1.40 sem fazer encode em base64.
69-
* Isso porque já será feito ao gerar o xml devido ao tipo no XSD ser xs:base64Binary.
125+
* Isso porque já será feito ao gerar o xml devido ao tipo no XSD ser xs:base64Binary.
70126
* @throws NoSuchAlgorithmException caso não encontre suporte para SHA-1.
71127
*/
72128
public static byte[] geraHashCSRT(String chave, String csrt) throws NoSuchAlgorithmException {
@@ -79,23 +135,22 @@ public static byte[] geraHashCSRT(String chave, String csrt) throws NoSuchAlgori
79135
return getHash(csrt + chave);
80136
}
81137

82-
83-
/**
84-
* @param valor
85-
* @return
86-
*/
138+
/**
139+
* @param valor
140+
* @return
141+
*/
87142
private static byte[] getHash(String valor) throws NoSuchAlgorithmException {
88143

89-
MessageDigest md = MessageDigest.getInstance("SHA-1");
90-
md.update(valor.getBytes());
91-
return md.digest();
144+
MessageDigest md = MessageDigest.getInstance("SHA-1");
145+
md.update(valor.getBytes());
146+
return md.digest();
147+
}
148+
149+
private static String getHexa(String valor) {
150+
return getHexa(valor.getBytes());
92151
}
93-
94-
private static String getHexa(String valor) {
95-
return getHexa(valor.getBytes());
96-
}
97-
98-
private static String getHexa(byte[] bytes) {
152+
153+
private static String getHexa(byte[] bytes) {
99154
StringBuilder s = new StringBuilder();
100155
for (byte aByte : bytes) {
101156
int parteAlta = ((aByte >> 4) & 0xf) << 4;
@@ -104,9 +159,27 @@ private static String getHexa(byte[] bytes) {
104159
s.append('0');
105160
}
106161
s.append(Integer.toHexString(parteAlta | parteBaixa));
107-
}
108-
return s.toString();
109-
}
162+
}
163+
return s.toString();
164+
}
165+
166+
private static String assinarQrCodeV3(String dados, Certificado certificado) throws NfeException {
167+
try {
168+
KeyStore keyStore = CertificadoService.getKeyStore(certificado);
169+
170+
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(certificado.getNome(),
171+
new KeyStore.PasswordProtection(ObjetoUtil.verifica(certificado.getSenha()).orElse("").toCharArray()));
172+
173+
PrivateKey privateKey = pkEntry.getPrivateKey();
174+
Signature signature = Signature.getInstance("SHA1withRSA");
175+
signature.initSign(privateKey);
176+
signature.update(dados.getBytes(StandardCharsets.UTF_8));
177+
byte[] signed = signature.sign();
178+
return Base64.getEncoder().encodeToString(signed);
179+
} catch (Exception e) {
180+
throw new NfeException("Erro ao gerar assinatura do QRCode V3: " + e.getMessage(), e);
181+
}
182+
}
110183

111184
}
112185

0 commit comments

Comments
 (0)