Compare commits

...

3 Commits

Author SHA1 Message Date
jordi fita mas 65ee8a139c Use white-space: pre-line for invoice notes and payment instructions
I want the `white-space: pre` to preserve the newline characters that
users may have used, but this prevents line wrapping and long lines are
not confined within the page margins.

`pre-line` preserves the newlines, but collapses spaces and tabs, and
wraps long text, which is more what i want.
2023-05-22 11:23:19 +02:00
jordi fita mas 5cae0efe8f Fix validation of product ID for invoice products that have none
For some reason, i assumed that if the invoice product has and ID, that
is it comes from the database, it must also have a product ID, which is
incorrect, because we allow invoice lines with products not added to the
product relation.

I am using zero to mean “no product ID”, so now that validation has to
include the zero as well.
2023-05-22 11:16:21 +02:00
jordi fita mas bbabf5c733 Use a null as product ID when adding new products to invoices
Otherwise, pgx (rightfully) tries to convert a "" into a integer, as
this is the field’s type, cannot, and panics with an error.

Added a IntegerOrNull method to FormField because this is exactly the
same that happens with the invoiceProductId, and made no sense to have
to do the logic twice, or in a function inside form.
2023-05-22 11:06:06 +02:00
6 changed files with 66 additions and 52 deletions

View File

