diff --git a/demo/demo.sql b/demo/demo.sql index a401164..d8ccf4f 100644 --- a/demo/demo.sql +++ b/demo/demo.sql @@ -1208,50 +1208,48 @@ values (92, 'en', 'Peak season') , (94, 'es', 'Temporada baja') ; -select set_season_range(92, '[2023-04-06, 2023-04-10]'); -select set_season_range(94, '[2023-04-11, 2023-04-27]'); -select set_season_range(93, '[2023-04-28, 2023-04-30]'); -select set_season_range(94, '[2023-05-01, 2023-06-01]'); -select set_season_range(93, '[2023-06-02, 2023-06-03]'); -select set_season_range(94, '[2023-06-04, 2023-06-08]'); -select set_season_range(93, '[2023-06-09, 2023-06-10]'); -select set_season_range(94, '[2023-06-11, 2023-06-15]'); -select set_season_range(93, '[2023-06-16, 2023-06-22]'); -select set_season_range(92, '[2023-06-23, 2023-06-25]'); -select set_season_range(93, '[2023-06-26, 2023-06-30]'); -select set_season_range(92, '[2023-07-01, 2023-08-27]'); -select set_season_range(93, '[2023-08-28, 2023-09-02]'); -select set_season_range(94, '[2023-09-03, 2023-09-07]'); -select set_season_range(93, '[2023-09-08, 2023-09-10]'); -select set_season_range(94, '[2023-09-11, 2023-09-14]'); -select set_season_range(93, '[2023-09-15, 2023-09-16]'); -select set_season_range(94, '[2023-09-17, 2023-09-21]'); -select set_season_range(93, '[2023-09-22, 2023-09-23]'); -select set_season_range(94, '[2023-09-24, 2023-09-28]'); -select set_season_range(93, '[2023-09-29, 2023-09-30]'); -select set_season_range(94, '[2023-10-01, 2023-10-12]'); +select set_season_range(92, daterange(make_date(extract(year from current_date)::int, 4, 6), make_date(extract(year from current_date)::int, 4, 11))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 4, 11), make_date(extract(year from current_date)::int, 4, 28))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 4, 28), make_date(extract(year from current_date)::int, 5, 1))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 5, 1), make_date(extract(year from current_date)::int, 6, 2))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 6, 2), make_date(extract(year from current_date)::int, 6, 4))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 6, 4), make_date(extract(year from current_date)::int, 6, 9))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 6, 9), make_date(extract(year from current_date)::int, 6, 11))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 6, 11), make_date(extract(year from current_date)::int, 6, 16))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 6, 16), make_date(extract(year from current_date)::int, 6, 23))); +select set_season_range(92, daterange(make_date(extract(year from current_date)::int, 6, 23), make_date(extract(year from current_date)::int, 6, 26))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 6, 26), make_date(extract(year from current_date)::int, 7, 1))); +select set_season_range(92, daterange(make_date(extract(year from current_date)::int, 7, 1), make_date(extract(year from current_date)::int, 8, 28))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 8, 28), make_date(extract(year from current_date)::int, 9, 3))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 9, 3), make_date(extract(year from current_date)::int, 9, 8))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 9, 8), make_date(extract(year from current_date)::int, 9, 11))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 9, 11), make_date(extract(year from current_date)::int, 9, 15))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 9, 15), make_date(extract(year from current_date)::int, 9, 17))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 9, 17), make_date(extract(year from current_date)::int, 9, 22))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 9, 22), make_date(extract(year from current_date)::int, 9, 24))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 9, 24), make_date(extract(year from current_date)::int, 9, 29))); +select set_season_range(93, daterange(make_date(extract(year from current_date)::int, 9, 29), make_date(extract(year from current_date)::int, 10, 1))); +select set_season_range(94, daterange(make_date(extract(year from current_date)::int, 10, 1), make_date(extract(year from current_date)::int, 10, 13))); -select set_campsite_type_cost (slug, 92, '20.00') from campsite_type where campsite_type_id = 72; -select set_campsite_type_cost (slug, 93, '16.50') from campsite_type where campsite_type_id = 72; -select set_campsite_type_cost (slug, 94, '12.50') from campsite_type where campsite_type_id = 72; -select set_campsite_type_cost (slug, 92, '20.00') from campsite_type where campsite_type_id = 73; -select set_campsite_type_cost (slug, 93, '16.50') from campsite_type where campsite_type_id = 73; -select set_campsite_type_cost (slug, 94, '12.50') from campsite_type where campsite_type_id = 73; -select set_campsite_type_cost (slug, 92, '20.00') from campsite_type where campsite_type_id = 74; -select set_campsite_type_cost (slug, 93, '16.50') from campsite_type where campsite_type_id = 74; -select set_campsite_type_cost (slug, 94, '12.50') from campsite_type where campsite_type_id = 74; -select set_campsite_type_cost (slug, 92, '20.00') from campsite_type where campsite_type_id = 75; -select set_campsite_type_cost (slug, 93, '16.50') from campsite_type where campsite_type_id = 75; -select set_campsite_type_cost (slug, 94, '12.50') from campsite_type where campsite_type_id = 75; -select set_campsite_type_cost (slug, 92, '20.00') from campsite_type where campsite_type_id = 76; -select set_campsite_type_cost (slug, 93, '16.50') from campsite_type where campsite_type_id = 76; -select set_campsite_type_cost (slug, 94, '12.50') from campsite_type where campsite_type_id = 76; +select set_campsite_type_cost (slug, 92, '4.00', '7.95', '7.95', '6.40') from campsite_type where campsite_type_id = 72; +select set_campsite_type_cost (slug, 93, '2.00', '7.40', '7.40', '5.90') from campsite_type where campsite_type_id = 72; +select set_campsite_type_cost (slug, 94, '0.00', '6.60', '6.60', '5.40') from campsite_type where campsite_type_id = 72; +select set_campsite_type_cost (slug, 92, '120.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 73; +select set_campsite_type_cost (slug, 93, '100.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 73; +select set_campsite_type_cost (slug, 94, '80.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 73; +select set_campsite_type_cost (slug, 92, '170.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 74; +select set_campsite_type_cost (slug, 93, '135.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 74; +select set_campsite_type_cost (slug, 94, '105.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 74; +select set_campsite_type_cost (slug, 92, '180.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 75; +select set_campsite_type_cost (slug, 93, '145.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 75; +select set_campsite_type_cost (slug, 94, '115.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 75; +select set_campsite_type_cost (slug, 92, '200.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 76; +select set_campsite_type_cost (slug, 93, '165.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 76; +select set_campsite_type_cost (slug, 94, '125.00', '0.0', '0.0', '0.0') from campsite_type where campsite_type_id = 76; alter table campsite_type_option alter column campsite_type_option_id restart with 102; insert into campsite_type_option (campsite_type_id, name, range) -values (72, 'Adults', '[1, 6]') - , (72, 'Nens (de 2 a 10 anys)', '[0, 4]') - , (72, 'Tenda petita (màx. 2 pers.)', '[0, 3]') +values (72, 'Tenda petita (màx. 2 pers.)', '[0, 3]') , (72, 'Tenda gran', '[0, 3]') , (72, 'Caravana', '[0, 3]') , (72, 'Autocaravana', '[0, 3]') @@ -1261,61 +1259,47 @@ values (72, 'Adults', '[1, 6]') , (72, 'Punt electricitat', '[0, 4]') ; -insert into campsite_type_option_i18n (campsite_type_option_id, lang_tag, name) -values (102, 'en', 'Adults') - , (102, 'es', 'Adultos') - , (103, 'en', 'Children (from 2 to 10 years)') - , (103, 'es', 'Niños (de 2 a 10 años)') - , (104, 'en', 'Small tent (2 pax max.)') - , (104, 'es', 'Tienda pequeña (máx. 2 pers.)') - , (105, 'en', 'Big tent') - , (105, 'es', 'Tienda grande') - , (106, 'en', 'Caravan') - , (106, 'es', 'Caravana') - , (107, 'en', 'Motorhome') - , (107, 'es', 'Autocaravana') - , (108, 'en', 'Van') - , (108, 'es', 'Furgoneta') - , (109, 'en', 'Car') - , (109, 'es', 'Coche') - , (110, 'en', 'Motorcycle') - , (110, 'es', 'Moto') - , (111, 'en', 'Electricity') - , (111, 'es', 'Puntos de electricidad') -; +select translate_campsite_type_option(102, 'en', 'Small tent (2 pax max.)'); +select translate_campsite_type_option(102, 'es', 'Tienda pequeña (máx. 2 pers.)'); +select translate_campsite_type_option(103, 'en', 'Big tent'); +select translate_campsite_type_option(103, 'es', 'Tienda grande'); +select translate_campsite_type_option(104, 'en', 'Caravan'); +select translate_campsite_type_option(104, 'es', 'Caravana'); +select translate_campsite_type_option(105, 'en', 'Motorhome'); +select translate_campsite_type_option(105, 'es', 'Autocaravana'); +select translate_campsite_type_option(106, 'en', 'Van'); +select translate_campsite_type_option(106, 'es', 'Furgoneta'); +select translate_campsite_type_option(107, 'en', 'Car'); +select translate_campsite_type_option(107, 'es', 'Coche'); +select translate_campsite_type_option(108, 'en', 'Motorcycle'); +select translate_campsite_type_option(108, 'es', 'Moto'); +select translate_campsite_type_option(109, 'en', 'Electricity'); +select translate_campsite_type_option(109, 'es', 'Puntos de electricidad'); -insert into campsite_type_option_cost (campsite_type_option_id, season_id, cost_per_night) -values (102, 92, 795) - , (102, 93, 740) - , (102, 94, 660) - , (103, 92, 640) - , (103, 93, 590) - , (103, 94, 540) - , (104, 92, 620) - , (104, 93, 550) - , (104, 94, 500) - , (105, 92, 800) - , (105, 93, 720) - , (105, 94, 620) - , (106, 92, 900) - , (106, 93, 750) - , (106, 94, 650) - , (107, 92, 1220) - , (107, 93, 1100) - , (107, 94, 950) - , (108, 92, 950) - , (108, 93, 850) - , (108, 94, 750) - , (109, 92, 700) - , (109, 93, 630) - , (109, 94, 530) - , (110, 92, 400) - , (110, 93, 360) - , (110, 94, 360) - , (111, 92, 690) - , (111, 93, 610) - , (111, 94, 590) -; +select set_campsite_type_option_cost(102, 92, '6.20'); +select set_campsite_type_option_cost(102, 93, '5.50'); +select set_campsite_type_option_cost(102, 94, '5.00'); +select set_campsite_type_option_cost(103, 92, '8.00'); +select set_campsite_type_option_cost(103, 93, '7.20'); +select set_campsite_type_option_cost(103, 94, '6.20'); +select set_campsite_type_option_cost(104, 92, '9.00'); +select set_campsite_type_option_cost(104, 93, '7.50'); +select set_campsite_type_option_cost(104, 94, '6.50'); +select set_campsite_type_option_cost(105, 92, '12.20'); +select set_campsite_type_option_cost(105, 93, '11.00'); +select set_campsite_type_option_cost(105, 94, '9.50'); +select set_campsite_type_option_cost(106, 92, '9.50'); +select set_campsite_type_option_cost(106, 93, '8.50'); +select set_campsite_type_option_cost(106, 94, '7.50'); +select set_campsite_type_option_cost(107, 92, '7.00'); +select set_campsite_type_option_cost(107, 93, '6.30'); +select set_campsite_type_option_cost(107, 94, '5.30'); +select set_campsite_type_option_cost(108, 92, '4.00'); +select set_campsite_type_option_cost(108, 93, '3.60'); +select set_campsite_type_option_cost(108, 94, '3.60'); +select set_campsite_type_option_cost(109, 92, '6.90'); +select set_campsite_type_option_cost(109, 93, '6.10'); +select set_campsite_type_option_cost(109, 94, '5.90'); insert into campsite_type_carousel (campsite_type_id, media_id, caption) values (72, 77, 'Llegenda') diff --git a/deploy/campsite_type_cost__per_age.sql b/deploy/campsite_type_cost__per_age.sql new file mode 100644 index 0000000..f179c56 --- /dev/null +++ b/deploy/campsite_type_cost__per_age.sql @@ -0,0 +1,18 @@ +-- Deploy camper:campsite_type_cost__per_age to pg +-- requires: campsite_type_cost + +begin; + +alter table camper.campsite_type_cost + add column cost_per_adult integer not null default 0 constraint per_adult_not_negative check(cost_per_adult >= 0) +, add column cost_per_teenager integer not null default 0 constraint per_teenager_not_negative check(cost_per_teenager >= 0) +, add column cost_per_child integer not null default 0 constraint per_child_not_negative check(cost_per_child >= 0) +; + +alter table camper.campsite_type_cost + alter column cost_per_adult drop default +, alter column cost_per_teenager drop default +, alter column cost_per_child drop default +; + +commit; diff --git a/deploy/set_campsite_type_cost.sql b/deploy/set_campsite_type_cost.sql index 5a53c7b..2c663ed 100644 --- a/deploy/set_campsite_type_cost.sql +++ b/deploy/set_campsite_type_cost.sql @@ -3,6 +3,8 @@ -- requires: schema_camper -- requires: campsite_type_cost -- requires: parse_price +-- requires: campsite_type__bookable_nights +-- requires: campsite_type_cost__per_age begin; @@ -10,20 +12,25 @@ set search_path to camper, public; drop function if exists set_campsite_type_cost(uuid, integer, integer, text, integer); -create or replace function set_campsite_type_cost(slug uuid, season_id integer, cost_per_night text, decimal_places integer default 2) returns void as +create or replace function set_campsite_type_cost(slug uuid, season_id integer, per_night text, per_adult text, per_teenager text, per_child text) returns void as $$ - insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) - select campsite_type_id, season_id, parse_price(cost_per_night, decimal_places) + insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) + select campsite_type_id, season_id, parse_price(per_night, decimal_digits), parse_price(per_adult, decimal_digits), parse_price(per_teenager, decimal_digits), parse_price(per_child, decimal_digits) from campsite_type + join company using (company_id) + join currency using (currency_code) where campsite_type.slug = set_campsite_type_cost.slug on conflict (campsite_type_id, season_id) do update set cost_per_night = excluded.cost_per_night + , cost_per_adult = excluded.cost_per_adult + , cost_per_teenager = excluded.cost_per_teenager + , cost_per_child = excluded.cost_per_child ; $$ language sql ; -revoke execute on function set_campsite_type_cost(uuid, integer, text, integer) from public; -grant execute on function set_campsite_type_cost(uuid, integer, text, integer) to admin; +revoke execute on function set_campsite_type_cost(uuid, integer, text, text, text, text) from public; +grant execute on function set_campsite_type_cost(uuid, integer, text, text, text, text) to admin; commit; diff --git a/pkg/booking/cart.go b/pkg/booking/cart.go new file mode 100644 index 0000000..749ab4c --- /dev/null +++ b/pkg/booking/cart.go @@ -0,0 +1,201 @@ +package booking + +import ( + "context" + "net/http" + "strconv" + "time" + + "github.com/jackc/pgx/v4" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/locale" + "dev.tandem.ws/tandem/camper/pkg/template" +) + +func handleBookingCart(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch head { + case "": + switch r.Method { + case http.MethodGet: + f := newBookingForm(r.Context(), company, conn, user.Locale) + if err := f.Parse(r); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if cart, err := computeCart(r.Context(), conn, f); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } else { + cart.MustRender(w, r, user, company) + } + default: + httplib.MethodNotAllowed(w, r, http.MethodGet) + } + default: + http.NotFound(w, r) + } +} + +type bookingCart struct { + Lines []*cartLine + Total string +} + +type cartLine struct { + Concept string + Units int + Subtotal string +} + +func (cart *bookingCart) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { + template.MustRenderPublicNoLayout(w, r, user, company, "booking/cart.gohtml", cart) +} + +func computeCart(ctx context.Context, conn *database.Conn, f *bookingForm) (*bookingCart, error) { + cart := &bookingCart{ + Total: "0.0", + } + campsiteType := f.CampsiteType.String() + if campsiteType == "" { + return cart, nil + } + arrivalDate, err := time.Parse(database.ISODateFormat, f.ArrivalDate.Val) + if err != nil { + return cart, nil + } + departureDate, err := time.Parse(database.ISODateFormat, f.DepartureDate.Val) + if err != nil { + return cart, nil + } + numAdults, err := strconv.Atoi(f.NumberAdults.Val) + if err != nil { + return cart, nil + } + numTeenagers, err := strconv.Atoi(f.NumberTeenagers.Val) + if err != nil { + return cart, nil + } + numChildren, err := strconv.Atoi(f.NumberChildren.Val) + if err != nil { + return cart, nil + } + + optionMap := make(map[int]*campsiteTypeOption) + typeOptions := f.CampsiteTypeOptions[campsiteType] + optionIDs := make([]int, 0, len(typeOptions)) + optionUnits := make([]int, 0, len(typeOptions)) + for _, option := range typeOptions { + units, _ := strconv.Atoi(option.Input.Val) + if units < 1 { + continue + } + optionMap[option.ID] = option + optionIDs = append(optionIDs, option.ID) + optionUnits = append(optionUnits, units) + } + + row := conn.QueryRow(ctx, ` + with per_person as ( + select count(*) as num_nights + , sum(cost_per_night)::integer as nights + , sum(cost_per_adult * $4)::integer as adults + , sum(cost_per_teenager * $5)::integer as teenagers + , sum(cost_per_child * $6)::integer as children + , sum(tourist_tax * $4)::integer as tourist_tax + , max(decimal_digits) as decimal_digits + from generate_series($1, $2, interval '1 day') as date(day) + left join season_calendar on season_range @> date.day::date + left join season using (season_id) + left join campsite_type using (company_id) + left join campsite_type_cost using (campsite_type_id, season_id) + left join company using (company_id) + left join currency using (currency_code) + where campsite_type.slug = $3 + ), per_option as ( + select campsite_type_option_id + , sum(cost_per_night * units)::integer as option_cost + from generate_series($1, $2, interval '1 day') as date(day) + join season_calendar on season_range @> date.day::date + join campsite_type_option_cost using (season_id) + join unnest($7::integer[], $8::integer[]) as option_units(campsite_type_option_id, units) using (campsite_type_option_id) + group by campsite_type_option_id + union all select -1, 0 + ) + select num_nights + , coalesce(to_price(nights, decimal_digits), '') + , coalesce(to_price(adults, decimal_digits), '') + , coalesce(to_price(teenagers, decimal_digits), '') + , coalesce(to_price(children, decimal_digits), '') + , coalesce(to_price(tourist_tax, decimal_digits), '') + , coalesce(to_price(nights + adults + teenagers + children + tourist_tax + sum(option_cost)::integer, decimal_digits), '') + , array_agg((campsite_type_option_id, to_price(option_cost, decimal_digits))) + from per_person, per_option + group by num_nights + , nights + , adults + , teenagers + , children + , tourist_tax + , decimal_digits +`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, arrivalDate, departureDate.AddDate(0, 0, -1), campsiteType, numAdults, numTeenagers, numChildren, optionIDs, optionUnits) + + var numNights int + var nights string + var adults string + var teenagers string + var children string + var touristTax string + var total string + var optionPrices database.RecordArray + if err = row.Scan(&numNights, &nights, &adults, &teenagers, &children, &touristTax, &total, &optionPrices); 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")) + + for _, el := range optionPrices.Elements { + optionID := el.Fields[0].Get() + if optionID == nil { + continue + } + subtotal := el.Fields[1].Get() + if subtotal == nil { + continue + } + option := optionMap[int(optionID.(int32))] + if option == nil { + continue + } + units, _ := strconv.Atoi(option.Input.Val) + maybeAddLine(units, subtotal.(string), option.Label) + } + + maybeAddLine(numAdults, touristTax, locale.PgettextNoop("Tourist tax", "cart")) + + if total != "" { + cart.Total = total + } + + return cart, nil +} diff --git a/pkg/booking/public.go b/pkg/booking/public.go index 70f046f..411c4e3 100644 --- a/pkg/booking/public.go +++ b/pkg/booking/public.go @@ -48,6 +48,8 @@ func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *da default: httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) } + case "cart": + handleBookingCart(w, r, user, company, conn) case "success": handleSuccessfulPayment(w, r, user, company, conn) case "failure": @@ -74,12 +76,17 @@ func makeReservation(w http.ResponseWriter, r *http.Request, user *auth.User, co page.MustRender(w, r, user, company, conn) return } + cart, err := computeCart(r.Context(), conn, f) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } schema := httplib.Protocol(r) authority := httplib.Host(r) request := &redsys.Request{ TransactionType: redsys.TransactionTypeCharge, - Amount: "12.34", + Amount: cart.Total, OrderNumber: randomOrderNumber(), Product: "Test Booking", SuccessURL: fmt.Sprintf("%s://%s/%s/booking/success", schema, authority, user.Locale.Language), @@ -106,6 +113,7 @@ func randomOrderNumber() string { type publicPage struct { *template.PublicPage Form *bookingForm + Cart *bookingCart } func newPublicPage(ctx context.Context, company *auth.Company, conn *database.Conn, l *locale.Locale) *publicPage { @@ -121,7 +129,12 @@ func newPublicPageWithForm(form *bookingForm) *publicPage { func (p *publicPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { p.Setup(r, user, company, conn) - template.MustRenderPublic(w, r, user, company, "booking.gohtml", p) + var err error + p.Cart, err = computeCart(r.Context(), conn, p.Form) + if err != nil { + panic(err) + } + template.MustRenderPublicFiles(w, r, user, company, p, "booking/form.gohtml", "booking/cart.gohtml") } type bookingForm struct { @@ -136,12 +149,17 @@ type bookingForm struct { CampsiteTypeOptions map[string][]*campsiteTypeOption ArrivalDate *form.Input DepartureDate *form.Input + NumberAdults *form.Input + NumberTeenagers *form.Input + NumberChildren *form.Input + NumberDogs *form.Input ZonePreferences map[string]*form.Input ACSICard *form.Checkbox Agreement *form.Checkbox } type campsiteTypeOption struct { + ID int Label string Min int Max int @@ -186,6 +204,8 @@ func newBookingForm(ctx context.Context, company *auth.Company, conn *database.C } return &bookingForm{ + CampsiteTypeOptions: mustGetCampsiteTypeOptions(ctx, conn, company, l), + ZonePreferences: zonePreferences, FullName: &form.Input{ Name: "full_name", }, @@ -212,14 +232,28 @@ func newBookingForm(ctx context.Context, company *auth.Company, conn *database.C Name: "campsite_type", Options: typeSelectOptions, }, - CampsiteTypeOptions: mustGetCampsiteTypeOptions(ctx, conn, company, l), ArrivalDate: &form.Input{ Name: "arrival_date", }, DepartureDate: &form.Input{ Name: "departure_date", }, - ZonePreferences: zonePreferences, + NumberAdults: &form.Input{ + Name: "number_adults", + Val: "1", + }, + NumberTeenagers: &form.Input{ + Name: "number_teenagers", + Val: "0", + }, + NumberChildren: &form.Input{ + Name: "number_children", + Val: "0", + }, + NumberDogs: &form.Input{ + Name: "number_dogs", + Val: "0", + }, ACSICard: &form.Checkbox{ Name: "acsi_card", }, @@ -231,7 +265,8 @@ func newBookingForm(ctx context.Context, company *auth.Company, conn *database.C func mustGetCampsiteTypeOptions(ctx context.Context, conn *database.Conn, company *auth.Company, l *locale.Locale) map[string][]*campsiteTypeOption { rows, err := conn.Query(ctx, ` - select 'campsite_type_option_' || option.campsite_type_option_id + select option.campsite_type_option_id + , 'campsite_type_option_' || option.campsite_type_option_id , slug , coalesce(i18n.name, option.name) as l10_name , lower(range)::text @@ -254,7 +289,7 @@ func mustGetCampsiteTypeOptions(ctx context.Context, conn *database.Conn, compan option := &campsiteTypeOption{ Input: &form.Input{}, } - if err = rows.Scan(&option.Input.Name, &slug, &option.Label, &option.Input.Val, &option.Min, &option.Max); err != nil { + if err = rows.Scan(&option.ID, &option.Input.Name, &slug, &option.Label, &option.Input.Val, &option.Min, &option.Max); err != nil { panic(err) } options[slug] = append(options[slug], option) @@ -279,6 +314,10 @@ func (f *bookingForm) Parse(r *http.Request) error { f.CampsiteType.FillValue(r) f.ArrivalDate.FillValue(r) f.DepartureDate.FillValue(r) + f.NumberAdults.FillValue(r) + f.NumberTeenagers.FillValue(r) + f.NumberChildren.FillValue(r) + f.NumberDogs.FillValue(r) f.ACSICard.FillValue(r) f.Agreement.FillValue(r) for _, preferences := range f.ZonePreferences { @@ -329,6 +368,27 @@ func (f *bookingForm) Valid(ctx context.Context, conn *database.Conn, l *locale. v.CheckDateAfter(f.DepartureDate, f.ArrivalDate, l.GettextNoop("The departure date must be after the arrival date.")) } } + + if v.CheckRequired(f.NumberAdults, l.GettextNoop("Number of adults can not be empty")) { + if v.CheckValidInteger(f.NumberAdults, l.GettextNoop("Number of adults must be an integer.")) { + v.CheckMinInteger(f.NumberAdults, 1, l.GettextNoop("There must be at least one adult.")) + } + } + if v.CheckRequired(f.NumberTeenagers, l.GettextNoop("Number of teenagers can not be empty")) { + if v.CheckValidInteger(f.NumberTeenagers, l.GettextNoop("Number of teenagers must be an integer.")) { + v.CheckMinInteger(f.NumberTeenagers, 0, l.GettextNoop("Number of teenagers can not be negative.")) + } + } + if v.CheckRequired(f.NumberTeenagers, l.GettextNoop("Number of children can not be empty")) { + if v.CheckValidInteger(f.NumberTeenagers, l.GettextNoop("Number of children must be an integer.")) { + v.CheckMinInteger(f.NumberTeenagers, 0, l.GettextNoop("Number of children can not be negative.")) + } + } + if v.CheckRequired(f.NumberTeenagers, l.GettextNoop("Number of dogs can not be empty")) { + if v.CheckValidInteger(f.NumberTeenagers, l.GettextNoop("Number of dogs must be an integer.")) { + v.CheckMinInteger(f.NumberTeenagers, 0, l.GettextNoop("Number of dogs can not be negative.")) + } + } v.Check(f.Agreement, f.Agreement.Checked, l.GettextNoop("It is mandatory to agree to the reservation conditions.")) for _, options := range f.CampsiteTypeOptions { for _, option := range options { diff --git a/pkg/campsite/types/admin.go b/pkg/campsite/types/admin.go index 1baf919..96eae08 100644 --- a/pkg/campsite/types/admin.go +++ b/pkg/campsite/types/admin.go @@ -193,7 +193,7 @@ func translateTypes(ctx context.Context, tx *database.Tx, company *auth.Company, func setTypePrices(ctx context.Context, tx *database.Tx, slug string, prices map[int]*typePriceForm) error { for seasonID, p := range prices { - if err := tx.SetCampsiteTypeCost(ctx, slug, seasonID, p.PricePerNight.Val); err != nil { + if err := tx.SetCampsiteTypeCost(ctx, slug, seasonID, p.PricePerNight.Val, p.PricePerAdult.Val, p.PricePerTeenager.Val, p.PricePerChild.Val); err != nil { return err } } @@ -292,8 +292,11 @@ type typeForm struct { } type typePriceForm struct { - SeasonName string - PricePerNight *form.Input + SeasonName string + PricePerNight *form.Input + PricePerAdult *form.Input + PricePerTeenager *form.Input + PricePerChild *form.Input } func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn) (*typeForm, error) { @@ -359,6 +362,18 @@ func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn Name: fmt.Sprintf("season.%d.price_per_night", id), Val: "0", }, + PricePerAdult: &form.Input{ + Name: fmt.Sprintf("season.%d.price_per_adult", id), + Val: "0", + }, + PricePerTeenager: &form.Input{ + Name: fmt.Sprintf("season.%d.price_per_teenager", id), + Val: "0", + }, + PricePerChild: &form.Input{ + Name: fmt.Sprintf("season.%d.price_per_child", id), + Val: "0", + }, } } @@ -475,6 +490,9 @@ func (f *typeForm) FillFromDatabase(ctx context.Context, conn *database.Conn, sl rows, err := conn.Query(ctx, ` select season_id , to_price(cost_per_night) + , to_price(cost_per_adult) + , to_price(cost_per_teenager) + , to_price(cost_per_child) from campsite_type join campsite_type_cost using (campsite_type_id) where slug = $1 @@ -487,11 +505,17 @@ func (f *typeForm) FillFromDatabase(ctx context.Context, conn *database.Conn, sl for rows.Next() { var seasonID int var pricePerNight string - if err = rows.Scan(&seasonID, &pricePerNight); err != nil { + var pricePerAdult string + var pricePerTeenager string + var pricePerChild string + if err = rows.Scan(&seasonID, &pricePerNight, &pricePerAdult, &pricePerTeenager, &pricePerChild); err != nil { return err } if p, ok := f.Prices[seasonID]; ok { p.PricePerNight.Val = pricePerNight + p.PricePerAdult.Val = pricePerAdult + p.PricePerTeenager.Val = pricePerTeenager + p.PricePerChild.Val = pricePerChild } } return rows.Err() @@ -519,6 +543,9 @@ func (f *typeForm) Parse(r *http.Request) error { f.Media.FillValue(r) for _, p := range f.Prices { p.PricePerNight.FillValue(r) + p.PricePerAdult.FillValue(r) + p.PricePerTeenager.FillValue(r) + p.PricePerChild.FillValue(r) } return nil } @@ -556,6 +583,21 @@ func (f *typeForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Loc v.CheckMinDecimal(p.PricePerNight, 0.0, l.GettextNoop("Price per night must be zero or greater.")) } } + if v.CheckRequired(p.PricePerAdult, l.GettextNoop("Price per adult can not be empty.")) { + if v.CheckValidDecimal(p.PricePerAdult, l.GettextNoop("Price per adult must be a decimal number.")) { + v.CheckMinDecimal(p.PricePerAdult, 0.0, l.GettextNoop("Price per adult must be zero or greater.")) + } + } + if v.CheckRequired(p.PricePerTeenager, l.GettextNoop("Price per teenager can not be empty.")) { + if v.CheckValidDecimal(p.PricePerTeenager, l.GettextNoop("Price per teenager must be a decimal number.")) { + v.CheckMinDecimal(p.PricePerTeenager, 0.0, l.GettextNoop("Price per teenager must be zero or greater.")) + } + } + if v.CheckRequired(p.PricePerChild, l.GettextNoop("Price per child can not be empty.")) { + if v.CheckValidDecimal(p.PricePerChild, l.GettextNoop("Price per child must be a decimal number.")) { + v.CheckMinDecimal(p.PricePerChild, 0.0, l.GettextNoop("Price per child must be zero or greater.")) + } + } } return v.AllOK, nil } diff --git a/pkg/campsite/types/public.go b/pkg/campsite/types/public.go index 78b122b..2cf4fc0 100644 --- a/pkg/campsite/types/public.go +++ b/pkg/campsite/types/public.go @@ -83,10 +83,9 @@ type publicPage struct { } type typePrice struct { - SeasonName string - SeasonColor string - PricePerNight string - Options []*optionPrice + SeasonName string + SeasonColor string + Options []*optionPrice } type optionPrice struct { @@ -100,10 +99,6 @@ type typeFeature struct { } func newPublicPage(ctx context.Context, company *auth.Company, conn *database.Conn, loc *locale.Locale, slug string) (*publicPage, error) { - prices, err := collectPrices(ctx, conn, loc.Language, slug) - if err != nil { - return nil, err - } features, err := collectFeatures(ctx, conn, loc.Language, slug) if err != nil { return nil, err @@ -118,7 +113,6 @@ func newPublicPage(ctx context.Context, company *auth.Company, conn *database.Co Slug: slug, Carousel: mustCollectSlides(ctx, conn, loc, slug), Calendar: calendar, - Prices: prices, Features: features, } row := conn.QueryRow(ctx, ` @@ -155,18 +149,25 @@ func newPublicPage(ctx context.Context, company *auth.Company, conn *database.Co ); err != nil { return nil, err } - if err := conn.QueryRow(ctx, "select to_price(tourist_tax, $1) from company where company_id = $2", company.DecimalDigits, company.ID).Scan(&page.TouristTax); err != nil { + if err = conn.QueryRow(ctx, "select to_price(tourist_tax, $1) from company where company_id = $2", company.DecimalDigits, company.ID).Scan(&page.TouristTax); err != nil { + return nil, err + } + page.Prices, err = collectPrices(ctx, conn, loc.Language, slug, page.Name) + if err != nil { return nil, err } return page, nil } -func collectPrices(ctx context.Context, conn *database.Conn, language language.Tag, slug string) ([]*typePrice, error) { +func collectPrices(ctx context.Context, conn *database.Conn, language language.Tag, slug string, campsiteName string) ([]*typePrice, error) { rows, err := conn.Query(ctx, ` select coalesce(i18n.name, season.name) as l10n_name , to_color(season.color)::text - , to_price(coalesce(cost.cost_per_night, 0)) + , case when cost.cost_per_night > 0 then to_price(coalesce(cost.cost_per_night, 0)) else '' end + , case when cost.cost_per_adult > 0 then to_price(coalesce(cost.cost_per_adult, 0)) else '' end + , case when cost.cost_per_teenager > 0 then to_price(coalesce(cost.cost_per_teenager, 0)) else '' end + , case when cost.cost_per_child > 0 then to_price(coalesce(cost.cost_per_child, 0)) else '' end , array_agg((coalesce(option_i18n.name, option.name), to_price(coalesce(option_cost.cost_per_night, 0))) order by option.position) filter (where option.campsite_type_option_id is not null) from season left join season_i18n as i18n on season.season_id = i18n.season_id and i18n.lang_tag = $1 @@ -185,6 +186,9 @@ func collectPrices(ctx context.Context, conn *database.Conn, language language.T , season.name , season.color , cost.cost_per_night + , cost.cost_per_adult + , cost.cost_per_teenager + , cost.cost_per_child , season.position order by season.position, l10n_name `, pgx.QueryResultFormats{pgx.BinaryFormatCode}, language, slug) @@ -195,15 +199,49 @@ func collectPrices(ctx context.Context, conn *database.Conn, language language.T var prices []*typePrice for rows.Next() { price := &typePrice{} + var pricePerNight string + var pricePerAdult string + var pricePerTeenager string + var pricePerChild string var options database.RecordArray if err = rows.Scan( &price.SeasonName, &price.SeasonColor, - &price.PricePerNight, + &pricePerNight, + &pricePerAdult, + &pricePerTeenager, + &pricePerChild, &options, ); err != nil { return nil, err } + if pricePerNight != "" { + option := &optionPrice{ + PricePerNight: pricePerNight, + } + if pricePerAdult != "" || pricePerTeenager != "" || pricePerChild != "" || len(options.Elements) > 0 { + option.OptionName = campsiteName + } + price.Options = append(price.Options, option) + } + if pricePerAdult != "" { + price.Options = append(price.Options, &optionPrice{ + OptionName: locale.PgettextNoop("Adults", "header"), + PricePerNight: pricePerAdult, + }) + } + if pricePerTeenager != pricePerAdult && pricePerTeenager != "" { + price.Options = append(price.Options, &optionPrice{ + OptionName: locale.PgettextNoop("Teenagers (aged 11 to 16)", "header"), + PricePerNight: pricePerTeenager, + }) + } + if pricePerChild != "" { + price.Options = append(price.Options, &optionPrice{ + OptionName: locale.PgettextNoop("Children (aged 2 to 10)", "header"), + PricePerNight: pricePerChild, + }) + } for _, el := range options.Elements { price.Options = append(price.Options, &optionPrice{ OptionName: el.Fields[0].Get().(string), diff --git a/pkg/database/funcs.go b/pkg/database/funcs.go index 913a253..957afb6 100644 --- a/pkg/database/funcs.go +++ b/pkg/database/funcs.go @@ -147,8 +147,8 @@ func (tx *Tx) TranslateCampsiteType(ctx context.Context, slug string, langTag la _, err := tx.Exec(ctx, "select translate_campsite_type($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", slug, langTag, name, spiel, info, facilities, description, additionalInfo, checkIn, checkOut) return err } -func (tx *Tx) SetCampsiteTypeCost(ctx context.Context, slug string, seasonID int, costPerNight string) error { - _, err := tx.Exec(ctx, "select set_campsite_type_cost($1, $2, $3)", slug, seasonID, costPerNight) +func (tx *Tx) SetCampsiteTypeCost(ctx context.Context, slug string, seasonID int, perNight string, perAdult string, perTeenager string, perChild string) error { + _, err := tx.Exec(ctx, "select set_campsite_type_cost($1, $2, $3, $4, $5, $6)", slug, seasonID, perNight, perAdult, perTeenager, perChild) return err } diff --git a/po/ca.po b/po/ca.po index 982f8d9..94c927d 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-02-02 21:57+0100\n" +"POT-Creation-Date: 2024-02-04 06:23+0100\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -94,7 +94,7 @@ msgid "The campsite offers many different services." msgstr "El càmping disposa de diversos serveis." #: web/templates/public/amenity.gohtml:39 -#: web/templates/public/campsite/type.gohtml:114 +#: web/templates/public/campsite/type.gohtml:113 #: web/templates/public/campsite/page.gohtml:39 msgctxt "title" msgid "Features" @@ -164,7 +164,7 @@ msgid "Check-out Date" msgstr "Data de sortida" #: web/templates/public/campsite/type.gohtml:56 -#: web/templates/public/booking.gohtml:171 +#: web/templates/public/booking/cart.gohtml:25 msgctxt "action" msgid "Book" msgstr "Reserva" @@ -182,61 +182,60 @@ msgctxt "title" msgid "Prices" msgstr "Preus" -#: web/templates/public/campsite/type.gohtml:87 -#: web/templates/public/campsite/type.gohtml:93 -msgid "%s: %s €/night" -msgstr "%s: %s €/nit" +#: web/templates/public/campsite/type.gohtml:88 +msgid "%s: %s/night" +msgstr "%s: %s/nit" -#: web/templates/public/campsite/type.gohtml:89 -msgid "%s €/night" -msgstr "%s €/nit" +#: web/templates/public/campsite/type.gohtml:90 +msgid "%s/night" +msgstr "%s/nit" -#: web/templates/public/campsite/type.gohtml:96 +#: web/templates/public/campsite/type.gohtml:95 msgid "*Minimum %d nights per stay" msgstr "*Mínim %d nits per estada" -#: web/templates/public/campsite/type.gohtml:101 +#: web/templates/public/campsite/type.gohtml:100 msgid "10 % VAT included." msgstr "IVA del 10 % inclòs." -#: web/templates/public/campsite/type.gohtml:102 +#: web/templates/public/campsite/type.gohtml:101 msgid "Tourist tax: %s/night per person aged 17 or older." msgstr "Impost turístic: %s/nit per persona major de 16 anys." -#: web/templates/public/campsite/type.gohtml:104 +#: web/templates/public/campsite/type.gohtml:103 msgid "Dogs: %s/night, tied, accompanied, and minimal barking." -msgstr "Gossos: %s/night, lligats, acompanyats i el mínim de lladrucs." +msgstr "Gossos: %s/nit, lligats, acompanyats i el mínim de lladrucs." -#: web/templates/public/campsite/type.gohtml:106 +#: web/templates/public/campsite/type.gohtml:105 msgid "No dogs allowed." msgstr "No es permeten gossos." -#: web/templates/public/campsite/type.gohtml:125 +#: web/templates/public/campsite/type.gohtml:124 msgctxt "title" msgid "Info" msgstr "Informació" -#: web/templates/public/campsite/type.gohtml:129 +#: web/templates/public/campsite/type.gohtml:128 msgctxt "title" msgid "Facilities" msgstr "Equipaments" -#: web/templates/public/campsite/type.gohtml:133 +#: web/templates/public/campsite/type.gohtml:132 msgctxt "title" msgid "Description" msgstr "Descripció" -#: web/templates/public/campsite/type.gohtml:137 +#: web/templates/public/campsite/type.gohtml:136 msgctxt "title" msgid "Additional Information" msgstr "Informació addicional" -#: web/templates/public/campsite/type.gohtml:140 +#: web/templates/public/campsite/type.gohtml:139 msgctxt "time" msgid "Check-in" msgstr "Entrada" -#: web/templates/public/campsite/type.gohtml:144 +#: web/templates/public/campsite/type.gohtml:143 msgctxt "time" msgid "Check-out" msgstr "Sortida" @@ -482,99 +481,6 @@ msgctxt "legend" msgid "Faucet" msgstr "Aixeta" -#: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12 -#: web/templates/public/layout.gohtml:70 -msgctxt "title" -msgid "Booking" -msgstr "Reserva" - -#: web/templates/public/booking.gohtml:16 -msgctxt "title" -msgid "Customer Details" -msgstr "Detalls del client" - -#: web/templates/public/booking.gohtml:19 -msgctxt "input" -msgid "Full name" -msgstr "Nom i cognoms" - -#: web/templates/public/booking.gohtml:28 -msgctxt "input" -msgid "Address (optional)" -msgstr "Adreça (opcional)" - -#: web/templates/public/booking.gohtml:37 -msgctxt "input" -msgid "Postcode (optional)" -msgstr "Codi postal (opcional)" - -#: web/templates/public/booking.gohtml:46 -msgctxt "input" -msgid "Town or village (optional)" -msgstr "Població (opcional)" - -#: web/templates/public/booking.gohtml:55 -#: web/templates/admin/taxDetails.gohtml:101 -msgctxt "input" -msgid "Country" -msgstr "País" - -#: web/templates/public/booking.gohtml:58 -msgid "Choose a country" -msgstr "Esculli un país" - -#: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:27 -#: web/templates/admin/profile.gohtml:38 -#: web/templates/admin/taxDetails.gohtml:53 -msgctxt "input" -msgid "Email" -msgstr "Correu-e" - -#: web/templates/public/booking.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:45 -msgctxt "input" -msgid "Phone" -msgstr "Telèfon" - -#: web/templates/public/booking.gohtml:84 -msgctxt "title" -msgid "Accommodation" -msgstr "Allotjaments" - -#: web/templates/public/booking.gohtml:101 -msgctxt "input" -msgid "Area preferences (optional)" -msgstr "Preferències d’àrea (opcional)" - -#: web/templates/public/booking.gohtml:108 -msgid "Campground map" -msgstr "Mapa del càmping" - -#: web/templates/public/booking.gohtml:126 -msgctxt "title" -msgid "Booking Period" -msgstr "Període de reserva" - -#: web/templates/public/booking.gohtml:129 -msgctxt "input" -msgid "Arrival date" -msgstr "Data d’arribada" - -#: web/templates/public/booking.gohtml:139 -msgctxt "input" -msgid "Departure date" -msgstr "Data de sortida" - -#: web/templates/public/booking.gohtml:151 -msgctxt "input" -msgid "ACSI card? (optional)" -msgstr "Targeta ACSI? (opcional)" - -#: web/templates/public/booking.gohtml:158 -msgctxt "input" -msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" -msgstr "He llegit i accepto %[1]sles condicions de reserves%[2]s" - #: web/templates/public/layout.gohtml:12 web/templates/public/layout.gohtml:48 msgid "Campsite Montagut" msgstr "Càmping Montagut" @@ -608,6 +514,13 @@ msgctxt "title" msgid "Campsites" msgstr "Allotjaments" +#: web/templates/public/layout.gohtml:70 +#: web/templates/public/booking/form.gohtml:7 +#: web/templates/public/booking/form.gohtml:16 +msgctxt "title" +msgid "Booking" +msgstr "Reserva" + #: web/templates/public/layout.gohtml:91 msgctxt "title" msgid "Sections" @@ -622,6 +535,123 @@ msgstr "Obertura" msgid "RTC #%s" msgstr "Núm. RTC %s" +#: web/templates/public/booking/form.gohtml:29 +msgctxt "title" +msgid "Accommodation" +msgstr "Allotjaments" + +#: web/templates/public/booking/form.gohtml:43 +msgctxt "title" +msgid "Booking Period" +msgstr "Període de reserva" + +#: web/templates/public/booking/form.gohtml:46 +msgctxt "input" +msgid "Arrival date" +msgstr "Data d’arribada" + +#: web/templates/public/booking/form.gohtml:57 +msgctxt "input" +msgid "Departure date" +msgstr "Data de sortida" + +#: web/templates/public/booking/form.gohtml:72 +msgctxt "title" +msgid "Guests" +msgstr "Hostes" + +#: web/templates/public/booking/form.gohtml:76 +msgctxt "input" +msgid "Adults aged 17 or older" +msgstr "Adults de 17 anys o més" + +#: web/templates/public/booking/form.gohtml:86 +msgctxt "input" +msgid "Teenagers from 11 to 16 years old" +msgstr "Adolescents d’entre 11 i 16 anys" + +#: web/templates/public/booking/form.gohtml:96 +msgctxt "input" +msgid "Children from 2 to 10 years old" +msgstr "Nens d’entre 2 i 10 anys)" + +#: web/templates/public/booking/form.gohtml:106 +msgctxt "input" +msgid "Dogs" +msgstr "Gossos" + +#: web/templates/public/booking/form.gohtml:127 +msgctxt "input" +msgid "Area preferences (optional)" +msgstr "Preferències d’àrea (opcional)" + +#: web/templates/public/booking/form.gohtml:129 +msgid "Campground map" +msgstr "Mapa del càmping" + +#: web/templates/public/booking/form.gohtml:156 +msgctxt "title" +msgid "Customer Details" +msgstr "Detalls del client" + +#: web/templates/public/booking/form.gohtml:159 +msgctxt "input" +msgid "Full name" +msgstr "Nom i cognoms" + +#: web/templates/public/booking/form.gohtml:168 +msgctxt "input" +msgid "Address (optional)" +msgstr "Adreça (opcional)" + +#: web/templates/public/booking/form.gohtml:177 +msgctxt "input" +msgid "Postcode (optional)" +msgstr "Codi postal (opcional)" + +#: web/templates/public/booking/form.gohtml:186 +msgctxt "input" +msgid "Town or village (optional)" +msgstr "Població (opcional)" + +#: web/templates/public/booking/form.gohtml:195 +#: web/templates/admin/taxDetails.gohtml:101 +msgctxt "input" +msgid "Country" +msgstr "País" + +#: web/templates/public/booking/form.gohtml:198 +msgid "Choose a country" +msgstr "Esculli un país" + +#: web/templates/public/booking/form.gohtml:206 +#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38 +#: web/templates/admin/taxDetails.gohtml:53 +msgctxt "input" +msgid "Email" +msgstr "Correu-e" + +#: web/templates/public/booking/form.gohtml:215 +#: web/templates/admin/taxDetails.gohtml:45 +msgctxt "input" +msgid "Phone" +msgstr "Telèfon" + +#: web/templates/public/booking/form.gohtml:226 +msgctxt "input" +msgid "ACSI card? (optional)" +msgstr "Targeta ACSI? (opcional)" + +#: web/templates/public/booking/form.gohtml:233 +msgctxt "input" +msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" +msgstr "He llegit i accepto %[1]sles condicions de reserves%[2]s" + +#: web/templates/public/booking/cart.gohtml:14 +msgctxt "cart" +msgid "Total" +msgstr "Total" + #: web/templates/admin/legal/form.gohtml:8 #: web/templates/admin/legal/form.gohtml:29 msgctxt "title" @@ -674,7 +704,7 @@ msgstr "Contingut" #: web/templates/admin/campsite/form.gohtml:92 #: web/templates/admin/campsite/type/feature/form.gohtml:74 #: web/templates/admin/campsite/type/carousel/form.gohtml:59 -#: web/templates/admin/campsite/type/form.gohtml:228 +#: web/templates/admin/campsite/type/form.gohtml:277 #: web/templates/admin/campsite/type/option/form.gohtml:90 #: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/services/form.gohtml:81 @@ -696,7 +726,7 @@ msgstr "Actualitza" #: web/templates/admin/campsite/form.gohtml:94 #: web/templates/admin/campsite/type/feature/form.gohtml:76 #: web/templates/admin/campsite/type/carousel/form.gohtml:61 -#: web/templates/admin/campsite/type/form.gohtml:230 +#: web/templates/admin/campsite/type/form.gohtml:279 #: web/templates/admin/campsite/type/option/form.gohtml:92 #: web/templates/admin/season/form.gohtml:75 #: web/templates/admin/services/form.gohtml:83 @@ -1139,35 +1169,75 @@ msgctxt "input" msgid "Dogs allowed" msgstr "Es permeten gossos" +#: web/templates/admin/campsite/type/form.gohtml:147 +msgctxt "header" +msgid "Season" +msgstr "Temporada" + +#: web/templates/admin/campsite/type/form.gohtml:148 +msgctxt "header" +msgid "Price per night" +msgstr "Preu per nit" + #: web/templates/admin/campsite/type/form.gohtml:149 +msgctxt "header" +msgid "Price per adult (> 16)" +msgstr "Preu per adult (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:150 +msgctxt "header" +msgid "Price per teenager (11–16)" +msgstr "Preu per adolescent (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:151 +msgctxt "header" +msgid "Price per child (2–10)" +msgstr "Preu per nen (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:161 #: web/templates/admin/campsite/type/option/form.gohtml:76 msgctxt "input" msgid "Price per night" msgstr "Preu per nit" -#: web/templates/admin/campsite/type/form.gohtml:161 +#: web/templates/admin/campsite/type/form.gohtml:172 +msgctxt "input" +msgid "Price per adult (> 16)" +msgstr "Per per adult (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:183 +msgctxt "input" +msgid "Price per teenager (11–16)" +msgstr "Preu per adolescent (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:194 +msgctxt "input" +msgid "Price per child (2–10)" +msgstr "Preu per nene (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:210 msgctxt "input" msgid "Spiel" msgstr "Introducció" -#: web/templates/admin/campsite/type/form.gohtml:174 +#: web/templates/admin/campsite/type/form.gohtml:223 msgctxt "input" msgid "Info" msgstr "Informació" -#: web/templates/admin/campsite/type/form.gohtml:187 +#: web/templates/admin/campsite/type/form.gohtml:236 msgctxt "input" msgid "Facilities" msgstr "Equipaments" -#: web/templates/admin/campsite/type/form.gohtml:200 +#: web/templates/admin/campsite/type/form.gohtml:249 #: web/templates/admin/services/form.gohtml:66 #: web/templates/admin/surroundings/form.gohtml:54 msgctxt "input" msgid "Description" msgstr "Descripció" -#: web/templates/admin/campsite/type/form.gohtml:213 +#: web/templates/admin/campsite/type/form.gohtml:262 msgctxt "input" msgid "Additional Information" msgstr "Informació addicional" @@ -1864,7 +1934,7 @@ msgid "No booking found." msgstr "No s’ha trobat cap reserva." #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 -#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:528 +#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:555 #: pkg/campsite/feature.go:269 pkg/season/admin.go:412 #: pkg/services/admin.go:316 pkg/surroundings/admin.go:340 #: pkg/amenity/feature.go:269 pkg/amenity/admin.go:283 @@ -1872,7 +1942,7 @@ msgid "Name can not be empty." msgstr "No podeu deixar el nom en blanc." #: pkg/legal/admin.go:259 pkg/campsite/types/option.go:358 -#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:529 +#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:556 #: pkg/campsite/feature.go:270 pkg/amenity/feature.go:270 msgid "Name must have at least one letter." msgstr "El nom ha de tenir com a mínim una lletra." @@ -1902,12 +1972,12 @@ msgid "Slide image must be an image media type." msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge." #: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217 -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:351 msgid "Email can not be empty." msgstr "No podeu deixar el correu-e en blanc." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218 -#: pkg/booking/public.go:313 +#: pkg/booking/public.go:352 msgid "This email is not valid. It should be like name@domain.com." msgstr "Aquest correu-e no és vàlid. Hauria de ser similar a nom@domini.com." @@ -1964,15 +2034,15 @@ msgstr "El valor del màxim ha de ser un número enter." msgid "Maximum must be equal or greater than minimum." msgstr "El valor del màxim ha de ser igual o superir al del mínim." -#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:554 +#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:581 msgid "Price per night can not be empty." msgstr "No podeu deixar el preu per nit en blanc." -#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:555 +#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:582 msgid "Price per night must be a decimal number." msgstr "El preu per nit ha de ser un número decimal." -#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:556 +#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:583 msgid "Price per night must be zero or greater." msgstr "El preu per nit ha de ser com a mínim zero." @@ -1981,69 +2051,120 @@ msgstr "El preu per nit ha de ser com a mínim zero." msgid "Selected icon is not valid." msgstr "La icona escollida no és vàlida." -#: pkg/campsite/types/admin.go:310 +#: pkg/campsite/types/admin.go:313 msgctxt "input" msgid "Cover image" msgstr "Imatge de portada" -#: pkg/campsite/types/admin.go:311 +#: pkg/campsite/types/admin.go:314 msgctxt "action" msgid "Set campsite type cover" msgstr "Estableix la portada del tipus d’allotjament" -#: pkg/campsite/types/admin.go:531 +#: pkg/campsite/types/admin.go:558 msgid "Check-in can not be empty." msgstr "No podeu deixar l’entrada en blanc." -#: pkg/campsite/types/admin.go:532 +#: pkg/campsite/types/admin.go:559 msgid "Check-out can not be empty." msgstr "No podeu deixar la sortida en blanc." -#: pkg/campsite/types/admin.go:533 +#: pkg/campsite/types/admin.go:560 msgid "Cover image can not be empty." msgstr "No podeu deixar la imatge de portada en blanc." -#: pkg/campsite/types/admin.go:534 +#: pkg/campsite/types/admin.go:561 msgid "Cover image must be an image media type." msgstr "La imatge de portada ha de ser un mèdia de tipus imatge." -#: pkg/campsite/types/admin.go:538 +#: pkg/campsite/types/admin.go:565 msgid "Maximum number of campers can not be empty." msgstr "No podeu deixar el número màxim de persones en blanc." -#: pkg/campsite/types/admin.go:539 +#: pkg/campsite/types/admin.go:566 msgid "Maximum number of campers must be an integer number." msgstr "El número màxim de persones ha de ser enter." -#: pkg/campsite/types/admin.go:540 +#: pkg/campsite/types/admin.go:567 msgid "Maximum number of campers must be one or greater." msgstr "El número màxim de persones no pot ser zero." -#: pkg/campsite/types/admin.go:543 +#: pkg/campsite/types/admin.go:570 msgid "Minimum number of nights can not be empty." msgstr "No podeu deixar el número mínim de nits en blanc." -#: pkg/campsite/types/admin.go:544 +#: pkg/campsite/types/admin.go:571 msgid "Minimum number of nights must be an integer." msgstr "El número mínim de nits ha de ser enter." -#: pkg/campsite/types/admin.go:545 +#: pkg/campsite/types/admin.go:572 msgid "Minimum number of nights must be one or greater." msgstr "El número mínim de nits no pot ser zero." -#: pkg/campsite/types/admin.go:548 +#: pkg/campsite/types/admin.go:575 msgid "Maximum number of nights can not be empty." msgstr "No podeu deixar el número màxim de nits en blanc." -#: pkg/campsite/types/admin.go:549 +#: pkg/campsite/types/admin.go:576 msgid "Maximum number of nights must be an integer." msgstr "El número màxim de nits ha de ser enter." -#: pkg/campsite/types/admin.go:550 +#: pkg/campsite/types/admin.go:577 msgid "Maximum number of nights must be equal or greater than the minimum." msgstr "El valor del número màxim de nits ha de ser igual o superir al del mínim." -#: pkg/campsite/admin.go:275 pkg/booking/public.go:321 +#: pkg/campsite/types/admin.go:586 +msgid "Price per adult can not be empty." +msgstr "No podeu deixar el preu per adult en blanc." + +#: pkg/campsite/types/admin.go:587 +msgid "Price per adult must be a decimal number." +msgstr "El preu per adult ha de ser un número decimal." + +#: pkg/campsite/types/admin.go:588 +msgid "Price per adult must be zero or greater." +msgstr "El preu per adult ha de ser com a mínim zero." + +#: pkg/campsite/types/admin.go:591 +msgid "Price per teenager can not be empty." +msgstr "No podeu deixar el preu per adolescent en blanc." + +#: pkg/campsite/types/admin.go:592 +msgid "Price per teenager must be a decimal number." +msgstr "El preu per adolescent ha de ser un número decimal." + +#: pkg/campsite/types/admin.go:593 +msgid "Price per teenager must be zero or greater." +msgstr "El preu per adolescent ha de ser com a mínim zero." + +#: pkg/campsite/types/admin.go:596 +msgid "Price per child can not be empty." +msgstr "No podeu deixar el preu per nen en blanc." + +#: pkg/campsite/types/admin.go:597 +msgid "Price per child must be a decimal number." +msgstr "El preu per nen ha de ser un número decimal." + +#: pkg/campsite/types/admin.go:598 +msgid "Price per child must be zero or greater." +msgstr "El preu per nen ha de ser com a mínim zero." + +#: pkg/campsite/types/public.go:229 +msgctxt "header" +msgid "Adults" +msgstr "Adults" + +#: pkg/campsite/types/public.go:235 +msgctxt "header" +msgid "Teenagers (aged 11 to 16)" +msgstr "Adolescents (entre 11 i 16 anys)" + +#: pkg/campsite/types/public.go:241 +msgctxt "header" +msgid "Children (aged 2 to 10)" +msgstr "Mainada (entre 2 i 10 anys)" + +#: pkg/campsite/admin.go:275 pkg/booking/public.go:360 msgid "Selected campsite type is not valid." msgstr "El tipus d’allotjament escollit no és vàlid." @@ -2199,7 +2320,7 @@ msgstr "No podeu deixar l’adreça de l’enllaç en blanc." msgid "This web address is not valid. It should be like https://domain.com/." msgstr "Aquesta adreça web no és vàlida. Hauria de ser similar a https://domini.com/." -#: pkg/company/admin.go:200 pkg/booking/public.go:299 +#: pkg/company/admin.go:200 pkg/booking/public.go:338 msgid "Selected country is not valid." msgstr "El país escollit no és vàlid." @@ -2219,11 +2340,11 @@ msgstr "No podeu deixar el NIF en blanc." msgid "This VAT number is not valid." msgstr "Aquest NIF no és vàlid." -#: pkg/company/admin.go:212 pkg/booking/public.go:315 +#: pkg/company/admin.go:212 pkg/booking/public.go:354 msgid "Phone can not be empty." msgstr "No podeu deixar el telèfon en blanc." -#: pkg/company/admin.go:213 pkg/booking/public.go:316 +#: pkg/company/admin.go:213 pkg/booking/public.go:355 msgid "This phone number is not valid." msgstr "Aquest número de telèfon no és vàlid." @@ -2243,7 +2364,7 @@ msgstr "No podeu deixar la província en blanc." msgid "Postal code can not be empty." msgstr "No podeu deixar el codi postal en blanc." -#: pkg/company/admin.go:227 pkg/booking/public.go:308 +#: pkg/company/admin.go:227 pkg/booking/public.go:347 msgid "This postal code is not valid." msgstr "Aquest codi postal no és vàlid." @@ -2283,6 +2404,31 @@ msgstr "No podeu deixar el fitxer del mèdia en blanc." msgid "Filename can not be empty." msgstr "No podeu deixar el nom del fitxer en blanc." +#: pkg/booking/cart.go:171 +msgctxt "cart" +msgid "Night" +msgstr "Nit" + +#: pkg/booking/cart.go:172 +msgctxt "cart" +msgid "Adult" +msgstr "Adult" + +#: pkg/booking/cart.go:173 +msgctxt "cart" +msgid "Teenager" +msgstr "Adolescent" + +#: pkg/booking/cart.go:174 +msgctxt "cart" +msgid "Child" +msgstr "Nen" + +#: pkg/booking/cart.go:193 +msgctxt "cart" +msgid "Tourist tax" +msgstr "Impost turístic" + #: pkg/booking/admin.go:149 msgctxt "filename" msgid "bookings.ods" @@ -2340,54 +2486,102 @@ msgstr "La integració escollida no és vàlida." msgid "The merchant key is not valid." msgstr "Aquesta clau del comerç no és vàlid." -#: pkg/booking/public.go:303 +#: pkg/booking/public.go:342 msgid "Full name can not be empty." msgstr "No podeu deixar el nom i els cognoms en blanc." -#: pkg/booking/public.go:304 +#: pkg/booking/public.go:343 msgid "Full name must have at least one letter." msgstr "El nom i els cognoms han de tenir com a mínim una lletra." -#: pkg/booking/public.go:322 +#: pkg/booking/public.go:361 msgid "Arrival date can not be empty" msgstr "No podeu deixar la data d’arribada en blanc." -#: pkg/booking/public.go:323 +#: pkg/booking/public.go:362 msgid "Arrival date must be a valid date." msgstr "La data d’arribada ha de ser una data vàlida." -#: pkg/booking/public.go:327 +#: pkg/booking/public.go:366 msgid "Departure date can not be empty" msgstr "No podeu deixar la data de sortida en blanc." -#: pkg/booking/public.go:328 +#: pkg/booking/public.go:367 msgid "Departure date must be a valid date." msgstr "La data de sortida ha de ser una data vàlida." -#: pkg/booking/public.go:329 +#: pkg/booking/public.go:368 msgid "The departure date must be after the arrival date." msgstr "La data de sortida ha de ser posterior a la d’arribada." -#: pkg/booking/public.go:332 +#: pkg/booking/public.go:372 +msgid "Number of adults can not be empty" +msgstr "No podeu deixar el número d’adults en blanc." + +#: pkg/booking/public.go:373 +msgid "Number of adults must be an integer." +msgstr "El número d’adults ha de ser enter." + +#: pkg/booking/public.go:374 +msgid "There must be at least one adult." +msgstr "Hi ha d’haver com a mínim un adult." + +#: pkg/booking/public.go:377 +msgid "Number of teenagers can not be empty" +msgstr "No podeu deixar el número d’adolescents en blanc." + +#: pkg/booking/public.go:378 +msgid "Number of teenagers must be an integer." +msgstr "El número d’adolescents ha de ser enter." + +#: pkg/booking/public.go:379 +msgid "Number of teenagers can not be negative." +msgstr "El número d’adolescents no pot ser negatiu." + +#: pkg/booking/public.go:382 +msgid "Number of children can not be empty" +msgstr "No podeu deixar el número de nens en blanc." + +#: pkg/booking/public.go:383 +msgid "Number of children must be an integer." +msgstr "El número de nens ha de ser enter." + +#: pkg/booking/public.go:384 +msgid "Number of children can not be negative." +msgstr "El número de nens no pot ser negatiu." + +#: pkg/booking/public.go:387 +msgid "Number of dogs can not be empty" +msgstr "No podeu deixar el número de gossos en blanc." + +#: pkg/booking/public.go:388 +msgid "Number of dogs must be an integer." +msgstr "El número de gossos ha de ser enter." + +#: pkg/booking/public.go:389 +msgid "Number of dogs can not be negative." +msgstr "El número de gossos no pot ser negatiu." + +#: pkg/booking/public.go:392 msgid "It is mandatory to agree to the reservation conditions." msgstr "És obligatori acceptar les condicions de reserves." -#: pkg/booking/public.go:335 +#: pkg/booking/public.go:395 #, c-format msgid "%s can not be empty" msgstr "No podeu deixar %s en blanc." -#: pkg/booking/public.go:336 +#: pkg/booking/public.go:396 #, c-format msgid "%s must be an integer." msgstr "%s ha de ser un número enter." -#: pkg/booking/public.go:337 +#: pkg/booking/public.go:397 #, c-format msgid "%s must be %d or greater." msgstr "El valor de %s ha de ser com a mínim %d." -#: pkg/booking/public.go:338 +#: pkg/booking/public.go:398 #, c-format msgid "%s must be at most %d." msgstr "El valor de %s ha de ser com a màxim %d." @@ -2458,55 +2652,15 @@ msgstr "El valor de %s ha de ser com a màxim %d." #~ msgid "Party Details" #~ msgstr "Dades dels visitants" -#~ msgctxt "input" -#~ msgid "Adults" -#~ msgstr "Adults" - -#~ msgctxt "input" -#~ msgid "Teenagers (from 11 to 16 years old)" -#~ msgstr "Adolescents (entre 11 i 16 anys)" - -#~ msgctxt "input" -#~ msgid "Children (up to 10 years old)" -#~ msgstr "Nens (fins a 10 anys)" - -#~ msgctxt "input" -#~ msgid "Dogs" -#~ msgstr "Gossos" - -#~ msgid "Number of adults can not be empty" -#~ msgstr "No podeu deixar el número d’adults en blanc." - -#~ msgid "Number of adults must be an integer." -#~ msgstr "El número d’adults ha de ser enter." - #~ msgid "Number of adults must be one or greater." #~ msgstr "El número d’adults no pot ser zero." -#~ msgid "Number of teenagers can not be empty" -#~ msgstr "No podeu deixar el número d’adolescents en blanc." - -#~ msgid "Number of teenagers must be an integer." -#~ msgstr "El número d’adolescents ha de ser enter." - #~ msgid "Number of teenagers must be zero or greater." #~ msgstr "El número d’adolescents ha de ser com a mínim zero." -#~ msgid "Number of children can not be empty" -#~ msgstr "No podeu deixar el número de nens en blanc." - -#~ msgid "Number of children must be an integer." -#~ msgstr "El número de nens ha de ser enter." - #~ msgid "Number of children must be zero or greater." #~ msgstr "El número de nens ha de ser com a mínim zero." -#~ msgid "Number of dogs can not be empty" -#~ msgstr "No podeu deixar el número de gossos en blanc." - -#~ msgid "Number of dogs must be an integer." -#~ msgstr "El número de gossos ha de ser enter." - #~ msgid "Number of dogs must be zero or greater." #~ msgstr "El número de gossos ha de ser com a mínim zero." diff --git a/po/es.po b/po/es.po index 282a0e0..490e14a 100644 --- a/po/es.po +++ b/po/es.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-02-02 21:57+0100\n" +"POT-Creation-Date: 2024-02-04 06:23+0100\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -94,7 +94,7 @@ msgid "The campsite offers many different services." msgstr "El camping dispone de varios servicios." #: web/templates/public/amenity.gohtml:39 -#: web/templates/public/campsite/type.gohtml:114 +#: web/templates/public/campsite/type.gohtml:113 #: web/templates/public/campsite/page.gohtml:39 msgctxt "title" msgid "Features" @@ -164,7 +164,7 @@ msgid "Check-out Date" msgstr "Fecha de salida" #: web/templates/public/campsite/type.gohtml:56 -#: web/templates/public/booking.gohtml:171 +#: web/templates/public/booking/cart.gohtml:25 msgctxt "action" msgid "Book" msgstr "Reservar" @@ -182,61 +182,60 @@ msgctxt "title" msgid "Prices" msgstr "Precios" -#: web/templates/public/campsite/type.gohtml:87 -#: web/templates/public/campsite/type.gohtml:93 -msgid "%s: %s €/night" -msgstr "%s: %s €/noche" +#: web/templates/public/campsite/type.gohtml:88 +msgid "%s: %s/night" +msgstr "%s: %s/noche" -#: web/templates/public/campsite/type.gohtml:89 -msgid "%s €/night" -msgstr "%s €/noche" +#: web/templates/public/campsite/type.gohtml:90 +msgid "%s/night" +msgstr "%s/noche" -#: web/templates/public/campsite/type.gohtml:96 +#: web/templates/public/campsite/type.gohtml:95 msgid "*Minimum %d nights per stay" msgstr "*Mínimo %d noches por estancia" -#: web/templates/public/campsite/type.gohtml:101 +#: web/templates/public/campsite/type.gohtml:100 msgid "10 % VAT included." msgstr "IVA del 10 % incluido." -#: web/templates/public/campsite/type.gohtml:102 +#: web/templates/public/campsite/type.gohtml:101 msgid "Tourist tax: %s/night per person aged 17 or older." -msgstr "Impuesto turístico: %s/noche por persona mayor de de 16 años." +msgstr "Impuesto turístico: %s/noche por persona mayor de 16 años." -#: web/templates/public/campsite/type.gohtml:104 +#: web/templates/public/campsite/type.gohtml:103 msgid "Dogs: %s/night, tied, accompanied, and minimal barking." msgstr "Perros: %s/noche, atados, acompañados y con mínimo de ladrido." -#: web/templates/public/campsite/type.gohtml:106 +#: web/templates/public/campsite/type.gohtml:105 msgid "No dogs allowed." msgstr "No se permiten perros" -#: web/templates/public/campsite/type.gohtml:125 +#: web/templates/public/campsite/type.gohtml:124 msgctxt "title" msgid "Info" msgstr "Información" -#: web/templates/public/campsite/type.gohtml:129 +#: web/templates/public/campsite/type.gohtml:128 msgctxt "title" msgid "Facilities" msgstr "Equipamiento" -#: web/templates/public/campsite/type.gohtml:133 +#: web/templates/public/campsite/type.gohtml:132 msgctxt "title" msgid "Description" msgstr "Descripción" -#: web/templates/public/campsite/type.gohtml:137 +#: web/templates/public/campsite/type.gohtml:136 msgctxt "title" msgid "Additional Information" msgstr "Información adicional" -#: web/templates/public/campsite/type.gohtml:140 +#: web/templates/public/campsite/type.gohtml:139 msgctxt "time" msgid "Check-in" msgstr "Entrada" -#: web/templates/public/campsite/type.gohtml:144 +#: web/templates/public/campsite/type.gohtml:143 msgctxt "time" msgid "Check-out" msgstr "Salida" @@ -482,99 +481,6 @@ msgctxt "legend" msgid "Faucet" msgstr "Grifo" -#: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12 -#: web/templates/public/layout.gohtml:70 -msgctxt "title" -msgid "Booking" -msgstr "Reserva" - -#: web/templates/public/booking.gohtml:16 -msgctxt "title" -msgid "Customer Details" -msgstr "Detalles del cliente" - -#: web/templates/public/booking.gohtml:19 -msgctxt "input" -msgid "Full name" -msgstr "Nombre y apellidos" - -#: web/templates/public/booking.gohtml:28 -msgctxt "input" -msgid "Address (optional)" -msgstr "Dirección (opcional)" - -#: web/templates/public/booking.gohtml:37 -msgctxt "input" -msgid "Postcode (optional)" -msgstr "Código postal (opcional)" - -#: web/templates/public/booking.gohtml:46 -msgctxt "input" -msgid "Town or village (optional)" -msgstr "Población (opcional)" - -#: web/templates/public/booking.gohtml:55 -#: web/templates/admin/taxDetails.gohtml:101 -msgctxt "input" -msgid "Country" -msgstr "País" - -#: web/templates/public/booking.gohtml:58 -msgid "Choose a country" -msgstr "Escoja un país" - -#: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:27 -#: web/templates/admin/profile.gohtml:38 -#: web/templates/admin/taxDetails.gohtml:53 -msgctxt "input" -msgid "Email" -msgstr "Correo-e" - -#: web/templates/public/booking.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:45 -msgctxt "input" -msgid "Phone" -msgstr "Teléfono" - -#: web/templates/public/booking.gohtml:84 -msgctxt "title" -msgid "Accommodation" -msgstr "Alojamientos" - -#: web/templates/public/booking.gohtml:101 -msgctxt "input" -msgid "Area preferences (optional)" -msgstr "Preferencias de área (opcional)" - -#: web/templates/public/booking.gohtml:108 -msgid "Campground map" -msgstr "Mapa del camping" - -#: web/templates/public/booking.gohtml:126 -msgctxt "title" -msgid "Booking Period" -msgstr "Periodo de reserva" - -#: web/templates/public/booking.gohtml:129 -msgctxt "input" -msgid "Arrival date" -msgstr "Fecha de llegada" - -#: web/templates/public/booking.gohtml:139 -msgctxt "input" -msgid "Departure date" -msgstr "Fecha de salida" - -#: web/templates/public/booking.gohtml:151 -msgctxt "input" -msgid "ACSI card? (optional)" -msgstr "¿Tarjeta ACSI? (opcional)" - -#: web/templates/public/booking.gohtml:158 -msgctxt "input" -msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" -msgstr "He leído y acepto %[1]slas condiciones de reserva%[2]s" - #: web/templates/public/layout.gohtml:12 web/templates/public/layout.gohtml:48 msgid "Campsite Montagut" msgstr "Camping Montagut" @@ -608,6 +514,13 @@ msgctxt "title" msgid "Campsites" msgstr "Alojamientos" +#: web/templates/public/layout.gohtml:70 +#: web/templates/public/booking/form.gohtml:7 +#: web/templates/public/booking/form.gohtml:16 +msgctxt "title" +msgid "Booking" +msgstr "Reserva" + #: web/templates/public/layout.gohtml:91 msgctxt "title" msgid "Sections" @@ -622,6 +535,123 @@ msgstr "Apertura" msgid "RTC #%s" msgstr " RTC %s" +#: web/templates/public/booking/form.gohtml:29 +msgctxt "title" +msgid "Accommodation" +msgstr "Alojamientos" + +#: web/templates/public/booking/form.gohtml:43 +msgctxt "title" +msgid "Booking Period" +msgstr "Periodo de reserva" + +#: web/templates/public/booking/form.gohtml:46 +msgctxt "input" +msgid "Arrival date" +msgstr "Fecha de llegada" + +#: web/templates/public/booking/form.gohtml:57 +msgctxt "input" +msgid "Departure date" +msgstr "Fecha de salida" + +#: web/templates/public/booking/form.gohtml:72 +msgctxt "title" +msgid "Guests" +msgstr "Huéspedes" + +#: web/templates/public/booking/form.gohtml:76 +msgctxt "input" +msgid "Adults aged 17 or older" +msgstr "Adultos de 17 años o más" + +#: web/templates/public/booking/form.gohtml:86 +msgctxt "input" +msgid "Teenagers from 11 to 16 years old" +msgstr "Adolescentes de 11 a 16 años" + +#: web/templates/public/booking/form.gohtml:96 +msgctxt "input" +msgid "Children from 2 to 10 years old" +msgstr "Niños de 2 a 10 años" + +#: web/templates/public/booking/form.gohtml:106 +msgctxt "input" +msgid "Dogs" +msgstr "Perros" + +#: web/templates/public/booking/form.gohtml:127 +msgctxt "input" +msgid "Area preferences (optional)" +msgstr "Preferencias de área (opcional)" + +#: web/templates/public/booking/form.gohtml:129 +msgid "Campground map" +msgstr "Mapa del camping" + +#: web/templates/public/booking/form.gohtml:156 +msgctxt "title" +msgid "Customer Details" +msgstr "Detalles del cliente" + +#: web/templates/public/booking/form.gohtml:159 +msgctxt "input" +msgid "Full name" +msgstr "Nombre y apellidos" + +#: web/templates/public/booking/form.gohtml:168 +msgctxt "input" +msgid "Address (optional)" +msgstr "Dirección (opcional)" + +#: web/templates/public/booking/form.gohtml:177 +msgctxt "input" +msgid "Postcode (optional)" +msgstr "Código postal (opcional)" + +#: web/templates/public/booking/form.gohtml:186 +msgctxt "input" +msgid "Town or village (optional)" +msgstr "Población (opcional)" + +#: web/templates/public/booking/form.gohtml:195 +#: web/templates/admin/taxDetails.gohtml:101 +msgctxt "input" +msgid "Country" +msgstr "País" + +#: web/templates/public/booking/form.gohtml:198 +msgid "Choose a country" +msgstr "Escoja un país" + +#: web/templates/public/booking/form.gohtml:206 +#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38 +#: web/templates/admin/taxDetails.gohtml:53 +msgctxt "input" +msgid "Email" +msgstr "Correo-e" + +#: web/templates/public/booking/form.gohtml:215 +#: web/templates/admin/taxDetails.gohtml:45 +msgctxt "input" +msgid "Phone" +msgstr "Teléfono" + +#: web/templates/public/booking/form.gohtml:226 +msgctxt "input" +msgid "ACSI card? (optional)" +msgstr "¿Tarjeta ACSI? (opcional)" + +#: web/templates/public/booking/form.gohtml:233 +msgctxt "input" +msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" +msgstr "He leído y acepto %[1]slas condiciones de reserva%[2]s" + +#: web/templates/public/booking/cart.gohtml:14 +msgctxt "cart" +msgid "Total" +msgstr "Total" + #: web/templates/admin/legal/form.gohtml:8 #: web/templates/admin/legal/form.gohtml:29 msgctxt "title" @@ -674,7 +704,7 @@ msgstr "Contenido" #: web/templates/admin/campsite/form.gohtml:92 #: web/templates/admin/campsite/type/feature/form.gohtml:74 #: web/templates/admin/campsite/type/carousel/form.gohtml:59 -#: web/templates/admin/campsite/type/form.gohtml:228 +#: web/templates/admin/campsite/type/form.gohtml:277 #: web/templates/admin/campsite/type/option/form.gohtml:90 #: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/services/form.gohtml:81 @@ -696,7 +726,7 @@ msgstr "Actualizar" #: web/templates/admin/campsite/form.gohtml:94 #: web/templates/admin/campsite/type/feature/form.gohtml:76 #: web/templates/admin/campsite/type/carousel/form.gohtml:61 -#: web/templates/admin/campsite/type/form.gohtml:230 +#: web/templates/admin/campsite/type/form.gohtml:279 #: web/templates/admin/campsite/type/option/form.gohtml:92 #: web/templates/admin/season/form.gohtml:75 #: web/templates/admin/services/form.gohtml:83 @@ -1139,35 +1169,75 @@ msgctxt "input" msgid "Dogs allowed" msgstr "Se permiten perros" +#: web/templates/admin/campsite/type/form.gohtml:147 +msgctxt "header" +msgid "Season" +msgstr "Temporada" + +#: web/templates/admin/campsite/type/form.gohtml:148 +msgctxt "header" +msgid "Price per night" +msgstr "Precio por noche" + #: web/templates/admin/campsite/type/form.gohtml:149 +msgctxt "header" +msgid "Price per adult (> 16)" +msgstr "Precio por adulto (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:150 +msgctxt "header" +msgid "Price per teenager (11–16)" +msgstr "Precio por adolescente (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:151 +msgctxt "header" +msgid "Price per child (2–10)" +msgstr "Precio por niño (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:161 #: web/templates/admin/campsite/type/option/form.gohtml:76 msgctxt "input" msgid "Price per night" msgstr "Precio por noche" -#: web/templates/admin/campsite/type/form.gohtml:161 +#: web/templates/admin/campsite/type/form.gohtml:172 +msgctxt "input" +msgid "Price per adult (> 16)" +msgstr "Precio por adulto (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:183 +msgctxt "input" +msgid "Price per teenager (11–16)" +msgstr "Precio por adolescente (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:194 +msgctxt "input" +msgid "Price per child (2–10)" +msgstr "Precio por niño (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:210 msgctxt "input" msgid "Spiel" msgstr "Introducción" -#: web/templates/admin/campsite/type/form.gohtml:174 +#: web/templates/admin/campsite/type/form.gohtml:223 msgctxt "input" msgid "Info" msgstr "Información" -#: web/templates/admin/campsite/type/form.gohtml:187 +#: web/templates/admin/campsite/type/form.gohtml:236 msgctxt "input" msgid "Facilities" msgstr "Equipamento" -#: web/templates/admin/campsite/type/form.gohtml:200 +#: web/templates/admin/campsite/type/form.gohtml:249 #: web/templates/admin/services/form.gohtml:66 #: web/templates/admin/surroundings/form.gohtml:54 msgctxt "input" msgid "Description" msgstr "Descripción" -#: web/templates/admin/campsite/type/form.gohtml:213 +#: web/templates/admin/campsite/type/form.gohtml:262 msgctxt "input" msgid "Additional Information" msgstr "Información adicional" @@ -1864,7 +1934,7 @@ msgid "No booking found." msgstr "No se ha encontrado ninguna reserva." #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 -#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:528 +#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:555 #: pkg/campsite/feature.go:269 pkg/season/admin.go:412 #: pkg/services/admin.go:316 pkg/surroundings/admin.go:340 #: pkg/amenity/feature.go:269 pkg/amenity/admin.go:283 @@ -1872,7 +1942,7 @@ msgid "Name can not be empty." msgstr "No podéis dejar el nombre en blanco." #: pkg/legal/admin.go:259 pkg/campsite/types/option.go:358 -#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:529 +#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:556 #: pkg/campsite/feature.go:270 pkg/amenity/feature.go:270 msgid "Name must have at least one letter." msgstr "El nombre tiene que tener como mínimo una letra." @@ -1902,12 +1972,12 @@ msgid "Slide image must be an image media type." msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen." #: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217 -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:351 msgid "Email can not be empty." msgstr "No podéis dejar el correo-e en blanco." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218 -#: pkg/booking/public.go:313 +#: pkg/booking/public.go:352 msgid "This email is not valid. It should be like name@domain.com." msgstr "Este correo-e no es válido. Tiene que ser parecido a nombre@dominio.com." @@ -1964,15 +2034,15 @@ msgstr "El valor del máximo tiene que ser un número entero." msgid "Maximum must be equal or greater than minimum." msgstr "El valor del máximo tiene que ser igual o mayor al del mínimo." -#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:554 +#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:581 msgid "Price per night can not be empty." msgstr "No podéis dejar el precio por noche en blanco." -#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:555 +#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:582 msgid "Price per night must be a decimal number." msgstr "El precio por noche tiene que ser un número decimal." -#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:556 +#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:583 msgid "Price per night must be zero or greater." msgstr "El precio por noche tiene que ser como mínimo cero." @@ -1981,69 +2051,120 @@ msgstr "El precio por noche tiene que ser como mínimo cero." msgid "Selected icon is not valid." msgstr "El icono escogido no es válido." -#: pkg/campsite/types/admin.go:310 +#: pkg/campsite/types/admin.go:313 msgctxt "input" msgid "Cover image" msgstr "Imagen de portada" -#: pkg/campsite/types/admin.go:311 +#: pkg/campsite/types/admin.go:314 msgctxt "action" msgid "Set campsite type cover" msgstr "Establecer la portada del tipo de alojamiento" -#: pkg/campsite/types/admin.go:531 +#: pkg/campsite/types/admin.go:558 msgid "Check-in can not be empty." msgstr "No podéis dejar la entrada en blanco." -#: pkg/campsite/types/admin.go:532 +#: pkg/campsite/types/admin.go:559 msgid "Check-out can not be empty." msgstr "No podéis dejar la salida en blanco." -#: pkg/campsite/types/admin.go:533 +#: pkg/campsite/types/admin.go:560 msgid "Cover image can not be empty." msgstr "No podéis dejar la imagen de portada en blanco." -#: pkg/campsite/types/admin.go:534 +#: pkg/campsite/types/admin.go:561 msgid "Cover image must be an image media type." msgstr "La imagen de portada tiene que ser un medio de tipo imagen." -#: pkg/campsite/types/admin.go:538 +#: pkg/campsite/types/admin.go:565 msgid "Maximum number of campers can not be empty." msgstr "No podéis dejar el número máximo de personas en blanco." -#: pkg/campsite/types/admin.go:539 +#: pkg/campsite/types/admin.go:566 msgid "Maximum number of campers must be an integer number." msgstr "El número máximo de personas tiene que ser entero." -#: pkg/campsite/types/admin.go:540 +#: pkg/campsite/types/admin.go:567 msgid "Maximum number of campers must be one or greater." msgstr "El número máximo de personas no puede ser cero." -#: pkg/campsite/types/admin.go:543 +#: pkg/campsite/types/admin.go:570 msgid "Minimum number of nights can not be empty." msgstr "No podéis dejar el número mínimo de noches en blanco." -#: pkg/campsite/types/admin.go:544 +#: pkg/campsite/types/admin.go:571 msgid "Minimum number of nights must be an integer." msgstr "El número mínimo de noches tiene que ser entero." -#: pkg/campsite/types/admin.go:545 +#: pkg/campsite/types/admin.go:572 msgid "Minimum number of nights must be one or greater." msgstr "El número mínimo de noches no puede ser cero." -#: pkg/campsite/types/admin.go:548 +#: pkg/campsite/types/admin.go:575 msgid "Maximum number of nights can not be empty." msgstr "No podéis dejar el número máximo de noches en blanco." -#: pkg/campsite/types/admin.go:549 +#: pkg/campsite/types/admin.go:576 msgid "Maximum number of nights must be an integer." msgstr "El número máximo de noches tiene que ser entero." -#: pkg/campsite/types/admin.go:550 +#: pkg/campsite/types/admin.go:577 msgid "Maximum number of nights must be equal or greater than the minimum." msgstr "El valor del número máximo de noches tiene que ser igual o mayor al del mínimo." -#: pkg/campsite/admin.go:275 pkg/booking/public.go:321 +#: pkg/campsite/types/admin.go:586 +msgid "Price per adult can not be empty." +msgstr "No podéis dejar el precio por adulto en blanco." + +#: pkg/campsite/types/admin.go:587 +msgid "Price per adult must be a decimal number." +msgstr "El precio por adulto tiene que ser un número decimal." + +#: pkg/campsite/types/admin.go:588 +msgid "Price per adult must be zero or greater." +msgstr "El precio por adulto tiene que ser como mínimo cero." + +#: pkg/campsite/types/admin.go:591 +msgid "Price per teenager can not be empty." +msgstr "No podéis dejar el precio por adolescente en blanco." + +#: pkg/campsite/types/admin.go:592 +msgid "Price per teenager must be a decimal number." +msgstr "El precio por adolescente tiene que ser un número decimal." + +#: pkg/campsite/types/admin.go:593 +msgid "Price per teenager must be zero or greater." +msgstr "El precio por adolescente tiene que ser como mínimo cero." + +#: pkg/campsite/types/admin.go:596 +msgid "Price per child can not be empty." +msgstr "No podéis dejar el precio por niño en blanco." + +#: pkg/campsite/types/admin.go:597 +msgid "Price per child must be a decimal number." +msgstr "El precio por niño tiene que ser un número decimal." + +#: pkg/campsite/types/admin.go:598 +msgid "Price per child must be zero or greater." +msgstr "El precio por niño tiene que ser como mínimo cero." + +#: pkg/campsite/types/public.go:229 +msgctxt "header" +msgid "Adults" +msgstr "Adultos" + +#: pkg/campsite/types/public.go:235 +msgctxt "header" +msgid "Teenagers (aged 11 to 16)" +msgstr "Adolescentes (de 11 a 16 años)" + +#: pkg/campsite/types/public.go:241 +msgctxt "header" +msgid "Children (aged 2 to 10)" +msgstr "Niños (de 2 a 10 años)" + +#: pkg/campsite/admin.go:275 pkg/booking/public.go:360 msgid "Selected campsite type is not valid." msgstr "El tipo de alojamiento escogido no es válido." @@ -2199,7 +2320,7 @@ msgstr "No podéis dejar la dirección del enlace en blanco." msgid "This web address is not valid. It should be like https://domain.com/." msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/." -#: pkg/company/admin.go:200 pkg/booking/public.go:299 +#: pkg/company/admin.go:200 pkg/booking/public.go:338 msgid "Selected country is not valid." msgstr "El país escogido no es válido." @@ -2219,11 +2340,11 @@ msgstr "No podéis dejar el NIF en blanco." msgid "This VAT number is not valid." msgstr "Este NIF no es válido." -#: pkg/company/admin.go:212 pkg/booking/public.go:315 +#: pkg/company/admin.go:212 pkg/booking/public.go:354 msgid "Phone can not be empty." msgstr "No podéis dejar el teléfono en blanco." -#: pkg/company/admin.go:213 pkg/booking/public.go:316 +#: pkg/company/admin.go:213 pkg/booking/public.go:355 msgid "This phone number is not valid." msgstr "Este teléfono no es válido." @@ -2243,7 +2364,7 @@ msgstr "No podéis dejar la provincia en blanco." msgid "Postal code can not be empty." msgstr "No podéis dejar el código postal en blanco." -#: pkg/company/admin.go:227 pkg/booking/public.go:308 +#: pkg/company/admin.go:227 pkg/booking/public.go:347 msgid "This postal code is not valid." msgstr "Este código postal no es válido." @@ -2283,6 +2404,31 @@ msgstr "No podéis dejar el archivo del medio en blanco." msgid "Filename can not be empty." msgstr "No podéis dejar el nombre del archivo en blanco." +#: pkg/booking/cart.go:171 +msgctxt "cart" +msgid "Night" +msgstr "Noche" + +#: pkg/booking/cart.go:172 +msgctxt "cart" +msgid "Adult" +msgstr "Adulto" + +#: pkg/booking/cart.go:173 +msgctxt "cart" +msgid "Teenager" +msgstr "Adolescente" + +#: pkg/booking/cart.go:174 +msgctxt "cart" +msgid "Child" +msgstr "Niño" + +#: pkg/booking/cart.go:193 +msgctxt "cart" +msgid "Tourist tax" +msgstr "Impuesto turístico" + #: pkg/booking/admin.go:149 msgctxt "filename" msgid "bookings.ods" @@ -2340,54 +2486,102 @@ msgstr "La integración escogida no es válida." msgid "The merchant key is not valid." msgstr "Esta clave del comercio no es válida." -#: pkg/booking/public.go:303 +#: pkg/booking/public.go:342 msgid "Full name can not be empty." msgstr "No podéis dejar el nombre y los apellidos en blanco." -#: pkg/booking/public.go:304 +#: pkg/booking/public.go:343 msgid "Full name must have at least one letter." msgstr "El nombre y los apellidos tienen que tener como mínimo una letra." -#: pkg/booking/public.go:322 +#: pkg/booking/public.go:361 msgid "Arrival date can not be empty" msgstr "No podéis dejar la fecha de llegada en blanco." -#: pkg/booking/public.go:323 +#: pkg/booking/public.go:362 msgid "Arrival date must be a valid date." msgstr "La fecha de llegada tiene que ser una fecha válida." -#: pkg/booking/public.go:327 +#: pkg/booking/public.go:366 msgid "Departure date can not be empty" msgstr "No podéis dejar la fecha de partida en blanco." -#: pkg/booking/public.go:328 +#: pkg/booking/public.go:367 msgid "Departure date must be a valid date." msgstr "La fecha de partida tiene que ser una fecha válida." -#: pkg/booking/public.go:329 +#: pkg/booking/public.go:368 msgid "The departure date must be after the arrival date." msgstr "La fecha de partida tiene que ser posterior a la de llegada." -#: pkg/booking/public.go:332 +#: pkg/booking/public.go:372 +msgid "Number of adults can not be empty" +msgstr "No podéis dejar el número de adultos blanco." + +#: pkg/booking/public.go:373 +msgid "Number of adults must be an integer." +msgstr "El número de adultos tiene que ser entero." + +#: pkg/booking/public.go:374 +msgid "There must be at least one adult." +msgstr "Tiene que haber como mínimo un adulto." + +#: pkg/booking/public.go:377 +msgid "Number of teenagers can not be empty" +msgstr "No podéis dejar el número de adolescentes en blanco." + +#: pkg/booking/public.go:378 +msgid "Number of teenagers must be an integer." +msgstr "El número de adolescentes tiene que ser entero." + +#: pkg/booking/public.go:379 +msgid "Number of teenagers can not be negative." +msgstr "El número de adolescentes no puede ser negativo." + +#: pkg/booking/public.go:382 +msgid "Number of children can not be empty" +msgstr "No podéis dejar el número de niños en blanco." + +#: pkg/booking/public.go:383 +msgid "Number of children must be an integer." +msgstr "El número de niños tiene que ser entero." + +#: pkg/booking/public.go:384 +msgid "Number of children can not be negative." +msgstr "El número de niños no puede ser negativo." + +#: pkg/booking/public.go:387 +msgid "Number of dogs can not be empty" +msgstr "No podéis dejar el número de perros en blanco." + +#: pkg/booking/public.go:388 +msgid "Number of dogs must be an integer." +msgstr "El número de perros tiene que ser entero." + +#: pkg/booking/public.go:389 +msgid "Number of dogs can not be negative." +msgstr "El número de perros no puede ser negativo." + +#: pkg/booking/public.go:392 msgid "It is mandatory to agree to the reservation conditions." msgstr "Es obligatorio aceptar las condiciones de reserva." -#: pkg/booking/public.go:335 +#: pkg/booking/public.go:395 #, c-format msgid "%s can not be empty" msgstr "No podéis dejar %s en blanco." -#: pkg/booking/public.go:336 +#: pkg/booking/public.go:396 #, c-format msgid "%s must be an integer." msgstr "%s tiene que ser un número entero." -#: pkg/booking/public.go:337 +#: pkg/booking/public.go:397 #, c-format msgid "%s must be %d or greater." msgstr "%s tiene que ser como mínimo %d." -#: pkg/booking/public.go:338 +#: pkg/booking/public.go:398 #, c-format msgid "%s must be at most %d." msgstr "%s tiene que ser como máximo %d" @@ -2458,55 +2652,15 @@ msgstr "%s tiene que ser como máximo %d" #~ msgid "Party Details" #~ msgstr "Datos de los visitantes" -#~ msgctxt "input" -#~ msgid "Adults" -#~ msgstr "Adultos" - -#~ msgctxt "input" -#~ msgid "Teenagers (from 11 to 16 years old)" -#~ msgstr "Adolescentes (de 11 a 16 años)" - -#~ msgctxt "input" -#~ msgid "Children (up to 10 years old)" -#~ msgstr "Niños (hasta 10 años)" - -#~ msgctxt "input" -#~ msgid "Dogs" -#~ msgstr "Perros" - -#~ msgid "Number of adults can not be empty" -#~ msgstr "No podéis dejar el número de adultos blanco." - -#~ msgid "Number of adults must be an integer." -#~ msgstr "El número de adultos tiene que ser entero." - #~ msgid "Number of adults must be one or greater." #~ msgstr "El número de adultos no puede ser cero." -#~ msgid "Number of teenagers can not be empty" -#~ msgstr "No podéis dejar el número de adolescentes en blanco." - -#~ msgid "Number of teenagers must be an integer." -#~ msgstr "El número de adolescentes tiene que ser entero." - #~ msgid "Number of teenagers must be zero or greater." #~ msgstr "El número de adolescentes tiene que ser como mínimo cero." -#~ msgid "Number of children can not be empty" -#~ msgstr "No podéis dejar el número de niños en blanco." - -#~ msgid "Number of children must be an integer." -#~ msgstr "El número de niños tiene que ser entero." - #~ msgid "Number of children must be zero or greater." #~ msgstr "El número de niños tiene que ser como mínimo cero." -#~ msgid "Number of dogs can not be empty" -#~ msgstr "No podéis dejar el número de perros en blanco." - -#~ msgid "Number of dogs must be an integer." -#~ msgstr "El número de perros tiene que ser entero." - #~ msgid "Number of dogs must be zero or greater." #~ msgstr "El número de perros tiene que ser como mínimo cero." diff --git a/po/fr.po b/po/fr.po index f264133..e4ba7be 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2024-02-02 21:57+0100\n" +"POT-Creation-Date: 2024-02-04 06:23+0100\n" "PO-Revision-Date: 2023-12-20 10:13+0100\n" "Last-Translator: Oriol Carbonell \n" "Language-Team: French \n" @@ -95,7 +95,7 @@ msgid "The campsite offers many different services." msgstr "Le camping propose de nombreux services différents." #: web/templates/public/amenity.gohtml:39 -#: web/templates/public/campsite/type.gohtml:114 +#: web/templates/public/campsite/type.gohtml:113 #: web/templates/public/campsite/page.gohtml:39 msgctxt "title" msgid "Features" @@ -165,7 +165,7 @@ msgid "Check-out Date" msgstr "Date de départ" #: web/templates/public/campsite/type.gohtml:56 -#: web/templates/public/booking.gohtml:171 +#: web/templates/public/booking/cart.gohtml:25 msgctxt "action" msgid "Book" msgstr "Réserver" @@ -183,61 +183,60 @@ msgctxt "title" msgid "Prices" msgstr "Prix" -#: web/templates/public/campsite/type.gohtml:87 -#: web/templates/public/campsite/type.gohtml:93 -msgid "%s: %s €/night" -msgstr "%s : %s €/nuit" +#: web/templates/public/campsite/type.gohtml:88 +msgid "%s: %s/night" +msgstr "%s : %s/nuit" -#: web/templates/public/campsite/type.gohtml:89 -msgid "%s €/night" -msgstr "%s €/nuit" +#: web/templates/public/campsite/type.gohtml:90 +msgid "%s/night" +msgstr "%s/nuit" -#: web/templates/public/campsite/type.gohtml:96 +#: web/templates/public/campsite/type.gohtml:95 msgid "*Minimum %d nights per stay" msgstr "*Minimum %d nuits par séjour" -#: web/templates/public/campsite/type.gohtml:101 +#: web/templates/public/campsite/type.gohtml:100 msgid "10 % VAT included." msgstr "10 % TVA incluse." -#: web/templates/public/campsite/type.gohtml:102 +#: web/templates/public/campsite/type.gohtml:101 msgid "Tourist tax: %s/night per person aged 17 or older." msgstr "Taxe touristique: %s/nuit par personne de plus de 16 ans." -#: web/templates/public/campsite/type.gohtml:104 +#: web/templates/public/campsite/type.gohtml:103 msgid "Dogs: %s/night, tied, accompanied, and minimal barking." msgstr "Chiens : %s/nuit, attachés, accompagnés et aboiements minimes." -#: web/templates/public/campsite/type.gohtml:106 +#: web/templates/public/campsite/type.gohtml:105 msgid "No dogs allowed." msgstr "Chiens interdits." -#: web/templates/public/campsite/type.gohtml:125 +#: web/templates/public/campsite/type.gohtml:124 msgctxt "title" msgid "Info" msgstr "Info" -#: web/templates/public/campsite/type.gohtml:129 +#: web/templates/public/campsite/type.gohtml:128 msgctxt "title" msgid "Facilities" msgstr "Installations" -#: web/templates/public/campsite/type.gohtml:133 +#: web/templates/public/campsite/type.gohtml:132 msgctxt "title" msgid "Description" msgstr "Description" -#: web/templates/public/campsite/type.gohtml:137 +#: web/templates/public/campsite/type.gohtml:136 msgctxt "title" msgid "Additional Information" msgstr "Informations Complémentaires" -#: web/templates/public/campsite/type.gohtml:140 +#: web/templates/public/campsite/type.gohtml:139 msgctxt "time" msgid "Check-in" msgstr "Arrivée" -#: web/templates/public/campsite/type.gohtml:144 +#: web/templates/public/campsite/type.gohtml:143 msgctxt "time" msgid "Check-out" msgstr "Départ" @@ -483,99 +482,6 @@ msgctxt "legend" msgid "Faucet" msgstr "Robinet" -#: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12 -#: web/templates/public/layout.gohtml:70 -msgctxt "title" -msgid "Booking" -msgstr "Réservation" - -#: web/templates/public/booking.gohtml:16 -msgctxt "title" -msgid "Customer Details" -msgstr "Détails du client" - -#: web/templates/public/booking.gohtml:19 -msgctxt "input" -msgid "Full name" -msgstr "Nom et prénom" - -#: web/templates/public/booking.gohtml:28 -msgctxt "input" -msgid "Address (optional)" -msgstr "Adresse (Facultatif)" - -#: web/templates/public/booking.gohtml:37 -msgctxt "input" -msgid "Postcode (optional)" -msgstr "Code postal (Facultatif)" - -#: web/templates/public/booking.gohtml:46 -msgctxt "input" -msgid "Town or village (optional)" -msgstr "Ville (Facultatif)" - -#: web/templates/public/booking.gohtml:55 -#: web/templates/admin/taxDetails.gohtml:101 -msgctxt "input" -msgid "Country" -msgstr "Pays" - -#: web/templates/public/booking.gohtml:58 -msgid "Choose a country" -msgstr "Choisissez un pays" - -#: web/templates/public/booking.gohtml:66 web/templates/admin/login.gohtml:27 -#: web/templates/admin/profile.gohtml:38 -#: web/templates/admin/taxDetails.gohtml:53 -msgctxt "input" -msgid "Email" -msgstr "E-mail" - -#: web/templates/public/booking.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:45 -msgctxt "input" -msgid "Phone" -msgstr "Téléphone" - -#: web/templates/public/booking.gohtml:84 -msgctxt "title" -msgid "Accommodation" -msgstr "Hébergement" - -#: web/templates/public/booking.gohtml:101 -msgctxt "input" -msgid "Area preferences (optional)" -msgstr "Préférences de zone (facultatif)" - -#: web/templates/public/booking.gohtml:108 -msgid "Campground map" -msgstr "Plan du camping" - -#: web/templates/public/booking.gohtml:126 -msgctxt "title" -msgid "Booking Period" -msgstr "Période de réservation" - -#: web/templates/public/booking.gohtml:129 -msgctxt "input" -msgid "Arrival date" -msgstr "Date d’arrivée" - -#: web/templates/public/booking.gohtml:139 -msgctxt "input" -msgid "Departure date" -msgstr "Date de depart" - -#: web/templates/public/booking.gohtml:151 -msgctxt "input" -msgid "ACSI card? (optional)" -msgstr "Carte ACSI ? (Facultatif)" - -#: web/templates/public/booking.gohtml:158 -msgctxt "input" -msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" -msgstr "J’ai lu et j’accepte %[1]sles conditions de réservation%[2]s" - #: web/templates/public/layout.gohtml:12 web/templates/public/layout.gohtml:48 msgid "Campsite Montagut" msgstr "Camping Montagut" @@ -609,6 +515,13 @@ msgctxt "title" msgid "Campsites" msgstr "Locatifs" +#: web/templates/public/layout.gohtml:70 +#: web/templates/public/booking/form.gohtml:7 +#: web/templates/public/booking/form.gohtml:16 +msgctxt "title" +msgid "Booking" +msgstr "Réservation" + #: web/templates/public/layout.gohtml:91 msgctxt "title" msgid "Sections" @@ -623,6 +536,123 @@ msgstr "Ouverture" msgid "RTC #%s" msgstr "# RTC %s" +#: web/templates/public/booking/form.gohtml:29 +msgctxt "title" +msgid "Accommodation" +msgstr "Hébergement" + +#: web/templates/public/booking/form.gohtml:43 +msgctxt "title" +msgid "Booking Period" +msgstr "Période de réservation" + +#: web/templates/public/booking/form.gohtml:46 +msgctxt "input" +msgid "Arrival date" +msgstr "Date d’arrivée" + +#: web/templates/public/booking/form.gohtml:57 +msgctxt "input" +msgid "Departure date" +msgstr "Date de depart" + +#: web/templates/public/booking/form.gohtml:72 +msgctxt "title" +msgid "Guests" +msgstr "Personnes logeant" + +#: web/templates/public/booking/form.gohtml:76 +msgctxt "input" +msgid "Adults aged 17 or older" +msgstr "Adultes âgés 17 ans ou plus" + +#: web/templates/public/booking/form.gohtml:86 +msgctxt "input" +msgid "Teenagers from 11 to 16 years old" +msgstr "Adolescents de 11 à 16 ans" + +#: web/templates/public/booking/form.gohtml:96 +msgctxt "input" +msgid "Children from 2 to 10 years old" +msgstr "Enfants de 2 à 10 ans" + +#: web/templates/public/booking/form.gohtml:106 +msgctxt "input" +msgid "Dogs" +msgstr "Chiens" + +#: web/templates/public/booking/form.gohtml:127 +msgctxt "input" +msgid "Area preferences (optional)" +msgstr "Préférences de zone (facultatif)" + +#: web/templates/public/booking/form.gohtml:129 +msgid "Campground map" +msgstr "Plan du camping" + +#: web/templates/public/booking/form.gohtml:156 +msgctxt "title" +msgid "Customer Details" +msgstr "Détails du client" + +#: web/templates/public/booking/form.gohtml:159 +msgctxt "input" +msgid "Full name" +msgstr "Nom et prénom" + +#: web/templates/public/booking/form.gohtml:168 +msgctxt "input" +msgid "Address (optional)" +msgstr "Adresse (Facultatif)" + +#: web/templates/public/booking/form.gohtml:177 +msgctxt "input" +msgid "Postcode (optional)" +msgstr "Code postal (Facultatif)" + +#: web/templates/public/booking/form.gohtml:186 +msgctxt "input" +msgid "Town or village (optional)" +msgstr "Ville (Facultatif)" + +#: web/templates/public/booking/form.gohtml:195 +#: web/templates/admin/taxDetails.gohtml:101 +msgctxt "input" +msgid "Country" +msgstr "Pays" + +#: web/templates/public/booking/form.gohtml:198 +msgid "Choose a country" +msgstr "Choisissez un pays" + +#: web/templates/public/booking/form.gohtml:206 +#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38 +#: web/templates/admin/taxDetails.gohtml:53 +msgctxt "input" +msgid "Email" +msgstr "E-mail" + +#: web/templates/public/booking/form.gohtml:215 +#: web/templates/admin/taxDetails.gohtml:45 +msgctxt "input" +msgid "Phone" +msgstr "Téléphone" + +#: web/templates/public/booking/form.gohtml:226 +msgctxt "input" +msgid "ACSI card? (optional)" +msgstr "Carte ACSI ? (Facultatif)" + +#: web/templates/public/booking/form.gohtml:233 +msgctxt "input" +msgid "I have read and I accept %[1]sthe reservation conditions%[2]s" +msgstr "J’ai lu et j’accepte %[1]sles conditions de réservation%[2]s" + +#: web/templates/public/booking/cart.gohtml:14 +msgctxt "cart" +msgid "Total" +msgstr "Totale" + #: web/templates/admin/legal/form.gohtml:8 #: web/templates/admin/legal/form.gohtml:29 msgctxt "title" @@ -675,7 +705,7 @@ msgstr "Contenu" #: web/templates/admin/campsite/form.gohtml:92 #: web/templates/admin/campsite/type/feature/form.gohtml:74 #: web/templates/admin/campsite/type/carousel/form.gohtml:59 -#: web/templates/admin/campsite/type/form.gohtml:228 +#: web/templates/admin/campsite/type/form.gohtml:277 #: web/templates/admin/campsite/type/option/form.gohtml:90 #: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/services/form.gohtml:81 @@ -697,7 +727,7 @@ msgstr "Mettre à jour" #: web/templates/admin/campsite/form.gohtml:94 #: web/templates/admin/campsite/type/feature/form.gohtml:76 #: web/templates/admin/campsite/type/carousel/form.gohtml:61 -#: web/templates/admin/campsite/type/form.gohtml:230 +#: web/templates/admin/campsite/type/form.gohtml:279 #: web/templates/admin/campsite/type/option/form.gohtml:92 #: web/templates/admin/season/form.gohtml:75 #: web/templates/admin/services/form.gohtml:83 @@ -1140,35 +1170,75 @@ msgctxt "input" msgid "Dogs allowed" msgstr "Chiens acceptés" +#: web/templates/admin/campsite/type/form.gohtml:147 +msgctxt "header" +msgid "Season" +msgstr "Saison" + +#: web/templates/admin/campsite/type/form.gohtml:148 +msgctxt "header" +msgid "Price per night" +msgstr "Prix par nuit" + #: web/templates/admin/campsite/type/form.gohtml:149 +msgctxt "header" +msgid "Price per adult (> 16)" +msgstr "Prix per adulte (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:150 +msgctxt "header" +msgid "Price per teenager (11–16)" +msgstr "Prix per adolescent (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:151 +msgctxt "header" +msgid "Price per child (2–10)" +msgstr "Prix per enfant (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:161 #: web/templates/admin/campsite/type/option/form.gohtml:76 msgctxt "input" msgid "Price per night" msgstr "Prix par nuit" -#: web/templates/admin/campsite/type/form.gohtml:161 +#: web/templates/admin/campsite/type/form.gohtml:172 +msgctxt "input" +msgid "Price per adult (> 16)" +msgstr "Prix per adulte (> 16)" + +#: web/templates/admin/campsite/type/form.gohtml:183 +msgctxt "input" +msgid "Price per teenager (11–16)" +msgstr "Prix per adolescent (11–16)" + +#: web/templates/admin/campsite/type/form.gohtml:194 +msgctxt "input" +msgid "Price per child (2–10)" +msgstr "Prix per enfant (2–10)" + +#: web/templates/admin/campsite/type/form.gohtml:210 msgctxt "input" msgid "Spiel" msgstr "Boniment" -#: web/templates/admin/campsite/type/form.gohtml:174 +#: web/templates/admin/campsite/type/form.gohtml:223 msgctxt "input" msgid "Info" msgstr "Info" -#: web/templates/admin/campsite/type/form.gohtml:187 +#: web/templates/admin/campsite/type/form.gohtml:236 msgctxt "input" msgid "Facilities" msgstr "Installations" -#: web/templates/admin/campsite/type/form.gohtml:200 +#: web/templates/admin/campsite/type/form.gohtml:249 #: web/templates/admin/services/form.gohtml:66 #: web/templates/admin/surroundings/form.gohtml:54 msgctxt "input" msgid "Description" msgstr "Description" -#: web/templates/admin/campsite/type/form.gohtml:213 +#: web/templates/admin/campsite/type/form.gohtml:262 msgctxt "input" msgid "Additional Information" msgstr "Informations Complémentaires" @@ -1865,7 +1935,7 @@ msgid "No booking found." msgstr "Aucune réservation trouvée." #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 -#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:528 +#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:555 #: pkg/campsite/feature.go:269 pkg/season/admin.go:412 #: pkg/services/admin.go:316 pkg/surroundings/admin.go:340 #: pkg/amenity/feature.go:269 pkg/amenity/admin.go:283 @@ -1873,7 +1943,7 @@ msgid "Name can not be empty." msgstr "Le nom ne peut pas être laissé vide." #: pkg/legal/admin.go:259 pkg/campsite/types/option.go:358 -#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:529 +#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:556 #: pkg/campsite/feature.go:270 pkg/amenity/feature.go:270 msgid "Name must have at least one letter." msgstr "Le nom doit comporter au moins une lettre." @@ -1903,12 +1973,12 @@ msgid "Slide image must be an image media type." msgstr "L’image de la diapositive doit être de type média d’image." #: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217 -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:351 msgid "Email can not be empty." msgstr "L’e-mail ne peut pas être vide." #: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218 -#: pkg/booking/public.go:313 +#: pkg/booking/public.go:352 msgid "This email is not valid. It should be like name@domain.com." msgstr "Cette adresse e-mail n’est pas valide. Il devrait en être name@domain.com." @@ -1965,15 +2035,15 @@ msgstr "Le maximum doit être un nombre entier." msgid "Maximum must be equal or greater than minimum." msgstr "Le maximum doit être égal ou supérieur au minimum." -#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:554 +#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:581 msgid "Price per night can not be empty." msgstr "Le prix par nuit ne peut pas être vide." -#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:555 +#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:582 msgid "Price per night must be a decimal number." msgstr "Le prix par nuit doit être un nombre décimal." -#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:556 +#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:583 msgid "Price per night must be zero or greater." msgstr "Le prix par nuit doit être égal ou supérieur." @@ -1982,69 +2052,120 @@ msgstr "Le prix par nuit doit être égal ou supérieur." msgid "Selected icon is not valid." msgstr "L’icône sélectionnée n’est pas valide." -#: pkg/campsite/types/admin.go:310 +#: pkg/campsite/types/admin.go:313 msgctxt "input" msgid "Cover image" msgstr "Image de couverture" -#: pkg/campsite/types/admin.go:311 +#: pkg/campsite/types/admin.go:314 msgctxt "action" msgid "Set campsite type cover" msgstr "Définir une couverture type camping" -#: pkg/campsite/types/admin.go:531 +#: pkg/campsite/types/admin.go:558 msgid "Check-in can not be empty." msgstr "L’arrivée ne peut pas être vide." -#: pkg/campsite/types/admin.go:532 +#: pkg/campsite/types/admin.go:559 msgid "Check-out can not be empty." msgstr "Le départ ne peut pas être vide." -#: pkg/campsite/types/admin.go:533 +#: pkg/campsite/types/admin.go:560 msgid "Cover image can not be empty." msgstr "L’image de couverture ne peut pas être vide." -#: pkg/campsite/types/admin.go:534 +#: pkg/campsite/types/admin.go:561 msgid "Cover image must be an image media type." msgstr "L’image de couverture doit être de type média d’image." -#: pkg/campsite/types/admin.go:538 +#: pkg/campsite/types/admin.go:565 msgid "Maximum number of campers can not be empty." msgstr "Le nombre maximum de campeurs ne peut pas être vide." -#: pkg/campsite/types/admin.go:539 +#: pkg/campsite/types/admin.go:566 msgid "Maximum number of campers must be an integer number." msgstr "Le nombre maximum de campeurs doit être un nombre entier." -#: pkg/campsite/types/admin.go:540 +#: pkg/campsite/types/admin.go:567 msgid "Maximum number of campers must be one or greater." msgstr "Le nombre maximum de campeurs doit être égal ou supérieur à un campeur." -#: pkg/campsite/types/admin.go:543 +#: pkg/campsite/types/admin.go:570 msgid "Minimum number of nights can not be empty." msgstr "Le nombre minimum de nuits ne peut pas être vide." -#: pkg/campsite/types/admin.go:544 +#: pkg/campsite/types/admin.go:571 msgid "Minimum number of nights must be an integer." msgstr "Le nombre minimum de nuits doit être un entier." -#: pkg/campsite/types/admin.go:545 +#: pkg/campsite/types/admin.go:572 msgid "Minimum number of nights must be one or greater." msgstr "Le nombre minimum de nuits doit être supérieur ou égal à une nuit." -#: pkg/campsite/types/admin.go:548 +#: pkg/campsite/types/admin.go:575 msgid "Maximum number of nights can not be empty." msgstr "Le nombre maximale de nuits ne peut pas être vide." -#: pkg/campsite/types/admin.go:549 +#: pkg/campsite/types/admin.go:576 msgid "Maximum number of nights must be an integer." msgstr "Le nombre maximale de nuits doit être un entier." -#: pkg/campsite/types/admin.go:550 +#: pkg/campsite/types/admin.go:577 msgid "Maximum number of nights must be equal or greater than the minimum." msgstr "Le nombre maximale de nuits doit être égal ou supérieur au minimum." -#: pkg/campsite/admin.go:275 pkg/booking/public.go:321 +#: pkg/campsite/types/admin.go:586 +msgid "Price per adult can not be empty." +msgstr "Le prix par adulte ne peut pas être vide." + +#: pkg/campsite/types/admin.go:587 +msgid "Price per adult must be a decimal number." +msgstr "Le prix par adulte doit être un nombre décimal." + +#: pkg/campsite/types/admin.go:588 +msgid "Price per adult must be zero or greater." +msgstr "Le prix par adulte doit être égal ou supérieur." + +#: pkg/campsite/types/admin.go:591 +msgid "Price per teenager can not be empty." +msgstr "Le prix par adolescent ne peut pas être vide." + +#: pkg/campsite/types/admin.go:592 +msgid "Price per teenager must be a decimal number." +msgstr "Le prix par adolescent doit être un nombre décimal." + +#: pkg/campsite/types/admin.go:593 +msgid "Price per teenager must be zero or greater." +msgstr "Le prix par adolescent doit être égal ou supérieur." + +#: pkg/campsite/types/admin.go:596 +msgid "Price per child can not be empty." +msgstr "Le prix par enfant ne peut pas être vide." + +#: pkg/campsite/types/admin.go:597 +msgid "Price per child must be a decimal number." +msgstr "Le prix par enfant doit être un nombre décimal." + +#: pkg/campsite/types/admin.go:598 +msgid "Price per child must be zero or greater." +msgstr "Le prix par enfant doit être égal ou supérieur." + +#: pkg/campsite/types/public.go:229 +msgctxt "header" +msgid "Adults" +msgstr "Adultes" + +#: pkg/campsite/types/public.go:235 +msgctxt "header" +msgid "Teenagers (aged 11 to 16)" +msgstr "Adolescents (de 11 à 16 anys)" + +#: pkg/campsite/types/public.go:241 +msgctxt "header" +msgid "Children (aged 2 to 10)" +msgstr "Enfants (de 2 à 10 anys)" + +#: pkg/campsite/admin.go:275 pkg/booking/public.go:360 msgid "Selected campsite type is not valid." msgstr "Le type d’emplacement sélectionné n’est pas valide." @@ -2200,7 +2321,7 @@ msgstr "L’addresse du lien ne peut pas être vide." msgid "This web address is not valid. It should be like https://domain.com/." msgstr "Cette adresse web n’est pas valide. Il devrait en être https://domain.com/." -#: pkg/company/admin.go:200 pkg/booking/public.go:299 +#: pkg/company/admin.go:200 pkg/booking/public.go:338 msgid "Selected country is not valid." msgstr "Le pays sélectionné n’est pas valide." @@ -2220,11 +2341,11 @@ msgstr "Le numéro de TVA ne peut pas être vide." msgid "This VAT number is not valid." msgstr "Ce numéro de TVA n’est pas valide." -#: pkg/company/admin.go:212 pkg/booking/public.go:315 +#: pkg/company/admin.go:212 pkg/booking/public.go:354 msgid "Phone can not be empty." msgstr "Le téléphone ne peut pas être vide." -#: pkg/company/admin.go:213 pkg/booking/public.go:316 +#: pkg/company/admin.go:213 pkg/booking/public.go:355 msgid "This phone number is not valid." msgstr "Ce numéro de téléphone n’est pas valide." @@ -2244,7 +2365,7 @@ msgstr "La province ne peut pas être vide." msgid "Postal code can not be empty." msgstr "Le code postal ne peut pas être vide." -#: pkg/company/admin.go:227 pkg/booking/public.go:308 +#: pkg/company/admin.go:227 pkg/booking/public.go:347 msgid "This postal code is not valid." msgstr "Ce code postal n’est pas valide." @@ -2284,6 +2405,31 @@ msgstr "Le fichier téléchargé ne peut pas être vide." msgid "Filename can not be empty." msgstr "Le nom de fichier ne peut pas être vide." +#: pkg/booking/cart.go:171 +msgctxt "cart" +msgid "Night" +msgstr "Nuit" + +#: pkg/booking/cart.go:172 +msgctxt "cart" +msgid "Adult" +msgstr "Adulte" + +#: pkg/booking/cart.go:173 +msgctxt "cart" +msgid "Teenager" +msgstr "Adolescent" + +#: pkg/booking/cart.go:174 +msgctxt "cart" +msgid "Child" +msgstr "Enfant" + +#: pkg/booking/cart.go:193 +msgctxt "cart" +msgid "Tourist tax" +msgstr "Taxe touristique" + #: pkg/booking/admin.go:149 msgctxt "filename" msgid "bookings.ods" @@ -2341,54 +2487,102 @@ msgstr "L’intégration sélectionnée n’est pas valide." msgid "The merchant key is not valid." msgstr "La clé marchand n’est pas valide." -#: pkg/booking/public.go:303 +#: pkg/booking/public.go:342 msgid "Full name can not be empty." msgstr "Le nom complet ne peut pas être vide." -#: pkg/booking/public.go:304 +#: pkg/booking/public.go:343 msgid "Full name must have at least one letter." msgstr "Le nom complet doit comporter au moins une lettre." -#: pkg/booking/public.go:322 +#: pkg/booking/public.go:361 msgid "Arrival date can not be empty" msgstr "La date d’arrivée ne peut pas être vide" -#: pkg/booking/public.go:323 +#: pkg/booking/public.go:362 msgid "Arrival date must be a valid date." msgstr "La date d’arrivée doit être une date valide." -#: pkg/booking/public.go:327 +#: pkg/booking/public.go:366 msgid "Departure date can not be empty" msgstr "La date de départ ne peut pas être vide" -#: pkg/booking/public.go:328 +#: pkg/booking/public.go:367 msgid "Departure date must be a valid date." msgstr "La date de départ doit être une date valide." -#: pkg/booking/public.go:329 +#: pkg/booking/public.go:368 msgid "The departure date must be after the arrival date." msgstr "La date de départ doit être postérieure à la date d’arrivée." -#: pkg/booking/public.go:332 +#: pkg/booking/public.go:372 +msgid "Number of adults can not be empty" +msgstr "Le nombre d’adultes ne peut pas être vide." + +#: pkg/booking/public.go:373 +msgid "Number of adults must be an integer." +msgstr "Le nombre d’adultes doit être un entier." + +#: pkg/booking/public.go:374 +msgid "There must be at least one adult." +msgstr "Il doit y avoir au moins un adulte." + +#: pkg/booking/public.go:377 +msgid "Number of teenagers can not be empty" +msgstr "Le nombre d’adolescents ne peut pas être vide." + +#: pkg/booking/public.go:378 +msgid "Number of teenagers must be an integer." +msgstr "Le nombre d’adolescents doit être un entier." + +#: pkg/booking/public.go:379 +msgid "Number of teenagers can not be negative." +msgstr "Le nombre d’adolescents ne peut pas être négatif." + +#: pkg/booking/public.go:382 +msgid "Number of children can not be empty" +msgstr "Le nombre d’enfants ne peut pas être vide." + +#: pkg/booking/public.go:383 +msgid "Number of children must be an integer." +msgstr "Le nombre d’enfants doit être un entier." + +#: pkg/booking/public.go:384 +msgid "Number of children can not be negative." +msgstr "Le nombre d’enfants ne peut pas être négatif." + +#: pkg/booking/public.go:387 +msgid "Number of dogs can not be empty" +msgstr "Le nombre de chiens ne peut pas être vide." + +#: pkg/booking/public.go:388 +msgid "Number of dogs must be an integer." +msgstr "Le nombre de chiens nuits être un entier." + +#: pkg/booking/public.go:389 +msgid "Number of dogs can not be negative." +msgstr "Le nombre de chiens ne peut pas être négatif." + +#: pkg/booking/public.go:392 msgid "It is mandatory to agree to the reservation conditions." msgstr "Il est obligatoire d’accepter les conditions de réservation." -#: pkg/booking/public.go:335 +#: pkg/booking/public.go:395 #, c-format msgid "%s can not be empty" msgstr "%s ne peut pas être vide" -#: pkg/booking/public.go:336 +#: pkg/booking/public.go:396 #, c-format msgid "%s must be an integer." msgstr "%s doit être un entier." -#: pkg/booking/public.go:337 +#: pkg/booking/public.go:397 #, c-format msgid "%s must be %d or greater." msgstr "%s doit être %d ou plus." -#: pkg/booking/public.go:338 +#: pkg/booking/public.go:398 #, c-format msgid "%s must be at most %d." msgstr "%s doit être tout au plus %d." diff --git a/revert/campsite_type_cost__per_age.sql b/revert/campsite_type_cost__per_age.sql new file mode 100644 index 0000000..8c6b5ff --- /dev/null +++ b/revert/campsite_type_cost__per_age.sql @@ -0,0 +1,11 @@ +-- Revert camper:campsite_type_cost__per_age from pg + +begin; + +alter table camper.campsite_type_cost + drop column if exists cost_per_adult +, drop column if exists cost_per_teenager +, drop column if exists cost_per_child +; + +commit; diff --git a/revert/set_campsite_type_cost.sql b/revert/set_campsite_type_cost.sql index feb16b2..0a830ee 100644 --- a/revert/set_campsite_type_cost.sql +++ b/revert/set_campsite_type_cost.sql @@ -8,7 +8,7 @@ begin; set search_path to camper, public; -drop function if exists set_campsite_type_cost(uuid, integer, text, integer); +drop function if exists set_campsite_type_cost(uuid, integer, text, text, text, text); create or replace function set_campsite_type_cost(slug uuid, season_id integer, min_nights integer, cost_per_night text, decimal_places integer default 2) returns void as $$ diff --git a/sqitch.plan b/sqitch.plan index ee8a8f0..98c861b 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -227,5 +227,6 @@ edit_campsite_type [edit_campsite_type@v2 campsite_type__overflow_allowed campsi campsite_type__bookable_nights [campsite_type campsite_type_cost] 2024-01-31T19:45:46Z jordi fita mas # Add bookable_nights to campsite_type add_campsite_type [add_campsite_type@v3 campsite_type__bookable_nights] 2024-01-31T20:46:47Z jordi fita mas # Add bookable_nights param to add_campsite_type edit_campsite_type [edit_campsite_type@v3 campsite_type__bookable_nights] 2024-01-31T20:51:40Z jordi fita mas # Add bookable_nights param to edit_campsite_type -set_campsite_type_cost [set_campsite_type_cost@v3 campsite_type__bookable_nights] 2024-01-31T21:02:06Z jordi fita mas # Remove min_nights parameter from set_campsite_type_cost +campsite_type_cost__per_age [campsite_type_cost] 2024-02-03T20:48:54Z jordi fita mas # Add cost_per_adult, cost_per_teenager, and cost_per_child fields to campsite_type_cost +set_campsite_type_cost [set_campsite_type_cost@v3 campsite_type__bookable_nights campsite_type_cost__per_age] 2024-01-31T21:02:06Z jordi fita mas # Remove min_nights parameter from set_campsite_type_cost, and add per_adult, per_teenager, and per_child parameters campsite_type_cost__-min_nights [campsite_type__bookable_nights set_campsite_type_cost] 2024-01-31T21:46:33Z jordi fita mas # Remove min_nights field from campsite_type_cost relation diff --git a/test/campsite_type_cost.sql b/test/campsite_type_cost.sql index 72a53ac..87b1b10 100644 --- a/test/campsite_type_cost.sql +++ b/test/campsite_type_cost.sql @@ -5,7 +5,7 @@ reset client_min_messages; begin; -select plan(42); +select plan(57); set search_path to camper, public; @@ -36,6 +36,21 @@ select col_type_is('campsite_type_cost', 'cost_per_night', 'integer'); select col_not_null('campsite_type_cost', 'cost_per_night'); select col_hasnt_default('campsite_type_cost', 'cost_per_night'); +select has_column('campsite_type_cost', 'cost_per_adult'); +select col_type_is('campsite_type_cost', 'cost_per_adult', 'integer'); +select col_not_null('campsite_type_cost', 'cost_per_adult'); +select col_hasnt_default('campsite_type_cost', 'cost_per_adult'); + +select has_column('campsite_type_cost', 'cost_per_teenager'); +select col_type_is('campsite_type_cost', 'cost_per_teenager', 'integer'); +select col_not_null('campsite_type_cost', 'cost_per_teenager'); +select col_hasnt_default('campsite_type_cost', 'cost_per_teenager'); + +select has_column('campsite_type_cost', 'cost_per_child'); +select col_type_is('campsite_type_cost', 'cost_per_child', 'integer'); +select col_not_null('campsite_type_cost', 'cost_per_child'); +select col_hasnt_default('campsite_type_cost', 'cost_per_child'); + set client_min_messages to warning; truncate campsite_type_cost cascade; @@ -90,9 +105,9 @@ values (26, 2, 'Low') , (29, 4, 'Mid') ; -insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) -values (16, 26, 2) - , (18, 28, 4) +insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) +values (16, 26, 2, 3, 1, 0) + , (18, 28, 4, 5, 6, 7) ; prepare campsite_season_data as @@ -113,7 +128,7 @@ reset role; select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2'); select lives_ok( - $$ insert into campsite_type_cost(campsite_type_id, season_id, cost_per_night) values (16, 27, 3) $$, + $$ insert into campsite_type_cost(campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 27, 3, 4, 5, 6) $$, 'Admin from company 2 should be able to insert a new campsite type season to that company.' ); @@ -154,19 +169,19 @@ select bag_eq( ); select throws_ok( - $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) values (18, 29, 5) $$, + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (18, 29, 5, 6, 7, 8) $$, '42501', 'new row violates row-level security policy for table "campsite_type_cost"', 'Admin from company 2 should NOT be able to insert new campsite type costs to company 4.' ); select throws_ok( - $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) values (18, 27, 5) $$, + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (18, 27, 5, 6, 7, 8) $$, '42501', 'new row violates row-level security policy for table "campsite_type_cost"', 'Admin from company 2 should NOT be able to insert new row with a campsite type from company 4.' ); select throws_ok( - $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) values (16, 29, 5) $$, + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 29, 5, 6, 7, 8) $$, '42501', 'new row violates row-level security policy for table "campsite_type_cost"', 'Admin from company 2 should NOT be able to insert new row with a season from company 4.' ); @@ -220,11 +235,29 @@ select bag_eq( ); select throws_ok( - $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) values (16, 27, -1) $$, + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 27, -1, 2, 3, 4) $$, '23514', 'new row for relation "campsite_type_cost" violates check constraint "cost_not_negative"', 'Should not be able to insert campsite type costs with negative cost per night.' ); +select throws_ok( + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 27, 1, -1, 3, 4) $$, + '23514', 'new row for relation "campsite_type_cost" violates check constraint "per_adult_not_negative"', + 'Should not be able to insert campsite type costs with negative cost per adult.' +); + +select throws_ok( + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 27, 1, 2, -1, 4) $$, + '23514', 'new row for relation "campsite_type_cost" violates check constraint "per_teenager_not_negative"', + 'Should not be able to insert campsite type costs with negative cost per teenager.' +); + +select throws_ok( + $$ insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) values (16, 27, 1, 2, 3, -1) $$, + '23514', 'new row for relation "campsite_type_cost" violates check constraint "per_child_not_negative"', + 'Should not be able to insert campsite type costs with negative cost per child.' +); + reset role; diff --git a/test/set_campsite_type_cost.sql b/test/set_campsite_type_cost.sql index a9f0bd8..5de7120 100644 --- a/test/set_campsite_type_cost.sql +++ b/test/set_campsite_type_cost.sql @@ -9,15 +9,15 @@ select plan(13); set search_path to camper, public; -select has_function('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'integer']); -select function_lang_is('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'integer'], 'sql'); -select function_returns('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'integer'], 'void'); -select isnt_definer('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'integer']); -select volatility_is('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'integer'], 'volatile'); -select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'integer'], 'guest', array[]::text[]); -select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'integer'], 'employee', array[]::text[]); -select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'integer'], 'admin', array['EXECUTE']); -select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'integer'], 'authenticator', array[]::text[]); +select has_function('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'text', 'text', 'text']); +select function_lang_is('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'text', 'text', 'text'], 'sql'); +select function_returns('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'text', 'text', 'text'], 'void'); +select isnt_definer('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'text', 'text', 'text']); +select volatility_is('camper', 'set_campsite_type_cost', array['uuid', 'integer', 'text', 'text', 'text', 'text'], 'volatile'); +select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'text', 'text', 'text'], 'guest', array[]::text[]); +select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'text', 'text', 'text'], 'employee', array[]::text[]); +select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'text', 'text', 'text'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'set_campsite_type_cost', array ['uuid', 'integer', 'text', 'text', 'text', 'text'], 'authenticator', array[]::text[]); set client_min_messages to warning; truncate campsite_type_cost cascade; @@ -51,31 +51,31 @@ values (4, 1, 'High') , (6, 1, 'Low') ; -insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night) -values (3, 4, 44) - , (3, 5, 55) +insert into campsite_type_cost (campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child) +values (3, 4, 44, 55, 66, 77) + , (3, 5, 55, 66, 77, 88) ; select lives_ok( - $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 4, '12.34') $$, + $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 4, '12.34', '56.78', '90.12', '34.56') $$, 'Should be able to edit the cost for high season' ); select lives_ok( - $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 5, '0.0') $$, + $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 5, '0.0', '0.0', '0.0', '0.0') $$, 'Should be able to set the cost for mid season to zero' ); select lives_ok( - $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 6, '3.21') $$, + $$ select set_campsite_type_cost('87452b88-b48f-48d3-bb6c-0296de64164e', 6, '3.21', '0.98', '7.65', '4.32') $$, 'Should be able to set the cost for low season, adding it.' ); select bag_eq( - $$ select campsite_type_id, season_id, cost_per_night from campsite_type_cost $$, - $$ values (3, 4, 1234) - , (3, 5, 0) - , (3, 6, 321) + $$ select campsite_type_id, season_id, cost_per_night, cost_per_adult, cost_per_teenager, cost_per_child from campsite_type_cost $$, + $$ values (3, 4, 1234, 5678, 9012, 3456) + , (3, 5, 0, 0, 0, 0) + , (3, 6, 321, 98, 765, 432) $$, 'Should have updated all campsite type costs.' ); diff --git a/verify/campsite_type_cost__per_age.sql b/verify/campsite_type_cost__per_age.sql new file mode 100644 index 0000000..872fad8 --- /dev/null +++ b/verify/campsite_type_cost__per_age.sql @@ -0,0 +1,12 @@ +-- Verify camper:campsite_type_cost__per_age on pg + +begin; + +select cost_per_adult + , cost_per_teenager + , cost_per_child +from camper.campsite_type_cost +where false +; + +rollback; diff --git a/verify/set_campsite_type_cost.sql b/verify/set_campsite_type_cost.sql index f89f497..4270f56 100644 --- a/verify/set_campsite_type_cost.sql +++ b/verify/set_campsite_type_cost.sql @@ -2,6 +2,6 @@ begin; -select has_function_privilege('camper.set_campsite_type_cost(uuid, integer, text, integer)', 'execute'); +select has_function_privilege('camper.set_campsite_type_cost(uuid, integer, text, text, text, text)', 'execute'); rollback; diff --git a/web/static/public.css b/web/static/public.css index 49761ca..132a555 100644 --- a/web/static/public.css +++ b/web/static/public.css @@ -1301,7 +1301,7 @@ input[type="checkbox"] { border: 2px solid #777; height: 1.5em !important; width: 1.5em !important; - margin: 0 10px 0 30px; + margin-right: .625em; border-radius: 100%; vertical-align: text-bottom; position: relative; @@ -1348,11 +1348,46 @@ input[type="checkbox"]:focus { outline-offset: 2px; } +#booking { + display: flex; + align-items: start; + gap: 1rem; +} + +#booking fieldset { + padding: 0; +} + +#booking > fieldset { + flex: 1; +} + +#booking > footer { + flex: .33; + position: sticky; + top: 13rem; + opacity: 0; + visibility: hidden; + transition: opacity .5s ease; +} + +#booking > footer.is-visible { + opacity: 1; + visibility: visible; +} + +#booking br { + display: none; +} #booking fieldset { border: none; } +#booking > fieldset { + display: revert; +} + #booking legend { font-weight: bold; } @@ -1363,42 +1398,58 @@ input[type="checkbox"]:focus { padding: 20px; } -#booking fieldset { +#booking > fieldset > fieldset { margin-bottom: 1em; padding-bottom: 1em; border-bottom: 3px solid black; } -#booking fieldset:first-of-type, -#booking fieldset.campsite-options, -#booking fieldset:last-of-type { +#booking > fieldset > fieldset:last-of-type { + border-bottom: none; +} + +#booking .accommodation, +#booking .customer-details, +#booking .booking-period { display: grid; - row-gap: 1em; - column-gap: 1em; + gap: 1em; } -#booking fieldset.campsite-options:not(.is-visible) { - visibility: hidden; - max-height: 0; - overflow: hidden; - margin: 0; - padding: 0; - border: none; - line-height: 0; - opacity: 0; +#booking .accommodation { + grid-template-columns: repeat(auto-fit, minmax(15em, 1fr)); } -#booking fieldset:first-of-type { +#booking .accommodation label { + white-space: nowrap; +} + +#booking .customer-details { grid-template-columns: repeat(3, 1fr); } -#booking fieldset.campsite-options { - transition: opacity .25s ease-in; - grid-template-columns: repeat(4, 1fr); +#booking .customer-details .full-row { + grid-column: span 3; } -#booking fieldset:last-of-type { - border-bottom: none; +#booking .campsite-options { + flex-direction: column; +} + +#booking .campsite-options label { + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; +} + +#booking .campsite-options label span a { + display: block; +} + +#booking .campsite-options input[type="number"] { + width: 8em; +} + +#booking .booking-period { grid-template-columns: repeat(2, 1fr); } @@ -1407,10 +1458,58 @@ input[type="checkbox"]:focus { text-decoration: var(--accent) wavy underline; } +/**/ + +#booking .cart { + flex-direction: column; + gap: .5rem; +} + +#booking .cart div { + flex: 1; + min-height: unset; + display: flex; + gap: .5rem; + padding: 0; + justify-content: space-between; +} + +#booking .cart div:hover { + background: none; +} + +#booking .cart dt { + font-size: inherit; + font-weight: inherit; + margin: 0; + padding: 0; + border: none; + background: none; +} + +#booking .cart .total { + font-weight: bold; +} + +/**/ + @media (max-width: 48rem) { - #booking fieldset { + #booking { + flex-direction: column; + align-items: stretch; + } + + #booking > fieldset > fieldset:not(.accommodation) { grid-template-columns: 1fr !important; } + + #booking .customer-details .full-row { + grid-column: span 1; + } + + #booking > footer { + position: unset; + } } /* booking card */ diff --git a/web/templates/admin/campsite/type/form.gohtml b/web/templates/admin/campsite/type/form.gohtml index d7e3a46..c036f39 100644 --- a/web/templates/admin/campsite/type/form.gohtml +++ b/web/templates/admin/campsite/type/form.gohtml @@ -141,19 +141,68 @@ {{ with .Prices }}
{{( pgettext "Prices" "title" )}} - {{ range . }} -
- {{ .SeasonName }} - {{ with .PricePerNight -}} - - {{- end }} -
- {{- end }} + + + + + + + + + + + + {{ range . -}} + + + {{ with .PricePerNight -}} + + {{- end }} + {{ with .PricePerAdult -}} + + {{- end }} + {{ with .PricePerTeenager -}} + + {{- end }} + {{ with .PricePerChild -}} + + {{- end }} + + {{- end }} + +
{{( pgettext "Season" "header" )}}{{( pgettext "Price per night" "header" )}}{{( pgettext "Price per adult (> 16)" "header" )}}{{( pgettext "Price per teenager (11–16)" "header" )}}{{( pgettext "Price per child (2–10)" "header" )}}
{{ .SeasonName }} + + + + + + + +
{{- end }} {{ with .Spiel -}} diff --git a/web/templates/public/booking.gohtml b/web/templates/public/booking.gohtml deleted file mode 100644 index 9a123f5..0000000 --- a/web/templates/public/booking.gohtml +++ /dev/null @@ -1,203 +0,0 @@ - -{{ define "title" -}} - {{( pgettext "Booking" "title" )}} -{{- end }} - -{{ define "content" -}} - {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.publicPage*/ -}} -

