package checkout import ( "encoding/json" "fmt" "strings" "time" messages "git.k6n.net/go-cart-actor/proto/checkout" ) // PaymentStarted registers the beginning of a payment attempt for a checkout. // It either upserts the payment entry (based on paymentId) or creates a new one, // marks the checkout as having a payment in progress. func HandlePaymentStarted(g *CheckoutGrain, m *messages.PaymentStarted) error { if m == nil { return fmt.Errorf("PaymentStarted: nil payload") } paymentID := strings.TrimSpace(m.PaymentId) if paymentID == "" { return fmt.Errorf("PaymentStarted: missing paymentId") } if m.Amount < 0 { return fmt.Errorf("PaymentStarted: amount cannot be negative") } currency := strings.TrimSpace(m.Currency) provider := strings.TrimSpace(m.Provider) method := copyOptionalString(m.Method) startedAt := time.Now().UTC() if m.StartedAt != nil { startedAt = m.StartedAt.AsTime() } payment, found := g.FindPayment(paymentID) if found { if payment.Status != "pending" { return fmt.Errorf("PaymentStarted: payment already started") } if payment.PaymentId != paymentID { payment.PaymentId = paymentID } payment.Status = "pending" payment.Amount = m.Amount if currency != "" { payment.Currency = currency } if provider != "" { payment.Provider = provider } if method != nil { payment.Method = method } if m.SessionData != nil { payment.SessionData = (*json.RawMessage)(&m.SessionData.Value) } payment.StartedAt = &startedAt payment.CompletedAt = nil payment.ProcessorReference = nil } else { g.PaymentInProgress++ g.Payments = append(g.Payments, &Payment{ PaymentId: paymentID, Status: "pending", Amount: m.Amount, SessionData: (*json.RawMessage)(&m.SessionData.Value), Currency: currency, Provider: provider, Method: method, StartedAt: &startedAt, }) } return nil } func copyOptionalString(src *string) *string { if src == nil { return nil } trimmed := strings.TrimSpace(*src) if trimmed == "" { return nil } dst := trimmed return &dst }