Migrate all test files from resetTestData(t) to testutils.SetupTestDB(t) for isolated per-package test databases. - Add new feature tests: name history assertions, referral discount preview, time blockers, email validation, GDPR export, loyalty manual redemption - Update existing tests to use batch queries and SetupTestDB - Remove test_helpers.go resetTestData infrastructure - Add comprehensive user profile tests (442 new lines) Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
112 lines
3.7 KiB
Go
112 lines
3.7 KiB
Go
//go:build test && dev
|
|
// +build test,dev
|
|
|
|
package payments
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"crussell/db"
|
|
"crussell/testutils"
|
|
"crussell/testutils/fixtures"
|
|
)
|
|
|
|
func setupRefundTestWithDiscount(t *testing.T) (string, string, float64) {
|
|
t.Helper()
|
|
userID, err := fixtures.CreateTestUser(db.DB)
|
|
if err != nil {
|
|
t.Fatalf("failed to create user: %v", err)
|
|
}
|
|
serviceID, err := fixtures.CreateTestService(db.DB)
|
|
if err != nil {
|
|
t.Fatalf("failed to create service: %v", err)
|
|
}
|
|
bookingID, err := fixtures.CreateTestBookingAtTime(db.DB, userID, serviceID, time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC))
|
|
if err != nil {
|
|
t.Fatalf("failed to create booking: %v", err)
|
|
}
|
|
|
|
// Insert a real cash payment of 50
|
|
_, err = db.DB.Exec(context.Background(), `
|
|
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
|
|
VALUES ($1, 'full', 'cash', 5000, 'completed', NOW(), NOW())
|
|
`, bookingID)
|
|
if err != nil {
|
|
t.Fatalf("failed to create cash payment: %v", err)
|
|
}
|
|
|
|
// Insert a discount payment record (should be excluded from refund)
|
|
_, err = db.DB.Exec(context.Background(), `
|
|
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
|
|
VALUES ($1, 'partial', 'discount', 500, 'completed', NOW(), NOW())
|
|
`, bookingID)
|
|
if err != nil {
|
|
t.Fatalf("failed to create discount payment: %v", err)
|
|
}
|
|
|
|
// Insert an on_the_house payment record (should also be excluded)
|
|
_, err = db.DB.Exec(context.Background(), `
|
|
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
|
|
VALUES ($1, 'partial', 'on_the_house', 1000, 'completed', NOW(), NOW())
|
|
`, bookingID)
|
|
if err != nil {
|
|
t.Fatalf("failed to create on_the_house payment: %v", err)
|
|
}
|
|
|
|
return userID, bookingID, 50.0
|
|
}
|
|
|
|
func TestProcessCancellationRefund_ExcludesDiscountPayments(t *testing.T) {
|
|
testutils.SetupTestDB(t)
|
|
userID, bookingID, total := setupRefundTestWithDiscount(t)
|
|
|
|
farFuture := time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC)
|
|
now := farFuture.Add(-72 * time.Hour).Add(-1 * time.Hour) // >72h before
|
|
|
|
result, err := ProcessCancellationRefund(
|
|
context.Background(), bookingID, total, 50,
|
|
farFuture, now, "client_cancelled", &userID,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("ProcessCancellationRefund failed: %v", err)
|
|
}
|
|
|
|
// Refundable should be 50 (only the cash payment), not 65 (which would include discount + OTH)
|
|
if result.RefundableAmount != 50 {
|
|
t.Errorf("expected refundable 50 (excluding discount/OTH), got %.2f", result.RefundableAmount)
|
|
}
|
|
}
|
|
|
|
func TestProcessCancellationRefund_ExcludesOnTheHousePayments(t *testing.T) {
|
|
testutils.SetupTestDB(t)
|
|
userID, bookingID, total := setupRefundTestWithDiscount(t)
|
|
|
|
// Make on_the_house the only non-discount payment by marking the 50 cash as a payment that gets refunded
|
|
// but also add a pure on_the_house booking with no real money
|
|
_, err := db.DB.Exec(context.Background(), `
|
|
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
|
|
VALUES ($1, 'partial', 'discount', 2500, 'completed', NOW(), NOW())
|
|
`, bookingID)
|
|
if err != nil {
|
|
t.Fatalf("failed to create extra discount: %v", err)
|
|
}
|
|
|
|
farFuture := time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC)
|
|
now := farFuture.Add(-72 * time.Hour).Add(-1 * time.Hour)
|
|
|
|
result, err := ProcessCancellationRefund(
|
|
context.Background(), bookingID, total, 50,
|
|
farFuture, now, "client_cancelled", &userID,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("ProcessCancellationRefund failed: %v", err)
|
|
}
|
|
|
|
// Refundable should be based on the actual cash payment only
|
|
if result.RefundableAmount != 50 {
|
|
t.Errorf("expected refundable 50 (real money only), got %.2f", result.RefundableAmount)
|
|
}
|
|
}
|