camper/pkg/booking/cart.go

192 lines
4.5 KiB
Go

package booking
import (
"context"
"strconv"
"time"
"dev.tandem.ws/tandem/camper/pkg/database"
"dev.tandem.ws/tandem/camper/pkg/locale"
)
type bookingCart struct {
Lines []*cartLine
Total string
Enabled bool
}
type cartLine struct {
Concept string
Units int
Subtotal string
}
func newBookingCart(ctx context.Context, conn *database.Conn, f *bookingForm, campsiteType string) (*bookingCart, error) {
cart := &bookingCart{
Total: "0.0",
}
if f.Dates == nil {
return cart, nil
}
arrivalDate, err := time.Parse(database.ISODateFormat, f.Dates.ArrivalDate.Val)
if err != nil {
return cart, nil
}
departureDate, err := time.Parse(database.ISODateFormat, f.Dates.DepartureDate.Val)
if err != nil {
return cart, nil
}
if f.Guests == nil {
return cart, nil
}
numAdults, err := strconv.Atoi(f.Guests.NumberAdults.Val)
if err != nil {
return cart, nil
}
numTeenagers, err := strconv.Atoi(f.Guests.NumberTeenagers.Val)
if err != nil {
return cart, nil
}
numChildren, err := strconv.Atoi(f.Guests.NumberChildren.Val)
if err != nil {
return cart, nil
}
numDogs := 0
if f.Guests.NumberDogs != nil {
numDogs, err = strconv.Atoi(f.Guests.NumberDogs.Val)
if err != nil {
return cart, nil
}
}
zonePreferences := ""
if f.Options != nil && f.Options.ZonePreferences != nil {
zonePreferences = f.Options.ZonePreferences.Val
}
optionMap := make(map[int]*campsiteTypeOption)
var typeOptions []*campsiteTypeOption
if f.Options != nil {
typeOptions = f.Options.Options
}
optionUnits := make([]*database.OptionUnits, 0, len(typeOptions))
for _, option := range typeOptions {
units, _ := strconv.Atoi(option.Input.Val)
if units < 1 {
continue
}
optionMap[option.ID] = option
optionUnits = append(optionUnits, &database.OptionUnits{
OptionID: option.ID,
Units: units,
})
}
paymentSlug, err := conn.DraftPayment(
ctx,
f.PaymentSlug.Val,
arrivalDate,
departureDate,
campsiteType,
numAdults,
numTeenagers,
numChildren,
numDogs,
zonePreferences,
optionUnits,
)
if err != nil {
return nil, err
}
f.PaymentSlug.Val = paymentSlug
row := conn.QueryRow(ctx, `
select payment_id
, departure_date - arrival_date
, to_price(subtotal_nights, decimal_digits)
, to_price(subtotal_adults, decimal_digits)
, to_price(subtotal_teenagers, decimal_digits)
, to_price(subtotal_children, decimal_digits)
, to_price(subtotal_dogs, decimal_digits)
, to_price(subtotal_tourist_tax, decimal_digits)
, to_price(total, decimal_digits)
from payment
join company using (company_id)
join currency using (currency_code)
where payment.slug = $1
`, paymentSlug)
var paymentID int
var numNights int
var nights string
var adults string
var teenagers string
var children string
var dogs string
var touristTax string
var total string
if err = row.Scan(&paymentID, &numNights, &nights, &adults, &teenagers, &children, &dogs, &touristTax, &total); err != nil {
if database.ErrorIsNotFound(err) {
return cart, nil
}
return nil, err
}
maybeAddLine := func(units int, subtotal string, concept string) {
if units > 0 && subtotal != "" {
cart.Lines = append(cart.Lines, &cartLine{
Concept: concept,
Units: units,
Subtotal: subtotal,
})
}
}
maybeAddLine(numNights, nights, locale.PgettextNoop("Night", "cart"))
maybeAddLine(numAdults, adults, locale.PgettextNoop("Adult", "cart"))
maybeAddLine(numTeenagers, teenagers, locale.PgettextNoop("Teenager", "cart"))
maybeAddLine(numChildren, children, locale.PgettextNoop("Child", "cart"))
maybeAddLine(numDogs, dogs, locale.PgettextNoop("Dog", "cart"))
rows, err := conn.Query(ctx, `
select campsite_type_option_id
, units
, to_price(subtotal, decimal_digits)
from payment_option
join payment using (payment_id)
join company using (company_id)
join currency using (currency_code)
where payment_id = $1
`, paymentID)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var optionID int
var units int
var subtotal string
err = rows.Scan(&optionID, &units, &subtotal)
if err != nil {
return nil, err
}
option := optionMap[optionID]
if option == nil {
continue
}
maybeAddLine(units, subtotal, option.Label)
}
if rows.Err() != nil {
return nil, rows.Err()
}
maybeAddLine(numAdults, touristTax, locale.PgettextNoop("Tourist tax", "cart"))
if total != "0.0" {
cart.Total = total
cart.Enabled = f.Guests.Error == nil
}
return cart, nil
}