Skip to content

Commit

Permalink
Merge branch 'main' into addon-verifactu
Browse files Browse the repository at this point in the history
  • Loading branch information
apardods committed Nov 19, 2024
2 parents 214df6f + 073123e commit c3526d8
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 69 deletions.
46 changes: 26 additions & 20 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

## [v0.205.1] - 2024-11-19

### Added

- `org`: `Address` includes `LineOne()`, `LineTwo()`, `CompleteNumber()` methods to help with conversion to other formats with some regional formatting.

## [v0.205.0]
### Changes

- `bill`: `Invoice` can now have empty lines if discounts or charges present.

### Fixes

- `ch`: Deleted Supplier validation (not needed for under 2300 CHF/year)
- `bill`: `Invoice` `GetExtensions` method now works correctly if missing totals [Issue #424](https://github.com/invopop/gobl/issues/424).

## [v0.205.0] - 2024-11-12

### Added

Expand All @@ -28,7 +39,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- `cal`: Fixing json schema issue with date times.

## [v0.204.1]
## [v0.204.1] - 2024-11-04

### Added

Expand All @@ -38,7 +49,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- `tax`: identity code handling will skip default validation for specific countries that use special characters.

## [v0.204.0]
## [v0.204.0] - 2024-10-31

### Added

Expand Down Expand Up @@ -77,7 +88,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- `mx`: Tax ID validation now correctly supports `&` and `Ñ` symbols in codes.

## [v0.203.0]
## [v0.203.0] - 2024-20-21

### Added

Expand All @@ -91,7 +102,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `tax.Identity`: support Calculate method to normalize IDs.
- `tax.Regime`: properly set regime when alternative codes is given.

## [v0.202.0]
## [v0.202.0] - 2024-10-14

### Changed

Expand All @@ -107,7 +118,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- `mx`: fixed panic when normalizing an invoice with `tax` but no `ext` inside.

## [v0.201.0]
## [v0.201.0] - 2024-10-07

### Fixed

Expand All @@ -120,13 +131,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `pt`: reduced rate category for PT-MA was updated to reflect latest value of 4%
- `co-dian-v2`: moved from `co` tax regime into own addon.

## [v0.200.1]
## [v0.200.1] - 2024-09-30

### Fixed

- `pt`: moving invoice tags from saft addon to regime, ensure defaults present.

## [v0.200.0]
## [v0.200.0] - 2024-09-26

Another ~~significant~~ epic release. Introducing "add-ons" which move the normalization and validation rules from Tax Regimes to specific packages that need to be enabled inside a document to be used.

Expand Down Expand Up @@ -168,13 +179,13 @@ Finally, the `draft` flag has been removed from the header, and much more emphas
- `org`: `DocumentRef` consolidates references to previous documents in a single place.
- `bill`: invoice type option `other` for usage when regular scenarios do not apply.

## [v0.115.1]
## [v0.115.1] - 2024-09-10

### Fixes

- `tax`: totals calculator was ignoring tax combos with rate and percent, when they should be classed as exempt.

## [v0.115.0]
## [v0.115.0] - 2024-09-10

This one is big...

Expand Down Expand Up @@ -227,20 +238,20 @@ Invoices in GOBL can now also finally produced for any country in the world, eve
- `tax.Scenario`: potential issue around matching notes.
- `tax.Set`: improved validation embedded error handling.

## [v0.114.0]
## [v0.114.0] - 2024-08-26

### Changed

- `org.Name`: either given **or** surname are required, as opposed to both at the same time.

## [v0.113.0]
## [v0.113.0] - 2024-08-01

### Added

- `head`: validation rule to check for the presence of stamps
- GR: support for credit notes

## [v0.112.0]
## [v0.112.0] - 2024-07-29

Significant set of small changes related to renaming of the `l10n.CountryCode` type. The main reason for this is an attempt to reduce confusion between regular ISO country selection, and the specific country codes used for tax purposes. Normally they coincide, but exception cases like for Greece, whose ISO code is `GR` but use `EL` for tax purposes, or `XI` for companies in Northern Ireland, mean that there needs to be a clear selection.

Expand All @@ -256,6 +267,8 @@ Significant set of small changes related to renaming of the `l10n.CountryCode` t
- GR: support for simplified invoices
- `l10n`: ISO and Tax lists of country definitions available, e.g. `l10n.Countries().ISO()`
- `tax`: support for alternative country codes
- `tax`: Scenarios now handle extension key and value for filtering.
- PT: exemption text handling moved to scenarios.

### Upgraded

Expand All @@ -265,13 +278,6 @@ Significant set of small changes related to renaming of the `l10n.CountryCode` t

- GR: fixed certain tax combos not getting calculated by the regime

## [v0.112.0] - 2024-07-26

### Added

- `tax`: Scenarios now handle extension key and value for filtering.
- PT: exemption text handling moved to scenarios.

## [v0.111.1] - 2024-07-25

### Added
Expand Down
5 changes: 4 additions & 1 deletion bill/invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ func (inv *Invoice) ValidateWithContext(ctx context.Context) error {
validation.By(validateInvoiceCustomer),
),
validation.Field(&inv.Lines,
validation.Required,
validation.When(
len(inv.Discounts) == 0 && len(inv.Charges) == 0,
validation.Required.Error("cannot be empty without discounts or charges"),
),
),
validation.Field(&inv.Discounts),
validation.Field(&inv.Charges),
Expand Down
8 changes: 5 additions & 3 deletions bill/invoice_scenarios.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ func (inv *Invoice) GetExtensions() []tax.Extensions {
exts = append(exts, inv.Tax.Ext)
}
}
for _, cat := range inv.Totals.Taxes.Categories {
for _, rate := range cat.Rates {
exts = append(exts, rate.Ext)
if inv.Totals != nil && inv.Totals.Taxes != nil {
for _, cat := range inv.Totals.Taxes.Categories {
for _, rate := range cat.Rates {
exts = append(exts, rate.Ext)
}
}
}
return exts
Expand Down
30 changes: 20 additions & 10 deletions bill/invoice_scenarios_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/invopop/gobl/addons/it/sdi"
"github.com/invopop/gobl/addons/pt/saft"
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/tax"
Expand Down Expand Up @@ -105,14 +106,23 @@ func TestScenarios(t *testing.T) {
}

func TestInvoiceGetExtensions(t *testing.T) {
inv := baseInvoiceWithLines(t)
inv.Addons = tax.WithAddons(sdi.V1)
inv.Supplier.TaxID = &tax.Identity{
Country: "IT",
Code: "12345678903",
}
require.NoError(t, inv.Calculate())
ext := inv.GetExtensions()
assert.Len(t, ext, 2)
assert.Equal(t, "FPR12", ext[0][sdi.ExtKeyFormat].String())
t.Run("with lines", func(t *testing.T) {
inv := baseInvoiceWithLines(t)
inv.Addons = tax.WithAddons(sdi.V1)
inv.Supplier.TaxID = &tax.Identity{
Country: "IT",
Code: "12345678903",
}
require.NoError(t, inv.Calculate())
ext := inv.GetExtensions()
assert.Len(t, ext, 2)
assert.Equal(t, "FPR12", ext[0][sdi.ExtKeyFormat].String())
})
t.Run("missing lines", func(t *testing.T) {
inv := baseInvoice(t)
inv.Addons = tax.WithAddons(saft.V1)
require.NoError(t, inv.Calculate())
ext := inv.GetExtensions()
assert.Len(t, ext, 1)
})
}
20 changes: 20 additions & 0 deletions bill/invoice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,26 @@ func TestValidation(t *testing.T) {
err := inv.Validate()
assert.ErrorContains(t, err, "customer: (name: cannot be blank.).")
})

t.Run("missing lines", func(t *testing.T) {
inv := baseInvoice(t)
require.NoError(t, inv.Calculate())
err := inv.Validate()
assert.ErrorContains(t, err, "lines: cannot be empty without discounts or charges.")
})

t.Run("missing lines with charge", func(t *testing.T) {
inv := baseInvoice(t)
inv.Charges = []*bill.Charge{
{
Reason: "Testing",
Amount: num.MakeAmount(1000, 2),
},
}
require.NoError(t, inv.Calculate())
err := inv.Validate()
assert.NoError(t, err)
})
}

