Add quote number formatting and next number field to tax details

The same as for invoices: to allow people to have their own numbering
scheme, and for these that start using the program in the middle of the
current year.
This commit is contained in:
jordi fita mas 2023-06-09 12:43:50 +02:00
parent 6c3a3ff232
commit f43949dd43
5 changed files with 197 additions and 76 deletions

View File

@ -89,6 +89,8 @@ type taxDetailsForm struct {
Currency *SelectField
InvoiceNumberFormat *InputField
NextInvoiceNumber *InputField
QuoteNumberFormat *InputField
NextQuoteNumber *InputField
LegalDisclaimer *InputField
}
@ -117,6 +119,21 @@ func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDeta
"min=1",
},
},
QuoteNumberFormat: &InputField{
Name: "quote_number_format",
Label: pgettext("input", "Quotation number format", locale),
Type: "text",
Required: true,
},
NextQuoteNumber: &InputField{
Name: "next_quotation_number",
Label: pgettext("input", "Next quotation number", locale),
Type: "number",
Required: true,
Attributes: []template.HTMLAttr{
"min=1",
},
},
LegalDisclaimer: &InputField{
Name: "legal_disclaimer",
Label: pgettext("input", "Legal disclaimer", locale),
@ -132,6 +149,8 @@ func (form *taxDetailsForm) Parse(r *http.Request) error {
form.Currency.FillValue(r)
form.InvoiceNumberFormat.FillValue(r)
form.NextInvoiceNumber.FillValue(r)
form.QuoteNumberFormat.FillValue(r)
form.NextQuoteNumber.FillValue(r)
form.LegalDisclaimer.FillValue(r)
return nil
}
@ -141,6 +160,8 @@ func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool {
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))
validator.CheckValidInteger(form.NextInvoiceNumber, 1, math.MaxInt32, gettext("Next invoice number must be a number greater than zero.", form.locale))
validator.CheckRequiredInput(form.QuoteNumberFormat, gettext("Quotation number format can not be empty.", form.locale))
validator.CheckValidInteger(form.NextQuoteNumber, 1, math.MaxInt32, gettext("Next quotation number must be a number greater than zero.", form.locale))
return form.contactForm.Validate(ctx, conn) && validator.AllOK()
}
@ -159,12 +180,17 @@ func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn
, country_code
, currency_code
, invoice_number_format
, quote_number_format
, legal_disclaimer
, coalesce(invoice_number_counter.currval, 0) + 1
, coalesce(quote_number_counter.currval, 0) + 1
from company
left join invoice_number_counter
on invoice_number_counter.company_id = company.company_id
and year = date_part('year', current_date)
and invoice_number_counter.year = date_part('year', current_date)
left join quote_number_counter
on quote_number_counter.company_id = company.company_id
and quote_number_counter.year = date_part('year', current_date)
where company.company_id = $1`, company.Id).Scan(
form.BusinessName,
form.VATIN,
@ -179,15 +205,14 @@ func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn
form.Country,
form.Currency,
form.InvoiceNumberFormat,
form.QuoteNumberFormat,
form.LegalDisclaimer,
form.NextInvoiceNumber,
form.NextQuoteNumber,
)
if err != nil {
panic(err)
}
if err != nil {
panic(err)
}
return form
}
@ -234,8 +259,60 @@ 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, 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)
conn.MustExec(r.Context(), "update invoice_number_counter set currval = $1 where company_id = $2 and year = date_part('year', current_date)", form.NextInvoiceNumber.Integer()-1, company.Id)
tx := conn.MustBegin(r.Context())
defer tx.MustRollback(r.Context())
tx.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
, quote_number_format = $14
, legal_disclaimer = $15
where company_id = $16
`,
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.QuoteNumberFormat,
form.LegalDisclaimer,
company.Id)
tx.MustExec(r.Context(), `
insert into invoice_number_counter (company_id, year, currval)
values ($1, date_part('year', current_date), $2)
on conflict (company_id, year) do update
set currval = excluded.currval
`,
company.Id,
form.NextInvoiceNumber.Integer()-1)
tx.MustExec(r.Context(), `
insert into quote_number_counter (company_id, year, currval)
values ($1, date_part('year', current_date), $2)
on conflict (company_id, year) do update
set currval = excluded.currval
`,
company.Id,
form.NextQuoteNumber.Integer()-1)
tx.MustCommit(r.Context())
if IsHTMxRequest(r) {
w.Header().Set(HxTrigger, "closeModal")
w.WriteHeader(http.StatusNoContent)

View File

@ -137,6 +137,12 @@ func (tx *Tx) MustRollback(ctx context.Context) {
}
}
func (tx *Tx) MustExec(ctx context.Context, sql string, args ...interface{}) {
if _, err := tx.Exec(ctx, sql, args...); err != nil {
panic(err)
}
}
func (tx *Tx) MustGetInteger(ctx context.Context, sql string, args ...interface{}) int {
var result int
if err := tx.QueryRow(ctx, sql, args...).Scan(&result); err != nil {

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-06-08 12:44+0200\n"
"POT-Creation-Date: 2023-06-09 12:38+0200\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n"
@ -474,7 +474,7 @@ msgctxt "title"
msgid "Language"
msgstr "Idioma"
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:173
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:175
msgctxt "action"
msgid "Save changes"
msgstr "Desa canvis"
@ -538,57 +538,57 @@ msgstr "Moneda"
#: web/template/tax-details.gohtml:41
msgctxt "title"
msgid "Invoicing"
msgstr "Facturació"
msgid "Invoicing and Quoting"
msgstr "Facturació i pressuposts"
#: web/template/tax-details.gohtml:54
#: web/template/tax-details.gohtml:56
msgid "Are you sure?"
msgstr "Nesteu segur?"
#: web/template/tax-details.gohtml:60
#: web/template/tax-details.gohtml:62
msgctxt "title"
msgid "Tax Name"
msgstr "Nom impost"
#: web/template/tax-details.gohtml:61
#: web/template/tax-details.gohtml:63
msgctxt "title"
msgid "Rate (%)"
msgstr "Percentatge"
#: web/template/tax-details.gohtml:62
#: web/template/tax-details.gohtml:64
msgctxt "title"
msgid "Class"
msgstr "Classe"
#: web/template/tax-details.gohtml:86
#: web/template/tax-details.gohtml:88
msgid "No taxes added yet."
msgstr "No hi ha cap impost."
#: web/template/tax-details.gohtml:92 web/template/tax-details.gohtml:153
#: web/template/tax-details.gohtml:94 web/template/tax-details.gohtml:155
msgctxt "title"
msgid "New Line"
msgstr "Nova línia"
#: web/template/tax-details.gohtml:106
#: web/template/tax-details.gohtml:108
msgctxt "action"
msgid "Add new tax"
msgstr "Afegeix nou impost"
#: web/template/tax-details.gohtml:122
#: web/template/tax-details.gohtml:124
msgctxt "title"
msgid "Payment Method"
msgstr "Mètode de pagament"
#: web/template/tax-details.gohtml:123
#: web/template/tax-details.gohtml:125
msgctxt "title"
msgid "Instructions"
msgstr "Instruccions"
#: web/template/tax-details.gohtml:147
#: web/template/tax-details.gohtml:149
msgid "No payment methods added yet."
msgstr "No hi ha cap mètode de pagament."
#: web/template/tax-details.gohtml:165
#: web/template/tax-details.gohtml:167
msgctxt "action"
msgid "Add new payment method"
msgstr "Afegeix nou mètode de pagament"
@ -724,88 +724,106 @@ msgstr "Heu seleccionat un impost que no és vàlid."
msgid "You can only select a tax of each class."
msgstr "Només podeu seleccionar un impost de cada classe."
#: pkg/company.go:100
#: pkg/company.go:102
msgctxt "input"
msgid "Currency"
msgstr "Moneda"
#: pkg/company.go:107
#: pkg/company.go:109
msgctxt "input"
msgid "Invoice number format"
msgstr "Format del número de factura"
#: pkg/company.go:113
#: pkg/company.go:115
msgctxt "input"
msgid "Next invoice number"
msgstr "Següent número de factura"
#: pkg/company.go:122
#: pkg/company.go:124
msgctxt "input"
msgid "Quotation number format"
msgstr "Format del número de pressupost"
#: pkg/company.go:130
msgctxt "input"
msgid "Next quotation number"
msgstr "Següent número de pressupost"
#: pkg/company.go:139
msgctxt "input"
msgid "Legal disclaimer"
msgstr "Nota legal"
#: pkg/company.go:141
#: pkg/company.go:160
msgid "Selected currency is not valid."
msgstr "Heu seleccionat una moneda que no és vàlida."
#: pkg/company.go:142
#: pkg/company.go:161
msgid "Invoice number format can not be empty."
msgstr "No podeu deixar el format del número de factura en blanc."
#: pkg/company.go:143
#: pkg/company.go:162
msgid "Next invoice number must be a number greater than zero."
msgstr "El següent número de factura ha de ser un número major a zero."
#: pkg/company.go:350
#: pkg/company.go:163
msgid "Quotation number format can not be empty."
msgstr "No podeu deixar el format del número de pressupost en blanc."
#: pkg/company.go:164
msgid "Next quotation number must be a number greater than zero."
msgstr "El següent número de pressupost ha de ser un número major a zero."
#: pkg/company.go:427
msgctxt "input"
msgid "Tax name"
msgstr "Nom impost"
#: pkg/company.go:356
#: pkg/company.go:433
msgctxt "input"
msgid "Tax Class"
msgstr "Classe dimpost"
#: pkg/company.go:359
#: pkg/company.go:436
msgid "Select a tax class"
msgstr "Escolliu una classe dimpost"
#: pkg/company.go:363
#: pkg/company.go:440
msgctxt "input"
msgid "Rate (%)"
msgstr "Percentatge"
#: pkg/company.go:386
#: pkg/company.go:463
msgid "Tax name can not be empty."
msgstr "No podeu deixar el nom de limpost en blanc."
#: pkg/company.go:387
#: pkg/company.go:464
msgid "Selected tax class is not valid."
msgstr "Heu seleccionat una classe dimpost que no és vàlida."
#: pkg/company.go:388
#: pkg/company.go:465
msgid "Tax rate can not be empty."
msgstr "No podeu deixar percentatge en blanc."
#: pkg/company.go:389
#: pkg/company.go:466
msgid "Tax rate must be an integer between -99 and 99."
msgstr "El percentatge ha de ser entre -99 i 99."
#: pkg/company.go:452
#: pkg/company.go:529
msgctxt "input"
msgid "Payment method name"
msgstr "Nom del mètode de pagament"
#: pkg/company.go:458
#: pkg/company.go:535
msgctxt "input"
msgid "Instructions"
msgstr "Instruccions"
#: pkg/company.go:476
#: pkg/company.go:553
msgid "Payment method name can not be empty."
msgstr "No podeu deixar el nom del mètode de pagament en blanc."
#: pkg/company.go:477
#: pkg/company.go:554
msgid "Payment instructions can not be empty."
msgstr "No podeu deixar les instruccions de pagament en blanc."

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-06-08 12:44+0200\n"
"POT-Creation-Date: 2023-06-09 12:38+0200\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
@ -474,7 +474,7 @@ msgctxt "title"
msgid "Language"
msgstr "Idioma"
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:173
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:175
msgctxt "action"
msgid "Save changes"
msgstr "Guardar cambios"
@ -538,57 +538,57 @@ msgstr "Moneda"
#: web/template/tax-details.gohtml:41
msgctxt "title"
msgid "Invoicing"
msgstr "Facturación"
msgid "Invoicing and Quoting"
msgstr "Facturación y presupuestos"
#: web/template/tax-details.gohtml:54
#: web/template/tax-details.gohtml:56
msgid "Are you sure?"
msgstr "¿Estáis seguro?"
#: web/template/tax-details.gohtml:60
#: web/template/tax-details.gohtml:62
msgctxt "title"
msgid "Tax Name"
msgstr "Nombre impuesto"
#: web/template/tax-details.gohtml:61
#: web/template/tax-details.gohtml:63
msgctxt "title"
msgid "Rate (%)"
msgstr "Porcentaje"
#: web/template/tax-details.gohtml:62
#: web/template/tax-details.gohtml:64
msgctxt "title"
msgid "Class"
msgstr "Clase"
#: web/template/tax-details.gohtml:86
#: web/template/tax-details.gohtml:88
msgid "No taxes added yet."
msgstr "No hay impuestos."
#: web/template/tax-details.gohtml:92 web/template/tax-details.gohtml:153
#: web/template/tax-details.gohtml:94 web/template/tax-details.gohtml:155
msgctxt "title"
msgid "New Line"
msgstr "Nueva línea"
#: web/template/tax-details.gohtml:106
#: web/template/tax-details.gohtml:108
msgctxt "action"
msgid "Add new tax"
msgstr "Añadir nuevo impuesto"
#: web/template/tax-details.gohtml:122
#: web/template/tax-details.gohtml:124
msgctxt "title"
msgid "Payment Method"
msgstr "Método de pago"
#: web/template/tax-details.gohtml:123
#: web/template/tax-details.gohtml:125
msgctxt "title"
msgid "Instructions"
msgstr "Instrucciones"
#: web/template/tax-details.gohtml:147
#: web/template/tax-details.gohtml:149
msgid "No payment methods added yet."
msgstr "No hay métodos de pago."
#: web/template/tax-details.gohtml:165
#: web/template/tax-details.gohtml:167
msgctxt "action"
msgid "Add new payment method"
msgstr "Añadir nuevo método de pago"
@ -724,88 +724,106 @@ msgstr "Habéis escogido un impuesto que no es válido."
msgid "You can only select a tax of each class."
msgstr "Solo podéis escoger un impuesto de cada clase."
#: pkg/company.go:100
#: pkg/company.go:102
msgctxt "input"
msgid "Currency"
msgstr "Moneda"
#: pkg/company.go:107
#: pkg/company.go:109
msgctxt "input"
msgid "Invoice number format"
msgstr "Formato del número de factura"
#: pkg/company.go:113
#: pkg/company.go:115
msgctxt "input"
msgid "Next invoice number"
msgstr "Número de presupuesto"
msgstr "Siguiente número de factura"
#: pkg/company.go:122
#: pkg/company.go:124
msgctxt "input"
msgid "Quotation number format"
msgstr "Formato del número de presupuesto"
#: pkg/company.go:130
msgctxt "input"
msgid "Next quotation number"
msgstr "Siguiente número de presupuesto"
#: pkg/company.go:139
msgctxt "input"
msgid "Legal disclaimer"
msgstr "Nota legal"
#: pkg/company.go:141
#: pkg/company.go:160
msgid "Selected currency is not valid."
msgstr "Habéis escogido una moneda que no es válida."
#: pkg/company.go:142
#: pkg/company.go:161
msgid "Invoice number format can not be empty."
msgstr "No podéis dejar el formato del número de factura en blanco."
#: pkg/company.go:143
#: pkg/company.go:162
msgid "Next invoice number must be a number greater than zero."
msgstr "El siguiente número de factura tiene que ser un número mayor a cero."
#: pkg/company.go:350
#: pkg/company.go:163
msgid "Quotation number format can not be empty."
msgstr "No podéis dejar el formato del número de presupuesto en blanco."
#: pkg/company.go:164
msgid "Next quotation number must be a number greater than zero."
msgstr "El siguiente número de presupuesto tiene que ser un número mayor a cero."
#: pkg/company.go:427
msgctxt "input"
msgid "Tax name"
msgstr "Nombre impuesto"
#: pkg/company.go:356
#: pkg/company.go:433
msgctxt "input"
msgid "Tax Class"
msgstr "Clase de impuesto"
#: pkg/company.go:359
#: pkg/company.go:436
msgid "Select a tax class"
msgstr "Escoged una clase de impuesto"
#: pkg/company.go:363
#: pkg/company.go:440
msgctxt "input"
msgid "Rate (%)"
msgstr "Porcentaje"
#: pkg/company.go:386
#: pkg/company.go:463
msgid "Tax name can not be empty."
msgstr "No podéis dejar el nombre del impuesto en blanco."
#: pkg/company.go:387
#: pkg/company.go:464
msgid "Selected tax class is not valid."
msgstr "Habéis escogido una clase impuesto que no es válida."
#: pkg/company.go:388
#: pkg/company.go:465
msgid "Tax rate can not be empty."
msgstr "No podéis dejar el porcentaje en blanco."
#: pkg/company.go:389
#: pkg/company.go:466
msgid "Tax rate must be an integer between -99 and 99."
msgstr "El porcentaje tiene que estar entre -99 y 99."
#: pkg/company.go:452
#: pkg/company.go:529
msgctxt "input"
msgid "Payment method name"
msgstr "Nombre del método de pago"
#: pkg/company.go:458
#: pkg/company.go:535
msgctxt "input"
msgid "Instructions"
msgstr "Instrucciones"
#: pkg/company.go:476
#: pkg/company.go:553
msgid "Payment method name can not be empty."
msgstr "No podéis dejar el nombre del método de pago en blanco."
#: pkg/company.go:477
#: pkg/company.go:554
msgid "Payment instructions can not be empty."
msgstr "No podéis dejar las instrucciones de pago en blanco."

View File

@ -38,10 +38,12 @@
</fieldset>
<fieldset id="invoicing">
<legend>{{( pgettext "Invoicing" "title" )}}</legend>
<legend>{{( pgettext "Invoicing and Quoting" "title" )}}</legend>
{{ template "input-field" .InvoiceNumberFormat }}
{{ template "input-field" .NextInvoiceNumber }}
{{ template "input-field" .QuoteNumberFormat }}
{{ template "input-field" .NextQuoteNumber }}
{{ template "input-field" .LegalDisclaimer }}
</fieldset>
</form>