Route us_ein tax IDs to org.Identity - #45
Merged
Merged
Conversation
US Employer Identification Numbers (us_ein) were being mapped to a GOBL tax.Identity, whose code must match ^[A-Z0-9]+$. Because the US regime defines no normalizer, the hyphen in EIN values (e.g. "41-4637166") was left in place and validation failed with "code: must be in a valid format", surfacing as a 422 when creating the silo entry. US EINs don't belong to a VAT-like tax scheme, so they should be represented as a party org.Identity (type EIN) rather than a tax.Identity code, matching how the German Steuernummer (de_stn) is already handled. org.Identity codes permit hyphens as separators, so the value validates. Both org-identity mappings now also set the identity's country to make them self-describing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes Stripe invoice conversion failures for US customers with us_ein tax IDs by mapping EINs to GOBL party identities (org.Identity) instead of tax identities (tax.Identity), aligning with GOBL’s US regime model and avoiding validation errors caused by hyphenated EIN formats.
Changes:
- Treat Stripe
us_einas anorg.Identity(typeEIN) rather than atax.Identity, and include it in the identity-routing logic (orgIDKeys). - Add symmetric org-identity mapping support for
us_einin both conversion directions, and setCountryon org identities (de_stn,us_ein). - Update unit tests to cover the new
FromTaxIDToOrgbehavior and updated identity expectations withCountry.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| party.go | Routes us_ein through org.Identity conversions (incl. country) and adds reverse mapping support in ToTaxIDFromOrg. |
| party_test.go | Updates identity assertions to include Country and adds a new us_ein case for FromTaxIDToOrg. |
Comments suppressed due to low confidence (1)
party.go:223
FromTaxIDToOrgcan leaveoidas nil for unsupported Stripe tax ID types, but it still callsoid.Normalize()unconditionally. Even ifNormalizecurrently tolerates a nil receiver, an explicit nil check here would make the control flow clearer and avoid relying on upstream nil-safety.
Code: cbc.Code(taxID.Value),
}
}
oid.Normalize()
return oid
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Converting a Stripe invoice for a US customer with a
us_eintax ID failed when creating the silo entry:us_einvalues were being mapped into a GOBLtax.Identity, whosecodemust match^[A-Z0-9]+$. GOBL would normally strip separators during normalization, but only when no tax regime exists for the country. A US regime does exist and defines no normalizer, so the hyphen in EIN values (e.g.41-4637166) was left in place and validation failed withcode: must be in a valid format.There's also a conceptual issue: GOBL's US regime states US entities "do not have an official tax scheme and should omit the
codefield," and definesus.IdentityTypeEINas anorg.Identitytype — so an EIN should live in the party'sidentitiesarray, not intax_id.code.Fix
Route
us_einto a GOBLorg.Identity(typeEIN) instead of atax.Identity, mirroring how the German Steuernummer (de_stn) is already handled.org.Identitycodes permit hyphens as separators, so41-4637166validates as-is.us_eintoorgIDKeysso it's recognized as a party identity in all conversion paths (customer, supplier-from-invoice, supplier-from-account).FromTaxIDToOrg(Stripe → GOBL): mapus_ein→org.Identity{Type: EIN, ...}.ToTaxIDFromOrg(GOBL → Stripe): symmetric reverse mapping.de_stnandus_ein) now also set the identity'scountry, making them self-describing.Resulting customer representation:
Verification
customer: (tax_id: (code: must be in a valid format.))).us_eincase toTestFromTaxIDToOrgand updated thede_stnassertions for the newcountryfield.go test ./...),go vetandgofmtclean.🤖 Generated with Claude Code