FocusNFe Brazilian fiscal Issuer NF-e NFC-e Java REST API Client (Open Source)

Maven Central Javadocs Build Status Coverage Codacy Badge Codacy Badge

focusnfe

Java Connector - FocusNFe Brazilian fiscal Issuer NF-e NFC-e MD-e API

Built-based on the documentation: https://focusnfe.com.br/doc/

Supported Java Versions:

Maven dependency:

<dependency>
    <groupId>org.frekele.fiscal</groupId>
    <artifactId>focusnfe-api-client</artifactId>
    <version>1.0.4</version>
</dependency>

Gradle dependency:

compile 'org.frekele.fiscal:focusnfe-api-client:1.0.4'

Java Documetation

Repositories:

Interfaces Descriptions Usage Examples
FocusNFeV2Repository NF-e API V2 remote call FocusNFeV2RepositoryIT
FocusNFCeV2Repository NFC-e API V2 remote call FocusNFCeV2RepositoryIT
FocusMDeV2Repository MD-e API V2 remote call FocusMDeV2RepositoryIT
FocusWebHookV2Repository WebHook API V2 remote call FocusWebHookV2RepositoryIT
FocusNcmV2Repository NCM API V2 remote call FocusNcmV2RepositoryIT
FocusBackupV2Repository Backups API V2 remote call FocusBackupV2RepositoryIT
FocusDownloadRepository Download Files remote call FocusDownloadRepositoryIT

Sample Example

public class MyMainExample {

    public static void main(String[] args) {
        ResteasyClient client = new ResteasyClientBuilder().build();
        FocusNFeAuth auth = FocusNFeAuth.newBuilder()
            .withAccessToken("your-token-here")
            .withEnvironment(EnvironmentFocusNFeEnum.HOMOLOGATION)
            .build();

        FocusNFeV2Repository nfeRepository = new FocusNFeV2RepositoryImpl(client, auth);

        String reference = "your-nfe-reference";
        NFeConsultarBodyResponse bodyResponse = nfeRepository.consultarNFeCompleta(reference).getBody();

        NFeRetornoRequisicaoNotaFiscal requisicaoNotaFiscal = bodyResponse.getRequisicaoNotaFiscal();
        NFeProtocoloNotaFiscal protocoloNotaFiscal = bodyResponse.getProtocoloNotaFiscal();
        
        String chaveNfe = requisicaoNotaFiscal.getChaveNfe();
        String numeroProtocolo = protocoloNotaFiscal.getNumeroProtocolo();
        String pathXmlNFe = bodyResponse.getCaminhoXmlNotaFiscal();
        String pathDanfeNFe = bodyResponse.getCaminhoDanfe();

        FocusDownloadRepository downloadRepository = new FocusDownloadRepositoryImpl(client, auth);
        
        InputStream xmlInputStream = downloadRepository.downloadXml(pathXmlNFe).getBody();
        InputStream pdfInputStream = downloadRepository.downloadPdf(pathDanfeNFe).getBody();
    }
}

Usage with CDI (Contexts and Dependency Injection)

public class FocusNFeProducer {

    @Produces
    @FocusNFe
    public FocusNFeAuth producesFocusNFeAuth() {
        String accessToken = System.getenv("FOCUS_NFE_ACCESS_TOKEN");
        String environment = System.getenv("FOCUS_NFE_ENVIRONMENT");
        return new FocusNFeAuth(accessToken, environment);
    }

    @Produces
    @FocusNFe
    public ResteasyClient producesResteasyClient() {
        ResteasyClient client = new ResteasyClientBuilder()
                // Example:
                // Register your Custom Logging here.
                //.register(CustomLoggingFilter.class)
                .build();
        return client;
    }

    public void closeResteasyClient(@Disposes @FocusNFe ResteasyClient client) {
        client.close();
    }
}

//Then you just need to @inject.
public class MyService {

    @Inject
    @FocusNFe
    private FocusNFeV2Repository repository;

    public void callExample() {
        String reference = UUID.randomUUID().toString();
        NFeEnvioRequisicaoNotaFiscal nfe = NFeEnvioRequisicaoNotaFiscal.newBuilder()
            .withNaturezaOperacao("VENDA DE MERCADORIA")
            .withDataEmissao(OffsetDateTime.now())
            .withTipoDocumento(NFeTipoDocumentoEnum.NOTA_FISCAL_SAIDA)
	    ........... (add more fields)
            .build();
        NFeAutorizarResponse response = repository.autorizar(reference, new NFeAutorizarBodyRequest(nfe));
        NFeAutorizarBodyResponse body = response.getBody();
    }
}

