camper/pkg/booking/cart.go

210 lines
4.8 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
DownPayment string
DownPaymentPercent int
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
}
var ACSICard bool
if f.Guests.ACSICard != nil {
ACSICard = f.Guests.ACSICard.Checked
}
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,
})
}
row := conn.QueryRow(ctx, `
select payment.slug
, 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)
, to_price(payment.down_payment, decimal_digits)
, (payment.down_payment_percent * 100)::int
from draft_payment($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) as payment
join currency using (currency_code)
`,
database.ZeroNullUUID(f.PaymentSlug.Val),
arrivalDate,
departureDate,
campsiteType,
numAdults,
numTeenagers,
numChildren,
numDogs,
zonePreferences,
ACSICard,
database.OptionUnitsArray(optionUnits),
)
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
var downPayment string
if err = row.Scan(
&f.PaymentSlug.Val,
&paymentID,
&numNights,
&nights,
&adults,
&teenagers,
&children,
&dogs,
&touristTax,
&total,
&downPayment,
&cart.DownPaymentPercent,
); 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 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
if downPayment != total {
cart.DownPayment = downPayment
}
}
return cart, nil
}