2 Commits
Author SHA1 Message Date
esilva ab55a748ab Marshalling 2025-09-14 15:44:07 +01:00
esilva b2bca295e0 Added benchmark test 2025-09-08 19:09:04 +01:00
4 changed files with 120 additions and 41 deletions
+3
View File
@@ -2,3 +2,6 @@ test:
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
rm coverage.out
bench:
go test -bench=. -cpuprofile=cpu.out -memprofile=mem.out
+18 -2
View File
@@ -5,8 +5,8 @@ import (
"testing"
)
func TestFatQRAPI(t *testing.T) {
input := "A:123456789*B:999999990*C:PT*D:FT*E:N*F:20191231*" +
var (
completeInput = "A:123456789*B:999999990*C:PT*D:FT*E:N*F:20191231*" +
"G:FT AB2019/0035*H:CSDF7T5H-0035*I1:PT*I2:12000.00*I3:15000.00*" +
"I4:900.00*I5:50000.00*I6:6500.00*I7:80000.00*I8:18400.00*J1:PT-AC*" +
"J2:10000.00*J3:25000.56*J4:1000.02*J5:75000.00*J6:6750.00*" +
@@ -14,6 +14,10 @@ func TestFatQRAPI(t *testing.T) {
"K5:25000.00*K6:3000.00*K7:40000.00*K8:8800.00*L:100.00*M:25.00*" +
"N:64000.02*O:513600.58*P:100.00*Q:kLp0*R:9999*" +
"S:TB;PT00000000000000000000000;513500.58"
)
func TestFatQRAPI(t *testing.T) {
input := completeInput
var qr gofatqr.FatQR
err := qr.Scan(input, 0)
@@ -21,3 +25,15 @@ func TestFatQRAPI(t *testing.T) {
t.Errorf("Should not have occurred an error for: %s, %+v", input, err)
}
}
func BenchmarkFatQRScan(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var qr gofatqr.FatQR
err := qr.Scan(completeInput, 0)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
}
+46 -37
View File
@@ -5,6 +5,7 @@ package gofatqr
// implementation too, who knows amirite
import (
"encoding/json"
"fmt"
"strconv"
"strings"
@@ -21,37 +22,42 @@ const (
NifValidation
)
const (
decCount = 2
separator = "*"
)
type FiscalSpace struct {
TaxCountryRegion string // 1 - fiscal space
TaxableBase *dec.Decimal // 2
TaxableReduced *dec.Decimal // 3
VatTotalReducedTax *dec.Decimal // 4
TaxableIntermediateBase *dec.Decimal // 5
VatTotalIntermediateTax *dec.Decimal // 6
TaxableNormalBase *dec.Decimal // 7
VatTotalNormalBase *dec.Decimal // 8
TaxCountryRegion string `json:"TaxCountryRegion"` // 1
TaxableBase *dec.Decimal `json:"TaxableBase"` // 2
TaxableReduced *dec.Decimal `json:"TaxableReduced"` // 3
VatTotalReducedTax *dec.Decimal `json:"VatTotalReducedTax"` // 4
TaxableIntermediateBase *dec.Decimal `json:"TaxableIntermediateBase"` // 5
VatTotalIntermediateTax *dec.Decimal `json:"VatTotalIntermediateTax"` // 6
TaxableNormalBase *dec.Decimal `json:"TaxableNormalBase"` // 7
VatTotalNormalBase *dec.Decimal `json:"VatTotalNormalBase"` // 8
}
type FatQR struct {
TaxRegistrationNumber string // A
CustomerTaxID string // B
Country string // C customer country ISO 3166-1 alpha2
InvoiceType string // D
InvoiceStatus string // E
InvoiceDate time.Time // F
InvoiceNo string // G
ATCUD string // H
IFiscalSpace FiscalSpace // I1-I8
JFiscalSpace FiscalSpace // I1-I8
KFiscalSpace FiscalSpace // I1-I8
NotTaxable *dec.Decimal // L
StampDuty *dec.Decimal // M "Imposto de Selo"
TaxPayable *dec.Decimal // N
GrossTotal *dec.Decimal // O
WithholdingTaxAmount *dec.Decimal // P
HashQuartet string // Q
SoftwareCertificateNumber int64 // R
OtherInfo string // S
TaxRegistrationNumber string `json:"TaxRegistrationNumber"` // A
CustomerTaxID string `json:"CustomerTaxID"` // B
Country string `json:"Country"` // C country ISO 3166-1 alpha2
InvoiceType string `json:"InvoiceType"` // D
InvoiceStatus string `json:"InvoiceStatus"` // E
InvoiceDate time.Time `json:"InvoiceDate"` // F
InvoiceNo string `json:"InvoiceNo"` // G
ATCUD string `json:"ATCUD"` // H
IFiscalSpace FiscalSpace `json:"IFiscalSpace"` // I1-I8
JFiscalSpace FiscalSpace `json:"JFiscalSpace"` // I1-I8
KFiscalSpace FiscalSpace `json:"KFiscalSpace"` // I1-I8
NotTaxable *dec.Decimal `json:"NotTaxable"` // L
StampDuty *dec.Decimal `json:"StampDuty"` // M "Imposto de Selo"
TaxPayable *dec.Decimal `json:"TaxPayable"` // N
GrossTotal *dec.Decimal `json:"GrossTotal"` // O
WithholdingTaxAmount *dec.Decimal `json:"WithholdingTaxAmount"` // P
HashQuartet string `json:"HashQuartet"` // Q
SWCertNo int64 `json:"SWCertNo"` // R
OtherInfo string `json:"OtherInfo"` // S
}
type FieldCodec struct {
@@ -69,12 +75,6 @@ var (
"K1", "K2", "K3", "K4", "K5", "K6", "K7", "K8",
"L", "M", "N", "O", "P", "Q", "R", "S",
}
// lastKey = fieldOrder[len(fieldOrder)-1]
)
const (
decCount = 2
separator = "*"
)
var fatQRFieldMap = map[string]FieldCodec{
@@ -571,7 +571,7 @@ var fatQRFieldMap = map[string]FieldCodec{
Required: true,
Parse: func(f *FatQR, val string) error {
var err error
f.SoftwareCertificateNumber, err = strconv.ParseInt(val, 10, 16)
f.SWCertNo, err = strconv.ParseInt(val, 10, 16)
if err != nil {
return err
}
@@ -579,10 +579,10 @@ var fatQRFieldMap = map[string]FieldCodec{
return nil
},
String: func(f *FatQR) string {
return "R:" + fmt.Sprintf("%04d", f.SoftwareCertificateNumber)
return "R:" + fmt.Sprintf("%04d", f.SWCertNo)
},
Empty: func(f *FatQR) bool {
return f.SoftwareCertificateNumber < 1
return f.SWCertNo < 1
},
},
"S": {
@@ -611,6 +611,15 @@ func stringDecimal(d *dec.Decimal) string {
return d.Truncate(decCount).StringFixed(decCount)
}
func (fq *FatQR) ToJSON() []byte {
jsondata, _ := json.Marshal(fq)
return jsondata
}
func (fq *FatQR) FromJSON(data []byte) error {
return json.Unmarshal(data, fq)
}
func (fq *FatQR) scanPart(part []string) error {
val, ok := fatQRFieldMap[part[0]]
if !ok {
@@ -627,7 +636,7 @@ func (fq *FatQR) scanPart(part []string) error {
func (fq *FatQR) scanParts(parts []string) error {
for k := range parts {
keyValuePair := strings.Split(parts[k], ":")
keyValuePair := strings.SplitN(parts[k], ":", 2)
if len(keyValuePair) != 2 {
return fmt.Errorf("failed to parse key value pair: %s", parts[k])
}
+53 -2
View File
@@ -285,5 +285,56 @@ func TestScanPartI2(t *testing.T) {
}
}
// TODO:
// Add more UTs
func TestMarshalling(t *testing.T) {
input := "A:123456789*B:999999990*C:PT*D:FT*E:N*F:20191231*" +
"G:FT AB2019/0035*H:CSDF7T5H-0035*I1:PT*I2:12000.00*I3:15000.00*" +
"I4:900.00*I5:50000.00*I6:6500.00*I7:80000.00*I8:18400.00*J1:PT-AC*" +
"J2:10000.00*J3:25000.56*J4:1000.02*J5:75000.00*J6:6750.00*" +
"J7:100000.00*J8:18000.00*K1:PT-MA*K2:5000.00*K3:12500.00*K4:625.00*" +
"K5:25000.00*K6:3000.00*K7:40000.00*K8:8800.00*L:100.00*M:25.00*" +
"N:64000.02*O:513600.58*P:100.00*Q:kLp0*R:9999*" +
"S:TB;PT00000000000000000000000;513500.58"
expected := "{\"TaxRegistrationNumber\":\"123456789\",\"CustomerTaxID\":\"999999990\"," +
"\"Country\":\"PT\",\"InvoiceType\":\"FT\",\"InvoiceStatus\":\"N\"," +
"\"InvoiceDate\":\"2019-12-31T00:00:00Z\",\"InvoiceNo\":\"FT AB2019/0035\"," +
"\"ATCUD\":\"CSDF7T5H-0035\",\"IFiscalSpace\":{\"TaxCountryRegion\":\"PT\"," +
"\"TaxableBase\":\"12000\",\"TaxableReduced\":\"15000\",\"VatTotalReducedTax\":\"900\"," +
"\"TaxableIntermediateBase\":\"50000\",\"VatTotalIntermediateTax\":\"6500\"," +
"\"TaxableNormalBase\":\"80000\",\"VatTotalNormalBase\":\"18400\"}," +
"\"JFiscalSpace\":{\"TaxCountryRegion\":\"PT-AC\",\"TaxableBase\":\"10000\"," +
"\"TaxableReduced\":\"25000.56\",\"VatTotalReducedTax\":\"1000.02\"," +
"\"TaxableIntermediateBase\":\"75000\",\"VatTotalIntermediateTax\":\"6750\"," +
"\"TaxableNormalBase\":\"100000\",\"VatTotalNormalBase\":\"18000\"}," +
"\"KFiscalSpace\":{\"TaxCountryRegion\":\"PT-MA\",\"TaxableBase\":\"5000\"," +
"\"TaxableReduced\":\"12500\",\"VatTotalReducedTax\":\"625\"," +
"\"TaxableIntermediateBase\":\"25000\",\"VatTotalIntermediateTax\":\"3000\"," +
"\"TaxableNormalBase\":\"40000\",\"VatTotalNormalBase\":\"8800\"},\"NotTaxable\":\"100\"," +
"\"StampDuty\":\"25\",\"TaxPayable\":\"64000.02\",\"GrossTotal\":\"513600.58\"," +
"\"WithholdingTaxAmount\":\"100\",\"HashQuartet\":\"kLp0\",\"SWCertNo\":9999," +
"\"OtherInfo\":\"TB;PT00000000000000000000000;513500.58\"}"
var f FatQR
err := f.Scan(input, 0)
if err != nil {
t.Errorf("Scan should've been successful: %+v", err)
}
jsonData := f.ToJSON()
if diff := cmp.Diff(string(jsonData), expected); diff != "" {
t.Errorf("String mismatch (-want +got):\n%s", diff)
}
var newF FatQR
err = newF.FromJSON(jsonData)
if err != nil {
t.Errorf("FromJSON should've been successful: %+v", err)
}
newJsonData := newF.ToJSON()
if diff := cmp.Diff(string(newJsonData), expected); diff != "" {
t.Errorf("String mismatch (-want +got):\n%s", diff)
}
}
// TODO: Add more UTs