FinOpenPOS
Fiscal Module

Fiscal Module Architecture

The fiscal module implements complete Brazilian electronic invoicing (NF-e model 55 and NFC-e model 65) following the SEFAZ MOC 4.00 specification, ported from PHP sped-nfe to TypeScript with a DDD layered architecture.

Overview

The fiscal module implements complete Brazilian electronic invoicing (NF-e model 55 and NFC-e model 65) following the SEFAZ MOC 4.00 specification. It was ported from the PHP sped-nfe library to TypeScript, adapted to a DDD (Domain-Driven Design) layered architecture.

Monorepo Structure

The project uses a Turborepo monorepo. The pure fiscal logic lives in a standalone package (@finopenpos/fiscal) at packages/fiscal/, with zero database dependencies. The DB-coupled files (repositories and invoice service) live in the app layer at apps/web/src/lib/.

  • packages/fiscal/src/ — standalone fiscal package (domain logic, XML, SEFAZ, etc.)
  • apps/web/src/lib/ — DB-coupled service/repository files (invoice-service, invoice-repository, fiscal-settings-repository)
  • apps/web/src/ — Next.js app (pages, tRPC routers, etc.)

Layer Diagram

┌─────────────────────────────────────────────────────────────┐
│  Presentation Layer (apps/web/)                              │
│  fiscal/page.tsx, fiscal/[id]/page.tsx, settings/page.tsx   │
│  FormTextField, invoiceStatusBadgeVariant                   │
├─────────────────────────────────────────────────────────────┤
│  Application Layer (apps/web/src/lib/trpc/)                  │
│  routers/fiscal.ts, routers/fiscal-settings.ts              │
├─────────────────────────────────────────────────────────────┤
│  Domain Services (apps/web/src/lib/)                         │
│  invoice-service.ts (orchestrates the invoice lifecycle)    │
├─────────────────────────────────────────────────────────────┤
│  Domain Logic (packages/fiscal/src/)                         │
│  tax-icms.ts, tax-pis-cofins-ipi.ts, tax-issqn.ts          │
│  value-objects/access-key.ts, value-objects/tax-id.ts       │
│  tax-element.ts (decoupling pattern)                        │
├─────────────────────────────────────────────────────────────┤
│  Infrastructure (packages/fiscal/src/)                       │
│  xml-builder.ts, xml-utils.ts, complement.ts                │
│  sefaz-transport.ts, sefaz-request-builders.ts              │
│  sefaz-response-parsers.ts, sefaz-urls.ts                   │
│  certificate.ts, qrcode.ts, contingency.ts                  │
│  convert.ts, txt-structures.ts                              │
├─────────────────────────────────────────────────────────────┤
│  Persistence (apps/web/src/lib/)                             │
│  fiscal-settings-repository.ts, invoice-repository.ts       │
│  Drizzle ORM + PGLite (apps/web/src/lib/db/schema.ts)       │
└─────────────────────────────────────────────────────────────┘

Dependency Flow

invoice-service
├── fiscal-settings-repository ──→ DB (fiscalSettings)
├── invoice-repository ──→ DB (invoices, invoiceItems, invoiceEvents)
├── certificate.ts ──→ node:crypto, xml-crypto
├── xml-builder.ts
│   ├── tax-icms.ts ──→ tax-element.ts
│   ├── tax-pis-cofins-ipi.ts ──→ tax-element.ts
│   ├── value-objects/ (AccessKey, TaxId)
│   ├── xml-utils.ts (tag, escapeXml)
│   └── format-utils.ts
├── sefaz-client.ts
│   ├── sefaz-transport.ts ──→ curl (mTLS)
│   ├── sefaz-request-builders.ts
│   ├── sefaz-response-parsers.ts
│   └── sefaz-urls.ts
├── complement.ts (protocol attachment)
└── qrcode.ts (NFC-e QR code)

Key rule: Tax modules (domain) never import xml-builder (infrastructure). They return TaxElement structures, which xml-builder serializes. This prevents circular dependencies and keeps domain logic pure.