@ -70,6 +70,15 @@ func (field *InputField) Integer() int {
return value return value
} }
func (field *InputField) IntegerOrNil() interface{} {
if field.Val != "" {
if i := field.Integer(); i > 0 {
return i
}
}
return nil
}
func (field *InputField) Float64() float64 { func (field *InputField) Float64() float64 {
value, err := strconv.ParseFloat(field.Val, 64) value, err := strconv.ParseFloat(field.Val, 64)
if err != nil { if err != nil {

View File

@ -862,7 +862,10 @@ func (form *invoiceProductForm) Parse(r *http.Request) error {
func (form *invoiceProductForm) Validate() bool { func (form *invoiceProductForm) Validate() bool {
validator := newFormValidator() validator := newFormValidator()
if form.InvoiceProductId.Val != "" { if form.InvoiceProductId.Val != "" {
validator.CheckValidInteger(form.ProductId, 1, math.MaxInt32, gettext("Product ID must be a number greater than zero.", form.locale)) validator.CheckValidInteger(form.InvoiceProductId, 1, math.MaxInt32, gettext("Invoice product ID must be a number greater than zero.", form.locale))
}
if form.ProductId.Val != "" {
validator.CheckValidInteger(form.ProductId, 0, math.MaxInt32, gettext("Product ID must be a positive number or zero.", form.locale))
} }
validator.CheckRequiredInput(form.Name, gettext("Name can not be empty.", form.locale)) validator.CheckRequiredInput(form.Name, gettext("Name can not be empty.", form.locale))
if validator.CheckRequiredInput(form.Price, gettext("Price can not be empty.", form.locale)) { if validator.CheckRequiredInput(form.Price, gettext("Price can not be empty.", form.locale)) {

View File

@ -48,15 +48,9 @@ func (src EditedInvoiceProductArray) EncodeBinary(ci *pgtype.ConnInfo, buf []byt
} }
var values [][]interface{} var values [][]interface{}
for _, form := range src { for _, form := range src {
var invoiceProductId interface{} = nil
if form.InvoiceProductId.Val != "" {
if id := form.InvoiceProductId.Integer(); id > 0 {
invoiceProductId = id
}
}
values = append(values, []interface{}{ values = append(values, []interface{}{
invoiceProductId, form.InvoiceProductId.IntegerOrNil(),
form.ProductId.Val, form.ProductId.IntegerOrNil(),
form.Name.Val, form.Name.Val,
form.Description.Val, form.Description.Val,
form.Price.Val, form.Price.Val,

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: numerus\n" "Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-05-19 13:55+0200\n" "POT-Creation-Date: 2023-05-22 11:12+0200\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n" "PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n" "Language-Team: Catalan <ca@dodds.net>\n"
@ -565,7 +565,7 @@ msgstr "Nom"
#: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202 #: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202
#: pkg/expenses.go:361 pkg/invoices.go:187 pkg/invoices.go:597 #: pkg/expenses.go:361 pkg/invoices.go:187 pkg/invoices.go:597
#: pkg/invoices.go:1044 pkg/contacts.go:140 pkg/contacts.go:325 #: pkg/invoices.go:1047 pkg/contacts.go:140 pkg/contacts.go:325
msgctxt "input" msgctxt "input"
msgid "Tags" msgid "Tags"
msgstr "Etiquetes" msgstr "Etiquetes"
@ -613,25 +613,25 @@ msgctxt "input"
msgid "Taxes" msgid "Taxes"
msgstr "Imposts" msgstr "Imposts"
#: pkg/products.go:309 pkg/profile.go:92 pkg/invoices.go:867 #: pkg/products.go:309 pkg/profile.go:92 pkg/invoices.go:870
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc." msgstr "No podeu deixar el nom en blanc."
#: pkg/products.go:310 pkg/invoices.go:868 #: pkg/products.go:310 pkg/invoices.go:871
msgid "Price can not be empty." msgid "Price can not be empty."
msgstr "No podeu deixar el preu en blanc." msgstr "No podeu deixar el preu en blanc."
#: pkg/products.go:311 pkg/invoices.go:869 #: pkg/products.go:311 pkg/invoices.go:872
msgid "Price must be a number greater than zero." msgid "Price must be a number greater than zero."
msgstr "El preu ha de ser un número major a zero." msgstr "El preu ha de ser un número major a zero."
#: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232 #: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:877 #: pkg/invoices.go:880
msgid "Selected tax is not valid." msgid "Selected tax is not valid."
msgstr "Heu seleccionat un impost que no és vàlid." msgstr "Heu seleccionat un impost que no és vàlid."
#: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233 #: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:878 #: pkg/invoices.go:881
msgid "You can only select a tax of each class." msgid "You can only select a tax of each class."
msgstr "Només podeu seleccionar un impost de cada classe." msgstr "Només podeu seleccionar un impost de cada classe."
@ -739,37 +739,37 @@ msgstr "La confirmació no és igual a la contrasenya."
msgid "Selected language is not valid." msgid "Selected language is not valid."
msgstr "Heu seleccionat un idioma que no és vàlid." msgstr "Heu seleccionat un idioma que no és vàlid."
#: pkg/dashboard.go:131 #: pkg/dashboard.go:138
msgctxt "input" msgctxt "input"
msgid "Period" msgid "Period"
msgstr "Període" msgstr "Període"
#: pkg/dashboard.go:134 #: pkg/dashboard.go:141
msgctxt "period option" msgctxt "period option"
msgid "Month" msgid "Month"
msgstr "Mes" msgstr "Mes"
#: pkg/dashboard.go:138 #: pkg/dashboard.go:145
msgctxt "period option" msgctxt "period option"
msgid "Previous month" msgid "Previous month"
msgstr "Mes anterior" msgstr "Mes anterior"
#: pkg/dashboard.go:142 #: pkg/dashboard.go:149
msgctxt "period option" msgctxt "period option"
msgid "Quarter" msgid "Quarter"
msgstr "Trimestre" msgstr "Trimestre"
#: pkg/dashboard.go:146 #: pkg/dashboard.go:153
msgctxt "period option" msgctxt "period option"
msgid "Previous quarter" msgid "Previous quarter"
msgstr "Trimestre anterior" msgstr "Trimestre anterior"
#: pkg/dashboard.go:150 #: pkg/dashboard.go:157
msgctxt "period option" msgctxt "period option"
msgid "Year" msgid "Year"
msgstr "Any" msgstr "Any"
#: pkg/dashboard.go:154 #: pkg/dashboard.go:161
msgctxt "period option" msgctxt "period option"
msgid "Previous year" msgid "Previous year"
msgstr "Any anterior" msgstr "Any anterior"
@ -860,7 +860,7 @@ msgstr "Escolliu un client a facturar."
msgid "invoices.zip" msgid "invoices.zip"
msgstr "factures.zip" msgstr "factures.zip"
#: pkg/invoices.go:530 pkg/invoices.go:1028 #: pkg/invoices.go:530 pkg/invoices.go:1031
msgid "Invalid action" msgid "Invalid action"
msgstr "Acció invàlida." msgstr "Acció invàlida."
@ -906,22 +906,26 @@ msgid "Discount (%)"
msgstr "Descompte (%)" msgstr "Descompte (%)"
#: pkg/invoices.go:865 #: pkg/invoices.go:865
msgid "Product ID must be a number greater than zero." msgid "Invoice product ID must be a number greater than zero."
msgstr "LID del producte ha de ser un número major a zero." msgstr "LID del producte de factura ha de ser un número major a zero."
#: pkg/invoices.go:871 #: pkg/invoices.go:868
msgid "Product ID must be a positive number or zero."
msgstr "LID del producte ha de ser un número positiu o zero."
#: pkg/invoices.go:874
msgid "Quantity can not be empty." msgid "Quantity can not be empty."
msgstr "No podeu deixar la quantitat en blanc." msgstr "No podeu deixar la quantitat en blanc."
#: pkg/invoices.go:872 #: pkg/invoices.go:875
msgid "Quantity must be a number greater than zero." msgid "Quantity must be a number greater than zero."
msgstr "La quantitat ha de ser un número major a zero." msgstr "La quantitat ha de ser un número major a zero."
#: pkg/invoices.go:874 #: pkg/invoices.go:877
msgid "Discount can not be empty." msgid "Discount can not be empty."
msgstr "No podeu deixar el descompte en blanc." msgstr "No podeu deixar el descompte en blanc."
#: pkg/invoices.go:875 #: pkg/invoices.go:878
msgid "Discount must be a percentage between 0 and 100." msgid "Discount must be a percentage between 0 and 100."
msgstr "El descompte ha de ser un percentatge entre 0 i 100." msgstr "El descompte ha de ser un percentatge entre 0 i 100."

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: numerus\n" "Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-05-19 13:55+0200\n" "POT-Creation-Date: 2023-05-22 11:12+0200\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n" "PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n" "Language-Team: Spanish <es@tp.org.es>\n"
@ -565,7 +565,7 @@ msgstr "Nombre"
#: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202 #: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202
#: pkg/expenses.go:361 pkg/invoices.go:187 pkg/invoices.go:597 #: pkg/expenses.go:361 pkg/invoices.go:187 pkg/invoices.go:597
#: pkg/invoices.go:1044 pkg/contacts.go:140 pkg/contacts.go:325 #: pkg/invoices.go:1047 pkg/contacts.go:140 pkg/contacts.go:325
msgctxt "input" msgctxt "input"
msgid "Tags" msgid "Tags"
msgstr "Etiquetes" msgstr "Etiquetes"
@ -613,25 +613,25 @@ msgctxt "input"
msgid "Taxes" msgid "Taxes"
msgstr "Impuestos" msgstr "Impuestos"
#: pkg/products.go:309 pkg/profile.go:92 pkg/invoices.go:867 #: pkg/products.go:309 pkg/profile.go:92 pkg/invoices.go:870
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco." msgstr "No podéis dejar el nombre en blanco."
#: pkg/products.go:310 pkg/invoices.go:868 #: pkg/products.go:310 pkg/invoices.go:871
msgid "Price can not be empty." msgid "Price can not be empty."
msgstr "No podéis dejar el precio en blanco." msgstr "No podéis dejar el precio en blanco."
#: pkg/products.go:311 pkg/invoices.go:869 #: pkg/products.go:311 pkg/invoices.go:872
msgid "Price must be a number greater than zero." msgid "Price must be a number greater than zero."
msgstr "El precio tiene que ser un número mayor a cero." msgstr "El precio tiene que ser un número mayor a cero."
#: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232 #: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:877 #: pkg/invoices.go:880
msgid "Selected tax is not valid." msgid "Selected tax is not valid."
msgstr "Habéis escogido un impuesto que no es válido." msgstr "Habéis escogido un impuesto que no es válido."
#: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233 #: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:878 #: pkg/invoices.go:881
msgid "You can only select a tax of each class." msgid "You can only select a tax of each class."
msgstr "Solo podéis escoger un impuesto de cada clase." msgstr "Solo podéis escoger un impuesto de cada clase."
@ -739,37 +739,37 @@ msgstr "La confirmación no corresponde con la contraseña."
msgid "Selected language is not valid." msgid "Selected language is not valid."
msgstr "Habéis escogido un idioma que no es válido." msgstr "Habéis escogido un idioma que no es válido."
#: pkg/dashboard.go:131 #: pkg/dashboard.go:138
msgctxt "input" msgctxt "input"
msgid "Period" msgid "Period"
msgstr "Periodo" msgstr "Periodo"
#: pkg/dashboard.go:134 #: pkg/dashboard.go:141
msgctxt "period option" msgctxt "period option"
msgid "Month" msgid "Month"
msgstr "Mes" msgstr "Mes"
#: pkg/dashboard.go:138 #: pkg/dashboard.go:145
msgctxt "period option" msgctxt "period option"
msgid "Previous month" msgid "Previous month"
msgstr "Mes anterior" msgstr "Mes anterior"
#: pkg/dashboard.go:142 #: pkg/dashboard.go:149
msgctxt "period option" msgctxt "period option"
msgid "Quarter" msgid "Quarter"
msgstr "Trimestre" msgstr "Trimestre"
#: pkg/dashboard.go:146 #: pkg/dashboard.go:153
msgctxt "period option" msgctxt "period option"
msgid "Previous quarter" msgid "Previous quarter"
msgstr "Trimestre anterior" msgstr "Trimestre anterior"
#: pkg/dashboard.go:150 #: pkg/dashboard.go:157
msgctxt "period option" msgctxt "period option"
msgid "Year" msgid "Year"
msgstr "Año" msgstr "Año"
#: pkg/dashboard.go:154 #: pkg/dashboard.go:161
msgctxt "period option" msgctxt "period option"
msgid "Previous year" msgid "Previous year"
msgstr "Año anterior" msgstr "Año anterior"
@ -860,7 +860,7 @@ msgstr "Escoged un cliente a facturar."
msgid "invoices.zip" msgid "invoices.zip"
msgstr "facturas.zip" msgstr "facturas.zip"
#: pkg/invoices.go:530 pkg/invoices.go:1028 #: pkg/invoices.go:530 pkg/invoices.go:1031
msgid "Invalid action" msgid "Invalid action"
msgstr "Acción inválida." msgstr "Acción inválida."
@ -906,22 +906,26 @@ msgid "Discount (%)"
msgstr "Descuento (%)" msgstr "Descuento (%)"
#: pkg/invoices.go:865 #: pkg/invoices.go:865
msgid "Product ID must be a number greater than zero." msgid "Invoice product ID must be a number greater than zero."
msgstr "El ID de producto tiene que ser un número mayor a cero." msgstr "El ID de producto de factura tiene que ser un número mayor a cero."
#: pkg/invoices.go:871 #: pkg/invoices.go:868
msgid "Product ID must be a positive number or zero."
msgstr "El ID de producto tiene que ser un número positivo o cero."
#: pkg/invoices.go:874
msgid "Quantity can not be empty." msgid "Quantity can not be empty."
msgstr "No podéis dejar la cantidad en blanco." msgstr "No podéis dejar la cantidad en blanco."
#: pkg/invoices.go:872 #: pkg/invoices.go:875
msgid "Quantity must be a number greater than zero." msgid "Quantity must be a number greater than zero."
msgstr "La cantidad tiene que ser un número mayor a cero." msgstr "La cantidad tiene que ser un número mayor a cero."
#: pkg/invoices.go:874 #: pkg/invoices.go:877
msgid "Discount can not be empty." msgid "Discount can not be empty."
msgstr "No podéis dejar el descuento en blanco." msgstr "No podéis dejar el descuento en blanco."
#: pkg/invoices.go:875 #: pkg/invoices.go:878
msgid "Discount must be a percentage between 0 and 100." msgid "Discount must be a percentage between 0 and 100."
msgstr "El descuento tiene que ser un porcentaje entre 0 y 100." msgstr "El descuento tiene que ser un porcentaje entre 0 y 100."

View File

@ -56,7 +56,7 @@
} }
.invoice .notes, .invoice .payment-instructions { .invoice .notes, .invoice .payment-instructions {
white-space: pre; white-space: pre-line;
text-align: right; text-align: right;
} }