mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
169 lines
4.1 KiB
Go
169 lines
4.1 KiB
Go
package stripe
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/stripe/stripe-go/v83"
|
|
)
|
|
|
|
// Option configures a Client instance.
|
|
type Option func(*Client)
|
|
|
|
// WithAccount sets the Stripe connected account identifier used for requests.
|
|
func WithAccount(account string) Option {
|
|
return func(c *Client) {
|
|
c.account = strings.TrimSpace(account)
|
|
}
|
|
}
|
|
|
|
// Client wraps Stripe's SDK to expose the subset of functionality needed by the
|
|
// application while keeping the rest of the codebase decoupled from the SDK.
|
|
type Client struct {
|
|
api *stripe.Client
|
|
account string
|
|
}
|
|
|
|
// New constructs a Client using the provided secret key. The key must not be empty.
|
|
func New(secretKey string, opts ...Option) (*Client, error) {
|
|
trimmed := strings.TrimSpace(secretKey)
|
|
if trimmed == "" {
|
|
return nil, errors.New("stripe secret key is required")
|
|
}
|
|
|
|
api := stripe.NewClient(trimmed)
|
|
client := &Client{api: api}
|
|
for _, opt := range opts {
|
|
opt(client)
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
// Payment represents the subset of payment intent data consumed by the booking service.
|
|
type Payment struct {
|
|
ID string
|
|
Amount float64
|
|
Currency string
|
|
Status string
|
|
PaymentMethod string
|
|
BookingID *uint
|
|
Created time.Time
|
|
}
|
|
|
|
// NormalizePaymentIntent converts a Stripe payment intent into the simplified Payment structure used
|
|
// by the application. Fields that are absent default to their zero values.
|
|
func NormalizePaymentIntent(pi *stripe.PaymentIntent) Payment {
|
|
if pi == nil {
|
|
return Payment{}
|
|
}
|
|
|
|
amount := float64(pi.AmountReceived) / 100.0
|
|
if amount == 0 {
|
|
amount = float64(pi.Amount) / 100.0
|
|
}
|
|
|
|
return Payment{
|
|
ID: pi.ID,
|
|
Amount: amount,
|
|
Currency: strings.ToUpper(string(pi.Currency)),
|
|
Status: string(pi.Status),
|
|
PaymentMethod: deriveMethod(pi),
|
|
BookingID: extractBookingID(pi.Metadata),
|
|
Created: time.Unix(int64(pi.Created), 0),
|
|
}
|
|
}
|
|
|
|
// ListPaymentsParams defines the time boundaries used when fetching Stripe payments.
|
|
type ListPaymentsParams struct {
|
|
From time.Time
|
|
To time.Time
|
|
}
|
|
|
|
// ListPayments fetches payment intents created within the provided time range. The
|
|
// results are normalised into Payment structs suitable for downstream processing.
|
|
func (c *Client) ListPayments(ctx context.Context, params ListPaymentsParams) ([]Payment, error) {
|
|
listParams := &stripe.PaymentIntentListParams{}
|
|
listParams.Context = ctx
|
|
listParams.AddExpand("data.latest_charge")
|
|
listParams.AddExpand("data.payment_method")
|
|
|
|
if !params.From.IsZero() {
|
|
listParams.Filters.AddFilter("created", "gte", strconv.FormatInt(params.From.Unix(), 10))
|
|
}
|
|
if !params.To.IsZero() {
|
|
listParams.Filters.AddFilter("created", "lte", strconv.FormatInt(params.To.Unix(), 10))
|
|
}
|
|
|
|
if c.account != "" {
|
|
listParams.SetStripeAccount(c.account)
|
|
}
|
|
|
|
seq := c.api.V1PaymentIntents.List(ctx, listParams)
|
|
payments := make([]Payment, 0)
|
|
var listErr error
|
|
|
|
seq(func(pi *stripe.PaymentIntent, err error) bool {
|
|
if err != nil {
|
|
listErr = err
|
|
return false
|
|
}
|
|
if pi == nil {
|
|
return true
|
|
}
|
|
payments = append(payments, NormalizePaymentIntent(pi))
|
|
return true
|
|
})
|
|
|
|
if listErr != nil {
|
|
return nil, fmt.Errorf("stripe payment intents iteration failed: %w", listErr)
|
|
}
|
|
|
|
return payments, nil
|
|
}
|
|
|
|
func deriveMethod(pi *stripe.PaymentIntent) string {
|
|
if pi == nil {
|
|
return ""
|
|
}
|
|
|
|
if pi.LatestCharge != nil && pi.LatestCharge.PaymentMethodDetails != nil {
|
|
typ := pi.LatestCharge.PaymentMethodDetails.Type
|
|
if typ != "" {
|
|
return string(typ)
|
|
}
|
|
}
|
|
|
|
if pi.PaymentMethod != nil && pi.PaymentMethod.Type != "" {
|
|
return string(pi.PaymentMethod.Type)
|
|
}
|
|
|
|
if len(pi.PaymentMethodTypes) > 0 {
|
|
return pi.PaymentMethodTypes[0]
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func extractBookingID(metadata map[string]string) *uint {
|
|
if len(metadata) == 0 {
|
|
return nil
|
|
}
|
|
|
|
keys := []string{"booking_id", "bookingId", "bookingID"}
|
|
for _, key := range keys {
|
|
if raw, ok := metadata[key]; ok {
|
|
if raw == "" {
|
|
continue
|
|
}
|
|
if id, err := strconv.ParseUint(raw, 10, 32); err == nil {
|
|
value := uint(id)
|
|
return &value
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|