Add “part” of the bookings’ management
“Part”, because it is not possible to add or actually manage any booking yet, but it has the export feature that we need to validate the project.
This commit is contained in:
parent
1b7e7ed2c6
commit
d945f55096
|
@ -654,4 +654,18 @@ select translate_surroundings_highlight(120, 'fr', 'Pyrénées', '<p>Pyrénées
|
|||
select translate_surroundings_highlight(121, 'fr', 'Gérone', '<p>Visite incontournable, principalement: le quartier juifs, les Rambles, la cathédrale et les jardins qui l’entourent … Sans oublier ses nombreuses boutiques !</p><p><a href="https://www.girona.cat/turisme/fra/">Turisme Girona</a></p>');
|
||||
select translate_surroundings_highlight(122, 'fr', 'Barcelone', '<p>Barcelone c’est plus que des boutiques et le Barça … Découvrez la richesse de ces quartiers: Gràcia, Barceloneta, …</p><p><a href="https://www.barcelonaturisme.com/wv3/fr/">Turisme Barcelona</a></p>');
|
||||
|
||||
alter table booking alter column booking_id restart with 122;
|
||||
|
||||
insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card, booking_status)
|
||||
values (52, 72, 'Juli Verd', current_date + interval '23 days', current_date + interval '25 days', 0, false, 'created')
|
||||
, (52, 72, 'Pere Gil', current_date + interval '24 days', current_date + interval '25 days', 1, true, 'cancelled')
|
||||
, (52, 73, 'Calèndula Groga', current_date + interval '24 days', current_date + interval '25 days', 0, false, 'confirmed')
|
||||
, (52, 73, 'Rosa Blava', current_date + interval '15 days', current_date + interval '22 days', 0, false, 'checked-in')
|
||||
, (52, 74, 'Margarita Blanca', current_date + interval '7 days', current_date + interval '8 days', 0, false, 'invoiced')
|
||||
, (52, 74, 'Camèlia Vermella', current_date + interval '7 days', current_date + interval '8 days', 0, false, 'created')
|
||||
, (52, 74, 'Valeriana Rosa', current_date + interval '3 days', current_date + interval '8 days', 0, true, 'cancelled')
|
||||
, (52, 75, 'Jacint Violeta', current_date + interval '30 days', current_date + interval '33 days', 0, false, 'checked-in')
|
||||
, (52, 76, 'Hortènsia Grisa', current_date + interval '29 days', current_date + interval '34 days', 0, false, 'invoiced')
|
||||
;
|
||||
|
||||
commit;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
-- Deploy camper:available_booking_status to pg
|
||||
-- requires: booking_status
|
||||
-- requires: booking_status_i18n
|
||||
|
||||
begin;
|
||||
|
||||
insert into camper.booking_status (booking_status, name)
|
||||
values ('created', 'Created')
|
||||
, ('cancelled', 'Cancelled')
|
||||
, ('confirmed', 'Confirmed')
|
||||
, ('checked-in', 'Checked in')
|
||||
, ('invoiced', 'Invoiced')
|
||||
;
|
||||
|
||||
insert into camper.booking_status_i18n (booking_status, lang_tag, name)
|
||||
values ('created', 'ca', 'Creada')
|
||||
, ('cancelled', 'ca', 'Cancel·lada')
|
||||
, ('confirmed', 'ca', 'Confirmada')
|
||||
, ('checked-in', 'ca', 'Registrada')
|
||||
, ('invoiced', 'ca', 'Facturada')
|
||||
, ('created', 'es', 'Creada')
|
||||
, ('cancelled', 'es', 'Cancelada')
|
||||
, ('confirmed', 'es', 'Confirmada')
|
||||
, ('checked-in', 'es', 'Registrada')
|
||||
, ('invoiced', 'es', 'Facturada')
|
||||
, ('created', 'fr', 'Créé')
|
||||
, ('cancelled', 'fr', 'Annulé')
|
||||
, ('confirmed', 'fr', 'Confirmé')
|
||||
, ('checked-in', 'fr', 'Enregistré')
|
||||
, ('invoiced', 'fr', 'Facturé')
|
||||
;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,64 @@
|
|||
-- Deploy camper:booking to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: company
|
||||
-- requires: user_profile
|
||||
-- requires: campsite_type
|
||||
-- requires: booking_status
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create table booking (
|
||||
booking_id integer generated by default as identity primary key,
|
||||
company_id integer not null references company,
|
||||
slug uuid not null unique default gen_random_uuid(),
|
||||
campsite_type_id integer not null references campsite_type,
|
||||
holder_name text not null constraint holder_name_not_empty check (length(trim(holder_name)) > 0),
|
||||
arrival_date date not null,
|
||||
departure_date date not null constraint departure_after_arrival check (departure_date > arrival_date),
|
||||
number_dogs integer not null constraint number_dogs_nonnegative check (number_dogs >= 0),
|
||||
acsi_card boolean not null,
|
||||
booking_status text not null default 'created' references booking_status,
|
||||
created_at timestamptz not null default current_timestamp
|
||||
);
|
||||
|
||||
grant select, insert, update on table booking to employee;
|
||||
grant select, insert, update, delete on table booking to admin;
|
||||
|
||||
alter table booking enable row level security;
|
||||
|
||||
create policy select_from_company
|
||||
on booking
|
||||
for select
|
||||
using (
|
||||
company_id in (select company_id from user_profile)
|
||||
)
|
||||
;
|
||||
|
||||
create policy insert_to_company
|
||||
on booking
|
||||
for insert
|
||||
with check (
|
||||
company_id in (select company_id from user_profile)
|
||||
)
|
||||
;
|
||||
|
||||
create policy update_company
|
||||
on booking
|
||||
for update
|
||||
using (
|
||||
company_id in (select company_id from user_profile)
|
||||
)
|
||||
;
|
||||
|
||||
create policy delete_from_company
|
||||
on booking
|
||||
for delete
|
||||
using (
|
||||
company_id in (select company_id from user_profile)
|
||||
)
|
||||
;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,17 @@
|
|||
-- Deploy camper:booking_status to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create table booking_status (
|
||||
booking_status text not null primary key,
|
||||
name text not null
|
||||
);
|
||||
|
||||
grant select on table booking_status to employee;
|
||||
grant select on table booking_status to admin;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,21 @@
|
|||
-- Deploy camper:booking_status_i18n to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: booking_status
|
||||
-- requires: language
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create table booking_status_i18n (
|
||||
booking_status text not null references booking_status,
|
||||
lang_tag text not null references language,
|
||||
name text not null,
|
||||
primary key (booking_status, lang_tag)
|
||||
);
|
||||
|
||||
grant select on table booking_status_i18n to employee;
|
||||
grant select on table booking_status_i18n to admin;
|
||||
|
||||
commit;
|
|
@ -26,13 +26,13 @@ import (
|
|||
)
|
||||
|
||||
type adminHandler struct {
|
||||
booking *booking.AdminHandler
|
||||
campsite *campsite.AdminHandler
|
||||
company *company.AdminHandler
|
||||
home *home.AdminHandler
|
||||
legal *legal.AdminHandler
|
||||
location *location.AdminHandler
|
||||
media *media.AdminHandler
|
||||
payment *booking.AdminHandler
|
||||
season *season.AdminHandler
|
||||
services *services.AdminHandler
|
||||
surroundings *surroundings.AdminHandler
|
||||
|
@ -41,13 +41,13 @@ type adminHandler struct {
|
|||
|
||||
func newAdminHandler(mediaDir string) *adminHandler {
|
||||
return &adminHandler{
|
||||
booking: booking.NewAdminHandler(),
|
||||
campsite: campsite.NewAdminHandler(),
|
||||
company: company.NewAdminHandler(),
|
||||
home: home.NewAdminHandler(),
|
||||
legal: legal.NewAdminHandler(),
|
||||
location: location.NewAdminHandler(),
|
||||
media: media.NewAdminHandler(mediaDir),
|
||||
payment: booking.NewAdminHandler(),
|
||||
season: season.NewAdminHandler(),
|
||||
services: services.NewAdminHandler(),
|
||||
surroundings: surroundings.NewAdminHandler(),
|
||||
|
@ -71,6 +71,8 @@ func (h *adminHandler) Handle(user *auth.User, company *auth.Company, conn *data
|
|||
var head string
|
||||
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||
switch head {
|
||||
case "bookings":
|
||||
h.booking.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "campsites":
|
||||
h.campsite.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "company":
|
||||
|
@ -83,8 +85,6 @@ func (h *adminHandler) Handle(user *auth.User, company *auth.Company, conn *data
|
|||
h.location.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "media":
|
||||
h.media.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "payment":
|
||||
h.payment.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "seasons":
|
||||
h.season.Handler(user, company, conn).ServeHTTP(w, r)
|
||||
case "services":
|
||||
|
|
|
@ -7,7 +7,10 @@ package booking
|
|||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/text/language"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"dev.tandem.ws/tandem/camper/pkg/auth"
|
||||
"dev.tandem.ws/tandem/camper/pkg/database"
|
||||
|
@ -33,17 +36,30 @@ func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *dat
|
|||
case "":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
f := newPaymentForm(user.Locale)
|
||||
if err := f.FillFromDatabase(r.Context(), company, conn); err != nil {
|
||||
if !database.ErrorIsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
f.MustRender(w, r, user, company)
|
||||
case http.MethodPut:
|
||||
updatePaymentSettings(w, r, user, company, conn)
|
||||
serveBookingIndex(w, r, user, company, conn)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet)
|
||||
}
|
||||
case "payment":
|
||||
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||
switch head {
|
||||
case "":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
f := newPaymentForm(user.Locale)
|
||||
if err := f.FillFromDatabase(r.Context(), company, conn); err != nil {
|
||||
if !database.ErrorIsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
f.MustRender(w, r, user, company)
|
||||
case http.MethodPut:
|
||||
updatePaymentSettings(w, r, user, company, conn)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
|
||||
}
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
|
@ -51,6 +67,91 @@ func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *dat
|
|||
})
|
||||
}
|
||||
|
||||
func serveBookingIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
|
||||
bookings, err := collectBookingEntries(r.Context(), conn, user.Locale.Language)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
page := bookingIndex(bookings)
|
||||
page.MustRender(w, r, user, company)
|
||||
}
|
||||
|
||||
func collectBookingEntries(ctx context.Context, conn *database.Conn, lang language.Tag) ([]*bookingEntry, error) {
|
||||
rows, err := conn.Query(ctx, `
|
||||
select left(slug::text, 10)
|
||||
, '/admin/booking/' || slug
|
||||
, arrival_date
|
||||
, departure_date
|
||||
, holder_name
|
||||
, booking.booking_status
|
||||
, coalesce(i18n.name, status.name)
|
||||
from booking
|
||||
join booking_status as status using (booking_status)
|
||||
left join booking_status_i18n as i18n on status.booking_status = i18n.booking_status and i18n.lang_tag = $1
|
||||
order by arrival_date desc
|
||||
`, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var entries []*bookingEntry
|
||||
for rows.Next() {
|
||||
entry := &bookingEntry{}
|
||||
if err = rows.Scan(&entry.Reference, &entry.URL, &entry.ArrivalDate, &entry.DepartureDate, &entry.HolderName, &entry.Status, &entry.StatusLabel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
type bookingEntry struct {
|
||||
Reference string
|
||||
URL string
|
||||
ArrivalDate time.Time
|
||||
DepartureDate time.Time
|
||||
HolderName string
|
||||
Status string
|
||||
StatusLabel string
|
||||
}
|
||||
|
||||
type bookingIndex []*bookingEntry
|
||||
|
||||
func (page bookingIndex) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
||||
switch r.URL.Query().Get("format") {
|
||||
case "ods":
|
||||
columns := []string{
|
||||
"Reference",
|
||||
"Arrival Date",
|
||||
"Departure Date",
|
||||
"Holder Name",
|
||||
"Status",
|
||||
}
|
||||
ods, err := writeTableOds(page, columns, user.Locale, func(sb *strings.Builder, entry *bookingEntry) error {
|
||||
if err := writeCellString(sb, entry.Reference); err != nil {
|
||||
return err
|
||||
}
|
||||
writeCellDate(sb, entry.ArrivalDate)
|
||||
writeCellDate(sb, entry.DepartureDate)
|
||||
if err := writeCellString(sb, entry.HolderName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeCellString(sb, entry.StatusLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mustWriteOdsResponse(w, ods, user.Locale.Pgettext("bookings.ods", "filename"))
|
||||
default:
|
||||
template.MustRenderAdmin(w, r, user, company, "booking/index.gohtml", page)
|
||||
}
|
||||
}
|
||||
|
||||
type paymentForm struct {
|
||||
MerchantCode *form.Input
|
||||
TerminalNumber *form.Input
|
||||
|
@ -116,7 +217,7 @@ func (f *paymentForm) FillFromDatabase(ctx context.Context, company *auth.Compan
|
|||
}
|
||||
|
||||
func (f *paymentForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
||||
template.MustRenderAdmin(w, r, user, company, "payment.gohtml", f)
|
||||
template.MustRenderAdmin(w, r, user, company, "booking/payment.gohtml", f)
|
||||
}
|
||||
|
||||
func (f *paymentForm) Parse(r *http.Request) error {
|
||||
|
@ -169,5 +270,5 @@ func updatePaymentSettings(w http.ResponseWriter, r *http.Request, user *auth.Us
|
|||
if err := conn.SetupRedsys(r.Context(), company.ID, f.MerchantCode.Val, f.TerminalNumber.Int(), f.Environment.Selected[0], f.Integration.Selected[0], f.EncryptKey.Val); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
httplib.Redirect(w, r, "/admin/payment", http.StatusSeeOther)
|
||||
httplib.Redirect(w, r, "/admin/booking/payment", http.StatusSeeOther)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package booking
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"dev.tandem.ws/tandem/camper/pkg/locale"
|
||||
)
|
||||
|
||||
const (
|
||||
mimetype = "application/vnd.oasis.opendocument.spreadsheet"
|
||||
metaDashInfManifestXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<manifest:manifest
|
||||
xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
|
||||
manifest:version="1.3">
|
||||
<manifest:file-entry manifest:full-path="/" manifest:version="1.3" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>
|
||||
<manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/>
|
||||
<manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/>
|
||||
<manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>
|
||||
</manifest:manifest>
|
||||
`
|
||||
metaXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document-meta
|
||||
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
office:version="1.3">
|
||||
<office:meta>
|
||||
<meta:creation-date></meta:creation-date>
|
||||
<meta:generator>Camper</meta:generator>
|
||||
</office:meta>
|
||||
</office:document-meta>
|
||||
`
|
||||
stylesXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document-styles
|
||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
office:version="1.3">
|
||||
</office:document-styles>
|
||||
`
|
||||
)
|
||||
|
||||
func writeTableOds[K interface{}](rows []*K, columns []string, locale *locale.Locale, writeRow func(*strings.Builder, *K) error) ([]byte, error) {
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document-content
|
||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
||||
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
|
||||
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
||||
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
||||
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
||||
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
||||
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
||||
office:version="1.3">
|
||||
<office:scripts/>
|
||||
<office:font-face-decls>
|
||||
<style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>
|
||||
</office:font-face-decls>
|
||||
<office:automatic-styles>
|
||||
<style:style style:name="co1" style:family="table-column">
|
||||
<style:table-column-properties fo:break-before="auto" style:column-width="0.889in"/>
|
||||
</style:style>
|
||||
<style:style style:name="ro1" style:family="table-row">
|
||||
<style:table-row-properties style:row-height="0.178in" fo:break-before="auto" style:use-optimal-row-height="true"/>
|
||||
</style:style>
|
||||
<style:style style:name="ta1" style:family="table" style:master-page-name="Default">
|
||||
<style:table-properties table:display="true" style:writing-mode="lr-tb"/>
|
||||
</style:style>
|
||||
<number:date-style style:name="N37" number:automatic-order="true">
|
||||
<number:day number:style="long"/>
|
||||
<number:text>/</number:text>
|
||||
<number:month number:style="long"/>
|
||||
<number:text>/</number:text>
|
||||
<number:year/>
|
||||
</number:date-style>
|
||||
<style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>
|
||||
</office:automatic-styles>
|
||||
<office:body>
|
||||
<office:spreadsheet>
|
||||
<table:calculation-settings table:automatic-find-labels="false" table:use-regular-expressions="false" table:use-wildcards="true"/>
|
||||
<table:table table:name="Sheet1" table:style-name="ta1">
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" <table:table-column table:style-name=\"co1\" table:number-columns-repeated=\"%d\" table:default-cell-style-name=\"Default\"/>\n", len(columns)))
|
||||
sb.WriteString(` <table:table-row table:style-name="ro1">
|
||||
`)
|
||||
for _, t := range columns {
|
||||
if err := writeCellString(&sb, locale.GetC(t, "header")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
sb.WriteString(" </table:table-row>\n")
|
||||
for _, row := range rows {
|
||||
sb.WriteString(" <table:table-row table:style-name=\"ro1\">\n")
|
||||
if err := writeRow(&sb, row); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sb.WriteString(" </table:table-row>\n")
|
||||
}
|
||||
sb.WriteString(` </table:table>
|
||||
<table:named-expressions/>
|
||||
</office:spreadsheet>
|
||||
</office:body>
|
||||
</office:document-content>
|
||||
`)
|
||||
return writeOds(sb.String())
|
||||
}
|
||||
|
||||
func writeOds(content string) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
ods := zip.NewWriter(buf)
|
||||
if err := writeOdsFile(ods, "mimetype", mimetype, zip.Store); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeOdsFile(ods, "META-INF/manifest.xml", metaDashInfManifestXml, zip.Deflate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeOdsFile(ods, "meta.xml", metaXml, zip.Deflate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeOdsFile(ods, "styles.xml", stylesXml, zip.Deflate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeOdsFile(ods, "content.xml", content, zip.Deflate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ods.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func writeOdsFile(ods *zip.Writer, name string, content string, method uint16) error {
|
||||
f, err := ods.CreateHeader(&zip.FileHeader{
|
||||
Name: name,
|
||||
Method: method,
|
||||
Modified: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write([]byte(content))
|
||||
return err
|
||||
}
|
||||
|
||||
func writeCellString(sb *strings.Builder, s string) error {
|
||||
sb.WriteString(` <table:table-cell office:value-type="string" calcext:value-type="string"><text:p>`)
|
||||
if err := xml.EscapeText(sb, []byte(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
sb.WriteString("</text:p></table:table-cell>\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeCellDate(sb *strings.Builder, t time.Time) {
|
||||
sb.WriteString(fmt.Sprintf(" <table:table-cell table:style-name=\"ce1\" office:value-type=\"date\" office:date-value=\"%s\" calcext:value-type=\"date\"><text:p>%s</text:p></table:table-cell>\n", t.Format("2006-01-02"), t.Format("02/01/06")))
|
||||
}
|
||||
|
||||
func mustWriteOdsResponse(w http.ResponseWriter, ods []byte, filename string) {
|
||||
w.Header().Set("Content-Type", "application/vnd.oasis.opendocument.spreadsheet")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := w.Write(ods); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -99,6 +99,9 @@ func mustRenderLayout(w io.Writer, user *auth.User, company *auth.Company, templ
|
|||
"formatPrice": func(price string) string {
|
||||
return formatPrice(price, user.Locale.Language, user.Locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol)
|
||||
},
|
||||
"formatDate": func(time time.Time) template.HTML {
|
||||
return template.HTML(`<time datetime="` + time.Format("2006-01-02") + `">` + time.Format("02/01/2006") + "</time>")
|
||||
},
|
||||
"queryEscape": func(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
},
|
||||
|
|
156
po/ca.po
156
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-01-18 15:25+0100\n"
|
||||
"POT-Creation-Date: 2024-01-18 20:54+0100\n"
|
||||
"PO-Revision-Date: 2023-07-22 23:45+0200\n"
|
||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||
"Language-Team: Catalan <ca@dodds.net>\n"
|
||||
|
@ -406,7 +406,7 @@ msgstr "Menú"
|
|||
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
|
||||
#: web/templates/admin/campsite/index.gohtml:6
|
||||
#: web/templates/admin/campsite/index.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:92
|
||||
msgctxt "title"
|
||||
msgid "Campsites"
|
||||
msgstr "Allotjaments"
|
||||
|
@ -553,9 +553,9 @@ msgctxt "input"
|
|||
msgid "Map Embed"
|
||||
msgstr "Incrustació del mapa"
|
||||
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62
|
||||
#: web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/taxDetails.gohtml:167
|
||||
#: web/templates/admin/booking/payment.gohtml:62
|
||||
msgctxt "action"
|
||||
msgid "Save changes"
|
||||
msgstr "Desa els canvis"
|
||||
|
@ -933,42 +933,6 @@ msgctxt "action"
|
|||
msgid "Cancel"
|
||||
msgstr "Canceŀla"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Paràmetres de pagament"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Codi del comerç"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Número de terminal"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clau del comerç (només si s’ha de canviar)"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clau del comerç"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Entorn"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Integració"
|
||||
|
||||
#: web/templates/admin/dashboard.gohtml:6
|
||||
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
|
||||
msgctxt "title"
|
||||
|
@ -1243,6 +1207,13 @@ msgctxt "title"
|
|||
msgid "Company Settings"
|
||||
msgstr "Paràmetres de l’empresa"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
#: web/templates/admin/booking/payment.gohtml:6
|
||||
#: web/templates/admin/booking/payment.gohtml:12
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Paràmetres de pagament"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:52
|
||||
#: web/templates/admin/media/index.gohtml:6
|
||||
#: web/templates/admin/media/index.gohtml:11
|
||||
|
@ -1260,6 +1231,13 @@ msgctxt "action"
|
|||
msgid "Logout"
|
||||
msgstr "Surt"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/booking/index.gohtml:6
|
||||
#: web/templates/admin/booking/index.gohtml:13
|
||||
msgctxt "title"
|
||||
msgid "Bookings"
|
||||
msgstr "Reserves"
|
||||
|
||||
#: web/templates/admin/home/index.gohtml:11
|
||||
msgctxt "title"
|
||||
msgid "Cover"
|
||||
|
@ -1343,6 +1321,75 @@ msgctxt "title"
|
|||
msgid "Upload Media"
|
||||
msgstr "Pujada de mèdia"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Codi del comerç"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Número de terminal"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clau del comerç (només si s’ha de canviar)"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clau del comerç"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Entorn"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Integració"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:11
|
||||
msgctxt "action"
|
||||
msgid "Add Booking"
|
||||
msgstr "Afegeix reserva"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:12
|
||||
msgctxt "action"
|
||||
msgid "Export Bookings"
|
||||
msgstr "Exporta reserves"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Reference"
|
||||
msgstr "Referència"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Arrival Date"
|
||||
msgstr "Data d’arribada"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:20
|
||||
msgctxt "header"
|
||||
msgid "Departure Date"
|
||||
msgstr "Data de sortida"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:21
|
||||
msgctxt "header"
|
||||
msgid "Holder Name"
|
||||
msgstr "Nom del titular"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:22
|
||||
msgctxt "header"
|
||||
msgid "Status"
|
||||
msgstr "Estat"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:38
|
||||
msgid "No booking found."
|
||||
msgstr "No s’ha trobat cap reserva."
|
||||
|
||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
|
||||
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
|
||||
#: pkg/season/admin.go:412 pkg/services/admin.go:316
|
||||
|
@ -1706,55 +1753,60 @@ 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/admin.go:76
|
||||
#: pkg/booking/admin.go:148
|
||||
msgctxt "filename"
|
||||
msgid "bookings.ods"
|
||||
msgstr "reserves.ods"
|
||||
|
||||
#: pkg/booking/admin.go:176
|
||||
msgctxt "redsys environment"
|
||||
msgid "Test"
|
||||
msgstr "Proves"
|
||||
|
||||
#: pkg/booking/admin.go:80
|
||||
#: pkg/booking/admin.go:180
|
||||
msgctxt "redsys environment"
|
||||
msgid "Live"
|
||||
msgstr "Real"
|
||||
|
||||
#: pkg/booking/admin.go:89
|
||||
#: pkg/booking/admin.go:189
|
||||
msgctxt "redsys integration"
|
||||
msgid "InSite"
|
||||
msgstr "InSite"
|
||||
|
||||
#: pkg/booking/admin.go:93
|
||||
#: pkg/booking/admin.go:193
|
||||
msgctxt "redsys integration"
|
||||
msgid "Redirect"
|
||||
msgstr "Redirecció"
|
||||
|
||||
#: pkg/booking/admin.go:137
|
||||
#: pkg/booking/admin.go:237
|
||||
msgid "Merchant code can not be empty."
|
||||
msgstr "No podeu deixar el codi del comerç en blanc."
|
||||
|
||||
#: pkg/booking/admin.go:138
|
||||
#: pkg/booking/admin.go:238
|
||||
msgid "Merchant code must be exactly nine digits long."
|
||||
msgstr "El codi del comerç ha de ser de nou dígits."
|
||||
|
||||
#: pkg/booking/admin.go:139
|
||||
#: pkg/booking/admin.go:239
|
||||
msgid "Merchant code must be a number."
|
||||
msgstr "El codi del comerç."
|
||||
|
||||
#: pkg/booking/admin.go:143
|
||||
#: pkg/booking/admin.go:243
|
||||
msgid "Terminal number can not be empty."
|
||||
msgstr "No podeu deixar el número del terminal en blanc."
|
||||
|
||||
#: pkg/booking/admin.go:144
|
||||
#: pkg/booking/admin.go:244
|
||||
msgid "Terminal number must be a number between 1 and 999."
|
||||
msgstr "El número del terminal ha de ser entre 1 i 999"
|
||||
|
||||
#: pkg/booking/admin.go:152
|
||||
#: pkg/booking/admin.go:252
|
||||
msgid "Selected environment is not valid."
|
||||
msgstr "L’entorn escollit no és vàlid."
|
||||
|
||||
#: pkg/booking/admin.go:153
|
||||
#: pkg/booking/admin.go:253
|
||||
msgid "Selected integration is not valid."
|
||||
msgstr "La integració escollida no és vàlida."
|
||||
|
||||
#: pkg/booking/admin.go:156
|
||||
#: pkg/booking/admin.go:256
|
||||
msgid "The merchant key is not valid."
|
||||
msgstr "Aquesta clau del comerç no és vàlid."
|
||||
|
||||
|
|
156
po/es.po
156
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-01-18 15:25+0100\n"
|
||||
"POT-Creation-Date: 2024-01-18 20:54+0100\n"
|
||||
"PO-Revision-Date: 2023-07-22 23:46+0200\n"
|
||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||
|
@ -406,7 +406,7 @@ msgstr "Menú"
|
|||
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
|
||||
#: web/templates/admin/campsite/index.gohtml:6
|
||||
#: web/templates/admin/campsite/index.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:92
|
||||
msgctxt "title"
|
||||
msgid "Campsites"
|
||||
msgstr "Alojamientos"
|
||||
|
@ -553,9 +553,9 @@ msgctxt "input"
|
|||
msgid "Map Embed"
|
||||
msgstr "Incrustación del mapa"
|
||||
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62
|
||||
#: web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/taxDetails.gohtml:167
|
||||
#: web/templates/admin/booking/payment.gohtml:62
|
||||
msgctxt "action"
|
||||
msgid "Save changes"
|
||||
msgstr "Guardar los cambios"
|
||||
|
@ -933,42 +933,6 @@ msgctxt "action"
|
|||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Parámetros de pago"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Código del comercio"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Número de terminal"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clave del comercio (sólo si se debe cambiar)"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clave del comercio"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Entorno"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Integración"
|
||||
|
||||
#: web/templates/admin/dashboard.gohtml:6
|
||||
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
|
||||
msgctxt "title"
|
||||
|
@ -1243,6 +1207,13 @@ msgctxt "title"
|
|||
msgid "Company Settings"
|
||||
msgstr "Parámetros de la empresa"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
#: web/templates/admin/booking/payment.gohtml:6
|
||||
#: web/templates/admin/booking/payment.gohtml:12
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Parámetros de pago"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:52
|
||||
#: web/templates/admin/media/index.gohtml:6
|
||||
#: web/templates/admin/media/index.gohtml:11
|
||||
|
@ -1260,6 +1231,13 @@ msgctxt "action"
|
|||
msgid "Logout"
|
||||
msgstr "Salir"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/booking/index.gohtml:6
|
||||
#: web/templates/admin/booking/index.gohtml:13
|
||||
msgctxt "title"
|
||||
msgid "Bookings"
|
||||
msgstr "Reservas"
|
||||
|
||||
#: web/templates/admin/home/index.gohtml:11
|
||||
msgctxt "title"
|
||||
msgid "Cover"
|
||||
|
@ -1343,6 +1321,75 @@ msgctxt "title"
|
|||
msgid "Upload Media"
|
||||
msgstr "Subida de medio"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Código del comercio"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Número de terminal"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clave del comercio (sólo si se debe cambiar)"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clave del comercio"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Entorno"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Integración"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:11
|
||||
msgctxt "action"
|
||||
msgid "Add Booking"
|
||||
msgstr "Añadir reserva"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:12
|
||||
msgctxt "action"
|
||||
msgid "Export Bookings"
|
||||
msgstr "Exportar eservas"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Reference"
|
||||
msgstr "Referencia"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Arrival Date"
|
||||
msgstr "Fecha de llegada"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:20
|
||||
msgctxt "header"
|
||||
msgid "Departure Date"
|
||||
msgstr "Fecha de salida"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:21
|
||||
msgctxt "header"
|
||||
msgid "Holder Name"
|
||||
msgstr "Nombre del titular"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:22
|
||||
msgctxt "header"
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:38
|
||||
msgid "No booking found."
|
||||
msgstr "No se ha encontrado ninguna reserva."
|
||||
|
||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
|
||||
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
|
||||
#: pkg/season/admin.go:412 pkg/services/admin.go:316
|
||||
|
@ -1706,55 +1753,60 @@ 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/admin.go:76
|
||||
#: pkg/booking/admin.go:148
|
||||
msgctxt "filename"
|
||||
msgid "bookings.ods"
|
||||
msgstr "reservas.ods"
|
||||
|
||||
#: pkg/booking/admin.go:176
|
||||
msgctxt "redsys environment"
|
||||
msgid "Test"
|
||||
msgstr "Pruebas"
|
||||
|
||||
#: pkg/booking/admin.go:80
|
||||
#: pkg/booking/admin.go:180
|
||||
msgctxt "redsys environment"
|
||||
msgid "Live"
|
||||
msgstr "Real"
|
||||
|
||||
#: pkg/booking/admin.go:89
|
||||
#: pkg/booking/admin.go:189
|
||||
msgctxt "redsys integration"
|
||||
msgid "InSite"
|
||||
msgstr "InSite"
|
||||
|
||||
#: pkg/booking/admin.go:93
|
||||
#: pkg/booking/admin.go:193
|
||||
msgctxt "redsys integration"
|
||||
msgid "Redirect"
|
||||
msgstr "Redirección"
|
||||
|
||||
#: pkg/booking/admin.go:137
|
||||
#: pkg/booking/admin.go:237
|
||||
msgid "Merchant code can not be empty."
|
||||
msgstr "No podéis dejar el código del comercio en blanco."
|
||||
|
||||
#: pkg/booking/admin.go:138
|
||||
#: pkg/booking/admin.go:238
|
||||
msgid "Merchant code must be exactly nine digits long."
|
||||
msgstr "El código del comercio tiene que ser de nueve dígitos."
|
||||
|
||||
#: pkg/booking/admin.go:139
|
||||
#: pkg/booking/admin.go:239
|
||||
msgid "Merchant code must be a number."
|
||||
msgstr "El código del comercio tiene que ser un número."
|
||||
|
||||
#: pkg/booking/admin.go:143
|
||||
#: pkg/booking/admin.go:243
|
||||
msgid "Terminal number can not be empty."
|
||||
msgstr "No podéis dejar el número de terminal en blanco."
|
||||
|
||||
#: pkg/booking/admin.go:144
|
||||
#: pkg/booking/admin.go:244
|
||||
msgid "Terminal number must be a number between 1 and 999."
|
||||
msgstr "El número de terminal tiene que ser entre 1 y 999."
|
||||
|
||||
#: pkg/booking/admin.go:152
|
||||
#: pkg/booking/admin.go:252
|
||||
msgid "Selected environment is not valid."
|
||||
msgstr "El entorno escogido no es válido."
|
||||
|
||||
#: pkg/booking/admin.go:153
|
||||
#: pkg/booking/admin.go:253
|
||||
msgid "Selected integration is not valid."
|
||||
msgstr "La integración escogida no es válida."
|
||||
|
||||
#: pkg/booking/admin.go:156
|
||||
#: pkg/booking/admin.go:256
|
||||
msgid "The merchant key is not valid."
|
||||
msgstr "Esta clave del comercio no es válida."
|
||||
|
||||
|
|
158
po/fr.po
158
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-01-18 15:25+0100\n"
|
||||
"POT-Creation-Date: 2024-01-18 20:54+0100\n"
|
||||
"PO-Revision-Date: 2023-12-20 10:13+0100\n"
|
||||
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
|
||||
"Language-Team: French <traduc@traduc.org>\n"
|
||||
|
@ -306,7 +306,7 @@ msgstr "Camping"
|
|||
#: web/templates/public/layout.gohtml:70
|
||||
msgctxt "title"
|
||||
msgid "Booking"
|
||||
msgstr "Reservation"
|
||||
msgstr "Réservation"
|
||||
|
||||
#: web/templates/public/booking.gohtml:16
|
||||
msgctxt "title"
|
||||
|
@ -407,7 +407,7 @@ msgstr "Menu"
|
|||
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
|
||||
#: web/templates/admin/campsite/index.gohtml:6
|
||||
#: web/templates/admin/campsite/index.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:92
|
||||
msgctxt "title"
|
||||
msgid "Campsites"
|
||||
msgstr "Locatifs"
|
||||
|
@ -554,9 +554,9 @@ msgctxt "input"
|
|||
msgid "Map Embed"
|
||||
msgstr "Carte intégrée"
|
||||
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62
|
||||
#: web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/location.gohtml:60 web/templates/admin/profile.gohtml:75
|
||||
#: web/templates/admin/taxDetails.gohtml:167
|
||||
#: web/templates/admin/booking/payment.gohtml:62
|
||||
msgctxt "action"
|
||||
msgid "Save changes"
|
||||
msgstr "Enregistrer les changements"
|
||||
|
@ -934,42 +934,6 @@ msgctxt "action"
|
|||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Paramètres de paiement"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Code Marchant"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Numéro de terminal"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clé marchande (uniquement si vous devez la changer)"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clé Marchant"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Environnement"
|
||||
|
||||
#: web/templates/admin/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Intégration"
|
||||
|
||||
#: web/templates/admin/dashboard.gohtml:6
|
||||
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:86
|
||||
msgctxt "title"
|
||||
|
@ -1244,6 +1208,13 @@ msgctxt "title"
|
|||
msgid "Company Settings"
|
||||
msgstr "Paramètres de l'entreprise"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:40
|
||||
#: web/templates/admin/booking/payment.gohtml:6
|
||||
#: web/templates/admin/booking/payment.gohtml:12
|
||||
msgctxt "title"
|
||||
msgid "Payment Settings"
|
||||
msgstr "Paramètres de paiement"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:52
|
||||
#: web/templates/admin/media/index.gohtml:6
|
||||
#: web/templates/admin/media/index.gohtml:11
|
||||
|
@ -1261,6 +1232,13 @@ msgctxt "action"
|
|||
msgid "Logout"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: web/templates/admin/layout.gohtml:89
|
||||
#: web/templates/admin/booking/index.gohtml:6
|
||||
#: web/templates/admin/booking/index.gohtml:13
|
||||
msgctxt "title"
|
||||
msgid "Bookings"
|
||||
msgstr "Réservations"
|
||||
|
||||
#: web/templates/admin/home/index.gohtml:11
|
||||
msgctxt "title"
|
||||
msgid "Cover"
|
||||
|
@ -1344,6 +1322,75 @@ msgctxt "title"
|
|||
msgid "Upload Media"
|
||||
msgstr "Envoyer un fichier"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:17
|
||||
msgctxt "input"
|
||||
msgid "Merchant Code"
|
||||
msgstr "Code Marchant"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Terminal Number"
|
||||
msgstr "Numéro de terminal"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:36
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key (only if must change it)"
|
||||
msgstr "Clé marchande (uniquement si vous devez la changer)"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:38
|
||||
msgctxt "input"
|
||||
msgid "Merchant Key"
|
||||
msgstr "Clé Marchant"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:48
|
||||
msgctxt "title"
|
||||
msgid "Environment"
|
||||
msgstr "Environnement"
|
||||
|
||||
#: web/templates/admin/booking/payment.gohtml:55
|
||||
msgctxt "title"
|
||||
msgid "Integration"
|
||||
msgstr "Intégration"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:11
|
||||
msgctxt "action"
|
||||
msgid "Add Booking"
|
||||
msgstr "Ajouter une réservation"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:12
|
||||
msgctxt "action"
|
||||
msgid "Export Bookings"
|
||||
msgstr "Exporter les réservations"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Reference"
|
||||
msgstr "Référence"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Arrival Date"
|
||||
msgstr "Date d’arrivée"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:20
|
||||
msgctxt "header"
|
||||
msgid "Departure Date"
|
||||
msgstr "Date de depart"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:21
|
||||
msgctxt "header"
|
||||
msgid "Holder Name"
|
||||
msgstr "Nom du titulaire"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:22
|
||||
msgctxt "header"
|
||||
msgid "Status"
|
||||
msgstr "Statut"
|
||||
|
||||
#: web/templates/admin/booking/index.gohtml:38
|
||||
msgid "No booking found."
|
||||
msgstr "Aucune réservation trouvée."
|
||||
|
||||
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
|
||||
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
|
||||
#: pkg/season/admin.go:412 pkg/services/admin.go:316
|
||||
|
@ -1707,55 +1754,60 @@ 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/admin.go:76
|
||||
#: pkg/booking/admin.go:148
|
||||
msgctxt "filename"
|
||||
msgid "bookings.ods"
|
||||
msgstr "reservations.ods"
|
||||
|
||||
#: pkg/booking/admin.go:176
|
||||
msgctxt "redsys environment"
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
|
||||
#: pkg/booking/admin.go:80
|
||||
#: pkg/booking/admin.go:180
|
||||
msgctxt "redsys environment"
|
||||
msgid "Live"
|
||||
msgstr "Live"
|
||||
|
||||
#: pkg/booking/admin.go:89
|
||||
#: pkg/booking/admin.go:189
|
||||
msgctxt "redsys integration"
|
||||
msgid "InSite"
|
||||
msgstr "Insite"
|
||||
|
||||
#: pkg/booking/admin.go:93
|
||||
#: pkg/booking/admin.go:193
|
||||
msgctxt "redsys integration"
|
||||
msgid "Redirect"
|
||||
msgstr "Redirection"
|
||||
|
||||
#: pkg/booking/admin.go:137
|
||||
#: pkg/booking/admin.go:237
|
||||
msgid "Merchant code can not be empty."
|
||||
msgstr "Le code marchand ne peut pas être vide."
|
||||
|
||||
#: pkg/booking/admin.go:138
|
||||
#: pkg/booking/admin.go:238
|
||||
msgid "Merchant code must be exactly nine digits long."
|
||||
msgstr "Le code marchand doit comporter exactement neuf chiffres."
|
||||
|
||||
#: pkg/booking/admin.go:139
|
||||
#: pkg/booking/admin.go:239
|
||||
msgid "Merchant code must be a number."
|
||||
msgstr "Le code du commerçant doit être un chiffre."
|
||||
|
||||
#: pkg/booking/admin.go:143
|
||||
#: pkg/booking/admin.go:243
|
||||
msgid "Terminal number can not be empty."
|
||||
msgstr "Le numéro de terminal ne peut pas être vide."
|
||||
|
||||
#: pkg/booking/admin.go:144
|
||||
#: pkg/booking/admin.go:244
|
||||
msgid "Terminal number must be a number between 1 and 999."
|
||||
msgstr "Le numéro de terminal doit être compris entre 1 et 999."
|
||||
|
||||
#: pkg/booking/admin.go:152
|
||||
#: pkg/booking/admin.go:252
|
||||
msgid "Selected environment is not valid."
|
||||
msgstr "L’environnement sélectionné n’est pas valide."
|
||||
|
||||
#: pkg/booking/admin.go:153
|
||||
#: pkg/booking/admin.go:253
|
||||
msgid "Selected integration is not valid."
|
||||
msgstr "L’intégration sélectionnée n’est pas valide."
|
||||
|
||||
#: pkg/booking/admin.go:156
|
||||
#: pkg/booking/admin.go:256
|
||||
msgid "The merchant key is not valid."
|
||||
msgstr "La clé marchand n’est pas valide."
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
-- Revert camper:available_booking_status from pg
|
||||
|
||||
begin;
|
||||
|
||||
delete
|
||||
from camper.booking_status_i18n
|
||||
;
|
||||
|
||||
delete
|
||||
from camper.booking_status
|
||||
;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:booking from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop table if exists camper.booking;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:booking_status from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop table if exists camper.booking_status;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:booking_status_i18n from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop table if exists camper.booking_status_i18n;
|
||||
|
||||
commit;
|
|
@ -156,3 +156,7 @@ remove_cover_carousel_slide [roles schema_camper cover_carousel cover_carousel_i
|
|||
order_cover_carousel [schema_camper roles cover_carousel] 2024-01-16T18:40:12Z jordi fita mas <jordi@tandem.blog> # Add function to order cover carousel
|
||||
company_user_profile [roles schema_camper user company_user current_company_id] 2024-01-17T17:37:19Z jordi fita mas <jordi@tandem.blog> # Add view to list users for admins
|
||||
company_login_attempt [roles schema_camper login_attempt user company_user current_company_id] 2024-01-17T19:02:26Z jordi fita mas <jordi@tandem.blog> # Add view to see login attempts for current company
|
||||
booking_status [roles schema_camper] 2024-01-18T14:34:53Z jordi fita mas <jordi@tandem.blog> # Add relation of booking statuses
|
||||
booking_status_i18n [roles schema_camper booking_status language] 2024-01-18T14:39:49Z jordi fita mas <jordi@tandem.blog> # Add relation of booking status’ translations
|
||||
available_booking_status [booking_status booking_status_i18n] 2024-01-18T14:45:37Z jordi fita mas <jordi@tandem.blog> # Add the list of available booking statuses
|
||||
booking [roles schema_camper company user_profile campsite_type booking_status] 2024-01-18T16:48:07Z jordi fita mas <jordi@tandem.blog> # Booking relation
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
-- Test booking
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(79);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_table('booking');
|
||||
select has_pk('booking');
|
||||
select table_privs_are('booking', 'guest', array[]::text[]);
|
||||
select table_privs_are('booking', 'employee', array['SELECT', 'INSERT', 'UPDATE']);
|
||||
select table_privs_are('booking', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||
select table_privs_are('booking', 'authenticator', array[]::text[]);
|
||||
|
||||
select has_column('booking', 'booking_id');
|
||||
select col_is_pk('booking', 'booking_id');
|
||||
select col_type_is('booking', 'booking_id', 'integer');
|
||||
select col_not_null('booking', 'booking_id');
|
||||
select col_hasnt_default('booking', 'booking_id');
|
||||
|
||||
select has_column('booking', 'company_id');
|
||||
select col_is_fk('booking', 'company_id');
|
||||
select fk_ok('booking', 'company_id', 'company', 'company_id');
|
||||
select col_type_is('booking', 'company_id', 'integer');
|
||||
select col_not_null('booking', 'company_id');
|
||||
select col_hasnt_default('booking', 'company_id');
|
||||
|
||||
select has_column('booking', 'slug');
|
||||
select col_is_unique('booking', 'slug');
|
||||
select col_type_is('booking', 'slug', 'uuid');
|
||||
select col_not_null('booking', 'slug');
|
||||
select col_has_default('booking', 'slug');
|
||||
select col_default_is('booking', 'slug', 'gen_random_uuid()');
|
||||
|
||||
select has_column('booking', 'campsite_type_id');
|
||||
select col_is_fk('booking', 'campsite_type_id');
|
||||
select fk_ok('booking', 'campsite_type_id', 'campsite_type', 'campsite_type_id');
|
||||
select col_type_is('booking', 'campsite_type_id', 'integer');
|
||||
select col_not_null('booking', 'campsite_type_id');
|
||||
select col_hasnt_default('booking', 'campsite_type_id');
|
||||
|
||||
select has_column('booking', 'holder_name');
|
||||
select col_type_is('booking', 'holder_name', 'text');
|
||||
select col_not_null('booking', 'holder_name');
|
||||
select col_hasnt_default('booking', 'holder_name');
|
||||
|
||||
select has_column('booking', 'arrival_date');
|
||||
select col_type_is('booking', 'arrival_date', 'date');
|
||||
select col_not_null('booking', 'arrival_date');
|
||||
select col_hasnt_default('booking', 'arrival_date');
|
||||
|
||||
select has_column('booking', 'departure_date');
|
||||
select col_type_is('booking', 'departure_date', 'date');
|
||||
select col_not_null('booking', 'departure_date');
|
||||
select col_hasnt_default('booking', 'departure_date');
|
||||
|
||||
select has_column('booking', 'number_dogs');
|
||||
select col_type_is('booking', 'number_dogs', 'integer');
|
||||
select col_not_null('booking', 'number_dogs');
|
||||
select col_hasnt_default('booking', 'number_dogs');
|
||||
|
||||
select has_column('booking', 'acsi_card');
|
||||
select col_type_is('booking', 'acsi_card', 'boolean');
|
||||
select col_not_null('booking', 'acsi_card');
|
||||
select col_hasnt_default('booking', 'acsi_card');
|
||||
|
||||
select has_column('booking', 'booking_status');
|
||||
select col_is_fk('booking', 'booking_status');
|
||||
select fk_ok('booking', 'booking_status', 'booking_status', 'booking_status');
|
||||
select col_type_is('booking', 'booking_status', 'text');
|
||||
select col_not_null('booking', 'booking_status');
|
||||
select col_has_default('booking', 'booking_status');
|
||||
select col_default_is('booking', 'booking_status', 'created');
|
||||
|
||||
select has_column('booking', 'created_at');
|
||||
select col_type_is('booking', 'created_at', 'timestamp with time zone');
|
||||
select col_not_null('booking', 'created_at');
|
||||
select col_has_default('booking', 'created_at');
|
||||
select col_default_is('booking', 'created_at', 'CURRENT_TIMESTAMP');
|
||||
|
||||
|
||||
set client_min_messages to warning;
|
||||
truncate booking cascade;
|
||||
truncate campsite_type cascade;
|
||||
truncate media cascade;
|
||||
truncate media_content cascade;
|
||||
truncate company_host cascade;
|
||||
truncate company_user cascade;
|
||||
truncate company cascade;
|
||||
truncate auth."user" cascade;
|
||||
reset client_min_messages;
|
||||
|
||||
insert into auth."user" (user_id, email, name, password, cookie, cookie_expires_at)
|
||||
values (1, 'employee2@tandem.blog', 'Demo', 'test', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||
, (3, 'admin2@tandem.blog', 'Admin', 'test', '6d8215c4888ffac017c3e4b8438e9a1a5559decd719df9c790', current_timestamp + interval '1 month')
|
||||
, (5, 'employee4@tandem.blog', 'Demo', 'test', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||
;
|
||||
|
||||
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', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
|
||||
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
|
||||
;
|
||||
|
||||
insert into company_user (company_id, user_id, role)
|
||||
values (2, 1, 'employee')
|
||||
, (2, 3, 'admin')
|
||||
, (4, 5, 'employee')
|
||||
;
|
||||
|
||||
insert into company_host (company_id, host)
|
||||
values (2, 'co2')
|
||||
, (4, 'co4')
|
||||
;
|
||||
|
||||
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 (6, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
, (8, 4, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
;
|
||||
|
||||
insert into campsite_type (campsite_type_id, company_id, name, media_id, dogs_allowed, max_campers)
|
||||
values (10, 2, 'Wooden lodge', 6, false, 7)
|
||||
, (12, 4, 'Bungalow', 8, false, 6)
|
||||
;
|
||||
|
||||
insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card)
|
||||
values (2, 10, 'Holder 2', '2024-01-18', '2024-01-19', 0, false)
|
||||
, (4, 12, 'Holder 4', '2024-01-18', '2024-01-19', 0, false)
|
||||
;
|
||||
|
||||
prepare booking_data as
|
||||
select company_id, holder_name
|
||||
from booking
|
||||
order by company_id, holder_name;
|
||||
|
||||
|
||||
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/employee4@tandem.blog', 'co4');
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (4, 'Holder 4')
|
||||
$$,
|
||||
'Should only list bookings from second company'
|
||||
);
|
||||
|
||||
reset role;
|
||||
|
||||
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/employee2@tandem.blog', 'co2');
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
$$,
|
||||
'Should only list bookings from first company'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ insert into booking(company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (2, 10, 'New Holder', '2024-01-18', '2024-01-19', 0, false) $$,
|
||||
'Users from company 2 should be able to insert a new booking type to their company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
, (2, 'New Holder')
|
||||
$$,
|
||||
'The new row should have been added'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ update booking set holder_name = 'Another Holder' where company_id = 2 and holder_name = 'New Holder' $$,
|
||||
'Users from company 2 should be able to update bookins of their company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
, (2, 'Another Holder')
|
||||
$$,
|
||||
'The row should have been updated.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (4, 12, 'Another holder', '2024-01-18', '2024-01-19', 0, false) $$,
|
||||
'42501', 'new row violates row-level security policy for table "booking"',
|
||||
'Users from company 2 should NOT be able to insert new bookings to company 4.'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ update booking set holder_name = 'Nope' where company_id = 4 $$,
|
||||
'Users from company 2 should not be able to update new campsite types of company 4, but no error if company_id is not changed.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
, (2, 'Another Holder')
|
||||
$$,
|
||||
'No row should have been changed.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ update booking set company_id = 4 where company_id = 2 $$,
|
||||
'42501', 'new row violates row-level security policy for table "booking"',
|
||||
'Users from company 2 should NOT be able to move bookings to company 4'
|
||||
);
|
||||
|
||||
reset role;
|
||||
|
||||
|
||||
select set_cookie('6d8215c4888ffac017c3e4b8438e9a1a5559decd719df9c790/admin2@tandem.blog', 'co2');
|
||||
|
||||
select lives_ok(
|
||||
$$ delete from booking where company_id = 2 and holder_name = 'Another Holder' $$,
|
||||
'Admins from company 2 should be able to delete campsite type from their company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
$$,
|
||||
'The row should have been deleted.'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ delete from booking where company_id = 4 $$,
|
||||
'Admins from company 2 should NOT be able to delete bookins from company 4, but not error is thrown'
|
||||
);
|
||||
|
||||
reset role;
|
||||
|
||||
select bag_eq(
|
||||
'booking_data',
|
||||
$$ values (2, 'Holder 2')
|
||||
, (4, 'Holder 4')
|
||||
$$,
|
||||
'No row should have been changed'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (2, 10, ' ', '2024-01-18', '2024-01-19', 0, false) $$,
|
||||
'23514', 'new row for relation "booking" violates check constraint "holder_name_not_empty"',
|
||||
'Should not be able to add bookings with a blank holder name.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (2, 10, 'Holder', '2024-01-18', '2024-01-17', 0, false) $$,
|
||||
'23514', 'new row for relation "booking" violates check constraint "departure_after_arrival"',
|
||||
'Should not be able to add bookings with a departure date before the arrival.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (2, 10, 'Holder', '2024-01-18', '2024-01-18', 0, false) $$,
|
||||
'23514', 'new row for relation "booking" violates check constraint "departure_after_arrival"',
|
||||
'Should not be able to add bookings with a departure date equal to the arrival.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card) values (2, 10, 'Holder', '2024-01-18', '2024-01-19', -1, false) $$,
|
||||
'23514', 'new row for relation "booking" violates check constraint "number_dogs_nonnegative"',
|
||||
'Should not be able to add bookings owing dogs to holder.'
|
||||
);
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
-- Test booking_status
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(15);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_table('booking_status');
|
||||
select has_pk('booking_status');
|
||||
select table_privs_are('booking_status', 'guest', array[]::text[]);
|
||||
select table_privs_are('booking_status', 'employee', array['SELECT']);
|
||||
select table_privs_are('booking_status', 'admin', array['SELECT']);
|
||||
select table_privs_are('booking_status', 'authenticator', array[]::text[]);
|
||||
|
||||
select has_column('booking_status', 'booking_status');
|
||||
select col_is_pk('booking_status', 'booking_status');
|
||||
select col_type_is('booking_status', 'booking_status', 'text');
|
||||
select col_not_null('booking_status', 'booking_status');
|
||||
select col_hasnt_default('booking_status', 'booking_status');
|
||||
|
||||
select has_column('booking_status', 'name');
|
||||
select col_type_is('booking_status', 'name', 'text');
|
||||
select col_not_null('booking_status', 'name');
|
||||
select col_hasnt_default('booking_status', 'name');
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
-- Test booking_status_i18n
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(23);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_table('booking_status_i18n');
|
||||
select has_pk('booking_status_i18n');
|
||||
select col_is_pk('booking_status_i18n', array['booking_status', 'lang_tag']);
|
||||
select table_privs_are('booking_status_i18n', 'guest', array[]::text[]);
|
||||
select table_privs_are('booking_status_i18n', 'employee', array['SELECT']);
|
||||
select table_privs_are('booking_status_i18n', 'admin', array['SELECT']);
|
||||
select table_privs_are('booking_status_i18n', 'authenticator', array[]::text[]);
|
||||
|
||||
select has_column('booking_status_i18n', 'booking_status');
|
||||
select col_is_fk('booking_status_i18n', 'booking_status');
|
||||
select fk_ok('booking_status_i18n', 'booking_status', 'booking_status', 'booking_status');
|
||||
select col_type_is('booking_status_i18n', 'booking_status', 'text');
|
||||
select col_not_null('booking_status_i18n', 'booking_status');
|
||||
select col_hasnt_default('booking_status_i18n', 'booking_status');
|
||||
|
||||
select has_column('booking_status_i18n', 'lang_tag');
|
||||
select col_is_fk('booking_status_i18n', 'lang_tag');
|
||||
select fk_ok('booking_status_i18n', 'lang_tag', 'language', 'lang_tag');
|
||||
select col_type_is('booking_status_i18n', 'lang_tag', 'text');
|
||||
select col_not_null('booking_status_i18n', 'lang_tag');
|
||||
select col_hasnt_default('booking_status_i18n', 'lang_tag');
|
||||
|
||||
select has_column('booking_status_i18n', 'name');
|
||||
select col_type_is('booking_status_i18n', 'name', 'text');
|
||||
select col_not_null('booking_status_i18n', 'name');
|
||||
select col_hasnt_default('booking_status_i18n', 'name');
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
-- Verify camper:available_booking_status on pg
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper;
|
||||
|
||||
select 1 / count(*) from booking_status where booking_status = 'created' and name = 'Created';
|
||||
select 1 / count(*) from booking_status where booking_status = 'cancelled' and name = 'Cancelled';
|
||||
select 1 / count(*) from booking_status where booking_status = 'confirmed' and name = 'Confirmed';
|
||||
select 1 / count(*) from booking_status where booking_status = 'checked-in' and name = 'Checked in';
|
||||
select 1 / count(*) from booking_status where booking_status = 'invoiced' and name = 'Invoiced';
|
||||
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'created' and lang_tag = 'ca' and name = 'Creada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'cancelled' and lang_tag = 'ca' and name = 'Cancel·lada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'confirmed' and lang_tag = 'ca' and name = 'Confirmada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'checked-in' and lang_tag = 'ca' and name = 'Registrada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'invoiced' and lang_tag = 'ca' and name = 'Facturada';
|
||||
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'created' and lang_tag = 'es' and name = 'Creada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'cancelled' and lang_tag = 'es' and name = 'Cancelada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'confirmed' and lang_tag = 'es' and name = 'Confirmada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'checked-in' and lang_tag = 'es' and name = 'Registrada';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'invoiced' and lang_tag = 'es' and name = 'Facturada';
|
||||
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'created' and lang_tag = 'fr' and name = 'Créé';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'cancelled' and lang_tag = 'fr' and name = 'Annulé';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'confirmed' and lang_tag = 'fr' and name = 'Confirmé';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'checked-in' and lang_tag = 'fr' and name = 'Enregistré';
|
||||
select 1 / count(*) from booking_status_i18n where booking_status = 'invoiced' and lang_tag = 'fr' and name = 'Facturé';
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,25 @@
|
|||
-- Verify camper:booking on pg
|
||||
|
||||
begin;
|
||||
|
||||
select booking_id
|
||||
, company_id
|
||||
, slug
|
||||
, booking_id
|
||||
, holder_name
|
||||
, arrival_date
|
||||
, departure_date
|
||||
, number_dogs
|
||||
, acsi_card
|
||||
, booking_status
|
||||
, created_at
|
||||
from camper.booking
|
||||
where false;
|
||||
|
||||
select 1 / count(*) from pg_class where oid = 'camper.booking'::regclass and relrowsecurity;
|
||||
select 1 / count(*) from pg_policy where polname = 'select_from_company' and polrelid = 'camper.booking'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.booking'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.booking'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.booking'::regclass;
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,10 @@
|
|||
-- Verify camper:booking_status on pg
|
||||
|
||||
begin;
|
||||
|
||||
select booking_status
|
||||
, name
|
||||
from camper.booking_status
|
||||
where false;
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,11 @@
|
|||
-- Verify camper:booking_status_i18n on pg
|
||||
|
||||
begin;
|
||||
|
||||
select booking_status
|
||||
, lang_tag
|
||||
, name
|
||||
from camper.booking_status_i18n
|
||||
where false;
|
||||
|
||||
rollback;
|
|
@ -279,7 +279,7 @@ table:not(.month) th, table:not(.month) td {
|
|||
}
|
||||
|
||||
table:not(.month) th {
|
||||
text-align: start;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
/* user menu */
|
||||
|
@ -511,7 +511,7 @@ textarea {
|
|||
/* accommodation type */
|
||||
|
||||
fieldset img {
|
||||
max-width: 400px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
/* calendar */
|
||||
|
@ -624,8 +624,8 @@ fieldset img {
|
|||
}
|
||||
|
||||
.sortable img {
|
||||
max-width: 20rem;
|
||||
border-radius: 5px;
|
||||
max-width: 20rem;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#slide-index img {
|
||||
|
@ -678,7 +678,8 @@ fieldset img {
|
|||
opacity: .3;
|
||||
}
|
||||
|
||||
/* i18n input */
|
||||
/*<editor-fold desc="i18n input">*/
|
||||
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -702,3 +703,28 @@ fieldset img {
|
|||
label[x-show] > span, label[x-show] > br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*</editor-fold>*/
|
||||
/*<editor-fold desc="booking">*/
|
||||
|
||||
.booking-created .booking-status {
|
||||
background-color: var(--camper--color--light-blue);
|
||||
}
|
||||
|
||||
.booking-cancelled .booking-status {
|
||||
background-color: var(--camper--color--rosy);
|
||||
}
|
||||
|
||||
.booking-confirmed .booking-status {
|
||||
background-color: var(--camper--color--hay);
|
||||
}
|
||||
|
||||
.booking-checked-in .booking-status {
|
||||
background-color: var(--camper--color--light-green);
|
||||
}
|
||||
|
||||
.booking-invoiced .booking-status {
|
||||
background-color: var(--camper--color--light-gray);
|
||||
}
|
||||
|
||||
/*</editor-fold>*/
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Bookings" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.bookingIndex*/ -}}
|
||||
<a href="/admin/bookings/new">{{( pgettext "Add Booking" "action" )}}</a>
|
||||
<a href="/admin/bookings?format=ods">{{( pgettext "Export Bookings" "action" )}}</a>
|
||||
<h2>{{( pgettext "Bookings" "title" )}}</h2>
|
||||
{{ if . -}}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{( pgettext "Reference" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Arrival Date" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Departure Date" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Holder Name" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Status" "header" )}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range . -}}
|
||||
<tr class="booking-{{ .Status }}">
|
||||
<td><a href="{{ .URL }}">{{ .Reference }}</a></td>
|
||||
<td>{{ .ArrivalDate | formatDate }}</td>
|
||||
<td>{{ .DepartureDate | formatDate }}</td>
|
||||
<td>{{ .HolderName }}</td>
|
||||
<td class="booking-status">{{ .StatusLabel }}</td>
|
||||
</tr>
|
||||
{{- end }}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ else -}}
|
||||
<p>{{( gettext "No booking found." )}}</p>
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.paymentForm*/ -}}
|
||||
<form data-hx-put="/admin/payment">
|
||||
<form data-hx-put="/admin/booking/payment">
|
||||
<h2>{{( pgettext "Payment Settings" "title" )}}</h2>
|
||||
{{ CSRFInput }}
|
||||
<fieldset>
|
|
@ -37,7 +37,7 @@
|
|||
<a href="/admin/company">{{( pgettext "Company Settings" "title" )}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/payment">{{( pgettext "Payment Settings" "title" )}}</a>
|
||||
<a href="/admin/booking/payment">{{( pgettext "Payment Settings" "title" )}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/campsites/types">{{( pgettext "Campsite Types" "title" )}}</a>
|
||||
|
@ -85,6 +85,9 @@
|
|||
<li>
|
||||
<a href="/admin/">{{( pgettext "Dashboard" "title" )}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/bookings">{{( pgettext "Bookings" "title" )}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/campsites">{{( pgettext "Campsites" "title" )}}</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue