diff --git a/go.mod b/go.mod index 69bdda6..51854b0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/invopop/gobl.fatturapa go 1.19 require ( - github.com/invopop/gobl v0.58.1 + github.com/invopop/gobl v0.64.0 github.com/invopop/xmldsig v0.7.0 github.com/magefile/mage v1.14.0 github.com/spf13/cobra v1.7.0 @@ -15,18 +15,22 @@ require ( cloud.google.com/go v0.110.2 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beevik/etree v1.1.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/invopop/jsonschema v0.7.0 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect github.com/invopop/validation v0.3.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/otiai10/copy v1.10.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 84bd598..e96b93f 100644 --- a/go.sum +++ b/go.sum @@ -614,10 +614,14 @@ github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= @@ -794,14 +798,21 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/gobl v0.58.1 h1:Iagqgx1Z6IsqypAaMWUnITMUIcDautfK/k1SeIPH7S0= github.com/invopop/gobl v0.58.1/go.mod h1:V4YpkOYucgBYbk3VMlUZJSENjg1N5NTGV0Baok6H5J0= +github.com/invopop/gobl v0.62.1-0.20231120151502-d9bdf163d804 h1:Lz9Odb4RhAGQv6NzVaW/pFiAa1+mkmvacNsTKW/VGdY= +github.com/invopop/gobl v0.62.1-0.20231120151502-d9bdf163d804/go.mod h1:sEngvTr2gAxexosO0rmQInVSL8C613TUPvBcFT4xMyM= +github.com/invopop/gobl v0.64.0 h1:eaSLjGyTKRSHGMfN6tJyc1Xh2j6oqaJjnccXv/h2tfI= +github.com/invopop/gobl v0.64.0/go.mod h1:sEngvTr2gAxexosO0rmQInVSL8C613TUPvBcFT4xMyM= github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/invopop/validation v0.3.0 h1:o260kbjXzoBO/ypXDSSrCLL7SxEFUXBsX09YTE9AxZw= github.com/invopop/validation v0.3.0/go.mod h1:qIBG6APYLp2Wu3/96p3idYjP8ffTKVmQBfKiZbw0Hts= github.com/invopop/xmldsig v0.7.0 h1:cnUE5SOW4TanHKCnF5Va/PfsdK0LgEoRE/+P6It5LuY= github.com/invopop/xmldsig v0.7.0/go.mod h1:dc3+2BYNw0vzauyZiOobTltp1t3BbvWSq7ae/F2gdk0= github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -827,6 +838,8 @@ github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuz github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= @@ -887,6 +900,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/items.go b/items.go index 4197cfb..277b9f4 100644 --- a/items.go +++ b/items.go @@ -5,7 +5,6 @@ import ( "github.com/invopop/gobl/bill" "github.com/invopop/gobl/i18n" - "github.com/invopop/gobl/regimes/common" "github.com/invopop/gobl/regimes/it" "github.com/invopop/gobl/tax" ) @@ -48,7 +47,7 @@ func generateLineDetails(inv *bill.Invoice) []*dettaglioLinee { var dl []*dettaglioLinee for _, line := range inv.Lines { - vatTax := line.Taxes.Get(common.TaxCategoryVAT) + vatTax := line.Taxes.Get(tax.CategoryVAT) dl = append(dl, &dettaglioLinee{ NumeroLinea: strconv.Itoa(line.Index), @@ -70,7 +69,7 @@ func generateTaxSummary(inv *bill.Invoice) []*datiRiepilogo { var vatRateTotals []*tax.RateTotal for _, cat := range inv.Totals.Taxes.Categories { - if cat.Code == common.TaxCategoryVAT { + if cat.Code == tax.CategoryVAT { vatRateTotals = cat.Rates break } diff --git a/test/data/invoice-simple-with-pec.json b/test/data/invoice-simple-with-pec.json new file mode 100644 index 0000000..7c487fb --- /dev/null +++ b/test/data/invoice-simple-with-pec.json @@ -0,0 +1,206 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "679a2f25-7483-11ec-9722-7ea2cb436ff6", + "dig": { + "alg": "sha256", + "val": "a822e8e5808906fec7f7c01238604745da5303a975215421913e7ab1b26adfc3" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "type": "standard", + "series": "SAMPLE", + "code": "001", + "issue_date": "2023-03-02", + "currency": "EUR", + "tax": { + "tags": ["freelance"] + }, + "supplier": { + "name": "MªF. Services", + "tax_id": { + "country": "IT", + "code": "12345678903" + }, + "people": [ + { + "name": { + "given": "GIANCARLO", + "surname": "ROSSI" + } + } + ], + "addresses": [ + { + "num": "1", + "street": "VIALE DELLA LIBERTÀ", + "locality": "ROMA", + "region": "RM", + "code": "00100", + "country": "IT" + } + ], + "emails": [ + { + "addr": "billing@example.com" + } + ], + "telephones": [ + { + "num": "999999999" + } + ], + "registration": { + "capital": "50000.00", + "currency": "EUR", + "office": "RM", + "entry": "123456" + }, + "ext": { + "it-sdi-fiscal-regime": "RF01" + } + }, + "customer": { + "name": "MARIO LEONI", + "tax_id": { + "country": "IT", + "code": "09876543217" + }, + "people": [ + { + "name": { + "prefix": "Dott.", + "given": "MARIO", + "surname": "LEONI" + } + } + ], + "inboxes": [ + { + "key": "it-sdi-pec", + "code": "fooo@inbox.com" + } + ], + "addresses": [ + { + "num": "32", + "street": "VIALE DELI LAVORATORI", + "locality": "FIRENZE", + "region": "FI", + "code": "50100", + "country": "IT" + } + ], + "emails": [ + { + "addr": "leoni@mario.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": "22.0%" + } + ], + "total": "1620.00" + }, + { + "i": 2, + "quantity": "1", + "item": { + "name": "Special Untaxed Work", + "price": "100.00", + "unit": "h" + }, + "sum": "100.00", + "taxes": [ + { + "cat": "VAT", + "rate": "exempt", + "ext": { + "it-sdi-nature": "N2.2" + } + } + ], + "total": "100.00" + } + ], + "discounts": [ + { + "i": 1, + "base": "1720.00", + "percent": "50%", + "amount": "860.00", + "reason": "10th year anniversary discount" + } + ], + "charges": [ + { + "i": 1, + "base": "1720.00", + "percent": "10%", + "amount": "172.00", + "reason": "10th year anniversary charge" + } + ], + "payment": { + "instructions": { + "key": "card" + } + }, + "totals": { + "sum": "1720.00", + "discount": "860.00", + "charge": "172.00", + "total": "1032.00", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "base": "1620.00", + "percent": "22.0%", + "amount": "356.40" + }, + { + "key": "exempt", + "ext": { + "it-sdi-nature": "N2.2" + }, + "base": "100.00", + "amount": "0.00" + } + ], + "amount": "356.40" + } + ], + "sum": "356.40" + }, + "tax": "356.40", + "total_with_tax": "1388.40", + "payable": "1388.40" + } + } +} diff --git a/test/data/invoice-simple.json b/test/data/invoice-simple.json index 2f6350d..53e46d9 100644 --- a/test/data/invoice-simple.json +++ b/test/data/invoice-simple.json @@ -1,208 +1,206 @@ { - "$schema": "https://gobl.org/draft-0/envelope", - "head": { - "uuid": "679a2f25-7483-11ec-9722-7ea2cb436ff6", - "dig": { - "alg": "sha256", - "val": "a822e8e5808906fec7f7c01238604745da5303a975215421913e7ab1b26adfc3" - } - }, - "doc": { - "$schema": "https://gobl.org/draft-0/bill/invoice", - "type": "standard", - "series": "SAMPLE", - "code": "001", - "issue_date": "2023-03-02", - "currency": "EUR", - "tax": { - "tags": [ - "freelance" - ] - }, - "supplier": { - "name": "MªF. Services", - "tax_id": { - "country": "IT", - "code": "12345678903" - }, - "people": [ - { - "name": { - "given": "GIANCARLO", - "surname": "ROSSI" - } - } - ], - "addresses": [ - { - "num": "1", - "street": "VIALE DELLA LIBERTÀ", - "locality": "ROMA", - "region": "RM", - "code": "00100", - "country": "IT" - } - ], - "emails": [ - { - "addr": "billing@example.com" - } - ], - "telephones": [ - { - "num": "999999999" - } - ], - "registration": { - "capital": "50000.00", - "currency": "EUR", - "office": "RM", - "entry": "123456" - }, - "ext": { - "it-sdi-fiscal-regime": "RF01" - } - }, - "customer": { - "name": "MARIO LEONI", - "tax_id": { - "country": "IT", - "code": "09876543217" - }, - "people": [ - { - "name": { - "prefix": "Dott.", - "given": "MARIO", - "surname": "LEONI" - } - } - ], - "inboxes": [ - { - "key": "codice-destinatario", - "code": "ABCDEF1" - } - ], - "addresses": [ - { - "num": "32", - "street": "VIALE DELI LAVORATORI", - "locality": "FIRENZE", - "region": "FI", - "code": "50100", - "country": "IT" - } - ], - "emails": [ - { - "addr": "leoni@mario.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": "22.0%" - } - ], - "total": "1620.00" - }, - { - "i": 2, - "quantity": "1", - "item": { - "name": "Special Untaxed Work", - "price": "100.00", - "unit": "h" - }, - "sum": "100.00", - "taxes": [ - { - "cat": "VAT", - "rate": "exempt", - "ext": { - "it-sdi-nature": "N2.2" - } - } - ], - "total": "100.00" - } - ], - "discounts": [ - { - "i": 1, - "base": "1720.00", - "percent": "50%", - "amount": "860.00", - "reason": "10th year anniversary discount" - } - ], - "charges": [ - { - "i": 1, - "base": "1720.00", - "percent": "10%", - "amount": "172.00", - "reason": "10th year anniversary charge" - } - ], - "payment": { - "instructions": { - "key": "card" - } - }, - "totals": { - "sum": "1720.00", - "discount": "860.00", - "charge": "172.00", - "total": "1032.00", - "taxes": { - "categories": [ - { - "code": "VAT", - "rates": [ - { - "key": "standard", - "base": "1620.00", - "percent": "22.0%", - "amount": "356.40" - }, - { - "key": "exempt", - "ext": { - "it-sdi-nature": "N2.2" - }, - "base": "100.00", - "amount": "0.00" - } - ], - "amount": "356.40" - } - ], - "sum": "356.40" - }, - "tax": "356.40", - "total_with_tax": "1388.40", - "payable": "1388.40" - } - } + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "679a2f25-7483-11ec-9722-7ea2cb436ff6", + "dig": { + "alg": "sha256", + "val": "a822e8e5808906fec7f7c01238604745da5303a975215421913e7ab1b26adfc3" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "type": "standard", + "series": "SAMPLE", + "code": "001", + "issue_date": "2023-03-02", + "currency": "EUR", + "tax": { + "tags": ["freelance"] + }, + "supplier": { + "name": "MªF. Services", + "tax_id": { + "country": "IT", + "code": "12345678903" + }, + "people": [ + { + "name": { + "given": "GIANCARLO", + "surname": "ROSSI" + } + } + ], + "addresses": [ + { + "num": "1", + "street": "VIALE DELLA LIBERTÀ", + "locality": "ROMA", + "region": "RM", + "code": "00100", + "country": "IT" + } + ], + "emails": [ + { + "addr": "billing@example.com" + } + ], + "telephones": [ + { + "num": "999999999" + } + ], + "registration": { + "capital": "50000.00", + "currency": "EUR", + "office": "RM", + "entry": "123456" + }, + "ext": { + "it-sdi-fiscal-regime": "RF01" + } + }, + "customer": { + "name": "MARIO LEONI", + "tax_id": { + "country": "IT", + "code": "09876543217" + }, + "people": [ + { + "name": { + "prefix": "Dott.", + "given": "MARIO", + "surname": "LEONI" + } + } + ], + "inboxes": [ + { + "key": "it-sdi-code", + "code": "ABCDEF1" + } + ], + "addresses": [ + { + "num": "32", + "street": "VIALE DELI LAVORATORI", + "locality": "FIRENZE", + "region": "FI", + "code": "50100", + "country": "IT" + } + ], + "emails": [ + { + "addr": "leoni@mario.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": "22.0%" + } + ], + "total": "1620.00" + }, + { + "i": 2, + "quantity": "1", + "item": { + "name": "Special Untaxed Work", + "price": "100.00", + "unit": "h" + }, + "sum": "100.00", + "taxes": [ + { + "cat": "VAT", + "rate": "exempt", + "ext": { + "it-sdi-nature": "N2.2" + } + } + ], + "total": "100.00" + } + ], + "discounts": [ + { + "i": 1, + "base": "1720.00", + "percent": "50%", + "amount": "860.00", + "reason": "10th year anniversary discount" + } + ], + "charges": [ + { + "i": 1, + "base": "1720.00", + "percent": "10%", + "amount": "172.00", + "reason": "10th year anniversary charge" + } + ], + "payment": { + "instructions": { + "key": "card" + } + }, + "totals": { + "sum": "1720.00", + "discount": "860.00", + "charge": "172.00", + "total": "1032.00", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "base": "1620.00", + "percent": "22.0%", + "amount": "356.40" + }, + { + "key": "exempt", + "ext": { + "it-sdi-nature": "N2.2" + }, + "base": "100.00", + "amount": "0.00" + } + ], + "amount": "356.40" + } + ], + "sum": "356.40" + }, + "tax": "356.40", + "total_with_tax": "1388.40", + "payable": "1388.40" + } + } } diff --git a/transmission.go b/transmission.go index 9570f93..d186c42 100644 --- a/transmission.go +++ b/transmission.go @@ -21,54 +21,69 @@ const ( defaultCodiceDestinatarioForeignBusiness = "XXXXXXX" ) -const inboxKeyCodiceDestinatario = "codice-destinatario" - // Data related to the transmission of the invoice type datiTrasmissione struct { IdTrasmittente *taxID `xml:",omitempty"` // nolint:revive ProgressivoInvio string `xml:",omitempty"` FormatoTrasmissione string `xml:",omitempty"` CodiceDestinatario string + PECDestinatario string `xml:",omitempty"` } func (c *Converter) newDatiTrasmissione(inv *bill.Invoice, env *gobl.Envelope) *datiTrasmissione { - if c.Config.Transmitter == nil { - return &datiTrasmissione{ - CodiceDestinatario: codiceDestinatario(inv.Customer), - } + dt := &datiTrasmissione{ + CodiceDestinatario: codiceDestinatario(inv.Customer), + PECDestinatario: pecDestinatario(inv.Customer), } - return &datiTrasmissione{ - IdTrasmittente: &taxID{ + // Do we need to add the transmitter info? + if c.Config.Transmitter != nil { + dt.IdTrasmittente = &taxID{ IdPaese: c.Config.Transmitter.CountryCode, IdCodice: c.Config.Transmitter.TaxID, - }, - ProgressivoInvio: env.Head.UUID.String()[:8], - FormatoTrasmissione: formatoTransmissione(inv.Customer), - CodiceDestinatario: codiceDestinatario(inv.Customer), + } + dt.ProgressivoInvio = env.Head.UUID.String()[:8] + dt.FormatoTrasmissione = formatoTransmissione(inv.Customer) } + + return dt } func formatoTransmissione(cus *org.Party) string { - taxID := cus.TaxID - - if taxID.Country == l10n.IT && taxID.Type == it.TaxIdentityTypeGovernment { - return formatoTrasmissioneFPA12 + if cus != nil { + taxID := cus.TaxID + if taxID.Country == l10n.IT && taxID.Type == it.TaxIdentityTypeGovernment { + return formatoTrasmissioneFPA12 + } } return formatoTrasmissioneFPR12 } func codiceDestinatario(cus *org.Party) string { - if cus.TaxID.Country != l10n.IT { - return defaultCodiceDestinatarioForeignBusiness - } - - for _, inbox := range cus.Inboxes { - if inbox.Key == inboxKeyCodiceDestinatario { - return inbox.Code + if cus != nil { + if cus.TaxID != nil && cus.TaxID.Country != l10n.IT { + return defaultCodiceDestinatarioForeignBusiness + } + for _, inbox := range cus.Inboxes { + if inbox.Key == it.KeyInboxSDICode { + return inbox.Code + } } } + // When this is returned, we'll assume there is a PEC. + // This is also valid for individuals. return defaultCodiceDestinatarioItalianBusiness } + +func pecDestinatario(cus *org.Party) string { + if cus != nil { + for _, inbox := range cus.Inboxes { + if inbox.Key == it.KeyInboxSDIPEC { + return inbox.Code + } + } + } + return "" +} diff --git a/transmission_test.go b/transmission_test.go index 061543a..22ed8b2 100644 --- a/transmission_test.go +++ b/transmission_test.go @@ -39,4 +39,17 @@ func TestTransmissionData(t *testing.T) { assert.Equal(t, "", dt.ProgressivoInvio) assert.Equal(t, "", dt.FormatoTrasmissione) }) + + t.Run("should set codice destinatario to 0000000 if customer is Italian with PEC", func(t *testing.T) { + converter := test.NewConverter() + + env := test.LoadTestFile("invoice-simple-with-pec.json") + doc, err := test.ConvertFromGOBL(env, converter) + require.NoError(t, err) + + dt := doc.FatturaElettronicaHeader.DatiTrasmissione + + assert.Equal(t, "0000000", dt.CodiceDestinatario) + assert.Equal(t, "fooo@inbox.com", dt.PECDestinatario) + }) }