Skip to content

Add Norway (NO) tax regime#728

Open
0xjgv wants to merge 7 commits intoinvopop:mainfrom
0xjgv:main
Open

Add Norway (NO) tax regime#728
0xjgv wants to merge 7 commits intoinvopop:mainfrom
0xjgv:main

Conversation

@0xjgv
Copy link
Copy Markdown
Contributor

@0xjgv 0xjgv commented Feb 23, 2026

We chose Norway as the next tax regime through a repeatable analysis: we audited all supported and upcoming countries, scored gaps against economic potential weighted by Invopop's customer base, and narrowed to three. Norway ranked highest for regulatory clarity, manageable scope, and iteration speed. That said, this approach is second to the one driven by customers' needs.

Add full Norwegian tax regime implementation, including VAT support, organisasjonsnummer validation, simplified invoice handling, and invoice type handling.

  • Norwegian VAT regime with four tax rates: general (25%), reduced (15%), super-reduced (12%), special (11.11%)
  • Historical rate values for super-reduced rate (6% from 2004, 7% from 2005, 8% from 2006, 10% from 2016, 12% from 2018, 6% COVID reduction Apr 2020, 12% restored Oct 2021)
  • Bilingual (EN/NB) descriptions for all rates
  • Organisasjonsnummer (org.Identity type ON) with mod-11 check digit validation per Brønnøysundregistrene spec
  • Tax identity normalization stripping NO prefix and MVA suffix
  • Simplified invoice support: relaxes supplier address and TaxID requirements, customer is optional (following the SE pattern)
  • Supplier TaxID intentionally optional — Norwegian businesses below NOK 50,000 turnover are not VAT-registered but may still issue invoices
  • Invoice validation: supplier name required (address required for standard, optional for simplified), customer name required on standard invoices
  • Credit note and debit note correction types requiring preceding document reference
  • Norwegian (nb) translations alongside English
  • Regime description field using here.Doc (following FR pattern)
  • Six example invoices: standard domestic, multi-rate, simplified, reverse-charge, credit note, debit note

Sources

Out of Scope

Deliberately excluded from this PR (documented in README):

  • SAF-T Norway — reporting/audit format, not transaction-level invoicing
  • EHF / Peppol addon — B2B mandatory e-invoicing proposed from 2028, not yet law

Pre-Review Checklist

  • Opened this PR as a draft
  • Read the CONTRIBUTING.md guide.
  • Performed a self-review of my code.
  • Added thorough tests with at least 90% code coverage.
  • Modified or created example GOBL documents to show my changes in use, if appropriate.
  • Added links to the source of the changes in tax regimes or addons, either structured or in the comments.
  • Run go generate . to ensure that the Schemas and Regime data are up to date.
  • Reviewed and fixed all linter warnings.
  • Been obsessive with pointer nil checks to avoid panics.
  • Updated the CHANGELOG.md with an overview of my changes.
  • Requested a review from Copilot and fixed or dismissed (with a reason) all the feedback raised.

Only after checking off all the previous items:

  • Marked this PR as ready for review and requested one from @samlown.

@0xjgv
Copy link
Copy Markdown
Contributor Author

0xjgv commented Feb 23, 2026

@samlown could you please request a review from Copilot? 🙏

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Norway (NO) as a first-class tax regime in GOBL, including VAT rate definitions, identity normalization/validation, and invoice-specific validation/scenario behavior, plus generated schema/data and example fixtures.

Changes:

  • Register new NO regime and implement Norwegian VAT category/rates (incl. historical values), invoice tags/scenarios, and correction support.
  • Add Norwegian identity support: organisasjonsnummer (org.Identity type ON) and tax identity normalization/validation (mod-11).
  • Add tests + example documents/JSON snapshots, and update generated regime/schema data + changelog.
  • (Also introduces repo-level agent/tooling files: Makefile, .claude/, agent_docs/, CLAUDE.md.)

Reviewed changes

