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:
| Capability | MIDDAG BR | MIDDAG GLOBAL |
|---|---|---|
| Currency | BRL | USD |
| Stripe account | Stripe BR | Stripe US |
| Invoice | Stripe Invoice (BRL) | Stripe Invoice (USD) |
| Tax invoice (NFSe) | Yes -- ISSNet, Brasilia/DF | No |
| Payment methods | Credit card, Pix, Boleto | Credit card |
| Tax rules | Brazilian municipal tax (ISS) + federal | US tax (varies by state) |
The routing decision follows this hierarchy:
- Explicit product entity assignment (if the product's channels block enables only one entity)
- Organization's
billing_entitysetting - Auto-detection from tax ID (CNPJ = BR; EIN/VAT = GLOBAL)
- 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
| Event | Invoice created by |
|---|---|
| One-time payment completed | Stripe (automatically with charge) |
| Subscription renewal paid | Stripe (automatically with subscription) |
| Manual invoice sent | Admin creates in Stripe |
Webhook sync
The InvoiceStripeService processes webhooks from both Stripe accounts (BR and GLOBAL). Key events:
| Webhook event | Action in MIDDAG Account |
|---|---|
invoice.created | Local invoice record created |
invoice.finalized | Invoice marked as finalized (immutable) |
invoice.paid | Invoice marked as paid, linked to order and entitlement |
invoice.payment_failed | Payment failure recorded, triggers recovery policy |
invoice.voided | Invoice voided locally |
invoice.marked_uncollectible | Invoice marked as uncollectible |
invoice.overdue | Invoice 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.
Invoice-to-entitlement link
Invoices are linked to entitlements indirectly through orders:
Stripe Invoice -> WooCommerce Order -> EntitlementThere 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:
| Operation | Description |
|---|---|
| Issue NFSe | Submit XML with provider, recipient, service, tax values |
| Query NFSe | Check status of submitted NFSe (authorized, rejected) |
| Cancel NFSe | Cancel 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:
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
Related pages
- The Role of WooCommerce -- boundary between WooCommerce and MIDDAG Account
- Payment Status Mapping -- complete status mapping
- Refunds and Cancellations -- refund impact on invoices
- Orders -- order concept reference