Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single page instead of split into many pages; possibly each <fieldset> should be in a separate page/view. The idea is for Oriol to check the design and decide how it would be presented to the user, so i needed something to show him first. I hardcoded the **test** data for the customer’s Redsys account. Is this bad? I hope not, but i am not really, really sure. The data sent to Redsys is just a placeholder because there are booking details that i do not know, like what i have to do with the “teenagers” field or the area preferences, thus i can not yet have a booking relation. Nevertheless, had to generate a random order number up to 12-chars in length or Redsys would refuse the payment, claiming that the order is duplicated. The Redsys package is based on the PHP code provided by Redsys themselves, plus some hints at the implementations from various Go packages that did not know why they were so complicated. Had to grant select on table country to guest in order to show the select with the country options. I have changed the “Postal code” input in taxDetails for “Postcode” because this is the spell that it is used in the current web, i did not see a reason to change it—it is an accepted form—, and i did not want to have inconsistencies between forms.
This commit is contained in:
parent
96fb253354
commit
302ce29e4a
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
||||
* 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)
|
||||
}
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
||||
* 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
||||
* 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
|
||||
}
|
448
po/ca.po
448
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 <jordi@tandem.blog>\n"
|
||||
"Language-Team: Catalan <ca@dodds.net>\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 "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
|
||||
msgstr "<abbr title=\"Número\">Núm.</abbr> <abbr title=\"Registre de Turisme de Catalunya\">RTC</abbr> %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"
|
||||
|
||||
|
|
447
po/es.po
447
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 <jordi@tandem.blog>\n"
|
||||
"Language-Team: Spanish <es@tp.org.es>\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 "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
|
||||
msgstr "<abbr title=\"Número\">Nº</abbr> <abbr title=\"Registro de Turismo de Cataluña\">RTC</abbr> %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"
|
||||
|
||||
|
|
|
@ -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[]);
|
||||
|
|
|
@ -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[]);
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
{{- end }}
|
||||
{{ with .PostalCode -}}
|
||||
<label>
|
||||
{{( pgettext "Postal Code" "input")}}<br>
|
||||
{{( pgettext "Postcode" "input")}}<br>
|
||||
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
|
||||
required autocomplete="postal-code" {{ template "error-attrs" . }}><br>
|
||||
</label>
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Booking" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.publicPage*/ -}}
|
||||
<h2>{{( pgettext "Booking" "title" )}}</h2>
|
||||
{{ with .Form -}}
|
||||
<form action="/{{ currentLocale }}/booking" method="post">
|
||||
<fieldset>
|
||||
<legend>{{( pgettext "Customer Details" "title" )}}</legend>
|
||||
{{ with .FullName -}}
|
||||
<label>
|
||||
{{( pgettext "Full name" "input" )}}<br>
|
||||
<input type="text" required autocomplete="name" minlength="2"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Address -}}
|
||||
<label>
|
||||
{{( pgettext "Address (optional)" "input" )}}<br>
|
||||
<input type="text" autocomplete="billing street-address"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .PostalCode -}}
|
||||
<label>
|
||||
{{( pgettext "Postcode (optional)" "input" )}}<br>
|
||||
<input type="text" autocomplete="billing postal-code"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .City -}}
|
||||
<label>
|
||||
{{( pgettext "Town or village (optional)" "input" )}}<br>
|
||||
<input type="text"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Country -}}
|
||||
<label>
|
||||
{{( pgettext "Country" "input" )}}<br>
|
||||
<select name="{{ .Name }}"
|
||||
required autocomplete="country">
|
||||
<option>{{( gettext "Choose a country" )}}</option>
|
||||
{{ template "error-attrs" . }}>{{ template "list-options" . }}
|
||||
</select><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Email -}}
|
||||
<label>
|
||||
{{( pgettext "Email" "input" )}}<br>
|
||||
<input type="email" required autocomplete="email"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Phone -}}
|
||||
<label>
|
||||
{{( pgettext "Phone" "input" )}}<br>
|
||||
<input type="tel" required autocomplete="tel"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{( pgettext "Party Details" "title" )}}</legend>
|
||||
{{ with .Adults -}}
|
||||
<label>
|
||||
{{( pgettext "Adults" "input" )}}<br>
|
||||
<input type="number" required min="1"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Teenagers -}}
|
||||
<label>
|
||||
{{( pgettext "Teenagers (from 11 to 16 years old)" "input" )}}<br>
|
||||
<input type="number" required min="0"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Children -}}
|
||||
<label>
|
||||
{{( pgettext "Children (up to 10 years old)" "input" )}}<br>
|
||||
<input type="number" required min="0"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .Dogs -}}
|
||||
<label>
|
||||
{{( pgettext "Dogs" "input" )}}<br>
|
||||
<input type="number" required min="0"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{( pgettext "Accomodation" "title" )}}</legend>
|
||||
{{ range .CampsiteType.Options -}}
|
||||
<label><input type="radio" name="{{ $.Form.CampsiteType.Name }}" value="{{ .Value }}"
|
||||
> {{ .Label }}</label><br>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
{{ range .CampsiteType.Options -}}
|
||||
{{ $options := index $.Form.CampsiteTypeOptions .Value }}
|
||||
{{ if $options -}}
|
||||
<fieldset>
|
||||
<legend>{{ .Label }}</legend>
|
||||
{{ range $options -}}
|
||||
<label>
|
||||
{{ .Label }}<br>
|
||||
<input type="number" required
|
||||
name="{{ .Input.Name }}" value="{{ .Input.Val }}"
|
||||
min="{{ .Min }}" max="{{ .Max }}"
|
||||
{{ template "error-attrs" .Input }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
<fieldset>
|
||||
<legend>{{( pgettext "Booking Period" "title" )}}</legend>
|
||||
{{ with .ArrivalDate -}}
|
||||
<label>
|
||||
{{( pgettext "Arrival date" "input" )}}<br>
|
||||
<input type="date" required
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .DepartureDate -}}
|
||||
<label>
|
||||
{{( pgettext "Departure date" "input" )}}<br>
|
||||
<input type="date" required
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .AreaPreferences -}}
|
||||
<label>
|
||||
{{( pgettext "Area preferences (optional)" "input" )}}<br>
|
||||
<input type="text"
|
||||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||||
><br>
|
||||
</label>
|
||||
{{- end }}
|
||||
{{ with .ACSICard -}}
|
||||
<label>
|
||||
<input type="checkbox" name="{{ .Name }}" {{ if .Checked}}checked{{ end }}
|
||||
{{ template "error-attrs" . }}
|
||||
> {{( pgettext "ACSI card? (optional)" "input" )}}</label><br>
|
||||
{{- end }}
|
||||
{{ with .Agreement -}}
|
||||
<label>
|
||||
<input type="checkbox" required name="{{ .Name }}" {{ if .Checked}}checked{{ end }}
|
||||
{{ template "error-attrs" . }}
|
||||
> {{( pgettext "I have read and I accept the reservation conditions" "input" )}}</label><br>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
<footer>
|
||||
<button type="submit">{{( pgettext "Book" "action" )}} <span>→</span></button>
|
||||
</footer>
|
||||
</form>
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Payment Failed" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}}
|
||||
<h2>{{( pgettext "Payment Failed" "title" )}}</h2>
|
||||
{{- end }}
|
|
@ -0,0 +1,20 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Payment" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.paymentPage*/ -}}
|
||||
<h2>{{( pgettext "Payment" "title" )}}</h2>
|
||||
{{ with .Request -}}
|
||||
<form action="https://sis-t.redsys.es:25443/sis/realizarPago" method="post">
|
||||
<input type="hidden" name="Ds_MerchantParameters" value="{{ .MerchantParameters }}"/>
|
||||
<input type="hidden" name="Ds_Signature" value="{{ .Signature }}"/>
|
||||
<input type="hidden" name="Ds_SignatureVersion" value="{{ .SignatureVersion }}"/>
|
||||
<button type="submit">{{( pgettext "Pay" "action" )}}</button>
|
||||
</form>
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,12 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Payment Successful" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}}
|
||||
<h2>{{( pgettext "Payment Successful" "title" )}}</h2>
|
||||
{{- end }}
|
Loading…
Reference in New Issue