Copilot reviewed 29 out of 35 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
regimes/regimes.go Registers the new Norway regime via blank import.
regimes/no/no.go Defines and registers the NO tax.RegimeDef (currency, VAT scheme, validator/normalizer, tags, scenarios, corrections).
regimes/no/tax_categories.go VAT category + four rates with historical values and bilingual labels/sources.
regimes/no/tax_identity.go Tax identity normalization (strip NO + MVA) and mod-11 validation.
regimes/no/identities.go Adds org identity type ON + normalization/validation using same mod-11 logic.
regimes/no/invoices.go Norway-specific invoice validation rules (supplier requirements, customer name, preceding refs for credit/debit).
regimes/no/scenarios.go Adds foretaksregisteret tag + scenario note injection (and reverse-charge note).
regimes/no/*_test.go Coverage for normalization/validation, scenarios, and invoice calc/validation behaviors.
regimes/no/README.md Regime documentation (rates, identities, tags, scope).
examples/no/*.yaml + examples/no/out/*.json Example invoices and expected calculated envelopes/snapshots.
data/schemas/tax/regime-code.json Adds NO to regime-code schema enum.
data/regimes/no.json Generated serialized regime definition for NO.
CHANGELOG.md Notes addition of Norwegian regime in Unreleased.
Makefile Adds dev workflow targets (build/test/generate/lint/etc.) using .claude/scripts/run_silent.sh.
.claude/settings.local.json Adds Claude session hooks/plugins (appears local/developer-specific).
.claude/scripts/* Adds helper scripts used by Makefile and Claude context gathering.
agent_docs/* + CLAUDE.md Adds agent-facing documentation and repo patterns/checklists.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread regimes/no/tax_categories.go
Comment thread .claude/settings.local.json Outdated
Comment thread Makefile Outdated
@0xjgv
Copy link
Copy Markdown
Contributor Author

0xjgv commented Feb 24, 2026

@pmenendz, here is the harness to steer claude code #734

Copy link
Copy Markdown
Collaborator

@samlown samlown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid first attempt. There are a few things I'd remove before accepting the PR in order to be more usable. Support for simplified invoices is usually a requirement.

Comment thread regimes/no/invoices.go Outdated
Comment thread regimes/no/invoices.go Outdated
Comment thread regimes/no/invoices_test.go Outdated
Comment thread regimes/no/no.go
Comment thread regimes/no/scenarios.go Outdated
Comment thread regimes/no/README.md Outdated
0xjgv added a commit to 0xjgv/gobl that referenced this pull request Feb 25, 2026
- Add simplified invoice support: TagSimplified check, customer Empty,
  relaxed supplier validation
- Relax supplier TaxID requirement: optional for non-VAT-registered
  companies below NOK 50,000 turnover
- Conditional supplier address: required for standard, optional for
  simplified invoices
- Remove TestInvoiceCalculation and redundant calculation assertions
- Add Description field to regime definition using here.Doc
- Remove foretaksregisteret tag, constant, scenario, TagSet, and all
  related tests and examples
- Add simplified invoice example and dedicated test cases
- Update README.md and CHANGELOG.md to reflect changes
- Change invoiceScenarios from func to var for FR/DE/IT consistency
- Regenerate data/regimes/no.json
@0xjgv 0xjgv requested a review from samlown February 25, 2026 10:33
@0xjgv
Copy link
Copy Markdown
Contributor Author

0xjgv commented Feb 25, 2026

Solid first attempt. There are a few things I'd remove before accepting the PR in order to be more usable. Support for simplified invoices is usually a requirement.

Thank you 🙏 @samlown. I’ve addressed the comments, and I really enjoyed thinking through what it takes to support a new e-invoicing regime (sources of truth, regulatory changes, company types, etc.).

Copy link
Copy Markdown
Collaborator

@samlown samlown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thanks! Only change would be to relax the customer not-present check, then happy to merge 👍

Comment thread regimes/no/invoices.go Outdated
@0xjgv 0xjgv requested a review from samlown February 25, 2026 16:06
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 96.87500% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.08%. Comparing base (926130f) to head (c04c2cd).

Files with missing lines Patch % Lines
regimes/no/tax_identity.go 91.66% 1 Missing and 2 partials ⚠️
regimes/no/invoices.go 96.22% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #728      +/-   ##
==========================================
+ Coverage   93.05%   93.08%   +0.03%     
==========================================
  Files         333      337       +4     
  Lines       17785    17945     +160     
==========================================
+ Hits        16549    16704     +155     
- Misses        870      872       +2     
- Partials      366      369       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@0xjgv 0xjgv closed this Feb 25, 2026
@0xjgv 0xjgv mentioned this pull request Feb 25, 2026
5 tasks
0xjgv added a commit to 0xjgv/gobl that referenced this pull request Feb 25, 2026
- Add simplified invoice support: TagSimplified check, customer Empty,
  relaxed supplier validation
- Relax supplier TaxID requirement: optional for non-VAT-registered
  companies below NOK 50,000 turnover
- Conditional supplier address: required for standard, optional for
  simplified invoices
- Remove TestInvoiceCalculation and redundant calculation assertions
- Add Description field to regime definition using here.Doc
- Remove foretaksregisteret tag, constant, scenario, TagSet, and all
  related tests and examples
- Add simplified invoice example and dedicated test cases
- Update README.md and CHANGELOG.md to reflect changes
- Change invoiceScenarios from func to var for FR/DE/IT consistency
- Regenerate data/regimes/no.json
@0xjgv 0xjgv reopened this Feb 25, 2026
Implements complete support for Norway's VAT tax regime with:
- VAT categories and rates (standard 25%, reduced 15%, super-reduced 12%, special 11.11%)
- Organisasjonsnummer (org.Identity type ON) with mod-11 validation
- Tax identity normalization stripping NO prefix and MVA suffix
- Support for reverse-charge and foretaksregisteret tagging with legal notes
- Invoice validation requiring supplier name/address/tax ID and customer name
- Credit note and debit note correction types with preceding doc reference
- Norwegian (nb) translation support alongside English
- Comprehensive tests with edge case coverage
- Example fixtures: standard invoice, credit note, debit note, reverse-charge

Sources:
- Skatteetaten VAT rates: https://www.skatteetaten.no/en/rates/vat/
- Brønnøysundregistrene org.nr: https://www.brreg.no/en/about-us-2/our-registers/
- Merverdiavgiftsloven: https://lovdata.no/dokument/NL/lov/2009-06-19-58
Add bilingual descriptions to general rate and foretaksregisteret tag,
historical super-reduced rate values (COVID reduction, 2012 increase),
fix special rate Since date to 2009, and add standard and multi-rate
example invoices.
Fix super-reduced rate history (wrong dates, missing intermediate rates)
and add pre-2005 history for general and reduced rates based on
Stortinget resolutions and NOU 2019:11. Add calculation verification
tests for standard, tax-inclusive, and multi-rate invoices, plus
reverse-charge exempt scenario test.
- Add simplified invoice support: TagSimplified check, customer Empty,
  relaxed supplier validation
- Relax supplier TaxID requirement: optional for non-VAT-registered
  companies below NOK 50,000 turnover
- Conditional supplier address: required for standard, optional for
  simplified invoices
- Remove TestInvoiceCalculation and redundant calculation assertions
- Add Description field to regime definition using here.Doc
- Remove foretaksregisteret tag, constant, scenario, TagSet, and all
  related tests and examples
- Add simplified invoice example and dedicated test cases
- Update README.md and CHANGELOG.md to reflect changes
- Change invoiceScenarios from func to var for FR/DE/IT consistency
- Regenerate data/regimes/no.json
Add tax authority source references following the upstream clean-regimes
pattern (Skatteetaten, Brønnøysundregistrene, Lovdata) and regenerate
schema and regime JSON to include NO in the $defs format.
@0xjgv
Copy link
Copy Markdown
Contributor Author

0xjgv commented Mar 9, 2026

@samlown comments addressed 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants