feat(go): add --print-fio-table debug flag to fuj sync #14
@@ -11,6 +11,7 @@ import (
|
||||
"fuj-management/go/internal/services/banksync"
|
||||
"fuj-management/go/internal/services/membership"
|
||||
"fuj-management/go/internal/web"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@@ -28,6 +29,9 @@ func main() {
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// Honour LOG_LEVEL for slog calls in any package (e.g. internal/io/fio debug logs).
|
||||
slog.SetDefault(logging.New(os.Getenv("LOG_LEVEL")))
|
||||
|
||||
cmd, args := os.Args[1], os.Args[2:]
|
||||
|
||||
switch cmd {
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,6 +27,9 @@ func (c *apiClient) FetchTransactions(ctx context.Context, from, to time.Time) (
|
||||
const layout = "2006-01-02"
|
||||
url := fmt.Sprintf("https://fioapi.fio.cz/v1/rest/periods/%s/%s/%s/transactions.json",
|
||||
c.token, from.Format(layout), to.Format(layout))
|
||||
slog.Debug("fio api: GET",
|
||||
"url", strings.Replace(url, c.token, "****", 1),
|
||||
"from", from.Format(layout), "to", to.Format(layout))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
@@ -35,6 +40,7 @@ func (c *apiClient) FetchTransactions(ctx context.Context, from, to time.Time) (
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
slog.Debug("fio api: response", "status", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("fio api: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
@@ -42,7 +48,9 @@ func (c *apiClient) FetchTransactions(ctx context.Context, from, to time.Time) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseAPIResponse(body)
|
||||
txns, err := parseAPIResponse(body)
|
||||
slog.Debug("fio api: parsed", "body_bytes", len(body), "parsed_count", len(txns))
|
||||
return txns, err
|
||||
}
|
||||
|
||||
// fioAPIResponse is the top-level envelope from the Fio JSON API.
|
||||
|
||||
@@ -4,6 +4,7 @@ package fio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -36,7 +37,9 @@ func New(token, accountNum string, hc httpDoer) Client {
|
||||
hc = http.DefaultClient
|
||||
}
|
||||
if token != "" {
|
||||
slog.Debug("fio: client selected", "type", "api")
|
||||
return &apiClient{token: token, hc: hc}
|
||||
}
|
||||
slog.Debug("fio: client selected", "type", "transparent", "account_num", accountNum)
|
||||
return &transparentClient{accountNum: accountNum, hc: hc}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -28,6 +29,10 @@ func (c *transparentClient) FetchTransactions(ctx context.Context, from, to time
|
||||
from.Format("2.1.2006"),
|
||||
to.Format("2.1.2006"),
|
||||
)
|
||||
slog.Debug("fio transparent: GET",
|
||||
"url", url,
|
||||
"from", from.Format("2006-01-02"), "to", to.Format("2006-01-02"))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -37,6 +42,7 @@ func (c *transparentClient) FetchTransactions(ctx context.Context, from, to time
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
slog.Debug("fio transparent: response", "status", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("fio transparent: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
@@ -44,6 +50,7 @@ func (c *transparentClient) FetchTransactions(ctx context.Context, from, to time
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
slog.Debug("fio transparent: body read", "body_bytes", len(body))
|
||||
return parseTransparentHTML(body)
|
||||
}
|
||||
|
||||
@@ -63,6 +70,7 @@ func parseTransparentHTML(body []byte) ([]Transaction, error) {
|
||||
rows := extractSecondTableRows(body)
|
||||
|
||||
var txns []Transaction
|
||||
var droppedBadDate, droppedNonpositive int
|
||||
for _, row := range rows {
|
||||
col := func(i int) string {
|
||||
if i < len(row) {
|
||||
@@ -72,7 +80,12 @@ func parseTransparentHTML(body []byte) ([]Transaction, error) {
|
||||
}
|
||||
dateStr := parseCzechDate(col(tColDate))
|
||||
amount := parseCzechAmount(col(tColAmount))
|
||||
if dateStr == "" || amount <= 0 {
|
||||
if dateStr == "" {
|
||||
droppedBadDate++
|
||||
continue
|
||||
}
|
||||
if amount <= 0 {
|
||||
droppedNonpositive++
|
||||
continue
|
||||
}
|
||||
txns = append(txns, Transaction{
|
||||
@@ -86,6 +99,11 @@ func parseTransparentHTML(body []byte) ([]Transaction, error) {
|
||||
BankID: "", // not available on HTML path
|
||||
})
|
||||
}
|
||||
slog.Debug("fio transparent: parsed",
|
||||
"raw_rows", len(rows),
|
||||
"kept", len(txns),
|
||||
"dropped_bad_date", droppedBadDate,
|
||||
"dropped_nonpositive_amount", droppedNonpositive)
|
||||
return txns, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +112,8 @@ func SyncToSheets(
|
||||
})
|
||||
}
|
||||
|
||||
// 4b. Optional debug table (dry-run only).
|
||||
if opts.DryRun && opts.PrintFioTable {
|
||||
// 4b. Optional debug table (dry-run only; suppress when nothing was fetched).
|
||||
if opts.DryRun && opts.PrintFioTable && len(txns) > 0 {
|
||||
printFioTable(os.Stdout, txns, syncIDs, existingIDs)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user