Usage without CDI

public class MyService {
    
    public void callExample() {
        //First create FocusNFeAuth
        Properties prop = // read your Properties or System.env
        String accessToken = prop.getProperty("accessToken");
        String environment = prop.getProperty("environment"); // PRODUCTION OR HOMOLOGATION
        FocusNFeAuth auth = FocusNFeAuth.newBuilder()
                .withAccessToken(accessToken)
                .withEnvironment(environment)
                .build();

        //Build one client per thread, or use CDI Injection.
        ResteasyClient client = new ResteasyClientBuilder()
                // Example, you can customize a connections.
                // Add proxy.
                //.defaultProxy("192.168.56.67", 3456)
                // Change connection Pool size.
                //.connectionPoolSize(3)
                // Change connection TTL.
                //.connectionTTL(30, TimeUnit.MINUTES)
                .build();

        FocusNFeV2Repository repository = new FocusNFeV2RepositoryImpl(client, auth);
        repository.autorizar(reference, new NFeAutorizarBodyRequest(nfe));

        //Is important to close in end, or use CDI.
        client.close();
    }
}

Example usage NF-e and NFC-e

POST - Autorizar NF-e (Asynchronous)

String reference = UUID.randomUUID().toString();
NFeEnvioRequisicaoNotaFiscal nfe = NFeEnvioRequisicaoNotaFiscal.newBuilder()
    .withNaturezaOperacao("VENDA DE MERCADORIA")
    .withDataEmissao(OffsetDateTime.now())
    .withTipoDocumento(NFeTipoDocumentoEnum.NOTA_FISCAL_SAIDA)
    .withFinalidadeEmissao(NFeFinalidadeEmissaoEnum.NOTA_NORMAL)
    .withCnpjEmitente("your-cnpj-here")
    .withNomeDestinatario("NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL")
    .withCpfDestinatario("98445556550")
    .withTelefoneDestinatario("5196185555")
    .withLogradouroDestinatario("Av Otto Niemeyer")
    .withNumeroDestinatario("600")
    .withBairroDestinatario("Tristeza")
    .withMunicipioDestinatario("Porto Alegre")
    .withUfDestinatario(NFeUnidadeFederativaEnum.RIO_GRANDE_DO_SUL)
    .withCepDestinatario("91910-001")
    .withModalidadeFrete(NFeModalidadeFreteEnum.POR_CONTA_EMITENTE)
    .withItems(new ArrayList<>())
    .build();
NFeItem item = NFeItem.newBuilder()
    .withNumeroItem("1")
    .withCodigoProduto("XYZ-12345")
    .withDescricao("Produto Teste 12345 XYZ")
    .withCfop("5102")
    .withCodigoNcm("94036000")
    .withUnidadeComercial("UN")
    .withQuantidadeComercial(BigDecimal.valueOf(1))
    .withValorUnitarioComercial(new BigDecimal("124.35"))
    .withUnidadeTributavel("UN")
    .withQuantidadeTributavel(BigDecimal.valueOf(1))
    .withValorUnitarioTributavel(new BigDecimal("124.35"))
    .withValorBruto(new BigDecimal("124.35"))
    .withIcmsSituacaoTributaria(NFeIcmsSituacaoTributariaEnum.TRIBUTADA_SIMPLES_NACIONAL_SEM_PERMISSAO_CREDITO)
    .withIcmsOrigem(NFeIcmsOrigemEnum.NACIONAL)
    .withPisSituacaoTributaria(NFePisCofinsSituacaoTributariaEnum.OPERACAO_ISENTA_DA_CONTRIBUICAO)
    .withCofinsSituacaoTributaria(NFePisCofinsSituacaoTributariaEnum.OPERACAO_ISENTA_DA_CONTRIBUICAO)
    .withIncluiNoTotal(NFeIncluiNoTotalEnum.SIM)
    .build();
nfe.getItems().add(item);