{{( pgettext "Booking" "title" )}}

- {{ with .Form -}} -
-
- {{( pgettext "Customer Details" "title" )}} - {{ with .FullName -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .Address -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .PostalCode -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .City -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .Country -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .Email -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .Phone -}} - - {{ template "error-message" . }} - {{- end }} -
-
- {{( pgettext "Accommodation" "title" )}} - {{ range .CampsiteType.Options -}} -
- {{- end }} - {{ template "error-message" .CampsiteType }} -
- {{ range $campsiteType := .CampsiteType.Options -}} - {{ $options := index $.Form.CampsiteTypeOptions .Value }} - {{ $zonePreferences := index $.Form.ZonePreferences .Value }} - {{ if or $options $zonePreferences }} -
- {{ .Label }} - {{ with $zonePreferences -}} -
- - {{ template "error-message" . }} - {{( gettext "Campground map" )}}
-
- {{- end }} - {{ range $options -}} - - {{ template "error-message" .Input }} - {{- end }} -
- {{- end }} - {{- end }} -
- {{( pgettext "Booking Period" "title" )}} - {{ with .ArrivalDate -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .DepartureDate -}} - - {{ template "error-message" . }} - {{- end }} - {{ with .ACSICard -}} -
- {{ template "error-message" . }} - {{- end }} - {{ with .Agreement -}} -
- {{ template "error-message" . }} - {{- end }} -
-
-
- - VISA - MasterCard - Maestro - -
- -
-
- {{- end }} - - - -{{- end }} diff --git a/web/templates/public/booking/cart.gohtml b/web/templates/public/booking/cart.gohtml new file mode 100644 index 0000000..9dc7b17 --- /dev/null +++ b/web/templates/public/booking/cart.gohtml @@ -0,0 +1,25 @@ + +{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.bookingCart */ -}} +
+ {{ range .Lines -}} +
+
{{ .Units}} x {{( pgettext .Concept "cart" )}}
+
{{ formatPrice .Subtotal }}
+
+ {{- end }} +
+
{{( pgettext "Total" "cart" )}}
+
{{ formatPrice .Total }}
+
+
+
+ + VISA + MasterCard + Maestro + +
+ diff --git a/web/templates/public/booking/form.gohtml b/web/templates/public/booking/form.gohtml new file mode 100644 index 0000000..c5360d7 --- /dev/null +++ b/web/templates/public/booking/form.gohtml @@ -0,0 +1,245 @@ + +{{ define "title" -}} + {{( pgettext "Booking" "title" )}} +{{- end }} + +{{ define "head" -}} + {{ template "alpineScript" }} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.publicPage*/ -}} +

