From f2b24a83a38ec4dc67e9032cebdb25f213a1d180 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Fri, 26 Apr 2024 17:09:36 +0200 Subject: [PATCH] Add check-in form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I based the form from the documentation given by the Mossos d’Esquadra[0], required by law. https://registreviatgers.mossos.gencat.cat/mossos_hotels/AppJava/fitxaviatger.do?reqCode=create --- deploy/available_id_document_types.sql | 39 +++ deploy/available_sexes.sql | 23 ++ deploy/booking_guest.sql | 35 +++ deploy/check_in_guests.sql | 75 +++++ deploy/checked_in_guest.sql | 22 ++ deploy/id_document_type.sql | 17 ++ deploy/id_document_type_i18n.sql | 21 ++ deploy/sex.sql | 17 ++ deploy/sex_i18n.sql | 21 ++ pkg/booking/admin.go | 16 + pkg/booking/checkin.go | 339 +++++++++++++++++++++ pkg/booking/public.go | 6 +- pkg/database/CheckedInGuest.go | 84 +++++ pkg/database/funcs.go | 5 + pkg/database/types.go | 25 ++ pkg/form/input.go | 11 +- pkg/form/select.go | 11 + pkg/template/render.go | 3 + po/ca.po | 291 +++++++++++++----- po/es.po | 291 +++++++++++++----- po/fr.po | 291 +++++++++++++----- revert/available_id_document_types.sql | 10 + revert/available_sexes.sql | 10 + revert/booking_guest.sql | 7 + revert/check_in_guests.sql | 7 + revert/checked_in_guest.sql | 7 + revert/id_document_type.sql | 7 + revert/id_document_type_i18n.sql | 7 + revert/sex.sql | 7 + revert/sex_i18n.sql | 7 + sqitch.plan | 9 + test/booking_guest.sql | 111 +++++++ test/check_in_guests.sql | 89 ++++++ test/checked_in_guest.sql | 30 ++ test/id_document_type.sql | 35 +++ test/id_document_type_i18n.sql | 44 +++ test/sex.sql | 34 +++ test/sex_i18n.sql | 44 +++ verify/available_id_document_types.sql | 35 +++ verify/available_sexes.sql | 19 ++ verify/booking_guest.sql | 23 ++ verify/check_in_guests.sql | 7 + verify/checked_in_guest.sql | 7 + verify/id_document_type.sql | 10 + verify/id_document_type_i18n.sql | 11 + verify/sex.sql | 10 + verify/sex_i18n.sql | 11 + web/static/camper.css | 80 +++++ web/templates/admin/booking/checkin.gohtml | 34 +++ web/templates/admin/booking/form.gohtml | 3 + web/templates/admin/booking/guest.gohtml | 139 +++++++++ 51 files changed, 2243 insertions(+), 254 deletions(-) create mode 100644 deploy/available_id_document_types.sql create mode 100644 deploy/available_sexes.sql create mode 100644 deploy/booking_guest.sql create mode 100644 deploy/check_in_guests.sql create mode 100644 deploy/checked_in_guest.sql create mode 100644 deploy/id_document_type.sql create mode 100644 deploy/id_document_type_i18n.sql create mode 100644 deploy/sex.sql create mode 100644 deploy/sex_i18n.sql create mode 100644 pkg/booking/checkin.go create mode 100644 pkg/database/CheckedInGuest.go create mode 100644 revert/available_id_document_types.sql create mode 100644 revert/available_sexes.sql create mode 100644 revert/booking_guest.sql create mode 100644 revert/check_in_guests.sql create mode 100644 revert/checked_in_guest.sql create mode 100644 revert/id_document_type.sql create mode 100644 revert/id_document_type_i18n.sql create mode 100644 revert/sex.sql create mode 100644 revert/sex_i18n.sql create mode 100644 test/booking_guest.sql create mode 100644 test/check_in_guests.sql create mode 100644 test/checked_in_guest.sql create mode 100644 test/id_document_type.sql create mode 100644 test/id_document_type_i18n.sql create mode 100644 test/sex.sql create mode 100644 test/sex_i18n.sql create mode 100644 verify/available_id_document_types.sql create mode 100644 verify/available_sexes.sql create mode 100644 verify/booking_guest.sql create mode 100644 verify/check_in_guests.sql create mode 100644 verify/checked_in_guest.sql create mode 100644 verify/id_document_type.sql create mode 100644 verify/id_document_type_i18n.sql create mode 100644 verify/sex.sql create mode 100644 verify/sex_i18n.sql create mode 100644 web/templates/admin/booking/checkin.gohtml create mode 100644 web/templates/admin/booking/guest.gohtml diff --git a/deploy/available_id_document_types.sql b/deploy/available_id_document_types.sql new file mode 100644 index 0000000..97758d0 --- /dev/null +++ b/deploy/available_id_document_types.sql @@ -0,0 +1,39 @@ +-- Deploy camper:available_id_document_types to pg +-- requires: id_document_type +-- requires: id_document_type_i18n + +begin; + +set search_path to camper; + +insert into id_document_type (id_document_type_id, name) +values ('D', 'DNI') + , ('P', 'Passport') + , ('C', 'Driving license') + , ('I', 'Identification document') + , ('N', 'Spanish residence permit') + , ('X', 'Residence permit from another Member State of the European Union') +; + +insert into id_document_type_i18n (id_document_type_id, lang_tag, name) +values ('D', 'ca', 'DNI') + , ('P', 'ca', 'Passaport') + , ('C', 'ca', 'Permís de conduir') + , ('I', 'ca', 'Carta o document d’identitat') + , ('N', 'ca', 'Permís de residència espanyol') + , ('X', 'ca', 'Permís de residència d’un altre estat membre de la Unió Europea') + , ('D', 'es', 'DNI') + , ('P', 'es', 'Pasaporte') + , ('C', 'es', 'Permiso de conducir') + , ('I', 'es', 'Carta o documento de identidad') + , ('N', 'es', 'Permiso de residencia español') + , ('X', 'es', 'Permiso de residencia de otro Estado Miembro de la Unión Europea') + , ('D', 'fr', 'DNI') + , ('P', 'fr', 'Passeport') + , ('C', 'fr', 'Permis de conduire') + , ('I', 'fr', 'Carte d’identité') + , ('N', 'fr', 'Permis de séjour espagnol') + , ('X', 'fr', 'Titre de séjour d’un autre État membre de l’Union européenne') +; + +commit; diff --git a/deploy/available_sexes.sql b/deploy/available_sexes.sql new file mode 100644 index 0000000..91f4a80 --- /dev/null +++ b/deploy/available_sexes.sql @@ -0,0 +1,23 @@ +-- Deploy camper:available_sexes to pg +-- requires: sex +-- requires: sex_i18n + +begin; + +set search_path to camper; + +insert into sex (sex_id, name) +values ('F', 'Female') + , ('M', 'Male') +; + +insert into sex_i18n (sex_id, lang_tag, name) +values ('F', 'ca', 'Femení') + , ('M', 'ca', 'Masculí') + , ('F', 'es', 'Femenino') + , ('M', 'es', 'Masculino') + , ('F', 'fr', 'Féminin') + , ('M', 'fr', 'Masculin') +; + +commit; diff --git a/deploy/booking_guest.sql b/deploy/booking_guest.sql new file mode 100644 index 0000000..3693a78 --- /dev/null +++ b/deploy/booking_guest.sql @@ -0,0 +1,35 @@ +-- Deploy camper:booking_guest to pg +-- requires: roles +-- requires: schema_camper +-- requires: booking +-- requires: sex +-- requires: id_document_type +-- requires: extension_pg_libphonenumber + +begin; + +set search_path to camper, public; + +create table booking_guest ( + booking_guest_id integer generated by default as identity primary key, + booking_id integer not null references booking, + id_document_type_id varchar(1) not null references id_document_type, + id_document_number text not null, + id_document_issue_date date, + given_name text not null, + first_surname text not null, + second_surname text not null, + sex_id varchar(1) not null references sex, + birthdate date not null, + country_code country_code not null references country, + phone packed_phone_number, + address text not null, + created_at timestamp with time zone not null default current_timestamp, + updated_at timestamp with time zone not null default current_timestamp, + unique (booking_id, id_document_type_id, id_document_number) +); + +grant select, insert, update, delete on table booking_guest to employee; +grant select, insert, update, delete on table booking_guest to admin; + +commit; diff --git a/deploy/check_in_guests.sql b/deploy/check_in_guests.sql new file mode 100644 index 0000000..bd74f2c --- /dev/null +++ b/deploy/check_in_guests.sql @@ -0,0 +1,75 @@ +-- Deploy camper:check_in_guests to pg +-- requires: roles +-- requires: schema_camper +-- requires: booking +-- requires: booking_guest +-- requires: checked_in_guest +-- requires: extension_pg_libphonenumber + +begin; + +set search_path to camper, public; + +create or replace function check_in_guests(bid integer, guests checked_in_guest[]) returns void as +$$ + insert into booking_guest + ( booking_id + , id_document_type_id + , id_document_number + , id_document_issue_date + , given_name + , first_surname + , second_surname + , sex_id + , birthdate + , country_code + , phone + , address + ) + select bid + , id_document_type_id + , id_document_number + , id_document_issue_date + , given_name + , first_surname + , second_surname + , sex_id + , birthdate + , country_code + , case when phone is null or phone = '' then null else parse_packed_phone_number(phone, country_code) end + , address + from unnest(guests) as guest + on conflict (booking_id, id_document_type_id, id_document_number) do update + set id_document_type_id = excluded.id_document_type_id + , id_document_number = excluded.id_document_number + , id_document_issue_date = excluded.id_document_issue_date + , given_name = excluded.given_name + , first_surname = excluded.first_surname + , second_surname = excluded.second_surname + , sex_id = excluded.sex_id + , birthdate = excluded.birthdate + , country_code = excluded.country_code + , phone = excluded.phone + , address = excluded.address + , updated_at = current_timestamp + ; + + delete from booking_guest + where booking_id = bid + and updated_at < current_timestamp + ; + + update booking + set booking_status = 'checked-in' + where booking_id = bid + and booking_status in ('created', 'confirmed') + ; +$$ + language sql +; + +revoke execute on function check_in_guests(integer, checked_in_guest[]) from public; +grant execute on function check_in_guests(integer, checked_in_guest[]) to employee; +grant execute on function check_in_guests(integer, checked_in_guest[]) to admin; + +commit; diff --git a/deploy/checked_in_guest.sql b/deploy/checked_in_guest.sql new file mode 100644 index 0000000..f760cf9 --- /dev/null +++ b/deploy/checked_in_guest.sql @@ -0,0 +1,22 @@ +-- Deploy camper:checked_in_guest to pg +-- requires: schema_camper + +begin; + +set search_path to camper, public; + +create type checked_in_guest as ( + id_document_type_id varchar(1), + id_document_number text, + id_document_issue_date date, + given_name text, + first_surname text, + second_surname text, + sex_id varchar(1), + birthdate date, + country_code country_code, + phone text, + address text +); + +commit; diff --git a/deploy/id_document_type.sql b/deploy/id_document_type.sql new file mode 100644 index 0000000..2288c3f --- /dev/null +++ b/deploy/id_document_type.sql @@ -0,0 +1,17 @@ +-- Deploy camper:id_document_type to pg +-- requires: roles +-- requires: schema_camper + +begin; + +set search_path to camper, public; + +create table id_document_type ( + id_document_type_id varchar(1) primary key, + name text not null +); + +grant select on table id_document_type to employee; +grant select on table id_document_type to admin; + +commit; diff --git a/deploy/id_document_type_i18n.sql b/deploy/id_document_type_i18n.sql new file mode 100644 index 0000000..1c07ede --- /dev/null +++ b/deploy/id_document_type_i18n.sql @@ -0,0 +1,21 @@ +-- Deploy camper:id_document_type_i18n to pg +-- requires: roles +-- requires: schema_camper +-- requires: id_document_type +-- requires: language + +begin; + +set search_path to camper, public; + +create table id_document_type_i18n ( + id_document_type_id varchar(1) not null references id_document_type, + lang_tag text not null references language, + name text not null, + primary key (id_document_type_id, lang_tag) +); + +grant select on table id_document_type_i18n to employee; +grant select on table id_document_type_i18n to admin; + +commit; diff --git a/deploy/sex.sql b/deploy/sex.sql new file mode 100644 index 0000000..9ec0b53 --- /dev/null +++ b/deploy/sex.sql @@ -0,0 +1,17 @@ +-- Deploy camper:sex to pg +-- requires: roles +-- requires: schema_camper + +begin; + +set search_path to camper, public; + +create table sex ( + sex_id varchar(1) primary key, + name text not null +); + +grant select on table sex to employee; +grant select on table sex to admin; + +commit; diff --git a/deploy/sex_i18n.sql b/deploy/sex_i18n.sql new file mode 100644 index 0000000..ea6c070 --- /dev/null +++ b/deploy/sex_i18n.sql @@ -0,0 +1,21 @@ +-- Deploy camper:sex_i18n to pg +-- requires: roles +-- requires: schema_camper +-- requires: sex +-- requires: language + +begin; + +set search_path to camper, public; + +create table sex_i18n ( + sex_id varchar(1) not null references sex, + lang_tag text not null references language, + name text not null, + primary key (sex_id, lang_tag) +); + +grant select on sex_i18n to employee; +grant select on sex_i18n to admin; + +commit; diff --git a/pkg/booking/admin.go b/pkg/booking/admin.go index 554da61..7e5c8b9 100644 --- a/pkg/booking/admin.go +++ b/pkg/booking/admin.go @@ -113,6 +113,22 @@ func (h *AdminHandler) bookingHandler(user *auth.User, company *auth.Company, co default: httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut) } + case "check-in": + switch r.Method { + case http.MethodGet: + serveCheckInForm(w, r, user, company, conn, slug) + case http.MethodPost: + checkInBooking(w, r, user, company, conn, slug) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) + } + case "guest": + switch r.Method { + case http.MethodGet: + serveGuestForm(w, r, user, company, conn, slug) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet) + } default: http.NotFound(w, r) } diff --git a/pkg/booking/checkin.go b/pkg/booking/checkin.go new file mode 100644 index 0000000..364b0b2 --- /dev/null +++ b/pkg/booking/checkin.go @@ -0,0 +1,339 @@ +package booking + +import ( + "context" + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + "dev.tandem.ws/tandem/camper/pkg/form" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/locale" + "dev.tandem.ws/tandem/camper/pkg/template" + "github.com/jackc/pgx/v4" + "math" + "net/http" + "time" +) + +func serveCheckInForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, slug string) { + f := newCheckinForm(slug) + if err := f.FillFromDatabase(r.Context(), conn, user.Locale); err != nil { + panic(err) + } + f.MustRender(w, r, user, company) +} + +func serveGuestForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, slug string) { + f, err := newGuestForm(r.Context(), conn, user.Locale, slug) + if err != nil { + panic(err) + } + f.MustRender(w, r, user, company) +} + +func checkInBooking(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, slug string) { + f := newCheckinForm(slug) + if err := f.Parse(r, user, conn); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := user.VerifyCSRFToken(r); err != nil { + http.Error(w, err.Error(), http.StatusForbidden) + return + } + if ok, err := f.Valid(r.Context(), conn, user.Locale); err != nil { + panic(err) + } else if !ok { + if !httplib.IsHTMxRequest(r) { + w.WriteHeader(http.StatusUnprocessableEntity) + } + f.MustRender(w, r, user, company) + } + + guests := make([]*database.CheckedInGuest, 0, len(f.Guests)) + for _, g := range f.Guests { + guests = append(guests, g.checkedInGuest()) + } + if err := conn.CheckInGuests(r.Context(), f.Slug, guests); err != nil { + panic(err) + } + httplib.Redirect(w, r, "/admin/bookings", http.StatusSeeOther) +} + +type checkInForm struct { + Slug string + Guests []*guestForm +} + +func newCheckinForm(slug string) *checkInForm { + return &checkInForm{ + Slug: slug, + } +} + +func (f *checkInForm) FillFromDatabase(ctx context.Context, conn *database.Conn, l *locale.Locale) error { + documentTypes := mustGetDocumentTypeOptions(ctx, conn, l) + sexes := mustGetSexOptions(ctx, conn, l) + countries := mustGetCountryOptions(ctx, conn, l) + + rows, err := conn.Query(ctx, ` + select array[id_document_type_id] + , id_document_number + , coalesce(id_document_issue_date::text, '') + , given_name + , first_surname + , second_surname + , array[sex_id] + , birthdate::text + , array[guest.country_code::text] + , coalesce(guest.phone::text, '') + , guest.address + from booking_guest as guest + join booking using (booking_id) + where slug = $1 +`, f.Slug) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + guest := newGuestFormWithOptions(documentTypes, sexes, countries, nil) + if err := guest.FillFromRow(rows); err != nil { + return err + } + f.Guests = append(f.Guests, guest) + } + if len(f.Guests) == 0 { + var numberGuests int + var country []string + row := conn.QueryRow(ctx, "select number_adults + number_teenagers, array[coalesce(country_code, '')] from booking where slug = $1", f.Slug) + if err = row.Scan(&numberGuests, &country); err != nil { + return err + } + guests := make([]*guestForm, 0, numberGuests) + for i := 0; i < numberGuests; i++ { + guests = append(guests, newGuestFormWithOptions(documentTypes, sexes, countries, country)) + } + f.Guests = guests + } + return nil +} + +func mustGetDocumentTypeOptions(ctx context.Context, conn *database.Conn, l *locale.Locale) []*form.Option { + return form.MustGetOptions(ctx, conn, "select idt.id_document_type_id::text, coalesce(i18n.name, idt.name) as l10n_name from id_document_type as idt left join id_document_type_i18n as i18n on idt.id_document_type_id = i18n.id_document_type_id and i18n.lang_tag = $1 order by l10n_name", l.Language) +} + +func mustGetSexOptions(ctx context.Context, conn *database.Conn, l *locale.Locale) []*form.Option { + return form.MustGetOptions(ctx, conn, "select sex.sex_id::text, coalesce(i18n.name, sex.name) as l10n_name from sex left join sex_i18n as i18n on sex.sex_id = i18n.sex_id and i18n.lang_tag = $1 order by l10n_name", l.Language) +} + +func (f *checkInForm) Parse(r *http.Request, user *auth.User, conn *database.Conn) error { + if err := r.ParseForm(); err != nil { + return err + } + + documentTypes := mustGetDocumentTypeOptions(r.Context(), conn, user.Locale) + sexes := mustGetSexOptions(r.Context(), conn, user.Locale) + countries := mustGetCountryOptions(r.Context(), conn, user.Locale) + + guest := newGuestFormWithOptions(documentTypes, sexes, countries, nil) + count := guest.count(r) + f.Guests = make([]*guestForm, 0, count) + guest.FillValueIndex(r, 0) + f.Guests = append(f.Guests, guest) + for i := 1; i < count; i++ { + guest = newGuestFormWithOptions(documentTypes, sexes, countries, nil) + guest.FillValueIndex(r, i) + f.Guests = append(f.Guests, guest) + } + + return nil +} + +func (f *checkInForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) { + allOK := true + for _, g := range f.Guests { + if ok, err := g.Valid(ctx, conn, l); err != nil { + return false, err + } else if !ok { + allOK = false + } + } + return allOK, nil +} + +func (f *checkInForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { + template.MustRenderAdminFiles(w, r, user, company, f, "booking/checkin.gohtml", "booking/guest.gohtml") +} + +type guestForm struct { + IDDocumentType *form.Select + IDDocumentNumber *form.Input + IDDocumentDate *form.Input + GivenName *form.Input + FirstSurname *form.Input + SecondSurname *form.Input + Sex *form.Select + Birthdate *form.Input + Country *form.Select + Address *form.Input + Phone *form.Input +} + +func newGuestForm(ctx context.Context, conn *database.Conn, l *locale.Locale, slug string) (*guestForm, error) { + documentTypes := mustGetDocumentTypeOptions(ctx, conn, l) + sexes := mustGetSexOptions(ctx, conn, l) + countries := mustGetCountryOptions(ctx, conn, l) + + var country []string + row := conn.QueryRow(ctx, "select array[coalesce(country_code, '')] from booking where slug = $1", slug) + if err := row.Scan(&country); err != nil { + return nil, err + } + return newGuestFormWithOptions(documentTypes, sexes, countries, country), nil +} + +func newGuestFormWithOptions(documentTypes []*form.Option, sexes []*form.Option, countries []*form.Option, selectedCountry []string) *guestForm { + return &guestForm{ + IDDocumentType: &form.Select{ + Name: "id_document_type", + Options: documentTypes, + }, + IDDocumentNumber: &form.Input{ + Name: "id_document_number", + }, + IDDocumentDate: &form.Input{ + Name: "id_document_date", + }, + GivenName: &form.Input{ + Name: "given_name", + }, + FirstSurname: &form.Input{ + Name: "first_surname", + }, + SecondSurname: &form.Input{ + Name: "second_surname", + }, + Sex: &form.Select{ + Name: "sex", + Options: sexes, + }, + Birthdate: &form.Input{ + Name: "birthdate", + }, + Country: &form.Select{ + Name: "country", + Options: countries, + Selected: selectedCountry, + }, + Address: &form.Input{ + Name: "address", + }, + Phone: &form.Input{ + Name: "phone", + }, + } +} + +func (f *guestForm) count(r *http.Request) int { + keys := []string{f.IDDocumentType.Name, f.IDDocumentNumber.Name, f.IDDocumentDate.Name, f.GivenName.Name, f.FirstSurname.Name, f.SecondSurname.Name, f.Sex.Name, f.Birthdate.Name, f.Country.Name, f.Address.Name, f.Phone.Name} + min := math.MaxInt + for _, key := range keys { + l := len(r.Form[key]) + if len(r.Form[key]) < min { + min = l + } + } + return min +} + +func (f *guestForm) FillValueIndex(r *http.Request, idx int) { + f.IDDocumentType.FillValueIndex(r, idx) + f.IDDocumentNumber.FillValueIndex(r, idx) + f.IDDocumentDate.FillValueIndex(r, idx) + f.GivenName.FillValueIndex(r, idx) + f.FirstSurname.FillValueIndex(r, idx) + f.SecondSurname.FillValueIndex(r, idx) + f.Sex.FillValueIndex(r, idx) + f.Birthdate.FillValueIndex(r, idx) + f.Country.FillValueIndex(r, idx) + f.Address.FillValueIndex(r, idx) + f.Phone.FillValueIndex(r, idx) +} + +func (f *guestForm) FillFromRow(row pgx.Rows) error { + return row.Scan( + &f.IDDocumentType.Selected, + &f.IDDocumentNumber.Val, + &f.IDDocumentDate.Val, + &f.GivenName.Val, + &f.FirstSurname.Val, + &f.SecondSurname.Val, + &f.Sex.Selected, + &f.Birthdate.Val, + &f.Country.Selected, + &f.Phone.Val, + &f.Address.Val, + ) +} + +func (f *guestForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) { + v := form.NewValidator(l) + + today := time.Now() + yesterday := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC) + + v.CheckSelectedOptions(f.IDDocumentType, l.GettextNoop("Selected ID document type is not valid.")) + v.CheckRequired(f.IDDocumentNumber, l.GettextNoop("ID document number can not be empty.")) + if f.IDDocumentDate.Val != "" { + if v.CheckValidDate(f.IDDocumentDate, l.GettextNoop("ID document issue date must be a valid date.")) { + v.CheckMaxDate(f.IDDocumentDate, yesterday, l.Gettext("ID document issue date must be in the past.")) + } + } + v.CheckRequired(f.GivenName, l.GettextNoop("Full name can not be empty.")) + v.CheckRequired(f.FirstSurname, l.GettextNoop("Full name can not be empty.")) + v.CheckSelectedOptions(f.Sex, l.GettextNoop("Selected sex is not valid.")) + if v.CheckRequired(f.Birthdate, l.GettextNoop("Birthdate can not be empty")) { + if v.CheckValidDate(f.Birthdate, l.GettextNoop("Birthdate must be a valid date.")) { + v.CheckMaxDate(f.Birthdate, yesterday, l.Gettext("Birthdate must be in the past.")) + } + } + var country string + if v.CheckSelectedOptions(f.Country, l.GettextNoop("Selected country is not valid.")) { + country = f.Country.Selected[0] + } + if f.Phone.Val != "" && country != "" { + if _, err := v.CheckValidPhone(ctx, conn, f.Phone, country, l.GettextNoop("This phone number is not valid.")); err != nil { + return false, err + } + } + + return v.AllOK, nil +} + +func (f *guestForm) checkedInGuest() *database.CheckedInGuest { + birthdate, err := time.Parse(database.ISODateFormat, f.Birthdate.Val) + if err != nil { + panic(err) + } + issueDate, err := time.Parse(database.ISODateFormat, f.IDDocumentDate.Val) + if err != nil { + issueDate = time.Time{} + } + return &database.CheckedInGuest{ + IDDocumentType: f.IDDocumentType.String(), + IDDocumentNumber: f.IDDocumentNumber.Val, + IDDocumentIssueDate: issueDate, + GivenName: f.GivenName.Val, + FirstSurname: f.FirstSurname.Val, + SecondSurname: f.SecondSurname.Val, + Sex: f.Sex.String(), + Birthdate: birthdate, + CountryCode: f.Country.String(), + Phone: f.Phone.Val, + Address: f.Address.Val, + } +} + +func (f *guestForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { + template.MustRenderAdminNoLayout(w, r, user, company, "booking/guest.gohtml", f) +} diff --git a/pkg/booking/public.go b/pkg/booking/public.go index 70f0175..fc0878a 100644 --- a/pkg/booking/public.go +++ b/pkg/booking/public.go @@ -547,7 +547,7 @@ func newBookingCustomerFields(ctx context.Context, conn *database.Conn, l *local }, Country: &form.Select{ Name: "country", - Options: form.MustGetOptions(ctx, conn, "select country.country_code, coalesce(i18n.name, country.name) as l10n_name from country left join country_i18n as i18n on country.country_code = i18n.country_code and i18n.lang_tag = $1 order by l10n_name", l.Language), + Options: mustGetCountryOptions(ctx, conn, l), }, Email: &form.Input{ Name: "email", @@ -561,6 +561,10 @@ func newBookingCustomerFields(ctx context.Context, conn *database.Conn, l *local } } +func mustGetCountryOptions(ctx context.Context, conn *database.Conn, l *locale.Locale) []*form.Option { + return form.MustGetOptions(ctx, conn, "select country.country_code, coalesce(i18n.name, country.name) as l10n_name from country left join country_i18n as i18n on country.country_code = i18n.country_code and i18n.lang_tag = $1 order by l10n_name", l.Language) +} + func (f *bookingCustomerFields) FillValues(r *http.Request) { f.FullName.FillValue(r) f.Address.FillValue(r) diff --git a/pkg/database/CheckedInGuest.go b/pkg/database/CheckedInGuest.go new file mode 100644 index 0000000..3e2379c --- /dev/null +++ b/pkg/database/CheckedInGuest.go @@ -0,0 +1,84 @@ +package database + +import ( + "fmt" + "time" + + "github.com/jackc/pgio" + "github.com/jackc/pgtype" +) + +type CheckedInGuest struct { + IDDocumentType string + IDDocumentNumber string + IDDocumentIssueDate time.Time + GivenName string + FirstSurname string + SecondSurname string + Sex string + Birthdate time.Time + CountryCode string + Phone string + Address string +} + +func (src CheckedInGuest) EncodeBinary(ci *pgtype.ConnInfo, dst []byte) ([]byte, error) { + typeName := CheckedInGuestTypeName + dt, ok := ci.DataTypeForName(typeName) + if !ok { + return nil, fmt.Errorf("unable to find oid for type name %v", typeName) + } + var idDocumentIssueDate interface{} + var noDate time.Time + if src.IDDocumentIssueDate != noDate { + idDocumentIssueDate = src.IDDocumentIssueDate + } + values := []interface{}{ + src.IDDocumentType, + src.IDDocumentNumber, + idDocumentIssueDate, + src.GivenName, + src.FirstSurname, + src.SecondSurname, + src.Sex, + src.Birthdate, + src.CountryCode, + src.Phone, + src.Address, + } + ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType) + if err := ct.Set(values); err != nil { + return nil, err + } + return ct.EncodeBinary(ci, dst) +} + +type CheckedInGuestArray []*CheckedInGuest + +func (src CheckedInGuestArray) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) { + typeName := CheckedInGuestTypeName + dt, ok := ci.DataTypeForName(typeName) + if !ok { + return nil, fmt.Errorf("unable to find oid for type name %v", typeName) + } + + arrayHeader := pgtype.ArrayHeader{ + ElementOID: int32(dt.OID), + Dimensions: []pgtype.ArrayDimension{{Length: int32(len(src)), LowerBound: 1}}, + } + buf = arrayHeader.EncodeBinary(ci, buf) + for _, optionUnits := range src { + sp := len(buf) + buf = pgio.AppendInt32(buf, -1) + + elemBuf, err := optionUnits.EncodeBinary(ci, buf) + if err != nil { + return nil, err + } + if elemBuf != nil { + buf = elemBuf + pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4)) + } + } + return buf, nil +} diff --git a/pkg/database/funcs.go b/pkg/database/funcs.go index b7ddd8d..112eadf 100644 --- a/pkg/database/funcs.go +++ b/pkg/database/funcs.go @@ -365,3 +365,8 @@ func (tx *Tx) EditBooking(ctx context.Context, bookingID int, customerName strin _, err := tx.Exec(ctx, "select edit_booking($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", bookingID, customerName, zeronull.Text(customerAddress), zeronull.Text(customerPostCode), zeronull.Text(customerCity), zeronull.Text(customerCountryCode), zeronull.Text(customerEmail), zeronull.Text(customerPhone), customerLangTag, bookingStatus, campsiteIDs) return err } + +func (c *Conn) CheckInGuests(ctx context.Context, bookingSlug string, guests []*CheckedInGuest) error { + _, err := c.Exec(ctx, "select check_in_guests(booking_id, $2) from booking where slug = $1", bookingSlug, CheckedInGuestArray(guests)) + return err +} diff --git a/pkg/database/types.go b/pkg/database/types.go index 23a9274..3820411 100644 --- a/pkg/database/types.go +++ b/pkg/database/types.go @@ -13,6 +13,7 @@ import ( ) const ( + CheckedInGuestTypeName = "checked_in_guest" OptionUnitsTypeName = "option_units" RedsysRequestTypeName = "redsys_request" RedsysResponseTypeName = "redsys_response" @@ -125,6 +126,30 @@ func registerConnectionTypes(ctx context.Context, conn *pgx.Conn) error { return err } + checkedInGuestType, err := pgtype.NewCompositeType( + CheckedInGuestTypeName, + []pgtype.CompositeTypeField{ + {"id_document_type_id", pgtype.VarcharOID}, + {"id_document_number", pgtype.TextOID}, + {"id_document_issue_date", pgtype.DateOID}, + {"given_name", pgtype.TextOID}, + {"first_surname", pgtype.TextOID}, + {"second_surname", pgtype.TextOID}, + {"sex_id", pgtype.VarcharOID}, + {"birthdate", pgtype.DateOID}, + {"country_code", pgtype.TextOID}, + {"phone", pgtype.TextOID}, + {"address", pgtype.TextOID}, + }, + conn.ConnInfo(), + ) + if err != nil { + return err + } + if _, err = registerType(ctx, conn, checkedInGuestType, checkedInGuestType.TypeName()); err != nil { + return err + } + return nil } diff --git a/pkg/form/input.go b/pkg/form/input.go index d065583..21b7080 100644 --- a/pkg/form/input.go +++ b/pkg/form/input.go @@ -28,8 +28,17 @@ func (input *Input) setError(err error) { } func (input *Input) FillValue(r *http.Request) { - input.Val = strings.TrimSpace(r.FormValue(input.Name)) + input.FillValueIndex(r, 0) } + +func (input *Input) FillValueIndex(r *http.Request, idx int) { + var val string + if vs := r.Form[input.Name]; len(vs) > idx { + val = vs[idx] + } + input.Val = strings.TrimSpace(val) +} + func (input *Input) Value() (driver.Value, error) { return input.Val, nil } diff --git a/pkg/form/select.go b/pkg/form/select.go index 792c531..8398bf5 100644 --- a/pkg/form/select.go +++ b/pkg/form/select.go @@ -48,7 +48,18 @@ func (s *Select) FillValue(r *http.Request) { s.Selected = r.Form[s.Name] } +func (s *Select) FillValueIndex(r *http.Request, idx int) { + if vs := r.Form[s.Name]; len(vs) > idx { + s.Selected = []string{vs[idx]} + } else { + s.Selected = nil + } +} + func (s *Select) ValidOptionsSelected() bool { + if len(s.Selected) == 0 { + return false + } for _, selected := range s.Selected { if !s.isValidOption(selected) { return false diff --git a/pkg/template/render.go b/pkg/template/render.go index f68138e..f931e73 100644 --- a/pkg/template/render.go +++ b/pkg/template/render.go @@ -117,6 +117,9 @@ func mustRenderLayout(w io.Writer, user *auth.User, company *auth.Company, templ "formatDateAttr": func(time time.Time) string { return time.Format(database.ISODateFormat) }, + "today": func() string { + return time.Now().Format(database.ISODateFormat) + }, "queryEscape": func(s string) string { return url.QueryEscape(s) }, diff --git a/po/ca.po b/po/ca.po index 1a6aebb..efc5064 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-04-24 19:59+0200\n" +"POT-Creation-Date: 2024-04-26 16:53+0200\n" "PO-Revision-Date: 2024-02-06 10:04+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -116,7 +116,7 @@ msgstr "Reserva" #: web/templates/mail/payment/details.gotxt:16 #: web/templates/public/booking/fields.gohtml:14 #: web/templates/admin/payment/details.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:12 +#: web/templates/admin/booking/fields.gohtml:13 msgctxt "title" msgid "Accommodation" msgstr "Allotjament" @@ -155,7 +155,7 @@ msgstr "No" #: web/templates/public/campsite/dates.gohtml:4 #: web/templates/public/booking/fields.gohtml:30 #: web/templates/admin/payment/details.gohtml:86 -#: web/templates/admin/booking/fields.gohtml:31 +#: web/templates/admin/booking/fields.gohtml:32 msgctxt "input" msgid "Arrival date" msgstr "Data d’arribada" @@ -164,7 +164,7 @@ msgstr "Data d’arribada" #: web/templates/public/campsite/dates.gohtml:15 #: web/templates/public/booking/fields.gohtml:41 #: web/templates/admin/payment/details.gohtml:90 -#: web/templates/admin/booking/fields.gohtml:42 +#: web/templates/admin/booking/fields.gohtml:43 msgctxt "input" msgid "Departure date" msgstr "Data de sortida" @@ -178,7 +178,7 @@ msgstr "Nits" #: web/templates/mail/payment/details.gotxt:22 #: web/templates/public/booking/fields.gohtml:60 #: web/templates/admin/payment/details.gohtml:98 -#: web/templates/admin/booking/fields.gohtml:92 +#: web/templates/admin/booking/fields.gohtml:93 msgctxt "input" msgid "Adults aged 17 or older" msgstr "Adults de 17 anys o més" @@ -186,7 +186,7 @@ msgstr "Adults de 17 anys o més" #: web/templates/mail/payment/details.gotxt:23 #: web/templates/public/booking/fields.gohtml:71 #: web/templates/admin/payment/details.gohtml:102 -#: web/templates/admin/booking/fields.gohtml:108 +#: web/templates/admin/booking/fields.gohtml:109 msgctxt "input" msgid "Teenagers from 11 to 16 years old" msgstr "Adolescents d’entre 11 i 16 anys" @@ -194,7 +194,7 @@ msgstr "Adolescents d’entre 11 i 16 anys" #: web/templates/mail/payment/details.gotxt:24 #: web/templates/public/booking/fields.gohtml:82 #: web/templates/admin/payment/details.gohtml:106 -#: web/templates/admin/booking/fields.gohtml:124 +#: web/templates/admin/booking/fields.gohtml:125 msgctxt "input" msgid "Children from 2 to 10 years old" msgstr "Nens d’entre 2 i 10 anys" @@ -202,14 +202,14 @@ msgstr "Nens d’entre 2 i 10 anys" #: web/templates/mail/payment/details.gotxt:25 #: web/templates/public/booking/fields.gohtml:100 #: web/templates/admin/payment/details.gohtml:110 -#: web/templates/admin/booking/fields.gohtml:139 +#: web/templates/admin/booking/fields.gohtml:140 msgctxt "input" msgid "Dogs" msgstr "Gossos" #: web/templates/mail/payment/details.gotxt:26 #: web/templates/admin/payment/details.gohtml:114 -#: web/templates/admin/booking/fields.gohtml:166 pkg/booking/cart.go:244 +#: web/templates/admin/booking/fields.gohtml:167 pkg/booking/cart.go:242 msgctxt "cart" msgid "Tourist tax" msgstr "Impost turístic" @@ -239,7 +239,7 @@ msgstr "Opcions del tipus d’allotjament" #: web/templates/mail/payment/details.gotxt:39 #: web/templates/public/booking/fields.gohtml:146 #: web/templates/admin/payment/details.gohtml:140 -#: web/templates/admin/booking/fields.gohtml:187 +#: web/templates/admin/booking/fields.gohtml:188 msgctxt "title" msgid "Customer Details" msgstr "Detalls del client" @@ -247,7 +247,7 @@ msgstr "Detalls del client" #: web/templates/mail/payment/details.gotxt:41 #: web/templates/public/booking/fields.gohtml:149 #: web/templates/admin/payment/details.gohtml:143 -#: web/templates/admin/booking/fields.gohtml:190 +#: web/templates/admin/booking/fields.gohtml:191 msgctxt "input" msgid "Full name" msgstr "Nom i cognoms" @@ -930,7 +930,7 @@ msgstr "Menú" #: web/templates/admin/campsite/type/option/index.gohtml:10 #: web/templates/admin/campsite/type/index.gohtml:10 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:95 -#: web/templates/admin/booking/fields.gohtml:265 +#: web/templates/admin/booking/fields.gohtml:266 msgctxt "title" msgid "Campsites" msgstr "Allotjaments" @@ -978,6 +978,7 @@ msgid "Booking Period" msgstr "Període de reserva" #: web/templates/public/booking/fields.gohtml:56 +#: web/templates/admin/booking/checkin.gohtml:20 msgctxt "title" msgid "Guests" msgstr "Hostes" @@ -987,18 +988,18 @@ msgid "Note: Due to guest capacity, we have added more accommodations to the boo msgstr "Nota: S’han afegit més allotjaments a la reserva degut a la capacitat de cadascuna, però no es garanteix que estiguin de costat." #: web/templates/public/booking/fields.gohtml:109 -#: web/templates/admin/booking/fields.gohtml:178 +#: web/templates/admin/booking/fields.gohtml:179 msgid "Note: This accommodation does not allow dogs." msgstr "Nota: A aquest allotjament no s’hi permeten gossos." #: web/templates/public/booking/fields.gohtml:121 -#: web/templates/admin/booking/fields.gohtml:55 +#: web/templates/admin/booking/fields.gohtml:56 msgctxt "input" msgid "Area preferences (optional)" msgstr "Preferències d’àrea (opcional)" #: web/templates/public/booking/fields.gohtml:123 -#: web/templates/admin/booking/fields.gohtml:59 +#: web/templates/admin/booking/fields.gohtml:60 msgid "Campground map" msgstr "Mapa del càmping" @@ -1008,12 +1009,13 @@ msgid "Town or village" msgstr "Població" #: web/templates/public/booking/fields.gohtml:193 -#: web/templates/admin/booking/fields.gohtml:203 +#: web/templates/admin/booking/fields.gohtml:204 +#: web/templates/admin/booking/guest.gohtml:109 msgid "Choose a country" msgstr "Esculli un país" #: web/templates/public/booking/fields.gohtml:247 -#: web/templates/admin/booking/fields.gohtml:258 +#: web/templates/admin/booking/fields.gohtml:259 msgctxt "input" msgid "ACSI card? (optional)" msgstr "Targeta ACSI? (opcional)" @@ -1098,8 +1100,8 @@ msgid "Down payment" msgstr "A compte" #: web/templates/admin/payment/index.gohtml:24 -#: web/templates/admin/booking/fields.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:172 +#: web/templates/admin/booking/fields.gohtml:75 +#: web/templates/admin/booking/fields.gohtml:173 msgctxt "header" msgid "Total" msgstr "Total" @@ -1194,7 +1196,7 @@ msgstr "Contingut" #: web/templates/admin/amenity/form.gohtml:91 #: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/media/form.gohtml:39 -#: web/templates/admin/booking/fields.gohtml:272 +#: web/templates/admin/booking/form.gohtml:45 msgctxt "action" msgid "Update" msgstr "Actualitza" @@ -1214,7 +1216,7 @@ msgstr "Actualitza" #: web/templates/admin/amenity/feature/form.gohtml:67 #: web/templates/admin/amenity/carousel/form.gohtml:52 #: web/templates/admin/amenity/form.gohtml:93 -#: web/templates/admin/booking/fields.gohtml:274 +#: web/templates/admin/booking/form.gohtml:47 msgctxt "action" msgid "Add" msgstr "Afegeix" @@ -2161,7 +2163,7 @@ msgid "Add Amenity" msgstr "Afegeix instaŀlació" #: web/templates/admin/amenity/index.gohtml:20 -#: web/templates/admin/booking/grid.gohtml:13 +#: web/templates/admin/booking/grid.gohtml:15 msgctxt "header" msgid "Label" msgstr "Etiqueta" @@ -2204,7 +2206,8 @@ msgid "Logout" msgstr "Surt" #: web/templates/admin/layout.gohtml:92 -#: web/templates/admin/booking/form.gohtml:15 +#: web/templates/admin/booking/form.gohtml:19 +#: web/templates/admin/booking/checkin.gohtml:10 #: web/templates/admin/booking/index.gohtml:6 #: web/templates/admin/booking/index.gohtml:16 msgctxt "title" @@ -2312,51 +2315,53 @@ msgctxt "title" msgid "Upload Media" msgstr "Pujada de mèdia" -#: web/templates/admin/booking/fields.gohtml:18 +#: web/templates/admin/booking/fields.gohtml:19 msgid "Choose an accommodation" msgstr "Esculliu un allotjament" -#: web/templates/admin/booking/fields.gohtml:72 +#: web/templates/admin/booking/fields.gohtml:73 msgctxt "header" msgid "Units" msgstr "Unitats" -#: web/templates/admin/booking/fields.gohtml:73 +#: web/templates/admin/booking/fields.gohtml:74 msgctxt "header" msgid "Decription" msgstr "Descripció" -#: web/templates/admin/booking/fields.gohtml:80 pkg/booking/cart.go:234 +#: web/templates/admin/booking/fields.gohtml:81 pkg/booking/cart.go:232 msgctxt "cart" msgid "Night" msgstr "Nit" -#: web/templates/admin/booking/fields.gohtml:199 +#: web/templates/admin/booking/fields.gohtml:200 msgctxt "input" msgid "Country (optional)" msgstr "País (opcional)" -#: web/templates/admin/booking/fields.gohtml:211 +#: web/templates/admin/booking/fields.gohtml:212 +#: web/templates/admin/booking/guest.gohtml:128 msgctxt "input" msgid "Address (optional)" msgstr "Adreça (opcional)" -#: web/templates/admin/booking/fields.gohtml:220 +#: web/templates/admin/booking/fields.gohtml:221 msgctxt "input" msgid "Postcode (optional)" msgstr "Codi postal (opcional)" -#: web/templates/admin/booking/fields.gohtml:229 +#: web/templates/admin/booking/fields.gohtml:230 msgctxt "input" msgid "Town or village (optional)" msgstr "Població (opcional)" -#: web/templates/admin/booking/fields.gohtml:238 +#: web/templates/admin/booking/fields.gohtml:239 msgctxt "input" msgid "Email (optional)" msgstr "Correu-e (opcional)" -#: web/templates/admin/booking/fields.gohtml:247 +#: web/templates/admin/booking/fields.gohtml:248 +#: web/templates/admin/booking/guest.gohtml:117 msgctxt "input" msgid "Phone (optional)" msgstr "Telèfon (opcional)" @@ -2371,6 +2376,31 @@ msgctxt "title" msgid "New Booking" msgstr "Nova reserva" +#: web/templates/admin/booking/form.gohtml:25 +msgctxt "action" +msgid "Check-in Booking" +msgstr "Registra la reserva" + +#: web/templates/admin/booking/checkin.gohtml:6 +msgctxt "title" +msgid "Check-in Booking" +msgstr "Registre de la reserva" + +#: web/templates/admin/booking/checkin.gohtml:15 +msgctxt "action" +msgid "Edit Booking" +msgstr "Edita la reserva" + +#: web/templates/admin/booking/checkin.gohtml:26 +msgctxt "action" +msgid "Check-in" +msgstr "Registra" + +#: web/templates/admin/booking/checkin.gohtml:31 +msgctxt "action" +msgid "Add another guest" +msgstr "Afegeix un altre hoste" + #: web/templates/admin/booking/index.gohtml:14 msgctxt "action" msgid "Add Booking" @@ -2400,6 +2430,64 @@ msgstr "Nom del titular" msgid "No booking found." msgstr "No s’ha trobat cap reserva." +#: web/templates/admin/booking/guest.gohtml:5 +msgctxt "action" +msgid "Remove" +msgstr "Esborra" + +#: web/templates/admin/booking/guest.gohtml:8 +msgctxt "input" +msgid "ID document number" +msgstr "Número de document d’identitat" + +#: web/templates/admin/booking/guest.gohtml:20 +msgctxt "input" +msgid "ID document type" +msgstr "Tipus de document" + +#: web/templates/admin/booking/guest.gohtml:25 +msgid "Choose an ID document type" +msgstr "Esculli un tipus de document" + +#: web/templates/admin/booking/guest.gohtml:33 +msgctxt "input" +msgid "ID document issue date (if any)" +msgstr "Data d’expedició (si hi consta)" + +#: web/templates/admin/booking/guest.gohtml:44 +msgctxt "input" +msgid "First surname" +msgstr "Primer cognom" + +#: web/templates/admin/booking/guest.gohtml:56 +msgctxt "input" +msgid "Second surname (if has one)" +msgstr "Segon cognom (si en té)" + +#: web/templates/admin/booking/guest.gohtml:67 +msgctxt "input" +msgid "Given name" +msgstr "Nom" + +#: web/templates/admin/booking/guest.gohtml:79 +msgctxt "input" +msgid "Sex" +msgstr "Sexe" + +#: web/templates/admin/booking/guest.gohtml:84 +msgid "Choose a sex" +msgstr "Esculli un sexe" + +#: web/templates/admin/booking/guest.gohtml:92 +msgctxt "input" +msgid "Birthdate" +msgstr "Data de naixement" + +#: web/templates/admin/booking/guest.gohtml:104 +msgctxt "input" +msgid "Nationality" +msgstr "Nacionalitat" + #: pkg/payment/settings.go:37 msgctxt "redsys environment" msgid "Test" @@ -2501,12 +2589,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:224 -#: pkg/booking/public.go:545 +#: pkg/booking/public.go:596 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:225 -#: pkg/booking/admin.go:316 pkg/booking/public.go:546 +#: pkg/booking/admin.go:437 pkg/booking/public.go:597 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." @@ -2717,8 +2805,8 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Mainada (entre 2 i 10 anys)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:292 pkg/booking/public.go:173 -#: pkg/booking/public.go:228 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:413 pkg/booking/public.go:177 +#: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "El tipus d’allotjament escollit no és vàlid." @@ -2814,7 +2902,8 @@ 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:207 pkg/booking/public.go:530 +#: pkg/company/admin.go:207 pkg/booking/checkin.go:301 +#: pkg/booking/public.go:581 msgid "Selected country is not valid." msgstr "El país escollit no és vàlid." @@ -2834,15 +2923,16 @@ 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:219 pkg/booking/public.go:548 +#: pkg/company/admin.go:219 pkg/booking/public.go:599 msgid "Phone can not be empty." msgstr "No podeu deixar el telèfon en blanc." -#: pkg/company/admin.go:220 pkg/booking/admin.go:321 pkg/booking/public.go:549 +#: pkg/company/admin.go:220 pkg/booking/checkin.go:305 pkg/booking/admin.go:442 +#: pkg/booking/public.go:600 msgid "This phone number is not valid." msgstr "Aquest número de telèfon no és vàlid." -#: pkg/company/admin.go:230 pkg/booking/public.go:538 +#: pkg/company/admin.go:230 pkg/booking/public.go:589 msgid "Address can not be empty." msgstr "No podeu deixar l’adreça en blanc." @@ -2854,11 +2944,11 @@ msgstr "No podeu deixar la població en blanc." msgid "Province can not be empty." msgstr "No podeu deixar la província en blanc." -#: pkg/company/admin.go:233 pkg/booking/public.go:540 +#: pkg/company/admin.go:233 pkg/booking/public.go:591 msgid "Postcode can not be empty." msgstr "No podeu deixar el codi postal en blanc." -#: pkg/company/admin.go:234 pkg/booking/admin.go:311 pkg/booking/public.go:541 +#: pkg/company/admin.go:234 pkg/booking/admin.go:432 pkg/booking/public.go:592 msgid "This postcode is not valid." msgstr "Aquest codi postal no és vàlid." @@ -2910,169 +3000,202 @@ 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:235 +#: pkg/booking/checkin.go:285 +msgid "Selected ID document type is not valid." +msgstr "El tipus de document d’identitat escollit no és vàlid." + +#: pkg/booking/checkin.go:286 +msgid "ID document number can not be empty." +msgstr "No podeu deixar el número document d’identitat en blanc." + +#: pkg/booking/checkin.go:288 +msgid "ID document issue date must be a valid date." +msgstr "La data d’expedició del document d’identitat ha de ser una data vàlida." + +#: pkg/booking/checkin.go:289 +msgid "ID document issue date must be in the past." +msgstr "La data d’expedició del document d’identitat ha de ser al passat." + +#: pkg/booking/checkin.go:292 pkg/booking/checkin.go:293 +#: pkg/booking/admin.go:425 pkg/booking/public.go:585 +msgid "Full name can not be empty." +msgstr "No podeu deixar el nom i els cognoms en blanc." + +#: pkg/booking/checkin.go:294 +msgid "Selected sex is not valid." +msgstr "El sexe escollit no és vàlid." + +#: pkg/booking/checkin.go:295 +msgid "Birthdate can not be empty" +msgstr "No podeu deixar la data de naixement en blanc." + +#: pkg/booking/checkin.go:296 +msgid "Birthdate must be a valid date." +msgstr "La data de naixement ha de ser una data vàlida." + +#: pkg/booking/checkin.go:297 +msgid "Birthdate must be in the past." +msgstr "La data de naixement ha de ser al passat." + +#: pkg/booking/cart.go:233 msgctxt "cart" msgid "Adult" msgstr "Adult" -#: pkg/booking/cart.go:236 +#: pkg/booking/cart.go:234 msgctxt "cart" msgid "Teenager" msgstr "Adolescent" -#: pkg/booking/cart.go:237 +#: pkg/booking/cart.go:235 msgctxt "cart" msgid "Child" msgstr "Nen" -#: pkg/booking/cart.go:238 +#: pkg/booking/cart.go:236 msgctxt "cart" msgid "Dog" msgstr "Gos" -#: pkg/booking/admin.go:144 +#: pkg/booking/admin.go:217 msgctxt "filename" msgid "bookings.ods" msgstr "reserves.ods" -#: pkg/booking/admin.go:304 pkg/booking/public.go:534 -msgid "Full name can not be empty." -msgstr "No podeu deixar el nom i els cognoms en blanc." - -#: pkg/booking/admin.go:305 pkg/booking/public.go:535 +#: pkg/booking/admin.go:426 pkg/booking/public.go:586 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/admin.go:310 +#: pkg/booking/admin.go:431 msgid "Country can not be empty to validate the postcode." msgstr "No podeu deixar el país en blanc per validar el codi postal." -#: pkg/booking/admin.go:320 +#: pkg/booking/admin.go:441 msgid "Country can not be empty to validate the phone." msgstr "No podeu deixar el país en blanc per validar el telèfon." -#: pkg/booking/admin.go:327 +#: pkg/booking/admin.go:448 msgid "You must select at least one accommodation." msgstr "Heu d’escollir com a mínim un allotjament." -#: pkg/booking/admin.go:333 +#: pkg/booking/admin.go:454 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Els allotjaments escollits no estan disponibles a les dates demanades." -#: pkg/booking/public.go:277 pkg/booking/public.go:306 +#: pkg/booking/public.go:284 pkg/booking/public.go:313 msgid "Arrival date must be a valid date." msgstr "La data d’arribada ha de ser una data vàlida." -#: pkg/booking/public.go:291 pkg/booking/public.go:313 +#: pkg/booking/public.go:298 pkg/booking/public.go:320 msgid "Departure date must be a valid date." msgstr "La data de sortida ha de ser una data vàlida." -#: pkg/booking/public.go:305 +#: pkg/booking/public.go:312 msgid "Arrival date can not be empty" msgstr "No podeu deixar la data d’arribada en blanc." -#: pkg/booking/public.go:307 +#: pkg/booking/public.go:314 #, c-format msgid "Arrival date must be %s or after." msgstr "La data d’arribada ha de ser igual o posterior a %s." -#: pkg/booking/public.go:308 +#: pkg/booking/public.go:315 #, c-format msgid "Arrival date must be %s or before." msgstr "La data d’arribada ha de ser anterior o igual a %s." -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:319 msgid "Departure date can not be empty" msgstr "No podeu deixar la data de sortida en blanc." -#: pkg/booking/public.go:314 +#: pkg/booking/public.go:321 #, c-format msgid "Departure date must be %s or after." msgstr "La data de sortida ha de ser igual o posterior a %s." -#: pkg/booking/public.go:315 +#: pkg/booking/public.go:322 #, c-format msgid "Departure date must be %s or before." msgstr "La data de sortida ha de ser anterior o igual a %s." -#: pkg/booking/public.go:369 +#: pkg/booking/public.go:380 #, c-format msgid "There can be at most %d guests in this accommodation." msgstr "Hi poden haver com a màxim %d convidats a aquest allotjament." -#: pkg/booking/public.go:389 +#: pkg/booking/public.go:400 msgid "Number of adults can not be empty" msgstr "No podeu deixar el número d’adults en blanc." -#: pkg/booking/public.go:390 +#: pkg/booking/public.go:401 msgid "Number of adults must be an integer." msgstr "El número d’adults ha de ser enter." -#: pkg/booking/public.go:391 +#: pkg/booking/public.go:402 msgid "There must be at least one adult." msgstr "Hi ha d’haver com a mínim un adult." -#: pkg/booking/public.go:394 +#: pkg/booking/public.go:405 msgid "Number of teenagers can not be empty" msgstr "No podeu deixar el número d’adolescents en blanc." -#: pkg/booking/public.go:395 +#: pkg/booking/public.go:406 msgid "Number of teenagers must be an integer." msgstr "El número d’adolescents ha de ser enter." -#: pkg/booking/public.go:396 +#: pkg/booking/public.go:407 msgid "Number of teenagers can not be negative." msgstr "El número d’adolescents no pot ser negatiu." -#: pkg/booking/public.go:399 +#: pkg/booking/public.go:410 msgid "Number of children can not be empty" msgstr "No podeu deixar el número de nens en blanc." -#: pkg/booking/public.go:400 +#: pkg/booking/public.go:411 msgid "Number of children must be an integer." msgstr "El número de nens ha de ser enter." -#: pkg/booking/public.go:401 +#: pkg/booking/public.go:412 msgid "Number of children can not be negative." msgstr "El número de nens no pot ser negatiu." -#: pkg/booking/public.go:404 +#: pkg/booking/public.go:415 msgid "Number of dogs can not be empty" msgstr "No podeu deixar el número de gossos en blanc." -#: pkg/booking/public.go:405 +#: pkg/booking/public.go:416 msgid "Number of dogs must be an integer." msgstr "El número de gossos ha de ser enter." -#: pkg/booking/public.go:406 +#: pkg/booking/public.go:417 msgid "Number of dogs can not be negative." msgstr "El número de gossos no pot ser negatiu." -#: pkg/booking/public.go:477 +#: pkg/booking/public.go:524 #, c-format msgid "%s can not be empty" msgstr "No podeu deixar %s en blanc." -#: pkg/booking/public.go:478 +#: pkg/booking/public.go:525 #, c-format msgid "%s must be an integer." msgstr "%s ha de ser un número enter." -#: pkg/booking/public.go:479 +#: pkg/booking/public.go:526 #, 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:480 +#: pkg/booking/public.go:527 #, c-format msgid "%s must be at most %d." msgstr "El valor de %s ha de ser com a màxim %d." -#: pkg/booking/public.go:539 +#: pkg/booking/public.go:590 msgid "Town or village can not be empty." msgstr "No podeu deixar la població en blanc." -#: pkg/booking/public.go:554 +#: pkg/booking/public.go:605 msgid "It is mandatory to agree to the reservation conditions." msgstr "És obligatori acceptar les condicions de reserves." diff --git a/po/es.po b/po/es.po index 77ad1b1..abb8377 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-04-24 19:59+0200\n" +"POT-Creation-Date: 2024-04-26 16:53+0200\n" "PO-Revision-Date: 2024-02-06 10:04+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -116,7 +116,7 @@ msgstr "Reserva" #: web/templates/mail/payment/details.gotxt:16 #: web/templates/public/booking/fields.gohtml:14 #: web/templates/admin/payment/details.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:12 +#: web/templates/admin/booking/fields.gohtml:13 msgctxt "title" msgid "Accommodation" msgstr "Alojamientos" @@ -155,7 +155,7 @@ msgstr "No" #: web/templates/public/campsite/dates.gohtml:4 #: web/templates/public/booking/fields.gohtml:30 #: web/templates/admin/payment/details.gohtml:86 -#: web/templates/admin/booking/fields.gohtml:31 +#: web/templates/admin/booking/fields.gohtml:32 msgctxt "input" msgid "Arrival date" msgstr "Fecha de llegada" @@ -164,7 +164,7 @@ msgstr "Fecha de llegada" #: web/templates/public/campsite/dates.gohtml:15 #: web/templates/public/booking/fields.gohtml:41 #: web/templates/admin/payment/details.gohtml:90 -#: web/templates/admin/booking/fields.gohtml:42 +#: web/templates/admin/booking/fields.gohtml:43 msgctxt "input" msgid "Departure date" msgstr "Fecha de salida" @@ -178,7 +178,7 @@ msgstr "Noches" #: web/templates/mail/payment/details.gotxt:22 #: web/templates/public/booking/fields.gohtml:60 #: web/templates/admin/payment/details.gohtml:98 -#: web/templates/admin/booking/fields.gohtml:92 +#: web/templates/admin/booking/fields.gohtml:93 msgctxt "input" msgid "Adults aged 17 or older" msgstr "Adultos de 17 años o más" @@ -186,7 +186,7 @@ msgstr "Adultos de 17 años o más" #: web/templates/mail/payment/details.gotxt:23 #: web/templates/public/booking/fields.gohtml:71 #: web/templates/admin/payment/details.gohtml:102 -#: web/templates/admin/booking/fields.gohtml:108 +#: web/templates/admin/booking/fields.gohtml:109 msgctxt "input" msgid "Teenagers from 11 to 16 years old" msgstr "Adolescentes de 11 a 16 años" @@ -194,7 +194,7 @@ msgstr "Adolescentes de 11 a 16 años" #: web/templates/mail/payment/details.gotxt:24 #: web/templates/public/booking/fields.gohtml:82 #: web/templates/admin/payment/details.gohtml:106 -#: web/templates/admin/booking/fields.gohtml:124 +#: web/templates/admin/booking/fields.gohtml:125 msgctxt "input" msgid "Children from 2 to 10 years old" msgstr "Niños de 2 a 10 años" @@ -202,14 +202,14 @@ msgstr "Niños de 2 a 10 años" #: web/templates/mail/payment/details.gotxt:25 #: web/templates/public/booking/fields.gohtml:100 #: web/templates/admin/payment/details.gohtml:110 -#: web/templates/admin/booking/fields.gohtml:139 +#: web/templates/admin/booking/fields.gohtml:140 msgctxt "input" msgid "Dogs" msgstr "Perros" #: web/templates/mail/payment/details.gotxt:26 #: web/templates/admin/payment/details.gohtml:114 -#: web/templates/admin/booking/fields.gohtml:166 pkg/booking/cart.go:244 +#: web/templates/admin/booking/fields.gohtml:167 pkg/booking/cart.go:242 msgctxt "cart" msgid "Tourist tax" msgstr "Impuesto turístico" @@ -239,7 +239,7 @@ msgstr "Opciones del tipo de alojamiento" #: web/templates/mail/payment/details.gotxt:39 #: web/templates/public/booking/fields.gohtml:146 #: web/templates/admin/payment/details.gohtml:140 -#: web/templates/admin/booking/fields.gohtml:187 +#: web/templates/admin/booking/fields.gohtml:188 msgctxt "title" msgid "Customer Details" msgstr "Detalles del cliente" @@ -247,7 +247,7 @@ msgstr "Detalles del cliente" #: web/templates/mail/payment/details.gotxt:41 #: web/templates/public/booking/fields.gohtml:149 #: web/templates/admin/payment/details.gohtml:143 -#: web/templates/admin/booking/fields.gohtml:190 +#: web/templates/admin/booking/fields.gohtml:191 msgctxt "input" msgid "Full name" msgstr "Nombre y apellidos" @@ -930,7 +930,7 @@ msgstr "Menú" #: web/templates/admin/campsite/type/option/index.gohtml:10 #: web/templates/admin/campsite/type/index.gohtml:10 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:95 -#: web/templates/admin/booking/fields.gohtml:265 +#: web/templates/admin/booking/fields.gohtml:266 msgctxt "title" msgid "Campsites" msgstr "Alojamientos" @@ -978,6 +978,7 @@ msgid "Booking Period" msgstr "Periodo de reserva" #: web/templates/public/booking/fields.gohtml:56 +#: web/templates/admin/booking/checkin.gohtml:20 msgctxt "title" msgid "Guests" msgstr "Huéspedes" @@ -987,18 +988,18 @@ msgid "Note: Due to guest capacity, we have added more accommodations to the boo msgstr "Nota: Se han añadido alojamientos a la reserva debido a la capacidad de cada una, pero no se garantiza que estén de lado." #: web/templates/public/booking/fields.gohtml:109 -#: web/templates/admin/booking/fields.gohtml:178 +#: web/templates/admin/booking/fields.gohtml:179 msgid "Note: This accommodation does not allow dogs." msgstr "Nota: En este alojamiento no se permiten perros." #: web/templates/public/booking/fields.gohtml:121 -#: web/templates/admin/booking/fields.gohtml:55 +#: web/templates/admin/booking/fields.gohtml:56 msgctxt "input" msgid "Area preferences (optional)" msgstr "Preferencias de área (opcional)" #: web/templates/public/booking/fields.gohtml:123 -#: web/templates/admin/booking/fields.gohtml:59 +#: web/templates/admin/booking/fields.gohtml:60 msgid "Campground map" msgstr "Mapa del camping" @@ -1008,12 +1009,13 @@ msgid "Town or village" msgstr "Población" #: web/templates/public/booking/fields.gohtml:193 -#: web/templates/admin/booking/fields.gohtml:203 +#: web/templates/admin/booking/fields.gohtml:204 +#: web/templates/admin/booking/guest.gohtml:109 msgid "Choose a country" msgstr "Escoja un país" #: web/templates/public/booking/fields.gohtml:247 -#: web/templates/admin/booking/fields.gohtml:258 +#: web/templates/admin/booking/fields.gohtml:259 msgctxt "input" msgid "ACSI card? (optional)" msgstr "¿Tarjeta ACSI? (opcional)" @@ -1098,8 +1100,8 @@ msgid "Down payment" msgstr "A cuenta" #: web/templates/admin/payment/index.gohtml:24 -#: web/templates/admin/booking/fields.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:172 +#: web/templates/admin/booking/fields.gohtml:75 +#: web/templates/admin/booking/fields.gohtml:173 msgctxt "header" msgid "Total" msgstr "Total" @@ -1194,7 +1196,7 @@ msgstr "Contenido" #: web/templates/admin/amenity/form.gohtml:91 #: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/media/form.gohtml:39 -#: web/templates/admin/booking/fields.gohtml:272 +#: web/templates/admin/booking/form.gohtml:45 msgctxt "action" msgid "Update" msgstr "Actualizar" @@ -1214,7 +1216,7 @@ msgstr "Actualizar" #: web/templates/admin/amenity/feature/form.gohtml:67 #: web/templates/admin/amenity/carousel/form.gohtml:52 #: web/templates/admin/amenity/form.gohtml:93 -#: web/templates/admin/booking/fields.gohtml:274 +#: web/templates/admin/booking/form.gohtml:47 msgctxt "action" msgid "Add" msgstr "Añadir" @@ -2161,7 +2163,7 @@ msgid "Add Amenity" msgstr "Añadir instalación" #: web/templates/admin/amenity/index.gohtml:20 -#: web/templates/admin/booking/grid.gohtml:13 +#: web/templates/admin/booking/grid.gohtml:15 msgctxt "header" msgid "Label" msgstr "Etiqueta" @@ -2204,7 +2206,8 @@ msgid "Logout" msgstr "Salir" #: web/templates/admin/layout.gohtml:92 -#: web/templates/admin/booking/form.gohtml:15 +#: web/templates/admin/booking/form.gohtml:19 +#: web/templates/admin/booking/checkin.gohtml:10 #: web/templates/admin/booking/index.gohtml:6 #: web/templates/admin/booking/index.gohtml:16 msgctxt "title" @@ -2312,51 +2315,53 @@ msgctxt "title" msgid "Upload Media" msgstr "Subida de medio" -#: web/templates/admin/booking/fields.gohtml:18 +#: web/templates/admin/booking/fields.gohtml:19 msgid "Choose an accommodation" msgstr "Escoja un alojamiento" -#: web/templates/admin/booking/fields.gohtml:72 +#: web/templates/admin/booking/fields.gohtml:73 msgctxt "header" msgid "Units" msgstr "Unidades" -#: web/templates/admin/booking/fields.gohtml:73 +#: web/templates/admin/booking/fields.gohtml:74 msgctxt "header" msgid "Decription" msgstr "Descripción" -#: web/templates/admin/booking/fields.gohtml:80 pkg/booking/cart.go:234 +#: web/templates/admin/booking/fields.gohtml:81 pkg/booking/cart.go:232 msgctxt "cart" msgid "Night" msgstr "Noche" -#: web/templates/admin/booking/fields.gohtml:199 +#: web/templates/admin/booking/fields.gohtml:200 msgctxt "input" msgid "Country (optional)" msgstr "País (opcional)" -#: web/templates/admin/booking/fields.gohtml:211 +#: web/templates/admin/booking/fields.gohtml:212 +#: web/templates/admin/booking/guest.gohtml:128 msgctxt "input" msgid "Address (optional)" msgstr "Dirección (opcional)" -#: web/templates/admin/booking/fields.gohtml:220 +#: web/templates/admin/booking/fields.gohtml:221 msgctxt "input" msgid "Postcode (optional)" msgstr "Código postal (opcional)" -#: web/templates/admin/booking/fields.gohtml:229 +#: web/templates/admin/booking/fields.gohtml:230 msgctxt "input" msgid "Town or village (optional)" msgstr "Población (opcional)" -#: web/templates/admin/booking/fields.gohtml:238 +#: web/templates/admin/booking/fields.gohtml:239 msgctxt "input" msgid "Email (optional)" msgstr "Correo-e (opcional)" -#: web/templates/admin/booking/fields.gohtml:247 +#: web/templates/admin/booking/fields.gohtml:248 +#: web/templates/admin/booking/guest.gohtml:117 msgctxt "input" msgid "Phone (optional)" msgstr "Teléfono (opcional)" @@ -2371,6 +2376,31 @@ msgctxt "title" msgid "New Booking" msgstr "Nueva reserva" +#: web/templates/admin/booking/form.gohtml:25 +msgctxt "action" +msgid "Check-in Booking" +msgstr "Registrar reserva" + +#: web/templates/admin/booking/checkin.gohtml:6 +msgctxt "title" +msgid "Check-in Booking" +msgstr "Registro de la reserva" + +#: web/templates/admin/booking/checkin.gohtml:15 +msgctxt "action" +msgid "Edit Booking" +msgstr "Editar la reserva" + +#: web/templates/admin/booking/checkin.gohtml:26 +msgctxt "action" +msgid "Check-in" +msgstr "Registrar" + +#: web/templates/admin/booking/checkin.gohtml:31 +msgctxt "action" +msgid "Add another guest" +msgstr "Añadir otro huésped" + #: web/templates/admin/booking/index.gohtml:14 msgctxt "action" msgid "Add Booking" @@ -2400,6 +2430,64 @@ msgstr "Nombre del titular" msgid "No booking found." msgstr "No se ha encontrado ninguna reserva." +#: web/templates/admin/booking/guest.gohtml:5 +msgctxt "action" +msgid "Remove" +msgstr "Borrar" + +#: web/templates/admin/booking/guest.gohtml:8 +msgctxt "input" +msgid "ID document number" +msgstr "Número de documento de identidad" + +#: web/templates/admin/booking/guest.gohtml:20 +msgctxt "input" +msgid "ID document type" +msgstr "Tipo de documento" + +#: web/templates/admin/booking/guest.gohtml:25 +msgid "Choose an ID document type" +msgstr "Escoja un tipo de documento" + +#: web/templates/admin/booking/guest.gohtml:33 +msgctxt "input" +msgid "ID document issue date (if any)" +msgstr "Fecha expedición del documento (si hay)" + +#: web/templates/admin/booking/guest.gohtml:44 +msgctxt "input" +msgid "First surname" +msgstr "Primer apellido" + +#: web/templates/admin/booking/guest.gohtml:56 +msgctxt "input" +msgid "Second surname (if has one)" +msgstr "Segundo apellido (si tiene)" + +#: web/templates/admin/booking/guest.gohtml:67 +msgctxt "input" +msgid "Given name" +msgstr "Nombre" + +#: web/templates/admin/booking/guest.gohtml:79 +msgctxt "input" +msgid "Sex" +msgstr "Sexo" + +#: web/templates/admin/booking/guest.gohtml:84 +msgid "Choose a sex" +msgstr "Escoja un sexo" + +#: web/templates/admin/booking/guest.gohtml:92 +msgctxt "input" +msgid "Birthdate" +msgstr "Fecha de nacimiento" + +#: web/templates/admin/booking/guest.gohtml:104 +msgctxt "input" +msgid "Nationality" +msgstr "Nacionalidad" + #: pkg/payment/settings.go:37 msgctxt "redsys environment" msgid "Test" @@ -2501,12 +2589,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:224 -#: pkg/booking/public.go:545 +#: pkg/booking/public.go:596 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:225 -#: pkg/booking/admin.go:316 pkg/booking/public.go:546 +#: pkg/booking/admin.go:437 pkg/booking/public.go:597 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." @@ -2717,8 +2805,8 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Niños (de 2 a 10 años)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:292 pkg/booking/public.go:173 -#: pkg/booking/public.go:228 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:413 pkg/booking/public.go:177 +#: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "El tipo de alojamiento escogido no es válido." @@ -2814,7 +2902,8 @@ 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:207 pkg/booking/public.go:530 +#: pkg/company/admin.go:207 pkg/booking/checkin.go:301 +#: pkg/booking/public.go:581 msgid "Selected country is not valid." msgstr "El país escogido no es válido." @@ -2834,15 +2923,16 @@ 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:219 pkg/booking/public.go:548 +#: pkg/company/admin.go:219 pkg/booking/public.go:599 msgid "Phone can not be empty." msgstr "No podéis dejar el teléfono en blanco." -#: pkg/company/admin.go:220 pkg/booking/admin.go:321 pkg/booking/public.go:549 +#: pkg/company/admin.go:220 pkg/booking/checkin.go:305 pkg/booking/admin.go:442 +#: pkg/booking/public.go:600 msgid "This phone number is not valid." msgstr "Este teléfono no es válido." -#: pkg/company/admin.go:230 pkg/booking/public.go:538 +#: pkg/company/admin.go:230 pkg/booking/public.go:589 msgid "Address can not be empty." msgstr "No podéis dejar la dirección en blanco." @@ -2854,11 +2944,11 @@ msgstr "No podéis dejar la población en blanco." msgid "Province can not be empty." msgstr "No podéis dejar la provincia en blanco." -#: pkg/company/admin.go:233 pkg/booking/public.go:540 +#: pkg/company/admin.go:233 pkg/booking/public.go:591 msgid "Postcode can not be empty." msgstr "No podéis dejar el código postal en blanco." -#: pkg/company/admin.go:234 pkg/booking/admin.go:311 pkg/booking/public.go:541 +#: pkg/company/admin.go:234 pkg/booking/admin.go:432 pkg/booking/public.go:592 msgid "This postcode is not valid." msgstr "Este código postal no es válido." @@ -2910,169 +3000,202 @@ 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:235 +#: pkg/booking/checkin.go:285 +msgid "Selected ID document type is not valid." +msgstr "El tipo de documento de identidad escogido no es válido." + +#: pkg/booking/checkin.go:286 +msgid "ID document number can not be empty." +msgstr "No podéis dejar el número del documento de identidad en blanco." + +#: pkg/booking/checkin.go:288 +msgid "ID document issue date must be a valid date." +msgstr "La fecha de expedición del documento de identidad tiene que ser una fecha válida." + +#: pkg/booking/checkin.go:289 +msgid "ID document issue date must be in the past." +msgstr "La fecha de expedición del documento de identidad tiene que ser del pasado." + +#: pkg/booking/checkin.go:292 pkg/booking/checkin.go:293 +#: pkg/booking/admin.go:425 pkg/booking/public.go:585 +msgid "Full name can not be empty." +msgstr "No podéis dejar el nombre y los apellidos en blanco." + +#: pkg/booking/checkin.go:294 +msgid "Selected sex is not valid." +msgstr "El sexo escogido no es válido." + +#: pkg/booking/checkin.go:295 +msgid "Birthdate can not be empty" +msgstr "No podéis dejar la fecha de nacimiento en blanco." + +#: pkg/booking/checkin.go:296 +msgid "Birthdate must be a valid date." +msgstr "La fecha de nacimiento tiene que ser una fecha válida." + +#: pkg/booking/checkin.go:297 +msgid "Birthdate must be in the past." +msgstr "La fecha de nacimiento tiene que ser del pasado." + +#: pkg/booking/cart.go:233 msgctxt "cart" msgid "Adult" msgstr "Adulto" -#: pkg/booking/cart.go:236 +#: pkg/booking/cart.go:234 msgctxt "cart" msgid "Teenager" msgstr "Adolescente" -#: pkg/booking/cart.go:237 +#: pkg/booking/cart.go:235 msgctxt "cart" msgid "Child" msgstr "Niño" -#: pkg/booking/cart.go:238 +#: pkg/booking/cart.go:236 msgctxt "cart" msgid "Dog" msgstr "Perro" -#: pkg/booking/admin.go:144 +#: pkg/booking/admin.go:217 msgctxt "filename" msgid "bookings.ods" msgstr "reservas.ods" -#: pkg/booking/admin.go:304 pkg/booking/public.go:534 -msgid "Full name can not be empty." -msgstr "No podéis dejar el nombre y los apellidos en blanco." - -#: pkg/booking/admin.go:305 pkg/booking/public.go:535 +#: pkg/booking/admin.go:426 pkg/booking/public.go:586 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/admin.go:310 +#: pkg/booking/admin.go:431 msgid "Country can not be empty to validate the postcode." msgstr "No podéis dejar el país en blanco para validar el código postal." -#: pkg/booking/admin.go:320 +#: pkg/booking/admin.go:441 msgid "Country can not be empty to validate the phone." msgstr "No podéis dejar el país en blanco para validar el teléfono." -#: pkg/booking/admin.go:327 +#: pkg/booking/admin.go:448 msgid "You must select at least one accommodation." msgstr "Tenéis que seleccionar como mínimo un alojamiento." -#: pkg/booking/admin.go:333 +#: pkg/booking/admin.go:454 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Los alojamientos seleccionados no tienen disponibilidad en las fechas pedidas." -#: pkg/booking/public.go:277 pkg/booking/public.go:306 +#: pkg/booking/public.go:284 pkg/booking/public.go:313 msgid "Arrival date must be a valid date." msgstr "La fecha de llegada tiene que ser una fecha válida." -#: pkg/booking/public.go:291 pkg/booking/public.go:313 +#: pkg/booking/public.go:298 pkg/booking/public.go:320 msgid "Departure date must be a valid date." msgstr "La fecha de partida tiene que ser una fecha válida." -#: pkg/booking/public.go:305 +#: pkg/booking/public.go:312 msgid "Arrival date can not be empty" msgstr "No podéis dejar la fecha de llegada en blanco." -#: pkg/booking/public.go:307 +#: pkg/booking/public.go:314 #, c-format msgid "Arrival date must be %s or after." msgstr "La fecha de llegada tiene que ser igual o posterior a %s." -#: pkg/booking/public.go:308 +#: pkg/booking/public.go:315 #, c-format msgid "Arrival date must be %s or before." msgstr "La fecha de llegada tiene que ser anterior o igual a %s." -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:319 msgid "Departure date can not be empty" msgstr "No podéis dejar la fecha de partida en blanco." -#: pkg/booking/public.go:314 +#: pkg/booking/public.go:321 #, c-format msgid "Departure date must be %s or after." msgstr "La fecha de partida tiene que igual o posterior a %s." -#: pkg/booking/public.go:315 +#: pkg/booking/public.go:322 #, c-format msgid "Departure date must be %s or before." msgstr "La fecha de partida tiene que ser anterior o igual a %s." -#: pkg/booking/public.go:369 +#: pkg/booking/public.go:380 #, c-format msgid "There can be at most %d guests in this accommodation." msgstr "Solo puede haber como máximo %d invitados en este alojamiento." -#: pkg/booking/public.go:389 +#: pkg/booking/public.go:400 msgid "Number of adults can not be empty" msgstr "No podéis dejar el número de adultos blanco." -#: pkg/booking/public.go:390 +#: pkg/booking/public.go:401 msgid "Number of adults must be an integer." msgstr "El número de adultos tiene que ser entero." -#: pkg/booking/public.go:391 +#: pkg/booking/public.go:402 msgid "There must be at least one adult." msgstr "Tiene que haber como mínimo un adulto." -#: pkg/booking/public.go:394 +#: pkg/booking/public.go:405 msgid "Number of teenagers can not be empty" msgstr "No podéis dejar el número de adolescentes en blanco." -#: pkg/booking/public.go:395 +#: pkg/booking/public.go:406 msgid "Number of teenagers must be an integer." msgstr "El número de adolescentes tiene que ser entero." -#: pkg/booking/public.go:396 +#: pkg/booking/public.go:407 msgid "Number of teenagers can not be negative." msgstr "El número de adolescentes no puede ser negativo." -#: pkg/booking/public.go:399 +#: pkg/booking/public.go:410 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:400 +#: pkg/booking/public.go:411 msgid "Number of children must be an integer." msgstr "El número de niños tiene que ser entero." -#: pkg/booking/public.go:401 +#: pkg/booking/public.go:412 msgid "Number of children can not be negative." msgstr "El número de niños no puede ser negativo." -#: pkg/booking/public.go:404 +#: pkg/booking/public.go:415 msgid "Number of dogs can not be empty" msgstr "No podéis dejar el número de perros en blanco." -#: pkg/booking/public.go:405 +#: pkg/booking/public.go:416 msgid "Number of dogs must be an integer." msgstr "El número de perros tiene que ser entero." -#: pkg/booking/public.go:406 +#: pkg/booking/public.go:417 msgid "Number of dogs can not be negative." msgstr "El número de perros no puede ser negativo." -#: pkg/booking/public.go:477 +#: pkg/booking/public.go:524 #, c-format msgid "%s can not be empty" msgstr "No podéis dejar %s en blanco." -#: pkg/booking/public.go:478 +#: pkg/booking/public.go:525 #, c-format msgid "%s must be an integer." msgstr "%s tiene que ser un número entero." -#: pkg/booking/public.go:479 +#: pkg/booking/public.go:526 #, c-format msgid "%s must be %d or greater." msgstr "%s tiene que ser como mínimo %d." -#: pkg/booking/public.go:480 +#: pkg/booking/public.go:527 #, c-format msgid "%s must be at most %d." msgstr "%s tiene que ser como máximo %d" -#: pkg/booking/public.go:539 +#: pkg/booking/public.go:590 msgid "Town or village can not be empty." msgstr "No podéis dejar la población en blanco." -#: pkg/booking/public.go:554 +#: pkg/booking/public.go:605 msgid "It is mandatory to agree to the reservation conditions." msgstr "Es obligatorio aceptar las condiciones de reserva." diff --git a/po/fr.po b/po/fr.po index 7ea0168..aae8f01 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-04-24 19:59+0200\n" +"POT-Creation-Date: 2024-04-26 16:53+0200\n" "PO-Revision-Date: 2024-02-06 10:05+0100\n" "Last-Translator: Oriol Carbonell \n" "Language-Team: French \n" @@ -116,7 +116,7 @@ msgstr "Réservation" #: web/templates/mail/payment/details.gotxt:16 #: web/templates/public/booking/fields.gohtml:14 #: web/templates/admin/payment/details.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:12 +#: web/templates/admin/booking/fields.gohtml:13 msgctxt "title" msgid "Accommodation" msgstr "Hébergement" @@ -155,7 +155,7 @@ msgstr "Non" #: web/templates/public/campsite/dates.gohtml:4 #: web/templates/public/booking/fields.gohtml:30 #: web/templates/admin/payment/details.gohtml:86 -#: web/templates/admin/booking/fields.gohtml:31 +#: web/templates/admin/booking/fields.gohtml:32 msgctxt "input" msgid "Arrival date" msgstr "Date d’arrivée" @@ -164,7 +164,7 @@ msgstr "Date d’arrivée" #: web/templates/public/campsite/dates.gohtml:15 #: web/templates/public/booking/fields.gohtml:41 #: web/templates/admin/payment/details.gohtml:90 -#: web/templates/admin/booking/fields.gohtml:42 +#: web/templates/admin/booking/fields.gohtml:43 msgctxt "input" msgid "Departure date" msgstr "Date de depart" @@ -178,7 +178,7 @@ msgstr "Nuits" #: web/templates/mail/payment/details.gotxt:22 #: web/templates/public/booking/fields.gohtml:60 #: web/templates/admin/payment/details.gohtml:98 -#: web/templates/admin/booking/fields.gohtml:92 +#: web/templates/admin/booking/fields.gohtml:93 msgctxt "input" msgid "Adults aged 17 or older" msgstr "Adultes âgés 17 ans ou plus" @@ -186,7 +186,7 @@ msgstr "Adultes âgés 17 ans ou plus" #: web/templates/mail/payment/details.gotxt:23 #: web/templates/public/booking/fields.gohtml:71 #: web/templates/admin/payment/details.gohtml:102 -#: web/templates/admin/booking/fields.gohtml:108 +#: web/templates/admin/booking/fields.gohtml:109 msgctxt "input" msgid "Teenagers from 11 to 16 years old" msgstr "Adolescents de 11 à 16 ans" @@ -194,7 +194,7 @@ msgstr "Adolescents de 11 à 16 ans" #: web/templates/mail/payment/details.gotxt:24 #: web/templates/public/booking/fields.gohtml:82 #: web/templates/admin/payment/details.gohtml:106 -#: web/templates/admin/booking/fields.gohtml:124 +#: web/templates/admin/booking/fields.gohtml:125 msgctxt "input" msgid "Children from 2 to 10 years old" msgstr "Enfants de 2 à 10 ans" @@ -202,14 +202,14 @@ msgstr "Enfants de 2 à 10 ans" #: web/templates/mail/payment/details.gotxt:25 #: web/templates/public/booking/fields.gohtml:100 #: web/templates/admin/payment/details.gohtml:110 -#: web/templates/admin/booking/fields.gohtml:139 +#: web/templates/admin/booking/fields.gohtml:140 msgctxt "input" msgid "Dogs" msgstr "Chiens" #: web/templates/mail/payment/details.gotxt:26 #: web/templates/admin/payment/details.gohtml:114 -#: web/templates/admin/booking/fields.gohtml:166 pkg/booking/cart.go:244 +#: web/templates/admin/booking/fields.gohtml:167 pkg/booking/cart.go:242 msgctxt "cart" msgid "Tourist tax" msgstr "Taxe touristique" @@ -239,7 +239,7 @@ msgstr "Options de type d’emplacement de camping" #: web/templates/mail/payment/details.gotxt:39 #: web/templates/public/booking/fields.gohtml:146 #: web/templates/admin/payment/details.gohtml:140 -#: web/templates/admin/booking/fields.gohtml:187 +#: web/templates/admin/booking/fields.gohtml:188 msgctxt "title" msgid "Customer Details" msgstr "Détails du client" @@ -247,7 +247,7 @@ msgstr "Détails du client" #: web/templates/mail/payment/details.gotxt:41 #: web/templates/public/booking/fields.gohtml:149 #: web/templates/admin/payment/details.gohtml:143 -#: web/templates/admin/booking/fields.gohtml:190 +#: web/templates/admin/booking/fields.gohtml:191 msgctxt "input" msgid "Full name" msgstr "Nom et prénom" @@ -930,7 +930,7 @@ msgstr "Menu" #: web/templates/admin/campsite/type/option/index.gohtml:10 #: web/templates/admin/campsite/type/index.gohtml:10 #: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:95 -#: web/templates/admin/booking/fields.gohtml:265 +#: web/templates/admin/booking/fields.gohtml:266 msgctxt "title" msgid "Campsites" msgstr "Locatifs" @@ -978,6 +978,7 @@ msgid "Booking Period" msgstr "Période de réservation" #: web/templates/public/booking/fields.gohtml:56 +#: web/templates/admin/booking/checkin.gohtml:20 msgctxt "title" msgid "Guests" msgstr "Personnes logeant" @@ -987,18 +988,18 @@ msgid "Note: Due to guest capacity, we have added more accommodations to the boo msgstr "Remarque : En raison de la capacité d’accueils, nous avons ajouté d’autres hébergements à la réservation, mais nous ne pouvons garantir qu’ils seront côte à côte." #: web/templates/public/booking/fields.gohtml:109 -#: web/templates/admin/booking/fields.gohtml:178 +#: web/templates/admin/booking/fields.gohtml:179 msgid "Note: This accommodation does not allow dogs." msgstr "Remarque : Dans cet hébergement les chiens ne sont pas acceptés." #: web/templates/public/booking/fields.gohtml:121 -#: web/templates/admin/booking/fields.gohtml:55 +#: web/templates/admin/booking/fields.gohtml:56 msgctxt "input" msgid "Area preferences (optional)" msgstr "Préférences de zone (facultatif)" #: web/templates/public/booking/fields.gohtml:123 -#: web/templates/admin/booking/fields.gohtml:59 +#: web/templates/admin/booking/fields.gohtml:60 msgid "Campground map" msgstr "Plan du camping" @@ -1008,12 +1009,13 @@ msgid "Town or village" msgstr "Ville" #: web/templates/public/booking/fields.gohtml:193 -#: web/templates/admin/booking/fields.gohtml:203 +#: web/templates/admin/booking/fields.gohtml:204 +#: web/templates/admin/booking/guest.gohtml:109 msgid "Choose a country" msgstr "Choisissez un pays" #: web/templates/public/booking/fields.gohtml:247 -#: web/templates/admin/booking/fields.gohtml:258 +#: web/templates/admin/booking/fields.gohtml:259 msgctxt "input" msgid "ACSI card? (optional)" msgstr "Carte ACSI ? (facultatif)" @@ -1098,8 +1100,8 @@ msgid "Down payment" msgstr "Acompte" #: web/templates/admin/payment/index.gohtml:24 -#: web/templates/admin/booking/fields.gohtml:74 -#: web/templates/admin/booking/fields.gohtml:172 +#: web/templates/admin/booking/fields.gohtml:75 +#: web/templates/admin/booking/fields.gohtml:173 msgctxt "header" msgid "Total" msgstr "Totale" @@ -1194,7 +1196,7 @@ msgstr "Contenu" #: web/templates/admin/amenity/form.gohtml:91 #: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/media/form.gohtml:39 -#: web/templates/admin/booking/fields.gohtml:272 +#: web/templates/admin/booking/form.gohtml:45 msgctxt "action" msgid "Update" msgstr "Mettre à jour" @@ -1214,7 +1216,7 @@ msgstr "Mettre à jour" #: web/templates/admin/amenity/feature/form.gohtml:67 #: web/templates/admin/amenity/carousel/form.gohtml:52 #: web/templates/admin/amenity/form.gohtml:93 -#: web/templates/admin/booking/fields.gohtml:274 +#: web/templates/admin/booking/form.gohtml:47 msgctxt "action" msgid "Add" msgstr "Ajouter" @@ -2161,7 +2163,7 @@ msgid "Add Amenity" msgstr "Ajouter un installation" #: web/templates/admin/amenity/index.gohtml:20 -#: web/templates/admin/booking/grid.gohtml:13 +#: web/templates/admin/booking/grid.gohtml:15 msgctxt "header" msgid "Label" msgstr "Label" @@ -2204,7 +2206,8 @@ msgid "Logout" msgstr "Déconnexion" #: web/templates/admin/layout.gohtml:92 -#: web/templates/admin/booking/form.gohtml:15 +#: web/templates/admin/booking/form.gohtml:19 +#: web/templates/admin/booking/checkin.gohtml:10 #: web/templates/admin/booking/index.gohtml:6 #: web/templates/admin/booking/index.gohtml:16 msgctxt "title" @@ -2312,51 +2315,53 @@ msgctxt "title" msgid "Upload Media" msgstr "Envoyer un fichier" -#: web/templates/admin/booking/fields.gohtml:18 +#: web/templates/admin/booking/fields.gohtml:19 msgid "Choose an accommodation" msgstr "Choisissez un hébergement" -#: web/templates/admin/booking/fields.gohtml:72 +#: web/templates/admin/booking/fields.gohtml:73 msgctxt "header" msgid "Units" msgstr "Unités" -#: web/templates/admin/booking/fields.gohtml:73 +#: web/templates/admin/booking/fields.gohtml:74 msgctxt "header" msgid "Decription" msgstr "Description" -#: web/templates/admin/booking/fields.gohtml:80 pkg/booking/cart.go:234 +#: web/templates/admin/booking/fields.gohtml:81 pkg/booking/cart.go:232 msgctxt "cart" msgid "Night" msgstr "Nuit" -#: web/templates/admin/booking/fields.gohtml:199 +#: web/templates/admin/booking/fields.gohtml:200 msgctxt "input" msgid "Country (optional)" msgstr "Pays (facultatif)" -#: web/templates/admin/booking/fields.gohtml:211 +#: web/templates/admin/booking/fields.gohtml:212 +#: web/templates/admin/booking/guest.gohtml:128 msgctxt "input" msgid "Address (optional)" msgstr "Adresse (facultatif)" -#: web/templates/admin/booking/fields.gohtml:220 +#: web/templates/admin/booking/fields.gohtml:221 msgctxt "input" msgid "Postcode (optional)" msgstr "Code postal (facultatif)" -#: web/templates/admin/booking/fields.gohtml:229 +#: web/templates/admin/booking/fields.gohtml:230 msgctxt "input" msgid "Town or village (optional)" msgstr "Ville (facultatif)" -#: web/templates/admin/booking/fields.gohtml:238 +#: web/templates/admin/booking/fields.gohtml:239 msgctxt "input" msgid "Email (optional)" msgstr "E-mail (facultatif)" -#: web/templates/admin/booking/fields.gohtml:247 +#: web/templates/admin/booking/fields.gohtml:248 +#: web/templates/admin/booking/guest.gohtml:117 msgctxt "input" msgid "Phone (optional)" msgstr "Téléphone (facultatif)" @@ -2371,6 +2376,31 @@ msgctxt "title" msgid "New Booking" msgstr "Nouvelle réservation" +#: web/templates/admin/booking/form.gohtml:25 +msgctxt "action" +msgid "Check-in Booking" +msgstr "Enregistrer réservation" + +#: web/templates/admin/booking/checkin.gohtml:6 +msgctxt "title" +msgid "Check-in Booking" +msgstr "Enregistrement de la réservation" + +#: web/templates/admin/booking/checkin.gohtml:15 +msgctxt "action" +msgid "Edit Booking" +msgstr "Modifier la réservation" + +#: web/templates/admin/booking/checkin.gohtml:26 +msgctxt "action" +msgid "Check-in" +msgstr "Enregitrer" + +#: web/templates/admin/booking/checkin.gohtml:31 +msgctxt "action" +msgid "Add another guest" +msgstr "Ajouter un autre invité" + #: web/templates/admin/booking/index.gohtml:14 msgctxt "action" msgid "Add Booking" @@ -2400,6 +2430,64 @@ msgstr "Nom du titulaire" msgid "No booking found." msgstr "Aucune réservation trouvée." +#: web/templates/admin/booking/guest.gohtml:5 +msgctxt "action" +msgid "Remove" +msgstr "Retirer" + +#: web/templates/admin/booking/guest.gohtml:8 +msgctxt "input" +msgid "ID document number" +msgstr "Numéro de document d’identité" + +#: web/templates/admin/booking/guest.gohtml:20 +msgctxt "input" +msgid "ID document type" +msgstr "Type de document d’identité" + +#: web/templates/admin/booking/guest.gohtml:25 +msgid "Choose an ID document type" +msgstr "Choisissez un type de document d’identité" + +#: web/templates/admin/booking/guest.gohtml:33 +msgctxt "input" +msgid "ID document issue date (if any)" +msgstr "Date de délivrance du document d’identité (si j'en ai)" + +#: web/templates/admin/booking/guest.gohtml:44 +msgctxt "input" +msgid "First surname" +msgstr "Premier nom" + +#: web/templates/admin/booking/guest.gohtml:56 +msgctxt "input" +msgid "Second surname (if has one)" +msgstr "Deuxième nom" + +#: web/templates/admin/booking/guest.gohtml:67 +msgctxt "input" +msgid "Given name" +msgstr "Prénom" + +#: web/templates/admin/booking/guest.gohtml:79 +msgctxt "input" +msgid "Sex" +msgstr "Sexe" + +#: web/templates/admin/booking/guest.gohtml:84 +msgid "Choose a sex" +msgstr "Choisissez un sexe" + +#: web/templates/admin/booking/guest.gohtml:92 +msgctxt "input" +msgid "Birthdate" +msgstr "Date de naissance" + +#: web/templates/admin/booking/guest.gohtml:104 +msgctxt "input" +msgid "Nationality" +msgstr "Nationalité" + #: pkg/payment/settings.go:37 msgctxt "redsys environment" msgid "Test" @@ -2501,12 +2589,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:224 -#: pkg/booking/public.go:545 +#: pkg/booking/public.go:596 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:225 -#: pkg/booking/admin.go:316 pkg/booking/public.go:546 +#: pkg/booking/admin.go:437 pkg/booking/public.go:597 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." @@ -2717,8 +2805,8 @@ msgctxt "header" msgid "Children (aged 2 to 10)" msgstr "Enfants (de 2 à 10 anys)" -#: pkg/campsite/admin.go:280 pkg/booking/admin.go:292 pkg/booking/public.go:173 -#: pkg/booking/public.go:228 +#: pkg/campsite/admin.go:280 pkg/booking/admin.go:413 pkg/booking/public.go:177 +#: pkg/booking/public.go:232 msgid "Selected campsite type is not valid." msgstr "Le type d’emplacement sélectionné n’est pas valide." @@ -2814,7 +2902,8 @@ 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:207 pkg/booking/public.go:530 +#: pkg/company/admin.go:207 pkg/booking/checkin.go:301 +#: pkg/booking/public.go:581 msgid "Selected country is not valid." msgstr "Le pays sélectionné n’est pas valide." @@ -2834,15 +2923,16 @@ 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:219 pkg/booking/public.go:548 +#: pkg/company/admin.go:219 pkg/booking/public.go:599 msgid "Phone can not be empty." msgstr "Le téléphone ne peut pas être vide." -#: pkg/company/admin.go:220 pkg/booking/admin.go:321 pkg/booking/public.go:549 +#: pkg/company/admin.go:220 pkg/booking/checkin.go:305 pkg/booking/admin.go:442 +#: pkg/booking/public.go:600 msgid "This phone number is not valid." msgstr "Ce numéro de téléphone n’est pas valide." -#: pkg/company/admin.go:230 pkg/booking/public.go:538 +#: pkg/company/admin.go:230 pkg/booking/public.go:589 msgid "Address can not be empty." msgstr "L’adresse ne peut pas être vide." @@ -2854,11 +2944,11 @@ msgstr "La ville ne peut pas être vide." msgid "Province can not be empty." msgstr "La province ne peut pas être vide." -#: pkg/company/admin.go:233 pkg/booking/public.go:540 +#: pkg/company/admin.go:233 pkg/booking/public.go:591 msgid "Postcode can not be empty." msgstr "Le code postal ne peut pas être vide." -#: pkg/company/admin.go:234 pkg/booking/admin.go:311 pkg/booking/public.go:541 +#: pkg/company/admin.go:234 pkg/booking/admin.go:432 pkg/booking/public.go:592 msgid "This postcode is not valid." msgstr "Ce code postal n’est pas valide." @@ -2910,169 +3000,202 @@ 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:235 +#: pkg/booking/checkin.go:285 +msgid "Selected ID document type is not valid." +msgstr "Le type de document d’identité sélectionné n’est pas valide." + +#: pkg/booking/checkin.go:286 +msgid "ID document number can not be empty." +msgstr "Le numéro de documento d’identité ne peut pas être vide." + +#: pkg/booking/checkin.go:288 +msgid "ID document issue date must be a valid date." +msgstr "La date de délivrance du document d’identité doit être une date valide." + +#: pkg/booking/checkin.go:289 +msgid "ID document issue date must be in the past." +msgstr "La ate de délivrance du document d’identité doit être du passé." + +#: pkg/booking/checkin.go:292 pkg/booking/checkin.go:293 +#: pkg/booking/admin.go:425 pkg/booking/public.go:585 +msgid "Full name can not be empty." +msgstr "Le nom complet ne peut pas être vide." + +#: pkg/booking/checkin.go:294 +msgid "Selected sex is not valid." +msgstr "Le sexe sélectionné n’est pas valide." + +#: pkg/booking/checkin.go:295 +msgid "Birthdate can not be empty" +msgstr "La date de naissance ne peut pas être vide." + +#: pkg/booking/checkin.go:296 +msgid "Birthdate must be a valid date." +msgstr "La date de naissance doit être une date valide." + +#: pkg/booking/checkin.go:297 +msgid "Birthdate must be in the past." +msgstr "La date de naissance doit être du passé." + +#: pkg/booking/cart.go:233 msgctxt "cart" msgid "Adult" msgstr "Adulte" -#: pkg/booking/cart.go:236 +#: pkg/booking/cart.go:234 msgctxt "cart" msgid "Teenager" msgstr "Adolescent" -#: pkg/booking/cart.go:237 +#: pkg/booking/cart.go:235 msgctxt "cart" msgid "Child" msgstr "Enfant" -#: pkg/booking/cart.go:238 +#: pkg/booking/cart.go:236 msgctxt "cart" msgid "Dog" msgstr "Chien" -#: pkg/booking/admin.go:144 +#: pkg/booking/admin.go:217 msgctxt "filename" msgid "bookings.ods" msgstr "reservations.ods" -#: pkg/booking/admin.go:304 pkg/booking/public.go:534 -msgid "Full name can not be empty." -msgstr "Le nom complet ne peut pas être vide." - -#: pkg/booking/admin.go:305 pkg/booking/public.go:535 +#: pkg/booking/admin.go:426 pkg/booking/public.go:586 msgid "Full name must have at least one letter." msgstr "Le nom complet doit comporter au moins une lettre." -#: pkg/booking/admin.go:310 +#: pkg/booking/admin.go:431 msgid "Country can not be empty to validate the postcode." msgstr "Le pays ne peut pas être vide pour valider le code postal." -#: pkg/booking/admin.go:320 +#: pkg/booking/admin.go:441 msgid "Country can not be empty to validate the phone." msgstr "Le pays ne peut pas être vide pour valider le téléphone." -#: pkg/booking/admin.go:327 +#: pkg/booking/admin.go:448 msgid "You must select at least one accommodation." msgstr "Vous devez sélectionner au moins un hébergement." -#: pkg/booking/admin.go:333 +#: pkg/booking/admin.go:454 msgid "The selected accommodations have no available openings in the requested dates." msgstr "Les hébergements sélectionnés n’ont pas de disponibilités aux dates demandées." -#: pkg/booking/public.go:277 pkg/booking/public.go:306 +#: pkg/booking/public.go:284 pkg/booking/public.go:313 msgid "Arrival date must be a valid date." msgstr "La date d’arrivée doit être une date valide." -#: pkg/booking/public.go:291 pkg/booking/public.go:313 +#: pkg/booking/public.go:298 pkg/booking/public.go:320 msgid "Departure date must be a valid date." msgstr "La date de départ doit être une date valide." -#: pkg/booking/public.go:305 +#: pkg/booking/public.go:312 msgid "Arrival date can not be empty" msgstr "La date d’arrivée ne peut pas être vide" -#: pkg/booking/public.go:307 +#: pkg/booking/public.go:314 #, c-format msgid "Arrival date must be %s or after." msgstr "La date d’arrivée doit être égale ou postérieure à %s." -#: pkg/booking/public.go:308 +#: pkg/booking/public.go:315 #, c-format msgid "Arrival date must be %s or before." msgstr "La date d’arrivée doit être antérieure ou égale à %s." -#: pkg/booking/public.go:312 +#: pkg/booking/public.go:319 msgid "Departure date can not be empty" msgstr "La date de départ ne peut pas être vide" -#: pkg/booking/public.go:314 +#: pkg/booking/public.go:321 #, c-format msgid "Departure date must be %s or after." msgstr "La date de départ doit être égale ou postérieure à %s." -#: pkg/booking/public.go:315 +#: pkg/booking/public.go:322 #, c-format msgid "Departure date must be %s or before." msgstr "La date de départ doit être antérieure ou égale à %s." -#: pkg/booking/public.go:369 +#: pkg/booking/public.go:380 #, c-format msgid "There can be at most %d guests in this accommodation." msgstr "Il peut y avoir au plus %d invités dans cet hébergement." -#: pkg/booking/public.go:389 +#: pkg/booking/public.go:400 msgid "Number of adults can not be empty" msgstr "Le nombre d’adultes ne peut pas être vide." -#: pkg/booking/public.go:390 +#: pkg/booking/public.go:401 msgid "Number of adults must be an integer." msgstr "Le nombre d’adultes doit être un entier." -#: pkg/booking/public.go:391 +#: pkg/booking/public.go:402 msgid "There must be at least one adult." msgstr "Il doit y avoir au moins un adulte." -#: pkg/booking/public.go:394 +#: pkg/booking/public.go:405 msgid "Number of teenagers can not be empty" msgstr "Le nombre d’adolescents ne peut pas être vide." -#: pkg/booking/public.go:395 +#: pkg/booking/public.go:406 msgid "Number of teenagers must be an integer." msgstr "Le nombre d’adolescents doit être un entier." -#: pkg/booking/public.go:396 +#: pkg/booking/public.go:407 msgid "Number of teenagers can not be negative." msgstr "Le nombre d’adolescents ne peut pas être négatif." -#: pkg/booking/public.go:399 +#: pkg/booking/public.go:410 msgid "Number of children can not be empty" msgstr "Le nombre d’enfants ne peut pas être vide." -#: pkg/booking/public.go:400 +#: pkg/booking/public.go:411 msgid "Number of children must be an integer." msgstr "Le nombre d’enfants doit être un entier." -#: pkg/booking/public.go:401 +#: pkg/booking/public.go:412 msgid "Number of children can not be negative." msgstr "Le nombre d’enfants ne peut pas être négatif." -#: pkg/booking/public.go:404 +#: pkg/booking/public.go:415 msgid "Number of dogs can not be empty" msgstr "Le nombre de chiens ne peut pas être vide." -#: pkg/booking/public.go:405 +#: pkg/booking/public.go:416 msgid "Number of dogs must be an integer." msgstr "Le nombre de chiens nuits être un entier." -#: pkg/booking/public.go:406 +#: pkg/booking/public.go:417 msgid "Number of dogs can not be negative." msgstr "Le nombre de chiens ne peut pas être négatif." -#: pkg/booking/public.go:477 +#: pkg/booking/public.go:524 #, c-format msgid "%s can not be empty" msgstr "%s ne peut pas être vide" -#: pkg/booking/public.go:478 +#: pkg/booking/public.go:525 #, c-format msgid "%s must be an integer." msgstr "%s doit être un entier." -#: pkg/booking/public.go:479 +#: pkg/booking/public.go:526 #, c-format msgid "%s must be %d or greater." msgstr "%s doit être %d ou plus." -#: pkg/booking/public.go:480 +#: pkg/booking/public.go:527 #, c-format msgid "%s must be at most %d." msgstr "%s doit être tout au plus %d." -#: pkg/booking/public.go:539 +#: pkg/booking/public.go:590 msgid "Town or village can not be empty." msgstr "La ville ne peut pas être vide." -#: pkg/booking/public.go:554 +#: pkg/booking/public.go:605 msgid "It is mandatory to agree to the reservation conditions." msgstr "Il est obligatoire d’accepter les conditions de réservation." diff --git a/revert/available_id_document_types.sql b/revert/available_id_document_types.sql new file mode 100644 index 0000000..15e482f --- /dev/null +++ b/revert/available_id_document_types.sql @@ -0,0 +1,10 @@ +-- Revert camper:available_id_document_types from pg + +begin; + +set search_path to camper; + +delete from id_document_type_i18n; +delete from id_document_type; + +commit; diff --git a/revert/available_sexes.sql b/revert/available_sexes.sql new file mode 100644 index 0000000..831e577 --- /dev/null +++ b/revert/available_sexes.sql @@ -0,0 +1,10 @@ +-- Revert camper:available_sexes from pg + +begin; + +set search_path to camper; + +delete from sex_i18n; +delete from sex; + +commit; diff --git a/revert/booking_guest.sql b/revert/booking_guest.sql new file mode 100644 index 0000000..8601d4a --- /dev/null +++ b/revert/booking_guest.sql @@ -0,0 +1,7 @@ +-- Revert camper:booking_guest from pg + +begin; + +drop table if exists camper.booking_guest; + +commit; diff --git a/revert/check_in_guests.sql b/revert/check_in_guests.sql new file mode 100644 index 0000000..de9c2b4 --- /dev/null +++ b/revert/check_in_guests.sql @@ -0,0 +1,7 @@ +-- Revert camper:check_in_guests from pg + +begin; + +drop function if exists camper.check_in_guests(integer, camper.checked_in_guest[]); + +commit; diff --git a/revert/checked_in_guest.sql b/revert/checked_in_guest.sql new file mode 100644 index 0000000..c7e7b2f --- /dev/null +++ b/revert/checked_in_guest.sql @@ -0,0 +1,7 @@ +-- Revert camper:checked_in_guest from pg + +begin; + +drop type if exists camper.checked_in_guest; + +commit; diff --git a/revert/id_document_type.sql b/revert/id_document_type.sql new file mode 100644 index 0000000..f3261af --- /dev/null +++ b/revert/id_document_type.sql @@ -0,0 +1,7 @@ +-- Revert camper:id_document_type from pg + +begin; + +drop table if exists camper.id_document_type; + +commit; diff --git a/revert/id_document_type_i18n.sql b/revert/id_document_type_i18n.sql new file mode 100644 index 0000000..5554a37 --- /dev/null +++ b/revert/id_document_type_i18n.sql @@ -0,0 +1,7 @@ +-- Revert camper:id_document_type_i18n from pg + +begin; + +drop table if exists camper.id_document_type_i18n; + +commit; diff --git a/revert/sex.sql b/revert/sex.sql new file mode 100644 index 0000000..acb5118 --- /dev/null +++ b/revert/sex.sql @@ -0,0 +1,7 @@ +-- Revert camper:sex from pg + +begin; + +drop table if exists camper.sex; + +commit; diff --git a/revert/sex_i18n.sql b/revert/sex_i18n.sql new file mode 100644 index 0000000..82595e6 --- /dev/null +++ b/revert/sex_i18n.sql @@ -0,0 +1,7 @@ +-- Revert camper:sex_i18n from pg + +begin; + +drop table if exists camper.sex_i18n; + +commit; diff --git a/sqitch.plan b/sqitch.plan index b9b409d..e945109 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -290,3 +290,12 @@ booking_option [roles schema_camper booking campsite_type_option positive_intege add_booking_from_payment [roles schema_camper booking booking__payment_fields booking__stay booking_option payment payment__acsi_card payment_customer payment_option] 2024-04-24T11:23:22Z jordi fita mas # Add function to create a pre-booking from a payment edit_booking [roles schema_camper booking booking__payment_fields booking__stay booking_campsite] 2024-04-24T16:27:10Z jordi fita mas # Add function to update a booking edit_booking_from_payment [roles schema_camper booking booking__payment_fields booking__stay booking_option payment payment__acsi_card payment_option] 2024-04-25T17:18:41Z jordi fita mas # Add function to edit a booking from a payment +sex [roles schema_camper] 2024-04-25T22:02:27Z jordi fita mas # Add sex relation +sex_i18n [roles schema_camper sex language] 2024-04-25T22:06:21Z jordi fita mas # Add relation of sex translations +available_sexes [sex sex_i18n] 2024-04-25T22:09:27Z jordi fita mas # Add available sexes +id_document_type [roles schema_camper] 2024-04-25T22:26:47Z jordi fita mas # Add relation of identity document type +id_document_type_i18n [roles schema_camper id_document_type language] 2024-04-25T22:29:20Z jordi fita mas # Add relation for translations of ID document types +available_id_document_types [id_document_type id_document_type_i18n] 2024-04-25T22:32:05Z jordi fita mas # Add available ID document types +booking_guest [roles schema_camper booking sex id_document_type extension_pg_libphonenumber] 2024-04-26T09:40:17Z jordi fita mas # Add relation of booking guests +checked_in_guest [schema_camper] 2024-04-26T09:58:54Z jordi fita mas # Add type for checked-in guest +check_in_guests [roles schema_camper booking booking_guest checked_in_guest extension_pg_libphonenumber] 2024-04-26T10:31:53Z jordi fita mas # Add function to check-in guests diff --git a/test/booking_guest.sql b/test/booking_guest.sql new file mode 100644 index 0000000..8479fc0 --- /dev/null +++ b/test/booking_guest.sql @@ -0,0 +1,111 @@ +-- Test booking_guest +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(78); + +set search_path to camper, public; + +select has_table('booking_guest'); +select has_pk('booking_guest'); +select col_is_unique('booking_guest', array['booking_id', 'id_document_type_id', 'id_document_number']); +select table_privs_are('booking_guest', 'guest', array[]::text[]); +select table_privs_are('booking_guest', 'employee', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']); +select table_privs_are('booking_guest', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']); +select table_privs_are('booking_guest', 'authenticator', array[]::text[]); + +select has_column('booking_guest', 'booking_guest_id'); +select col_is_pk('booking_guest', 'booking_guest_id'); +select col_type_is('booking_guest', 'booking_guest_id', 'integer'); +select col_not_null('booking_guest', 'booking_guest_id'); +select col_hasnt_default('booking_guest', 'booking_guest_id'); + +select has_column('booking_guest', 'booking_id'); +select col_is_fk('booking_guest', 'booking_id'); +select fk_ok('booking_guest', 'booking_id', 'booking', 'booking_id'); +select col_type_is('booking_guest', 'booking_id', 'integer'); +select col_not_null('booking_guest', 'booking_id'); +select col_hasnt_default('booking_guest', 'booking_id'); + +select has_column('booking_guest', 'id_document_type_id'); +select col_is_fk('booking_guest', 'id_document_type_id'); +select fk_ok('booking_guest', 'id_document_type_id', 'id_document_type', 'id_document_type_id'); +select col_type_is('booking_guest', 'id_document_type_id', 'character varying(1)'); +select col_not_null('booking_guest', 'id_document_type_id'); +select col_hasnt_default('booking_guest', 'id_document_type_id'); + +select has_column('booking_guest', 'id_document_number'); +select col_type_is('booking_guest', 'id_document_number', 'text'); +select col_not_null('booking_guest', 'id_document_number'); +select col_hasnt_default('booking_guest', 'id_document_number'); + +select has_column('booking_guest', 'id_document_issue_date'); +select col_type_is('booking_guest', 'id_document_issue_date', 'date'); +select col_is_null('booking_guest', 'id_document_issue_date'); +select col_hasnt_default('booking_guest', 'id_document_issue_date'); + +select has_column('booking_guest', 'given_name'); +select col_type_is('booking_guest', 'given_name', 'text'); +select col_not_null('booking_guest', 'given_name'); +select col_hasnt_default('booking_guest', 'given_name'); + +select has_column('booking_guest', 'first_surname'); +select col_type_is('booking_guest', 'first_surname', 'text'); +select col_not_null('booking_guest', 'first_surname'); +select col_hasnt_default('booking_guest', 'first_surname'); + +select has_column('booking_guest', 'second_surname'); +select col_type_is('booking_guest', 'second_surname', 'text'); +select col_not_null('booking_guest', 'second_surname'); +select col_hasnt_default('booking_guest', 'second_surname'); + +select has_column('booking_guest', 'sex_id'); +select col_is_fk('booking_guest', 'sex_id'); +select fk_ok('booking_guest', 'sex_id', 'sex', 'sex_id'); +select col_type_is('booking_guest', 'sex_id', 'character varying(1)'); +select col_not_null('booking_guest', 'sex_id'); +select col_hasnt_default('booking_guest', 'sex_id'); + +select has_column('booking_guest', 'birthdate'); +select col_type_is('booking_guest', 'birthdate', 'date'); +select col_not_null('booking_guest', 'birthdate'); +select col_hasnt_default('booking_guest', 'birthdate'); + +select has_column('booking_guest', 'country_code'); +select col_is_fk('booking_guest', 'country_code'); +select fk_ok('booking_guest', 'country_code', 'country', 'country_code'); +select col_type_is('booking_guest', 'country_code', 'country_code'); +select col_not_null('booking_guest', 'country_code'); +select col_hasnt_default('booking_guest', 'country_code'); + +select has_column('booking_guest', 'phone'); +select col_type_is('booking_guest', 'phone', 'packed_phone_number'); +select col_is_null('booking_guest', 'phone'); +select col_hasnt_default('booking_guest', 'phone'); + +select has_column('booking_guest', 'address'); +select col_type_is('booking_guest', 'address', 'text'); +select col_not_null('booking_guest', 'address'); +select col_hasnt_default('booking_guest', 'address'); + +select has_column('booking_guest', 'created_at'); +select col_type_is('booking_guest', 'created_at', 'timestamp with time zone'); +select col_not_null('booking_guest', 'created_at'); +select col_has_default('booking_guest', 'created_at'); +select col_default_is('booking_guest', 'created_at', 'CURRENT_TIMESTAMP'); + +select has_column('booking_guest', 'updated_at'); +select col_type_is('booking_guest', 'updated_at', 'timestamp with time zone'); +select col_not_null('booking_guest', 'updated_at'); +select col_has_default('booking_guest', 'updated_at'); +select col_default_is('booking_guest', 'updated_at', 'CURRENT_TIMESTAMP'); + + +select * +from finish(); + +rollback; + diff --git a/test/check_in_guests.sql b/test/check_in_guests.sql new file mode 100644 index 0000000..4c1da1c --- /dev/null +++ b/test/check_in_guests.sql @@ -0,0 +1,89 @@ +-- Test check_in_guests +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(13); + +set search_path to camper, public; + +select has_function('camper', 'check_in_guests', array['integer', 'checked_in_guest[]']); +select function_lang_is('camper', 'check_in_guests', array['integer', 'checked_in_guest[]'], 'sql'); +select function_returns('camper', 'check_in_guests', array['integer', 'checked_in_guest[]'], 'void'); +select isnt_definer('camper', 'check_in_guests', array['integer', 'checked_in_guest[]']); +select volatility_is('camper', 'check_in_guests', array['integer', 'checked_in_guest[]'], 'volatile'); +select function_privs_are('camper', 'check_in_guests', array ['integer', 'checked_in_guest[]'], 'guest', array[]::text[]); +select function_privs_are('camper', 'check_in_guests', array ['integer', 'checked_in_guest[]'], 'employee', array['EXECUTE']); +select function_privs_are('camper', 'check_in_guests', array ['integer', 'checked_in_guest[]'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'check_in_guests', array ['integer', 'checked_in_guest[]'], 'authenticator', array[]::text[]); + + +set client_min_messages to warning; +truncate booking_guest cascade; +truncate booking cascade; +truncate campsite_type cascade; +truncate media cascade; +truncate media_content cascade; +truncate company cascade; +reset client_min_messages; + +insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, rtc_number, tourist_tax, tourist_tax_max_days, country_code, currency_code, default_lang_tag) +values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 7, 'ES', 'EUR', 'ca') +; + +insert into media_content (media_type, bytes) +values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};') +; + +insert into media (media_id, company_id, original_filename, content_hash) +values (6, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};')) +; + +insert into campsite_type (campsite_type_id, company_id, name, media_id, max_campers, bookable_nights) +values (12, 2, 'Wooden lodge', 6, 7, '[1, 7]') +; + +insert into booking (booking_id, company_id, campsite_type_id, holder_name, stay, acsi_card, currency_code, zone_preferences, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total, booking_status) +values (14, 2, 12, 'Holder 2', daterange('2024-01-18', '2024-01-29'), false, 'EUR', '', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 'confirmed') + , (16, 2, 12, 'Holder 4', daterange('2024-01-28', '2024-01-29'), true, 'USD', 'None', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'invoiced') +; + +insert into booking_guest (booking_id, id_document_type_id, id_document_number, id_document_issue_date, given_name, first_surname, second_surname, sex_id, birthdate, country_code, phone, address, created_at, updated_at) +values (14, 'D', '4444444A', '2022-01-01', 'Given', 'First', 'Last', 'F', '1991-07-02', 'ES', '+32 977 977 977', 'Fake St., 123', '2023-03-03 03:03:03', '2023-03-03 03:03:03') + , (16, 'P', '123456-ABC', '2020-12-20', 'Mah', 'Name', '', 'M', '1980-03-31', 'JP', '123 123 123', 'Dunno', '2022-02-02 02:02:02', '2022-02-02 02:02:02') +; + +select lives_ok( + $$ select check_in_guests(14, array[('C', 'UABCA', null, 'Jan-Michael', 'Vincent', '', 'M', '1944-07-15', 'US', '5673159097', 'One Rabbit Road'), ('D', '4444444A', '2021-02-02', 'Gibbon', 'Di', 'Luffy', 'M', '1981-09-25', 'GB', null, '')]::checked_in_guest[]) $$, + 'Should be able to check-in guests for the first booking' +); + +select lives_ok( + $$ select check_in_guests(16, array[('I', 'Huh?', '1999-09-09', 'Mayumi', 'Tanaka', '', 'F', '1955-01-15', 'JP', '5083262771', 'Somewhere')]::checked_in_guest[]) $$, + 'Should be able to check-in guests for the second booking' +); + +select bag_eq ( + $$ select booking_id, booking_status from booking $$, + $$ values (14, 'checked-in') + , (16, 'invoiced') + $$, + 'Should have updated the status if it was created or confirmed' +); + +select bag_eq ( + $$ select booking_id, id_document_type_id::text, id_document_number, id_document_issue_date::text, given_name, first_surname, second_surname, sex_id::text, birthdate::text, country_code::text, phone::text, address, created_at, updated_at from booking_guest $$, + $$ values (14, 'C', 'UABCA', null, 'Jan-Michael', 'Vincent', '', 'M', '1944-07-15', 'US', '+1 567-315-9097', 'One Rabbit Road', current_timestamp, current_timestamp) + , (14, 'D', '4444444A', '2021-02-02', 'Gibbon', 'Di', 'Luffy', 'M', '1981-09-25', 'GB', null, '', '2023-03-03 03:03:03', current_timestamp) + , (16, 'I', 'Huh?', '1999-09-09', 'Mayumi', 'Tanaka', '', 'F', '1955-01-15', 'JP', '+81 50-8326-2771', 'Somewhere', current_timestamp, current_timestamp) + $$, + 'Should have updated guest information' +); + + +select * +from finish(); + +rollback; diff --git a/test/checked_in_guest.sql b/test/checked_in_guest.sql new file mode 100644 index 0000000..e242e9b --- /dev/null +++ b/test/checked_in_guest.sql @@ -0,0 +1,30 @@ +-- Test checked_in_guest +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(13); + +set search_path to camper, public; + +select has_composite('camper', 'checked_in_guest', 'Composite type camper.checked_in_guest should exist'); +select columns_are('camper', 'checked_in_guest', array['id_document_type_id', 'id_document_number', 'id_document_issue_date', 'given_name', 'first_surname', 'second_surname', 'sex_id', 'birthdate', 'country_code', 'phone', 'address']); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'id_document_type_id'::name, 'character varying(1)'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'id_document_number'::name, 'text'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'id_document_issue_date'::name, 'date'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'given_name'::name, 'text'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'first_surname'::name, 'text'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'second_surname'::name, 'text'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'sex_id'::name, 'character varying(1)'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'birthdate'::name, 'date'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'country_code'::name, 'country_code'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'phone'::name, 'text'); +select col_type_is('camper'::name, 'checked_in_guest'::name, 'address'::name, 'text'); + + +select * +from finish(); + +rollback; diff --git a/test/id_document_type.sql b/test/id_document_type.sql new file mode 100644 index 0000000..80c8e3b --- /dev/null +++ b/test/id_document_type.sql @@ -0,0 +1,35 @@ +-- Test id_document_type +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(15); + +set search_path to camper, public; + +select has_table('id_document_type'); +select has_pk('id_document_type'); +select table_privs_are('id_document_type', 'guest', array[]::text[]); +select table_privs_are('id_document_type', 'employee', array['SELECT']); +select table_privs_are('id_document_type', 'admin', array['SELECT']); +select table_privs_are('id_document_type', 'authenticator', array[]::text[]); + +select has_column('id_document_type', 'id_document_type_id'); +select col_is_pk('id_document_type', 'id_document_type_id'); +select col_type_is('id_document_type', 'id_document_type_id', 'character varying(1)'); +select col_not_null('id_document_type', 'id_document_type_id'); +select col_hasnt_default('id_document_type', 'id_document_type_id'); + +select has_column('id_document_type', 'name'); +select col_type_is('id_document_type', 'name', 'text'); +select col_not_null('id_document_type', 'name'); +select col_hasnt_default('id_document_type', 'name'); + + +select * +from finish(); + +rollback; + diff --git a/test/id_document_type_i18n.sql b/test/id_document_type_i18n.sql new file mode 100644 index 0000000..9306929 --- /dev/null +++ b/test/id_document_type_i18n.sql @@ -0,0 +1,44 @@ +-- Test id_document_type_i18n +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(23); + +set search_path to camper, public; + +select has_table('id_document_type_i18n'); +select has_pk('id_document_type_i18n'); +select col_is_pk('id_document_type_i18n', array['id_document_type_id', 'lang_tag']); +select table_privs_are('id_document_type_i18n', 'guest', array[]::text[]); +select table_privs_are('id_document_type_i18n', 'employee', array['SELECT']); +select table_privs_are('id_document_type_i18n', 'admin', array['SELECT']); +select table_privs_are('id_document_type_i18n', 'authenticator', array[]::text[]); + +select has_column('id_document_type_i18n', 'id_document_type_id'); +select col_is_fk('id_document_type_i18n', 'id_document_type_id'); +select fk_ok('id_document_type_i18n', 'id_document_type_id', 'id_document_type', 'id_document_type_id'); +select col_type_is('id_document_type_i18n', 'id_document_type_id', 'character varying(1)'); +select col_not_null('id_document_type_i18n', 'id_document_type_id'); +select col_hasnt_default('id_document_type_i18n', 'id_document_type_id'); + +select has_column('id_document_type_i18n', 'lang_tag'); +select col_is_fk('id_document_type_i18n', 'lang_tag'); +select fk_ok('id_document_type_i18n', 'lang_tag', 'language', 'lang_tag'); +select col_type_is('id_document_type_i18n', 'lang_tag', 'text'); +select col_not_null('id_document_type_i18n', 'lang_tag'); +select col_hasnt_default('id_document_type_i18n', 'lang_tag'); + +select has_column('id_document_type_i18n', 'name'); +select col_type_is('id_document_type_i18n', 'name', 'text'); +select col_not_null('id_document_type_i18n', 'name'); +select col_hasnt_default('id_document_type_i18n', 'name'); + + +select * +from finish(); + +rollback; + diff --git a/test/sex.sql b/test/sex.sql new file mode 100644 index 0000000..9928527 --- /dev/null +++ b/test/sex.sql @@ -0,0 +1,34 @@ +-- Test sex +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(15); + +set search_path to camper, public; + +select has_table('sex'); +select has_pk('sex'); +select table_privs_are('sex', 'guest', array[]::text[]); +select table_privs_are('sex', 'employee', array['SELECT']); +select table_privs_are('sex', 'admin', array['SELECT']); +select table_privs_are('sex', 'authenticator', array[]::text[]); + +select has_column('sex', 'sex_id'); +select col_is_pk('sex', 'sex_id'); +select col_type_is('sex', 'sex_id', 'character varying(1)'); +select col_not_null('sex', 'sex_id'); +select col_hasnt_default('sex', 'sex_id'); + +select has_column('sex', 'name'); +select col_type_is('sex', 'name', 'text'); +select col_not_null('sex', 'name'); +select col_hasnt_default('sex', 'name'); + + +select * +from finish(); + +rollback; diff --git a/test/sex_i18n.sql b/test/sex_i18n.sql new file mode 100644 index 0000000..d4fb0fc --- /dev/null +++ b/test/sex_i18n.sql @@ -0,0 +1,44 @@ +-- Test sex_i18n +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(23); + +set search_path to camper, public; + +select has_table('sex_i18n'); +select has_pk('sex_i18n'); +select col_is_pk('sex_i18n', array['sex_id', 'lang_tag']); +select table_privs_are('sex_i18n', 'guest', array[]::text[]); +select table_privs_are('sex_i18n', 'employee', array['SELECT']); +select table_privs_are('sex_i18n', 'admin', array['SELECT']); +select table_privs_are('sex_i18n', 'authenticator', array[]::text[]); + +select has_column('sex_i18n', 'sex_id'); +select col_is_fk('sex_i18n', 'sex_id'); +select fk_ok('sex_i18n', 'sex_id', 'sex', 'sex_id'); +select col_type_is('sex_i18n', 'sex_id', 'character varying(1)'); +select col_not_null('sex_i18n', 'sex_id'); +select col_hasnt_default('sex_i18n', 'sex_id'); + +select has_column('sex_i18n', 'lang_tag'); +select col_is_fk('sex_i18n', 'lang_tag'); +select fk_ok('sex_i18n', 'lang_tag', 'language', 'lang_tag'); +select col_type_is('sex_i18n', 'lang_tag', 'text'); +select col_not_null('sex_i18n', 'lang_tag'); +select col_hasnt_default('sex_i18n', 'lang_tag'); + +select has_column('sex_i18n', 'name'); +select col_type_is('sex_i18n', 'name', 'text'); +select col_not_null('sex_i18n', 'name'); +select col_hasnt_default('sex_i18n', 'name'); + + +select * +from finish(); + +rollback; + diff --git a/verify/available_id_document_types.sql b/verify/available_id_document_types.sql new file mode 100644 index 0000000..fcf66c7 --- /dev/null +++ b/verify/available_id_document_types.sql @@ -0,0 +1,35 @@ +-- Verify camper:available_id_document_types on pg + +begin; + +set search_path to camper; + +select 1 / count(*) from id_document_type where id_document_type_id = 'D' and name = 'DNI'; +select 1 / count(*) from id_document_type where id_document_type_id = 'P' and name = 'Passport'; +select 1 / count(*) from id_document_type where id_document_type_id = 'C' and name = 'Driving license'; +select 1 / count(*) from id_document_type where id_document_type_id = 'I' and name = 'Identification document'; +select 1 / count(*) from id_document_type where id_document_type_id = 'N' and name = 'Spanish residence permit'; +select 1 / count(*) from id_document_type where id_document_type_id = 'X' and name = 'Residence permit from another Member State of the European Union'; + +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'D' and lang_tag = 'ca' and name = 'DNI'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'P' and lang_tag = 'ca' and name = 'Passaport'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'C' and lang_tag = 'ca' and name = 'Permís de conduir'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'I' and lang_tag = 'ca' and name = 'Carta o document d’identitat'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'N' and lang_tag = 'ca' and name = 'Permís de residència espanyol'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'X' and lang_tag = 'ca' and name = 'Permís de residència d’un altre estat membre de la Unió Europea'; + +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'D' and lang_tag = 'es' and name = 'DNI'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'P' and lang_tag = 'es' and name = 'Pasaporte'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'C' and lang_tag = 'es' and name = 'Permiso de conducir'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'I' and lang_tag = 'es' and name = 'Carta o documento de identidad'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'N' and lang_tag = 'es' and name = 'Permiso de residencia español'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'X' and lang_tag = 'es' and name = 'Permiso de residencia de otro Estado Miembro de la Unión Europea'; + +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'D' and lang_tag = 'fr' and name = 'DNI'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'P' and lang_tag = 'fr' and name = 'Passeport'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'C' and lang_tag = 'fr' and name = 'Permis de conduire'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'I' and lang_tag = 'fr' and name = 'Carte d’identité'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'N' and lang_tag = 'fr' and name = 'Permis de séjour espagnol'; +select 1 / count(*) from id_document_type_i18n where id_document_type_id = 'X' and lang_tag = 'fr' and name = 'Titre de séjour d’un autre État membre de l’Union européenne'; + +rollback; diff --git a/verify/available_sexes.sql b/verify/available_sexes.sql new file mode 100644 index 0000000..9ca72b2 --- /dev/null +++ b/verify/available_sexes.sql @@ -0,0 +1,19 @@ +-- Verify camper:available_sexes on pg + +begin; + +set search_path to camper; + +select 1 / count(*) from sex where sex_id = 'F' and name = 'Female'; +select 1 / count(*) from sex where sex_id = 'M' and name = 'Male'; + +select 1 / count(*) from sex_i18n where sex_id = 'F' and lang_tag = 'ca' and name = 'Femení'; +select 1 / count(*) from sex_i18n where sex_id = 'M' and lang_tag = 'ca' and name = 'Masculí'; + +select 1 / count(*) from sex_i18n where sex_id = 'F' and lang_tag = 'es' and name = 'Femenino'; +select 1 / count(*) from sex_i18n where sex_id = 'M' and lang_tag = 'es' and name = 'Masculino'; + +select 1 / count(*) from sex_i18n where sex_id = 'F' and lang_tag = 'fr' and name = 'Féminin'; +select 1 / count(*) from sex_i18n where sex_id = 'M' and lang_tag = 'fr' and name = 'Masculin'; + +rollback; diff --git a/verify/booking_guest.sql b/verify/booking_guest.sql new file mode 100644 index 0000000..aa6f811 --- /dev/null +++ b/verify/booking_guest.sql @@ -0,0 +1,23 @@ +-- Verify camper:booking_guest on pg + +begin; + +select booking_guest_id + , booking_id + , id_document_type_id + , id_document_number + , id_document_issue_date + , given_name + , first_surname + , second_surname + , sex_id + , birthdate + , country_code + , phone + , address + , created_at + , updated_at +from camper.booking_guest +where false; + +rollback; diff --git a/verify/check_in_guests.sql b/verify/check_in_guests.sql new file mode 100644 index 0000000..8a9bd23 --- /dev/null +++ b/verify/check_in_guests.sql @@ -0,0 +1,7 @@ +-- Verify camper:check_in_guests on pg + +begin; + +select has_function_privilege('camper.check_in_guests(integer, camper.checked_in_guest[])', 'execute'); + +rollback; diff --git a/verify/checked_in_guest.sql b/verify/checked_in_guest.sql new file mode 100644 index 0000000..1c6b904 --- /dev/null +++ b/verify/checked_in_guest.sql @@ -0,0 +1,7 @@ +-- Verify camper:checked_in_guest on pg + +begin; + +select pg_catalog.has_type_privilege('camper.checked_in_guest', 'usage'); + +rollback; diff --git a/verify/id_document_type.sql b/verify/id_document_type.sql new file mode 100644 index 0000000..5c4c505 --- /dev/null +++ b/verify/id_document_type.sql @@ -0,0 +1,10 @@ +-- Verify camper:id_document_type on pg + +begin; + +select id_document_type_id + , name +from camper.id_document_type +where false; + +rollback; diff --git a/verify/id_document_type_i18n.sql b/verify/id_document_type_i18n.sql new file mode 100644 index 0000000..5c8f055 --- /dev/null +++ b/verify/id_document_type_i18n.sql @@ -0,0 +1,11 @@ +-- Verify camper:id_document_type_i18n on pg + +begin; + +select id_document_type_id + , lang_tag + , name +from camper.id_document_type_i18n +where false; + +rollback; diff --git a/verify/sex.sql b/verify/sex.sql new file mode 100644 index 0000000..5a1d644 --- /dev/null +++ b/verify/sex.sql @@ -0,0 +1,10 @@ +-- Verify camper:sex on pg + +begin; + +select sex_id + , name +from camper.sex +where false; + +rollback; diff --git a/verify/sex_i18n.sql b/verify/sex_i18n.sql new file mode 100644 index 0000000..29ee0c8 --- /dev/null +++ b/verify/sex_i18n.sql @@ -0,0 +1,11 @@ +-- Verify camper:sex_i18n on pg + +begin; + +select sex_id + , lang_tag + , name +from camper.sex_i18n +where false; + +rollback; diff --git a/web/static/camper.css b/web/static/camper.css index f7fd36c..306e969 100644 --- a/web/static/camper.css +++ b/web/static/camper.css @@ -919,3 +919,83 @@ label[x-show] > span, label[x-show] > br { } /**/ +/**/ + +#checkin-guests { + display: flex; + flex-direction: column; +} + +#checkin-guests :is(label, fieldset) { + margin-top: 0; +} + +#checkin-guests br { + display: none; +} + +#checkin-guests > fieldset { + counter-reset: guest-count; +} + +#checkin-guests > fieldset > fieldset { + counter-increment: guest-count; + position: relative; + display: grid; + grid-template-columns: repeat(4, 1fr); + border-bottom: .5px solid; + padding: 2.25em 0 1em; + column-gap: 1ch; + row-gap: .75em; +} + +#checkin-guests > fieldset > fieldset::before { + content: '#' counter(guest-count); + position: absolute; +} + +#checkin-guests fieldset fieldset:first-of-type button { + display: none; +} + +#checkin-guests fieldset button { + position: absolute; + right: 0; + width: min-content; + min-width: unset; + line-height: 1; + border: none; + cursor: pointer; +} + +#checkin-guests > fieldset > fieldset::before, +#checkin-guests fieldset button { + top: .25em; +} + +#checkin-guests fieldset button:hover { + background-color: var(--camper--color--light-gray); +} + +#checkin-guests fieldset button::before { + content: '⌫'; +} + +#checkin-guests :is(input, select) { + width: 100%; +} + +#checkin-guests label:nth-of-type(2), #checkin-guests label:nth-of-type(9) { + grid-column: span 2; +} + +#checkin-guests label:last-of-type { + grid-column: 1 / -1; +} + +#checkin-guests footer { + display: flex; + justify-content: space-between; +} + +/**/ diff --git a/web/templates/admin/booking/checkin.gohtml b/web/templates/admin/booking/checkin.gohtml new file mode 100644 index 0000000..65c36c4 --- /dev/null +++ b/web/templates/admin/booking/checkin.gohtml @@ -0,0 +1,34 @@ + +{{ define "title" -}} + {{( pgettext "Check-in Booking" "title" )}} +{{- end }} + +{{ define "breadcrumb" -}} +
  • {{( pgettext "Bookings" "title" )}}
  • +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.checkinForm*/ -}} + {{( pgettext "Edit Booking" "action" )}} +

    {{ template "title" .}}

    +
    + {{ CSRFInput }} +
    + {{( pgettext "Guests" "title" )}} + {{ range .Guests -}} + {{ template "guest.gohtml" . }} + {{- end }} +
    +
    + + +
    +
    +{{- end }} diff --git a/web/templates/admin/booking/form.gohtml b/web/templates/admin/booking/form.gohtml index b0f9539..f086dc5 100644 --- a/web/templates/admin/booking/form.gohtml +++ b/web/templates/admin/booking/form.gohtml @@ -21,6 +21,9 @@ {{ define "content" -}} {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.adminBookingForm*/ -}} + {{ if .ID -}} + {{( pgettext "Check-in Booking" "action" )}} + {{- end }}

    {{ template "title" .}}

    + + {{ with .IDDocumentNumber -}} + + {{- end }} + {{ with .IDDocumentType -}} + + {{- end }} + {{ with .IDDocumentDate -}} + + {{- end }} + {{ with .FirstSurname -}} + + {{- end }} + {{ with .SecondSurname -}} + + {{- end }} + {{ with .GivenName -}} + + {{- end }} + {{ with .Sex -}} + + {{- end }} + {{ with .Birthdate -}} + + {{- end }} + {{ with .Country -}} + + {{- end }} + {{ with .Phone -}} + + {{- end }} + {{ with .Address -}} + + {{- end }} +