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 }