{{( pgettext "Booking" "title" )}}

+ {{ with .Form -}} +
+
+
+ {{( pgettext "Accommodation" "title" )}} + {{ range .CampsiteType.Options -}} +
+ {{- end }} + {{ template "error-message" .CampsiteType }} +
+
+ {{( pgettext "Booking Period" "title" )}} + {{ with .ArrivalDate -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .DepartureDate -}} + + {{ template "error-message" . }} + {{- end }} +
+
+ {{( pgettext "Guests" "title" )}} + + {{ with .NumberAdults -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .NumberTeenagers -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .NumberChildren -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .NumberDogs -}} + + {{ template "error-message" . }} + {{- end }} +
+ {{ range $campsiteType := .CampsiteType.Options -}} + {{ $options := index $.Form.CampsiteTypeOptions .Value }} + {{ $zonePreferences := index $.Form.ZonePreferences .Value }} + {{ if or $options $zonePreferences }} +
+ {{ .Label }} + {{ with $zonePreferences -}} + + {{ template "error-message" . }} + {{- end }} + {{ range $options -}} + + {{ template "error-message" .Input }} + {{- end }} +
+ {{- end }} + {{- end }} +
+ {{( pgettext "Customer Details" "title" )}} + {{ with .FullName -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .Address -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .PostalCode -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .City -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .Country -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .Email -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .Phone -}} + + {{ template "error-message" . }} + {{- end }} + {{ with .ACSICard -}} +
+ {{ template "error-message" . }} + {{- end }} + {{ with .Agreement -}} +
+ {{ template "error-message" . }} + {{- end }} +
+
+
+ {{ template "cart.gohtml" $.Cart }} +
+
+ {{- end }} + +{{- end }} diff --git a/web/templates/public/campsite/type.gohtml b/web/templates/public/campsite/type.gohtml index 6753eff..27da167 100644 --- a/web/templates/public/campsite/type.gohtml +++ b/web/templates/public/campsite/type.gohtml @@ -82,15 +82,14 @@ {{ .SeasonName }} -
- {{- if .Options -}} - {{ printf (gettext "%s: %s €/night") $.Name .PricePerNight }} - {{- else -}} - {{ printf (gettext "%s €/night") .PricePerNight }} - {{- end -}} -
{{ range .Options }} -
{{ printf (gettext "%s: %s €/night") .OptionName .PricePerNight }}
+
+ {{- if .OptionName -}} + {{ printf (gettext "%s: %s/night") .OptionName (formatPrice .PricePerNight) }} + {{- else -}} + {{ printf (gettext "%s/night") (formatPrice .PricePerNight) }} + {{- end -}} +
{{- end }} {{ if gt $.MinNights 1 -}}
{{ printf (gettext "*Minimum %d nights per stay") $.MinNights }}