Biblioteca PHP independente de frameworks para validar documentos fiscais, gerar XML DFE v11, validar com os XSD oficiais, assinar com XAdES-BES, criar pacotes ZIP e comunicar com serviços e-Fatura de Cabo Verde.
Important
Este projecto não é oficial da DNRE. A utilização em produção exige homologação do software, credenciais válidas e testes nos ambientes oficiais.
- nove tipos de documento:
FTE,FRE,TVE,RCE,NCE,NDE,DTE,DVEeNLE; - geração, validação e interpretação de IUD;
- validação de NIF, entidades, linhas, impostos e reconciliação de totais;
- emissão online e em contingência;
- geração de XML compacto DFE v11;
- ciclo de eventos
FDCeUDN, incluindo XML, ZIP e submissão; - validação com os XSD oficiais de 27 de Maio de 2024;
- assinatura XAdES-BES com RSA-SHA256;
- validação de certificados e correspondência da chave privada;
- pacotes ZIP Deflate com nomes
{IUD}.xml; - sequências e idempotência em memória ou transaccionais por PDO;
- submissão por middleware e directamente à plataforma;
- consultas fiscais, repetição segura e reconciliação através de PSR-18;
- cálculos monetários com representação decimal exacta;
- DFA em PDF com QR Code;
- DTOs imutáveis e tipados, sem retirar a API por arrays;
- integrações opcionais com Laravel, Symfony e Yii2;
- CLI para inspeccionar IUDs e validar XML;
- respostas JSON/XML normalizadas;
- nenhuma dependência de Laravel, Symfony ou outro framework.
O fluxo completo, com decisões de contingência, validação, assinatura, submissão e reconciliação, está documentado em Arquitectura.
- PHP 8.1 ou superior;
- extensões
curl,dom,json,libxml,opensslezip.
composer require kowts/efatura-cvPara instalar directamente do ramo de desenvolvimento, pode declarar o repositório Git:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/Kowts/efatura-cv-php"
}
],
"require": {
"kowts/efatura-cv": "dev-main"
}
}<?php
use Kowts\Efatura\Config\EfaturaConfig;
use Kowts\Efatura\Domain\DocumentType;
use Kowts\Efatura\Domain\Environment;
use Kowts\Efatura\Efatura;
$efatura = new Efatura(new EfaturaConfig(
transmitterNif: '123456789',
transmitterLed: '001',
softwareCode: 'MEUSOFT',
softwareName: 'Meu Software',
softwareVersion: '1.0.0',
middlewareBaseUrl: 'https://middleware.exemplo.cv',
transmitterKey: getenv('EFATURA_TRANSMITTER_KEY') ?: null,
defaultSerie: 'SER-F',
emitter: [
'taxId' => ['countryCode' => 'CV', 'value' => '123456789'],
'name' => 'Empresa, Lda.',
'address' => ['countryCode' => 'CV', 'addressDetail' => 'Praia'],
'contacts' => ['email' => 'facturacao@exemplo.cv', 'telephone' => '2600000'],
],
environment: Environment::Test
));
$invoice = $efatura->document()
->type(DocumentType::ElectronicInvoice)
->issueDate('2026-07-08')
->issueTime('10:30:00')
->receiver([
'taxId' => ['countryCode' => 'CV', 'value' => '987654321'],
'name' => 'Cliente',
])
->line([
'quantity' => ['value' => 1, 'unitCode' => 'UN'],
'price' => 1000,
'priceExtension' => 1000,
'netTotal' => 1000,
'taxes' => [[
'taxTypeCode' => 'IVA',
'taxPercentage' => 15,
'taxTotal' => 150,
]],
'item' => [
'description' => 'Serviço',
'emitterIdentification' => 'SERV-1',
],
])
->totals([
'priceExtensionTotalAmount' => 1000,
'netTotalAmount' => 1000,
'taxTotalAmount' => 150,
'payableAmount' => 1150,
])
->validate();
$number = $efatura->nextDocumentNumber($invoice['issueDate'], $invoice['type']);
$iud = $efatura->buildIud($invoice['issueDate'], $invoice['type'], $number);
$xml = $efatura->buildDfeXml($iud, $invoice);
$xsd = $efatura->validateXml($xml);
if (!$xsd['valid']) {
throw new RuntimeException(json_encode($xsd['errors'], JSON_THROW_ON_ERROR));
}
$signed = $efatura->signXml(
$xml,
file_get_contents('/segredos/certificado.pem'),
file_get_contents('/segredos/chave-privada.pem'),
getenv('EFATURA_KEY_PASSWORD') ?: null
);
$zip = $efatura->buildDfeZip([['iud' => $iud, 'xml' => $signed['xml']]]);
$result = $efatura->submitDfeZip($zip);Instale também o Yii2 na aplicação consumidora:
composer require yiisoft/yii2Para arranque local, testes ou ambientes sem submissão fiscal real, pode
registar o componente apenas com config:
use Kowts\Efatura\Bridge\Yii2\EfaturaComponent;
return [
'components' => [
'efatura' => [
'class' => EfaturaComponent::class,
'config' => [
'transmitter_nif' => '100200300',
'transmitter_led' => '001',
'software_code' => 'MEUSOFT',
'software_name' => 'Meu Software',
'software_version' => '1.0.0',
'environment' => 'TEST',
],
],
],
];Warning
Em produção, configure o componente Yii2 através da propriedade factory,
utilizando PdoSequenceStore e PdoSubmissionRegistry. O armazenamento em
memória destina-se apenas a desenvolvimento e testes.
Consulte docs/yii2.md para a configuração completa.
Depois use a biblioteca sem duplicar regras fiscais:
use Kowts\Efatura\Domain\DocumentType;
$iud = Yii::$app->efatura->buildSequentialIud('2026-07-08', DocumentType::ElectronicInvoice);
$xml = Yii::$app->efatura->buildDfeXml($iud, $documento);Em produção, construa o cliente com uma factory e stores persistentes:
use Kowts\Efatura\Bridge\Yii2\EfaturaComponent;
use Kowts\Efatura\Config\EfaturaConfig;
use Kowts\Efatura\Efatura;
use Kowts\Efatura\Infrastructure\Sequence\PdoSequenceStore;
use Kowts\Efatura\Infrastructure\Submission\PdoSubmissionRegistry;
return [
'components' => [
'efatura' => [
'class' => EfaturaComponent::class,
'config' => [
// Mesma configuração fiscal do exemplo anterior.
],
'factory' => static function (EfaturaComponent $component): Efatura {
$pdo = Yii::$app->db->pdo;
$prefix = Yii::$app->db->tablePrefix;
return new Efatura(
EfaturaConfig::fromArray($component->config),
sequenceStore: new PdoSequenceStore($pdo, $prefix . 'efatura_sequences'),
submissionRegistry: new PdoSubmissionRegistry($pdo, $prefix . 'efatura_submissions'),
);
},
],
],
];As tabelas de sequência e submissão devem ser criadas por migrações Yii2.
O armazenamento predefinido existe apenas em memória. Em produção, use uma base de dados para impedir números duplicados entre processos. A implementação PDO suporta SQLite, MySQL/MariaDB, PostgreSQL e SQL Server:
use Kowts\Efatura\Infrastructure\Sequence\PdoSequenceStore;
$pdo = new PDO('mysql:host=localhost;dbname=faturacao', 'utilizador', 'senha');
$sequences = new PdoSequenceStore($pdo);
$sequences->createTable(); // Execute uma vez, ou converta para uma migração.
$efatura = new Efatura($config, $sequences);A sequência é independente por NIF transmissor, ano, LED e tipo documental. Guarde sempre o IUD, XML, ZIP e resposta de transporte. Uma falha de rede não autoriza a reutilização ou substituição automática do número fiscal.
Consulte Persistência PDO para detalhes de motores suportados, migrações, idempotência e limites conhecidos.
- nunca envie chaves, certificados, tokens ou credenciais para o navegador;
- não guarde segredos no repositório;
- valide o certificado antes da emissão;
- use TLS e armazenamento cifrado;
- registe respostas técnicas sem expor dados pessoais ou segredos;
- fixe uma versão exacta do pacote em sistemas de produção.
Consulte Assinatura e certificados e Segurança.
- Arquitectura
- Referência da API
- Referência automática da API
- Auditoria técnica
- Conformidade
- Assinatura e certificados
- Persistência PDO
- Guia de produção
- Emissão em contingência
- Laravel, Symfony e Yii2
- Guia fiscal completo para Yii2
- Lançamentos e verificação
- Exemplos completos
- Exemplo em PHP puro
- Exemplos dos tipos documentais
- Contribuir
O pacote está em desenvolvimento activo. Os XSD oficiais estão incluídos, mas não foram publicados vectores oficiais para comparar byte a byte IUD, ZIP e assinaturas. Os testes internos não devem ser confundidos com certificação oficial.
Os XSD incluídos são os artefactos do sistema e-Fatura de Cabo Verde.
MIT © 2026 Kowts.