NFeAutorizarBodyRequest bodyRequest = NFeAutorizarBodyRequest.newBuilder().withNfe(nfe).build();
NFeAutorizarResponse response = repository.autorizar(reference, bodyRequest);

//Get Body with Json Object Mapping.
NFeAutorizarBodyResponse responseBody = response.getBody();
//Get Body with String.
String responseBodyString = response.getBodyString();

//Get Http Header 'X-Rate-Limit-Limit'.
String responseHeaderValue = response.getRateLimitLimit();
//Get Http Header 'X-Rate-Limit-Remaining'.
String responseHeaderValue = response.getRateLimitRemaining();
//Get Http Header 'X-Rate-Limit-Reset'.
String responseHeaderValue = response.getRateLimitReset();
//Get Http Header 'X-Runtime'.
String responseHeaderValue = response.getRuntime();

//Get Http Status Response.
String responseStatus = response.getStatus();

//Get All Http Response.
Response httpResponse = response.getResponse();

POST - Autorizar NFC-e (Synchronous)

.....
NFCeAutorizarBodyRequest bodyRequest = new NFCeAutorizarBodyRequest(nfce);
NFCeAutorizarResponse response = repository.autorizarConsultarNFeCompleta(reference, bodyRequest);

POST - AutorizarConsultarNFeCompleta NFC-e (Synchronous)

.....
NFCeAutorizarBodyRequest bodyRequest = new NFCeAutorizarBodyRequest(nfce);
NFCeAutorizarResponse response = repository.autorizarConsultarNFeCompleta(reference, bodyRequest);

DELETE - Cancelar NF-e NFC-e

NFeCancelarResponse response = repository.cancelar(reference, new NFeCancelarBodyRequest("Teste de cancelamento de nota"));

//Or with Builder Pattern.
NFeCancelarBodyRequest bodyRequest = NFeCancelarBodyRequest.newBuilder()
    .withJustificativa("Teste de cancelamento de nota")
    .build();
NFeCancelarResponse response = repository.cancelar(reference, bodyRequest);

POST - EmitirCCe NF-e

NFeCCeBodyRequest bodyRequest = NFeCCeBodyRequest.newBuilder()
    .withCorrecao("Teste de carta de correcao")
    .build();
NFeCCeResponse response = repository.emitirCCe(reference, bodyRequest);

POST - EnviarEmail NF-e NFC-e

NFeEmailBodyRequest bodyRequest = NFeEmailBodyRequest.newBuilder()
    .withEmails("alguem@example.org", "teste@teste.com.br")
    .build();
NFeEmailResponse response = repository.enviarEmail(reference, bodyRequest);

GET - Consultar NF-e NFC-e

NFeConsultarResponse response = repository.consultar(reference);

GET - ConsultarNFeCompleta NF-e NFC-e

NFeConsultarResponse response = repository.consultarNFeCompleta(reference);

POST - Inutilizar NF-e NFC-e

NFeInutilizarBodyRequest bodyRequest = NFeInutilizarBodyRequest.newBuilder()
    .withCnpj("your-cnpj-here")
    .withSerie("1")
    .withNumeroInicial("7")
    .withNumeroFinal("9")
    .withJustificativa("Teste de inutilizacao de nota")
    .build();
NFeInutilizarResponse response = repository.inutilizar(bodyRequest);

Example usage MD-e

POST - Manifestar

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeManifestarBodyRequest bodyRequest = MDeManifestarBodyRequest.newBuilder()
    .withTipo(MDeTipoManifestacaoEnum.CONFIRMACAO)
    .withJustificativa("Fornecedor entregou produtos")
    .build();
MDeManifestarResponse response = repository.manifestar(chaveNFe, bodyRequest);

GET - ConsultarManifestos

String cnpjEmitente = "your-cnpj-here";
MDeConsultarManifestosResponse response = repository.consultarManifestos(cnpjEmitente);

//Or with parameter 'versao'
MDeConsultarManifestosResponse response = repository.consultarManifestos(cnpjEmitente, 40);

GET - ConsultarManifestos

String cnpjEmitente = "your-cnpj-here";
MDeConsultarManifestosResponse response = repository.consultarManifestosPendentes(cnpjEmitente);

//Or with parameter 'versao'
MDeConsultarManifestosResponse response = repository.consultarManifestosPendentes(cnpjEmitente, 40);

