mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-09 20:26:51 +00:00
Introduce Stripe integration for automatic payment ingestion and refund tracking. Adds new fields to the payment model for Stripe IDs and status, Stripe client driver, sync service, cron job, manual API endpoint, and public webhook handler for real-time updates. Includes tests and documentation. Manual cash entry remains supported.
135 lines
3.6 KiB
Go
135 lines
3.6 KiB
Go
package booking
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
u "github.com/rjNemo/underscore"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/rjNemo/rentease/internal/config"
|
|
)
|
|
|
|
type Booking struct {
|
|
From time.Time
|
|
To time.Time
|
|
gorm.Model
|
|
Name string `gorm:"column:customer_name"`
|
|
PhoneNumber string
|
|
Email string
|
|
Platform config.Platform
|
|
ExternalID *string `gorm:"uniqueIndex:booking_external_id"`
|
|
Items []Item
|
|
Payments []Payment `gorm:"foreignKey:BookingID"`
|
|
ID int
|
|
CustomerNumber int `gorm:"column:customers"`
|
|
PlatformFees float64 `gorm:"type:decimal(10,2)"`
|
|
Canceled bool `gorm:"default:false"`
|
|
}
|
|
|
|
// NewBooking creates a new booking with the given parameters
|
|
func NewBooking(from, to time.Time, name, phoneNumber, email, platform string,
|
|
customerNumber int, platformFees float64, externalID *string,
|
|
) *Booking {
|
|
return &Booking{
|
|
From: from,
|
|
To: to,
|
|
Name: name,
|
|
PhoneNumber: phoneNumber,
|
|
CustomerNumber: customerNumber,
|
|
Email: email,
|
|
Platform: config.Platform(platform),
|
|
PlatformFees: platformFees,
|
|
ExternalID: externalID,
|
|
}
|
|
}
|
|
|
|
func (b Booking) InvoiceNumber(hc *config.Host) string {
|
|
return fmt.Sprintf("%s%04s", hc.InvoicePrefix, strconv.Itoa(b.ID+hc.CustomerSeed))
|
|
}
|
|
|
|
func (b Booking) ToInvoice(hc *config.Host) Invoice {
|
|
total := u.Reduce(b.Items, func(i Item, sum float64) float64 {
|
|
return sum + i.Price*float64(i.Quantity)
|
|
}, 0.0)
|
|
amountPaid := u.Reduce(b.Payments, func(i Payment, sum float64) float64 {
|
|
return sum + i.Amount
|
|
}, 0.0)
|
|
|
|
return Invoice{
|
|
Host: *hc,
|
|
Name: b.Name,
|
|
PhoneNumber: b.PhoneNumber,
|
|
CustomersNumber: b.CustomerNumber,
|
|
Platform: b.Platform.ToFrench(),
|
|
ID: b.InvoiceNumber(hc),
|
|
From: b.From.Format("02/01/2006"),
|
|
To: b.To.Format("02/01/2006"),
|
|
Total: strconv.FormatFloat(total, 'f', 2, 64),
|
|
AmountPaid: strconv.FormatFloat(amountPaid, 'f', 2, 64),
|
|
BalanceDue: strconv.FormatFloat(total-amountPaid, 'f', 2, 64),
|
|
Lines: u.Map(b.Items, func(i Item) InvoiceLine {
|
|
return InvoiceLine{
|
|
Name: i.ToFrench(),
|
|
Quantity: i.Quantity,
|
|
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
|
Total: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
|
}
|
|
}),
|
|
Payments: u.Map(b.Payments, func(p Payment) PaymentLine {
|
|
return PaymentLine{
|
|
Date: p.CreatedAt.Format("02/01/2006"),
|
|
Method: p.PaymentMethod.ToFrench(),
|
|
Amount: strconv.FormatFloat(p.Amount, 'f', 2, 64),
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
|
|
// WithID returns a copy of the booking with the given ID
|
|
func (b *Booking) WithID(id int) *Booking {
|
|
b.ID = id
|
|
return b
|
|
}
|
|
|
|
type Item struct {
|
|
gorm.Model
|
|
Item string
|
|
PaymentMethod string
|
|
PaymentStatus string `gorm:"default:Pending"`
|
|
ID int
|
|
BookingID int
|
|
Quantity int
|
|
Price float64 `gorm:"type:decimal(10,2)"`
|
|
}
|
|
|
|
// ToFrench translates the item name to french
|
|
func (i Item) ToFrench() string {
|
|
switch i.Item {
|
|
case "T2":
|
|
return "T2"
|
|
case "T3":
|
|
return "T3"
|
|
case "Airport":
|
|
return "Transport Aéroport"
|
|
case "Port":
|
|
return "Transport Gare Maritime"
|
|
case "Transport":
|
|
return "Transport"
|
|
case "Taxes":
|
|
return "Taxes de sejour"
|
|
default:
|
|
return i.Item
|
|
}
|
|
}
|
|
|
|
type Payment struct {
|
|
gorm.Model
|
|
BookingID uint `gorm:"not null;index"`
|
|
Booking Booking `gorm:"foreignKey:BookingID;constraint:OnDelete:CASCADE"`
|
|
Amount float64
|
|
PaymentMethod config.PaymentMethod
|
|
StripePaymentID *string `gorm:"size:255;uniqueIndex"`
|
|
StripeStatus *string `gorm:"size:32"`
|
|
}
|