Skip to content

Commit

Permalink
Merge pull request #19 from invopop/ext-refactor
Browse files Browse the repository at this point in the history
Upgrade and adapt to the new GOBL Extensions feature
  • Loading branch information
samlown authored Sep 21, 2023
2 parents 2d9d2d5 + 1fe3205 commit bdbadf0
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 212 deletions.
5 changes: 1 addition & 4 deletions body.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ type scontoMaggiorazione struct {
}

func newFatturaElettronicaBody(inv *bill.Invoice) (*fatturaElettronicaBody, error) {
dbs, err := newDatiBeniServizi(inv)
if err != nil {
return nil, err
}
dbs := newDatiBeniServizi(inv)

dp, err := newDatiPagamento(inv)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion fatturapa.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ func (c *Converter) ConvertFromGOBL(env *gobl.Envelope) (*Document, error) {
}

// Make sure we're dealing with raw data
invoice = invoice.RemoveIncludedTaxes(2)
invoice, err := invoice.RemoveIncludedTaxes()
if err != nil {
return nil, err
}

datiTrasmissione := c.newDatiTrasmissione(invoice, env)

Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/invopop/gobl.fatturapa
go 1.19

require (
github.com/invopop/gobl v0.50.2
github.com/invopop/gobl v0.55.0
github.com/invopop/xmldsig v0.7.0
github.com/magefile/mage v1.14.0
github.com/spf13/cobra v1.7.0
Expand Down Expand Up @@ -32,3 +32,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect
)

// replace github.com/invopop/gobl => ../gobl
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,12 @@ 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.50.2 h1:wQgx85xDE9wHdrtMjIctvlkpY2BKHUNs7qn9/cC9qMw=
github.com/invopop/gobl v0.50.2/go.mod h1:X7EqVSEfeeIymdaOUrwkHu+OPPNATAHDQ8FPs2BvZFM=
github.com/invopop/gobl v0.54.0 h1:4sejjcl+p6thFoFVmi1w+yHNpHV2gbM/k9flT8q9SYk=
github.com/invopop/gobl v0.54.0/go.mod h1:/s8rsPX3RK5J/yGK41lzzzB+zXeC29rpIZBYjSjvYzM=
github.com/invopop/gobl v0.54.1-0.20230828145858-ddfafb15835d h1:LoEAkw3y/Fa5GtiVV8bVkaej1XywpbROB55a3XU+Jf8=
github.com/invopop/gobl v0.54.1-0.20230828145858-ddfafb15835d/go.mod h1:/s8rsPX3RK5J/yGK41lzzzB+zXeC29rpIZBYjSjvYzM=
github.com/invopop/gobl v0.55.0 h1:NV62UR/W2f/mWwqhnlkjuBad/Zb64u50pDIQDBTeFnw=
github.com/invopop/gobl v0.55.0/go.mod h1:/s8rsPX3RK5J/yGK41lzzzB+zXeC29rpIZBYjSjvYzM=
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/validation v0.3.0 h1:o260kbjXzoBO/ypXDSSrCLL7SxEFUXBsX09YTE9AxZw=
Expand Down
128 changes: 18 additions & 110 deletions items.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package fatturapa

import (
"fmt"
"strconv"

"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/i18n"
"github.com/invopop/gobl/num"
"github.com/invopop/gobl/regimes/common"
"github.com/invopop/gobl/regimes/it"
"github.com/invopop/gobl/tax"
)

var taxCategoryVat = regime.Category(common.TaxCategoryVAT)

// datiBeniServizi contains all data related to the goods and services sold.
type datiBeniServizi struct {
DettaglioLinee []*dettaglioLinee
Expand Down Expand Up @@ -42,57 +37,35 @@ type datiRiepilogo struct {
RiferimentoNormativo string `xml:",omitempty"`
}

func newDatiBeniServizi(inv *bill.Invoice) (*datiBeniServizi, error) {
dl, err := generateLineDetails(inv)
if err != nil {
return nil, err
}

dr, err := generateTaxSummary(inv)
if err != nil {
return nil, err
}

func newDatiBeniServizi(inv *bill.Invoice) *datiBeniServizi {
return &datiBeniServizi{
DettaglioLinee: dl,
DatiRiepilogo: dr,
}, nil
DettaglioLinee: generateLineDetails(inv),
DatiRiepilogo: generateTaxSummary(inv),
}
}

func generateLineDetails(inv *bill.Invoice) ([]*dettaglioLinee, error) {
func generateLineDetails(inv *bill.Invoice) []*dettaglioLinee {
var dl []*dettaglioLinee

for _, line := range inv.Lines {
vatRate := ""

for _, tax := range line.Taxes {
if tax.Category == common.TaxCategoryVAT {
vatRate = formatPercentage(tax.Percent)
break
}
}

codeNatura, err := findCodeNaturaLine(line)
if err != nil {
return nil, err
}
vatTax := line.Taxes.Get(common.TaxCategoryVAT)

dl = append(dl, &dettaglioLinee{
NumeroLinea: strconv.Itoa(line.Index),
Descrizione: line.Item.Name,
Quantita: formatAmount(&line.Quantity),
PrezzoUnitario: formatAmount(&line.Item.Price),
PrezzoTotale: formatAmount(&line.Sum),
AliquotaIVA: vatRate,
Natura: codeNatura,
AliquotaIVA: formatPercentage(vatTax.Percent),
Natura: vatTax.Ext[it.ExtKeySDINature].String(),
ScontoMaggiorazione: extractLinePriceAdjustments(line),
})
}

return dl, nil
return dl
}

func generateTaxSummary(inv *bill.Invoice) ([]*datiRiepilogo, error) {
func generateTaxSummary(inv *bill.Invoice) []*datiRiepilogo {
var dr []*datiRiepilogo
var vatRateTotals []*tax.RateTotal

Expand All @@ -104,21 +77,16 @@ func generateTaxSummary(inv *bill.Invoice) ([]*datiRiepilogo, error) {
}

for _, rateTotal := range vatRateTotals {
codeNatura, err := findCodeNaturaSummary(rateTotal)
if err != nil {
return nil, err
}

dr = append(dr, &datiRiepilogo{
AliquotaIVA: formatPercentage(rateTotal.Percent),
Natura: codeNatura,
Natura: rateTotal.Ext[it.ExtKeySDINature].String(),
ImponibileImporto: formatAmount(&rateTotal.Base),
Imposta: formatAmount(&rateTotal.Amount),
RiferimentoNormativo: findRiferimentoNormativo(rateTotal),
})
}

return dr, nil
return dr
}

func extractLinePriceAdjustments(line *bill.Line) []*scontoMaggiorazione {
Expand All @@ -143,76 +111,16 @@ func extractLinePriceAdjustments(line *bill.Line) []*scontoMaggiorazione {
return scontiMaggiorazioni
}

func findCodeNaturaLine(line *bill.Line) (string, error) {
rateKey := findZeroVatTaxRate(line)
if rateKey == "" {
return "", nil
}

return findCodeNatura(rateKey)
}

func findCodeNaturaSummary(rateTotal *tax.RateTotal) (string, error) {
if !isZeroRate(rateTotal.Percent) {
return "", nil
}

return findCodeNatura(rateTotal.Key)
}

func findCodeNatura(rateKey cbc.Key) (string, error) {
rate := findRate(taxCategoryVat.Rates, rateKey)
if rate == nil {
return "", fmt.Errorf("'Natura' code not found for VAT rate of zero with key '%s'", rateKey)
}

code := rate.Codes[it.KeyFatturaPANatura]
if code == "" {
return "", fmt.Errorf("'Natura' code not found for VAT rate of zero with key '%s'", rateKey)
}

return code.String(), nil
}

func findRiferimentoNormativo(rateTotal *tax.RateTotal) string {
if !isZeroRate(rateTotal.Percent) {
return ""
}

rate := findRate(taxCategoryVat.Rates, rateTotal.Key)
if rate == nil {
return ""
}

return rate.Name[i18n.IT]
}

func findRate(rates []*tax.Rate, taxRateKey cbc.Key) *tax.Rate {
for _, rate := range rates {
if rate.Key == taxRateKey {
return rate
}
}
return nil
}
def := regime.ExtensionDef(it.ExtKeySDINature)

func findZeroVatTaxRate(line *bill.Line) cbc.Key {
var combo *tax.Combo
nature := rateTotal.Ext[it.ExtKeySDINature]

for _, tax := range line.Taxes {
if tax.Category == common.TaxCategoryVAT {
combo = tax
break
for _, c := range def.Codes {
if c.Code == nature {
return c.Name[i18n.IT]
}
}

if combo == nil || !isZeroRate(combo.Percent) {
return ""
}

return combo.Rate
}

func isZeroRate(percent *num.Percentage) bool {
return percent == nil || percent.IsZero()
return ""
}
59 changes: 59 additions & 0 deletions items_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package fatturapa_test

import (
"testing"

"github.com/invopop/gobl.fatturapa/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDettaglioLinee(t *testing.T) {
t.Run("should contain the line info", func(t *testing.T) {
env := test.LoadTestFile("invoice-simple.json")
doc, err := test.ConvertFromGOBL(env)
require.NoError(t, err)

dl := doc.FatturaElettronicaBody[0].DatiBeniServizi.DettaglioLinee[0]

assert.Equal(t, "1", dl.NumeroLinea)
assert.Equal(t, "Development services", dl.Descrizione)
assert.Equal(t, "20.00", dl.Quantita)
assert.Equal(t, "90.00", dl.PrezzoUnitario)
assert.Equal(t, "1800.00", dl.PrezzoTotale)
assert.Equal(t, "22.00", dl.AliquotaIVA)
assert.Equal(t, "", dl.Natura)

sm := dl.ScontoMaggiorazione[0]

assert.Equal(t, "SC", sm.Tipo)
assert.Equal(t, "10.00", sm.Percentuale)
assert.Equal(t, "180.00", sm.Importo)

dl = doc.FatturaElettronicaBody[0].DatiBeniServizi.DettaglioLinee[1]

assert.Equal(t, "2", dl.NumeroLinea)
assert.Equal(t, "N2.2", dl.Natura)
})
}

func TestDatiRiepilogo(t *testing.T) {
t.Run("should contain the tax summary info", func(t *testing.T) {
env := test.LoadTestFile("invoice-simple.json")
doc, err := test.ConvertFromGOBL(env)
require.NoError(t, err)

dr := doc.FatturaElettronicaBody[0].DatiBeniServizi.DatiRiepilogo[0]

assert.Equal(t, "22.00", dr.AliquotaIVA)
assert.Equal(t, "1620.00", dr.ImponibileImporto)
assert.Equal(t, "356.40", dr.Imposta)
assert.Equal(t, "", dr.Natura)
assert.Equal(t, "", dr.RiferimentoNormativo)

dr = doc.FatturaElettronicaBody[0].DatiBeniServizi.DatiRiepilogo[1]

assert.Equal(t, "N2.2", dr.Natura)
assert.Equal(t, "Non soggette - altri casi", dr.RiferimentoNormativo)
})
}
18 changes: 1 addition & 17 deletions parties.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ func newCedentePrestatore(inv *bill.Invoice) (*supplier, error) {
return nil, err
}

rf, err := findCodeRegimeFiscale(inv)
if err != nil {
return nil, err
}

contatti := newContatti(s)

return &supplier{
Expand All @@ -93,7 +88,7 @@ func newCedentePrestatore(inv *bill.Invoice) (*supplier, error) {
IdCodice: s.TaxID.Code.String(),
},
Anagrafica: newAnagrafica(s),
RegimeFiscale: rf,
RegimeFiscale: s.Ext[it.ExtKeySDIFiscalRegime].String(),
},
Sede: address,
IscrizioneREA: newIscrizioneREA(s),
Expand Down Expand Up @@ -165,17 +160,6 @@ func newContatti(party *org.Party) *contatti {
return c
}

func findCodeRegimeFiscale(inv *bill.Invoice) (string, error) {
ss := inv.ScenarioSummary()

regimeFiscale := ss.Codes[it.KeyFatturaPARegimeFiscale]
if regimeFiscale == "" {
return "", errors.New("could not find RegimeFiscale code for supplier")
}

return regimeFiscale.String(), nil
}

func customerFiscaleIVA(id *tax.Identity, fallBack string) *taxID {
idCodice := id.Code.String()

Expand Down
2 changes: 1 addition & 1 deletion payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func findCodeModalitaPagamento(key cbc.Key) (string, error) {
return "", fmt.Errorf("ModalitaPagamento Code not found for payment method key '%s'", key)
}

code := keyDef.Codes[it.KeyFatturaPAModalitaPagamento]
code := keyDef.Map[it.KeyFatturaPAModalitaPagamento]
if code == "" {
return "", fmt.Errorf("ModalitaPagamento Code not found for payment method key '%s'", key)
}
Expand Down
Loading

0 comments on commit bdbadf0

Please sign in to comment.