Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions addons/pl/favat/bill.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/l10n"
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/rules"
"github.com/invopop/gobl/rules/is"
Expand Down Expand Up @@ -72,11 +73,11 @@ func billInvoiceRules() *rules.Set {
rules.When(is.Func("not simplified", invoiceNotSimplified),
rules.Field("customer",
rules.Assert("09", "customer is required", is.Present),
rules.Field("tax_id",
Comment thread
mrdanwa marked this conversation as resolved.
rules.Assert("10", "customer tax ID is required", is.Present),
),
),
),
rules.Assert("10", "customer Polish tax ID code is required",
is.Func("Polish customer tax ID code", invoiceCustomerPLTaxIDCodePresent),
),
// Customer JST identity check (invoice-level, needs both customer.ext and customer.identities)
rules.Assert("11",
fmt.Sprintf("customer requires identity with role '%s' and code for JST", cbc.Code("8")),
Expand Down Expand Up @@ -121,6 +122,19 @@ func invoiceNotSimplified(val any) bool {
return !inv.HasTags(tax.TagSimplified)
}

// invoiceCustomerPLTaxIDCodePresent returns false when the customer has a
// Polish tax ID but no code — the NIP is mandatory for Polish entities.
func invoiceCustomerPLTaxIDCodePresent(val any) bool {
inv, ok := val.(*bill.Invoice)
if !ok || inv == nil || inv.Customer == nil || inv.Customer.TaxID == nil {
return true
}
if inv.Customer.TaxID.Country == l10n.PL.Tax() {
return len(inv.Customer.TaxID.Code) > 0
}
return true
}

func invoiceCustomerJSTIdentityValid(val any) bool {
inv, ok := val.(*bill.Invoice)
if !ok || inv == nil || inv.Customer == nil {
Expand Down
30 changes: 28 additions & 2 deletions addons/pl/favat/bill_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,38 @@ func TestSimplifiedInvoiceCustomerValidation(t *testing.T) {
}

func TestCustomerTaxIDValidation(t *testing.T) {
t.Run("customer without tax ID", func(t *testing.T) {
t.Run("customer without tax ID is valid", func(t *testing.T) {
inv := standardInvoice()
inv.Customer.TaxID = nil
require.NoError(t, inv.Calculate())
err := rules.Validate(inv)
assert.ErrorContains(t, err, "customer tax ID is required")
assert.NoError(t, err)
})

t.Run("Polish customer with tax ID code is valid", func(t *testing.T) {
inv := standardInvoice()
require.NoError(t, inv.Calculate())
err := rules.Validate(inv)
assert.NoError(t, err)
})

t.Run("Polish customer with empty tax ID code is invalid", func(t *testing.T) {
inv := standardInvoice()
inv.Customer.TaxID.Code = ""
require.NoError(t, inv.Calculate())
err := rules.Validate(inv)
assert.ErrorContains(t, err, "customer Polish tax ID code is required")
})

t.Run("non-Polish customer with empty tax ID code is valid", func(t *testing.T) {
inv := standardInvoice()
inv.Customer.TaxID = &tax.Identity{
Country: "DE",
Code: "",
}
require.NoError(t, inv.Calculate())
err := rules.Validate(inv)
assert.NoError(t, err)
})
}

Expand Down
Loading