GET - ConsultarUltimoManifesto

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeConsultarUltimoManifestoResponse response = repository.consultarUltimoManifesto(chaveNFe);

GET - ConsultarNFe

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeConsultarNFeResponse response = repository.consultarNFe(chaveNFe);

GET - ConsultarNFeCompleta

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeConsultarNFeResponse response = repository.consultarNFeCompleta(chaveNFe);

GET - DownloadNFe

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeDownloadXmlResponse response = repository.downloadNFe(chaveNFe);

GET - DownloadCancelamento

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeDownloadXmlResponse response = repository.downloadCancelamento(chaveNFe);

GET - DownloadUltimaCCe

String chaveNFe = "41180684689100015855001002510000040306642480";
MDeDownloadXmlResponse response = repository.downloadUltimaCCe(chaveNFe);

Example usage WebHooks

POST - Criar

String cnpjEmitente = "your-cnpj-here";
WebHookCriarBodyRequest bodyRequest = WebHookCriarBodyRequest.newBuilder()
    .withCnpj(cnpjEmitente)
    .withEvent("nfe")
    .withUrl("http://minha.url/nfe")
    .build();
WebHookCriarResponse response = repository.criar(bodyRequest);
String webHookId = bodyResponse.getId());

GET - Consultar

WebHookConsultarResponse response = repository.consultar(webHookId);

GET - ConsultarTodos

WebHookConsultarTodosResponse response = repository.consultarTodos();

DELETE - Excluir

WebHookExcluirResponse response = repository.excluir(webHookId);

Example usage for search NCMs

GET - Consultar

NcmConsultarResponse response = repository.consultar("94036000");

GET - ConsultarTodos

NcmQueryParam queryParam = NcmQueryParam.newBuilder().build();
NcmConsultarTodosResponse response = repository.consultarTodos(queryParam);

GET - ConsultarTodos

NcmQueryParam queryParam = NcmQueryParam.newBuilder().build();
NcmConsultarTodosResponse response = repository.consultarTodos(queryParam);

//Or with queryParams
NcmQueryParam queryParam = NcmQueryParam.newBuilder()
    .withCapitulo("94")
    .withPosicao("03")
    .withSubposicao1("6")
    .withSubposicao2("0")
    .withItem1("0")
    .withItem2("0")
    .build();
NcmConsultarTodosResponse response = repository.consultarTodos(queryParam);

//Or with offset
NcmQueryParam queryParam = NcmQueryParam.newBuilder()
    .withCodigo("9")
    .withOffset("20")
    .build();
NcmConsultarTodosResponse response = repository.consultarTodos(queryParam);

Example usage for search Backups

GET - Consultar

String cnpjEmitente = "your-cnpj-here";
BackupConsultaResponse response = repository.consultarTodos(cnpjEmitente);

Example usage for Download Files

GET - DownloadXml

String reference = "your-reference";
 String pathXmlNFe = nfeRepository.consultar(reference).getBody().getCaminhoXmlNotaFiscal();
DownloadFileResponse response = downloadRepository.downloadXml(pathXmlNFe);
InputStream inputStream = response.getBody();

GET - DownloadPdf

String reference = "your-reference";
 String pathDanfeNFe = nfeRepository.consultar(reference).getBody().getCaminhoDanfe();
DownloadFileResponse response = downloadRepository.downloadPdf(pathDanfeNFe);
InputStream inputStream = response.getBody();

GET - DownloadHtml

String reference = "your-reference";
 String pathDanfeNFCe = nfeRepository.consultar(reference).getBody().getCaminhoDanfe();
DownloadFileResponse response = downloadRepository.downloadHtml(pathDanfeNFe);
InputStream inputStream = response.getBody();

GET - DownloadZip

String cnpjEmitente = "your-cnpj-here";
NFeBackup backup = backupRepository.consultarTodos(cnpjEmitente).getBody().getBackups().get(0);
DownloadFileResponse response = downloadRepository.downloadZip(backup.getDanfes());
InputStream inputStream = response.getBody();

Working with RestEasy (JAX-RS) Exceptions