Numeric Conventions

ConceptStorageExampleXML Output
Monetary (vBC, vICMS, vNF)Cents (integer)1050"10.50"
ICMS/FCP rates (pICMS, pFCP)Hundredths (4dp)180000"18.0000"
PIS/COFINS rates (pPIS)x10000 (4dp)16500"1.6500"
Quantitiesx1000 (3dp)1500"1.500"

Key Domain Types

TypeValuesMeaning
InvoiceModel55, 65NF-e (B2B), NFC-e (consumer)
InvoiceStatuspending, authorized, rejected, cancelled, denied, contingency, voidedLifecycle states
SefazEnvironment1, 2Production, Homologation
EmissionType1, 6, 7, 9Normal, SVC-AN, SVC-RS, Offline
TaxRegime1, 2, 3Simples Nacional, Simples excess, Normal

Multi-Tenancy

All database tables are keyed by user_uid. Every repository function receives userUid as first parameter. There is no cross-tenant data access.

File Index

All files in the @finopenpos/fiscal package live under packages/fiscal/src/. The three DB-coupled files live in apps/web/src/lib/.

FileLocationLayerPurpose
types.tspackages/fiscal/src/DomainAll type definitions
constants.tspackages/fiscal/src/DomainXML namespaces, payment codes
state-codes.tspackages/fiscal/src/DomainUF - IBGE code mapping
sefaz-status-codes.tspackages/fiscal/src/DomaincStat response codes
value-objects/access-key.tspackages/fiscal/src/Domain44-digit access key
value-objects/tax-id.tspackages/fiscal/src/DomainCPF/CNPJ value object
format-utils.tspackages/fiscal/src/DomainCents/rate formatting
tax-element.tspackages/fiscal/src/DomainTaxElement decoupling pattern
tax-icms.tspackages/fiscal/src/DomainICMS tax (15+ variants)
tax-pis-cofins-ipi.tspackages/fiscal/src/DomainPIS, COFINS, IPI, II
tax-issqn.tspackages/fiscal/src/DomainISS (services)
tax-is.tspackages/fiscal/src/DomainIS (consumption)
xml-utils.tspackages/fiscal/src/Infratag(), escapeXml(), extractXmlTagValue()
xml-builder.tspackages/fiscal/src/InfraFull NF-e XML generation
complement.tspackages/fiscal/src/InfraProtocol attachment
certificate.tspackages/fiscal/src/InfraPFX extraction, XML signing
sefaz-urls.tspackages/fiscal/src/InfraState endpoint registry
sefaz-transport.tspackages/fiscal/src/InfraSOAP HTTP + mTLS via curl
sefaz-request-builders.tspackages/fiscal/src/InfraRequest XML generators
sefaz-response-parsers.tspackages/fiscal/src/InfraResponse parsing
sefaz-event-types.tspackages/fiscal/src/InfraEvent constants + helpers
sefaz-reform-events.tspackages/fiscal/src/InfraIBS/CBS reform events
contingency.tspackages/fiscal/src/InfraOffline fallback config
contingency-nfe.tspackages/fiscal/src/InfraNF-e contingency adjustments
epec-nfce.tspackages/fiscal/src/InfraNFC-e EPEC registration
qrcode.tspackages/fiscal/src/InfraNFC-e QR code generation
convert.tspackages/fiscal/src/InfraTXT - XML conversion
txt-structures.tspackages/fiscal/src/InfraTXT field layouts
valid-txt.tspackages/fiscal/src/InfraTXT validation
standardize.tspackages/fiscal/src/InfraXML type detection
gtin.tspackages/fiscal/src/InfraBarcode validation
cep-lookup.tspackages/fiscal/src/InfraCEP/postal code lookup
config-validate.tspackages/fiscal/src/InfraConfig JSON validation
invoice-service.tsapps/web/src/lib/ServiceInvoice lifecycle orchestration
fiscal-settings-repository.tsapps/web/src/lib/PersistenceSettings CRUD
invoice-repository.tsapps/web/src/lib/PersistenceInvoice CRUD

On this page