package matching // Expected values verified against scripts/match_payments.py on 2026-05-06: // // PYTHONPATH=scripts:. python3 << 'EOF' // from match_payments import infer_transaction_details // MEMBERS = ["Tomáš Němeček (Tov)", "Jana Nováková"] // cases = [ // ({"sender":"Tomas Nemecek","message":"clenske 04/2026","user_id":"","date":"2026-04-15"}, "full match"), // ({"sender":"Tomas Nemecek","message":"","user_id":"","date":"2026-04-15"}, "sender fallback month"), // ({"sender":"Jana Novakova","message":"","user_id":"","date":44197}, "serial int date"), // ({"sender":"neznamy","message":"","user_id":"","date":""}, "no match"), // ({"sender":"Tomas Nemecek","message":"","user_id":"","date":44197.5}, "serial float date"), // ] // for tx, label in cases: // r = infer_transaction_details(tx, MEMBERS) // print(label + ": members=" + repr(r["members"]) + " months=" + repr(r["months"]) + " search_text=" + repr(r["search_text"])) // EOF // // Output: // // full match: members=[('Tomáš Němeček (Tov)', 'auto')] months=['2026-04'] search_text='Tomas Nemecek clenske 04/2026 ' // sender fallback month: members=[('Tomáš Němeček (Tov)', 'auto')] months=['2026-04'] search_text='Tomas Nemecek ' // serial int date: members=[('Jana Nováková', 'auto')] months=['2021-01'] search_text='Jana Novakova ' // no match: members=[] months=[] search_text='neznamy ' // serial float date: members=[('Tomáš Němeček (Tov)', 'auto')] months=['2021-01'] search_text='Tomas Nemecek ' import ( "reflect" "testing" ) var inferMembers = []string{"Tomáš Němeček (Tov)", "Jana Nováková"} func TestInferTransactionDetails(t *testing.T) { t.Parallel() cases := []struct { name string tx Transaction defaultYear int wantMembers []Match wantMonths []string wantSearchText string }{ { name: "full match — members and months from search text", tx: Transaction{Sender: "Tomas Nemecek", Message: "clenske 04/2026", UserID: "", Date: "2026-04-15"}, defaultYear: 2026, wantMembers: []Match{{Name: "Tomáš Němeček (Tov)", Confidence: ConfidenceAuto}}, wantMonths: []string{"2026-04"}, // Python: sender + " " + message + " " + user_id (no trim) wantSearchText: "Tomas Nemecek clenske 04/2026 ", }, { // months not in message → fall back to date string name: "months fall back to date string", tx: Transaction{Sender: "Tomas Nemecek", Message: "", UserID: "", Date: "2026-04-15"}, defaultYear: 2026, wantMembers: []Match{{Name: "Tomáš Němeček (Tov)", Confidence: ConfidenceAuto}}, wantMonths: []string{"2026-04"}, wantSearchText: "Tomas Nemecek ", }, { // months fall back to Sheets serial int date name: "months fall back to serial int date", tx: Transaction{Sender: "Jana Novakova", Message: "", UserID: "", Date: int(44197)}, defaultYear: 2026, wantMembers: []Match{{Name: "Jana Nováková", Confidence: ConfidenceAuto}}, wantMonths: []string{"2021-01"}, wantSearchText: "Jana Novakova ", }, { // months fall back to Sheets serial float64 date name: "months fall back to serial float date", tx: Transaction{Sender: "Tomas Nemecek", Message: "", UserID: "", Date: float64(44197.5)}, defaultYear: 2026, wantMembers: []Match{{Name: "Tomáš Němeček (Tov)", Confidence: ConfidenceAuto}}, wantMonths: []string{"2021-01"}, wantSearchText: "Tomas Nemecek ", }, { name: "no match — both slices empty not nil", tx: Transaction{Sender: "neznamy", Message: "", UserID: "", Date: ""}, defaultYear: 2026, wantMembers: []Match{}, wantMonths: []string{}, wantSearchText: "neznamy ", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { t.Parallel() got := InferTransactionDetails(tc.tx, inferMembers, tc.defaultYear) if !reflect.DeepEqual(got.Members, tc.wantMembers) { t.Errorf("Members\n got %v\n want %v", got.Members, tc.wantMembers) } if !reflect.DeepEqual(got.Months, tc.wantMonths) { t.Errorf("Months\n got %v\n want %v", got.Months, tc.wantMonths) } if got.SearchText != tc.wantSearchText { t.Errorf("SearchText\n got %q\n want %q", got.SearchText, tc.wantSearchText) } }) } }