From b84f1774f945205a8036f55bd1a655ff75d4d4d8 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Thu, 2 Mar 2023 10:24:44 +0100 Subject: [PATCH] Replace static legal disclaimer with a database field --- demo/demo.sql | 4 ++-- deploy/company.sql | 1 + pkg/company.go | 22 +++++++++++++++++++--- pkg/invoices.go | 27 ++++++++++++++------------- test/company.sql | 8 +++++++- verify/company.sql | 1 + web/template/invoices/view.gohtml | 9 +-------- web/template/tax-details.gohtml | 7 +++++++ 8 files changed, 52 insertions(+), 27 deletions(-) diff --git a/demo/demo.sql b/demo/demo.sql index b3b4b37..7f35ab2 100644 --- a/demo/demo.sql +++ b/demo/demo.sql @@ -9,8 +9,8 @@ values ('demo@numerus', 'Demo User', 'demo', 'invoicer') ; alter sequence company_company_id_seq restart; -insert into company (business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code) -values ('Juli Verd', 'ES40404040D', 'Pesebre', parse_packed_phone_number('972 50 60 70', 'ES'), 'info@numerus.cat', 'https://numerus.cat/', 'C/ de l’Hort', 'Castelló d’Empúries', 'Girona', '17486', 'ES', 'EUR'); +insert into company (business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, legal_disclaimer) +values ('Juli Verd', 'ES40404040D', 'Pesebre', parse_packed_phone_number('972 50 60 70', 'ES'), 'info@numerus.cat', 'https://numerus.cat/', 'C/ de l’Hort', 'Castelló d’Empúries', 'Girona', '17486', 'ES', 'EUR', 'Juli Verd és responsable del tractament de les seves dades d’acord amb el RGPD i la LOPDGDD, i les tracta per a mantenir una relació mercantil/comercial amb vostè. Les conservarà mentre es mantingui aquesta relació i no es comunicaran a tercers. Pot exercir els drets d’accés, rectificació, portabilitat, supressió, limitació i oposició a Juli Verd, amb domicili Carrer de l’Hort 71, 17486 Castelló d’Empúries o enviant un correu electrònic a info@numerus.cat. Per a qualsevol reclamació pot acudir a agpd.es. Per a més informació pot consultar la nostra política de privacitat a numerus.cat.'); insert into company_user (company_id, user_id) values (1, 1) diff --git a/deploy/company.sql b/deploy/company.sql index ee5ea2f..841c554 100644 --- a/deploy/company.sql +++ b/deploy/company.sql @@ -27,6 +27,7 @@ create table company ( country_code country_code not null references country, currency_code currency_code not null references currency, invoice_number_format text not null default '"FRA"YYYY0000', + legal_disclaimer text not null default '', created_at timestamptz not null default current_timestamp ); diff --git a/pkg/company.go b/pkg/company.go index 54aec39..d677423 100644 --- a/pkg/company.go +++ b/pkg/company.go @@ -79,7 +79,9 @@ type Tax struct { type taxDetailsForm struct { *contactForm - Currency *SelectField + Currency *SelectField + InvoiceNumberFormat *InputField + LegalDisclaimer *InputField } func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDetailsForm { @@ -92,6 +94,17 @@ func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDeta Required: true, Selected: []string{"EUR"}, }, + InvoiceNumberFormat: &InputField{ + Name: "invoice_number_format", + Label: pgettext("input", "Invoice number format", locale), + Type: "text", + Required: true, + }, + LegalDisclaimer: &InputField{ + Name: "legal_disclaimer", + Label: pgettext("input", "Legal disclaimer", locale), + Type: "textarea", + }, } } @@ -100,17 +113,20 @@ func (form *taxDetailsForm) Parse(r *http.Request) error { return err } form.Currency.FillValue(r) + form.InvoiceNumberFormat.FillValue(r) + form.LegalDisclaimer.FillValue(r) return nil } func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool { validator := newFormValidator() validator.CheckValidSelectOption(form.Currency, gettext("Selected currency is not valid.", form.locale)) + validator.CheckRequiredInput(form.InvoiceNumberFormat, gettext("Invoice number format can not be empty.", form.locale)) return form.contactForm.Validate(ctx, conn) && validator.AllOK() } func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn, company *Company) *taxDetailsForm { - err := conn.QueryRow(ctx, "select business_name, substr(vatin::text, 3), trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code from company where company_id = $1", company.Id).Scan(form.BusinessName, form.VATIN, form.TradeName, form.Phone, form.Email, form.Web, form.Address, form.City, form.Province, form.PostalCode, form.Country, form.Currency) + err := conn.QueryRow(ctx, "select business_name, substr(vatin::text, 3), trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, invoice_number_format, legal_disclaimer from company where company_id = $1", company.Id).Scan(form.BusinessName, form.VATIN, form.TradeName, form.Phone, form.Email, form.Web, form.Address, form.City, form.Province, form.PostalCode, form.Country, form.Currency, form.InvoiceNumberFormat, form.LegalDisclaimer) if err != nil { panic(err) } @@ -156,7 +172,7 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr return } company := mustGetCompany(r) - conn.MustExec(r.Context(), "update company set business_name = $1, vatin = ($11 || $2)::vatin, trade_name = $3, phone = parse_packed_phone_number($4, $11), email = $5, web = $6, address = $7, city = $8, province = $9, postal_code = $10, country_code = $11, currency_code = $12 where company_id = $13", form.BusinessName, form.VATIN, form.TradeName, form.Phone, form.Email, form.Web, form.Address, form.City, form.Province, form.PostalCode, form.Country, form.Currency, company.Id) + conn.MustExec(r.Context(), "update company set business_name = $1, vatin = ($11 || $2)::vatin, trade_name = $3, phone = parse_packed_phone_number($4, $11), email = $5, web = $6, address = $7, city = $8, province = $9, postal_code = $10, country_code = $11, currency_code = $12, invoice_number_format = $13, legal_disclaimer = $14 where company_id = $15", form.BusinessName, form.VATIN, form.TradeName, form.Phone, form.Email, form.Web, form.Address, form.City, form.Province, form.PostalCode, form.Country, form.Currency, form.InvoiceNumberFormat, form.LegalDisclaimer, company.Id) http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther) return } diff --git a/pkg/invoices.go b/pkg/invoices.go index ce8f6fd..dd56ccf 100644 --- a/pkg/invoices.go +++ b/pkg/invoices.go @@ -121,18 +121,19 @@ func mustClose(closer io.Closer) { } type invoice struct { - Number string - Slug string - Date time.Time - Invoicer taxDetails - Invoicee taxDetails - Notes string - Products []*invoiceProduct - Subtotal string - Taxes [][]string - TaxClasses []string - HasDiscounts bool - Total string + Number string + Slug string + Date time.Time + Invoicer taxDetails + Invoicee taxDetails + Notes string + Products []*invoiceProduct + Subtotal string + Taxes [][]string + TaxClasses []string + HasDiscounts bool + Total string + LegalDisclaimer string } type taxDetails struct { @@ -166,7 +167,7 @@ func mustGetInvoice(ctx context.Context, conn *Conn, company *Company, slug stri if notFoundErrorOrPanic(conn.QueryRow(ctx, "select invoice_id, decimal_digits, invoice_number, invoice_date, notes, business_name, vatin, phone, email, address, city, province, postal_code, to_price(subtotal, decimal_digits), to_price(total, decimal_digits) from invoice join contact using (contact_id) join invoice_amount using (invoice_id) join currency using (currency_code) where invoice.slug = $1", slug).Scan(&invoiceId, &decimalDigits, &inv.Number, &inv.Date, &inv.Notes, &inv.Invoicee.Name, &inv.Invoicee.VATIN, &inv.Invoicee.Phone, &inv.Invoicee.Email, &inv.Invoicee.Address, &inv.Invoicee.City, &inv.Invoicee.Province, &inv.Invoicee.PostalCode, &inv.Subtotal, &inv.Total)) { return nil } - if err := conn.QueryRow(ctx, "select business_name, vatin, phone, email, address, city, province, postal_code from company where company_id = $1", company.Id).Scan(&inv.Invoicer.Name, &inv.Invoicer.VATIN, &inv.Invoicer.Phone, &inv.Invoicer.Email, &inv.Invoicer.Address, &inv.Invoicer.City, &inv.Invoicer.Province, &inv.Invoicer.PostalCode); err != nil { + if err := conn.QueryRow(ctx, "select business_name, vatin, phone, email, address, city, province, postal_code, legal_disclaimer from company where company_id = $1", company.Id).Scan(&inv.Invoicer.Name, &inv.Invoicer.VATIN, &inv.Invoicer.Phone, &inv.Invoicer.Email, &inv.Invoicer.Address, &inv.Invoicer.City, &inv.Invoicer.Province, &inv.Invoicer.PostalCode, &inv.LegalDisclaimer); err != nil { panic(err) } if err := conn.QueryRow(ctx, "select array_agg(array[name, to_price(amount, $2)]) from invoice_tax_amount join tax using (tax_id) where invoice_id = $1", invoiceId, decimalDigits).Scan(&inv.Taxes); err != nil { diff --git a/test/company.sql b/test/company.sql index f53bbe4..9cdaaf3 100644 --- a/test/company.sql +++ b/test/company.sql @@ -5,7 +5,7 @@ reset client_min_messages; begin; -select plan(85); +select plan(90); set search_path to numerus, auth, public; @@ -100,6 +100,12 @@ select col_not_null('company', 'invoice_number_format'); select col_has_default('company', 'invoice_number_format'); select col_default_is('company', 'invoice_number_format', '"FRA"YYYY0000'); +select has_column('company', 'legal_disclaimer'); +select col_type_is('company', 'legal_disclaimer', 'text'); +select col_not_null('company', 'legal_disclaimer'); +select col_has_default('company', 'legal_disclaimer'); +select col_default_is('company', 'legal_disclaimer', ''); + select has_column('company', 'created_at'); select col_type_is('company', 'created_at', 'timestamp with time zone'); select col_not_null('company', 'created_at'); diff --git a/verify/company.sql b/verify/company.sql index bd21fd7..5b1db99 100644 --- a/verify/company.sql +++ b/verify/company.sql @@ -17,6 +17,7 @@ select company_id , country_code , currency_code , invoice_number_format + , legal_disclaimer , created_at from numerus.company where false; diff --git a/web/template/invoices/view.gohtml b/web/template/invoices/view.gohtml index 0088e7c..d9c29a6 100644 --- a/web/template/invoices/view.gohtml +++ b/web/template/invoices/view.gohtml @@ -34,14 +34,7 @@ {{ .Invoicer.Phone }}
- +
diff --git a/web/template/tax-details.gohtml b/web/template/tax-details.gohtml index f715ab4..70cacd7 100644 --- a/web/template/tax-details.gohtml +++ b/web/template/tax-details.gohtml @@ -32,6 +32,13 @@ {{ template "select-field" .Currency }} + +
+ {{( pgettext "Invoicing" "title" )}} + + {{ template "input-field" .InvoiceNumberFormat }} + {{ template "input-field" .LegalDisclaimer }} +
{{ end }}