Skip to content

Commit

Permalink
Add support for other taxes to myDATA Greece
Browse files Browse the repository at this point in the history
  • Loading branch information
cavalle committed Dec 13, 2024
1 parent c7664f4 commit 9f314c4
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `bill`: `Tax.MergeExtensions` convenience method for adding extensions to tax objects and avoid nil panics.
- `cbc`: `Key.Pop` method for splitting keys with sub-keys, e.g. `cbc.Key("a+b").Pop() == cbc.Key("a")`.
- `in`: added Indian regime
- `gr-mydata`: added `gr-mydata-other-tax` extension to set the category of other taxes in charges.

### Changed

Expand Down
145 changes: 143 additions & 2 deletions addons/gr/mydata/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ const (
ExtKeyIncomeCat = "gr-mydata-income-cat"
ExtKeyIncomeType = "gr-mydata-income-type"
ExtKeyPaymentMeans = "gr-mydata-payment-means"

InvoiceTypeRetailPrefix = "11."
ExtKeyOtherTax = "gr-mydata-other-tax"
)

var extensions = []*cbc.Definition{
Expand Down Expand Up @@ -1024,4 +1023,146 @@ var extensions = []*cbc.Definition{
},
},
},
{
Key: ExtKeyOtherTax,
Name: i18n.String{
i18n.EN: "Other taxes category",
i18n.EL: "Κατηγορία Λοιπών Φόρων",
},
Values: []*cbc.Definition{
{
Code: "1",
Name: i18n.String{
i18n.EN: "a1) 20% fire insurance premiums",
i18n.EL: "α1) Ασφάλιστρα κλάδου πυρός 20%",
},
},
{
Code: "2",
Name: i18n.String{
i18n.EN: "a2) 20% fire insurance premiums",
i18n.EL: "α2) Ασφάλιστρα κλάδου πυρός 20%",
},
},
{
Code: "3",
Name: i18n.String{
i18n.EN: "b) 4% life insurance premiums",
i18n.EL: "β) Ασφάλιστρα κλάδου ζωής 4%",
},
},
{
Code: "4",
Name: i18n.String{
i18n.EN: "c) 15% other insurance premiums",
i18n.EL: "γ) Ασφάλιστρα λοιπών κλάδων 15%",
},
},
{
Code: "5",
Name: i18n.String{
i18n.EN: "d) 0% tax-exempt insurance premiums",
i18n.EL: "δ) Απαλλασσόμενα φόρου ασφάλιστρα 0%",
},
},
{
Code: "6",
Name: i18n.String{
i18n.EN: "Hotels 1-2 stars 0,50 €",
i18n.EL: "Ξενοδοχεία 1-2 αστέρων 0,50 €",
},
},
{
Code: "7",
Name: i18n.String{
i18n.EN: "Hotels 3 stars 1,50 €",
i18n.EL: "Ξενοδοχεία 3 αστέρων 1,50 €",
},
},
{
Code: "8",
Name: i18n.String{
i18n.EN: "Hotels 4 stars 3,00 €",
i18n.EL: "Ξενοδοχεία 4 αστέρων 3,00 €",
},
},
{
Code: "9",
Name: i18n.String{
i18n.EN: "Hotels 5 stars 4,00 €",
i18n.EL: "Ξενοδοχεία 5 αστέρων 4,00 €",
},
},
{
Code: "10",
Name: i18n.String{
i18n.EN: "Rental rooms - Furnished rooms - Apartments 0,50 €",
i18n.EL: "Ενοικιαζόμενα δωμάτια - Επιπλωμένα δωμάτια - Διαμερίσματα 0,50 €",
},
},
{
Code: "11",
Name: i18n.String{
i18n.EN: "Special 5% tax on tv-broadcast commercials (EFTD)",
i18n.EL: "Ειδικός φόρος στις διαφημίσεις που προβάλλονται από την τηλεόραση (ΕΦΔΤ) 5%",
},
},
{
Code: "12",
Name: i18n.String{
i18n.EN: "10% luxury tax on the taxable value of intra-community acquired goods and those imported from third countries",
i18n.EL: "Φόρος πολυτελείας 10% επί της φορολογητέας αξίας για τα ενδοκοινοτικά αποκτήματα και εισαγόμενα από τρίτες χώρες",
},
},
{
Code: "13",
Name: i18n.String{
i18n.EN: "10% luxury tax on the selling price before VAT for domestically produced goods",
i18n.EL: "Φόρος πολυτελείας 10% επί της τιμής πώλησης προ Φ.Π.Α. για τα εγχωρίως παραγόμενα",
},
},
{
Code: "14",
Name: i18n.String{
i18n.EN: "80% Public fees on the admission ticket price for casinos",
i18n.EL: "Δικαιώματα του Δημοσίου στα εισιτήρια των καζίνο (80% επί του εισιτηρίου)",
},
},
{
Code: "15",
Name: i18n.String{
i18n.EN: "Fire industry insurance premiums 20%",
i18n.EL: "Ασφάλιστρα κλάδου πυρός 20%",
},
},
{
Code: "16",
Name: i18n.String{
i18n.EN: "Customs duties- Taxes",
i18n.EL: "Λοιποί Τελωνειακοί Δασμοί-Φόροι",
},
},
{
Code: "17",
Name: i18n.String{
i18n.EN: "Other Taxes",
i18n.EL: "Λοιποί Φόροι",
},
},
{
Code: "18",
Name: i18n.String{
i18n.EN: "Charges of other Taxes",
i18n.EL: "Επιβαρύνσεις Λοιπών Φόρων",
},
},
{
Code: "19",
Name: i18n.String{
i18n.EN: "Special consumption tax",
i18n.EL: "ΕΦΚ",
},
},
},
},
}
25 changes: 13 additions & 12 deletions addons/gr/mydata/invoices.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func validateInvoice(inv *bill.Invoice) error {
),
validation.Field(&inv.Customer,
validation.When(
!IsRetail(inv),
requiresValidCustomer(inv),
validation.Required,
validation.By(validateBusinessParty),
validation.By(validateBusinessCustomer),
Expand All @@ -40,10 +40,6 @@ func validateInvoice(inv *bill.Invoice) error {
),
validation.Skip,
),
validation.Field(&inv.Charges,
validation.Empty.Error("not supported by mydata"),
validation.Skip,
),
validation.Field(&inv.Discounts,
validation.Empty.Error("not supported by mydata"),
validation.Skip,
Expand Down Expand Up @@ -182,13 +178,18 @@ func validateInvoicePreceding(value any) error {
)
}

// IsRetail returns true if the invoice type corresponds to a retail invoice.
func IsRetail(inv *bill.Invoice) bool {
if inv.Tax == nil || inv.Tax.Ext == nil {
return false
}
// requiresValidCustomer returns true if the invoice type requires a customer.
func requiresValidCustomer(inv *bill.Invoice) bool {
// Invoice type categories that require a valid customer.
typeCats := []string{"1", "2", "5"}

it := inv.Tax.Ext[ExtKeyInvoiceType].String()

it := inv.Tax.Ext[ExtKeyInvoiceType]
for _, prefix := range typeCats {
if strings.HasPrefix(it, prefix+".") {
return true
}
}

return strings.HasPrefix(string(it), InvoiceTypeRetailPrefix)
return false
}
15 changes: 15 additions & 0 deletions addons/gr/mydata/invoices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@ func TestSimplifiedInvoiceValidation(t *testing.T) {
assert.NoError(t, inv.Validate())
}

func TestOtherInvoiceTypeValidation(t *testing.T) {
inv := validInvoice()
inv.Type = bill.InvoiceTypeOther
inv.Tax = &bill.Tax{
Ext: tax.Extensions{
mydata.ExtKeyInvoiceType: "8.2",
},
}
inv.Customer.TaxID = nil
inv.Customer.Addresses = nil

require.NoError(t, inv.Calculate())
assert.NoError(t, inv.Validate())
}

func TestPrecedingValidation(t *testing.T) {
inv := validInvoice()

Expand Down
49 changes: 49 additions & 0 deletions examples/gr/invoice-accommodation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
$schema: "https://gobl.org/draft-0/bill/invoice"
$addons: ["gr-mydata-v1"]
uuid: "019035bd-4522-7eb3-83bf-9185ead05ee6"
currency: "EUR"
issue_date: "2022-02-01"
series: "SAMPLE"
code: "001"
type: "other"
tax:
ext:
"gr-mydata-invoice-type": "8.2"

supplier:
tax_id:
country: "EL"
code: "177472438"
name: "Ελληνικά Τρόφιμα Α.Ε."
emails:
- addr: "hellenicfoods@example.com"
addresses:
- num: "12"
street: "Λεωφόρος Βουλιαγμένης"
locality: "Αθήνα"
code: "11636"
country: "GR"

customer:
tax_id:
country: "EL"
code: "841442160"
name: "Αιγαίο Λιανική Α.Ε."
emails:
- addr: "aegeanretail@example.com"
addresses:
- num: "45"
street: "Οδός Εγνατίας"
locality: "Θεσσαλονίκη"
code: "54625"
country: "GR"

charges:
- reason: "Accommodation tax"
amount: "3.00"
ext:
"gr-mydata-other-tax": "8"

payment:
instructions:
key: cash
96 changes: 96 additions & 0 deletions examples/gr/out/invoice-accommodation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"$schema": "https://gobl.org/draft-0/envelope",
"head": {
"uuid": "8a51fd30-2a27-11ee-be56-0242ac120002",
"dig": {
"alg": "sha256",
"val": "66ba51da8b4d361f1df79c094057ac3eade2f70680699a424531658c15c89631"
}
},
"doc": {
"$schema": "https://gobl.org/draft-0/bill/invoice",
"$regime": "EL",
"$addons": [
"gr-mydata-v1"
],
"uuid": "019035bd-4522-7eb3-83bf-9185ead05ee6",
"type": "other",
"series": "SAMPLE",
"code": "001",
"issue_date": "2022-02-01",
"currency": "EUR",
"tax": {
"ext": {
"gr-mydata-invoice-type": "8.2"
}
},
"supplier": {
"name": "Ελληνικά Τρόφιμα Α.Ε.",
"tax_id": {
"country": "EL",
"code": "177472438"
},
"addresses": [
{
"num": "12",
"street": "Λεωφόρος Βουλιαγμένης",
"locality": "Αθήνα",
"code": "11636",
"country": "GR"
}
],
"emails": [
{
"addr": "hellenicfoods@example.com"
}
]
},
"customer": {
"name": "Αιγαίο Λιανική Α.Ε.",
"tax_id": {
"country": "EL",
"code": "841442160"
},
"addresses": [
{
"num": "45",
"street": "Οδός Εγνατίας",
"locality": "Θεσσαλονίκη",
"code": "54625",
"country": "GR"
}
],
"emails": [
{
"addr": "aegeanretail@example.com"
}
]
},
"charges": [
{
"i": 1,
"reason": "Accommodation tax",
"amount": "3.00",
"ext": {
"gr-mydata-other-tax": "8"
}
}
],
"payment": {
"instructions": {
"key": "cash",
"ext": {
"gr-mydata-payment-means": "3"
}
}
},
"totals": {
"sum": "0.00",
"charge": "3.00",
"total": "3.00",
"tax": "0.00",
"total_with_tax": "3.00",
"payable": "3.00"
}
}
}
Loading

0 comments on commit 9f314c4

Please sign in to comment.