Add ready_payment function and use their slug as URL
Now that the payments have slug, i can use them in the URL to show the actual data of a payment, and kickstart the payment process with Redsys.
This commit is contained in:
parent
148d9075da
commit
15dde3f491
|
@ -19,10 +19,11 @@ create table payment_customer (
|
||||||
country_code country_code not null references country,
|
country_code country_code not null references country,
|
||||||
email email not null,
|
email email not null,
|
||||||
phone packed_phone_number not null,
|
phone packed_phone_number not null,
|
||||||
acsi_card boolean not null
|
acsi_card boolean not null,
|
||||||
|
lang_tag text not null references language
|
||||||
);
|
);
|
||||||
|
|
||||||
grant select, insert on table payment_customer to guest;
|
grant select, insert, update on table payment_customer to guest;
|
||||||
grant select, insert, update on table payment_customer to employee;
|
grant select, insert, update on table payment_customer to employee;
|
||||||
grant select, insert, update, delete on table payment_customer to admin;
|
grant select, insert, update, delete on table payment_customer to admin;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
-- Deploy camper:ready_payment to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_camper
|
||||||
|
-- requires: payment
|
||||||
|
-- requires: payment_customer
|
||||||
|
-- requires: country_code
|
||||||
|
-- requires: email
|
||||||
|
-- requires: extension_pg_libphonenumber
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to camper, public;
|
||||||
|
|
||||||
|
create or replace function ready_payment(payment_slug uuid, customer_name text, customer_address text, customer_post_code text, customer_city text, customer_country_code country_code, customer_email email, customer_phone text, customer_lang_tag text, customer_acsi_card boolean) returns integer as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
pid integer;
|
||||||
|
begin
|
||||||
|
update payment
|
||||||
|
set payment_status = 'pending'
|
||||||
|
, updated_at = current_timestamp
|
||||||
|
where slug = payment_slug
|
||||||
|
and payment_status = 'draft'
|
||||||
|
returning payment_id into pid
|
||||||
|
;
|
||||||
|
|
||||||
|
if pid is null then
|
||||||
|
raise check_violation using message = 'insert or update on table "payment" violates check constraint "payment_is_draft"';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
insert into payment_customer (payment_id, full_name, address, postal_code, city, country_code, email, phone, acsi_card, lang_tag)
|
||||||
|
values (pid, customer_name, customer_address, customer_post_code, customer_city, customer_country_code, customer_email, parse_packed_phone_number(customer_phone, customer_country_code), customer_acsi_card, customer_lang_tag)
|
||||||
|
on conflict (payment_id) do update
|
||||||
|
set full_name = excluded.full_name
|
||||||
|
, address = excluded.address
|
||||||
|
, postal_code = excluded.postal_code
|
||||||
|
, city = excluded.city
|
||||||
|
, country_code = excluded.country_code
|
||||||
|
, email = excluded.email
|
||||||
|
, phone = excluded.phone
|
||||||
|
, acsi_card = excluded.acsi_card
|
||||||
|
, lang_tag = excluded.lang_tag
|
||||||
|
;
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
end;
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function ready_payment(uuid, text, text, text, text, country_code, email, text, text, boolean) from public;
|
||||||
|
grant execute on function ready_payment(uuid, text, text, text, text, country_code, email, text, text, boolean) to guest;
|
||||||
|
grant execute on function ready_payment(uuid, text, text, text, text, country_code, email, text, text, boolean) to employee;
|
||||||
|
grant execute on function ready_payment(uuid, text, text, text, text, country_code, email, text, text, boolean) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -17,6 +17,7 @@ import (
|
||||||
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/legal"
|
"dev.tandem.ws/tandem/camper/pkg/legal"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/location"
|
"dev.tandem.ws/tandem/camper/pkg/location"
|
||||||
|
"dev.tandem.ws/tandem/camper/pkg/payment"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/services"
|
"dev.tandem.ws/tandem/camper/pkg/services"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/surroundings"
|
"dev.tandem.ws/tandem/camper/pkg/surroundings"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/template"
|
"dev.tandem.ws/tandem/camper/pkg/template"
|
||||||
|
@ -29,6 +30,7 @@ type publicHandler struct {
|
||||||
campsite *campsite.PublicHandler
|
campsite *campsite.PublicHandler
|
||||||
legal *legal.PublicHandler
|
legal *legal.PublicHandler
|
||||||
location *location.PublicHandler
|
location *location.PublicHandler
|
||||||
|
payment *payment.PublicHandler
|
||||||
services *services.PublicHandler
|
services *services.PublicHandler
|
||||||
surroundings *surroundings.PublicHandler
|
surroundings *surroundings.PublicHandler
|
||||||
}
|
}
|
||||||
|
@ -41,6 +43,7 @@ func newPublicHandler() *publicHandler {
|
||||||
campsite: campsite.NewPublicHandler(),
|
campsite: campsite.NewPublicHandler(),
|
||||||
legal: legal.NewPublicHandler(),
|
legal: legal.NewPublicHandler(),
|
||||||
location: location.NewPublicHandler(),
|
location: location.NewPublicHandler(),
|
||||||
|
payment: payment.NewPublicHandler(),
|
||||||
services: services.NewPublicHandler(),
|
services: services.NewPublicHandler(),
|
||||||
surroundings: surroundings.NewPublicHandler(),
|
surroundings: surroundings.NewPublicHandler(),
|
||||||
}
|
}
|
||||||
|
@ -65,6 +68,8 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da
|
||||||
h.legal.Handler(user, company, conn).ServeHTTP(w, r)
|
h.legal.Handler(user, company, conn).ServeHTTP(w, r)
|
||||||
case "location":
|
case "location":
|
||||||
h.location.Handler(user, company, conn).ServeHTTP(w, r)
|
h.location.Handler(user, company, conn).ServeHTTP(w, r)
|
||||||
|
case "payments":
|
||||||
|
h.payment.Handler(user, company, conn).ServeHTTP(w, r)
|
||||||
case "services":
|
case "services":
|
||||||
h.services.Handler(user, company, conn).ServeHTTP(w, r)
|
h.services.Handler(user, company, conn).ServeHTTP(w, r)
|
||||||
case "surroundings":
|
case "surroundings":
|
||||||
|
|
|
@ -6,98 +6,46 @@
|
||||||
package booking
|
package booking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"dev.tandem.ws/tandem/camper/pkg/auth"
|
"dev.tandem.ws/tandem/camper/pkg/auth"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/database"
|
"dev.tandem.ws/tandem/camper/pkg/database"
|
||||||
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
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 {
|
func requestPayment(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
|
||||||
*template.PublicPage
|
f, err := newBookingForm(r, company, conn, user.Locale)
|
||||||
Environment string
|
if err != nil {
|
||||||
Request *redsys.SignedRequest
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPaymentPage(request *redsys.SignedRequest) *paymentPage {
|
_, err = conn.ReadyPayment(
|
||||||
return &paymentPage{
|
r.Context(),
|
||||||
PublicPage: template.NewPublicPage(),
|
f.PaymentSlug.Val,
|
||||||
Request: request,
|
f.Customer.FullName.Val,
|
||||||
}
|
f.Customer.Address.Val,
|
||||||
}
|
f.Customer.PostalCode.Val,
|
||||||
|
f.Customer.City.Val,
|
||||||
func (p *paymentPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
|
f.Customer.Country.String(),
|
||||||
p.Setup(r, user, company, conn)
|
f.Customer.Email.Val,
|
||||||
if err := conn.QueryRow(r.Context(), "select environment from redsys where company_id = $1", company.ID).Scan(&p.Environment); err != nil && !database.ErrorIsNotFound(err) {
|
f.Customer.Phone.Val,
|
||||||
|
user.Locale.Language,
|
||||||
|
f.Customer.ACSICard.Checked,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
template.MustRenderPublic(w, r, user, company, "payment/request.gohtml", p)
|
httplib.Redirect(w, r, fmt.Sprintf("/%s/payments/%s", user.Locale.Language, f.PaymentSlug.Val), http.StatusSeeOther)
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ package booking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -20,7 +18,6 @@ import (
|
||||||
"dev.tandem.ws/tandem/camper/pkg/form"
|
"dev.tandem.ws/tandem/camper/pkg/form"
|
||||||
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/locale"
|
"dev.tandem.ws/tandem/camper/pkg/locale"
|
||||||
"dev.tandem.ws/tandem/camper/pkg/redsys"
|
|
||||||
"dev.tandem.ws/tandem/camper/pkg/template"
|
"dev.tandem.ws/tandem/camper/pkg/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,66 +44,16 @@ func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *da
|
||||||
}
|
}
|
||||||
page.MustRender(w, r, user, company, conn)
|
page.MustRender(w, r, user, company, conn)
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
makeReservation(w, r, user, company, conn)
|
requestPayment(w, r, user, company, conn)
|
||||||
default:
|
default:
|
||||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost)
|
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:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeReservation(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
|
|
||||||
f, err := newBookingForm(r, company, conn, user.Locale)
|
|
||||||
if 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
|
|
||||||
}
|
|
||||||
|
|
||||||
schema := httplib.Protocol(r)
|
|
||||||
authority := httplib.Host(r)
|
|
||||||
baseURL := fmt.Sprintf("%s://%s/%s/booking", schema, authority, user.Locale.Language)
|
|
||||||
request := &redsys.Request{
|
|
||||||
TransactionType: redsys.TransactionTypeCharge,
|
|
||||||
Amount: f.Cart.Total,
|
|
||||||
OrderNumber: randomOrderNumber(),
|
|
||||||
Product: "Test Booking",
|
|
||||||
SuccessURL: fmt.Sprintf("%s/success", baseURL),
|
|
||||||
FailureURL: fmt.Sprintf("%s/failure", baseURL),
|
|
||||||
NotificationURL: fmt.Sprintf("%s/notification", baseURL),
|
|
||||||
ConsumerLanguage: user.Locale.Language,
|
|
||||||
}
|
|
||||||
signed, err := redsys.SignRequest(r.Context(), conn, company, 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 {
|
type publicPage struct {
|
||||||
*template.PublicPage
|
*template.PublicPage
|
||||||
Form *bookingForm
|
Form *bookingForm
|
||||||
|
@ -272,6 +219,9 @@ func (f *bookingForm) Valid(ctx context.Context, conn *database.Conn, l *locale.
|
||||||
if f.Customer == nil {
|
if f.Customer == nil {
|
||||||
return false, errors.New("no customer fields")
|
return false, errors.New("no customer fields")
|
||||||
}
|
}
|
||||||
|
if f.Cart == nil {
|
||||||
|
return false, errors.New("no booking cart")
|
||||||
|
}
|
||||||
|
|
||||||
v.CheckSelectedOptions(f.CampsiteType, l.GettextNoop("Selected campsite type is not valid."))
|
v.CheckSelectedOptions(f.CampsiteType, l.GettextNoop("Selected campsite type is not valid."))
|
||||||
f.Dates.Valid(v, l)
|
f.Dates.Valid(v, l)
|
||||||
|
|
|
@ -357,3 +357,7 @@ func (c *Conn) DraftPayment(ctx context.Context, paymentSlug string, arrivalDate
|
||||||
}
|
}
|
||||||
return c.GetText(ctx, "select draft_payment($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", paymentSlugParam, arrivalDate, departureDate, campsiteTypeSlug, numAdults, numTeenagers, numChildren, numDogs, zonePreferences, options)
|
return c.GetText(ctx, "select draft_payment($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", paymentSlugParam, arrivalDate, departureDate, campsiteTypeSlug, numAdults, numTeenagers, numChildren, numDogs, zonePreferences, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) ReadyPayment(ctx context.Context, paymentSlug string, customerName string, customerAddress string, customerPostCode string, customerCity string, customerCountryCode string, customerEmail string, customerPhone string, customerLangTag language.Tag, acsiCard bool) (int, error) {
|
||||||
|
return c.GetInt(ctx, "select ready_payment($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", paymentSlug, customerName, customerAddress, customerPostCode, customerCity, customerCountryCode, customerEmail, customerPhone, customerLangTag, acsiCard)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
package payment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
"dev.tandem.ws/tandem/camper/pkg/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 paymentSlug string
|
||||||
|
paymentSlug, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||||
|
|
||||||
|
if !uuid.Valid(paymentSlug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payment, err := fetchPayment(r.Context(), conn, paymentSlug)
|
||||||
|
if err != nil {
|
||||||
|
if database.ErrorIsNotFound(err) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var head string
|
||||||
|
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||||
|
switch head {
|
||||||
|
case "":
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
page := newPaymentPage(payment)
|
||||||
|
page.MustRender(w, r, user, company, conn)
|
||||||
|
default:
|
||||||
|
httplib.MethodNotAllowed(w, r, http.MethodGet)
|
||||||
|
}
|
||||||
|
case "success":
|
||||||
|
handleSuccessfulPayment(w, r, user, company, conn, payment)
|
||||||
|
case "failure":
|
||||||
|
handleFailedPayment(w, r, user, company, conn, payment)
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchPayment(ctx context.Context, conn *database.Conn, paymentSlug string) (*Payment, error) {
|
||||||
|
row := conn.QueryRow(ctx, `
|
||||||
|
select payment_id
|
||||||
|
, payment.slug::text
|
||||||
|
, payment.created_at
|
||||||
|
, to_price(total, decimal_digits)
|
||||||
|
from payment
|
||||||
|
join company using (company_id)
|
||||||
|
join currency using (currency_code)
|
||||||
|
where payment.slug = $1
|
||||||
|
and payment_status <> 'draft'
|
||||||
|
`, paymentSlug)
|
||||||
|
payment := &Payment{}
|
||||||
|
if err := row.Scan(&payment.ID, &payment.Slug, &payment.CreateTime, &payment.Total); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return payment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Payment struct {
|
||||||
|
ID int
|
||||||
|
Slug string
|
||||||
|
Total string
|
||||||
|
CreateTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (payment *Payment) createRequest(r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) (*redsys.SignedRequest, error) {
|
||||||
|
schema := httplib.Protocol(r)
|
||||||
|
authority := httplib.Host(r)
|
||||||
|
baseURL := fmt.Sprintf("%s://%s/%s/payments/%s", schema, authority, user.Locale.Language, payment.Slug)
|
||||||
|
request := &redsys.Request{
|
||||||
|
TransactionType: redsys.TransactionTypeCharge,
|
||||||
|
Amount: payment.Total,
|
||||||
|
OrderNumber: payment.OrderNumber(),
|
||||||
|
Product: user.Locale.Pgettext("Campsite Booking", "order product name"),
|
||||||
|
SuccessURL: fmt.Sprintf("%s/success", baseURL),
|
||||||
|
FailureURL: fmt.Sprintf("%s/failure", baseURL),
|
||||||
|
NotificationURL: fmt.Sprintf("%s/notification", baseURL),
|
||||||
|
ConsumerLanguage: user.Locale.Language,
|
||||||
|
}
|
||||||
|
return redsys.SignRequest(r.Context(), conn, company, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (payment *Payment) OrderNumber() string {
|
||||||
|
return fmt.Sprintf("%08d%s", payment.ID, payment.Slug[:4])
|
||||||
|
}
|
||||||
|
|
||||||
|
type paymentPage struct {
|
||||||
|
*template.PublicPage
|
||||||
|
Environment string
|
||||||
|
Payment *Payment
|
||||||
|
Request *redsys.SignedRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPaymentPage(payment *Payment) *paymentPage {
|
||||||
|
return &paymentPage{
|
||||||
|
PublicPage: template.NewPublicPage(),
|
||||||
|
Payment: payment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
request, err := p.Payment.createRequest(r, user, company, conn)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
p.Request = request
|
||||||
|
if err := conn.QueryRow(r.Context(), "select environment from redsys where company_id = $1", company.ID).Scan(&p.Environment); err != nil && !database.ErrorIsNotFound(err) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
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, payment *Payment) {
|
||||||
|
var head string
|
||||||
|
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||||
|
|
||||||
|
switch head {
|
||||||
|
case "":
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
page := newSuccessfulPaymentPage(payment)
|
||||||
|
page.MustRender(w, r, user, company, conn)
|
||||||
|
default:
|
||||||
|
httplib.MethodNotAllowed(w, r, http.MethodGet)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type successfulPaymentPage struct {
|
||||||
|
*template.PublicPage
|
||||||
|
Payment *Payment
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSuccessfulPaymentPage(payment *Payment) *successfulPaymentPage {
|
||||||
|
return &successfulPaymentPage{
|
||||||
|
PublicPage: template.NewPublicPage(),
|
||||||
|
Payment: payment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.MustRenderPublicFiles(w, r, user, company, p, "payment/success.gohtml", "payment/details.gohtml")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleFailedPayment(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, payment *Payment) {
|
||||||
|
var head string
|
||||||
|
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||||
|
|
||||||
|
switch head {
|
||||||
|
case "":
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
page := newFailedPaymentPage(payment)
|
||||||
|
page.MustRender(w, r, user, company, conn)
|
||||||
|
default:
|
||||||
|
httplib.MethodNotAllowed(w, r, http.MethodGet)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type failedPaymentPage struct {
|
||||||
|
*template.PublicPage
|
||||||
|
Payment *Payment
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFailedPaymentPage(payment *Payment) *failedPaymentPage {
|
||||||
|
return &failedPaymentPage{
|
||||||
|
PublicPage: template.NewPublicPage(),
|
||||||
|
Payment: payment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.MustRenderPublicFiles(w, r, user, company, p, "payment/failure.gohtml", "payment/details.gohtml")
|
||||||
|
}
|
135
po/ca.po
135
po/ca.po
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: camper\n"
|
"Project-Id-Version: camper\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||||
"POT-Creation-Date: 2024-02-12 05:10+0100\n"
|
"POT-Creation-Date: 2024-02-12 17:49+0100\n"
|
||||||
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
|
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Catalan <ca@dodds.net>\n"
|
"Language-Team: Catalan <ca@dodds.net>\n"
|
||||||
|
@ -60,28 +60,56 @@ msgid "Zone 1"
|
||||||
msgstr "Zona 1"
|
msgstr "Zona 1"
|
||||||
|
|
||||||
#: web/templates/public/payment/success.gohtml:6
|
#: web/templates/public/payment/success.gohtml:6
|
||||||
#: web/templates/public/payment/success.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Successful"
|
msgid "Payment Successful"
|
||||||
msgstr "Pagament amb èxit"
|
msgstr "Pagament amb èxit"
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:6
|
#: web/templates/public/payment/success.gohtml:12
|
||||||
#: web/templates/public/payment/request.gohtml:11
|
msgid "We have received the payment. Thank you."
|
||||||
msgctxt "title"
|
msgstr "Hem rebut el vostre pagament. Gràcies."
|
||||||
msgid "Payment"
|
|
||||||
msgstr "Pagament"
|
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:23
|
#: web/templates/public/payment/request.gohtml:6
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Booking Payment"
|
||||||
|
msgstr "Pagament de la reserva"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:18
|
||||||
|
msgid "Thank you for your booking. Please, click the button below to pay with a credit card via Servired/Redsys."
|
||||||
|
msgstr "Gràcies per la vostra reserva. Feu clic al botó de sota per pagar amb targeta de crèdit via Servired/Redsys."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:27
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Pay"
|
msgid "Pay with credit card"
|
||||||
msgstr "Paga"
|
msgstr "Paga amb targeta de crèdit"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:30
|
||||||
|
msgid "Please, wait until we redirect you to the payment page."
|
||||||
|
msgstr "Espereu mentre us enviem a la pàgina de pagament."
|
||||||
|
|
||||||
#: web/templates/public/payment/failure.gohtml:6
|
#: web/templates/public/payment/failure.gohtml:6
|
||||||
#: web/templates/public/payment/failure.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Failed"
|
msgid "Payment Failed"
|
||||||
msgstr "Ha fallat el pagament"
|
msgstr "Ha fallat el pagament"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/failure.gohtml:12
|
||||||
|
msgid "We could not process the payment. Please, contact us for support."
|
||||||
|
msgstr "No hem pogut processar el pagament. Poseu-vos en contacte amb nosaltres per solucionar el problema."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:4
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Order Number"
|
||||||
|
msgstr "Número de comanda"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:8
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "Data"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Total"
|
||||||
|
msgstr "Total"
|
||||||
|
|
||||||
#: web/templates/public/services.gohtml:7
|
#: web/templates/public/services.gohtml:7
|
||||||
#: web/templates/public/services.gohtml:16
|
#: web/templates/public/services.gohtml:16
|
||||||
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
||||||
|
@ -1951,6 +1979,11 @@ msgstr "Estat"
|
||||||
msgid "No booking found."
|
msgid "No booking found."
|
||||||
msgstr "No s’ha trobat cap reserva."
|
msgstr "No s’ha trobat cap reserva."
|
||||||
|
|
||||||
|
#: pkg/payment/public.go:97
|
||||||
|
msgctxt "order product name"
|
||||||
|
msgid "Campsite Booking"
|
||||||
|
msgstr "Reserva de càmping"
|
||||||
|
|
||||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
||||||
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
||||||
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
||||||
|
@ -1990,12 +2023,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."
|
msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge."
|
||||||
|
|
||||||
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
||||||
#: pkg/booking/public.go:583
|
#: pkg/booking/public.go:533
|
||||||
msgid "Email can not be empty."
|
msgid "Email can not be empty."
|
||||||
msgstr "No podeu deixar el correu-e en blanc."
|
msgstr "No podeu deixar el correu-e en blanc."
|
||||||
|
|
||||||
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
||||||
#: pkg/booking/public.go:584
|
#: pkg/booking/public.go:534
|
||||||
msgid "This email is not valid. It should be like name@domain.com."
|
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."
|
msgstr "Aquest correu-e no és vàlid. Hauria de ser similar a nom@domini.com."
|
||||||
|
|
||||||
|
@ -2206,8 +2239,8 @@ msgctxt "header"
|
||||||
msgid "Children (aged 2 to 10)"
|
msgid "Children (aged 2 to 10)"
|
||||||
msgstr "Mainada (entre 2 i 10 anys)"
|
msgstr "Mainada (entre 2 i 10 anys)"
|
||||||
|
|
||||||
#: pkg/campsite/admin.go:275 pkg/booking/public.go:224
|
#: pkg/campsite/admin.go:275 pkg/booking/public.go:171
|
||||||
#: pkg/booking/public.go:276
|
#: pkg/booking/public.go:226
|
||||||
msgid "Selected campsite type is not valid."
|
msgid "Selected campsite type is not valid."
|
||||||
msgstr "El tipus d’allotjament escollit no és vàlid."
|
msgstr "El tipus d’allotjament escollit no és vàlid."
|
||||||
|
|
||||||
|
@ -2363,7 +2396,7 @@ msgstr "No podeu deixar l’adreça de l’enllaç en blanc."
|
||||||
msgid "This web address is not valid. It should be like https://domain.com/."
|
msgid "This web address is not valid. It should be like https://domain.com/."
|
||||||
msgstr "Aquesta adreça web no és vàlida. Hauria de ser similar a https://domini.com/."
|
msgstr "Aquesta adreça web no és vàlida. Hauria de ser similar a https://domini.com/."
|
||||||
|
|
||||||
#: pkg/company/admin.go:200 pkg/booking/public.go:570
|
#: pkg/company/admin.go:200 pkg/booking/public.go:520
|
||||||
msgid "Selected country is not valid."
|
msgid "Selected country is not valid."
|
||||||
msgstr "El país escollit no és vàlid."
|
msgstr "El país escollit no és vàlid."
|
||||||
|
|
||||||
|
@ -2383,11 +2416,11 @@ msgstr "No podeu deixar el NIF en blanc."
|
||||||
msgid "This VAT number is not valid."
|
msgid "This VAT number is not valid."
|
||||||
msgstr "Aquest NIF no és vàlid."
|
msgstr "Aquest NIF no és vàlid."
|
||||||
|
|
||||||
#: pkg/company/admin.go:212 pkg/booking/public.go:586
|
#: pkg/company/admin.go:212 pkg/booking/public.go:536
|
||||||
msgid "Phone can not be empty."
|
msgid "Phone can not be empty."
|
||||||
msgstr "No podeu deixar el telèfon en blanc."
|
msgstr "No podeu deixar el telèfon en blanc."
|
||||||
|
|
||||||
#: pkg/company/admin.go:213 pkg/booking/public.go:587
|
#: pkg/company/admin.go:213 pkg/booking/public.go:537
|
||||||
msgid "This phone number is not valid."
|
msgid "This phone number is not valid."
|
||||||
msgstr "Aquest número de telèfon no és vàlid."
|
msgstr "Aquest número de telèfon no és vàlid."
|
||||||
|
|
||||||
|
@ -2407,7 +2440,7 @@ msgstr "No podeu deixar la província en blanc."
|
||||||
msgid "Postal code can not be empty."
|
msgid "Postal code can not be empty."
|
||||||
msgstr "No podeu deixar el codi postal en blanc."
|
msgstr "No podeu deixar el codi postal en blanc."
|
||||||
|
|
||||||
#: pkg/company/admin.go:227 pkg/booking/public.go:579
|
#: pkg/company/admin.go:227 pkg/booking/public.go:529
|
||||||
msgid "This postal code is not valid."
|
msgid "This postal code is not valid."
|
||||||
msgstr "Aquest codi postal no és vàlid."
|
msgstr "Aquest codi postal no és vàlid."
|
||||||
|
|
||||||
|
@ -2534,127 +2567,135 @@ msgstr "La integració escollida no és vàlida."
|
||||||
msgid "The merchant key is not valid."
|
msgid "The merchant key is not valid."
|
||||||
msgstr "Aquesta clau del comerç no és vàlid."
|
msgstr "Aquesta clau del comerç no és vàlid."
|
||||||
|
|
||||||
#: pkg/booking/public.go:325 pkg/booking/public.go:354
|
#: pkg/booking/public.go:275 pkg/booking/public.go:304
|
||||||
msgid "Arrival date must be a valid date."
|
msgid "Arrival date must be a valid date."
|
||||||
msgstr "La data d’arribada ha de ser una data vàlida."
|
msgstr "La data d’arribada ha de ser una data vàlida."
|
||||||
|
|
||||||
#: pkg/booking/public.go:339 pkg/booking/public.go:361
|
#: pkg/booking/public.go:289 pkg/booking/public.go:311
|
||||||
msgid "Departure date must be a valid date."
|
msgid "Departure date must be a valid date."
|
||||||
msgstr "La data de sortida ha de ser una data vàlida."
|
msgstr "La data de sortida ha de ser una data vàlida."
|
||||||
|
|
||||||
#: pkg/booking/public.go:353
|
#: pkg/booking/public.go:303
|
||||||
msgid "Arrival date can not be empty"
|
msgid "Arrival date can not be empty"
|
||||||
msgstr "No podeu deixar la data d’arribada en blanc."
|
msgstr "No podeu deixar la data d’arribada en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:355
|
#: pkg/booking/public.go:305
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or after."
|
msgid "Arrival date must be %s or after."
|
||||||
msgstr "La data d’arribada ha de ser igual o posterior a %s."
|
msgstr "La data d’arribada ha de ser igual o posterior a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:356
|
#: pkg/booking/public.go:306
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or before."
|
msgid "Arrival date must be %s or before."
|
||||||
msgstr "La data d’arribada ha de ser anterior o igual a %s."
|
msgstr "La data d’arribada ha de ser anterior o igual a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:360
|
#: pkg/booking/public.go:310
|
||||||
msgid "Departure date can not be empty"
|
msgid "Departure date can not be empty"
|
||||||
msgstr "No podeu deixar la data de sortida en blanc."
|
msgstr "No podeu deixar la data de sortida en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:362
|
#: pkg/booking/public.go:312
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or after."
|
msgid "Departure date must be %s or after."
|
||||||
msgstr "La data de sortida ha de ser igual o posterior a %s."
|
msgstr "La data de sortida ha de ser igual o posterior a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:363
|
#: pkg/booking/public.go:313
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or before."
|
msgid "Departure date must be %s or before."
|
||||||
msgstr "La data de sortida ha de ser anterior o igual a %s."
|
msgstr "La data de sortida ha de ser anterior o igual a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:405
|
#: pkg/booking/public.go:355
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "There can be at most %d guests in this accommodation."
|
msgid "There can be at most %d guests in this accommodation."
|
||||||
msgstr "Hi poden haver com a màxim %d convidats a aquest allotjament."
|
msgstr "Hi poden haver com a màxim %d convidats a aquest allotjament."
|
||||||
|
|
||||||
#: pkg/booking/public.go:425
|
#: pkg/booking/public.go:375
|
||||||
msgid "Number of adults can not be empty"
|
msgid "Number of adults can not be empty"
|
||||||
msgstr "No podeu deixar el número d’adults en blanc."
|
msgstr "No podeu deixar el número d’adults en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:426
|
#: pkg/booking/public.go:376
|
||||||
msgid "Number of adults must be an integer."
|
msgid "Number of adults must be an integer."
|
||||||
msgstr "El número d’adults ha de ser enter."
|
msgstr "El número d’adults ha de ser enter."
|
||||||
|
|
||||||
#: pkg/booking/public.go:427
|
#: pkg/booking/public.go:377
|
||||||
msgid "There must be at least one adult."
|
msgid "There must be at least one adult."
|
||||||
msgstr "Hi ha d’haver com a mínim un adult."
|
msgstr "Hi ha d’haver com a mínim un adult."
|
||||||
|
|
||||||
#: pkg/booking/public.go:430
|
#: pkg/booking/public.go:380
|
||||||
msgid "Number of teenagers can not be empty"
|
msgid "Number of teenagers can not be empty"
|
||||||
msgstr "No podeu deixar el número d’adolescents en blanc."
|
msgstr "No podeu deixar el número d’adolescents en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:431
|
#: pkg/booking/public.go:381
|
||||||
msgid "Number of teenagers must be an integer."
|
msgid "Number of teenagers must be an integer."
|
||||||
msgstr "El número d’adolescents ha de ser enter."
|
msgstr "El número d’adolescents ha de ser enter."
|
||||||
|
|
||||||
#: pkg/booking/public.go:432
|
#: pkg/booking/public.go:382
|
||||||
msgid "Number of teenagers can not be negative."
|
msgid "Number of teenagers can not be negative."
|
||||||
msgstr "El número d’adolescents no pot ser negatiu."
|
msgstr "El número d’adolescents no pot ser negatiu."
|
||||||
|
|
||||||
#: pkg/booking/public.go:435
|
#: pkg/booking/public.go:385
|
||||||
msgid "Number of children can not be empty"
|
msgid "Number of children can not be empty"
|
||||||
msgstr "No podeu deixar el número de nens en blanc."
|
msgstr "No podeu deixar el número de nens en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:436
|
#: pkg/booking/public.go:386
|
||||||
msgid "Number of children must be an integer."
|
msgid "Number of children must be an integer."
|
||||||
msgstr "El número de nens ha de ser enter."
|
msgstr "El número de nens ha de ser enter."
|
||||||
|
|
||||||
#: pkg/booking/public.go:437
|
#: pkg/booking/public.go:387
|
||||||
msgid "Number of children can not be negative."
|
msgid "Number of children can not be negative."
|
||||||
msgstr "El número de nens no pot ser negatiu."
|
msgstr "El número de nens no pot ser negatiu."
|
||||||
|
|
||||||
#: pkg/booking/public.go:440
|
#: pkg/booking/public.go:390
|
||||||
msgid "Number of dogs can not be empty"
|
msgid "Number of dogs can not be empty"
|
||||||
msgstr "No podeu deixar el número de gossos en blanc."
|
msgstr "No podeu deixar el número de gossos en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:441
|
#: pkg/booking/public.go:391
|
||||||
msgid "Number of dogs must be an integer."
|
msgid "Number of dogs must be an integer."
|
||||||
msgstr "El número de gossos ha de ser enter."
|
msgstr "El número de gossos ha de ser enter."
|
||||||
|
|
||||||
#: pkg/booking/public.go:442
|
#: pkg/booking/public.go:392
|
||||||
msgid "Number of dogs can not be negative."
|
msgid "Number of dogs can not be negative."
|
||||||
msgstr "El número de gossos no pot ser negatiu."
|
msgstr "El número de gossos no pot ser negatiu."
|
||||||
|
|
||||||
#: pkg/booking/public.go:513
|
#: pkg/booking/public.go:463
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s can not be empty"
|
msgid "%s can not be empty"
|
||||||
msgstr "No podeu deixar %s en blanc."
|
msgstr "No podeu deixar %s en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:514
|
#: pkg/booking/public.go:464
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be an integer."
|
msgid "%s must be an integer."
|
||||||
msgstr "%s ha de ser un número enter."
|
msgstr "%s ha de ser un número enter."
|
||||||
|
|
||||||
#: pkg/booking/public.go:515
|
#: pkg/booking/public.go:465
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be %d or greater."
|
msgid "%s must be %d or greater."
|
||||||
msgstr "El valor de %s ha de ser com a mínim %d."
|
msgstr "El valor de %s ha de ser com a mínim %d."
|
||||||
|
|
||||||
#: pkg/booking/public.go:516
|
#: pkg/booking/public.go:466
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be at most %d."
|
msgid "%s must be at most %d."
|
||||||
msgstr "El valor de %s ha de ser com a màxim %d."
|
msgstr "El valor de %s ha de ser com a màxim %d."
|
||||||
|
|
||||||
#: pkg/booking/public.go:574
|
#: pkg/booking/public.go:524
|
||||||
msgid "Full name can not be empty."
|
msgid "Full name can not be empty."
|
||||||
msgstr "No podeu deixar el nom i els cognoms en blanc."
|
msgstr "No podeu deixar el nom i els cognoms en blanc."
|
||||||
|
|
||||||
#: pkg/booking/public.go:575
|
#: pkg/booking/public.go:525
|
||||||
msgid "Full name must have at least one letter."
|
msgid "Full name must have at least one letter."
|
||||||
msgstr "El nom i els cognoms han de tenir com a mínim una lletra."
|
msgstr "El nom i els cognoms han de tenir com a mínim una lletra."
|
||||||
|
|
||||||
#: pkg/booking/public.go:592
|
#: pkg/booking/public.go:542
|
||||||
msgid "It is mandatory to agree to the reservation conditions."
|
msgid "It is mandatory to agree to the reservation conditions."
|
||||||
msgstr "És obligatori acceptar les condicions de reserves."
|
msgstr "És obligatori acceptar les condicions de reserves."
|
||||||
|
|
||||||
|
#~ msgctxt "title"
|
||||||
|
#~ msgid "Payment"
|
||||||
|
#~ msgstr "Pagament"
|
||||||
|
|
||||||
|
#~ msgctxt "action"
|
||||||
|
#~ msgid "Pay"
|
||||||
|
#~ msgstr "Paga"
|
||||||
|
|
||||||
#~ msgctxt "input"
|
#~ msgctxt "input"
|
||||||
#~ msgid "Check-in Date"
|
#~ msgid "Check-in Date"
|
||||||
#~ msgstr "Data d’entrada"
|
#~ msgstr "Data d’entrada"
|
||||||
|
|
135
po/es.po
135
po/es.po
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: camper\n"
|
"Project-Id-Version: camper\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||||
"POT-Creation-Date: 2024-02-12 05:10+0100\n"
|
"POT-Creation-Date: 2024-02-12 17:49+0100\n"
|
||||||
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
|
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||||
|
@ -60,28 +60,56 @@ msgid "Zone 1"
|
||||||
msgstr "Zona 1"
|
msgstr "Zona 1"
|
||||||
|
|
||||||
#: web/templates/public/payment/success.gohtml:6
|
#: web/templates/public/payment/success.gohtml:6
|
||||||
#: web/templates/public/payment/success.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Successful"
|
msgid "Payment Successful"
|
||||||
msgstr "Pago con éxito"
|
msgstr "Pago con éxito"
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:6
|
#: web/templates/public/payment/success.gohtml:12
|
||||||
#: web/templates/public/payment/request.gohtml:11
|
msgid "We have received the payment. Thank you."
|
||||||
msgctxt "title"
|
msgstr "Hemos recibido su pago. Gracias."
|
||||||
msgid "Payment"
|
|
||||||
msgstr "Pago"
|
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:23
|
#: web/templates/public/payment/request.gohtml:6
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Booking Payment"
|
||||||
|
msgstr "Pago de la reserva"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:18
|
||||||
|
msgid "Thank you for your booking. Please, click the button below to pay with a credit card via Servired/Redsys."
|
||||||
|
msgstr "Gracias por vuestro pedido. Haced clic al botón de abajo para pagar con tarjeta de crédito vía Servired/Redsys."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:27
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Pay"
|
msgid "Pay with credit card"
|
||||||
msgstr "Pagar"
|
msgstr "Pagar con tarjeta de crédito"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:30
|
||||||
|
msgid "Please, wait until we redirect you to the payment page."
|
||||||
|
msgstr "Esperad mientras se os redirige a la página de pago."
|
||||||
|
|
||||||
#: web/templates/public/payment/failure.gohtml:6
|
#: web/templates/public/payment/failure.gohtml:6
|
||||||
#: web/templates/public/payment/failure.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Failed"
|
msgid "Payment Failed"
|
||||||
msgstr "Pago fallido"
|
msgstr "Pago fallido"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/failure.gohtml:12
|
||||||
|
msgid "We could not process the payment. Please, contact us for support."
|
||||||
|
msgstr "No hemos podido procesar su pago. Póngase en contacto con nosotros para solucionar el problema."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:4
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Order Number"
|
||||||
|
msgstr "Número de pedido"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:8
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "Fecha"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Total"
|
||||||
|
msgstr "Total"
|
||||||
|
|
||||||
#: web/templates/public/services.gohtml:7
|
#: web/templates/public/services.gohtml:7
|
||||||
#: web/templates/public/services.gohtml:16
|
#: web/templates/public/services.gohtml:16
|
||||||
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
||||||
|
@ -1951,6 +1979,11 @@ msgstr "Estado"
|
||||||
msgid "No booking found."
|
msgid "No booking found."
|
||||||
msgstr "No se ha encontrado ninguna reserva."
|
msgstr "No se ha encontrado ninguna reserva."
|
||||||
|
|
||||||
|
#: pkg/payment/public.go:97
|
||||||
|
msgctxt "order product name"
|
||||||
|
msgid "Campsite Booking"
|
||||||
|
msgstr "Reserva de camping"
|
||||||
|
|
||||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
||||||
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
||||||
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
||||||
|
@ -1990,12 +2023,12 @@ msgid "Slide image must be an image media type."
|
||||||
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
|
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
|
||||||
|
|
||||||
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
||||||
#: pkg/booking/public.go:583
|
#: pkg/booking/public.go:533
|
||||||
msgid "Email can not be empty."
|
msgid "Email can not be empty."
|
||||||
msgstr "No podéis dejar el correo-e en blanco."
|
msgstr "No podéis dejar el correo-e en blanco."
|
||||||
|
|
||||||
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
||||||
#: pkg/booking/public.go:584
|
#: pkg/booking/public.go:534
|
||||||
msgid "This email is not valid. It should be like name@domain.com."
|
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."
|
msgstr "Este correo-e no es válido. Tiene que ser parecido a nombre@dominio.com."
|
||||||
|
|
||||||
|
@ -2206,8 +2239,8 @@ msgctxt "header"
|
||||||
msgid "Children (aged 2 to 10)"
|
msgid "Children (aged 2 to 10)"
|
||||||
msgstr "Niños (de 2 a 10 años)"
|
msgstr "Niños (de 2 a 10 años)"
|
||||||
|
|
||||||
#: pkg/campsite/admin.go:275 pkg/booking/public.go:224
|
#: pkg/campsite/admin.go:275 pkg/booking/public.go:171
|
||||||
#: pkg/booking/public.go:276
|
#: pkg/booking/public.go:226
|
||||||
msgid "Selected campsite type is not valid."
|
msgid "Selected campsite type is not valid."
|
||||||
msgstr "El tipo de alojamiento escogido no es válido."
|
msgstr "El tipo de alojamiento escogido no es válido."
|
||||||
|
|
||||||
|
@ -2363,7 +2396,7 @@ msgstr "No podéis dejar la dirección del enlace en blanco."
|
||||||
msgid "This web address is not valid. It should be like https://domain.com/."
|
msgid "This web address is not valid. It should be like https://domain.com/."
|
||||||
msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/."
|
msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/."
|
||||||
|
|
||||||
#: pkg/company/admin.go:200 pkg/booking/public.go:570
|
#: pkg/company/admin.go:200 pkg/booking/public.go:520
|
||||||
msgid "Selected country is not valid."
|
msgid "Selected country is not valid."
|
||||||
msgstr "El país escogido no es válido."
|
msgstr "El país escogido no es válido."
|
||||||
|
|
||||||
|
@ -2383,11 +2416,11 @@ msgstr "No podéis dejar el NIF en blanco."
|
||||||
msgid "This VAT number is not valid."
|
msgid "This VAT number is not valid."
|
||||||
msgstr "Este NIF no es válido."
|
msgstr "Este NIF no es válido."
|
||||||
|
|
||||||
#: pkg/company/admin.go:212 pkg/booking/public.go:586
|
#: pkg/company/admin.go:212 pkg/booking/public.go:536
|
||||||
msgid "Phone can not be empty."
|
msgid "Phone can not be empty."
|
||||||
msgstr "No podéis dejar el teléfono en blanco."
|
msgstr "No podéis dejar el teléfono en blanco."
|
||||||
|
|
||||||
#: pkg/company/admin.go:213 pkg/booking/public.go:587
|
#: pkg/company/admin.go:213 pkg/booking/public.go:537
|
||||||
msgid "This phone number is not valid."
|
msgid "This phone number is not valid."
|
||||||
msgstr "Este teléfono no es válido."
|
msgstr "Este teléfono no es válido."
|
||||||
|
|
||||||
|
@ -2407,7 +2440,7 @@ msgstr "No podéis dejar la provincia en blanco."
|
||||||
msgid "Postal code can not be empty."
|
msgid "Postal code can not be empty."
|
||||||
msgstr "No podéis dejar el código postal en blanco."
|
msgstr "No podéis dejar el código postal en blanco."
|
||||||
|
|
||||||
#: pkg/company/admin.go:227 pkg/booking/public.go:579
|
#: pkg/company/admin.go:227 pkg/booking/public.go:529
|
||||||
msgid "This postal code is not valid."
|
msgid "This postal code is not valid."
|
||||||
msgstr "Este código postal no es válido."
|
msgstr "Este código postal no es válido."
|
||||||
|
|
||||||
|
@ -2534,127 +2567,135 @@ msgstr "La integración escogida no es válida."
|
||||||
msgid "The merchant key is not valid."
|
msgid "The merchant key is not valid."
|
||||||
msgstr "Esta clave del comercio no es válida."
|
msgstr "Esta clave del comercio no es válida."
|
||||||
|
|
||||||
#: pkg/booking/public.go:325 pkg/booking/public.go:354
|
#: pkg/booking/public.go:275 pkg/booking/public.go:304
|
||||||
msgid "Arrival date must be a valid date."
|
msgid "Arrival date must be a valid date."
|
||||||
msgstr "La fecha de llegada tiene que ser una fecha válida."
|
msgstr "La fecha de llegada tiene que ser una fecha válida."
|
||||||
|
|
||||||
#: pkg/booking/public.go:339 pkg/booking/public.go:361
|
#: pkg/booking/public.go:289 pkg/booking/public.go:311
|
||||||
msgid "Departure date must be a valid date."
|
msgid "Departure date must be a valid date."
|
||||||
msgstr "La fecha de partida tiene que ser una fecha válida."
|
msgstr "La fecha de partida tiene que ser una fecha válida."
|
||||||
|
|
||||||
#: pkg/booking/public.go:353
|
#: pkg/booking/public.go:303
|
||||||
msgid "Arrival date can not be empty"
|
msgid "Arrival date can not be empty"
|
||||||
msgstr "No podéis dejar la fecha de llegada en blanco."
|
msgstr "No podéis dejar la fecha de llegada en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:355
|
#: pkg/booking/public.go:305
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or after."
|
msgid "Arrival date must be %s or after."
|
||||||
msgstr "La fecha de llegada tiene que ser igual o posterior a %s."
|
msgstr "La fecha de llegada tiene que ser igual o posterior a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:356
|
#: pkg/booking/public.go:306
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or before."
|
msgid "Arrival date must be %s or before."
|
||||||
msgstr "La fecha de llegada tiene que ser anterior o igual a %s."
|
msgstr "La fecha de llegada tiene que ser anterior o igual a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:360
|
#: pkg/booking/public.go:310
|
||||||
msgid "Departure date can not be empty"
|
msgid "Departure date can not be empty"
|
||||||
msgstr "No podéis dejar la fecha de partida en blanco."
|
msgstr "No podéis dejar la fecha de partida en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:362
|
#: pkg/booking/public.go:312
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or after."
|
msgid "Departure date must be %s or after."
|
||||||
msgstr "La fecha de partida tiene que igual o posterior a %s."
|
msgstr "La fecha de partida tiene que igual o posterior a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:363
|
#: pkg/booking/public.go:313
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or before."
|
msgid "Departure date must be %s or before."
|
||||||
msgstr "La fecha de partida tiene que ser anterior o igual a %s."
|
msgstr "La fecha de partida tiene que ser anterior o igual a %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:405
|
#: pkg/booking/public.go:355
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "There can be at most %d guests in this accommodation."
|
msgid "There can be at most %d guests in this accommodation."
|
||||||
msgstr "Solo puede haber como máximo %d invitados en este alojamiento."
|
msgstr "Solo puede haber como máximo %d invitados en este alojamiento."
|
||||||
|
|
||||||
#: pkg/booking/public.go:425
|
#: pkg/booking/public.go:375
|
||||||
msgid "Number of adults can not be empty"
|
msgid "Number of adults can not be empty"
|
||||||
msgstr "No podéis dejar el número de adultos blanco."
|
msgstr "No podéis dejar el número de adultos blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:426
|
#: pkg/booking/public.go:376
|
||||||
msgid "Number of adults must be an integer."
|
msgid "Number of adults must be an integer."
|
||||||
msgstr "El número de adultos tiene que ser entero."
|
msgstr "El número de adultos tiene que ser entero."
|
||||||
|
|
||||||
#: pkg/booking/public.go:427
|
#: pkg/booking/public.go:377
|
||||||
msgid "There must be at least one adult."
|
msgid "There must be at least one adult."
|
||||||
msgstr "Tiene que haber como mínimo un adulto."
|
msgstr "Tiene que haber como mínimo un adulto."
|
||||||
|
|
||||||
#: pkg/booking/public.go:430
|
#: pkg/booking/public.go:380
|
||||||
msgid "Number of teenagers can not be empty"
|
msgid "Number of teenagers can not be empty"
|
||||||
msgstr "No podéis dejar el número de adolescentes en blanco."
|
msgstr "No podéis dejar el número de adolescentes en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:431
|
#: pkg/booking/public.go:381
|
||||||
msgid "Number of teenagers must be an integer."
|
msgid "Number of teenagers must be an integer."
|
||||||
msgstr "El número de adolescentes tiene que ser entero."
|
msgstr "El número de adolescentes tiene que ser entero."
|
||||||
|
|
||||||
#: pkg/booking/public.go:432
|
#: pkg/booking/public.go:382
|
||||||
msgid "Number of teenagers can not be negative."
|
msgid "Number of teenagers can not be negative."
|
||||||
msgstr "El número de adolescentes no puede ser negativo."
|
msgstr "El número de adolescentes no puede ser negativo."
|
||||||
|
|
||||||
#: pkg/booking/public.go:435
|
#: pkg/booking/public.go:385
|
||||||
msgid "Number of children can not be empty"
|
msgid "Number of children can not be empty"
|
||||||
msgstr "No podéis dejar el número de niños en blanco."
|
msgstr "No podéis dejar el número de niños en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:436
|
#: pkg/booking/public.go:386
|
||||||
msgid "Number of children must be an integer."
|
msgid "Number of children must be an integer."
|
||||||
msgstr "El número de niños tiene que ser entero."
|
msgstr "El número de niños tiene que ser entero."
|
||||||
|
|
||||||
#: pkg/booking/public.go:437
|
#: pkg/booking/public.go:387
|
||||||
msgid "Number of children can not be negative."
|
msgid "Number of children can not be negative."
|
||||||
msgstr "El número de niños no puede ser negativo."
|
msgstr "El número de niños no puede ser negativo."
|
||||||
|
|
||||||
#: pkg/booking/public.go:440
|
#: pkg/booking/public.go:390
|
||||||
msgid "Number of dogs can not be empty"
|
msgid "Number of dogs can not be empty"
|
||||||
msgstr "No podéis dejar el número de perros en blanco."
|
msgstr "No podéis dejar el número de perros en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:441
|
#: pkg/booking/public.go:391
|
||||||
msgid "Number of dogs must be an integer."
|
msgid "Number of dogs must be an integer."
|
||||||
msgstr "El número de perros tiene que ser entero."
|
msgstr "El número de perros tiene que ser entero."
|
||||||
|
|
||||||
#: pkg/booking/public.go:442
|
#: pkg/booking/public.go:392
|
||||||
msgid "Number of dogs can not be negative."
|
msgid "Number of dogs can not be negative."
|
||||||
msgstr "El número de perros no puede ser negativo."
|
msgstr "El número de perros no puede ser negativo."
|
||||||
|
|
||||||
#: pkg/booking/public.go:513
|
#: pkg/booking/public.go:463
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s can not be empty"
|
msgid "%s can not be empty"
|
||||||
msgstr "No podéis dejar %s en blanco."
|
msgstr "No podéis dejar %s en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:514
|
#: pkg/booking/public.go:464
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be an integer."
|
msgid "%s must be an integer."
|
||||||
msgstr "%s tiene que ser un número entero."
|
msgstr "%s tiene que ser un número entero."
|
||||||
|
|
||||||
#: pkg/booking/public.go:515
|
#: pkg/booking/public.go:465
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be %d or greater."
|
msgid "%s must be %d or greater."
|
||||||
msgstr "%s tiene que ser como mínimo %d."
|
msgstr "%s tiene que ser como mínimo %d."
|
||||||
|
|
||||||
#: pkg/booking/public.go:516
|
#: pkg/booking/public.go:466
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be at most %d."
|
msgid "%s must be at most %d."
|
||||||
msgstr "%s tiene que ser como máximo %d"
|
msgstr "%s tiene que ser como máximo %d"
|
||||||
|
|
||||||
#: pkg/booking/public.go:574
|
#: pkg/booking/public.go:524
|
||||||
msgid "Full name can not be empty."
|
msgid "Full name can not be empty."
|
||||||
msgstr "No podéis dejar el nombre y los apellidos en blanco."
|
msgstr "No podéis dejar el nombre y los apellidos en blanco."
|
||||||
|
|
||||||
#: pkg/booking/public.go:575
|
#: pkg/booking/public.go:525
|
||||||
msgid "Full name must have at least one letter."
|
msgid "Full name must have at least one letter."
|
||||||
msgstr "El nombre y los apellidos tienen que tener como mínimo una letra."
|
msgstr "El nombre y los apellidos tienen que tener como mínimo una letra."
|
||||||
|
|
||||||
#: pkg/booking/public.go:592
|
#: pkg/booking/public.go:542
|
||||||
msgid "It is mandatory to agree to the reservation conditions."
|
msgid "It is mandatory to agree to the reservation conditions."
|
||||||
msgstr "Es obligatorio aceptar las condiciones de reserva."
|
msgstr "Es obligatorio aceptar las condiciones de reserva."
|
||||||
|
|
||||||
|
#~ msgctxt "title"
|
||||||
|
#~ msgid "Payment"
|
||||||
|
#~ msgstr "Pago"
|
||||||
|
|
||||||
|
#~ msgctxt "action"
|
||||||
|
#~ msgid "Pay"
|
||||||
|
#~ msgstr "Pagar"
|
||||||
|
|
||||||
#~ msgctxt "input"
|
#~ msgctxt "input"
|
||||||
#~ msgid "Check-in Date"
|
#~ msgid "Check-in Date"
|
||||||
#~ msgstr "Fecha de entrada"
|
#~ msgstr "Fecha de entrada"
|
||||||
|
|
135
po/fr.po
135
po/fr.po
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: camper\n"
|
"Project-Id-Version: camper\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||||
"POT-Creation-Date: 2024-02-12 05:10+0100\n"
|
"POT-Creation-Date: 2024-02-12 17:49+0100\n"
|
||||||
"PO-Revision-Date: 2024-02-06 10:05+0100\n"
|
"PO-Revision-Date: 2024-02-06 10:05+0100\n"
|
||||||
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
|
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
|
||||||
"Language-Team: French <traduc@traduc.org>\n"
|
"Language-Team: French <traduc@traduc.org>\n"
|
||||||
|
@ -60,28 +60,56 @@ msgid "Zone 1"
|
||||||
msgstr "Zone 1"
|
msgstr "Zone 1"
|
||||||
|
|
||||||
#: web/templates/public/payment/success.gohtml:6
|
#: web/templates/public/payment/success.gohtml:6
|
||||||
#: web/templates/public/payment/success.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Successful"
|
msgid "Payment Successful"
|
||||||
msgstr "Paiement réussi"
|
msgstr "Paiement réussi"
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:6
|
#: web/templates/public/payment/success.gohtml:12
|
||||||
#: web/templates/public/payment/request.gohtml:11
|
msgid "We have received the payment. Thank you."
|
||||||
msgctxt "title"
|
msgstr "Nous avons reçu le paiement. Merci."
|
||||||
msgid "Payment"
|
|
||||||
msgstr "Paiement"
|
|
||||||
|
|
||||||
#: web/templates/public/payment/request.gohtml:23
|
#: web/templates/public/payment/request.gohtml:6
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Booking Payment"
|
||||||
|
msgstr "Paiement de la réservation"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:18
|
||||||
|
msgid "Thank you for your booking. Please, click the button below to pay with a credit card via Servired/Redsys."
|
||||||
|
msgstr "Merci pour votre réservation. Veuillez cliquer sur le bouton ci-dessous pour payer avec une carte de crédit via Servired/Redsys."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:27
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Pay"
|
msgid "Pay with credit card"
|
||||||
msgstr "Payer"
|
msgstr "Payez avec une carte de crédit"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/request.gohtml:30
|
||||||
|
msgid "Please, wait until we redirect you to the payment page."
|
||||||
|
msgstr "Veuillez attendre que nous vous redirigeons vers la page de paiement."
|
||||||
|
|
||||||
#: web/templates/public/payment/failure.gohtml:6
|
#: web/templates/public/payment/failure.gohtml:6
|
||||||
#: web/templates/public/payment/failure.gohtml:11
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Payment Failed"
|
msgid "Payment Failed"
|
||||||
msgstr "Le paiement a échoué"
|
msgstr "Le paiement a échoué"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/failure.gohtml:12
|
||||||
|
msgid "We could not process the payment. Please, contact us for support."
|
||||||
|
msgstr "Nous n’avons pas pu traiter le paiement. S’il vous plaît, contactez-nous pour obtenir de l’aide."
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:4
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Order Number"
|
||||||
|
msgstr "Numéro de commande"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:8
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "Date"
|
||||||
|
|
||||||
|
#: web/templates/public/payment/details.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Total"
|
||||||
|
msgstr "Totale"
|
||||||
|
|
||||||
#: web/templates/public/services.gohtml:7
|
#: web/templates/public/services.gohtml:7
|
||||||
#: web/templates/public/services.gohtml:16
|
#: web/templates/public/services.gohtml:16
|
||||||
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
|
||||||
|
@ -1951,6 +1979,11 @@ msgstr "Statut"
|
||||||
msgid "No booking found."
|
msgid "No booking found."
|
||||||
msgstr "Aucune réservation trouvée."
|
msgstr "Aucune réservation trouvée."
|
||||||
|
|
||||||
|
#: pkg/payment/public.go:97
|
||||||
|
msgctxt "order product name"
|
||||||
|
msgid "Campsite Booking"
|
||||||
|
msgstr "Réservation camping"
|
||||||
|
|
||||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
|
||||||
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
|
||||||
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
|
||||||
|
@ -1990,12 +2023,12 @@ msgid "Slide image must be an image media type."
|
||||||
msgstr "L’image de la diapositive doit être de type média d’image."
|
msgstr "L’image de la diapositive doit être de type média d’image."
|
||||||
|
|
||||||
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
|
||||||
#: pkg/booking/public.go:583
|
#: pkg/booking/public.go:533
|
||||||
msgid "Email can not be empty."
|
msgid "Email can not be empty."
|
||||||
msgstr "L’e-mail ne peut pas être vide."
|
msgstr "L’e-mail ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
|
||||||
#: pkg/booking/public.go:584
|
#: pkg/booking/public.go:534
|
||||||
msgid "This email is not valid. It should be like name@domain.com."
|
msgid "This email is not valid. It should be like name@domain.com."
|
||||||
msgstr "Cette adresse e-mail n’est pas valide. Il devrait en être name@domain.com."
|
msgstr "Cette adresse e-mail n’est pas valide. Il devrait en être name@domain.com."
|
||||||
|
|
||||||
|
@ -2206,8 +2239,8 @@ msgctxt "header"
|
||||||
msgid "Children (aged 2 to 10)"
|
msgid "Children (aged 2 to 10)"
|
||||||
msgstr "Enfants (de 2 à 10 anys)"
|
msgstr "Enfants (de 2 à 10 anys)"
|
||||||
|
|
||||||
#: pkg/campsite/admin.go:275 pkg/booking/public.go:224
|
#: pkg/campsite/admin.go:275 pkg/booking/public.go:171
|
||||||
#: pkg/booking/public.go:276
|
#: pkg/booking/public.go:226
|
||||||
msgid "Selected campsite type is not valid."
|
msgid "Selected campsite type is not valid."
|
||||||
msgstr "Le type d’emplacement sélectionné n’est pas valide."
|
msgstr "Le type d’emplacement sélectionné n’est pas valide."
|
||||||
|
|
||||||
|
@ -2363,7 +2396,7 @@ msgstr "L’addresse du lien ne peut pas être vide."
|
||||||
msgid "This web address is not valid. It should be like https://domain.com/."
|
msgid "This web address is not valid. It should be like https://domain.com/."
|
||||||
msgstr "Cette adresse web n’est pas valide. Il devrait en être https://domain.com/."
|
msgstr "Cette adresse web n’est pas valide. Il devrait en être https://domain.com/."
|
||||||
|
|
||||||
#: pkg/company/admin.go:200 pkg/booking/public.go:570
|
#: pkg/company/admin.go:200 pkg/booking/public.go:520
|
||||||
msgid "Selected country is not valid."
|
msgid "Selected country is not valid."
|
||||||
msgstr "Le pays sélectionné n’est pas valide."
|
msgstr "Le pays sélectionné n’est pas valide."
|
||||||
|
|
||||||
|
@ -2383,11 +2416,11 @@ msgstr "Le numéro de TVA ne peut pas être vide."
|
||||||
msgid "This VAT number is not valid."
|
msgid "This VAT number is not valid."
|
||||||
msgstr "Ce numéro de TVA n’est pas valide."
|
msgstr "Ce numéro de TVA n’est pas valide."
|
||||||
|
|
||||||
#: pkg/company/admin.go:212 pkg/booking/public.go:586
|
#: pkg/company/admin.go:212 pkg/booking/public.go:536
|
||||||
msgid "Phone can not be empty."
|
msgid "Phone can not be empty."
|
||||||
msgstr "Le téléphone ne peut pas être vide."
|
msgstr "Le téléphone ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/company/admin.go:213 pkg/booking/public.go:587
|
#: pkg/company/admin.go:213 pkg/booking/public.go:537
|
||||||
msgid "This phone number is not valid."
|
msgid "This phone number is not valid."
|
||||||
msgstr "Ce numéro de téléphone n’est pas valide."
|
msgstr "Ce numéro de téléphone n’est pas valide."
|
||||||
|
|
||||||
|
@ -2407,7 +2440,7 @@ msgstr "La province ne peut pas être vide."
|
||||||
msgid "Postal code can not be empty."
|
msgid "Postal code can not be empty."
|
||||||
msgstr "Le code postal ne peut pas être vide."
|
msgstr "Le code postal ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/company/admin.go:227 pkg/booking/public.go:579
|
#: pkg/company/admin.go:227 pkg/booking/public.go:529
|
||||||
msgid "This postal code is not valid."
|
msgid "This postal code is not valid."
|
||||||
msgstr "Ce code postal n’est pas valide."
|
msgstr "Ce code postal n’est pas valide."
|
||||||
|
|
||||||
|
@ -2534,127 +2567,135 @@ msgstr "L’intégration sélectionnée n’est pas valide."
|
||||||
msgid "The merchant key is not valid."
|
msgid "The merchant key is not valid."
|
||||||
msgstr "La clé marchand n’est pas valide."
|
msgstr "La clé marchand n’est pas valide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:325 pkg/booking/public.go:354
|
#: pkg/booking/public.go:275 pkg/booking/public.go:304
|
||||||
msgid "Arrival date must be a valid date."
|
msgid "Arrival date must be a valid date."
|
||||||
msgstr "La date d’arrivée doit être une date valide."
|
msgstr "La date d’arrivée doit être une date valide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:339 pkg/booking/public.go:361
|
#: pkg/booking/public.go:289 pkg/booking/public.go:311
|
||||||
msgid "Departure date must be a valid date."
|
msgid "Departure date must be a valid date."
|
||||||
msgstr "La date de départ doit être une date valide."
|
msgstr "La date de départ doit être une date valide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:353
|
#: pkg/booking/public.go:303
|
||||||
msgid "Arrival date can not be empty"
|
msgid "Arrival date can not be empty"
|
||||||
msgstr "La date d’arrivée ne peut pas être vide"
|
msgstr "La date d’arrivée ne peut pas être vide"
|
||||||
|
|
||||||
#: pkg/booking/public.go:355
|
#: pkg/booking/public.go:305
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or after."
|
msgid "Arrival date must be %s or after."
|
||||||
msgstr "La date d’arrivée doit être égale ou postérieure à %s."
|
msgstr "La date d’arrivée doit être égale ou postérieure à %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:356
|
#: pkg/booking/public.go:306
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Arrival date must be %s or before."
|
msgid "Arrival date must be %s or before."
|
||||||
msgstr "La date d’arrivée doit être antérieure ou égale à %s."
|
msgstr "La date d’arrivée doit être antérieure ou égale à %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:360
|
#: pkg/booking/public.go:310
|
||||||
msgid "Departure date can not be empty"
|
msgid "Departure date can not be empty"
|
||||||
msgstr "La date de départ ne peut pas être vide"
|
msgstr "La date de départ ne peut pas être vide"
|
||||||
|
|
||||||
#: pkg/booking/public.go:362
|
#: pkg/booking/public.go:312
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or after."
|
msgid "Departure date must be %s or after."
|
||||||
msgstr "La date de départ doit être égale ou postérieure à %s."
|
msgstr "La date de départ doit être égale ou postérieure à %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:363
|
#: pkg/booking/public.go:313
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Departure date must be %s or before."
|
msgid "Departure date must be %s or before."
|
||||||
msgstr "La date de départ doit être antérieure ou égale à %s."
|
msgstr "La date de départ doit être antérieure ou égale à %s."
|
||||||
|
|
||||||
#: pkg/booking/public.go:405
|
#: pkg/booking/public.go:355
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "There can be at most %d guests in this accommodation."
|
msgid "There can be at most %d guests in this accommodation."
|
||||||
msgstr "Il peut y avoir au plus %d invités dans cet hébergement."
|
msgstr "Il peut y avoir au plus %d invités dans cet hébergement."
|
||||||
|
|
||||||
#: pkg/booking/public.go:425
|
#: pkg/booking/public.go:375
|
||||||
msgid "Number of adults can not be empty"
|
msgid "Number of adults can not be empty"
|
||||||
msgstr "Le nombre d’adultes ne peut pas être vide."
|
msgstr "Le nombre d’adultes ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:426
|
#: pkg/booking/public.go:376
|
||||||
msgid "Number of adults must be an integer."
|
msgid "Number of adults must be an integer."
|
||||||
msgstr "Le nombre d’adultes doit être un entier."
|
msgstr "Le nombre d’adultes doit être un entier."
|
||||||
|
|
||||||
#: pkg/booking/public.go:427
|
#: pkg/booking/public.go:377
|
||||||
msgid "There must be at least one adult."
|
msgid "There must be at least one adult."
|
||||||
msgstr "Il doit y avoir au moins un adulte."
|
msgstr "Il doit y avoir au moins un adulte."
|
||||||
|
|
||||||
#: pkg/booking/public.go:430
|
#: pkg/booking/public.go:380
|
||||||
msgid "Number of teenagers can not be empty"
|
msgid "Number of teenagers can not be empty"
|
||||||
msgstr "Le nombre d’adolescents ne peut pas être vide."
|
msgstr "Le nombre d’adolescents ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:431
|
#: pkg/booking/public.go:381
|
||||||
msgid "Number of teenagers must be an integer."
|
msgid "Number of teenagers must be an integer."
|
||||||
msgstr "Le nombre d’adolescents doit être un entier."
|
msgstr "Le nombre d’adolescents doit être un entier."
|
||||||
|
|
||||||
#: pkg/booking/public.go:432
|
#: pkg/booking/public.go:382
|
||||||
msgid "Number of teenagers can not be negative."
|
msgid "Number of teenagers can not be negative."
|
||||||
msgstr "Le nombre d’adolescents ne peut pas être négatif."
|
msgstr "Le nombre d’adolescents ne peut pas être négatif."
|
||||||
|
|
||||||
#: pkg/booking/public.go:435
|
#: pkg/booking/public.go:385
|
||||||
msgid "Number of children can not be empty"
|
msgid "Number of children can not be empty"
|
||||||
msgstr "Le nombre d’enfants ne peut pas être vide."
|
msgstr "Le nombre d’enfants ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:436
|
#: pkg/booking/public.go:386
|
||||||
msgid "Number of children must be an integer."
|
msgid "Number of children must be an integer."
|
||||||
msgstr "Le nombre d’enfants doit être un entier."
|
msgstr "Le nombre d’enfants doit être un entier."
|
||||||
|
|
||||||
#: pkg/booking/public.go:437
|
#: pkg/booking/public.go:387
|
||||||
msgid "Number of children can not be negative."
|
msgid "Number of children can not be negative."
|
||||||
msgstr "Le nombre d’enfants ne peut pas être négatif."
|
msgstr "Le nombre d’enfants ne peut pas être négatif."
|
||||||
|
|
||||||
#: pkg/booking/public.go:440
|
#: pkg/booking/public.go:390
|
||||||
msgid "Number of dogs can not be empty"
|
msgid "Number of dogs can not be empty"
|
||||||
msgstr "Le nombre de chiens ne peut pas être vide."
|
msgstr "Le nombre de chiens ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:441
|
#: pkg/booking/public.go:391
|
||||||
msgid "Number of dogs must be an integer."
|
msgid "Number of dogs must be an integer."
|
||||||
msgstr "Le nombre de chiens nuits être un entier."
|
msgstr "Le nombre de chiens nuits être un entier."
|
||||||
|
|
||||||
#: pkg/booking/public.go:442
|
#: pkg/booking/public.go:392
|
||||||
msgid "Number of dogs can not be negative."
|
msgid "Number of dogs can not be negative."
|
||||||
msgstr "Le nombre de chiens ne peut pas être négatif."
|
msgstr "Le nombre de chiens ne peut pas être négatif."
|
||||||
|
|
||||||
#: pkg/booking/public.go:513
|
#: pkg/booking/public.go:463
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s can not be empty"
|
msgid "%s can not be empty"
|
||||||
msgstr "%s ne peut pas être vide"
|
msgstr "%s ne peut pas être vide"
|
||||||
|
|
||||||
#: pkg/booking/public.go:514
|
#: pkg/booking/public.go:464
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be an integer."
|
msgid "%s must be an integer."
|
||||||
msgstr "%s doit être un entier."
|
msgstr "%s doit être un entier."
|
||||||
|
|
||||||
#: pkg/booking/public.go:515
|
#: pkg/booking/public.go:465
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be %d or greater."
|
msgid "%s must be %d or greater."
|
||||||
msgstr "%s doit être %d ou plus."
|
msgstr "%s doit être %d ou plus."
|
||||||
|
|
||||||
#: pkg/booking/public.go:516
|
#: pkg/booking/public.go:466
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s must be at most %d."
|
msgid "%s must be at most %d."
|
||||||
msgstr "%s doit être tout au plus %d."
|
msgstr "%s doit être tout au plus %d."
|
||||||
|
|
||||||
#: pkg/booking/public.go:574
|
#: pkg/booking/public.go:524
|
||||||
msgid "Full name can not be empty."
|
msgid "Full name can not be empty."
|
||||||
msgstr "Le nom complet ne peut pas être vide."
|
msgstr "Le nom complet ne peut pas être vide."
|
||||||
|
|
||||||
#: pkg/booking/public.go:575
|
#: pkg/booking/public.go:525
|
||||||
msgid "Full name must have at least one letter."
|
msgid "Full name must have at least one letter."
|
||||||
msgstr "Le nom complet doit comporter au moins une lettre."
|
msgstr "Le nom complet doit comporter au moins une lettre."
|
||||||
|
|
||||||
#: pkg/booking/public.go:592
|
#: pkg/booking/public.go:542
|
||||||
msgid "It is mandatory to agree to the reservation conditions."
|
msgid "It is mandatory to agree to the reservation conditions."
|
||||||
msgstr "Il est obligatoire d’accepter les conditions de réservation."
|
msgstr "Il est obligatoire d’accepter les conditions de réservation."
|
||||||
|
|
||||||
|
#~ msgctxt "title"
|
||||||
|
#~ msgid "Payment"
|
||||||
|
#~ msgstr "Paiement"
|
||||||
|
|
||||||
|
#~ msgctxt "action"
|
||||||
|
#~ msgid "Pay"
|
||||||
|
#~ msgstr "Payer"
|
||||||
|
|
||||||
#~ msgctxt "input"
|
#~ msgctxt "input"
|
||||||
#~ msgid "Check-in Date"
|
#~ msgid "Check-in Date"
|
||||||
#~ msgstr "Date d'arrivée"
|
#~ msgstr "Date d'arrivée"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert camper:ready_payment from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists camper.ready_payment(uuid, text, text, text, text, camper.country_code, camper.email, text, text, boolean);
|
||||||
|
|
||||||
|
commit;
|
|
@ -247,3 +247,4 @@ payment [roles schema_camper company campsite_type payment_status] 2024-02-11T21
|
||||||
payment_customer [roles schema_camper payment country country_code extension_pg_libphonenumber] 2024-02-12T00:10:20Z jordi fita mas <jordi@tandem.blog> # Add relation of payment customer
|
payment_customer [roles schema_camper payment country country_code extension_pg_libphonenumber] 2024-02-12T00:10:20Z jordi fita mas <jordi@tandem.blog> # Add relation of payment customer
|
||||||
payment_option [roles schema_camper payment campsite_type_option] 2024-02-12T00:58:07Z jordi fita mas <jordi@tandem.blog> # Add relation of payment for campsite type options
|
payment_option [roles schema_camper payment campsite_type_option] 2024-02-12T00:58:07Z jordi fita mas <jordi@tandem.blog> # Add relation of payment for campsite type options
|
||||||
draft_payment [roles schema_camper season_calendar season campsite_type campsite_type_pet_cost campsite_type_cost campsite_type_option_cost campsite_type_option payment payment_option] 2024-02-12T01:31:52Z jordi fita mas <jordi@tandem.blog> # Add function to create a payment draft
|
draft_payment [roles schema_camper season_calendar season campsite_type campsite_type_pet_cost campsite_type_cost campsite_type_option_cost campsite_type_option payment payment_option] 2024-02-12T01:31:52Z jordi fita mas <jordi@tandem.blog> # Add function to create a payment draft
|
||||||
|
ready_payment [roles schema_camper payment payment_customer country_code email extension_pg_libphonenumber] 2024-02-12T12:57:24Z jordi fita mas <jordi@tandem.blog> # Add function to ready a draft payment
|
||||||
|
|
|
@ -115,9 +115,9 @@ select lives_ok(
|
||||||
);
|
);
|
||||||
|
|
||||||
select bag_eq(
|
select bag_eq(
|
||||||
$$ select company_id, campsite_type_id, arrival_date::text, departure_date::text, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total, zone_preferences, created_at, updated_at from payment $$,
|
$$ select company_id, campsite_type_id, arrival_date::text, departure_date::text, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total, zone_preferences, payment_status, created_at, updated_at from payment $$,
|
||||||
$$ values (2, 12, '2024-08-28', '2024-09-04', 3200, 2, 10420, 4, 20840, 6, 25080, 3, 2450, 4900, 79160, 'pref I before E', '2024-01-01 01:01:01', current_timestamp)
|
$$ values (2, 12, '2024-08-28', '2024-09-04', 3200, 2, 10420, 4, 20840, 6, 25080, 3, 2450, 4900, 79160, 'pref I before E', 'draft', '2024-01-01 01:01:01', current_timestamp)
|
||||||
, (2, 14, '2024-08-29', '2024-09-03', 71000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 72750, '', current_timestamp, current_timestamp)
|
, (2, 14, '2024-08-29', '2024-09-03', 71000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 72750, '', 'draft', current_timestamp, current_timestamp)
|
||||||
$$,
|
$$,
|
||||||
'Should have added and updated payments'
|
'Should have added and updated payments'
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,13 +5,13 @@ reset client_min_messages;
|
||||||
|
|
||||||
begin;
|
begin;
|
||||||
|
|
||||||
select plan(47);
|
select plan(53);
|
||||||
|
|
||||||
set search_path to camper, public;
|
set search_path to camper, public;
|
||||||
|
|
||||||
select has_table('payment_customer');
|
select has_table('payment_customer');
|
||||||
select has_pk('payment_customer');
|
select has_pk('payment_customer');
|
||||||
select table_privs_are('payment_customer', 'guest', array['SELECT', 'INSERT']);
|
select table_privs_are('payment_customer', 'guest', array['SELECT', 'INSERT', 'UPDATE']);
|
||||||
select table_privs_are('payment_customer', 'employee', array['SELECT', 'INSERT', 'UPDATE']);
|
select table_privs_are('payment_customer', 'employee', array['SELECT', 'INSERT', 'UPDATE']);
|
||||||
select table_privs_are('payment_customer', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
select table_privs_are('payment_customer', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
select table_privs_are('payment_customer', 'authenticator', array[]::text[]);
|
select table_privs_are('payment_customer', 'authenticator', array[]::text[]);
|
||||||
|
@ -66,6 +66,13 @@ select col_type_is('payment_customer', 'acsi_card', 'boolean');
|
||||||
select col_not_null('payment_customer', 'acsi_card');
|
select col_not_null('payment_customer', 'acsi_card');
|
||||||
select col_hasnt_default('payment_customer', 'acsi_card');
|
select col_hasnt_default('payment_customer', 'acsi_card');
|
||||||
|
|
||||||
|
select has_column('payment_customer', 'lang_tag');
|
||||||
|
select col_is_fk('payment_customer', 'lang_tag');
|
||||||
|
select fk_ok('payment_customer', 'lang_tag', 'language', 'lang_tag');
|
||||||
|
select col_type_is('payment_customer', 'lang_tag', 'text');
|
||||||
|
select col_not_null('payment_customer', 'lang_tag');
|
||||||
|
select col_hasnt_default('payment_customer', 'lang_tag');
|
||||||
|
|
||||||
|
|
||||||
select *
|
select *
|
||||||
from finish();
|
from finish();
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
-- Test ready_payment
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(15);
|
||||||
|
|
||||||
|
set search_path to camper, public;
|
||||||
|
|
||||||
|
select has_function('camper', 'ready_payment', array['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean']);
|
||||||
|
select function_lang_is('camper', 'ready_payment', array['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'plpgsql');
|
||||||
|
select function_returns('camper', 'ready_payment', array['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'integer');
|
||||||
|
select isnt_definer('camper', 'ready_payment', array['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean']);
|
||||||
|
select volatility_is('camper', 'ready_payment', array['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'volatile');
|
||||||
|
select function_privs_are('camper', 'ready_payment', array ['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'guest', array['EXECUTE']);
|
||||||
|
select function_privs_are('camper', 'ready_payment', array ['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'employee', array['EXECUTE']);
|
||||||
|
select function_privs_are('camper', 'ready_payment', array ['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'admin', array['EXECUTE']);
|
||||||
|
select function_privs_are('camper', 'ready_payment', array ['uuid', 'text', 'text', 'text', 'text', 'country_code', 'email', 'text', 'text', 'boolean'], 'authenticator', array[]::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_customer cascade;
|
||||||
|
truncate payment cascade;
|
||||||
|
truncate campsite_type cascade;
|
||||||
|
truncate media cascade;
|
||||||
|
truncate media_content cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 350, 'ES', 'EUR', 'ca')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into media_content (media_type, bytes)
|
||||||
|
values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into media (media_id, company_id, original_filename, content_hash)
|
||||||
|
values (10, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into campsite_type (campsite_type_id, slug, company_id, name, media_id, max_campers, bookable_nights, overflow_allowed)
|
||||||
|
values (12, 'c1b6f4fc-32c1-4cd5-b796-0c5059152a52', 2, 'Plots', 10, 6, '[1, 7]', true)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment (payment_id, slug, company_id, campsite_type_id, arrival_date, departure_date, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total, zone_preferences, payment_status, created_at, updated_at)
|
||||||
|
values (22, '4ef35e2f-ef98-42d6-a724-913bd761ca8c', 2, 12, '2024-08-28', '2024-09-04', 3200, 2, 10420, 4, 20840, 6, 25080, 3, 2450, 4900, 79160, 'pref I before E', 'draft', '2024-01-01 01:01:01', '2024-01-01')
|
||||||
|
, (24, '6d1b8e4c-c3c6-4fe4-92c1-2cbf94526693', 2, 12, '2024-08-29', '2024-09-03', 71000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 72750, '', 'draft', current_timestamp, current_timestamp)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_customer (payment_id, full_name, address, postal_code, city, country_code, email, phone, acsi_card, lang_tag)
|
||||||
|
values (24, '', '', '', '', 'FR', 'a@a.com', '555-555-555', true, 'es')
|
||||||
|
;
|
||||||
|
|
||||||
|
select is(
|
||||||
|
ready_payment('4ef35e2f-ef98-42d6-a724-913bd761ca8c', 'Juli Verd', 'C/ Fals, 123', '17486', 'Castelló d’Empúries', 'ES', 'juli@verd.cat', '972486 160', 'ca', true),
|
||||||
|
22,
|
||||||
|
'Should be able to ready the first draft payment'
|
||||||
|
);
|
||||||
|
|
||||||
|
select is(
|
||||||
|
ready_payment('6d1b8e4c-c3c6-4fe4-92c1-2cbf94526693', 'Pere Gil', 'Gutenbergstr. 9-13', '82178', 'Puchheim', 'DE', 'pere@gil.de', '8980902-0', 'en', false),
|
||||||
|
24,
|
||||||
|
'Should be able to ready the second draft payment, and update customer details'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok(
|
||||||
|
$$ select ready_payment('7ba7f0a5-d73d-4d6e-a9c4-3b88f2b2a357', 'Juli Verd', 'C/ Fals, 123', '17486', 'Castelló d’Empúries', 'ES', 'juli@verd.cat', '972 486 160', 'ca', true) $$,
|
||||||
|
'23514', 'insert or update on table "payment" violates check constraint "payment_is_draft"',
|
||||||
|
'Should not be able to ready an inexistent payment'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok(
|
||||||
|
$$ select ready_payment('4ef35e2f-ef98-42d6-a724-913bd761ca8c', 'Juli Verd', 'C/ Fals, 123', '17486', 'Castelló d’Empúries', 'ES', 'juli@verd.cat', '972 486 160', 'ca', true) $$,
|
||||||
|
'23514', 'insert or update on table "payment" violates check constraint "payment_is_draft"',
|
||||||
|
'Should not be able to ready an already processed payment'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_id, slug::text, company_id, campsite_type_id, arrival_date::text, departure_date::text, subtotal_nights, number_adults, subtotal_adults, number_teenagers, subtotal_teenagers, number_children, subtotal_children, number_dogs, subtotal_dogs, subtotal_tourist_tax, total, zone_preferences, payment_status, created_at, updated_at from payment $$,
|
||||||
|
$$ values (22, '4ef35e2f-ef98-42d6-a724-913bd761ca8c', 2, 12, '2024-08-28', '2024-09-04', 3200, 2, 10420, 4, 20840, 6, 25080, 3, 2450, 4900, 79160, 'pref I before E', 'pending', '2024-01-01 01:01:01', current_timestamp)
|
||||||
|
, (24, '6d1b8e4c-c3c6-4fe4-92c1-2cbf94526693', 2, 12, '2024-08-29', '2024-09-03', 71000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 72750, '', 'pending', current_timestamp, current_timestamp)
|
||||||
|
$$,
|
||||||
|
'Should have updated payments'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_id, full_name, address, postal_code, city, country_code::text, email::text, phone::text, acsi_card, lang_tag from payment_customer $$,
|
||||||
|
$$ values (22, 'Juli Verd', 'C/ Fals, 123', '17486', 'Castelló d’Empúries', 'ES', 'juli@verd.cat', '+34 972 48 61 60', true, 'ca')
|
||||||
|
, (24, 'Pere Gil', 'Gutenbergstr. 9-13', '82178', 'Puchheim', 'DE', 'pere@gil.de', '+49 89 809020', false, 'en')
|
||||||
|
$$,
|
||||||
|
'Should have added and updated customer details'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -11,6 +11,7 @@ select payment_id
|
||||||
, email
|
, email
|
||||||
, phone
|
, phone
|
||||||
, acsi_card
|
, acsi_card
|
||||||
|
, lang_tag
|
||||||
from camper.payment_customer
|
from camper.payment_customer
|
||||||
where false;
|
where false;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify camper:ready_payment on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('camper.ready_payment(uuid, text, text, text, text, camper.country_code, camper.email, text, text, boolean)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -140,6 +140,10 @@ p + p, dl + p {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialog:modal {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 4.2rem;
|
font-size: 4.2rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
@ -1526,6 +1530,16 @@ input[type="checkbox"]:focus {
|
||||||
width: 4.8rem;
|
width: 4.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dl.payment-details div {
|
||||||
|
flex-basis: unset;
|
||||||
|
min-height: unset;
|
||||||
|
padding: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.payment-details dt {
|
||||||
|
padding: unset;
|
||||||
|
}
|
||||||
|
|
||||||
body > footer {
|
body > footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -1812,7 +1826,6 @@ dt {
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.services_icon::before {
|
.services_icon::before {
|
||||||
content: '';
|
content: '';
|
||||||
background: var(--accent-2);
|
background: var(--accent-2);
|
||||||
|
@ -1825,17 +1838,41 @@ dt {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
.services_icon:hover::before {
|
|
||||||
background: var(--accent-2);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.services_icon a {
|
.services_icon a {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
text-decoration: var(--accent) wavy underline;
|
text-decoration: var(--accent) wavy underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*<editor-fold desc="redirect dialog">*/
|
||||||
|
|
||||||
|
dialog.redirect:modal {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.redirect::before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
width: 2.4rem;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border: 3px solid var(--contrast);
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: rotation linear 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation {
|
||||||
|
from {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*</editor-fold>*/
|
||||||
|
|
||||||
[x-cloak] {
|
[x-cloak] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/payment.Payment*/ -}}
|
||||||
|
<dl class="payment-details">
|
||||||
|
<div>
|
||||||
|
<dt>{{( pgettext "Order Number" "title" )}}</dt>
|
||||||
|
<dd>{{ .OrderNumber }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt>{{( pgettext "Date" "title" )}}</dt>
|
||||||
|
<dd>{{ .CreateTime | formatDate }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt>{{( pgettext "Total" "title" )}}</dt>
|
||||||
|
<dd>{{ .Total | formatPrice }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
|
@ -7,6 +7,8 @@
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{ define "content" -}}
|
{{ define "content" -}}
|
||||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}}
|
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/payment.failedPaymentPage*/ -}}
|
||||||
<h2>{{( pgettext "Payment Failed" "title" )}}</h2>
|
<h2>{{ template "title" . }}</h2>
|
||||||
|
<p>{{( gettext "We could not process the payment. Please, contact us for support." )}}</p>
|
||||||
|
{{ template "details.gohtml" .Payment }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -3,24 +3,31 @@
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
{{ define "title" -}}
|
{{ define "title" -}}
|
||||||
{{( pgettext "Payment" "title" )}}
|
{{( pgettext "Booking Payment" "title" )}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "head" -}}
|
||||||
|
{{ template "alpineScript" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{ define "content" -}}
|
{{ define "content" -}}
|
||||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.paymentPage*/ -}}
|
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/payment.paymentPage*/ -}}
|
||||||
<h2>{{( pgettext "Payment" "title" )}}</h2>
|
<h2>{{ template "title" . }}</h2>
|
||||||
|
{{ template "details.gohtml" .Payment }}
|
||||||
{{ with .Request -}}
|
{{ with .Request -}}
|
||||||
<form
|
<p>{{( gettext "Thank you for your booking. Please, click the button below to pay with a credit card via Servired/Redsys.")}}</p>
|
||||||
{{ if eq $.Environment "live" -}}
|
<form id="payment" method="post" x-init="$el.submit()"
|
||||||
action="https://sis.redsys.es/sis/realizarPago"
|
{{- if eq $.Environment "live" }} action="https://sis.redsys.es/sis/realizarPago"
|
||||||
{{- else -}}
|
{{- else }} action="https://sis-t.redsys.es:25443/sis/realizarPago"
|
||||||
action="https://sis-t.redsys.es:25443/sis/realizarPago"
|
{{- end -}}
|
||||||
{{- end }}
|
>
|
||||||
method="post">
|
|
||||||
<input type="hidden" name="Ds_MerchantParameters" value="{{ .MerchantParameters }}"/>
|
<input type="hidden" name="Ds_MerchantParameters" value="{{ .MerchantParameters }}"/>
|
||||||
<input type="hidden" name="Ds_Signature" value="{{ .Signature }}"/>
|
<input type="hidden" name="Ds_Signature" value="{{ .Signature }}"/>
|
||||||
<input type="hidden" name="Ds_SignatureVersion" value="{{ .SignatureVersion }}"/>
|
<input type="hidden" name="Ds_SignatureVersion" value="{{ .SignatureVersion }}"/>
|
||||||
<button type="submit">{{( pgettext "Pay" "action" )}}</button>
|
<button type="submit">{{( pgettext "Pay with credit card" "action" )}}</button>
|
||||||
</form>
|
</form>
|
||||||
|
<dialog class="redirect" x-init="$el.showModal()">
|
||||||
|
<p>{{( gettext "Please, wait until we redirect you to the payment page.")}}</p>
|
||||||
|
</dialog>
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{ define "content" -}}
|
{{ define "content" -}}
|
||||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.failedPaymentPage*/ -}}
|
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/payment.successfulPaymentPage*/ -}}
|
||||||
<h2>{{( pgettext "Payment Successful" "title" )}}</h2>
|
<h2>{{ template "title" . }}</h2>
|
||||||
|
<p>{{( gettext "We have received the payment. Thank you." )}}</p>
|
||||||
|
{{ template "details.gohtml" .Payment }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
Loading…
Reference in New Issue