-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathretained_taxes_in.go
89 lines (77 loc) · 2.42 KB
/
retained_taxes_in.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package fatturapa
import (
"fmt"
"github.com/invopop/gobl/addons/it/sdi"
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/num"
"github.com/invopop/gobl/regimes/it"
"github.com/invopop/gobl/tax"
)
// processRetainedTaxes processes retained taxes and adds them to the appropriate line items
func processRetainedTaxes(inv *bill.Invoice, lineDetails []*LineDetail, retainedTaxes []*RetainedTax) error {
if len(retainedTaxes) == 0 || len(inv.Lines) == 0 {
return nil
}
// Process each retained tax
for _, rt := range retainedTaxes {
// Parse the retained tax rate and amount
rtRate, err1 := num.PercentageFromString(rt.Rate + "%")
rtAmount, err2 := num.AmountFromString(rt.Amount)
if err1 != nil || err2 != nil {
return fmt.Errorf("invalid retained tax rate or amount: %s %s", rt.Rate, rt.Amount)
}
// Convert tax type to category code
catCode, err := convertRetainedTaxType(rt.Type)
if err != nil {
return err
}
// Find a line with Retained="SI" that matches this retained tax
matched := false
for i, detail := range lineDetails {
// Only consider lines marked with Ritenuta="SI"
if detail.Retained == "SI" {
line := inv.Lines[i]
expectedAmount := rtRate.Of(*line.Total)
// Check if this matches the retained tax amount exactly
if expectedAmount.Equals(rtAmount) {
// Create and add the retained tax to the line
taxCombo := &tax.Combo{
Category: catCode,
Percent: &rtRate,
Ext: tax.Extensions{},
}
// Add the reason code to extensions if present
if rt.Reason != "" {
taxCombo.Ext[sdi.ExtKeyRetained] = cbc.Code(rt.Reason)
}
line.Taxes = append(line.Taxes, taxCombo)
matched = true
break
}
}
}
// If we couldn't match this retained tax, return an error
if !matched {
return fmt.Errorf("could not match retained tax: %s %s%% %s", rt.Type, rt.Rate, rt.Amount)
}
}
return nil
}
// convertRetainedTaxType converts a TipoRitenuta code to a tax category code
func convertRetainedTaxType(tipoRitenuta string) (cbc.Code, error) {
switch tipoRitenuta {
case "RT01":
return it.TaxCategoryIRPEF, nil
case "RT02":
return it.TaxCategoryIRES, nil
case "RT03":
return it.TaxCategoryINPS, nil
case "RT04":
return it.TaxCategoryENASARCO, nil
case "RT05":
return it.TaxCategoryENPAM, nil
default:
return "", fmt.Errorf("unknown TipoRitenuta code: %s", tipoRitenuta)
}
}