Port scripts/infer_payments.py parse_czk_amount to Go as internal/domain/money.ParseCZK. Preserves the Czech-locale heuristic (comma = decimal sep; 2+ dots = thousand seps; single dot = decimal) and returns (float64, error) so callers can opt into Python's silent-zero contract via v, _ := money.ParseCZK(s). All expected values verified against live Python on 2026-05-06. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
// Package money ports Czech-locale currency parsing from scripts/infer_payments.py.
|
|
package money
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// ErrInvalidAmount is returned by ParseCZK when the input cannot be parsed.
|
|
var ErrInvalidAmount = errors.New("money: invalid CZK amount")
|
|
|
|
// ParseCZK parses a Czech-locale amount string and returns the value in CZK
|
|
// as a float64. Mirrors scripts/infer_payments.py parse_czk_amount:
|
|
//
|
|
// - empty input → (0, nil)
|
|
// - "Kč"/"CZK" suffixes stripped (case-sensitive, like Python)
|
|
// - comma present → comma is decimal sep, dots/spaces are thousand seps
|
|
// ("1.500,00" → 1500.0)
|
|
// - no comma, 2+ dots → all dots are thousand seps ("1.500.000" → 1500000.0)
|
|
// - no comma, ≤1 dot → dot is decimal sep ("1.500" → 1.5)
|
|
// - on parse failure → (0, ErrInvalidAmount); callers wanting Python's
|
|
// silent-zero behaviour can discard the error: v, _ := ParseCZK(s)
|
|
func ParseCZK(s string) (float64, error) {
|
|
if s == "" {
|
|
return 0, nil
|
|
}
|
|
|
|
s = strings.ReplaceAll(s, "Kč", "")
|
|
s = strings.ReplaceAll(s, "CZK", "")
|
|
s = strings.TrimSpace(s)
|
|
|
|
if strings.ContainsRune(s, ',') {
|
|
s = strings.ReplaceAll(s, ".", "")
|
|
s = strings.ReplaceAll(s, " ", "")
|
|
s = strings.ReplaceAll(s, ",", ".")
|
|
} else if strings.Count(s, ".") > 1 {
|
|
s = strings.ReplaceAll(s, ".", "")
|
|
s = strings.ReplaceAll(s, " ", "")
|
|
} else {
|
|
s = strings.ReplaceAll(s, " ", "")
|
|
}
|
|
|
|
v, err := strconv.ParseFloat(s, 64)
|
|
if err != nil {
|
|
return 0, ErrInvalidAmount
|
|
}
|
|
return v, nil
|
|
}
|