try {
    MDeManifestarResponse response = repository.manifestar(chaveNFe, bodyRequest);
    MDeManifestarBodyResponse bodyResponse = response.getBody();
} catch (NotAuthorizedException e) {
    throw new FocusNFeException("User not Authorized!", e);
} catch (ClientErrorException e) {
    NFeErro nFeErro = e.getResponse().readEntity(NFeErro.class);
    throw new FocusNFeException("[ " + nFeErro.getCodigo() + " ] - " + nFeErro.getMensagem(), e);
} catch (WebApplicationException e) {
    int statusCode = e.getResponse().getStatus();
    String bodyError = e.getResponse().readEntity(String.class);
    throw new FocusNFeException(e);
}
HTTP Status Codes Expected RestEasy (JAX-RS) throw Exceptions
>= 200 && < 300 OK - Without exception.
>= 300 && < 400 throw new RedirectionException(response)
400 throw new BadRequestException(response)
401 throw new NotAuthorizedException(response)
403 throw new ForbiddenException(response)
404 throw new NotFoundException(response)
405 throw new NotAllowedException(response)
406 throw new NotAcceptableException(response)
415 throw new NotSupportedException(response)
500 throw new InternalServerErrorException(response)
503 throw new ServiceUnavailableException(response)
>= 400 && < 500 throw new ClientErrorException(response)
>= 500 throw new ServerErrorException(response)
Others throw new WebApplicationException(response)

Custom Logging for Response and Request

With the filter you can intercept all requests during sending and receiving responses. Everything before the Jackson conversion (json to Object) and (Object to Json).

public class CustomLoggingFilter implements ClientResponseFilter, ClientRequestFilter {

    private Logger logger = Logger.getLogger(CustomLoggingFilter.class.getName());

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        this.getLogger().debug("--> Request LoggingFilter: Uri = " + requestContext.getUri());
        this.getLogger().debug("--> Request LoggingFilter: Method= " + requestContext.getMethod());
        // Add more logs as you want.
    }

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
        this.getLogger().debug("<-- Response LoggingFilter:");
        this.getLogger().debug("<-- Response LoggingFilter: Status = " + responseContext.getStatus());
        // Add more logs as you want.
    }

    public Logger getLogger() {
        return logger;
    }
}

If you need to convert Json or Objects manually, do so:

Json –> JsonNode

JsonNode jsonNode = FocusNFeUtils.parseJsonToJsonNode(content);

Json –> Object

String content = "{ ..... }";
Class classType = MDeManifesto.class;
MDeManifesto manifesto = FocusNFeUtils.parseJsonTo(content, classType);

JsonNode –> String

String jsonString = FocusNFeUtils.parseJsonToString(jsonNode);

//with pretty printer
String jsonString = FocusNFeUtils.parseJsonToString(jsonNode, true);

Xml –> JsonNode

JsonNode jsonNode = FocusNFeUtils.parseXmlToJsonNode(content);

Xml –> Document

Document document = FocusNFeUtils.parseXmlToDocument(content);

Json –> Object

ObjectMapper mapper = new ObjectMapper();
String json = "{ ........ }";
MDeManifesto manifesto = mapper.readValue(json, MDeManifesto.class);

Json –> List

ObjectMapper mapper = new ObjectMapper();
String jsonArray = "[{ ........ }]";
List<MDeManifesto> manifestos = mapper.readValue(jsonArray, new TypeReference<List<MDeManifesto>>(){});

Object –> Json

ObjectMapper mapper = new ObjectMapper();
MDeManifesto manifesto = MDeManifesto.newBuilder().build();
String json = mapper.writeValueAsString(manifesto);

List –> Json

ObjectMapper mapper = new ObjectMapper();
List<MDeManifesto> manifestos = new ArrayList<>();
manifestos.add(manifesto1);
manifestos.add(manifesto2);
String jsonArray = mapper.writeValueAsString(manifestos);

InputStream –> byte[]

byte[] arrayBytes = FocusNFeUtils.parseToByteArray(inputStream);

InputStream –> ByteArrayOutputStream

ByteArrayOutputStream outputStream = FocusNFeUtils.parseToByteArrayOutputStream(inputStream);

Compile:

Compile with Maven:

mvn clean install -Dgpg.skip

Compile with integration Tests:

You need to add the environment variables to run the integration tests.

frekele/focusnfe-api-client is licensed under the [MIT License]. The terms of the license are as follows:

MIT License

Copyright (c) 2018 @frekele<Leandro Kersting de Freitas>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.