diff --git a/backend/internal/square/square.go b/backend/internal/square/square.go index cab4266..4047447 100644 --- a/backend/internal/square/square.go +++ b/backend/internal/square/square.go @@ -40,6 +40,10 @@ func (p *ProdClient) CreateCardOnFile(ctx context.Context, userID, cardToken str return nil, errors.New("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") } +func (p *ProdClient) CreateCardOnFileRaw(ctx context.Context, userID, cardNumber string, expMonth, expYear int, cvc string) (*CardOnFile, error) { + return nil, errors.New("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") +} + func (p *ProdClient) GetCardsOnFile(ctx context.Context, userID string) ([]CardOnFile, error) { return nil, errors.New("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") } diff --git a/backend/internal/square/square_dev.go b/backend/internal/square/square_dev.go index cbce45e..53825fa 100644 --- a/backend/internal/square/square_dev.go +++ b/backend/internal/square/square_dev.go @@ -40,6 +40,9 @@ func (d *devProdClient) RefundPayment(ctx context.Context, req RefundPaymentReq) func (d *devProdClient) CreateCardOnFile(ctx context.Context, userID, cardToken string) (*CardOnFile, error) { return nil, fmt.Errorf("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") } +func (d *devProdClient) CreateCardOnFileRaw(ctx context.Context, userID, cardNumber string, expMonth, expYear int, cvc string) (*CardOnFile, error) { + return nil, fmt.Errorf("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") +} func (d *devProdClient) GetCardsOnFile(ctx context.Context, userID string) ([]CardOnFile, error) { return nil, fmt.Errorf("square payments not yet configured — set SQUARE_ACCESS_TOKEN and SQUARE_LOCATION_ID in .env") } @@ -217,6 +220,39 @@ func (m *MockClient) CreateCardOnFile(ctx context.Context, userID, cardToken str return card, nil } +func (m *MockClient) CreateCardOnFileRaw(ctx context.Context, userID, cardNumber string, expMonth, expYear int, cvc string) (*CardOnFile, error) { + log.Printf("[SQUARE-MOCK] CreateCardOnFileRaw: user=%s", userID) + + m.mu.Lock() + defer m.mu.Unlock() + + if m.cards[userID] == nil { + m.cards[userID] = make(map[string]*CardOnFile) + } + + cardID := fmt.Sprintf("mock_card_%d", time.Now().UnixNano()) + last4 := cardNumber[len(cardNumber)-4:] + brands := map[string]string{"4": "VISA", "5": "MASTERCARD", "3": "AMEX", "6": "DISCOVER"} + brand := brands[string(cardNumber[0])] + if brand == "" { + brand = "VISA" + } + + card := &CardOnFile{ + ID: cardID, + CardID: "cfa_" + cardID, + Brand: brand, + Last4: last4, + ExpMonth: expMonth, + ExpYear: expYear, + Fingerprint: fmt.Sprintf("fp_%d", time.Now().UnixNano()), + IsDefault: len(m.cards[userID]) == 0, + } + m.cards[userID][cardID] = card + log.Printf("[SQUARE-MOCK] Card created: id=%s, brand=%s, last4=%s", cardID, card.Brand, card.Last4) + return card, nil +} + func (m *MockClient) GetCardsOnFile(ctx context.Context, userID string) ([]CardOnFile, error) { log.Printf("[SQUARE-MOCK] GetCardsOnFile: user=%s", userID) diff --git a/backend/internal/square/types.go b/backend/internal/square/types.go index b96765c..61afad1 100644 --- a/backend/internal/square/types.go +++ b/backend/internal/square/types.go @@ -66,6 +66,7 @@ type SquareClient interface { GetCheckout(ctx context.Context, checkoutID string) (*PaymentResult, error) RefundPayment(ctx context.Context, req RefundPaymentReq) (*RefundResult, error) CreateCardOnFile(ctx context.Context, userID, cardToken string) (*CardOnFile, error) + CreateCardOnFileRaw(ctx context.Context, userID, cardNumber string, expMonth, expYear int, cvc string) (*CardOnFile, error) GetCardsOnFile(ctx context.Context, userID string) ([]CardOnFile, error) DeleteCardOnFile(ctx context.Context, cardID string) error } \ No newline at end of file diff --git a/backend/main.go b/backend/main.go index 35ade58..15e6020 100644 --- a/backend/main.go +++ b/backend/main.go @@ -230,8 +230,9 @@ func main() { // User payment routes r.Post("/bookings/{id}/payment", payments.CreateBookingPayment) - r.Get("/user/payment-methods", payments.GetUserPaymentMethods) - r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod) + r.Get("/user/payment-methods", payments.GetUserPaymentMethods) + r.Post("/user/payment-methods", payments.CreatePaymentMethod) + r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod) r.Post("/bookings/{id}/tip", payments.CreateTipPayment) r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary) })