feat(payments): add gift card system v2 with management, expiry, inventory, audit log
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -51,6 +51,7 @@ type PaymentRecord struct {
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
CreatedBy *string
|
||||
GiftCardID *string
|
||||
}
|
||||
|
||||
type RefundRecord struct {
|
||||
@@ -81,7 +82,7 @@ func (s *PaymentService) CalculateFees(amount int64, method string) float64 {
|
||||
return float64(amount * 175 / 10000) / 100.0
|
||||
}
|
||||
|
||||
func (s *PaymentService) CreatePaymentRecord(ctx context.Context, record PaymentRecord) (string, error) {
|
||||
func (s *PaymentService) CreatePaymentRecord(ctx context.Context, record PaymentRecord, giftCardID *string) (string, error) {
|
||||
var bookingID *string
|
||||
if record.BookingID != "" {
|
||||
bookingID = &record.BookingID
|
||||
@@ -92,8 +93,9 @@ func (s *PaymentService) CreatePaymentRecord(ctx context.Context, record Payment
|
||||
INSERT INTO payments (
|
||||
booking_id, payment_type, payment_method, vendor_code, invoice_number,
|
||||
status, amount, is_vat_applicable, vat_rate, vat_amount, net_amount,
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by,
|
||||
gift_card_id
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)
|
||||
RETURNING id
|
||||
`,
|
||||
bookingID,
|
||||
@@ -114,6 +116,7 @@ func (s *PaymentService) CreatePaymentRecord(ctx context.Context, record Payment
|
||||
record.CreatedAt,
|
||||
record.UpdatedAt,
|
||||
record.CreatedBy,
|
||||
giftCardID,
|
||||
).Scan(&id)
|
||||
|
||||
if err != nil {
|
||||
@@ -170,7 +173,8 @@ func (s *PaymentService) GetBookingPaymentSummary(ctx context.Context, bookingID
|
||||
rows, err := db.DB.Query(ctx, `
|
||||
SELECT p.id, p.booking_id, p.payment_type, p.payment_method, p.vendor_code, p.invoice_number,
|
||||
p.status, p.amount, COALESCE(usc.last_4, ''), p.is_vat_applicable, p.vat_rate, p.vat_amount, p.net_amount,
|
||||
p.user_saved_card_id, p.square_payment_id, p.idempotency_key, p.fees, p.created_at, p.updated_at, p.created_by
|
||||
p.user_saved_card_id, p.square_payment_id, p.idempotency_key, p.fees, p.created_at, p.updated_at, p.created_by,
|
||||
p.gift_card_id
|
||||
FROM payments p
|
||||
LEFT JOIN user_saved_cards usc ON p.user_saved_card_id = usc.id
|
||||
WHERE p.booking_id = $1
|
||||
@@ -189,7 +193,7 @@ func (s *PaymentService) GetBookingPaymentSummary(ctx context.Context, bookingID
|
||||
&p.ID, &p.BookingID, &p.PaymentType, &p.PaymentMethod, &p.VendorCode, &p.InvoiceNumber,
|
||||
&p.Status, &p.Amount, &p.CardLast4, &p.IsVATApplicable, &p.VATRate, &p.VATAmount, &p.NetAmount,
|
||||
&p.UserSavedCardID, &p.SquarePaymentID, &p.IdempotencyKey, &p.Fees,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy, &p.GiftCardID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -237,14 +241,40 @@ func (s *PaymentService) CheckIdempotency(ctx context.Context, bookingID, idempo
|
||||
err := db.DB.QueryRow(ctx, `
|
||||
SELECT id, booking_id, payment_type, payment_method, vendor_code, invoice_number,
|
||||
status, amount, is_vat_applicable, vat_rate, vat_amount, net_amount,
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by,
|
||||
gift_card_id
|
||||
FROM payments
|
||||
WHERE booking_id = $1 AND idempotency_key = $2
|
||||
`, bookingID, idempotencyKey).Scan(
|
||||
&p.ID, &p.BookingID, &p.PaymentType, &p.PaymentMethod, &p.VendorCode, &p.InvoiceNumber,
|
||||
&p.Status, &p.Amount, &p.IsVATApplicable, &p.VATRate, &p.VATAmount, &p.NetAmount,
|
||||
&p.UserSavedCardID, &p.SquarePaymentID, &p.IdempotencyKey, &p.Fees,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy, &p.GiftCardID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (s *PaymentService) CheckIdempotencyByKey(ctx context.Context, idempotencyKey string) (*PaymentRecord, error) {
|
||||
var p PaymentRecord
|
||||
err := db.DB.QueryRow(ctx, `
|
||||
SELECT id, booking_id, payment_type, payment_method, vendor_code, invoice_number,
|
||||
status, amount, is_vat_applicable, vat_rate, vat_amount, net_amount,
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by,
|
||||
gift_card_id
|
||||
FROM payments
|
||||
WHERE idempotency_key = $1
|
||||
`, idempotencyKey).Scan(
|
||||
&p.ID, &p.BookingID, &p.PaymentType, &p.PaymentMethod, &p.VendorCode, &p.InvoiceNumber,
|
||||
&p.Status, &p.Amount, &p.IsVATApplicable, &p.VATRate, &p.VATAmount, &p.NetAmount,
|
||||
&p.UserSavedCardID, &p.SquarePaymentID, &p.IdempotencyKey, &p.Fees,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy, &p.GiftCardID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -261,14 +291,15 @@ func (s *PaymentService) GetPaymentByID(ctx context.Context, paymentID string) (
|
||||
err := db.DB.QueryRow(ctx, `
|
||||
SELECT id, booking_id, payment_type, payment_method, vendor_code, invoice_number,
|
||||
status, amount, is_vat_applicable, vat_rate, vat_amount, net_amount,
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by
|
||||
user_saved_card_id, square_payment_id, idempotency_key, fees, created_at, updated_at, created_by,
|
||||
gift_card_id
|
||||
FROM payments
|
||||
WHERE id = $1
|
||||
`, paymentID).Scan(
|
||||
&p.ID, &p.BookingID, &p.PaymentType, &p.PaymentMethod, &p.VendorCode, &p.InvoiceNumber,
|
||||
&p.Status, &p.Amount, &p.IsVATApplicable, &p.VATRate, &p.VATAmount, &p.NetAmount,
|
||||
&p.UserSavedCardID, &p.SquarePaymentID, &p.IdempotencyKey, &p.Fees,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy,
|
||||
&p.CreatedAt, &p.UpdatedAt, &p.CreatedBy, &p.GiftCardID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user