func TestInvoiceTagsValidation(t *testing.T) {
Expand Down
35 changes: 35 additions & 0 deletions examples/es/invoice-es-es-only-charges.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
$schema: "https://gobl.org/draft-0/bill/invoice"
$addons: ["es-facturae-v3"]
uuid: "3aea7b56-59d8-4beb-90bd-f8f280d852a0"
currency: "EUR"
issue_date: "2024-11-15"
series: "SAMPLE"
code: "001"

supplier:
tax_id:
country: "ES"
code: "B98602642" # random
name: "Provide One S.L."
emails:
- addr: "billing@example.com"
addresses:
- num: "42"
street: "Calle Pradillo"
locality: "Madrid"
region: "Madrid"
code: "28002"
country: "ES"

customer:
tax_id:
country: "ES"
code: "54387763P"
name: "Sample Consumer"

charges:
- reason: "A charge not related to a product"
amount: "50.00"
taxes:
- cat: VAT
rate: standard
97 changes: 97 additions & 0 deletions examples/es/out/invoice-es-es-only-charges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"$schema": "https://gobl.org/draft-0/envelope",
"head": {
"uuid": "8a51fd30-2a27-11ee-be56-0242ac120002",
"dig": {
"alg": "sha256",
"val": "3e611352aff72a27ab67167092eb70ef6dd7a291d9928744567c070368fe0551"
}
},
"doc": {
"$schema": "https://gobl.org/draft-0/bill/invoice",
"$regime": "ES",
"$addons": [
"es-facturae-v3"
],
"uuid": "3aea7b56-59d8-4beb-90bd-f8f280d852a0",
"type": "standard",
"series": "SAMPLE",
"code": "001",
"issue_date": "2024-11-15",
"currency": "EUR",
"tax": {
"ext": {
"es-facturae-doc-type": "FC",
"es-facturae-invoice-class": "OO"
}
},
"supplier": {
"name": "Provide One S.L.",
"tax_id": {
"country": "ES",
"code": "B98602642"
},
"addresses": [
{
"num": "42",
"street": "Calle Pradillo",
"locality": "Madrid",
"region": "Madrid",
"code": "28002",
"country": "ES"
}
],
"emails": [
{
"addr": "billing@example.com"
}
]
},
"customer": {
"name": "Sample Consumer",
"tax_id": {
"country": "ES",
"code": "54387763P"
}
},
"charges": [
{
"i": 1,
"reason": "A charge not related to a product",
"amount": "50.00",
"taxes": [
{
"cat": "VAT",
"rate": "standard",
"percent": "21.0%"
}
]
}
],
"totals": {
"sum": "0.00",
"charge": "50.00",
"total": "50.00",
"taxes": {
"categories": [
{
"code": "VAT",
"rates": [
{
"key": "standard",
"base": "50.00",
"percent": "21.0%",
"amount": "10.50"
}
],
"amount": "10.50"
}
],
"sum": "10.50"
},
"tax": "10.50",
"total_with_tax": "60.50",
"payable": "60.50"
}
}
}
2 changes: 0 additions & 2 deletions regimes/ch/ch.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ func New() *tax.RegimeDef {
// Validate checks the document type and determines if it can be validated.
func Validate(doc any) error {
switch obj := doc.(type) {
case *bill.Invoice:
return validateInvoice(obj)
case *tax.Identity:
return validateTaxIdentity(obj)
}
Expand Down
Loading

0 comments on commit c3526d8

Please sign in to comment.