aboutsummaryrefslogtreecommitdiffstats
path: root/internal/mapping/mapping_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/mapping/mapping_test.go')
-rw-r--r--internal/mapping/mapping_test.go118
1 files changed, 118 insertions, 0 deletions
diff --git a/internal/mapping/mapping_test.go b/internal/mapping/mapping_test.go
new file mode 100644
index 0000000..d9190cd
--- /dev/null
+++ b/internal/mapping/mapping_test.go
@@ -0,0 +1,118 @@
+package mapping
+
+import (
+ "errors"
+ "testing"
+ "time"
+
+ "simenandre.no/accounted-multicase-intgr/internal/accounted"
+ "simenandre.no/accounted-multicase-intgr/internal/multicase"
+)
+
+func config() *Config {
+ return &Config{
+ Accounts: map[string]string{"3000": "3001", "1460": "1460", "4301": "4000"},
+ CustomerLedgerAccount: "1510",
+ VATCodes: map[string]VATCode{
+ "3": {Rate: 25, Account: "2611"},
+ "6": {Rate: 0},
+ },
+ RoundingAccount: "3740",
+ MaxRoundingOre: 100,
+ SourceType: "manual",
+ }
+}
+
+func voucher(lines ...multicase.Line) multicase.Voucher {
+ return multicase.Voucher{
+ Type: "11", TypeText: "Faktura", Number: "100", Text: "Demo kunde",
+ Date: time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC), Lines: lines,
+ }
+}
+
+func TestSplitNet(t *testing.T) {
+ tests := []struct {
+ gross, want int64
+ rate float64
+ }{
+ {270019, 216015, 25},
+ {-270019, -216015, 25},
+ {12500, 10000, 25},
+ {1, 1, 25},
+ {11200, 10000, 12},
+ {5000, 5000, 0},
+ }
+ for _, tt := range tests {
+ if got := SplitNet(tt.gross, tt.rate); got != tt.want {
+ t.Errorf("SplitNet(%d, %v) = %d, want %d", tt.gross, tt.rate, got, tt.want)
+ }
+ }
+}
+
+func TestBuildSplitsVATAndMapsCustomerLedger(t *testing.T) {
+ e, err := config().Build(voucher(
+ multicase.Line{Account: "3000", Amount: -270019, VATCode: "3", CustomerNo: "20001"},
+ multicase.Line{Account: "20001", Amount: 270019, CustomerNo: "20001"},
+ ))
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := []accounted.Line{
+ {Account: "3001", Credit: 216015},
+ {Account: "2611", Credit: 54004},
+ {Account: "1510", Debit: 270019},
+ }
+ if len(e.Lines) != len(want) {
+ t.Fatalf("lines = %+v", e.Lines)
+ }
+ for i, w := range want {
+ g := e.Lines[i]
+ if g.Account != w.Account || g.Debit != w.Debit || g.Credit != w.Credit {
+ t.Errorf("line %d = %+v, want %+v", i, g, w)
+ }
+ }
+ if e.SourceID != "multicase:11:100" || e.EntryDate != "2026-10-01" || e.Description != "Faktura 100: Demo kunde" {
+ t.Errorf("header = %+v", e)
+ }
+}
+
+func TestBuildReportsUnmapped(t *testing.T) {
+ _, err := config().Build(voucher(
+ multicase.Line{Account: "9999", Amount: -100},
+ multicase.Line{Account: "1460", Amount: 100, VATCode: "42"},
+ ))
+ var u *UnmappedError
+ if !errors.As(err, &u) || len(u.Accounts) != 1 || u.Accounts[0] != "9999" || len(u.VATCodes) != 1 || u.VATCodes[0] != "42" {
+ t.Fatalf("err = %v", err)
+ }
+}
+
+func TestBuildRounding(t *testing.T) {
+ e, err := config().Build(voucher(
+ multicase.Line{Account: "1460", Amount: 1978734},
+ multicase.Line{Account: "4301", Amount: -1832162},
+ multicase.Line{Account: "4301", Amount: -146573},
+ ))
+ if err != nil {
+ t.Fatal(err)
+ }
+ last := e.Lines[len(e.Lines)-1]
+ if last.Account != "3740" || last.Debit != 1 {
+ t.Errorf("rounding line = %+v", last)
+ }
+
+ _, err = config().Build(voucher(
+ multicase.Line{Account: "1460", Amount: 1000},
+ multicase.Line{Account: "4301", Amount: -500},
+ ))
+ if err == nil {
+ t.Error("expected an error for a voucher off by more than max_rounding_ore")
+ }
+}
+
+func TestBuildSkipsZeroLines(t *testing.T) {
+ _, err := config().Build(voucher(multicase.Line{Account: "20001", Amount: 0, CustomerNo: "20001"}))
+ if !errors.Is(err, ErrEmpty) {
+ t.Fatalf("err = %v, want ErrEmpty", err)
+ }
+}