Skip to content

Taxes and Invoices ​

Tax handling and invoice generation in MIDDAG Account involve three systems: WooCommerce (tax calculation), Stripe (invoice generation), and ISSNet (Brazilian tax invoices). Which systems are involved depends on the billing entity for the transaction.

Dual-entity tax routing ​

Every transaction is routed to either MIDDAG BR (Brazilian entity) or MIDDAG GLOBAL (US LLC). The entity determines which tax and invoicing systems apply:

CapabilityMIDDAG BRMIDDAG GLOBAL
CurrencyBRLUSD
Stripe accountStripe BRStripe US
InvoiceStripe Invoice (BRL)Stripe Invoice (USD)
Tax invoice (NFSe)Yes -- ISSNet, Brasilia/DFNo
Payment methodsCredit card, Pix, BoletoCredit card
Tax rulesBrazilian municipal tax (ISS) + federalUS tax (varies by state)

The routing decision follows this hierarchy:

  1. Explicit product entity assignment (if the product's channels block enables only one entity)
  2. Organization's billing_entity setting
  3. Auto-detection from tax ID (CNPJ = BR; EIN/VAT = GLOBAL)
  4. Fallback to preferred currency (BRL = BR; USD = GLOBAL)

Admin can override the entity per transaction.

Tax handling in WooCommerce ​

WooCommerce manages tax calculation for orders:

  • Tax rates are configured in WooCommerce > Settings > Tax
  • Tax classes map to product types (standard, reduced, zero-rated)
  • Automatic tax calculation uses WooCommerce's built-in engine or a tax plugin

MIDDAG Account does not override or duplicate WooCommerce tax settings. Tax configuration remains entirely in WooCommerce.

Stripe invoices ​

Stripe generates an invoice for every payment. MIDDAG Account syncs these invoices locally through webhooks:

When invoices are created ​

EventInvoice created by
One-time payment completedStripe (automatically with charge)
Subscription renewal paidStripe (automatically with subscription)
Manual invoice sentAdmin creates in Stripe

Webhook sync ​

The InvoiceStripeService processes webhooks from both Stripe accounts (BR and GLOBAL). Key events:

Webhook eventAction in MIDDAG Account
invoice.createdLocal invoice record created
invoice.finalizedInvoice marked as finalized (immutable)
invoice.paidInvoice marked as paid, linked to order and entitlement
invoice.payment_failedPayment failure recorded, triggers recovery policy
invoice.voidedInvoice voided locally
invoice.marked_uncollectibleInvoice marked as uncollectible
invoice.overdueInvoice marked as overdue, admin notified

A reconciliation cron job runs every 15 minutes to catch any missed webhooks and resolve state inconsistencies between Stripe and local records.

Invoices are linked to entitlements indirectly through orders:

Stripe Invoice -> WooCommerce Order -> Entitlement

There is no direct entitlement_id on the invoice record. The chain is: invoice references a Stripe charge, the charge maps to a WC order, and the order maps to the entitlement.

Invoice PDF ​

Stripe generates PDF invoices automatically. These PDFs are available for download by the customer through the portal. MIDDAG Account does not generate its own invoice PDFs -- it uses Stripe's.

Tax invoices (NFSe) -- Brazilian operations only ​

For transactions processed through MIDDAG BR, a TaxInvoice (NFSe) -- Nota Fiscal de Servico Eletronica -- is issued via the ISSNet municipal tax system in Brasilia/DF.

When NFSe is issued ​

An NFSe is issued after a Stripe invoice is paid for a BR entity transaction. The flow:

ISSNet integration ​

The TaxInvoice domain integrates with ISSNet through SOAP API calls:

OperationDescription
Issue NFSeSubmit XML with provider, recipient, service, tax values
Query NFSeCheck status of submitted NFSe (authorized, rejected)
Cancel NFSeCancel a previously authorized NFSe (requires justification)

Because ISSNet does not support webhooks, a polling cron job runs every 5 minutes to check the status of pending NFSe submissions.

NFSe PDF storage ​

Authorized NFSe PDFs are generated and stored in Cloudflare R2. A cached URL is available through the REST API for portal download. Each TaxInvoice PDF references the originating Stripe Invoice for traceability.

Product NFSe readiness ​

Each product YAML can include NFSe-specific fields:

yaml
nfse:
  city_service_code: "01.07"
  federal_service_code: "1.07"
  description: "Licenciamento de software"

Products without these codes cannot have NFSe issued automatically. The catalog report (composer catalog:report) flags products that need NFSe codes.

What the admin sees ​

  • Invoices list -- All synced Stripe invoices with status, amount, currency, and entity
  • TaxInvoice list -- All NFSe records with ISSNet status (pending, authorized, rejected, cancelled)
  • Per-entitlement view -- Invoices and tax invoices linked to a specific entitlement via its order
  • Reconciliation dashboard -- Shows sync status between Stripe and local records