summaryrefslogtreecommitdiff
path: root/internal/billing/auto_topup.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/billing/auto_topup.go')
-rw-r--r--internal/billing/auto_topup.go56
1 files changed, 33 insertions, 23 deletions
diff --git a/internal/billing/auto_topup.go b/internal/billing/auto_topup.go
index a90405b..7fa4e59 100644
--- a/internal/billing/auto_topup.go
+++ b/internal/billing/auto_topup.go
@@ -160,6 +160,23 @@ func (s *Service) CreateAutoTopUpSetupSession(ctx context.Context, input AutoTop
if err != nil {
return AutoTopUpSetupResult{}, err
}
+ params := s.autoTopUpSetupSessionParams(input, customerID)
+ session, err := s.createStripeCheckout(ctx, params)
+ if err != nil {
+ return AutoTopUpSetupResult{}, fmt.Errorf("create automatic top-up setup session: %w", err)
+ }
+ if session == nil || session.ID == "" || session.URL == "" {
+ return AutoTopUpSetupResult{}, errors.New("Stripe returned an incomplete setup session")
+ }
+ if _, err := s.db.Exec(ctx, `INSERT INTO tenant_auto_topup_settings (tenant_id,threshold_micros,topup_amount_minor,stripe_setup_session_id)
+ VALUES ($1,$2,$3,$4) ON CONFLICT (tenant_id) DO UPDATE SET stripe_setup_session_id=EXCLUDED.stripe_setup_session_id,updated_at=now()`,
+ input.TenantID, s.defaultAutoTopUpThresholdMicros(), s.defaultAutoTopUpAmountMinor(), session.ID); err != nil {
+ return AutoTopUpSetupResult{}, fmt.Errorf("persist automatic top-up setup session: %w", err)
+ }
+ return AutoTopUpSetupResult{SessionID: session.ID, URL: session.URL}, nil
+}
+
+func (s *Service) autoTopUpSetupSessionParams(input AutoTopUpSetupInput, customerID string) *stripe.CheckoutSessionCreateParams {
params := &stripe.CheckoutSessionCreateParams{
Mode: stripe.String(string(stripe.CheckoutSessionModeSetup)),
Currency: stripe.String(s.currency),
@@ -181,19 +198,7 @@ func (s *Service) CreateAutoTopUpSetupSession(ctx context.Context, input AutoTop
}
}
params.SetIdempotencyKey("aigw_autotopup_setup_" + randomHex(16))
- session, err := s.createStripeCheckout(ctx, params)
- if err != nil {
- return AutoTopUpSetupResult{}, fmt.Errorf("create automatic top-up setup session: %w", err)
- }
- if session.ID == "" || session.URL == "" {
- return AutoTopUpSetupResult{}, errors.New("Stripe returned an incomplete setup session")
- }
- if _, err := s.db.Exec(ctx, `INSERT INTO tenant_auto_topup_settings (tenant_id,threshold_micros,topup_amount_minor,stripe_setup_session_id)
- VALUES ($1,$2,$3,$4) ON CONFLICT (tenant_id) DO UPDATE SET stripe_setup_session_id=EXCLUDED.stripe_setup_session_id,updated_at=now()`,
- input.TenantID, s.defaultAutoTopUpThresholdMicros(), s.defaultAutoTopUpAmountMinor(), session.ID); err != nil {
- return AutoTopUpSetupResult{}, fmt.Errorf("persist automatic top-up setup session: %w", err)
- }
- return AutoTopUpSetupResult{SessionID: session.ID, URL: session.URL}, nil
+ return params
}
func autoTopUpReturnURL(raw string, success bool) string {
@@ -344,16 +349,7 @@ func (s *Service) processAutoTopUpOnce(ctx context.Context) (bool, error) {
if err := tx.Commit(ctx); err != nil {
return false, err
}
- params := &stripe.PaymentIntentCreateParams{
- Amount: stripe.Int64(amountMinor), Currency: stripe.String(currency), Customer: stripe.String(customerID),
- PaymentMethod: stripe.String(paymentMethodID), Confirm: stripe.Bool(true), OffSession: stripe.Bool(true),
- ErrorOnRequiresAction: stripe.Bool(true), Description: stripe.String("AIGW automatic prepaid balance top-up"),
- Metadata: map[string]string{"aigw_action": "auto_topup", "aigw_tenant_id": tenantID, "aigw_topup_order_id": orderID},
- }
- if strings.TrimSpace(customerEmail) != "" {
- params.ReceiptEmail = stripe.String(strings.TrimSpace(customerEmail))
- }
- params.SetIdempotencyKey("aigw_autotopup_" + orderID)
+ params := s.autoTopUpPaymentIntentParams(tenantID, orderID, customerID, customerEmail, paymentMethodID, currency, amountMinor)
intent, callErr := s.createStripePaymentIntent(ctx, params)
if callErr != nil {
var stripeErr *stripe.Error
@@ -387,6 +383,20 @@ func (s *Service) processAutoTopUpOnce(ctx context.Context) (bool, error) {
return true, s.failAutoTopUp(ctx, tenantID, orderID, fmt.Errorf("automatic top-up PaymentIntent ended in status %s", intent.Status))
}
+func (s *Service) autoTopUpPaymentIntentParams(tenantID, orderID, customerID, customerEmail, paymentMethodID, currency string, amountMinor int64) *stripe.PaymentIntentCreateParams {
+ params := &stripe.PaymentIntentCreateParams{
+ Amount: stripe.Int64(amountMinor), Currency: stripe.String(currency), Customer: stripe.String(customerID),
+ PaymentMethod: stripe.String(paymentMethodID), Confirm: stripe.Bool(true), OffSession: stripe.Bool(true),
+ ErrorOnRequiresAction: stripe.Bool(true), Description: stripe.String("AIGW automatic prepaid balance top-up"),
+ Metadata: map[string]string{"aigw_action": "auto_topup", "aigw_tenant_id": tenantID, "aigw_topup_order_id": orderID},
+ }
+ if strings.TrimSpace(customerEmail) != "" {
+ params.ReceiptEmail = stripe.String(strings.TrimSpace(customerEmail))
+ }
+ params.SetIdempotencyKey("aigw_autotopup_" + orderID)
+ return params
+}
+
func (s *Service) scheduleAutoTopUpRetry(ctx context.Context, tenantID, orderID string, cause error) error {
message := truncateError(cause)
_, err := s.db.Exec(ctx, `UPDATE topup_orders SET reconciliation_error=$2 WHERE id=$1 AND status='pending'`, orderID, message)