Compare commits
2 Commits
fix/cache-
...
fix/go-dat
| Author | SHA1 | Date | |
|---|---|---|---|
| 723152cdad | |||
| e5a272b682 |
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-05-07 23:17 CEST — fix(go): pass raw value to FormatDate so numeric serial-day dates format
|
||||||
|
|
||||||
|
- `go/internal/services/membership/sources.go`: transaction-row parser now passes `row[idxDate]` directly to `matching.FormatDate` (via a new `getRaw` helper) instead of stringifying first via `getVal`. The Sheets API returns numeric serial-day values as `float64` for date-formatted cells; pre-stringifying them defeated `FormatDate`'s `case float64:` dispatch, causing all numeric dates to leak through as `"46147"` style strings instead of `"2026-05-05"`.
|
||||||
|
- Surfaced by `make parity` (M5.4): every `transactions[].date` field on `/api/adults` and `/api/juniors` differed between Python and Go.
|
||||||
|
- `sources_test.go::TestLoadTransactions` extended with a numeric-serial-day row covering the regression.
|
||||||
|
|
||||||
## 2026-05-07 23:05 CEST — fix(go): default CacheDir to `tmp/go` to avoid Python collision
|
## 2026-05-07 23:05 CEST — fix(go): default CacheDir to `tmp/go` to avoid Python collision
|
||||||
|
|
||||||
- `go/internal/config/config.go`: `CacheDir` default changed from `tmp` to `tmp/go`. Override via `CACHE_DIR` env var still works.
|
- `go/internal/config/config.go`: `CacheDir` default changed from `tmp` to `tmp/go`. Override via `CACHE_DIR` env var still works.
|
||||||
|
|||||||
@@ -394,9 +394,19 @@ func parseTransactionRows(rows [][]any) ([]reconcile.Transaction, error) {
|
|||||||
return fmt.Sprint(row[i])
|
return fmt.Sprint(row[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getRaw returns row[i] without stringifying — needed for FormatDate to
|
||||||
|
// dispatch on the underlying numeric type (Sheets returns serial-day
|
||||||
|
// numbers as float64). Stringifying first defeats that dispatch.
|
||||||
|
getRaw := func(row []any, i int) any {
|
||||||
|
if i < 0 || i >= len(row) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return row[i]
|
||||||
|
}
|
||||||
|
|
||||||
var txns []reconcile.Transaction
|
var txns []reconcile.Transaction
|
||||||
for _, row := range rows[1:] {
|
for _, row := range rows[1:] {
|
||||||
dateStr := matching.FormatDate(getVal(row, idxDate))
|
dateStr := matching.FormatDate(getRaw(row, idxDate))
|
||||||
amountRaw := row[idxAmount]
|
amountRaw := row[idxAmount]
|
||||||
if idxAmount < 0 || idxAmount >= len(row) {
|
if idxAmount < 0 || idxAmount >= len(row) {
|
||||||
amountRaw = ""
|
amountRaw = ""
|
||||||
|
|||||||
@@ -114,12 +114,15 @@ func TestLoadJuniors(t *testing.T) {
|
|||||||
|
|
||||||
func TestLoadTransactions(t *testing.T) {
|
func TestLoadTransactions(t *testing.T) {
|
||||||
// Sheets fake keyed by "<spreadsheetID>/<range>" — use the real constant.
|
// Sheets fake keyed by "<spreadsheetID>/<range>" — use the real constant.
|
||||||
|
// Row 1 uses a pre-formatted date string; row 2 uses the numeric Sheets
|
||||||
|
// serial-day form (float64) — the API returns either depending on cell
|
||||||
|
// formatting, and FormatDate must handle both.
|
||||||
paymentsKey := config.PaymentsSheetID + "/A1:Z"
|
paymentsKey := config.PaymentsSheetID + "/A1:Z"
|
||||||
sh := &sheets.Fake{Values: map[string][][]any{
|
sh := &sheets.Fake{Values: map[string][][]any{
|
||||||
paymentsKey: {
|
paymentsKey: {
|
||||||
{"Date", "Amount", "manual fix", "Person", "Purpose", "Inferred Amount", "Sender", "VS", "Message", "Bank ID", "Sync ID"},
|
{"Date", "Amount", "manual fix", "Person", "Purpose", "Inferred Amount", "Sender", "VS", "Message", "Bank ID", "Sync ID"},
|
||||||
{"2026-04-01", 700.0, "", "Alice", "2026-04", "", "Alice Bank", "", "fee", "", "abc"},
|
{"2026-04-01", 700.0, "", "Alice", "2026-04", "", "Alice Bank", "", "fee", "", "abc"},
|
||||||
{"2026-05-01", 500.0, "", "", "", "", "Bob Bank", "", "platba", "", "def"},
|
{46147.0, 500.0, "", "", "", "", "Bob Bank", "", "platba", "", "def"}, // 46147 serial-day = 2026-05-05
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
s := buildSources(t, &attendance.Fake{}, sh)
|
s := buildSources(t, &attendance.Fake{}, sh)
|
||||||
@@ -137,6 +140,12 @@ func TestLoadTransactions(t *testing.T) {
|
|||||||
if txns[0].Amount != 700 {
|
if txns[0].Amount != 700 {
|
||||||
t.Errorf("txn[0].Amount: want 700, got %v", txns[0].Amount)
|
t.Errorf("txn[0].Amount: want 700, got %v", txns[0].Amount)
|
||||||
}
|
}
|
||||||
|
if txns[0].Date != "2026-04-01" {
|
||||||
|
t.Errorf("txn[0].Date: want 2026-04-01, got %q", txns[0].Date)
|
||||||
|
}
|
||||||
|
if txns[1].Date != "2026-05-05" {
|
||||||
|
t.Errorf("txn[1].Date (numeric serial-day): want 2026-05-05, got %q", txns[1].Date)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadExceptions(t *testing.T) {
|
func TestLoadExceptions(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user