diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 14aa2ae..63a17b6 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,15 +13,15 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version-file: "go.mod" id: go - name: Lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v6 with: version: v1.58 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 144552a..10a4e38 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,10 +7,10 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version-file: "go.mod" id: go diff --git a/README.md b/README.md index 2b4043f..349f057 100644 --- a/README.md +++ b/README.md @@ -150,21 +150,22 @@ Invoice tax tags can be added to invoice documents in order to reflect a special The following extension can be applied to each line tax: - `es-tbai-product` – allows to correctly group the invoice's lines taxes in the TicketBAI breakdowns (a.k.a. desgloses). These are the valid values: - - `services` - indicates that the product being sold is a service (as opposed to a physical good). Services are accounted in the `DesgloseTipoOperacion > PrestacionServicios` breakdown of invoices to foreign customers. By default, all items are considered services. - - `goods` - indicates that the product being sold is a physical good. Products are accounted in the `DesgloseTipoOperacion > Entrega` breakdown of invoices to foreign customers. - - `resale` - indicates that a line item is sold without modification from a provider under the Equalisation Charge scheme. (This implies that the `OperacionEnRecargoDeEquivalenciaORegimenSimplificado` tag will be set to `S`). + + - `services` - indicates that the product being sold is a service (as opposed to a physical good). Services are accounted in the `DesgloseTipoOperacion > PrestacionServicios` breakdown of invoices to foreign customers. By default, all items are considered services. + - `goods` - indicates that the product being sold is a physical good. Products are accounted in the `DesgloseTipoOperacion > Entrega` breakdown of invoices to foreign customers. + - `resale` - indicates that a line item is sold without modification from a provider under the Equalisation Charge scheme. (This implies that the `OperacionEnRecargoDeEquivalenciaORegimenSimplificado` tag will be set to `S`). - `es-tbai-exemption` - identifies the specific TicketBAI reason code as to why taxes should not be applied to the line according to the whole set of exemptions or not-subject scenarios defined in the law. It has to be set along with the tax rate value of `exempt`. These are the valid values: - - `E1` – Exenta por el artículo 20 de la Norma Foral del IVA + - `E1` – Exenta por el artículo 20 de la Norma Foral del IVA - `E2` – Exenta por el artículo 21 de la Norma Foral del IVA - `E3` – Exenta por el artículo 22 de la Norma Foral del IVA - `E4` – Exenta por el artículo 23 y 24 de la Norma Foral del IVA - `E5` – Exenta por el artículo 25 de la Norma Foral del IVA - `E6` – Exenta por otra causa - `OT` – No sujeto por el artículo 7 de la Norma Foral de IVA / Otros supuestos - - `RL` – No sujeto por reglas de localización (*) + - `RL` – No sujeto por reglas de localización (\*) -_(*) As noted elsewhere, `RL` will be set automatically set in invoices using the `customer-rates` tax tag. It can also be set explicitly using the `es-tbai-exemption` extension in invoices not using that tag._ +_(\*) As noted elsewhere, `RL` will be set automatically set in invoices using the `customer-rates` tax tag. It can also be set explicitly using the `es-tbai-exemption` extension in invoices not using that tag._ ### Use-Cases @@ -181,6 +182,10 @@ Under what situations should the TicketBAI system be expected to function: Some sample test data is available in the `./test` directory. -If you make any modifications to the source YAML files, the JSON envelopes will need to be updated. +If you make any modifications to the source YAML files, the JSON envelopes will need to be updated, for example: + +```bash +gobl build -i --envelop test/data/invoice-es-es-b2c.yaml > test/data/invoice-es-es-b2c.json +``` Make sure you have the GOBL CLI installed ([more details](https://docs.gobl.org/quick-start/cli)). diff --git a/internal/doc/invoice.go b/internal/doc/invoice.go index c293968..3a6c2b2 100644 --- a/internal/doc/invoice.go +++ b/internal/doc/invoice.go @@ -145,7 +145,7 @@ func newRetencionSoportada(inv *bill.Invoice) string { func newClaves(inv *bill.Invoice) []IDClave { claves := []IDClave{} - if partyTaxCountry(inv.Customer) != "ES" { + if inv.Customer != nil && partyTaxCountry(inv.Customer) != "ES" { claves = append(claves, IDClave{ ClaveRegimenIvaOpTrascendencia: "02", }) diff --git a/test/data/invoice-es-es-b2c.json b/test/data/invoice-es-es-b2c.json new file mode 100644 index 0000000..a6c47fb --- /dev/null +++ b/test/data/invoice-es-es-b2c.json @@ -0,0 +1,166 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "0192d3c7-2dc5-74cf-b263-5892feb44432", + "dig": { + "alg": "sha256", + "val": "23d0b836e1ae2222abad42dd134fb2b972f27d991e97b1fc06db5b0dc0788e46" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "$regime": "ES", + "$tags": [ + "simplified" + ], + "uuid": "7fe11346-a0ce-11ee-b8f0-e6a7901137ed", + "type": "standard", + "series": "SIMPL", + "code": "0002", + "issue_date": "2023-12-18", + "currency": "EUR", + "supplier": { + "name": "Provide One S.L.", + "tax_id": { + "country": "ES", + "code": "B98602642" + }, + "addresses": [ + { + "num": "42", + "street": "San Frantzisko", + "locality": "Bilbo", + "region": "Bizkaia", + "code": "48003", + "country": "ES" + } + ], + "emails": [ + { + "addr": "billing@example.com" + } + ] + }, + "lines": [ + { + "i": 1, + "quantity": "20", + "item": { + "name": "Development services", + "price": "90.00", + "unit": "h" + }, + "sum": "1800.00", + "discounts": [ + { + "percent": "10%", + "amount": "180.00", + "reason": "Special discount" + } + ], + "taxes": [ + { + "cat": "VAT", + "rate": "standard", + "percent": "21.0%", + "ext": { + "es-tbai-product": "services" + } + } + ], + "total": "1620.00" + }, + { + "i": 2, + "quantity": "1", + "item": { + "name": "Some merch", + "price": "90.00" + }, + "sum": "90.00", + "taxes": [ + { + "cat": "VAT", + "rate": "standard", + "percent": "21.0%", + "ext": { + "es-tbai-product": "goods" + } + } + ], + "total": "90.00" + }, + { + "i": 3, + "quantity": "1", + "item": { + "name": "Some essential needs merch", + "price": "30.00" + }, + "sum": "30.00", + "taxes": [ + { + "cat": "VAT", + "rate": "reduced", + "percent": "10.0%", + "ext": { + "es-tbai-product": "goods" + } + } + ], + "total": "30.00" + } + ], + "totals": { + "sum": "1740.00", + "total": "1740.00", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "ext": { + "es-tbai-product": "services" + }, + "base": "1620.00", + "percent": "21.0%", + "amount": "340.20" + }, + { + "key": "standard", + "ext": { + "es-tbai-product": "goods" + }, + "base": "90.00", + "percent": "21.0%", + "amount": "18.90" + }, + { + "key": "reduced", + "ext": { + "es-tbai-product": "goods" + }, + "base": "30.00", + "percent": "10.0%", + "amount": "3.00" + } + ], + "amount": "362.10" + } + ], + "sum": "362.10" + }, + "tax": "362.10", + "total_with_tax": "2102.10", + "payable": "2102.10" + }, + "notes": [ + { + "key": "general", + "text": "Some random description" + } + ] + } +} diff --git a/test/data/invoice-es-es-b2c.yaml b/test/data/invoice-es-es-b2c.yaml new file mode 100644 index 0000000..4bdbfc1 --- /dev/null +++ b/test/data/invoice-es-es-b2c.yaml @@ -0,0 +1,62 @@ +$schema: "https://gobl.org/draft-0/bill/invoice" +$tags: + - "simplified" +uuid: "7fe11346-a0ce-11ee-b8f0-e6a7901137ed" +currency: "EUR" +issue_date: "2023-12-18" +series: "SIMPL" +code: "0002" + +supplier: + tax_id: + country: "ES" + code: "B98602642" # random + name: "Provide One S.L." + emails: + - addr: "billing@example.com" + addresses: + - num: "42" + street: "San Frantzisko" + locality: "Bilbo" + region: "Bizkaia" + code: "48003" + country: "ES" + +lines: + - quantity: 20 + item: + name: "Development services" + price: "90.00" + unit: "h" + discounts: + - percent: "10%" + reason: "Special discount" + taxes: + - cat: VAT + rate: standard + ext: + es-tbai-product: "services" + # es-tbai-not-subject: "RL" # set automatically + - quantity: 1 + item: + name: "Some merch" + price: "90.00" + taxes: + - cat: VAT + rate: standard + ext: + es-tbai-product: "goods" + # es-tbai-not-subject: "RL" # set automatically + - quantity: 1 + item: + name: "Some essential needs merch" + price: "30.00" + taxes: + - cat: VAT + rate: reduced + ext: + es-tbai-product: "goods" + # es-tbai-not-subject: "RL" # set automatically +notes: + - key: "general" + text: "Some random description" diff --git a/test/data/out/invoice-es-es-b2c.xml b/test/data/out/invoice-es-es-b2c.xml new file mode 100644 index 0000000..d87d6c1 --- /dev/null +++ b/test/data/out/invoice-es-es-b2c.xml @@ -0,0 +1,182 @@ + + + + 1.2 + + + + B98602642 + Provide One S.L. + + T + + + + SIMPL + 0002 + 01-02-2022 + 05:00:00 + S + + + 18-12-2023 + Some random description + + + Development services + 20 + 90.00 + 180.00 + 1960.00 + + + Some merch + 1 + 90.00 + 0.00 + 109.00 + + + Some essential needs merch + 1 + 30.00 + 0.00 + 33.00 + + + 2102.10 + 0.00 + + + 01 + + + + + + + + + S1 + + + 1620.00 + 21.00 + 340.20 + + + 90.00 + 21.00 + 18.90 + + + 30.00 + 10.00 + 3.00 + + + + + + + + + + + AF + 1234567890 + 01-01-2021 + 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 + + + My License + + 12345678A + + My Software + 1.0 + + + + + + + + + + + + /S8aGfLqEszOCzB0Wrq4e39gDbs5/bhoYB73w3kDIRKra7Im70Vst1f93dVUyEw25aphgjhhI+93VG1M79zmBw== + + + + vUJEC+igkjkP4KPksk87iMDA0hA7p2yDXxu9j5MbE4ho35JN9oyWVV0MN2CdyxCs7Gm47v8Xg6iho+GhW7eIKQ== + + + + t6jX6cUyp9e4oYMwvCU6dsAu/GU2dWkLS4YmhWPcHpPoelvJ5PScn27DJnNO3w5I/Hhx9fAsPBm9paA2GVtdBw== + + + VxIODMkSjL9s+3U1oqrztmpe39qR5iDhf1J6P5PXptHmf8OVaTlxLxbyLlCIhUm/vysauf5aDiLOJoop6KYdVptzy2THV49+o4tyg/fMC8pBi+p6aRmhlOW/H0oj7wT3LZQntqcRZC0dn+waFcoLeZVNEybKToRb5kRMd6qfkoJFbuUt8dZso4bZxjkZurSmIeHxCPe6wWsUAvIlurNTpi69a71lkLiaOWE3+gQ5NiM75hXY+uLCuAyy0Ud0sx8wy98zkXf8YpxK3I01Nf6yUYz6j2Ueh9zGagXHqGKxlJoGPiLtGANP9xDQ8o504n4cdI9gxCy2K5z2e9IxF9anIg== + + + MIIJtzCCB5+gAwIBAgICG3YwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxTlpaIFppdXJ0YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDSTE2MDQGA1UEAwwtQ0EgZGUgQ2l1ZGFkYW5vcyB5IEVudGlkYWRlcyAoNCkgLSBERVNBUlJPTExPMB4XDTIxMDMxNTEwMDQzN1oXDTI1MDMxNTEwMDQzN1owggFtMQswCQYDVQQGEwJFUzFvMG0GA1UEDQxmUmVnOkdhc3RlaXogL0hvamE6Qi0xNjY0NzIgL1RvbW86MzczOTMgL1NlY2Npb246OCAvTGlicm86MSAvRm9saW86MjAgL0ZlY2hhOjEwLTAyLTE5NzQgL0luc2NyaXBjacOzbjoxMRgwFgYDVQRhDA9WQVRFUy1TNzgzNjEwN0gxPTA7BgNVBAsMNE9yZGV6a2FyaSB6aXVydGFnaXJpYSAtIENlcnRpZmljYWRvIGRlIHJlcHJlc2VudGFudGUxFDASBgNVBAoMC0laRU5QRSBTLkEuMRIwEAYDVQQFEwk5OTk5OTk3M0sxGDAWBgNVBAQMD0ZJQ1RJQ0lPIEFDVElWTzEWMBQGA1UEKgwNUkVQUkVTRU5UQU5URTE4MDYGA1UEAwwvOTk5OTk5NzNLIFJFUFJFU0VOVEFOVEUgRklDVElDSU8gKFI6IFM3ODM2MTA3SCkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsI8cbiOSsEMrK+lr6Vn7xeDlI1UJIVWM4kMTyXoFcU9F7LkdbSv5jS1D1g3/c8YId1nFjPrHXjpBbjv4Am9QEvHKPa9djI9lTKS3gut5DDU1ePRAagnSCAr2Y6m4isbMF54S5tp0/Ng+myx5c2E+hMmgNw6uZ9KvdwaYY1gQW/N/7qS0KlA1eB0CSHyzZeVRgbYAXI6AMCtuYCRVNLbnzJBvSN0J4SuZeiM/KK0I0oj/8THajszp8hg3v2cfOMAGu5cM3yuBAPTBPBZCkGofwZqMn2ioMZXwRYuXJv4UEncs+d9qZbVGFpc9y0vwbQuPhZU2omSGTWedL4DlnbXDHAgMBAAGjggQyMIIELjCBxwYDVR0SBIG/MIG8hhVodHRwOi8vd3d3Lml6ZW5wZS5jb22BD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAxMCBWaXRvcmlhLUdhc3RlaXowDgYDVR0PAQH/BAQDAgXgMB8GA1UdJQQYMBYGCCsGAQUFBwMCBgorBgEEAYI3CgMMMB0GA1UdDgQWBBQRR3q3tcdVPr8U7NS+zkf7EBt32jAfBgNVHSMEGDAWgBRv//0N8gxjDyZxXRrgb2VkZjhrkzCCATQGA1UdIASCASswggEnMIIBDQYJKwYBBAHzOWYMMIH/MCUGCCsGAQUFBwIBFhlodHRwOi8vd3d3Lml6ZW5wZS5jb20vY3BzMIHVBggrBgEFBQcCAjCByAyBxUtvbnRzdWx0YSB3d3cuaXplbnBlLmNvbS1lbiBiYWxkaW50emFrIGV0YSBrb25kaXppb2FrIHppdXJ0YWdpcmlhbiBmaWRhdHUgZWRvIGVyYWJpbGkgYXVycmV0aWsgLSBDb25zdWx0ZSBlbiB3d3cuaXplbnBlLmNvbSBsb3MgdMOpcm1pbm9zIHkgY29uZGljaW9uZXMgYW50ZXMgZGUgdXRpbGl6YXIgbyBjb25maWFyIGVuIGVsIGNlcnRpZmljYWRvMAkGBwQAi+xAAQIwCQYHYIVUAQMFCDCBogYIKwYBBQUHAQEEgZUwgZIwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwZGVzLml6ZW5wZS5jb20waQYIKwYBBQUHMAKGXWh0dHA6Ly93d3cuaXplbnBlLmNvbS9jb250ZW5pZG9zL2luZm9ybWFjaW9uL2Nhc19pemVucGUvZXNfY2FzL2FkanVudG9zL0NDRUVSX2NlcnRfc2hhMjU2LmNydDCB2wYIKwYBBQUHAQMEgc4wgcswCAYGBACORgEBMAgGBgQAjkYBBDALBgYEAI5GAQMCAQ8wfAYGBACORgEFMHIwJBYeaHR0cHM6Ly93d3cuaXplbnBlLmNvbS9wZHMvZW4vEwJlbjAkFh5odHRwczovL3d3dy5pemVucGUuY29tL3Bkcy9ldS8TAmV1MCQWHmh0dHBzOi8vd3d3Lml6ZW5wZS5jb20vcGRzL2VzLxMCZXMwEwYGBACORgEGMAkGBwQAjkYBBgEwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsZGVzLml6ZW5wZS5jb20vY2dpLWJpbi9jcmwyMA0GCSqGSIb3DQEBCwUAA4ICAQCJaRL+xyX6HFu/6AX7N0j/r1ZB3OAY8t4S3KBvxQBs/PGeQmHFr8cnFXxb2cfkZ/5IzDDMElicChXq86BgaXn6xxtw4q30/qsuwz8iwF+mLKENFGIYTdxmaGCuSBwhENWrv03uUeskL4gIMQIu5fhpdZRj2aW4ccsb9QdfLCHRtjxrgZMoL7tpXRYQcpKgMKroAg3PuIhwdg3eLhVZvihtUJ0oNGtEBz+04eRCZjXx8dWVrmYxfTEqHFaYc8Nxu6AuQvPQdBAC2DoxYLUpihUBvKo8aUrU/QhUCue76Sq9hnzi6TXCofNeixMZBB+ODwvcInWTX0N/m7zC/9wRcQ1vE6gO6lbNd6JnwiLHclf+oLAsRLWwN9dEeDEER2IvtlmIapKhxDrPQ9zSAiibaVSAVxvWC5bal2CgfgijlamDQ8lPD+/Fv1O6s8hGTEfMiDNErCC7IWn3ckjg+Ipz11DQO2hRI/VmarFDFtreavVsSgwseVJIQxavgOzMJVFRx1TQCBZFvW9RnM32QDygq2vrs234fD3ak8DtdmKd0aPLNYSN3zaiaPOzfhK6Z5m36Zltqzhzjg0YkoPcbmPGUO5tq7X7SwFeb0Kx7gEPzZHavbcnNYtuPgqFJklNk2+3zztodccRgZGtLRQJay+xwSNh8YiU+NmIgx2ad24qugodzg== + + + + rCPHG4jkrBDKyvpa+lZ+8Xg5SNVCSFVjOJDE8l6BXFPRey5HW0r+Y0tQ9YN/3PGCHdZxYz6x146QW47+AJvUBLxyj2vXYyPZUykt4LreQw1NXj0QGoJ0ggK9mOpuIrGzBeeEubadPzYPpsseXNhPoTJoDcOrmfSr3cGmGNYEFvzf+6ktCpQNXgdAkh8s2XlUYG2AFyOgDArbmAkVTS258yQb0jdCeErmXojPyitCNKI//Ex2o7M6fIYN79nHzjABruXDN8rgQD0wTwWQpBqH8GajJ9oqDGV8EWLlyb+FBJ3LPnfamW1RhaXPctL8G0Lj4WVNqJkhk1nnS+A5Z21wxw== + AQAB + + + + + + + + 2022-02-01T04:00:00+00:00 + + + + + 2GrtUTk1CEDaqlG+Cq/RIrbT29BNG+spDJ8FVfBsMoyCSuzhnp/MSqbKXz1n6veO0QIXxMk2FfWtIG5R5Tclkw== + + + CN=CA de Ciudadanos y Entidades (4) - DESARROLLO,OU=NZZ Ziurtagiri publikoa - Certificado publico SCI,O=IZENPE S.A.,C=ES + 7030 + + + + + + + https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf + + + + + Quzn98x3PMbSHwbUzaj5f5KOpiH0u8bvmwbbbNkO9Es= + + + + + + Thirdparty + + + + + + + + urn:oid:1.2.840.10003.5.109.10 + + + text/xml + + + + + + + + \ No newline at end of file