Payouts CSV: amounts in major units

Go · Go · beginner · modification

Accountants kept asking why the statement shows `123400` for a 1,234.00 payout, so the amount column is now in major units, the way a spreadsheet import expects it. The conversion is plain integer arithmetic on the minor-unit amount, with no `float64` round trip, so large payouts keep every digit. Checked against last month's statement for a few accounts: amounts match the dashboard.

Go 1.22 payouts service, standard library only. `Payout` (existing, `types.go`) has `PaidAt time.Time`, `Currency string` (an ISO 4217 code), `AmountMinor int64` and `Reference string`. Payouts go out in USD, EUR, GBP, JPY, KRW, KWD and BHD; `AmountMinor` is always positive (refunds are a separate statement) and below 10^15. `money.MinorUnits(code string) int` (existing, package `example.com/payouts/internal/money`) returns the ISO 4217 minor-unit digits of every supported currency: 2 for most, 0 for JPY and KRW, 3 for KWD and BHD. References are generated by us (`po_` + 24 letters and digits). The existing handler calls `WritePayoutsCSV` with the account's payouts, already sorted.

Requirements

Files touched

--- internal/export/payouts.go
 import (
 	"encoding/csv"
+	"fmt"
 	"io"
-	"strconv"
 	"time"
 )
 func WritePayoutsCSV(w io.Writer, payouts []Payout) error {
 	cw := csv.NewWriter(w)
-	if err := cw.Write([]string{"paid_at", "currency", "amount_minor", "reference"}); err != nil {
+	if err := cw.Write([]string{"paid_at", "currency", "amount", "reference"}); err != nil {
 		return err
 	}
 			p.PaidAt.UTC().Format(time.DateOnly),
 			p.Currency,
-			strconv.FormatInt(p.AmountMinor, 10),
+			formatMajor(p.AmountMinor),
 			p.Reference,
 		}
 }
 
+// formatMajor renders an amount held in minor units as a plain decimal in
+// major units, the way spreadsheet imports expect it.
+func formatMajor(minor int64) string {
+	return fmt.Sprintf("%d.%02d", minor/100, minor%100)
+}
+

Review this PR

Go practice