From bda0e7f610f7e1722ebe6930b0f22fc2a0197185 Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Wed, 20 Nov 2024 12:06:17 +0000 Subject: [PATCH] Always adding product extension to items, fix preceding validation --- CHANGELOG.md | 8 ++++++ addons/es/tbai/invoice.go | 4 ++- addons/es/tbai/invoices_test.go | 19 ++++++++++++++ addons/es/tbai/org.go | 19 ++++++++++++++ addons/es/tbai/org_test.go | 26 +++++++++++++++++++ addons/es/tbai/tbai.go | 3 +++ examples/es/out/credit-note-es-es-tbai.json | 12 ++++++--- examples/es/out/invoice-es-nl-tbai-b2c.json | 7 +++-- .../es/out/invoice-es-nl-tbai-exempt.json | 7 +++-- 9 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 addons/es/tbai/org.go create mode 100644 addons/es/tbai/org_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index fad9a04b..a2eb8f02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - ae: added UAE regime +### Changed + +- `es-tbai-v1`: always add `es-tbai-product` extension to items, indicating default value. + +### Fixed + +- `es-tbai-v1`: issue with preceding validation. + ## [v0.205.1] - 2024-11-19 ### Added diff --git a/addons/es/tbai/invoice.go b/addons/es/tbai/invoice.go index 11fb29ae..db25602a 100644 --- a/addons/es/tbai/invoice.go +++ b/addons/es/tbai/invoice.go @@ -76,7 +76,9 @@ func validateInvoice(inv *bill.Invoice) error { inv.Type.In(es.InvoiceCorrectionTypes...), validation.Required, ), - validation.By(validateInvoicePreceding), + validation.Each( + validation.By(validateInvoicePreceding), + ), validation.Skip, ), validation.Field(&inv.Lines, diff --git a/addons/es/tbai/invoices_test.go b/addons/es/tbai/invoices_test.go index e4a65281..7cbd143d 100644 --- a/addons/es/tbai/invoices_test.go +++ b/addons/es/tbai/invoices_test.go @@ -15,6 +15,14 @@ import ( ) func TestInvoiceNormalization(t *testing.T) { + t.Run("nil", func(t *testing.T) { + ad := tax.AddonForKey(tbai.V1) + var inv *bill.Invoice + assert.NotPanics(t, func() { + ad.Normalizer(inv) + }) + }) + t.Run("standard invoice, no address", func(t *testing.T) { inv := testInvoiceStandard(t) inv.Tax = nil @@ -126,6 +134,17 @@ func TestInvoiceValidation(t *testing.T) { inv.Notes = nil assertValidationError(t, inv, "notes: with key 'general' missing") }) + + t.Run("correction", func(t *testing.T) { + inv := testInvoiceStandard(t) + require.NoError(t, inv.Calculate()) + require.NoError(t, inv.Correct( + bill.Credit, + bill.WithExtension(tbai.ExtKeyCorrection, "R4"), + )) + assert.Len(t, inv.Preceding, 1) + assert.NoError(t, inv.Validate()) + }) } func assertValidationError(t *testing.T, inv *bill.Invoice, expected string) { diff --git a/addons/es/tbai/org.go b/addons/es/tbai/org.go new file mode 100644 index 00000000..31c10010 --- /dev/null +++ b/addons/es/tbai/org.go @@ -0,0 +1,19 @@ +package tbai + +import ( + "github.com/invopop/gobl/org" + "github.com/invopop/gobl/tax" +) + +func normalizeOrgItem(item *org.Item) { + if item == nil { + return + } + if item.Ext == nil { + item.Ext = make(tax.Extensions) + } + if !item.Ext.Has(ExtKeyProduct) { + // Assume all items are services by default. + item.Ext[ExtKeyProduct] = "services" + } +} diff --git a/addons/es/tbai/org_test.go b/addons/es/tbai/org_test.go new file mode 100644 index 00000000..ea82672f --- /dev/null +++ b/addons/es/tbai/org_test.go @@ -0,0 +1,26 @@ +package tbai_test + +import ( + "testing" + + "github.com/invopop/gobl/addons/es/tbai" + "github.com/invopop/gobl/org" + "github.com/invopop/gobl/tax" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNormalizeOrgItem(t *testing.T) { + t.Run("nil", func(t *testing.T) { + ad := tax.AddonForKey(tbai.V1) + var item *org.Item + assert.NotPanics(t, func() { + ad.Normalizer(item) + }) + }) + t.Run("with standard invoice", func(t *testing.T) { + inv := testInvoiceStandard(t) + require.NoError(t, inv.Calculate()) + assert.Equal(t, "services", inv.Lines[0].Item.Ext[tbai.ExtKeyProduct].String()) + }) +} diff --git a/addons/es/tbai/tbai.go b/addons/es/tbai/tbai.go index 6caf3ddf..4f19706e 100644 --- a/addons/es/tbai/tbai.go +++ b/addons/es/tbai/tbai.go @@ -5,6 +5,7 @@ import ( "github.com/invopop/gobl/bill" "github.com/invopop/gobl/cbc" "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/org" "github.com/invopop/gobl/tax" ) @@ -44,6 +45,8 @@ func normalize(doc any) { switch obj := doc.(type) { case *bill.Invoice: normalizeInvoice(obj) + case *org.Item: + normalizeOrgItem(obj) } } diff --git a/examples/es/out/credit-note-es-es-tbai.json b/examples/es/out/credit-note-es-es-tbai.json index dd5d7553..5bc140e9 100644 --- a/examples/es/out/credit-note-es-es-tbai.json +++ b/examples/es/out/credit-note-es-es-tbai.json @@ -4,7 +4,7 @@ "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", "dig": { "alg": "sha256", - "val": "bd55d1603bc9a657f994684631ad5890c1adfe88c00dbb1f9edb40b7c6d215c5" + "val": "e4b79d1885c94a3d643b6c234ef7a6251bde4464bd6ee906e47523249c555e06" } }, "doc": { @@ -86,7 +86,10 @@ "item": { "name": "Development services", "price": "90.00", - "unit": "h" + "unit": "h", + "ext": { + "es-tbai-product": "services" + } }, "sum": "1800.00", "discounts": [ @@ -110,7 +113,10 @@ "quantity": "1", "item": { "name": "Financial service", - "price": "10.00" + "price": "10.00", + "ext": { + "es-tbai-product": "services" + } }, "sum": "10.00", "taxes": [ diff --git a/examples/es/out/invoice-es-nl-tbai-b2c.json b/examples/es/out/invoice-es-nl-tbai-b2c.json index e7c06be4..29faad19 100644 --- a/examples/es/out/invoice-es-nl-tbai-b2c.json +++ b/examples/es/out/invoice-es-nl-tbai-b2c.json @@ -4,7 +4,7 @@ "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", "dig": { "alg": "sha256", - "val": "3c08d66076cd20acf69aff434e5c1c652ca8c2414ebc14a1d944bef3932405e8" + "val": "fd03d73a5f1d5622214be36bdd7e2c4ae4640289ea028f214901d8057ad7dc07" } }, "doc": { @@ -62,7 +62,10 @@ "item": { "name": "Development services", "price": "90.00", - "unit": "h" + "unit": "h", + "ext": { + "es-tbai-product": "services" + } }, "sum": "1800.00", "discounts": [ diff --git a/examples/es/out/invoice-es-nl-tbai-exempt.json b/examples/es/out/invoice-es-nl-tbai-exempt.json index c2eaff3f..fd49f261 100644 --- a/examples/es/out/invoice-es-nl-tbai-exempt.json +++ b/examples/es/out/invoice-es-nl-tbai-exempt.json @@ -4,7 +4,7 @@ "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", "dig": { "alg": "sha256", - "val": "54c6eb1d6447f15a65d0f87aa67f3b272041e4e5ad2be14c14d2b7a85e47d9d3" + "val": "21f2bb5d933bd6a8cf777b2dfd2ccd9aedbe1e5a5d3d9467e976dbecc2f8a351" } }, "doc": { @@ -60,7 +60,10 @@ "item": { "name": "Development services", "price": "90.00", - "unit": "h" + "unit": "h", + "ext": { + "es-tbai-product": "services" + } }, "sum": "1800.00", "discounts": [