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 " 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 }}