From 450f7e1e49665c41f2cc55a75f0de37581c45f09 Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Thu, 8 Feb 2024 10:00:11 +0000 Subject: [PATCH 1/3] Generate simpler extensions for corrections --- bill/invoice_correct.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/bill/invoice_correct.go b/bill/invoice_correct.go index 6c66d708..e87c9d14 100644 --- a/bill/invoice_correct.go +++ b/bill/invoice_correct.go @@ -167,6 +167,8 @@ func (inv *Invoice) CorrectionOptionsSchema() (interface{}, error) { // Try to add all the specific options for the extensions if len(cd.Extensions) > 0 { if ext, ok := cos.Properties.Get("ext"); ok { + ext.Ref = "" // remove the ref + ext.Type = "object" ext.Properties = jsonschema.NewProperties() for _, pk := range cd.Extensions { re := r.ExtensionDef(pk) @@ -180,8 +182,12 @@ func (inv *Invoice) CorrectionOptionsSchema() (interface{}, error) { } var oneOf []*jsonschema.Schema if len(re.Codes) > 0 { - oneOf = make([]*jsonschema.Schema, len(re.Codes)) - for i, c := range re.Codes { + oneOf = make([]*jsonschema.Schema, 1, len(re.Codes)+1) + oneOf[0] = &jsonschema.Schema{ // empty option validated later + Const: "", + Title: "None", + } + for _, c := range re.Codes { ci := &jsonschema.Schema{ Const: c.Code.String(), Title: c.Name.String(), @@ -189,11 +195,15 @@ func (inv *Invoice) CorrectionOptionsSchema() (interface{}, error) { if len(c.Desc) > 0 { ci.Description = c.Desc.String() } - oneOf[i] = ci + oneOf = append(oneOf, ci) } } else if len(re.Keys) > 0 { - oneOf = make([]*jsonschema.Schema, len(re.Keys)) - for i, c := range re.Codes { + oneOf = make([]*jsonschema.Schema, 1, len(re.Keys)+1) + oneOf[0] = &jsonschema.Schema{ + Const: "", + Title: "None", + } + for _, c := range re.Codes { ci := &jsonschema.Schema{ Const: c.Code.String(), Title: c.Name.String(), @@ -201,16 +211,21 @@ func (inv *Invoice) CorrectionOptionsSchema() (interface{}, error) { if len(c.Desc) > 0 { ci.Description = c.Desc.String() } - oneOf[i] = ci + oneOf = append(oneOf, ci) } } if oneOf != nil { prop.OneOf = oneOf } ext.Properties.Set(pk.String(), prop) + ext.Required = append(ext.Required, pk.String()) } } } + cos.Required = append(cos.Required, "ext") + } else { + // Remove extensions, they're not needed if not defined + cos.Properties.Delete("ext") } if cd.ReasonRequired { From dd71bed628d0515913a01a6f8a22bb194a180117 Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Thu, 8 Feb 2024 10:00:53 +0000 Subject: [PATCH 2/3] Version bump --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 4804448f..7ff8976a 100644 --- a/version.go +++ b/version.go @@ -8,7 +8,7 @@ import ( type Version string // VERSION is the current version of the GOBL library. -const VERSION Version = "v0.67.2" +const VERSION Version = "v0.67.3" // Semver parses and returns semver func (v Version) Semver() *semver.Version { From 28ccb974f429a4d20ae8514e7b0f00b127e99c33 Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Thu, 8 Feb 2024 10:04:40 +0000 Subject: [PATCH 3/3] Test fix --- bill/invoice_correct_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bill/invoice_correct_test.go b/bill/invoice_correct_test.go index e098b046..688b33aa 100644 --- a/bill/invoice_correct_test.go +++ b/bill/invoice_correct_test.go @@ -164,10 +164,10 @@ func TestCorrectionOptionsSchema(t *testing.T) { require.True(t, ok) pmp, ok := pm.Properties.Get(string(es.ExtKeyFacturaECorrection)) require.True(t, ok) - assert.Len(t, pmp.OneOf, 22) + assert.Len(t, pmp.OneOf, 23) // Sorry, this is copied and pasted from the test output! - exp := `{"$ref":"https://gobl.org/draft-0/tax/ext-map","properties":{"es-facturae-correction":{"oneOf":[{"const":"01","title":"Invoice code"},{"const":"02","title":"Invoice series"},{"const":"03","title":"Issue date"},{"const":"04","title":"Name and surnames/Corporate name - Issuer (Sender)"},{"const":"05","title":"Name and surnames/Corporate name - Receiver"},{"const":"06","title":"Issuer's Tax Identification Number"},{"const":"07","title":"Receiver's Tax Identification Number"},{"const":"08","title":"Supplier's address"},{"const":"09","title":"Customer's address"},{"const":"10","title":"Item line"},{"const":"11","title":"Applicable Tax Rate"},{"const":"12","title":"Applicable Tax Amount"},{"const":"13","title":"Applicable Date/Period"},{"const":"14","title":"Invoice Class"},{"const":"15","title":"Legal literals"},{"const":"16","title":"Taxable Base"},{"const":"80","title":"Calculation of tax outputs"},{"const":"81","title":"Calculation of tax inputs"},{"const":"82","title":"Taxable Base modified due to return of packages and packaging materials"},{"const":"83","title":"Taxable Base modified due to discounts and rebates"},{"const":"84","title":"Taxable Base modified due to firm court ruling or administrative decision"},{"const":"85","title":"Taxable Base modified due to unpaid outputs where there is a judgement opening insolvency proceedings"}],"type":"string","title":"FacturaE Change","description":"FacturaE requires a specific and single code that explains why the previous invoice is being corrected."},"es-tbai-correction":{"oneOf":[{"const":"R1","title":"Rectified invoice: error based on law and Article 80 One, Two and Six of the Provincial Tax Law of VAT"},{"const":"R2","title":"Rectified invoice: error based on law and Article 80 Three of the Provincial Tax Law of VAT"},{"const":"R3","title":"Rectified invoice: error based on law and Article 80 Four of the Provincial Tax Law of VAT"},{"const":"R4","title":"Rectified invoice: Other"},{"const":"R5","title":"Rectified invoice: simplified invoices"}],"type":"string","title":"TicketBAI Rectification Type Code","description":"Corrected or rectified invoices that need to be sent in the TicketBAI format\nrequire a specific type code to be defined alongside the preceding invoice\ndata."}},"title":"Extensions","description":"Extensions for region specific requirements."}` + exp := `{"properties":{"es-facturae-correction":{"oneOf":[{"const":"","title":"None"},{"const":"01","title":"Invoice code"},{"const":"02","title":"Invoice series"},{"const":"03","title":"Issue date"},{"const":"04","title":"Name and surnames/Corporate name - Issuer (Sender)"},{"const":"05","title":"Name and surnames/Corporate name - Receiver"},{"const":"06","title":"Issuer's Tax Identification Number"},{"const":"07","title":"Receiver's Tax Identification Number"},{"const":"08","title":"Supplier's address"},{"const":"09","title":"Customer's address"},{"const":"10","title":"Item line"},{"const":"11","title":"Applicable Tax Rate"},{"const":"12","title":"Applicable Tax Amount"},{"const":"13","title":"Applicable Date/Period"},{"const":"14","title":"Invoice Class"},{"const":"15","title":"Legal literals"},{"const":"16","title":"Taxable Base"},{"const":"80","title":"Calculation of tax outputs"},{"const":"81","title":"Calculation of tax inputs"},{"const":"82","title":"Taxable Base modified due to return of packages and packaging materials"},{"const":"83","title":"Taxable Base modified due to discounts and rebates"},{"const":"84","title":"Taxable Base modified due to firm court ruling or administrative decision"},{"const":"85","title":"Taxable Base modified due to unpaid outputs where there is a judgement opening insolvency proceedings"}],"type":"string","title":"FacturaE Change","description":"FacturaE requires a specific and single code that explains why the previous invoice is being corrected."},"es-tbai-correction":{"oneOf":[{"const":"","title":"None"},{"const":"R1","title":"Rectified invoice: error based on law and Article 80 One, Two and Six of the Provincial Tax Law of VAT"},{"const":"R2","title":"Rectified invoice: error based on law and Article 80 Three of the Provincial Tax Law of VAT"},{"const":"R3","title":"Rectified invoice: error based on law and Article 80 Four of the Provincial Tax Law of VAT"},{"const":"R4","title":"Rectified invoice: Other"},{"const":"R5","title":"Rectified invoice: simplified invoices"}],"type":"string","title":"TicketBAI Rectification Type Code","description":"Corrected or rectified invoices that need to be sent in the TicketBAI format\nrequire a specific type code to be defined alongside the preceding invoice\ndata."}},"type":"object","required":["es-facturae-correction","es-tbai-correction"],"title":"Extensions","description":"Extensions for region specific requirements."}` data, err := json.Marshal(pm) require.NoError(t, err) if !assert.JSONEq(t, exp, string(data)) {