From 34918d770f6b5a8b30347231ebe88f78a3a12a02 Mon Sep 17 00:00:00 2001 From: H3ALY Date: Wed, 29 Oct 2025 10:00:58 +0000 Subject: [PATCH] Fix for tim.Time change to tickets model includes date helper. --- .../handlers/lottery/syndicate/syndicate.go | 14 ++++++-- .../lottery/tickets/ticket_handler.go | 34 +++++++++++++++---- internal/helpers/dates.go | 31 +++++++++++++++++ internal/services/tickets/ticketmatching.go | 6 +++- 4 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 internal/helpers/dates.go diff --git a/internal/handlers/lottery/syndicate/syndicate.go b/internal/handlers/lottery/syndicate/syndicate.go index e81f6f7..1589a6c 100644 --- a/internal/handlers/lottery/syndicate/syndicate.go +++ b/internal/handlers/lottery/syndicate/syndicate.go @@ -145,16 +145,24 @@ func SyndicateLogTicketHandler(app *bootstrap.App) http.HandlerFunc { case http.MethodPost: gameType := r.FormValue("game_type") - drawDate := r.FormValue("draw_date") + drawDateStr := r.FormValue("draw_date") method := r.FormValue("purchase_method") - err := ticketStorage.InsertTicket(app.DB, models.Ticket{ + dt, err := helpers.ParseDrawDate(drawDateStr) + if err != nil { + templateHelpers.SetFlash(r, "Invalid draw date") + http.Redirect(w, r, fmt.Sprintf("/syndicate/view?id=%d", syndicateId), http.StatusSeeOther) + return + } + + err = ticketStorage.InsertTicket(app.DB, models.Ticket{ UserId: userID, GameType: gameType, - DrawDate: drawDate, + DrawDate: dt, PurchaseMethod: method, SyndicateId: &syndicateId, }) + if err != nil { templateHelpers.SetFlash(r, "Failed to add ticket.") } else { diff --git a/internal/handlers/lottery/tickets/ticket_handler.go b/internal/handlers/lottery/tickets/ticket_handler.go index 6a30e92..29519ae 100644 --- a/internal/handlers/lottery/tickets/ticket_handler.go +++ b/internal/handlers/lottery/tickets/ticket_handler.go @@ -74,10 +74,18 @@ func AddTicket(app *bootstrap.App) http.HandlerFunc { } game := r.FormValue("game_type") - drawDate := r.FormValue("draw_date") + drawDateStr := r.FormValue("draw_date") purchaseMethod := r.FormValue("purchase_method") purchaseDate := r.FormValue("purchase_date") purchaseTime := r.FormValue("purchase_time") + + dt, err := helpers.ParseDrawDate(drawDateStr) + if err != nil { + http.Error(w, "Invalid draw date", http.StatusBadRequest) + return + } + drawDateDB := helpers.FormatDrawDate(dt) // "YYYY-MM-DD" + if purchaseTime != "" { purchaseDate += "T" + purchaseTime } @@ -165,7 +173,7 @@ func AddTicket(app *bootstrap.App) http.HandlerFunc { purchase_method, purchase_date, image_path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, - userID, game, drawDate, + userID, game, drawDateDB, b[0], b[1], b[2], b[3], b[4], b[5], bo[0], bo[1], purchaseMethod, purchaseDate, imagePath, @@ -195,10 +203,18 @@ func SubmitTicket(app *bootstrap.App) http.HandlerFunc { } game := r.FormValue("game_type") - drawDate := r.FormValue("draw_date") + drawDateStr := r.FormValue("draw_date") purchaseMethod := r.FormValue("purchase_method") purchaseDate := r.FormValue("purchase_date") purchaseTime := r.FormValue("purchase_time") + + dt, err := helpers.ParseDrawDate(drawDateStr) + if err != nil { + http.Error(w, "Invalid draw date", http.StatusBadRequest) + return + } + drawDateDB := helpers.FormatDrawDate(dt) + if purchaseTime != "" { purchaseDate += "T" + purchaseTime } @@ -253,7 +269,7 @@ func SubmitTicket(app *bootstrap.App) http.HandlerFunc { purchase_method, purchase_date, image_path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, - userID, game, drawDate, + userID, game, drawDateDB, b[0], b[1], b[2], b[3], b[4], b[5], bo[0], bo[1], purchaseMethod, purchaseDate, imagePath, @@ -299,6 +315,7 @@ func GetMyTickets(app *bootstrap.App) http.HandlerFunc { for rows.Next() { var t models.Ticket + var drawDateStr string // ← add var b1, b2, b3, b4, b5, b6, bo1, bo2 sql.NullInt64 var matchedMain, matchedBonus sql.NullInt64 var prizeTier sql.NullString @@ -307,7 +324,7 @@ func GetMyTickets(app *bootstrap.App) http.HandlerFunc { var prizeAmount sql.NullFloat64 if err := rows.Scan( - &t.Id, &t.GameType, &t.DrawDate, + &t.Id, &t.GameType, &drawDateStr, // ← was &t.DrawDate &b1, &b2, &b3, &b4, &b5, &b6, &bo1, &bo2, &t.PurchaseMethod, &t.PurchaseDate, &t.ImagePath, &t.Duplicate, @@ -317,6 +334,11 @@ func GetMyTickets(app *bootstrap.App) http.HandlerFunc { continue } + // Parse into time.Time (UTC) + if dt, err := helpers.ParseDrawDate(drawDateStr); err == nil { + t.DrawDate = dt + } + // Normalize fields t.Ball1 = int(b1.Int64) t.Ball2 = int(b2.Int64) @@ -351,7 +373,7 @@ func GetMyTickets(app *bootstrap.App) http.HandlerFunc { t.BonusBalls = helpers.BuildBonusSlice(t) // Fetch matching draw info - draw := draws.GetDrawResultForTicket(app.DB, t.GameType, t.DrawDate) + draw := draws.GetDrawResultForTicket(app.DB, t.GameType, helpers.FormatDrawDate(t.DrawDate)) t.MatchedDraw = draw tickets = append(tickets, t) diff --git a/internal/helpers/dates.go b/internal/helpers/dates.go new file mode 100644 index 0000000..ac1632f --- /dev/null +++ b/internal/helpers/dates.go @@ -0,0 +1,31 @@ +package helpers + +import ( + "fmt" + "time" +) + +var drawDateLayouts = []string{ + time.RFC3339, // 2006-01-02T15:04:05Z07:00 + "2006-01-02", // 2025-10-29 + "2006-01-02 15:04", // 2025-10-29 20:30 + "2006-01-02 15:04:05", // 2025-10-29 20:30:59 +} + +// ParseDrawDate tries multiple layouts and returns UTC. +func ParseDrawDate(s string) (time.Time, error) { + for _, l := range drawDateLayouts { + if t, err := time.ParseInLocation(l, s, time.Local); err == nil { + return t.UTC(), nil + } + } + return time.Time{}, fmt.Errorf("cannot parse draw date: %q", s) +} + +// FormatDrawDate normalizes a time to the storage format you use in SQL (date only). +func FormatDrawDate(t time.Time) string { + if t.IsZero() { + return "" + } + return t.UTC().Format("2006-01-02") +} diff --git a/internal/services/tickets/ticketmatching.go b/internal/services/tickets/ticketmatching.go index 61c2aaf..03dde8c 100644 --- a/internal/services/tickets/ticketmatching.go +++ b/internal/services/tickets/ticketmatching.go @@ -32,6 +32,10 @@ func RunTicketMatching(db *sql.DB, triggeredBy string) (models.MatchRunStats, er var pending []models.Ticket for rows.Next() { var t models.Ticket + var drawDateStr string + if dt, err := helpers.ParseDrawDate(drawDateStr); err == nil { + t.DrawDate = dt + } var b1, b2, b3, b4, b5, b6, bo1, bo2 sql.NullInt64 if err := rows.Scan( &t.Id, &t.GameType, &t.DrawDate, @@ -58,7 +62,7 @@ func RunTicketMatching(db *sql.DB, triggeredBy string) (models.MatchRunStats, er BonusBalls: helpers.BuildBonusSlice(t), } - draw := drawsSvc.GetDrawResultForTicket(db, t.GameType, t.DrawDate) + draw := drawsSvc.GetDrawResultForTicket(db, t.GameType, helpers.FormatDrawDate(t.DrawDate)) if draw.DrawID == 0 { // No draw yet → skip continue