package booking import ( "context" "errors" "fmt" "math" "strings" stripeclient "github.com/rjNemo/rentease/internal/driver/stripe" ) // ErrBookingNotFound indicates that a booking could not be retrieved from the datastore. var ErrBookingNotFound = errors.New("booking not found") // ErrNoOutstandingBalance indicates that the booking has already been fully paid. var ErrNoOutstandingBalance = errors.New("booking has no outstanding balance") // CreateStripePaymentLink generates a Stripe payment link for the outstanding balance of a booking. func (bs Service) CreateStripePaymentLink(ctx context.Context, bookingID int) (string, error) { if bs.stripe == nil { return "", ErrStripeClientNotConfigured } b := bs.store.Get(bookingID) if b == nil || b.ID == 0 { return "", ErrBookingNotFound } outstanding := calculateOutstandingBalance(b) if outstanding <= 0 { return "", ErrNoOutstandingBalance } description := fmt.Sprintf("Payment for booking %d", b.ID) if name := strings.TrimSpace(b.Name); name != "" { description = fmt.Sprintf("Payment for %s", name) } url, err := bs.stripe.CreatePaymentLink(ctx, stripeclient.CreatePaymentLinkParams{ Amount: outstanding, Currency: "eur", BookingID: uint(b.ID), Description: description, PaymentMethodTypes: []string{"card", "sepa_debit"}, }) if err != nil { return "", err } return url, nil } func calculateOutstandingBalance(b *Booking) float64 { if b == nil { return 0 } var total float64 for _, item := range b.Items { total += item.Price * float64(item.Quantity) } var paid float64 for _, payment := range b.Payments { paid += payment.Amount } outstanding := total - paid outstanding = math.Round(outstanding*100) / 100 if outstanding < 0 { return 0 } return outstanding }