From bd84df816923d216b61273a2ca0aa81fb6248226 Mon Sep 17 00:00:00 2001
From: jordi fita mas
Date: Tue, 13 Feb 2024 23:45:25 +0100
Subject: [PATCH] Add down payment
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Customer wants to require a down payment of 30 % for bookings made
one week or more before the actual date, and to make the full payment
otherwise.
This would require yet another relation to keep these values. Fuck it;
i added them to the function, as they are very unlikely to change.
That forced me to change the test for draft_payment to use relative
dates, otherwise there is no way i can have stable results in the
future.
---
deploy/down_payment.sql | 23 ++++++
deploy/draft_payment.sql | 5 ++
deploy/payment.sql | 2 +
deploy/percentage.sql | 14 ++++
pkg/booking/cart.go | 27 ++++++-
pkg/payment/public.go | 16 ++--
po/ca.po | 90 ++++++++++++---------
po/es.po | 90 ++++++++++++---------
po/fr.po | 90 ++++++++++++---------
revert/down_payment.sql | 7 ++
revert/percentage.sql | 7 ++
sqitch.plan | 4 +-
test/down_payment.sql | 76 +++++++++++++++++
test/draft_payment.sql | 34 ++++----
test/payment.sql | 8 +-
test/percentage.sql | 43 ++++++++++
verify/down_payment.sql | 7 ++
verify/payment.sql | 1 +
verify/percentage.sql | 7 ++
web/templates/mail/payment/body.gohtml | 4 +
web/templates/mail/payment/body.gotxt | 1 +
web/templates/public/booking/fields.gohtml | 6 ++
web/templates/public/payment/details.gohtml | 6 ++
23 files changed, 434 insertions(+), 134 deletions(-)
create mode 100644 deploy/down_payment.sql
create mode 100644 deploy/percentage.sql
create mode 100644 revert/down_payment.sql
create mode 100644 revert/percentage.sql
create mode 100644 test/down_payment.sql
create mode 100644 test/percentage.sql
create mode 100644 verify/down_payment.sql
create mode 100644 verify/percentage.sql
diff --git a/deploy/down_payment.sql b/deploy/down_payment.sql
new file mode 100644
index 0000000..1b03cbd
--- /dev/null
+++ b/deploy/down_payment.sql
@@ -0,0 +1,23 @@
+-- Deploy camper:down_payment to pg
+-- requires: roles
+-- requires: schema_camper
+-- requires: payment
+
+begin;
+
+set search_path to camper, public;
+
+create or replace function down_payment(p payment) returns integer as
+$$
+ select round(p.total * p.down_payment_percent)::integer;
+$$
+ language sql
+ stable
+;
+
+revoke execute on function down_payment(payment) from public;
+grant execute on function down_payment(payment) to guest;
+grant execute on function down_payment(payment) to employee;
+grant execute on function down_payment(payment) to admin;
+
+commit;
diff --git a/deploy/draft_payment.sql b/deploy/draft_payment.sql
index 1c3e4c6..e88863c 100644
--- a/deploy/draft_payment.sql
+++ b/deploy/draft_payment.sql
@@ -42,6 +42,7 @@ begin
, subtotal_dogs
, subtotal_tourist_tax
, total
+ , down_payment_percent
, zone_preferences
)
select coalesce(payment_slug, gen_random_uuid())
@@ -60,6 +61,7 @@ begin
, sum(case when num_dogs > 0 then coalesce(pet.cost_per_night, 0) else 0 end)::integer
, sum(tourist_tax * num_adults)::integer
, 0
+ , case when arrival_date - current_date >= 7 then 0.3 else 1.0 end
, coalesce(zone_preferences, '')
from generate_series(arrival_date, departure_date - 1, interval '1 day') as date(day)
left join season_calendar on season_range @> date.day::date
@@ -87,6 +89,7 @@ begin
, subtotal_dogs = excluded.subtotal_dogs
, subtotal_tourist_tax = excluded.subtotal_tourist_tax
, total = excluded.total
+ , down_payment_percent = excluded.down_payment_percent
, zone_preferences = excluded.zone_preferences
, updated_at = current_timestamp
returning *
@@ -134,6 +137,7 @@ begin
set total = subtotal_nights + subtotal_adults + subtotal_teenagers + subtotal_children + subtotal_dogs + subtotal_tourist_tax + coalesce(option.subtotal, 0)
from option
where payment_id = p.payment_id
+ returning total into p.total
;
else
delete
@@ -143,6 +147,7 @@ begin
update payment
set total = subtotal_nights + subtotal_adults + subtotal_teenagers + subtotal_children + subtotal_dogs + subtotal_tourist_tax
where payment_id = p.payment_id
+ returning total into p.total
;
end if;
diff --git a/deploy/payment.sql b/deploy/payment.sql
index 0dcfff1..74ce0c5 100644
--- a/deploy/payment.sql
+++ b/deploy/payment.sql
@@ -6,6 +6,7 @@
-- requires: payment_status
-- requires: positive_integer
-- requires: nonnegative_integer
+-- requires: percentage
begin;
@@ -29,6 +30,7 @@ create table payment (
subtotal_dogs nonnegative_integer not null,
subtotal_tourist_tax nonnegative_integer not null,
total nonnegative_integer not null,
+ down_payment_percent percentage not null default 1.0,
zone_preferences text not null,
payment_status text not null default 'draft' references payment_status,
created_at timestamp with time zone not null default current_timestamp,
diff --git a/deploy/percentage.sql b/deploy/percentage.sql
new file mode 100644
index 0000000..2cda0fa
--- /dev/null
+++ b/deploy/percentage.sql
@@ -0,0 +1,14 @@
+-- Deploy camper:percentage to pg
+-- requires: schema_camper
+
+begin;
+
+set search_path to camper, public;
+
+create domain percentage as numeric(3, 2)
+check( value >= 0 and value <= 1 )
+;
+
+comment on domain percentage is 'a positive percentage without decimals, but represented as numeric';
+
+commit;
diff --git a/pkg/booking/cart.go b/pkg/booking/cart.go
index e09411f..3ba9eb2 100644
--- a/pkg/booking/cart.go
+++ b/pkg/booking/cart.go
@@ -10,9 +10,10 @@ import (
)
type bookingCart struct {
- Lines []*cartLine
- Total string
- Enabled bool
+ Lines []*cartLine
+ Total string
+ DownPayment string
+ Enabled bool
}
type cartLine struct {
@@ -93,6 +94,7 @@ func newBookingCart(ctx context.Context, conn *database.Conn, f *bookingForm, ca
, to_price(subtotal_dogs, decimal_digits)
, to_price(subtotal_tourist_tax, decimal_digits)
, to_price(total, decimal_digits)
+ , to_price(payment.down_payment, decimal_digits)
from draft_payment($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) as payment
join company using (company_id)
join currency using (currency_code)
@@ -117,7 +119,20 @@ func newBookingCart(ctx context.Context, conn *database.Conn, f *bookingForm, ca
var dogs string
var touristTax string
var total string
- if err = row.Scan(&f.PaymentSlug.Val, &paymentID, &numNights, &nights, &adults, &teenagers, &children, &dogs, &touristTax, &total); err != nil {
+ var downPayment string
+ if err = row.Scan(
+ &f.PaymentSlug.Val,
+ &paymentID,
+ &numNights,
+ &nights,
+ &adults,
+ &teenagers,
+ &children,
+ &dogs,
+ &touristTax,
+ &total,
+ &downPayment,
+ ); err != nil {
if database.ErrorIsNotFound(err) {
return cart, nil
}
@@ -177,6 +192,10 @@ func newBookingCart(ctx context.Context, conn *database.Conn, f *bookingForm, ca
if total != "0.0" {
cart.Total = total
cart.Enabled = f.Guests.Error == nil
+
+ if downPayment != total {
+ cart.DownPayment = downPayment
+ }
}
return cart, nil
diff --git a/pkg/payment/public.go b/pkg/payment/public.go
index 26b5cbb..fdd5bf9 100644
--- a/pkg/payment/public.go
+++ b/pkg/payment/public.go
@@ -76,6 +76,7 @@ func fetchPayment(ctx context.Context, conn *database.Conn, paymentSlug string)
, payment.slug::text
, payment.created_at
, to_price(total, decimal_digits)
+ , to_price(payment.down_payment, decimal_digits)
from payment
join company using (company_id)
join currency using (currency_code)
@@ -83,17 +84,18 @@ func fetchPayment(ctx context.Context, conn *database.Conn, paymentSlug string)
and payment_status <> 'draft'
`, paymentSlug)
payment := &Payment{}
- if err := row.Scan(&payment.ID, &payment.Slug, &payment.CreateTime, &payment.Total); err != nil {
+ if err := row.Scan(&payment.ID, &payment.Slug, &payment.CreateTime, &payment.Total, &payment.DownPayment); err != nil {
return nil, err
}
return payment, nil
}
type Payment struct {
- ID int
- Slug string
- Total string
- CreateTime time.Time
+ ID int
+ Slug string
+ Total string
+ DownPayment string
+ CreateTime time.Time
}
func (payment *Payment) createRequest(r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) (*redsys.SignedRequest, error) {
@@ -102,7 +104,7 @@ func (payment *Payment) createRequest(r *http.Request, user *auth.User, company
baseURL := fmt.Sprintf("%s://%s/%s/payments/%s", schema, authority, user.Locale.Language, payment.Slug)
request := redsys.Request{
TransactionType: redsys.TransactionTypeCharge,
- Amount: payment.Total,
+ Amount: payment.DownPayment,
OrderNumber: payment.OrderNumber(),
Product: user.Locale.Pgettext("Campsite Booking", "order product name"),
SuccessURL: fmt.Sprintf("%s/success", baseURL),
@@ -269,6 +271,7 @@ type CompletedEmail struct {
ArrivalDate string
DepartureDate string
Total string
+ DownPayment string
CompanyAddress *address
}
@@ -286,6 +289,7 @@ func sendEmail(ctx context.Context, conn *database.Conn, payment *Payment, compa
CurrentLocale: locale.Language.String(),
PaymentReference: payment.OrderNumber(),
Total: template.FormatPrice(payment.Total, locale.Language, locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol),
+ DownPayment: template.FormatPrice(payment.DownPayment, locale.Language, locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol),
CompanyAddress: &address{},
}
diff --git a/po/ca.po b/po/ca.po
index 0c53830..65fe5de 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
-"POT-Creation-Date: 2024-02-13 05:09+0100\n"
+"POT-Creation-Date: 2024-02-13 23:38+0100\n"
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
"Last-Translator: jordi fita mas \n"
"Language-Team: Catalan \n"
@@ -95,7 +95,11 @@ msgid "Total: %s"
msgstr "Total: %s"
#: web/templates/mail/payment/body.gohtml:48
-#: web/templates/mail/payment/body.gotxt:11
+msgid "Down payment: %s"
+msgstr "A compte: %s"
+
+#: web/templates/mail/payment/body.gohtml:52
+#: web/templates/mail/payment/body.gotxt:12
msgid "Thank you for your booking, and see you soon!"
msgstr "Moltes gràcies per la reserva i fins aviat!"
@@ -119,6 +123,10 @@ msgstr "Data de sortida: **%s**"
msgid "Total: **%s**"
msgstr "Total: **%s**"
+#: web/templates/mail/payment/body.gotxt:10
+msgid "Down payment: **%s**"
+msgstr "A compte: **%s**"
+
#: web/templates/public/payment/success.gohtml:6
msgctxt "title"
msgid "Payment Successful"
@@ -170,6 +178,11 @@ msgctxt "title"
msgid "Total"
msgstr "Total"
+#: web/templates/public/payment/details.gohtml:17
+msgctxt "title"
+msgid "Down Payment"
+msgstr "A compte"
+
#: web/templates/public/services.gohtml:7
#: web/templates/public/services.gohtml:16
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
@@ -243,7 +256,7 @@ msgid "Discover"
msgstr "Descobreix"
#: web/templates/public/campsite/type.gohtml:49
-#: web/templates/public/booking/fields.gohtml:245
+#: web/templates/public/booking/fields.gohtml:256
msgctxt "action"
msgid "Book"
msgstr "Reserva"
@@ -366,13 +379,13 @@ msgid "Sun"
msgstr "dg"
#: web/templates/public/campsite/dates.gohtml:4
-#: web/templates/public/booking/fields.gohtml:28
+#: web/templates/public/booking/fields.gohtml:29
msgctxt "input"
msgid "Arrival date"
msgstr "Data d’arribada"
#: web/templates/public/campsite/dates.gohtml:15
-#: web/templates/public/booking/fields.gohtml:39
+#: web/templates/public/booking/fields.gohtml:40
msgctxt "input"
msgid "Departure date"
msgstr "Data de sortida"
@@ -629,121 +642,126 @@ msgstr "Obertura"
msgid "RTC #%s"
msgstr "Núm. RTC %s"
-#: web/templates/public/booking/fields.gohtml:15
+#: web/templates/public/booking/fields.gohtml:14
msgctxt "title"
msgid "Accommodation"
msgstr "Allotjaments"
-#: web/templates/public/booking/fields.gohtml:25
+#: web/templates/public/booking/fields.gohtml:26
msgctxt "title"
msgid "Booking Period"
msgstr "Període de reserva"
-#: web/templates/public/booking/fields.gohtml:52
+#: web/templates/public/booking/fields.gohtml:55
msgctxt "title"
msgid "Guests"
msgstr "Hostes"
-#: web/templates/public/booking/fields.gohtml:56
+#: web/templates/public/booking/fields.gohtml:59
msgctxt "input"
msgid "Adults aged 17 or older"
msgstr "Adults de 17 anys o més"
-#: web/templates/public/booking/fields.gohtml:67
+#: web/templates/public/booking/fields.gohtml:70
msgctxt "input"
msgid "Teenagers from 11 to 16 years old"
msgstr "Adolescents d’entre 11 i 16 anys"
-#: web/templates/public/booking/fields.gohtml:78
+#: web/templates/public/booking/fields.gohtml:81
msgctxt "input"
msgid "Children from 2 to 10 years old"
msgstr "Nens d’entre 2 i 10 anys)"
-#: web/templates/public/booking/fields.gohtml:88
+#: web/templates/public/booking/fields.gohtml:91
msgid "Note: Due to guest capacity, we have added more accomodations to the booking, but we cannot guarantee that they will be next to each other."
msgstr "Nota: S’han afegit més allotjaments a la reserva degut a la capacitat de cadascuna, però no es garanteix que estiguin de costat."
-#: web/templates/public/booking/fields.gohtml:96
+#: web/templates/public/booking/fields.gohtml:99
msgctxt "input"
msgid "Dogs"
msgstr "Gossos"
-#: web/templates/public/booking/fields.gohtml:105
+#: web/templates/public/booking/fields.gohtml:108
msgid "Note: This accommodation does not allow dogs."
msgstr "Nota: A aquest allotjament no s’hi permeten gossos."
-#: web/templates/public/booking/fields.gohtml:115
+#: web/templates/public/booking/fields.gohtml:120
msgctxt "input"
msgid "Area preferences (optional)"
msgstr "Preferències d’àrea (opcional)"
-#: web/templates/public/booking/fields.gohtml:117
+#: web/templates/public/booking/fields.gohtml:122
msgid "Campground map"
msgstr "Mapa del càmping"
-#: web/templates/public/booking/fields.gohtml:140
+#: web/templates/public/booking/fields.gohtml:145
msgctxt "title"
msgid "Customer Details"
msgstr "Detalls del client"
-#: web/templates/public/booking/fields.gohtml:143
+#: web/templates/public/booking/fields.gohtml:148
msgctxt "input"
msgid "Full name"
msgstr "Nom i cognoms"
-#: web/templates/public/booking/fields.gohtml:152
+#: web/templates/public/booking/fields.gohtml:157
msgctxt "input"
msgid "Address (optional)"
msgstr "Adreça (opcional)"
-#: web/templates/public/booking/fields.gohtml:161
+#: web/templates/public/booking/fields.gohtml:166
msgctxt "input"
msgid "Postcode (optional)"
msgstr "Codi postal (opcional)"
-#: web/templates/public/booking/fields.gohtml:170
+#: web/templates/public/booking/fields.gohtml:175
msgctxt "input"
msgid "Town or village (optional)"
msgstr "Població (opcional)"
-#: web/templates/public/booking/fields.gohtml:179
+#: web/templates/public/booking/fields.gohtml:184
#: web/templates/admin/taxDetails.gohtml:101
msgctxt "input"
msgid "Country"
msgstr "País"
-#: web/templates/public/booking/fields.gohtml:182
+#: web/templates/public/booking/fields.gohtml:187
msgid "Choose a country"
msgstr "Esculli un país"
-#: web/templates/public/booking/fields.gohtml:190
+#: web/templates/public/booking/fields.gohtml:195
#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38
#: web/templates/admin/taxDetails.gohtml:53
msgctxt "input"
msgid "Email"
msgstr "Correu-e"
-#: web/templates/public/booking/fields.gohtml:199
+#: web/templates/public/booking/fields.gohtml:204
#: web/templates/admin/taxDetails.gohtml:45
msgctxt "input"
msgid "Phone"
msgstr "Telèfon"
-#: web/templates/public/booking/fields.gohtml:210
+#: web/templates/public/booking/fields.gohtml:215
msgctxt "input"
msgid "ACSI card? (optional)"
msgstr "Targeta ACSI? (opcional)"
-#: web/templates/public/booking/fields.gohtml:217
+#: web/templates/public/booking/fields.gohtml:222
msgctxt "input"
msgid "I have read and I accept %[1]sthe reservation conditions%[2]s"
msgstr "He llegit i accepto %[1]sles condicions de reserves%[2]s"
-#: web/templates/public/booking/fields.gohtml:234
+#: web/templates/public/booking/fields.gohtml:239
msgctxt "cart"
msgid "Total"
msgstr "Total"
+#: web/templates/public/booking/fields.gohtml:244
+msgctxt "cart"
+msgid "Down payment"
+msgstr "A compte"
+
#: web/templates/admin/legal/form.gohtml:8
#: web/templates/admin/legal/form.gohtml:29
msgctxt "title"
@@ -2039,12 +2057,12 @@ msgstr "Estat"
msgid "No booking found."
msgstr "No s’ha trobat cap reserva."
-#: pkg/payment/public.go:107
+#: pkg/payment/public.go:109
msgctxt "order product name"
msgid "Campsite Booking"
msgstr "Reserva de càmping"
-#: pkg/payment/public.go:344
+#: pkg/payment/public.go:346
msgctxt "subject"
msgid "Booking payment successfully received"
msgstr "Rebut amb èxit el pagament de la reserva"
@@ -2545,32 +2563,32 @@ msgstr "No podeu deixar el fitxer del mèdia en blanc."
msgid "Filename can not be empty."
msgstr "No podeu deixar el nom del fitxer en blanc."
-#: pkg/booking/cart.go:144
+#: pkg/booking/cart.go:151
msgctxt "cart"
msgid "Night"
msgstr "Nit"
-#: pkg/booking/cart.go:145
+#: pkg/booking/cart.go:152
msgctxt "cart"
msgid "Adult"
msgstr "Adult"
-#: pkg/booking/cart.go:146
+#: pkg/booking/cart.go:153
msgctxt "cart"
msgid "Teenager"
msgstr "Adolescent"
-#: pkg/booking/cart.go:147
+#: pkg/booking/cart.go:154
msgctxt "cart"
msgid "Child"
msgstr "Nen"
-#: pkg/booking/cart.go:148
+#: pkg/booking/cart.go:155
msgctxt "cart"
msgid "Dog"
msgstr "Gos"
-#: pkg/booking/cart.go:183
+#: pkg/booking/cart.go:190
msgctxt "cart"
msgid "Tourist tax"
msgstr "Impost turístic"
diff --git a/po/es.po b/po/es.po
index f9e5c02..c28cf2d 100644
--- a/po/es.po
+++ b/po/es.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
-"POT-Creation-Date: 2024-02-13 05:09+0100\n"
+"POT-Creation-Date: 2024-02-13 23:38+0100\n"
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
"Last-Translator: jordi fita mas \n"
"Language-Team: Spanish \n"
@@ -95,7 +95,11 @@ msgid "Total: %s"
msgstr "Total: %s"
#: web/templates/mail/payment/body.gohtml:48
-#: web/templates/mail/payment/body.gotxt:11
+msgid "Down payment: %s"
+msgstr "A cuenta: %s"
+
+#: web/templates/mail/payment/body.gohtml:52
+#: web/templates/mail/payment/body.gotxt:12
msgid "Thank you for your booking, and see you soon!"
msgstr "Gracias por su reserva y ¡hasta pronto!"
@@ -119,6 +123,10 @@ msgstr "Fecha de salida: **%s**"
msgid "Total: **%s**"
msgstr "Total: **%s**"
+#: web/templates/mail/payment/body.gotxt:10
+msgid "Down payment: **%s**"
+msgstr "A cuenta: **%s**"
+
#: web/templates/public/payment/success.gohtml:6
msgctxt "title"
msgid "Payment Successful"
@@ -170,6 +178,11 @@ msgctxt "title"
msgid "Total"
msgstr "Total"
+#: web/templates/public/payment/details.gohtml:17
+msgctxt "title"
+msgid "Down Payment"
+msgstr "A cuenta"
+
#: web/templates/public/services.gohtml:7
#: web/templates/public/services.gohtml:16
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
@@ -243,7 +256,7 @@ msgid "Discover"
msgstr "Descubre"
#: web/templates/public/campsite/type.gohtml:49
-#: web/templates/public/booking/fields.gohtml:245
+#: web/templates/public/booking/fields.gohtml:256
msgctxt "action"
msgid "Book"
msgstr "Reservar"
@@ -366,13 +379,13 @@ msgid "Sun"
msgstr "do"
#: web/templates/public/campsite/dates.gohtml:4
-#: web/templates/public/booking/fields.gohtml:28
+#: web/templates/public/booking/fields.gohtml:29
msgctxt "input"
msgid "Arrival date"
msgstr "Fecha de llegada"
#: web/templates/public/campsite/dates.gohtml:15
-#: web/templates/public/booking/fields.gohtml:39
+#: web/templates/public/booking/fields.gohtml:40
msgctxt "input"
msgid "Departure date"
msgstr "Fecha de salida"
@@ -629,121 +642,126 @@ msgstr "Apertura"
msgid "RTC #%s"
msgstr "Nº RTC %s"
-#: web/templates/public/booking/fields.gohtml:15
+#: web/templates/public/booking/fields.gohtml:14
msgctxt "title"
msgid "Accommodation"
msgstr "Alojamientos"
-#: web/templates/public/booking/fields.gohtml:25
+#: web/templates/public/booking/fields.gohtml:26
msgctxt "title"
msgid "Booking Period"
msgstr "Periodo de reserva"
-#: web/templates/public/booking/fields.gohtml:52
+#: web/templates/public/booking/fields.gohtml:55
msgctxt "title"
msgid "Guests"
msgstr "Huéspedes"
-#: web/templates/public/booking/fields.gohtml:56
+#: web/templates/public/booking/fields.gohtml:59
msgctxt "input"
msgid "Adults aged 17 or older"
msgstr "Adultos de 17 años o más"
-#: web/templates/public/booking/fields.gohtml:67
+#: web/templates/public/booking/fields.gohtml:70
msgctxt "input"
msgid "Teenagers from 11 to 16 years old"
msgstr "Adolescentes de 11 a 16 años"
-#: web/templates/public/booking/fields.gohtml:78
+#: web/templates/public/booking/fields.gohtml:81
msgctxt "input"
msgid "Children from 2 to 10 years old"
msgstr "Niños de 2 a 10 años"
-#: web/templates/public/booking/fields.gohtml:88
+#: web/templates/public/booking/fields.gohtml:91
msgid "Note: Due to guest capacity, we have added more accomodations to the booking, but we cannot guarantee that they will be next to each other."
msgstr "Nota: Se han añadido alojamientos a la reserva debido a la capacidad de cada una, pero no se garantiza que estén de lado."
-#: web/templates/public/booking/fields.gohtml:96
+#: web/templates/public/booking/fields.gohtml:99
msgctxt "input"
msgid "Dogs"
msgstr "Perros"
-#: web/templates/public/booking/fields.gohtml:105
+#: web/templates/public/booking/fields.gohtml:108
msgid "Note: This accommodation does not allow dogs."
msgstr "Nota: En este alojamiento no se permiten perros."
-#: web/templates/public/booking/fields.gohtml:115
+#: web/templates/public/booking/fields.gohtml:120
msgctxt "input"
msgid "Area preferences (optional)"
msgstr "Preferencias de área (opcional)"
-#: web/templates/public/booking/fields.gohtml:117
+#: web/templates/public/booking/fields.gohtml:122
msgid "Campground map"
msgstr "Mapa del camping"
-#: web/templates/public/booking/fields.gohtml:140
+#: web/templates/public/booking/fields.gohtml:145
msgctxt "title"
msgid "Customer Details"
msgstr "Detalles del cliente"
-#: web/templates/public/booking/fields.gohtml:143
+#: web/templates/public/booking/fields.gohtml:148
msgctxt "input"
msgid "Full name"
msgstr "Nombre y apellidos"
-#: web/templates/public/booking/fields.gohtml:152
+#: web/templates/public/booking/fields.gohtml:157
msgctxt "input"
msgid "Address (optional)"
msgstr "Dirección (opcional)"
-#: web/templates/public/booking/fields.gohtml:161
+#: web/templates/public/booking/fields.gohtml:166
msgctxt "input"
msgid "Postcode (optional)"
msgstr "Código postal (opcional)"
-#: web/templates/public/booking/fields.gohtml:170
+#: web/templates/public/booking/fields.gohtml:175
msgctxt "input"
msgid "Town or village (optional)"
msgstr "Población (opcional)"
-#: web/templates/public/booking/fields.gohtml:179
+#: web/templates/public/booking/fields.gohtml:184
#: web/templates/admin/taxDetails.gohtml:101
msgctxt "input"
msgid "Country"
msgstr "País"
-#: web/templates/public/booking/fields.gohtml:182
+#: web/templates/public/booking/fields.gohtml:187
msgid "Choose a country"
msgstr "Escoja un país"
-#: web/templates/public/booking/fields.gohtml:190
+#: web/templates/public/booking/fields.gohtml:195
#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38
#: web/templates/admin/taxDetails.gohtml:53
msgctxt "input"
msgid "Email"
msgstr "Correo-e"
-#: web/templates/public/booking/fields.gohtml:199
+#: web/templates/public/booking/fields.gohtml:204
#: web/templates/admin/taxDetails.gohtml:45
msgctxt "input"
msgid "Phone"
msgstr "Teléfono"
-#: web/templates/public/booking/fields.gohtml:210
+#: web/templates/public/booking/fields.gohtml:215
msgctxt "input"
msgid "ACSI card? (optional)"
msgstr "¿Tarjeta ACSI? (opcional)"
-#: web/templates/public/booking/fields.gohtml:217
+#: web/templates/public/booking/fields.gohtml:222
msgctxt "input"
msgid "I have read and I accept %[1]sthe reservation conditions%[2]s"
msgstr "He leído y acepto %[1]slas condiciones de reserva%[2]s"
-#: web/templates/public/booking/fields.gohtml:234
+#: web/templates/public/booking/fields.gohtml:239
msgctxt "cart"
msgid "Total"
msgstr "Total"
+#: web/templates/public/booking/fields.gohtml:244
+msgctxt "cart"
+msgid "Down payment"
+msgstr "A cuenta"
+
#: web/templates/admin/legal/form.gohtml:8
#: web/templates/admin/legal/form.gohtml:29
msgctxt "title"
@@ -2039,12 +2057,12 @@ msgstr "Estado"
msgid "No booking found."
msgstr "No se ha encontrado ninguna reserva."
-#: pkg/payment/public.go:107
+#: pkg/payment/public.go:109
msgctxt "order product name"
msgid "Campsite Booking"
msgstr "Reserva de camping"
-#: pkg/payment/public.go:344
+#: pkg/payment/public.go:346
msgctxt "subject"
msgid "Booking payment successfully received"
msgstr "Se ha recibido correctamente el pago de la reserva"
@@ -2545,32 +2563,32 @@ msgstr "No podéis dejar el archivo del medio en blanco."
msgid "Filename can not be empty."
msgstr "No podéis dejar el nombre del archivo en blanco."
-#: pkg/booking/cart.go:144
+#: pkg/booking/cart.go:151
msgctxt "cart"
msgid "Night"
msgstr "Noche"
-#: pkg/booking/cart.go:145
+#: pkg/booking/cart.go:152
msgctxt "cart"
msgid "Adult"
msgstr "Adulto"
-#: pkg/booking/cart.go:146
+#: pkg/booking/cart.go:153
msgctxt "cart"
msgid "Teenager"
msgstr "Adolescente"
-#: pkg/booking/cart.go:147
+#: pkg/booking/cart.go:154
msgctxt "cart"
msgid "Child"
msgstr "Niño"
-#: pkg/booking/cart.go:148
+#: pkg/booking/cart.go:155
msgctxt "cart"
msgid "Dog"
msgstr "Perro"
-#: pkg/booking/cart.go:183
+#: pkg/booking/cart.go:190
msgctxt "cart"
msgid "Tourist tax"
msgstr "Impuesto turístico"
diff --git a/po/fr.po b/po/fr.po
index 455f3c3..15e07b8 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
-"POT-Creation-Date: 2024-02-13 05:02+0100\n"
+"POT-Creation-Date: 2024-02-13 23:38+0100\n"
"PO-Revision-Date: 2024-02-06 10:05+0100\n"
"Last-Translator: Oriol Carbonell \n"
"Language-Team: French \n"
@@ -95,7 +95,11 @@ msgid "Total: %s"
msgstr "Totale : %s"
#: web/templates/mail/payment/body.gohtml:48
-#: web/templates/mail/payment/body.gotxt:11
+msgid "Down payment: %s"
+msgstr "Acompte : %s"
+
+#: web/templates/mail/payment/body.gohtml:52
+#: web/templates/mail/payment/body.gotxt:12
msgid "Thank you for your booking, and see you soon!"
msgstr "Merci pour votre réservation et à bientôt !"
@@ -119,6 +123,10 @@ msgstr "Date de depart : **%s**"
msgid "Total: **%s**"
msgstr "Totale : **%s**"
+#: web/templates/mail/payment/body.gotxt:10
+msgid "Down payment: **%s**"
+msgstr "Acompte : **%s**"
+
#: web/templates/public/payment/success.gohtml:6
msgctxt "title"
msgid "Payment Successful"
@@ -170,6 +178,11 @@ msgctxt "title"
msgid "Total"
msgstr "Totale"
+#: web/templates/public/payment/details.gohtml:17
+msgctxt "title"
+msgid "Down Payment"
+msgstr "Acompte"
+
#: web/templates/public/services.gohtml:7
#: web/templates/public/services.gohtml:16
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
@@ -243,7 +256,7 @@ msgid "Discover"
msgstr "Découvrir"
#: web/templates/public/campsite/type.gohtml:49
-#: web/templates/public/booking/fields.gohtml:245
+#: web/templates/public/booking/fields.gohtml:256
msgctxt "action"
msgid "Book"
msgstr "Réserver"
@@ -366,13 +379,13 @@ msgid "Sun"
msgstr "Dim."
#: web/templates/public/campsite/dates.gohtml:4
-#: web/templates/public/booking/fields.gohtml:28
+#: web/templates/public/booking/fields.gohtml:29
msgctxt "input"
msgid "Arrival date"
msgstr "Date d’arrivée"
#: web/templates/public/campsite/dates.gohtml:15
-#: web/templates/public/booking/fields.gohtml:39
+#: web/templates/public/booking/fields.gohtml:40
msgctxt "input"
msgid "Departure date"
msgstr "Date de depart"
@@ -629,121 +642,126 @@ msgstr "Ouverture"
msgid "RTC #%s"
msgstr "# RTC %s"
-#: web/templates/public/booking/fields.gohtml:15
+#: web/templates/public/booking/fields.gohtml:14
msgctxt "title"
msgid "Accommodation"
msgstr "Hébergement"
-#: web/templates/public/booking/fields.gohtml:25
+#: web/templates/public/booking/fields.gohtml:26
msgctxt "title"
msgid "Booking Period"
msgstr "Période de réservation"
-#: web/templates/public/booking/fields.gohtml:52
+#: web/templates/public/booking/fields.gohtml:55
msgctxt "title"
msgid "Guests"
msgstr "Personnes logeant"
-#: web/templates/public/booking/fields.gohtml:56
+#: web/templates/public/booking/fields.gohtml:59
msgctxt "input"
msgid "Adults aged 17 or older"
msgstr "Adultes âgés 17 ans ou plus"
-#: web/templates/public/booking/fields.gohtml:67
+#: web/templates/public/booking/fields.gohtml:70
msgctxt "input"
msgid "Teenagers from 11 to 16 years old"
msgstr "Adolescents de 11 à 16 ans"
-#: web/templates/public/booking/fields.gohtml:78
+#: web/templates/public/booking/fields.gohtml:81
msgctxt "input"
msgid "Children from 2 to 10 years old"
msgstr "Enfants de 2 à 10 ans"
-#: web/templates/public/booking/fields.gohtml:88
+#: web/templates/public/booking/fields.gohtml:91
msgid "Note: Due to guest capacity, we have added more accomodations to the booking, but we cannot guarantee that they will be next to each other."
msgstr "Remarque : En raison de la capacité d’accueils, nous avons ajouté d’autres hébergements à la réservation, mais nous ne pouvons garantir qu’ils seront côte à côte."
-#: web/templates/public/booking/fields.gohtml:96
+#: web/templates/public/booking/fields.gohtml:99
msgctxt "input"
msgid "Dogs"
msgstr "Chiens"
-#: web/templates/public/booking/fields.gohtml:105
+#: web/templates/public/booking/fields.gohtml:108
msgid "Note: This accommodation does not allow dogs."
msgstr "Remarque : Dans cet hébergement les chiens ne sont pas acceptés."
-#: web/templates/public/booking/fields.gohtml:115
+#: web/templates/public/booking/fields.gohtml:120
msgctxt "input"
msgid "Area preferences (optional)"
msgstr "Préférences de zone (facultatif)"
-#: web/templates/public/booking/fields.gohtml:117
+#: web/templates/public/booking/fields.gohtml:122
msgid "Campground map"
msgstr "Plan du camping"
-#: web/templates/public/booking/fields.gohtml:140
+#: web/templates/public/booking/fields.gohtml:145
msgctxt "title"
msgid "Customer Details"
msgstr "Détails du client"
-#: web/templates/public/booking/fields.gohtml:143
+#: web/templates/public/booking/fields.gohtml:148
msgctxt "input"
msgid "Full name"
msgstr "Nom et prénom"
-#: web/templates/public/booking/fields.gohtml:152
+#: web/templates/public/booking/fields.gohtml:157
msgctxt "input"
msgid "Address (optional)"
msgstr "Adresse (Facultatif)"
-#: web/templates/public/booking/fields.gohtml:161
+#: web/templates/public/booking/fields.gohtml:166
msgctxt "input"
msgid "Postcode (optional)"
msgstr "Code postal (Facultatif)"
-#: web/templates/public/booking/fields.gohtml:170
+#: web/templates/public/booking/fields.gohtml:175
msgctxt "input"
msgid "Town or village (optional)"
msgstr "Ville (Facultatif)"
-#: web/templates/public/booking/fields.gohtml:179
+#: web/templates/public/booking/fields.gohtml:184
#: web/templates/admin/taxDetails.gohtml:101
msgctxt "input"
msgid "Country"
msgstr "Pays"
-#: web/templates/public/booking/fields.gohtml:182
+#: web/templates/public/booking/fields.gohtml:187
msgid "Choose a country"
msgstr "Choisissez un pays"
-#: web/templates/public/booking/fields.gohtml:190
+#: web/templates/public/booking/fields.gohtml:195
#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38
#: web/templates/admin/taxDetails.gohtml:53
msgctxt "input"
msgid "Email"
msgstr "E-mail"
-#: web/templates/public/booking/fields.gohtml:199
+#: web/templates/public/booking/fields.gohtml:204
#: web/templates/admin/taxDetails.gohtml:45
msgctxt "input"
msgid "Phone"
msgstr "Téléphone"
-#: web/templates/public/booking/fields.gohtml:210
+#: web/templates/public/booking/fields.gohtml:215
msgctxt "input"
msgid "ACSI card? (optional)"
msgstr "Carte ACSI ? (Facultatif)"
-#: web/templates/public/booking/fields.gohtml:217
+#: web/templates/public/booking/fields.gohtml:222
msgctxt "input"
msgid "I have read and I accept %[1]sthe reservation conditions%[2]s"
msgstr "J’ai lu et j’accepte %[1]sles conditions de réservation%[2]s"
-#: web/templates/public/booking/fields.gohtml:234
+#: web/templates/public/booking/fields.gohtml:239
msgctxt "cart"
msgid "Total"
msgstr "Totale"
+#: web/templates/public/booking/fields.gohtml:244
+msgctxt "cart"
+msgid "Down payment"
+msgstr "Acompte"
+
#: web/templates/admin/legal/form.gohtml:8
#: web/templates/admin/legal/form.gohtml:29
msgctxt "title"
@@ -2039,12 +2057,12 @@ msgstr "Statut"
msgid "No booking found."
msgstr "Aucune réservation trouvée."
-#: pkg/payment/public.go:107
+#: pkg/payment/public.go:109
msgctxt "order product name"
msgid "Campsite Booking"
msgstr "Réservation camping"
-#: pkg/payment/public.go:344
+#: pkg/payment/public.go:346
msgctxt "subject"
msgid "Booking payment successfully received"
msgstr "Paiement de réservation reçu avec succès"
@@ -2545,32 +2563,32 @@ msgstr "Le fichier téléchargé ne peut pas être vide."
msgid "Filename can not be empty."
msgstr "Le nom de fichier ne peut pas être vide."
-#: pkg/booking/cart.go:144
+#: pkg/booking/cart.go:151
msgctxt "cart"
msgid "Night"
msgstr "Nuit"
-#: pkg/booking/cart.go:145
+#: pkg/booking/cart.go:152
msgctxt "cart"
msgid "Adult"
msgstr "Adulte"
-#: pkg/booking/cart.go:146
+#: pkg/booking/cart.go:153
msgctxt "cart"
msgid "Teenager"
msgstr "Adolescent"
-#: pkg/booking/cart.go:147
+#: pkg/booking/cart.go:154
msgctxt "cart"
msgid "Child"
msgstr "Enfant"
-#: pkg/booking/cart.go:148
+#: pkg/booking/cart.go:155
msgctxt "cart"
msgid "Dog"
msgstr "Chien"
-#: pkg/booking/cart.go:183
+#: pkg/booking/cart.go:190
msgctxt "cart"
msgid "Tourist tax"
msgstr "Taxe touristique"
diff --git a/revert/down_payment.sql b/revert/down_payment.sql
new file mode 100644
index 0000000..bd3d38a
--- /dev/null
+++ b/revert/down_payment.sql
@@ -0,0 +1,7 @@
+-- Revert camper:down_payment from pg
+
+begin;
+
+drop function if exists camper.down_payment(camper.payment);
+
+commit;
diff --git a/revert/percentage.sql b/revert/percentage.sql
new file mode 100644
index 0000000..48e8a62
--- /dev/null
+++ b/revert/percentage.sql
@@ -0,0 +1,7 @@
+-- Revert camper:percentage from pg
+
+begin;
+
+drop domain if exists camper.percentage;
+
+commit;
diff --git a/sqitch.plan b/sqitch.plan
index 163b36e..6c2888b 100644
--- a/sqitch.plan
+++ b/sqitch.plan
@@ -245,7 +245,8 @@ payment_status [roles schema_camper] 2024-02-11T21:13:32Z jordi fita mas # Add relation for translation of payment status
available_payment_status [payment_status payment_status_i18n] 2024-02-11T21:22:38Z jordi fita mas # Add available payment statuses
positive_integer [schema_camper] 2024-02-13T20:24:09Z jordi fita mas # Add positive integer domain
-payment [roles schema_camper company campsite_type payment_status positive_integer nonnegative_integer] 2024-02-11T21:54:13Z jordi fita mas # Add relation for payments
+percentage [schema_camper] 2024-02-13T20:09:10Z jordi fita mas # Add percentage domain
+payment [roles schema_camper company campsite_type payment_status positive_integer nonnegative_integer percentage] 2024-02-11T21:54:13Z jordi fita mas # Add relation for payments
payment_customer [roles schema_camper payment country country_code extension_pg_libphonenumber] 2024-02-12T00:10:20Z jordi fita mas # Add relation of payment customer
payment_option [roles schema_camper payment campsite_type_option positive_integer nonnegative_integer] 2024-02-12T00:58:07Z jordi fita mas # 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 # Add function to create a payment draft
@@ -255,3 +256,4 @@ decode_base64url [roles schema_camper] 2024-02-12T20:03:17Z jordi fita mas # Add function to decode a Redsys signed response
payment_redsys_response [roles schema_camper payment currency_code] 2024-02-12T21:32:23Z jordi fita mas # Add relation for Redsys responses to payments
process_payment_response [roles schema_camper redsys_response payment payment_redsys_response parse_price currency] 2024-02-12T22:04:48Z jordi fita mas # Add function to process Redsys response of a payment
+down_payment [roles schema_camper payment] 2024-02-13T21:53:44Z jordi fita mas # Add function to compute payment down payment from its percentage
diff --git a/test/down_payment.sql b/test/down_payment.sql
new file mode 100644
index 0000000..9925f54
--- /dev/null
+++ b/test/down_payment.sql
@@ -0,0 +1,76 @@
+-- Test down_payment
+set client_min_messages to warning;
+create extension if not exists pgtap;
+reset client_min_messages;
+
+begin;
+
+select plan(10);
+
+set search_path to camper, public;
+
+select has_function('camper', 'down_payment', array['payment']);
+select function_lang_is('camper', 'down_payment', array['payment'], 'sql');
+select function_returns('camper', 'down_payment', array['payment'], 'integer');
+select isnt_definer('camper', 'down_payment', array['payment']);
+select volatility_is('camper', 'down_payment', array['payment'], 'stable');
+select function_privs_are('camper', 'down_payment', array['payment'], 'guest', array['EXECUTE']);
+select function_privs_are('camper', 'down_payment', array['payment'], 'employee', array['EXECUTE']);
+select function_privs_are('camper', 'down_payment', array['payment'], 'admin', array['EXECUTE']);
+select function_privs_are('camper', 'down_payment', array['payment'], '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, 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, down_payment_percent, zone_preferences)
+values (22, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, '')
+ , (23, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, '')
+ , (24, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2500, 0.75, '')
+ , (25, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1234, 0.99, '')
+ , (26, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, '')
+ , (27, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 987654, 0.33, '')
+ , (28, 2, 12, '2024-08-28', '2024-09-03', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 987654, 0.19, '')
+;
+
+select bag_eq(
+ $$ select payment_id, payment.down_payment from payment $$,
+ $$ values (22, 0)
+ , (23, 0)
+ , (24, 1875)
+ , (25, 1222)
+ , (26, 1)
+ , (27, 325926)
+ , (28, 187654)
+ $$,
+ 'Should give out the down payment for each payment'
+);
+
+
+select *
+from finish();
+
+rollback;
diff --git a/test/draft_payment.sql b/test/draft_payment.sql
index 26ded34..b3e1f95 100644
--- a/test/draft_payment.sql
+++ b/test/draft_payment.sql
@@ -5,7 +5,7 @@ reset client_min_messages;
begin;
-select plan(14);
+select plan(15);
set search_path to camper, public;
@@ -46,9 +46,9 @@ values (4, 2, 'High')
;
insert into season_calendar (season_id, season_range)
-values (4, '[2024-07-01,2024-08-30)')
- , (6, '[2024-08-30,2024-09-03)')
- , (8, '[2024-09-03,2024-09-08)')
+values (4, daterange(current_date, current_date + 60))
+ , (6, daterange(current_date + 60, current_date + 64))
+ , (8, daterange(current_date + 64, current_date + 69))
;
insert into media_content (media_type, bytes)
@@ -96,8 +96,8 @@ values (16, 4, 800)
;
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, '7cccfe16-695e-486d-a6a5-1162fb85cafb', 2, 12, '2024-08-30', '2024-09-01', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'draft', '2024-01-01 01:01:01', '2024-01-01 01:01:01')
- , (24, '6eeae04c-2fea-4d67-97dc-a4b8a83df99f', 2, 12, '2024-08-31', '2024-09-01', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'pending', '2024-01-01 02:02:02', '2024-01-01 02:02:02')
+values (22, '7cccfe16-695e-486d-a6a5-1162fb85cafb', 2, 12, current_date + 60, current_date + 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'draft', '2024-01-01 01:01:01', '2024-01-01 01:01:01')
+ , (24, '6eeae04c-2fea-4d67-97dc-a4b8a83df99f', 2, 12, current_date + 61, current_date + 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'pending', '2024-01-01 02:02:02', '2024-01-01 02:02:02')
;
insert into payment_option (payment_id, campsite_type_option_id, units, subtotal)
@@ -107,27 +107,33 @@ values (22, 16, 1, 0)
;
select lives_ok(
- $$ select draft_payment(null, '2024-08-29', '2024-09-03', 'b065f4e3-2cc8-491d-a413-d015d7d00183', 1, 2, 3, 0, null, null) $$,
+ $$ select draft_payment(null, current_date + 59, current_date + 64, 'b065f4e3-2cc8-491d-a413-d015d7d00183', 1, 2, 3, 0, null, null) $$,
'Should be able to create a new draft for Bungalows'
);
select lives_ok(
- $$ select draft_payment('7cccfe16-695e-486d-a6a5-1162fb85cafb', '2024-08-28', '2024-09-04', 'c1b6f4fc-32c1-4cd5-b796-0c5059152a52', 2, 4, 6, 3, 'pref I before E', array[(16, 2), (20, 3)]::option_units[]) $$,
+ $$ select draft_payment(null, current_date + 6, current_date + 11, 'b065f4e3-2cc8-491d-a413-d015d7d00183', 1, 2, 3, 0, null, null) $$,
+ 'A payment for a reservation in less than a week has a 100 % of downpayment'
+);
+
+select lives_ok(
+ $$ select draft_payment('7cccfe16-695e-486d-a6a5-1162fb85cafb', current_date + 58, current_date + 65, 'c1b6f4fc-32c1-4cd5-b796-0c5059152a52', 2, 4, 6, 3, 'pref I before E', array[(16, 2), (20, 3)]::option_units[]) $$,
'Should be able to update the draft for Plots'
);
select results_ne(
- $$ select slug::text from draft_payment('6eeae04c-2fea-4d67-97dc-a4b8a83df99f', '2024-08-01', '2024-08-06', 'b065f4e3-2cc8-491d-a413-d015d7d00183', 2, 1, 1, 1, 'under a tree', array[(16, 1), (18, 1)]::option_units[]) $$,
+ $$ select slug::text from draft_payment('6eeae04c-2fea-4d67-97dc-a4b8a83df99f', current_date + 31, current_date + 36, 'b065f4e3-2cc8-491d-a413-d015d7d00183', 2, 1, 1, 1, 'under a tree', array[(16, 1), (18, 1)]::option_units[]) $$,
$$ values ('6eeae04c-2fea-4d67-97dc-a4b8a83df99f') $$,
'When trying to draft a payment already pending, completed, failed, or refunded, create a new instead'
);
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, 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', '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, '', 'draft', current_timestamp, current_timestamp)
- , (2, 12, '2024-08-31', '2024-09-01', 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'pending', '2024-01-01 02:02:02', '2024-01-01 02:02:02')
- , (2, 14, '2024-08-01', '2024-08-06', 85000, 2, 0, 1, 0, 1, 0, 1, 0, 3500, 96000, 'under a tree', 'draft', current_timestamp, current_timestamp)
+ $$ select 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, down_payment_percent, zone_preferences, payment_status, created_at, updated_at from payment $$,
+ $$ values (2, 12, current_date + 58, current_date + 65, 3200, 2, 10420, 4, 20840, 6, 25080, 3, 2450, 4900, 79160, 0.3, 'pref I before E', 'draft', '2024-01-01 01:01:01', current_timestamp)
+ , (2, 14, current_date + 59, current_date + 64, 71000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 72750, 0.3, '', 'draft', current_timestamp, current_timestamp)
+ , (2, 14, current_date + 6, current_date + 11, 85000, 1, 0, 2, 0, 3, 0, 0, 0, 1750, 86750, 1.0, '', 'draft', current_timestamp, current_timestamp)
+ , (2, 12, current_date + 61, current_date + 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, '', 'pending', '2024-01-01 02:02:02', '2024-01-01 02:02:02')
+ , (2, 14, current_date + 31, current_date + 36, 85000, 2, 0, 1, 0, 1, 0, 1, 0, 3500, 96000, 0.3, 'under a tree', 'draft', current_timestamp, current_timestamp)
$$,
'Should have added and updated payments'
);
diff --git a/test/payment.sql b/test/payment.sql
index 69ab93f..c17161d 100644
--- a/test/payment.sql
+++ b/test/payment.sql
@@ -5,7 +5,7 @@ reset client_min_messages;
begin;
-select plan(103);
+select plan(108);
set search_path to camper, public;
@@ -108,6 +108,12 @@ select col_type_is('payment', 'total', 'nonnegative_integer');
select col_not_null('payment', 'total');
select col_hasnt_default('payment', 'total');
+select has_column('payment', 'down_payment_percent');
+select col_type_is('payment', 'down_payment_percent', 'percentage');
+select col_not_null('payment', 'down_payment_percent');
+select col_has_default('payment', 'down_payment_percent');
+select col_default_is('payment', 'down_payment_percent', '1.0');
+
select has_column('payment', 'zone_preferences');
select col_type_is('payment', 'zone_preferences', 'text');
select col_not_null('payment', 'zone_preferences');
diff --git a/test/percentage.sql b/test/percentage.sql
new file mode 100644
index 0000000..0e5b8cf
--- /dev/null
+++ b/test/percentage.sql
@@ -0,0 +1,43 @@
+-- Test percentage
+set client_min_messages to warning;
+create extension if not exists pgtap;
+reset client_min_messages;
+
+begin;
+
+select plan(10);
+
+set search_path to camper, public;
+
+select has_domain('percentage');
+select domain_type_is('percentage', 'numeric');
+
+select lives_ok($$ select 1.0::percentage $$);
+select lives_ok($$ select 0.0::percentage $$);
+select lives_ok($$ select 0.5::percentage $$);
+select lives_ok($$ select 0.33::percentage $$);
+select lives_ok($$ select 0.89::percentage $$);
+
+select throws_ok(
+ $$ select 1.01::percentage $$,
+ 23514, null,
+ 'Maximum percentage is 100 %'
+);
+
+select throws_ok(
+ $$ select (-0.01)::percentage $$,
+ 23514, null,
+ 'Minimum percentage is 0 %'
+);
+
+select is(
+ 0.001::percentage,
+ 0.00::percentage,
+ 'Percentage precission is 1 % (i.e., no decimals)'
+);
+
+
+select *
+from finish();
+
+rollback;
diff --git a/verify/down_payment.sql b/verify/down_payment.sql
new file mode 100644
index 0000000..65aefb7
--- /dev/null
+++ b/verify/down_payment.sql
@@ -0,0 +1,7 @@
+-- Verify camper:down_payment on pg
+
+begin;
+
+select has_function_privilege('camper.down_payment(camper.payment)', 'execute');
+
+rollback;
diff --git a/verify/payment.sql b/verify/payment.sql
index b065d15..0e36804 100644
--- a/verify/payment.sql
+++ b/verify/payment.sql
@@ -19,6 +19,7 @@ select payment_id
, subtotal_dogs
, subtotal_tourist_tax
, total
+ , down_payment_percent
, zone_preferences
, payment_status
, created_at
diff --git a/verify/percentage.sql b/verify/percentage.sql
new file mode 100644
index 0000000..998eb37
--- /dev/null
+++ b/verify/percentage.sql
@@ -0,0 +1,7 @@
+-- Verify camper:percentage on pg
+
+begin;
+
+select pg_catalog.has_type_privilege('camper.percentage', 'usage');
+
+rollback;
diff --git a/web/templates/mail/payment/body.gohtml b/web/templates/mail/payment/body.gohtml
index e605045..f858a30 100644
--- a/web/templates/mail/payment/body.gohtml
+++ b/web/templates/mail/payment/body.gohtml
@@ -43,6 +43,10 @@
{{ (printf ( gettext "Departure Date: %s") .DepartureDate) | raw }}
{{ (printf ( gettext "Total: %s") .Total) | raw }}
+ {{ if ne .Total .DownPayment -}}
+
+ {{ (printf ( gettext "Down payment: %s") .DownPayment) | raw }}
+ {{- end }}
{{( gettext "Thank you for your booking, and see you soon!" )}}
diff --git a/web/templates/mail/payment/body.gotxt b/web/templates/mail/payment/body.gotxt
index ef8a653..4112951 100644
--- a/web/templates/mail/payment/body.gotxt
+++ b/web/templates/mail/payment/body.gotxt
@@ -7,6 +7,7 @@
{{ printf ( gettext "Arrival Date: **%s**") .ArrivalDate }}
{{ printf ( gettext "Departure Date: **%s**") .DepartureDate }}
{{ printf ( gettext "Total: **%s**") .Total }}
+{{ if ne .Total .DownPayment }} {{ printf ( gettext "Down payment: **%s**") .DownPayment }}{{ end }}
{{( gettext "Thank you for your booking, and see you soon!" )}}
diff --git a/web/templates/public/booking/fields.gohtml b/web/templates/public/booking/fields.gohtml
index 11d717d..575dcd2 100644
--- a/web/templates/public/booking/fields.gohtml
+++ b/web/templates/public/booking/fields.gohtml
@@ -239,6 +239,12 @@
{{( pgettext "Total" "cart" )}}
{{ formatPrice .Total }}
+ {{ if .DownPayment -}}
+
+
{{( pgettext "Down payment" "cart" )}}
+ {{ formatPrice .DownPayment }}
+
+ {{- end }}
diff --git a/web/templates/public/payment/details.gohtml b/web/templates/public/payment/details.gohtml
index 0d8120e..c99b0b7 100644
--- a/web/templates/public/payment/details.gohtml
+++ b/web/templates/public/payment/details.gohtml
@@ -12,4 +12,10 @@
{{( pgettext "Total" "title" )}}
{{ .Total | formatPrice }}
+ {{ if ne .Total .DownPayment -}}
+
+
{{( pgettext "Down Payment" "title" )}}
+ {{ .DownPayment | formatPrice }}
+
+ {{- end }}