Replace static legal disclaimer with a database field
This commit is contained in:
parent
d6034ad732
commit
b84f1774f9
|
@ -9,8 +9,8 @@ values ('demo@numerus', 'Demo User', 'demo', 'invoicer')
|
||||||
;
|
;
|
||||||
|
|
||||||
alter sequence company_company_id_seq restart;
|
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)
|
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');
|
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)
|
insert into company_user (company_id, user_id)
|
||||||
values (1, 1)
|
values (1, 1)
|
||||||
|
|
|
@ -27,6 +27,7 @@ create table company (
|
||||||
country_code country_code not null references country,
|
country_code country_code not null references country,
|
||||||
currency_code currency_code not null references currency,
|
currency_code currency_code not null references currency,
|
||||||
invoice_number_format text not null default '"FRA"YYYY0000',
|
invoice_number_format text not null default '"FRA"YYYY0000',
|
||||||
|
legal_disclaimer text not null default '',
|
||||||
created_at timestamptz not null default current_timestamp
|
created_at timestamptz not null default current_timestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,9 @@ type Tax struct {
|
||||||
|
|
||||||
type taxDetailsForm struct {
|
type taxDetailsForm struct {
|
||||||
*contactForm
|
*contactForm
|
||||||
Currency *SelectField
|
Currency *SelectField
|
||||||
|
InvoiceNumberFormat *InputField
|
||||||
|
LegalDisclaimer *InputField
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDetailsForm {
|
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,
|
Required: true,
|
||||||
Selected: []string{"EUR"},
|
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
|
return err
|
||||||
}
|
}
|
||||||
form.Currency.FillValue(r)
|
form.Currency.FillValue(r)
|
||||||
|
form.InvoiceNumberFormat.FillValue(r)
|
||||||
|
form.LegalDisclaimer.FillValue(r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool {
|
func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool {
|
||||||
validator := newFormValidator()
|
validator := newFormValidator()
|
||||||
validator.CheckValidSelectOption(form.Currency, gettext("Selected currency is not valid.", form.locale))
|
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()
|
return form.contactForm.Validate(ctx, conn) && validator.AllOK()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn, company *Company) *taxDetailsForm {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +172,7 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
company := mustGetCompany(r)
|
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)
|
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,18 +121,19 @@ func mustClose(closer io.Closer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type invoice struct {
|
type invoice struct {
|
||||||
Number string
|
Number string
|
||||||
Slug string
|
Slug string
|
||||||
Date time.Time
|
Date time.Time
|
||||||
Invoicer taxDetails
|
Invoicer taxDetails
|
||||||
Invoicee taxDetails
|
Invoicee taxDetails
|
||||||
Notes string
|
Notes string
|
||||||
Products []*invoiceProduct
|
Products []*invoiceProduct
|
||||||
Subtotal string
|
Subtotal string
|
||||||
Taxes [][]string
|
Taxes [][]string
|
||||||
TaxClasses []string
|
TaxClasses []string
|
||||||
HasDiscounts bool
|
HasDiscounts bool
|
||||||
Total string
|
Total string
|
||||||
|
LegalDisclaimer string
|
||||||
}
|
}
|
||||||
|
|
||||||
type taxDetails struct {
|
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)) {
|
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
|
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)
|
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 {
|
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 {
|
||||||
|
|
|
@ -5,7 +5,7 @@ reset client_min_messages;
|
||||||
|
|
||||||
begin;
|
begin;
|
||||||
|
|
||||||
select plan(85);
|
select plan(90);
|
||||||
|
|
||||||
set search_path to numerus, auth, public;
|
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_has_default('company', 'invoice_number_format');
|
||||||
select col_default_is('company', 'invoice_number_format', '"FRA"YYYY0000');
|
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 has_column('company', 'created_at');
|
||||||
select col_type_is('company', 'created_at', 'timestamp with time zone');
|
select col_type_is('company', 'created_at', 'timestamp with time zone');
|
||||||
select col_not_null('company', 'created_at');
|
select col_not_null('company', 'created_at');
|
||||||
|
|
|
@ -17,6 +17,7 @@ select company_id
|
||||||
, country_code
|
, country_code
|
||||||
, currency_code
|
, currency_code
|
||||||
, invoice_number_format
|
, invoice_number_format
|
||||||
|
, legal_disclaimer
|
||||||
, created_at
|
, created_at
|
||||||
from numerus.company
|
from numerus.company
|
||||||
where false;
|
where false;
|
||||||
|
|
|
@ -34,14 +34,7 @@
|
||||||
{{ .Invoicer.Phone }}<br>
|
{{ .Invoicer.Phone }}<br>
|
||||||
</address>
|
</address>
|
||||||
|
|
||||||
<p class="legal">Oriol Carbonell Pujolàs és Responsable del Tractament de les seves dades d'acord
|
<p class="legal">{{ .LegalDisclaimer }}</p>
|
||||||
amb el RGPD i la LOPDGDDGDD, 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 Oriol Carbonell pUJOLÀS, amb domicili Carrer dels
|
|
||||||
Sastres 14, 17800 Olot o enviant un correu electrònic a info@visavis.cat. Per a
|
|
||||||
qualsevol reclamació pot acudir a agpd.es. Per a més informació pot consultar la
|
|
||||||
nostra política de privacitat a www.visavis.cat.</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
|
|
||||||
{{ template "select-field" .Currency }}
|
{{ template "select-field" .Currency }}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{{( pgettext "Invoicing" "title" )}}</legend>
|
||||||
|
|
||||||
|
{{ template "input-field" .InvoiceNumberFormat }}
|
||||||
|
{{ template "input-field" .LegalDisclaimer }}
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue