diff --git a/deploy/country.sql b/deploy/country.sql index 420d9d1..dccc95b 100644 --- a/deploy/country.sql +++ b/deploy/country.sql @@ -13,6 +13,7 @@ create table country ( postal_code_regex text not null ); +grant select on table country to guest; grant select on table country to employee; grant select on table country to admin; diff --git a/deploy/country_i18n.sql b/deploy/country_i18n.sql index 590e148..82dc9c6 100644 --- a/deploy/country_i18n.sql +++ b/deploy/country_i18n.sql @@ -16,6 +16,7 @@ create table country_i18n ( primary key (country_code, lang_tag) ); +grant select on table country_i18n to guest; grant select on table country_i18n to employee; grant select on table country_i18n to admin; diff --git a/pkg/app/public.go b/pkg/app/public.go index 0f688f5..e2a59db 100644 --- a/pkg/app/public.go +++ b/pkg/app/public.go @@ -9,6 +9,7 @@ import ( "net/http" "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/booking" "dev.tandem.ws/tandem/camper/pkg/campsite" "dev.tandem.ws/tandem/camper/pkg/database" "dev.tandem.ws/tandem/camper/pkg/home" @@ -19,6 +20,7 @@ import ( type publicHandler struct { home *home.PublicHandler + booking *booking.PublicHandler campsite *campsite.PublicHandler services *services.PublicHandler } @@ -26,6 +28,7 @@ type publicHandler struct { func newPublicHandler() *publicHandler { return &publicHandler{ home: home.NewPublicHandler(), + booking: booking.NewPublicHandler(), campsite: campsite.NewPublicHandler(), services: services.NewPublicHandler(), } @@ -38,6 +41,8 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da switch head { case "": h.home.Handler(user, company, conn).ServeHTTP(w, r) + case "booking": + h.booking.Handler(user, company, conn).ServeHTTP(w, r) case "campground": campgroundHandler(user, company, conn).ServeHTTP(w, r) case "campsites": diff --git a/pkg/booking/payment.go b/pkg/booking/payment.go new file mode 100644 index 0000000..ca72b15 --- /dev/null +++ b/pkg/booking/payment.go @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package booking + +import ( + "net/http" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/redsys" + "dev.tandem.ws/tandem/camper/pkg/template" +) + +type paymentPage struct { + *template.PublicPage + Request *redsys.SignedRequest +} + +func newPaymentPage(request *redsys.SignedRequest) *paymentPage { + return &paymentPage{ + PublicPage: template.NewPublicPage(), + Request: request, + } +} + +func (p *paymentPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "payment/request.gohtml", p) +} + +func handleSuccessfulPayment(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch head { + case "": + switch r.Method { + case http.MethodGet: + page := newSuccessfulPaymentPage() + page.MustRender(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) + } + default: + http.NotFound(w, r) + } +} + +type successfulPaymentPage struct { + *template.PublicPage +} + +func newSuccessfulPaymentPage() *successfulPaymentPage { + return &successfulPaymentPage{ + PublicPage: template.NewPublicPage(), + } +} + +func (p *successfulPaymentPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "payment/success.gohtml", p) +} + +func handleFailedPayment(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch head { + case "": + switch r.Method { + case http.MethodGet: + page := newFailedPaymentPage() + page.MustRender(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) + } + default: + http.NotFound(w, r) + } +} + +type failedPaymentPage struct { + *template.PublicPage +} + +func newFailedPaymentPage() *failedPaymentPage { + return &failedPaymentPage{ + PublicPage: template.NewPublicPage(), + } +} + +func (p *failedPaymentPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "payment/failure.gohtml", p) +} diff --git a/pkg/booking/public.go b/pkg/booking/public.go new file mode 100644 index 0000000..d127a24 --- /dev/null +++ b/pkg/booking/public.go @@ -0,0 +1,345 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package booking + +import ( + "context" + "crypto/rand" + "encoding/hex" + "fmt" + "net/http" + + "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/redsys" + "dev.tandem.ws/tandem/camper/pkg/template" +) + +type PublicHandler struct { +} + +func NewPublicHandler() *PublicHandler { + return &PublicHandler{} +} + +func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch head { + case "": + switch r.Method { + case http.MethodGet: + page := newPublicPage(r.Context(), company, conn, user.Locale) + page.MustRender(w, r, user, company, conn) + case http.MethodPost: + makeReservation(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) + } + case "success": + handleSuccessfulPayment(w, r, user, company, conn) + case "failure": + handleFailedPayment(w, r, user, company, conn) + default: + http.NotFound(w, r) + } + }) +} + +func makeReservation(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + f := newBookingForm(r.Context(), company, conn, user.Locale) + if err := f.Parse(r); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + 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) + } + page := newPublicPageWithForm(f) + page.MustRender(w, r, user, company, conn) + return + } + + client, err := redsys.New("361716962", "001", "sq7HjrUOBfKmC576ILgskD5srU870gJ7") + if err != nil { + panic(err) + } + schema := httplib.Protocol(r) + authority := httplib.Host(r) + request := &redsys.Request{ + TransactionType: redsys.TransactionTypeCharge, + Amount: 1234, + Currency: redsys.CurrencyEUR, + Order: randomOrderNumber(), + Product: "Test Booking", + SuccessURL: fmt.Sprintf("%s://%s/%s/booking/success", schema, authority, user.Locale.Language), + FailureURL: fmt.Sprintf("%s://%s/%s/booking/failure", schema, authority, user.Locale.Language), + ConsumerLanguage: redsys.LanguageCatalan, + } + signed, err := client.SignRequest(request) + if err != nil { + panic(err) + } + page := newPaymentPage(signed) + page.MustRender(w, r, user, company, conn) +} + +func randomOrderNumber() string { + bytes := make([]byte, 6) + if _, err := rand.Read(bytes); err != nil { + panic(err) + } + return hex.EncodeToString(bytes) +} + +type publicPage struct { + *template.PublicPage + Form *bookingForm +} + +func newPublicPage(ctx context.Context, company *auth.Company, conn *database.Conn, l *locale.Locale) *publicPage { + return newPublicPageWithForm(newBookingForm(ctx, company, conn, l)) +} + +func newPublicPageWithForm(form *bookingForm) *publicPage { + return &publicPage{ + PublicPage: template.NewPublicPage(), + Form: form, + } +} + +func (p *publicPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "booking.gohtml", p) +} + +type bookingForm struct { + FullName *form.Input + Address *form.Input + PostalCode *form.Input + City *form.Input + Country *form.Select + Email *form.Input + Phone *form.Input + Adults *form.Input + Teenagers *form.Input + Children *form.Input + Dogs *form.Input + CampsiteType *form.Select + CampsiteTypeOptions map[string][]*campsiteTypeOption + ArrivalDate *form.Input + DepartureDate *form.Input + AreaPreferences *form.Input + ACSICard *form.Checkbox + Agreement *form.Checkbox +} + +type campsiteTypeOption struct { + Label string + Min int + Max int + Input *form.Input +} + +func newBookingForm(ctx context.Context, company *auth.Company, conn *database.Conn, l *locale.Locale) *bookingForm { + f := &bookingForm{ + FullName: &form.Input{ + Name: "full_name", + }, + Address: &form.Input{ + Name: "address", + }, + PostalCode: &form.Input{ + Name: "postal_code", + }, + City: &form.Input{ + Name: "city", + }, + 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), + }, + Email: &form.Input{ + Name: "email", + }, + Phone: &form.Input{ + Name: "phone", + }, + Adults: &form.Input{ + Name: "adults", + Val: "2", + }, + Teenagers: &form.Input{ + Name: "teenagers", + Val: "0", + }, + Children: &form.Input{ + Name: "children", + Val: "0", + }, + Dogs: &form.Input{ + Name: "dogs", + Val: "0", + }, + CampsiteType: &form.Select{ + Name: "campsite_type", + Options: form.MustGetOptions(ctx, conn, "select type.slug, coalesce(i18n.name, type.name) as l10n_name from campsite_type as type left join campsite_type_i18n as i18n on type.campsite_type_id = i18n.campsite_type_id and i18n.lang_tag = $1 where company_id = $2 order by l10n_name", l.Language, company.ID), + }, + CampsiteTypeOptions: make(map[string][]*campsiteTypeOption), + ArrivalDate: &form.Input{ + Name: "arrival_date", + }, + DepartureDate: &form.Input{ + Name: "departure_date", + }, + AreaPreferences: &form.Input{ + Name: "area_preferences", + }, + ACSICard: &form.Checkbox{ + Name: "acsi_card", + }, + Agreement: &form.Checkbox{ + Name: "agreement", + }, + } + rows, err := conn.Query(ctx, ` + select 'campsite_type_option_' || option.campsite_type_option_id + , slug + , coalesce(option.name, i18n.name) as l10_name + , lower(range)::text + , lower(range) + , upper(range) + from campsite_type_option as option + join campsite_type using (campsite_type_id) + left join campsite_type_option_i18n as i18n on i18n.campsite_type_option_id = option.campsite_type_id and i18n.lang_tag = $1 + where company_id = $2 +`, l.Language, company.ID) + if err != nil { + panic(err) + } + for rows.Next() { + var slug string + option := &campsiteTypeOption{ + Input: &form.Input{}, + } + if err := rows.Scan(&option.Input.Name, &slug, &option.Label, &option.Input.Val, &option.Min, &option.Max); err != nil { + panic(err) + } + f.CampsiteTypeOptions[slug] = append(f.CampsiteTypeOptions[slug], option) + } + if rows.Err() != nil { + panic(rows.Err()) + } + return f +} +func (f *bookingForm) Parse(r *http.Request) error { + if err := r.ParseForm(); err != nil { + return err + } + f.FullName.FillValue(r) + f.Address.FillValue(r) + f.PostalCode.FillValue(r) + f.City.FillValue(r) + f.Country.FillValue(r) + f.Email.FillValue(r) + f.Phone.FillValue(r) + f.Adults.FillValue(r) + f.Teenagers.FillValue(r) + f.Children.FillValue(r) + f.Dogs.FillValue(r) + f.CampsiteType.FillValue(r) + f.ArrivalDate.FillValue(r) + f.DepartureDate.FillValue(r) + f.AreaPreferences.FillValue(r) + f.ACSICard.FillValue(r) + f.Agreement.FillValue(r) + for _, options := range f.CampsiteTypeOptions { + for _, option := range options { + option.Input.FillValue(r) + } + } + return nil +} + +func (f *bookingForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) { + v := form.NewValidator(l) + + var country string + if v.CheckSelectedOptions(f.Country, l.GettextNoop("Selected country is not valid.")) { + country = f.Country.Selected[0] + } + + if v.CheckRequired(f.FullName, l.GettextNoop("Full name can not be empty.")) { + v.CheckMinLength(f.FullName, 1, l.GettextNoop("Full name must have at least one letter.")) + } + + if f.PostalCode.Val != "" { + if _, err := v.CheckValidPostalCode(ctx, conn, f.PostalCode, country, l.GettextNoop("This postal code is not valid.")); err != nil { + return false, err + } + } + if v.CheckRequired(f.Email, l.GettextNoop("Email can not be empty.")) { + v.CheckValidEmail(f.Email, l.GettextNoop("This email is not valid. It should be like name@domain.com.")) + } + if v.CheckRequired(f.Phone, l.GettextNoop("Phone can not be empty.")) { + if _, err := v.CheckValidPhone(ctx, conn, f.Phone, country, l.GettextNoop("This phone number is not valid.")); err != nil { + return false, err + } + } + if v.CheckRequired(f.Adults, l.GettextNoop("Number of adults can not be empty")) { + if v.CheckValidInteger(f.Adults, l.GettextNoop("Number of adults must be an integer.")) { + v.CheckMinInteger(f.Adults, 1, l.GettextNoop("Number of adults must be one or greater.")) + } + } + if v.CheckRequired(f.Teenagers, l.GettextNoop("Number of teenagers can not be empty")) { + if v.CheckValidInteger(f.Teenagers, l.GettextNoop("Number of teenagers must be an integer.")) { + v.CheckMinInteger(f.Teenagers, 0, l.GettextNoop("Number of teenagers must be zero or greater.")) + } + } + if v.CheckRequired(f.Children, l.GettextNoop("Number of children can not be empty")) { + if v.CheckValidInteger(f.Children, l.GettextNoop("Number of children must be an integer.")) { + v.CheckMinInteger(f.Children, 0, l.GettextNoop("Number of children must be zero or greater.")) + } + } + if v.CheckRequired(f.Dogs, l.GettextNoop("Number of dogs can not be empty")) { + if v.CheckValidInteger(f.Dogs, l.GettextNoop("Number of dogs must be an integer.")) { + v.CheckMinInteger(f.Dogs, 0, l.GettextNoop("Number of dogs must be zero or greater.")) + } + } + var validBefore bool + v.CheckSelectedOptions(f.CampsiteType, l.GettextNoop("Selected campsite type is not valid.")) + if v.CheckRequired(f.ArrivalDate, l.GettextNoop("Arrival date can not be empty")) { + if v.CheckValidDate(f.ArrivalDate, l.GettextNoop("Arrival date must be a valid date.")) { + validBefore = true + } + } + if v.CheckRequired(f.DepartureDate, l.GettextNoop("Departure date can not be empty")) { + if v.CheckValidDate(f.DepartureDate, l.GettextNoop("Departure date must be a valid date.")) && validBefore { + v.CheckDateAfter(f.DepartureDate, f.ArrivalDate, l.GettextNoop("The departure date must be after the arrival date.")) + } + } + v.Check(f.Agreement, f.Agreement.Checked, l.GettextNoop("It is mandatory to agree to the reservation conditions.")) + for _, options := range f.CampsiteTypeOptions { + for _, option := range options { + if v.CheckRequired(option.Input, fmt.Sprintf(l.Gettext("%s can not be empty"), option.Label)) { + if v.CheckValidInteger(option.Input, fmt.Sprintf(l.Gettext("%s must be an integer."), option.Label)) { + if v.CheckMinInteger(option.Input, option.Min, fmt.Sprintf(l.Gettext("%s must be %d or greater."), option.Label, option.Min)) { + v.CheckMaxInteger(option.Input, option.Max, fmt.Sprintf(l.Gettext("%s must be at most %d."), option.Label, option.Max)) + } + } + } + } + } + return v.AllOK, nil +} diff --git a/pkg/form/validator.go b/pkg/form/validator.go index 95074d5..87673e9 100644 --- a/pkg/form/validator.go +++ b/pkg/form/validator.go @@ -43,6 +43,11 @@ func (v *Validator) CheckMinInteger(input *Input, min int, message string) bool return v.Check(input, i >= min, message) } +func (v *Validator) CheckMaxInteger(input *Input, max int, message string) bool { + i, _ := strconv.Atoi(input.Val) + return v.Check(input, i <= max, message) +} + func (v *Validator) CheckMinDecimal(input *Input, min float64, message string) bool { f, _ := strconv.ParseFloat(input.Val, 64) return v.Check(input, f >= min, message) @@ -109,6 +114,12 @@ func (v *Validator) CheckValidDate(field *Input, message string) bool { return v.Check(field, err == nil, message) } +func (v *Validator) CheckDateAfter(field *Input, beforeField *Input, message string) bool { + date, _ := time.Parse("2006-01-02", field.Val) + before, _ := time.Parse("2006-01-02", beforeField.Val) + return v.Check(field, date.After(before), message) +} + func (v *Validator) CheckPasswordConfirmation(password *Input, confirm *Input, message string) bool { return v.Check(confirm, password.Val == confirm.Val, message) } diff --git a/pkg/redsys/client.go b/pkg/redsys/client.go new file mode 100644 index 0000000..d5d69a5 --- /dev/null +++ b/pkg/redsys/client.go @@ -0,0 +1,174 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package redsys + +import ( + "bytes" + "crypto/cipher" + "crypto/des" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "strings" +) + +type Language int + +const ( + LanguageDefault Language = 0 + LanguageSpanish Language = 1 + LanguageEnglish Language = 2 + LanguageCatalan Language = 3 + LanguageFrench Language = 4 +) + +type TransactionType int + +const ( + TransactionTypeCharge TransactionType = 0 + TransactionTypeRefund TransactionType = 3 + TransactionTypePreauth TransactionType = 1 + TransactionTypePreauthConfirm TransactionType = 2 + TransactionTypePreauthVoid TransactionType = 9 + TransactionTypeSplitAuth TransactionType = 7 + TransactionTypeSplitConfirm TransactionType = 8 +) + +type Currency int + +// Source: https://sis-d.redsys.es/pagosonline/codigos-autorizacion.html#monedas +// The codes seem to be the same as ISO 4217 https://en.wikipedia.org/wiki/ISO_4217 +const ( + CurrencyEUR Currency = 978 +) + +type Request struct { + TransactionType TransactionType + Amount int64 + Currency Currency + Order string + Product string + CardHolder string + SuccessURL string + FailureURL string + ConsumerLanguage Language +} + +type merchantParameters struct { + MerchantCode string `json:"Ds_Merchant_MerchantCode"` + Terminal string `json:"Ds_Merchant_Terminal"` + TransactionType TransactionType `json:"Ds_Merchant_TransactionType,string"` + Amount int64 `json:"Ds_Merchant_Amount,string"` + Currency Currency `json:"Ds_Merchant_Currency,string"` + Order string `json:"Ds_Merchant_Order"` + MerchantURL string `json:"Ds_Merchant_MerchantURL,omitempty"` + Product string `json:"Ds_Merchant_ProductDescription,omitempty"` + CardHolder string `json:"Ds_Merchant_Titular,omitempty"` + SuccessURL string `json:"Ds_Merchant_UrlOK,omitempty"` + FailureURL string `json:"Ds_Merchant_UrlKO,omitempty"` + MerchantName string `json:"Ds_Merchant_MerchantName,omitempty"` + ConsumerLanguage Language `json:"Ds_Merchant_ConsumerLanguage,string,omitempty"` +} + +type Client struct { + merchantCode string + terminalCode string + crypto cipher.Block +} + +func New(merchantCode string, terminalCode string, key string) (*Client, error) { + b, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, fmt.Errorf("key is invalid base64: %v", err) + } + + crypto, err := des.NewTripleDESCipher(b) + if err != nil { + return nil, err + } + + return &Client{ + merchantCode: merchantCode, + terminalCode: terminalCode, + crypto: crypto, + }, nil +} + +func (p *Client) SignRequest(req *Request) (*SignedRequest, error) { + signed := &SignedRequest{ + SignatureVersion: "HMAC_SHA256_V1", + } + params := &merchantParameters{ + MerchantCode: p.merchantCode, + Terminal: p.terminalCode, + TransactionType: req.TransactionType, + Amount: req.Amount, + Currency: req.Currency, + Order: req.Order, + MerchantURL: "http://localhost/ca/", + Product: req.Product, + CardHolder: req.CardHolder, + SuccessURL: req.SuccessURL, + FailureURL: req.FailureURL, + MerchantName: "Merchant Here", + ConsumerLanguage: req.ConsumerLanguage, + } + var err error + signed.MerchantParameters, err = encodeMerchantParameters(params) + if err != nil { + return nil, err + } + signed.Signature = p.sign(params.Order, signed.MerchantParameters) + return signed, nil +} + +func encodeMerchantParameters(params *merchantParameters) (string, error) { + marshalled, err := json.Marshal(params) + if err != nil { + return "", err + } + return base64.URLEncoding.EncodeToString(marshalled), err +} + +func (p *Client) sign(id string, data string) string { + key := encrypt3DES(id, p.crypto) + return mac256(data, key) +} + +var iv = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + +func encrypt3DES(str string, crypto cipher.Block) string { + cbc := cipher.NewCBCEncrypter(crypto, iv) + + decrypted := []byte(str) + decryptedPadded, _ := zeroPad(decrypted, crypto.BlockSize()) + cbc.CryptBlocks(decryptedPadded, decryptedPadded) + + return base64.StdEncoding.EncodeToString(decryptedPadded) +} + +func zeroPad(data []byte, blockLen int) ([]byte, error) { + padLen := (blockLen - (len(data) % blockLen)) % blockLen + pad := bytes.Repeat([]byte{0x00}, padLen) + + return append(data, pad...), nil +} + +func mac256(data string, key string) string { + decodedKey, _ := base64.StdEncoding.DecodeString(key) + res := hmac.New(sha256.New, decodedKey) + res.Write([]byte(strings.TrimSpace(data))) + result := res.Sum(nil) + return base64.StdEncoding.EncodeToString(result) +} + +type SignedRequest struct { + MerchantParameters string + Signature string + SignatureVersion string +} diff --git a/po/ca.po b/po/ca.po index e071d1d..a2a0b7f 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: 2023-10-14 21:54+0200\n" +"POT-Creation-Date: 2023-10-19 21:23+0200\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -18,9 +18,32 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: web/templates/public/payment/success.gohtml:6 +#: web/templates/public/payment/success.gohtml:11 +msgctxt "title" +msgid "Payment Successful" +msgstr "Pagament amb èxit" + +#: web/templates/public/payment/request.gohtml:6 +#: web/templates/public/payment/request.gohtml:11 +msgctxt "title" +msgid "Payment" +msgstr "Pagament" + +#: web/templates/public/payment/request.gohtml:17 +msgctxt "action" +msgid "Pay" +msgstr "Paga" + +#: web/templates/public/payment/failure.gohtml:6 +#: web/templates/public/payment/failure.gohtml:11 +msgctxt "title" +msgid "Payment Failed" +msgstr "Ha fallat el pagament" + #: web/templates/public/services.gohtml:6 #: web/templates/public/services.gohtml:15 -#: web/templates/public/layout.gohtml:43 web/templates/public/layout.gohtml:70 +#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 #: web/templates/admin/services/index.gohtml:53 msgctxt "title" msgid "Services" @@ -30,8 +53,8 @@ msgstr "Serveis" msgid "The campsite offers many different services." msgstr "El càmping disposa de diversos serveis." -#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:29 -#: web/templates/public/layout.gohtml:68 +#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:30 +#: web/templates/public/layout.gohtml:69 msgctxt "title" msgid "Home" msgstr "Inici" @@ -52,7 +75,7 @@ msgstr "Els nostres serveis" #: web/templates/public/home.gohtml:34 #: web/templates/public/surroundings.gohtml:6 #: web/templates/public/surroundings.gohtml:10 -#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 +#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 msgctxt "title" msgid "Surroundings" msgstr "L’entorn" @@ -77,60 +100,109 @@ msgstr "Descobreix l’entorn" msgid "Come and enjoy!" msgstr "Vine a gaudir!" -#: web/templates/public/campsite/type.gohtml:40 +#: web/templates/public/campsite/type.gohtml:41 msgctxt "input" msgid "Check-in Date" msgstr "Data d’entrada" -#: web/templates/public/campsite/type.gohtml:46 +#: web/templates/public/campsite/type.gohtml:47 msgctxt "input" msgid "Check-out Date" msgstr "Data de sortida" -#: web/templates/public/campsite/type.gohtml:53 +#: web/templates/public/campsite/type.gohtml:54 +#: web/templates/public/booking.gohtml:175 msgctxt "action" msgid "Book" msgstr "Reserva" -#: web/templates/public/campsite/type.gohtml:59 +#: web/templates/public/campsite/type.gohtml:60 #: web/templates/admin/campsite/option/form.gohtml:58 #: web/templates/admin/campsite/type/form.gohtml:73 msgctxt "title" msgid "Prices" msgstr "Preus" -#: web/templates/public/campsite/type.gohtml:71 +#: web/templates/public/campsite/type.gohtml:72 msgid "Starting from %s €/night" msgstr "A partir de %s €/nit" -#: web/templates/public/campsite/type.gohtml:73 +#: web/templates/public/campsite/type.gohtml:74 msgid "%s €/night" msgstr "%s €/nit" -#: web/templates/public/campsite/type.gohtml:76 +#: web/templates/public/campsite/type.gohtml:77 msgid "*Minimum %d nights per stay" msgstr "*Mínim %d nits per estada" -#: web/templates/public/campsite/type.gohtml:90 +#: web/templates/public/campsite/type.gohtml:89 +#: web/templates/admin/season/index.gohtml:48 +msgctxt "title" +msgid "Calendar" +msgstr "Calendari" + +#: web/templates/public/campsite/type.gohtml:100 msgctxt "title" msgid "Features" msgstr "Característiques" -#: web/templates/public/campsite/type.gohtml:101 +#: web/templates/public/campsite/type.gohtml:111 msgctxt "title" msgid "Info" msgstr "Informació" -#: web/templates/public/campsite/type.gohtml:105 +#: web/templates/public/campsite/type.gohtml:115 msgctxt "title" msgid "Facilities" msgstr "Equipaments" -#: web/templates/public/campsite/type.gohtml:109 +#: web/templates/public/campsite/type.gohtml:119 msgctxt "title" msgid "Description" msgstr "Descripció" +#: web/templates/public/campsite/calendar.gohtml:18 +#: web/templates/admin/season/calendar.gohtml:16 +msgctxt "day" +msgid "Mon" +msgstr "dl" + +#: web/templates/public/campsite/calendar.gohtml:19 +#: web/templates/admin/season/calendar.gohtml:17 +msgctxt "day" +msgid "Tue" +msgstr "dt" + +#: web/templates/public/campsite/calendar.gohtml:20 +#: web/templates/admin/season/calendar.gohtml:18 +msgctxt "day" +msgid "Wed" +msgstr "dc" + +#: web/templates/public/campsite/calendar.gohtml:21 +#: web/templates/admin/season/calendar.gohtml:19 +msgctxt "day" +msgid "Thu" +msgstr "dj" + +#: web/templates/public/campsite/calendar.gohtml:22 +#: web/templates/admin/season/calendar.gohtml:20 +msgctxt "day" +msgid "Fri" +msgstr "dv" + +#: web/templates/public/campsite/calendar.gohtml:23 +#: web/templates/admin/season/calendar.gohtml:21 +msgctxt "day" +msgid "Sat" +msgstr "ds" + +#: web/templates/public/campsite/calendar.gohtml:24 +#: web/templates/admin/season/calendar.gohtml:22 +msgctxt "day" +msgid "Sun" +msgstr "dg" + #: web/templates/public/surroundings.gohtml:13 msgctxt "title" msgid "What to Do Outside the Campsite?" @@ -191,27 +263,140 @@ msgstr "Hi ha diversos punts on poder anar amb caiac, des de trams del riu Ter c #: web/templates/public/campground.gohtml:6 #: web/templates/public/campground.gohtml:11 -#: web/templates/public/layout.gohtml:30 web/templates/public/layout.gohtml:69 +#: web/templates/public/layout.gohtml:31 web/templates/public/layout.gohtml:70 msgctxt "title" msgid "Campground" msgstr "El càmping" #: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:15 -#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 +#: web/templates/public/layout.gohtml:46 web/templates/public/layout.gohtml:73 msgctxt "title" msgid "Contact" msgstr "Contacte" -#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:24 -#: web/templates/public/layout.gohtml:95 +#: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 +msgctxt "title" +msgid "Booking" +msgstr "Reserva" + +#: web/templates/public/booking.gohtml:15 +msgctxt "title" +msgid "Customer Details" +msgstr "Detalls del client" + +#: web/templates/public/booking.gohtml:18 +msgctxt "input" +msgid "Full name" +msgstr "Nom i cognoms" + +#: web/templates/public/booking.gohtml:26 +msgctxt "input" +msgid "Address (optional)" +msgstr "Adreça (opcional)" + +#: web/templates/public/booking.gohtml:34 +msgctxt "input" +msgid "Postcode (optional)" +msgstr "Codi postal (opcional)" + +#: web/templates/public/booking.gohtml:42 +msgctxt "input" +msgid "Town or village (optional)" +msgstr "Població (opcional)" + +#: web/templates/public/booking.gohtml:50 +#: web/templates/admin/taxDetails.gohtml:98 +msgctxt "input" +msgid "Country" +msgstr "País" + +#: web/templates/public/booking.gohtml:53 +msgid "Choose a country" +msgstr "Esculli un país" + +#: web/templates/public/booking.gohtml:60 web/templates/admin/login.gohtml:22 +#: web/templates/admin/profile.gohtml:35 +#: web/templates/admin/taxDetails.gohtml:50 +msgctxt "input" +msgid "Email" +msgstr "Correu-e" + +#: web/templates/public/booking.gohtml:68 +#: web/templates/admin/taxDetails.gohtml:42 +msgctxt "input" +msgid "Phone" +msgstr "Telèfon" + +#: web/templates/public/booking.gohtml:76 +msgctxt "title" +msgid "Party Details" +msgstr "Dades dels visitants" + +#: web/templates/public/booking.gohtml:79 +msgctxt "input" +msgid "Adults" +msgstr "Adults" + +#: web/templates/public/booking.gohtml:87 +msgctxt "input" +msgid "Teenagers (from 11 to 16 years old)" +msgstr "Adolescents (entre 11 i 16 anys)" + +#: web/templates/public/booking.gohtml:95 +msgctxt "input" +msgid "Children (up to 10 years old)" +msgstr "Nens (fins a 10 anys)" + +#: web/templates/public/booking.gohtml:103 +msgctxt "input" +msgid "Dogs" +msgstr "Gossos" + +#: web/templates/public/booking.gohtml:111 +msgctxt "title" +msgid "Accomodation" +msgstr "Acomodacions" + +#: web/templates/public/booking.gohtml:136 +msgctxt "title" +msgid "Booking Period" +msgstr "Període de reserva" + +#: web/templates/public/booking.gohtml:139 +msgctxt "input" +msgid "Arrival date" +msgstr "Data d’arribada" + +#: web/templates/public/booking.gohtml:147 +msgctxt "input" +msgid "Departure date" +msgstr "Data de sortida" + +#: web/templates/public/booking.gohtml:155 +msgctxt "input" +msgid "Area preferences (optional)" +msgstr "Preferències d’àrea (opcional)" + +#: web/templates/public/booking.gohtml:165 +msgctxt "input" +msgid "ACSI card? (optional)" +msgstr "Targeta ACSI? (opcional)" + +#: web/templates/public/booking.gohtml:171 +msgctxt "input" +msgid "I have read and I accept the reservation conditions" +msgstr "He llegit i accepto les condicions de reserves" + +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:25 +#: web/templates/public/layout.gohtml:96 msgid "Campsite Montagut" msgstr "Càmping Montagut" -#: web/templates/public/layout.gohtml:22 web/templates/admin/layout.gohtml:18 +#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:18 msgid "Skip to main content" msgstr "Salta al contingut principal" -#: web/templates/public/layout.gohtml:34 web/templates/public/layout.gohtml:79 +#: web/templates/public/layout.gohtml:35 web/templates/public/layout.gohtml:80 #: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/layout.gohtml:40 web/templates/admin/layout.gohtml:71 @@ -219,12 +404,12 @@ msgctxt "title" msgid "Campsites" msgstr "Allotjaments" -#: web/templates/public/layout.gohtml:66 +#: web/templates/public/layout.gohtml:67 msgctxt "title" msgid "Sections" msgstr "Apartats" -#: web/templates/public/layout.gohtml:92 +#: web/templates/public/layout.gohtml:93 msgid "RTC #%s" msgstr "Núm. RTC %s" @@ -735,52 +920,12 @@ msgstr "Color" msgid "No seasons added yet." msgstr "No s’ha afegit cap temporada encara." -#: web/templates/admin/season/index.gohtml:48 -msgctxt "title" -msgid "Calendar" -msgstr "Calendari" - #: web/templates/admin/season/l10n.gohtml:7 #: web/templates/admin/season/l10n.gohtml:14 msgctxt "title" msgid "Translate Season to %s" msgstr "Traducció de la temporada a %s" -#: web/templates/admin/season/calendar.gohtml:16 -msgctxt "day" -msgid "Mon" -msgstr "dl" - -#: web/templates/admin/season/calendar.gohtml:17 -msgctxt "day" -msgid "Tue" -msgstr "dt" - -#: web/templates/admin/season/calendar.gohtml:18 -msgctxt "day" -msgid "Wed" -msgstr "dc" - -#: web/templates/admin/season/calendar.gohtml:19 -msgctxt "day" -msgid "Thu" -msgstr "dj" - -#: web/templates/admin/season/calendar.gohtml:20 -msgctxt "day" -msgid "Fri" -msgstr "dv" - -#: web/templates/admin/season/calendar.gohtml:21 -msgctxt "day" -msgid "Sat" -msgstr "ds" - -#: web/templates/admin/season/calendar.gohtml:22 -msgctxt "day" -msgid "Sun" -msgstr "dg" - #: web/templates/admin/season/calendar.gohtml:49 #: web/templates/admin/media/picker.gohtml:61 msgctxt "action" @@ -798,12 +943,6 @@ msgctxt "title" msgid "Login" msgstr "Entrada" -#: web/templates/admin/login.gohtml:22 web/templates/admin/profile.gohtml:35 -#: web/templates/admin/taxDetails.gohtml:50 -msgctxt "input" -msgid "Email" -msgstr "Correu-e" - #: web/templates/admin/login.gohtml:31 web/templates/admin/profile.gohtml:46 msgctxt "input" msgid "Password" @@ -916,11 +1055,6 @@ msgctxt "input" msgid "Trade Name" msgstr "Nom comercial" -#: web/templates/admin/taxDetails.gohtml:42 -msgctxt "input" -msgid "Phone" -msgstr "Telèfon" - #: web/templates/admin/taxDetails.gohtml:66 msgctxt "input" msgid "Address" @@ -938,14 +1072,9 @@ msgstr "Província" #: web/templates/admin/taxDetails.gohtml:90 msgctxt "input" -msgid "Postal Code" +msgid "Postcode" msgstr "Codi postal" -#: web/templates/admin/taxDetails.gohtml:98 -msgctxt "input" -msgid "Country" -msgstr "País" - #: web/templates/admin/taxDetails.gohtml:108 msgctxt "input" msgid "RTC number" @@ -1082,10 +1211,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:210 +#: pkg/booking/public.go:292 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:211 +#: pkg/booking/public.go:293 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." @@ -1106,7 +1237,7 @@ msgstr "Automàtic" #: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 #: pkg/campsite/types/option.go:340 pkg/campsite/types/feature.go:243 #: pkg/campsite/types/admin.go:415 pkg/season/l10n.go:69 -#: pkg/season/admin.go:382 pkg/services/l10n.go:73 pkg/services/admin.go:266 +#: pkg/season/admin.go:394 pkg/services/l10n.go:73 pkg/services/admin.go:266 msgid "Name can not be empty." msgstr "No podeu deixar el nom en blanc." @@ -1213,7 +1344,12 @@ msgstr "El número mínim de nits ha de ser enter." msgid "Minimum number of nights must be one or greater." msgstr "El número mínim de nits no pot ser zero." -#: pkg/campsite/admin.go:226 +#: pkg/campsite/types/public.go:157 +msgctxt "season" +msgid "Closed" +msgstr "Tancat" + +#: pkg/campsite/admin.go:226 pkg/booking/public.go:321 msgid "Selected campsite type is not valid." msgstr "El tipus d’allotjament escollit no és vàlid." @@ -1221,96 +1357,96 @@ msgstr "El tipus d’allotjament escollit no és vàlid." msgid "Label can not be empty." msgstr "No podeu deixar l’etiqueta en blanc." -#: pkg/season/admin.go:202 +#: pkg/season/admin.go:212 msgctxt "month" msgid "January" msgstr "gener" -#: pkg/season/admin.go:203 +#: pkg/season/admin.go:213 msgctxt "month" msgid "February" msgstr "febrer" -#: pkg/season/admin.go:204 +#: pkg/season/admin.go:214 msgctxt "month" msgid "March" msgstr "març" -#: pkg/season/admin.go:205 +#: pkg/season/admin.go:215 msgctxt "month" msgid "April" msgstr "abril" -#: pkg/season/admin.go:206 +#: pkg/season/admin.go:216 msgctxt "month" msgid "May" msgstr "maig" -#: pkg/season/admin.go:207 +#: pkg/season/admin.go:217 msgctxt "month" msgid "June" msgstr "juny" -#: pkg/season/admin.go:208 +#: pkg/season/admin.go:218 msgctxt "month" msgid "July" msgstr "juliol" -#: pkg/season/admin.go:209 +#: pkg/season/admin.go:219 msgctxt "month" msgid "August" msgstr "agost" -#: pkg/season/admin.go:210 +#: pkg/season/admin.go:220 msgctxt "month" msgid "September" msgstr "setembre" -#: pkg/season/admin.go:211 +#: pkg/season/admin.go:221 msgctxt "month" msgid "October" msgstr "octubre" -#: pkg/season/admin.go:212 +#: pkg/season/admin.go:222 msgctxt "month" msgid "November" msgstr "novembre" -#: pkg/season/admin.go:213 +#: pkg/season/admin.go:223 msgctxt "month" msgid "December" msgstr "desembre" -#: pkg/season/admin.go:383 +#: pkg/season/admin.go:395 msgid "Color can not be empty." msgstr "No podeu deixar el color en blanc." -#: pkg/season/admin.go:384 +#: pkg/season/admin.go:396 msgid "This color is not valid. It must be like #123abc." msgstr "Aquest color no és vàlid. Hauria de ser similar a #123abc." -#: pkg/season/admin.go:460 +#: pkg/season/admin.go:472 msgctxt "action" msgid "Unset" msgstr "Desassigna" -#: pkg/season/admin.go:491 +#: pkg/season/admin.go:503 msgid "Start date can not be empty." msgstr "No podeu deixar la data d’inici en blanc." -#: pkg/season/admin.go:492 +#: pkg/season/admin.go:504 msgid "Start date must be a valid date." msgstr "La data d’inici ha de ser una data vàlida." -#: pkg/season/admin.go:494 +#: pkg/season/admin.go:506 msgid "End date can not be empty." msgstr "No podeu deixar la data de fi en blanc." -#: pkg/season/admin.go:495 +#: pkg/season/admin.go:507 msgid "End date must be a valid date." msgstr "La data de fi ha de ser una data vàlida." -#: pkg/company/admin.go:193 +#: pkg/company/admin.go:193 pkg/booking/public.go:279 msgid "Selected country is not valid." msgstr "El país escollit no és vàlid." @@ -1330,11 +1466,11 @@ msgstr "No podeu deixar el NIF en blanc." msgid "This VAT number is not valid." msgstr "Aquest NIF no és vàlid." -#: pkg/company/admin.go:205 +#: pkg/company/admin.go:205 pkg/booking/public.go:295 msgid "Phone can not be empty." msgstr "No podeu deixar el telèfon en blanc." -#: pkg/company/admin.go:206 +#: pkg/company/admin.go:206 pkg/booking/public.go:296 msgid "This phone number is not valid." msgstr "Aquest número de telèfon no és vàlid." @@ -1358,7 +1494,7 @@ msgstr "No podeu deixar la província en blanc." msgid "Postal code can not be empty." msgstr "No podeu deixar el codi postal en blanc." -#: pkg/company/admin.go:220 +#: pkg/company/admin.go:220 pkg/booking/public.go:288 msgid "This postal code is not valid." msgstr "Aquest codi postal no és vàlid." @@ -1386,6 +1522,106 @@ 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/public.go:283 +msgid "Full name can not be empty." +msgstr "No podeu deixar el nom i els cognoms en blanc." + +#: pkg/booking/public.go:284 +msgid "Full name must have at least one letter." +msgstr "El nom i els cognoms han de tenir com a mínim una lletra." + +#: pkg/booking/public.go:300 +msgid "Number of adults can not be empty" +msgstr "No podeu deixar el número d’adults en blanc." + +#: pkg/booking/public.go:301 +msgid "Number of adults must be an integer." +msgstr "El número d’adults ha de ser enter." + +#: pkg/booking/public.go:302 +msgid "Number of adults must be one or greater." +msgstr "El número d’adults no pot ser zero." + +#: pkg/booking/public.go:305 +msgid "Number of teenagers can not be empty" +msgstr "No podeu deixar el número d’adolescents en blanc." + +#: pkg/booking/public.go:306 +msgid "Number of teenagers must be an integer." +msgstr "El número d’adolescents ha de ser enter." + +#: pkg/booking/public.go:307 +msgid "Number of teenagers must be zero or greater." +msgstr "El número d’adolescents ha de ser com a mínim zero." + +#: pkg/booking/public.go:310 +msgid "Number of children can not be empty" +msgstr "No podeu deixar el número de nens en blanc." + +#: pkg/booking/public.go:311 +msgid "Number of children must be an integer." +msgstr "El número de nens ha de ser enter." + +#: pkg/booking/public.go:312 +msgid "Number of children must be zero or greater." +msgstr "El número de nens ha de ser com a mínim zero." + +#: pkg/booking/public.go:315 +msgid "Number of dogs can not be empty" +msgstr "No podeu deixar el número de gossos en blanc." + +#: pkg/booking/public.go:316 +msgid "Number of dogs must be an integer." +msgstr "El número de gossos ha de ser enter." + +#: pkg/booking/public.go:317 +msgid "Number of dogs must be zero or greater." +msgstr "El número de gossos ha de ser com a mínim zero." + +#: pkg/booking/public.go:322 +msgid "Arrival date can not be empty" +msgstr "No podeu deixar la data d’arribada en blanc." + +#: pkg/booking/public.go:323 +msgid "Arrival date must be a valid date." +msgstr "La data d’arribada ha de ser una data vàlida." + +#: pkg/booking/public.go:327 +msgid "Departure date can not be empty" +msgstr "No podeu deixar la data de sortida en blanc." + +#: pkg/booking/public.go:328 +msgid "Departure date must be a valid date." +msgstr "La data de sortida ha de ser una data vàlida." + +#: pkg/booking/public.go:329 +msgid "The departure date must be after the arrival date." +msgstr "La data de sortida ha de ser posterior a la d’arribada." + +#: pkg/booking/public.go:332 +msgid "It is mandatory to agree to the reservation conditions." +msgstr "És obligatori acceptar les condicions de reserves." + +#: pkg/booking/public.go:335 +#, c-format +msgid "%s can not be empty" +msgstr "No podeu deixar %s en blanc." + +#: pkg/booking/public.go:336 +#, c-format +msgid "%s must be an integer." +msgstr "%s ha de ser un número enter." + +#: pkg/booking/public.go:337 +#, c-format +msgid "%s must be %d or greater." +msgstr "El valor de %s ha de ser com a mínim %d." + +#: pkg/booking/public.go:338 +#, c-format +msgid "%s must be at most %d." +msgstr "El valor de %s ha de ser com a màxim %d." + #~ msgid "%s: %s €/night" #~ msgstr "%s: %s €/nit" diff --git a/po/es.po b/po/es.po index ba8e5d0..089ceb6 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: 2023-10-14 21:54+0200\n" +"POT-Creation-Date: 2023-10-19 21:23+0200\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -18,9 +18,32 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: web/templates/public/payment/success.gohtml:6 +#: web/templates/public/payment/success.gohtml:11 +msgctxt "title" +msgid "Payment Successful" +msgstr "Pago con éxito" + +#: web/templates/public/payment/request.gohtml:6 +#: web/templates/public/payment/request.gohtml:11 +msgctxt "title" +msgid "Payment" +msgstr "Pago" + +#: web/templates/public/payment/request.gohtml:17 +msgctxt "action" +msgid "Pay" +msgstr "Pagar" + +#: web/templates/public/payment/failure.gohtml:6 +#: web/templates/public/payment/failure.gohtml:11 +msgctxt "title" +msgid "Payment Failed" +msgstr "Pago fallido" + #: web/templates/public/services.gohtml:6 #: web/templates/public/services.gohtml:15 -#: web/templates/public/layout.gohtml:43 web/templates/public/layout.gohtml:70 +#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 #: web/templates/admin/services/index.gohtml:53 msgctxt "title" msgid "Services" @@ -30,8 +53,8 @@ msgstr "Servicios" msgid "The campsite offers many different services." msgstr "El camping dispone de varios servicios." -#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:29 -#: web/templates/public/layout.gohtml:68 +#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:30 +#: web/templates/public/layout.gohtml:69 msgctxt "title" msgid "Home" msgstr "Inicio" @@ -52,7 +75,7 @@ msgstr "Nuestros servicios" #: web/templates/public/home.gohtml:34 #: web/templates/public/surroundings.gohtml:6 #: web/templates/public/surroundings.gohtml:10 -#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 +#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 msgctxt "title" msgid "Surroundings" msgstr "El entorno" @@ -77,60 +100,109 @@ msgstr "Descubre el entorno" msgid "Come and enjoy!" msgstr "¡Ven a disfrutar!" -#: web/templates/public/campsite/type.gohtml:40 +#: web/templates/public/campsite/type.gohtml:41 msgctxt "input" msgid "Check-in Date" msgstr "Fecha de entrada" -#: web/templates/public/campsite/type.gohtml:46 +#: web/templates/public/campsite/type.gohtml:47 msgctxt "input" msgid "Check-out Date" msgstr "Fecha de salida" -#: web/templates/public/campsite/type.gohtml:53 +#: web/templates/public/campsite/type.gohtml:54 +#: web/templates/public/booking.gohtml:175 msgctxt "action" msgid "Book" msgstr "Reservar" -#: web/templates/public/campsite/type.gohtml:59 +#: web/templates/public/campsite/type.gohtml:60 #: web/templates/admin/campsite/option/form.gohtml:58 #: web/templates/admin/campsite/type/form.gohtml:73 msgctxt "title" msgid "Prices" msgstr "Precios" -#: web/templates/public/campsite/type.gohtml:71 +#: web/templates/public/campsite/type.gohtml:72 msgid "Starting from %s €/night" msgstr "A partir de %s €/noche" -#: web/templates/public/campsite/type.gohtml:73 +#: web/templates/public/campsite/type.gohtml:74 msgid "%s €/night" msgstr "%s €/noche" -#: web/templates/public/campsite/type.gohtml:76 +#: web/templates/public/campsite/type.gohtml:77 msgid "*Minimum %d nights per stay" msgstr "*Mínimo %d noches por estancia" -#: web/templates/public/campsite/type.gohtml:90 +#: web/templates/public/campsite/type.gohtml:89 +#: web/templates/admin/season/index.gohtml:48 +msgctxt "title" +msgid "Calendar" +msgstr "Calendario" + +#: web/templates/public/campsite/type.gohtml:100 msgctxt "title" msgid "Features" msgstr "Características" -#: web/templates/public/campsite/type.gohtml:101 +#: web/templates/public/campsite/type.gohtml:111 msgctxt "title" msgid "Info" msgstr "Información" -#: web/templates/public/campsite/type.gohtml:105 +#: web/templates/public/campsite/type.gohtml:115 msgctxt "title" msgid "Facilities" msgstr "Equipamento" -#: web/templates/public/campsite/type.gohtml:109 +#: web/templates/public/campsite/type.gohtml:119 msgctxt "title" msgid "Description" msgstr "Descripción" +#: web/templates/public/campsite/calendar.gohtml:18 +#: web/templates/admin/season/calendar.gohtml:16 +msgctxt "day" +msgid "Mon" +msgstr "lu" + +#: web/templates/public/campsite/calendar.gohtml:19 +#: web/templates/admin/season/calendar.gohtml:17 +msgctxt "day" +msgid "Tue" +msgstr "ma" + +#: web/templates/public/campsite/calendar.gohtml:20 +#: web/templates/admin/season/calendar.gohtml:18 +msgctxt "day" +msgid "Wed" +msgstr "mi" + +#: web/templates/public/campsite/calendar.gohtml:21 +#: web/templates/admin/season/calendar.gohtml:19 +msgctxt "day" +msgid "Thu" +msgstr "ju" + +#: web/templates/public/campsite/calendar.gohtml:22 +#: web/templates/admin/season/calendar.gohtml:20 +msgctxt "day" +msgid "Fri" +msgstr "vi" + +#: web/templates/public/campsite/calendar.gohtml:23 +#: web/templates/admin/season/calendar.gohtml:21 +msgctxt "day" +msgid "Sat" +msgstr "sá" + +#: web/templates/public/campsite/calendar.gohtml:24 +#: web/templates/admin/season/calendar.gohtml:22 +msgctxt "day" +msgid "Sun" +msgstr "do" + #: web/templates/public/surroundings.gohtml:13 msgctxt "title" msgid "What to Do Outside the Campsite?" @@ -191,27 +263,140 @@ msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Te #: web/templates/public/campground.gohtml:6 #: web/templates/public/campground.gohtml:11 -#: web/templates/public/layout.gohtml:30 web/templates/public/layout.gohtml:69 +#: web/templates/public/layout.gohtml:31 web/templates/public/layout.gohtml:70 msgctxt "title" msgid "Campground" msgstr "El camping" #: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:15 -#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 +#: web/templates/public/layout.gohtml:46 web/templates/public/layout.gohtml:73 msgctxt "title" msgid "Contact" msgstr "Contacto" -#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:24 -#: web/templates/public/layout.gohtml:95 +#: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 +msgctxt "title" +msgid "Booking" +msgstr "Reserva" + +#: web/templates/public/booking.gohtml:15 +msgctxt "title" +msgid "Customer Details" +msgstr "Detalles del cliente" + +#: web/templates/public/booking.gohtml:18 +msgctxt "input" +msgid "Full name" +msgstr "Nombre y apellidos" + +#: web/templates/public/booking.gohtml:26 +msgctxt "input" +msgid "Address (optional)" +msgstr "Dirección (opcional)" + +#: web/templates/public/booking.gohtml:34 +msgctxt "input" +msgid "Postcode (optional)" +msgstr "Código postal (opcional)" + +#: web/templates/public/booking.gohtml:42 +msgctxt "input" +msgid "Town or village (optional)" +msgstr "Población (opcional)" + +#: web/templates/public/booking.gohtml:50 +#: web/templates/admin/taxDetails.gohtml:98 +msgctxt "input" +msgid "Country" +msgstr "País" + +#: web/templates/public/booking.gohtml:53 +msgid "Choose a country" +msgstr "Escoja un país" + +#: web/templates/public/booking.gohtml:60 web/templates/admin/login.gohtml:22 +#: web/templates/admin/profile.gohtml:35 +#: web/templates/admin/taxDetails.gohtml:50 +msgctxt "input" +msgid "Email" +msgstr "Correo-e" + +#: web/templates/public/booking.gohtml:68 +#: web/templates/admin/taxDetails.gohtml:42 +msgctxt "input" +msgid "Phone" +msgstr "Teléfono" + +#: web/templates/public/booking.gohtml:76 +msgctxt "title" +msgid "Party Details" +msgstr "Datos de los visitantes" + +#: web/templates/public/booking.gohtml:79 +msgctxt "input" +msgid "Adults" +msgstr "Adultos" + +#: web/templates/public/booking.gohtml:87 +msgctxt "input" +msgid "Teenagers (from 11 to 16 years old)" +msgstr "Adolescentes (de 11 a 16 años)" + +#: web/templates/public/booking.gohtml:95 +msgctxt "input" +msgid "Children (up to 10 years old)" +msgstr "Niños (hasta 10 años)" + +#: web/templates/public/booking.gohtml:103 +msgctxt "input" +msgid "Dogs" +msgstr "Perros" + +#: web/templates/public/booking.gohtml:111 +msgctxt "title" +msgid "Accomodation" +msgstr "Acomodaciones" + +#: web/templates/public/booking.gohtml:136 +msgctxt "title" +msgid "Booking Period" +msgstr "Periodo de reserva" + +#: web/templates/public/booking.gohtml:139 +msgctxt "input" +msgid "Arrival date" +msgstr "Fecha de llegada" + +#: web/templates/public/booking.gohtml:147 +msgctxt "input" +msgid "Departure date" +msgstr "Fecha de salida" + +#: web/templates/public/booking.gohtml:155 +msgctxt "input" +msgid "Area preferences (optional)" +msgstr "Preferencias de área (opcional)" + +#: web/templates/public/booking.gohtml:165 +msgctxt "input" +msgid "ACSI card? (optional)" +msgstr "¿Tarjeta ACSI? (opcional)" + +#: web/templates/public/booking.gohtml:171 +msgctxt "input" +msgid "I have read and I accept the reservation conditions" +msgstr "He leído y acepto las condiciones de reserva" + +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:25 +#: web/templates/public/layout.gohtml:96 msgid "Campsite Montagut" msgstr "Camping Montagut" -#: web/templates/public/layout.gohtml:22 web/templates/admin/layout.gohtml:18 +#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:18 msgid "Skip to main content" msgstr "Saltar al contenido principal" -#: web/templates/public/layout.gohtml:34 web/templates/public/layout.gohtml:79 +#: web/templates/public/layout.gohtml:35 web/templates/public/layout.gohtml:80 #: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/layout.gohtml:40 web/templates/admin/layout.gohtml:71 @@ -219,12 +404,12 @@ msgctxt "title" msgid "Campsites" msgstr "Alojamientos" -#: web/templates/public/layout.gohtml:66 +#: web/templates/public/layout.gohtml:67 msgctxt "title" msgid "Sections" msgstr "Apartados" -#: web/templates/public/layout.gohtml:92 +#: web/templates/public/layout.gohtml:93 msgid "RTC #%s" msgstr " RTC %s" @@ -735,52 +920,12 @@ msgstr "Color" msgid "No seasons added yet." msgstr "No se ha añadido ninguna temporada todavía." -#: web/templates/admin/season/index.gohtml:48 -msgctxt "title" -msgid "Calendar" -msgstr "Calendario" - #: web/templates/admin/season/l10n.gohtml:7 #: web/templates/admin/season/l10n.gohtml:14 msgctxt "title" msgid "Translate Season to %s" msgstr "Traducción de la temporada a %s" -#: web/templates/admin/season/calendar.gohtml:16 -msgctxt "day" -msgid "Mon" -msgstr "lu" - -#: web/templates/admin/season/calendar.gohtml:17 -msgctxt "day" -msgid "Tue" -msgstr "ma" - -#: web/templates/admin/season/calendar.gohtml:18 -msgctxt "day" -msgid "Wed" -msgstr "mi" - -#: web/templates/admin/season/calendar.gohtml:19 -msgctxt "day" -msgid "Thu" -msgstr "ju" - -#: web/templates/admin/season/calendar.gohtml:20 -msgctxt "day" -msgid "Fri" -msgstr "vi" - -#: web/templates/admin/season/calendar.gohtml:21 -msgctxt "day" -msgid "Sat" -msgstr "sá" - -#: web/templates/admin/season/calendar.gohtml:22 -msgctxt "day" -msgid "Sun" -msgstr "do" - #: web/templates/admin/season/calendar.gohtml:49 #: web/templates/admin/media/picker.gohtml:61 msgctxt "action" @@ -798,12 +943,6 @@ msgctxt "title" msgid "Login" msgstr "Entrada" -#: web/templates/admin/login.gohtml:22 web/templates/admin/profile.gohtml:35 -#: web/templates/admin/taxDetails.gohtml:50 -msgctxt "input" -msgid "Email" -msgstr "Correo-e" - #: web/templates/admin/login.gohtml:31 web/templates/admin/profile.gohtml:46 msgctxt "input" msgid "Password" @@ -916,11 +1055,6 @@ msgctxt "input" msgid "Trade Name" msgstr "Nombre comercial" -#: web/templates/admin/taxDetails.gohtml:42 -msgctxt "input" -msgid "Phone" -msgstr "Teléfono" - #: web/templates/admin/taxDetails.gohtml:66 msgctxt "input" msgid "Address" @@ -938,14 +1072,9 @@ msgstr "Provincia" #: web/templates/admin/taxDetails.gohtml:90 msgctxt "input" -msgid "Postal Code" +msgid "Postcode" msgstr "Código postal" -#: web/templates/admin/taxDetails.gohtml:98 -msgctxt "input" -msgid "Country" -msgstr "País" - #: web/templates/admin/taxDetails.gohtml:108 msgctxt "input" msgid "RTC number" @@ -1082,10 +1211,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:210 +#: pkg/booking/public.go:292 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:211 +#: pkg/booking/public.go:293 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." @@ -1106,7 +1237,7 @@ msgstr "Automático" #: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 #: pkg/campsite/types/option.go:340 pkg/campsite/types/feature.go:243 #: pkg/campsite/types/admin.go:415 pkg/season/l10n.go:69 -#: pkg/season/admin.go:382 pkg/services/l10n.go:73 pkg/services/admin.go:266 +#: pkg/season/admin.go:394 pkg/services/l10n.go:73 pkg/services/admin.go:266 msgid "Name can not be empty." msgstr "No podéis dejar el nombre en blanco." @@ -1213,7 +1344,12 @@ msgstr "El número mínimo de noches tiene que ser entero." msgid "Minimum number of nights must be one or greater." msgstr "El número mínimo de noches no puede ser cero." -#: pkg/campsite/admin.go:226 +#: pkg/campsite/types/public.go:157 +msgctxt "season" +msgid "Closed" +msgstr "Cerrado" + +#: pkg/campsite/admin.go:226 pkg/booking/public.go:321 msgid "Selected campsite type is not valid." msgstr "El tipo de alojamiento escogido no es válido." @@ -1221,96 +1357,96 @@ msgstr "El tipo de alojamiento escogido no es válido." msgid "Label can not be empty." msgstr "No podéis dejar la etiqueta en blanco." -#: pkg/season/admin.go:202 +#: pkg/season/admin.go:212 msgctxt "month" msgid "January" msgstr "enero" -#: pkg/season/admin.go:203 +#: pkg/season/admin.go:213 msgctxt "month" msgid "February" msgstr "febrero" -#: pkg/season/admin.go:204 +#: pkg/season/admin.go:214 msgctxt "month" msgid "March" msgstr "marzo" -#: pkg/season/admin.go:205 +#: pkg/season/admin.go:215 msgctxt "month" msgid "April" msgstr "abril" -#: pkg/season/admin.go:206 +#: pkg/season/admin.go:216 msgctxt "month" msgid "May" msgstr "mayo" -#: pkg/season/admin.go:207 +#: pkg/season/admin.go:217 msgctxt "month" msgid "June" msgstr "junio" -#: pkg/season/admin.go:208 +#: pkg/season/admin.go:218 msgctxt "month" msgid "July" msgstr "julio" -#: pkg/season/admin.go:209 +#: pkg/season/admin.go:219 msgctxt "month" msgid "August" msgstr "agosto" -#: pkg/season/admin.go:210 +#: pkg/season/admin.go:220 msgctxt "month" msgid "September" msgstr "septiembre" -#: pkg/season/admin.go:211 +#: pkg/season/admin.go:221 msgctxt "month" msgid "October" msgstr "octubre" -#: pkg/season/admin.go:212 +#: pkg/season/admin.go:222 msgctxt "month" msgid "November" msgstr "noviembre" -#: pkg/season/admin.go:213 +#: pkg/season/admin.go:223 msgctxt "month" msgid "December" msgstr "diciembre" -#: pkg/season/admin.go:383 +#: pkg/season/admin.go:395 msgid "Color can not be empty." msgstr "No podéis dejar el color en blanco." -#: pkg/season/admin.go:384 +#: pkg/season/admin.go:396 msgid "This color is not valid. It must be like #123abc." msgstr "Este color no es válido. Tiene que ser parecido a #123abc." -#: pkg/season/admin.go:460 +#: pkg/season/admin.go:472 msgctxt "action" msgid "Unset" msgstr "Desasignar" -#: pkg/season/admin.go:491 +#: pkg/season/admin.go:503 msgid "Start date can not be empty." msgstr "No podéis dejar la fecha de inicio en blanco." -#: pkg/season/admin.go:492 +#: pkg/season/admin.go:504 msgid "Start date must be a valid date." msgstr "La fecha de inicio tiene que ser una fecha válida." -#: pkg/season/admin.go:494 +#: pkg/season/admin.go:506 msgid "End date can not be empty." msgstr "No podéis dejar la fecha final en blanco." -#: pkg/season/admin.go:495 +#: pkg/season/admin.go:507 msgid "End date must be a valid date." msgstr "La fecha final tiene que ser una fecha válida." -#: pkg/company/admin.go:193 +#: pkg/company/admin.go:193 pkg/booking/public.go:279 msgid "Selected country is not valid." msgstr "El país escogido no es válido." @@ -1330,11 +1466,11 @@ msgstr "No podéis dejar el NIF en blanco." msgid "This VAT number is not valid." msgstr "Este NIF no es válido." -#: pkg/company/admin.go:205 +#: pkg/company/admin.go:205 pkg/booking/public.go:295 msgid "Phone can not be empty." msgstr "No podéis dejar el teléfono en blanco." -#: pkg/company/admin.go:206 +#: pkg/company/admin.go:206 pkg/booking/public.go:296 msgid "This phone number is not valid." msgstr "Este teléfono no es válido." @@ -1358,7 +1494,7 @@ msgstr "No podéis dejar la provincia en blanco." msgid "Postal code can not be empty." msgstr "No podéis dejar el código postal en blanco." -#: pkg/company/admin.go:220 +#: pkg/company/admin.go:220 pkg/booking/public.go:288 msgid "This postal code is not valid." msgstr "Este código postal no es válido." @@ -1386,6 +1522,105 @@ 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/public.go:283 +msgid "Full name can not be empty." +msgstr "No podéis dejar el nombre y los apellidos en blanco." + +#: pkg/booking/public.go:284 +msgid "Full name must have at least one letter." +msgstr "El nombre y los apellidos tienen que tener como mínimo una letra." + +#: pkg/booking/public.go:300 +msgid "Number of adults can not be empty" +msgstr "No podéis dejar el número de adultos blanco." + +#: pkg/booking/public.go:301 +msgid "Number of adults must be an integer." +msgstr "El número de adultos tiene que ser entero." + +#: pkg/booking/public.go:302 +msgid "Number of adults must be one or greater." +msgstr "El número de adultos no puede ser cero." + +#: pkg/booking/public.go:305 +msgid "Number of teenagers can not be empty" +msgstr "No podéis dejar el número de adolescentes en blanco." + +#: pkg/booking/public.go:306 +msgid "Number of teenagers must be an integer." +msgstr "El número de adolescentes tiene que ser entero." + +#: pkg/booking/public.go:307 +msgid "Number of teenagers must be zero or greater." +msgstr "El número de adolescentes tiene que ser como mínimo cero." + +#: pkg/booking/public.go:310 +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:311 +msgid "Number of children must be an integer." +msgstr "El número de niños tiene que ser entero." + +#: pkg/booking/public.go:312 +msgid "Number of children must be zero or greater." +msgstr "El número de niños tiene que ser como mínimo cero." + +#: pkg/booking/public.go:315 +msgid "Number of dogs can not be empty" +msgstr "No podéis dejar el número de perros en blanco." + +#: pkg/booking/public.go:316 +msgid "Number of dogs must be an integer." +msgstr "El número de perros tiene que ser entero." + +#: pkg/booking/public.go:317 +msgid "Number of dogs must be zero or greater." +msgstr "El número de perros tiene que ser como mínimo cero." + +#: pkg/booking/public.go:322 +msgid "Arrival date can not be empty" +msgstr "No podéis dejar la fecha de llegada en blanco." + +#: pkg/booking/public.go:323 +msgid "Arrival date must be a valid date." +msgstr "La fecha de llegada tiene que ser una fecha válida." + +#: pkg/booking/public.go:327 +msgid "Departure date can not be empty" +msgstr "No podéis dejar la fecha de partida en blanco." + +#: pkg/booking/public.go:328 +msgid "Departure date must be a valid date." +msgstr "La fecha de partida tiene que ser una fecha válida." + +#: pkg/booking/public.go:329 +msgid "The departure date must be after the arrival date." +msgstr "La fecha de partida tiene que ser posterior a la de llegada." + +#: pkg/booking/public.go:332 +msgid "It is mandatory to agree to the reservation conditions." +msgstr "Es obligatorio aceptar las condiciones de reserva." + +#: pkg/booking/public.go:335 +msgid "%s can not be empty" +msgstr "No podéis dejar %s en blanco." + +#: pkg/booking/public.go:336 +#, c-format +msgid "%s must be an integer." +msgstr "%s tiene que ser un número entero." + +#: pkg/booking/public.go:337 +#, c-format +msgid "%s must be %d or greater." +msgstr "%s tiene que ser como mínimo %d." + +#: pkg/booking/public.go:338 +#, c-format +msgid "%s must be at most %d." +msgstr "%s tiene que ser como máximo %d" + #~ msgid "%s: %s €/night" #~ msgstr "%s: %s €/noche" diff --git a/test/country.sql b/test/country.sql index 7e32160..d47b16c 100644 --- a/test/country.sql +++ b/test/country.sql @@ -11,7 +11,7 @@ set search_path to camper, public; select has_table('country'); select has_pk('country' ); -select table_privs_are('country', 'guest', array []::text[]); +select table_privs_are('country', 'guest', array ['SELECT']); select table_privs_are('country', 'employee', array ['SELECT']); select table_privs_are('country', 'admin', array ['SELECT']); select table_privs_are('country', 'authenticator', array []::text[]); diff --git a/test/country_i18n.sql b/test/country_i18n.sql index d4bba51..fe27be4 100644 --- a/test/country_i18n.sql +++ b/test/country_i18n.sql @@ -12,7 +12,7 @@ set search_path to camper, public; select has_table('country_i18n'); select has_pk('country_i18n' ); select col_is_pk('country_i18n', array['country_code', 'lang_tag']); -select table_privs_are('country_i18n', 'guest', array []::text[]); +select table_privs_are('country_i18n', 'guest', array ['SELECT']); select table_privs_are('country_i18n', 'employee', array ['SELECT']); select table_privs_are('country_i18n', 'admin', array ['SELECT']); select table_privs_are('country_i18n', 'authenticator', array []::text[]); diff --git a/web/templates/admin/taxDetails.gohtml b/web/templates/admin/taxDetails.gohtml index cd9587f..39c0c57 100644 --- a/web/templates/admin/taxDetails.gohtml +++ b/web/templates/admin/taxDetails.gohtml @@ -87,7 +87,7 @@ {{- end }} {{ with .PostalCode -}} diff --git a/web/templates/public/booking.gohtml b/web/templates/public/booking.gohtml new file mode 100644 index 0000000..48e3ec8 --- /dev/null +++ b/web/templates/public/booking.gohtml @@ -0,0 +1,179 @@ + +{{ define "title" -}} + {{( pgettext "Booking" "title" )}} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.publicPage*/ -}} +

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

+ {{ with .Form -}} +
+
+ {{( pgettext "Customer Details" "title" )}} + {{ with .FullName -}} + + {{- end }} + {{ with .Address -}} + + {{- end }} + {{ with .PostalCode -}} + + {{- end }} + {{ with .City -}} + + {{- end }} + {{ with .Country -}} + + {{- end }} + {{ with .Email -}} + + {{- end }} + {{ with .Phone -}} + + {{- end }} +
+
+ {{( pgettext "Party Details" "title" )}} + {{ with .Adults -}} + + {{- end }} + {{ with .Teenagers -}} + + {{- end }} + {{ with .Children -}} + + {{- end }} + {{ with .Dogs -}} + + {{- end }} +
+
+ {{( pgettext "Accomodation" "title" )}} + {{ range .CampsiteType.Options -}} +
+ {{- end }} +
+ {{ range .CampsiteType.Options -}} + {{ $options := index $.Form.CampsiteTypeOptions .Value }} + {{ if $options -}} +
+ {{ .Label }} + {{ range $options -}} + + {{- end }} +
+ {{- end }} + {{- end }} +
+ {{( pgettext "Booking Period" "title" )}} + {{ with .ArrivalDate -}} + + {{- end }} + {{ with .DepartureDate -}} + + {{- end }} + {{ with .AreaPreferences -}} + + {{- end }} + {{ with .ACSICard -}} +
+ {{- end }} + {{ with .Agreement -}} +
+ {{- end }} +
+
+ +
+
+ {{- end }} +{{- end }} diff --git a/web/templates/public/payment/failure.gohtml b/web/templates/public/payment/failure.gohtml new file mode 100644 index 0000000..1c42b9c --- /dev/null +++ b/web/templates/public/payment/failure.gohtml @@ -0,0 +1,12 @@ + +{{ define "title" -}} + {{( pgettext "Payment Failed" "title" )}} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}} +

{{( pgettext "Payment Failed" "title" )}}

+{{- end }} diff --git a/web/templates/public/payment/request.gohtml b/web/templates/public/payment/request.gohtml new file mode 100644 index 0000000..38bfd5c --- /dev/null +++ b/web/templates/public/payment/request.gohtml @@ -0,0 +1,20 @@ + +{{ define "title" -}} + {{( pgettext "Payment" "title" )}} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.paymentPage*/ -}} +

{{( pgettext "Payment" "title" )}}

+ {{ with .Request -}} +
+ + + + +
+ {{- end }} +{{- end }} diff --git a/web/templates/public/payment/success.gohtml b/web/templates/public/payment/success.gohtml new file mode 100644 index 0000000..753b889 --- /dev/null +++ b/web/templates/public/payment/success.gohtml @@ -0,0 +1,12 @@ + +{{ define "title" -}} + {{( pgettext "Payment Successful" "title" )}} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}} +

{{( pgettext "Payment Successful" "title" )}}

+{{- end }}