Compare commits

..

5 Commits

Author SHA1 Message Date
jordi fita mas 6c3a3ff232 Allow empty contact and payment method for quotes
I have to use a value to be used as “none” for payment method and
contact.  In PL/pgSQL add_quote and edit_quote functions, that value is
NULL, while in forms it is the empty string.  I can not simply pass the
empty string for either of these fields because PL/pgSQL expects
(nullable) integers, and "" is not a valid integer and is not NULL
either.  A conversion is necessary.

Apparently, Go’s nil is not a valid representation for SQL’s NULL with
pgx, and had to use sql.NullString instead.

I also needed to coalesce contact’s VATIN and phone, because null values
can not be scanned to *string.  I did not do that before because
`coalesce(vatin, '')` throws an error that '' is not a valid VATIN and
just left as is, wrongly expecting that pgx would do the job of leaving
the string blank for me.  It does not.

Lastly, i can not blindly write Quotee’s tax details in the quote’s view
page, or we would see the (), characters for the empty address info.
2023-06-08 13:05:41 +02:00
jordi fita mas 5537a53834 Add margin between quotee and terms and conditions 2023-06-08 12:55:12 +02:00
jordi fita mas 9bb5bcd820 Use the same style for quoter and quotee than invoicer and invoicee 2023-06-08 12:52:40 +02:00
jordi fita mas 9fab65f108 Add terms and conditions to invoice’s view 2023-06-08 12:52:10 +02:00
jordi fita mas ba6f51ac5d Fix getting quote’s terms and conditions from form and database 2023-06-08 12:50:16 +02:00
6 changed files with 144 additions and 100 deletions

View File

@ -2,6 +2,7 @@ package pkg
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
@ -137,6 +138,13 @@ func (field *SelectField) String() string {
return field.Selected[0]
}
func (field *SelectField) OrNull() interface{} {
if field.String() == "" {
return sql.NullString{}
}
return field
}
func (field *SelectField) FillValue(r *http.Request) {
field.Selected = r.Form[field.Name]
}

View File

@ -89,7 +89,7 @@ func mustCollectQuoteEntries(ctx context.Context, conn *Conn, company *Company,
select quote.slug
, quote_date
, quote_number
, contact.business_name
, coalesce(contact.business_name, '')
, quote.tags
, quote.quote_status
, isi18n.name
@ -310,6 +310,7 @@ type quote struct {
Slug string
Date time.Time
Quoter taxDetails
HasQuotee bool
Quotee taxDetails
TermsAndConditions string
Notes string
@ -348,9 +349,10 @@ func mustGetQuote(ctx context.Context, conn *Conn, company *Company, slug string
, terms_and_conditions
, notes
, coalesce(instructions, '')
, contact_id is not null
, coalesce(business_name, '')
, vatin
, phone
, coalesce(vatin::text, '')
, coalesce(phone::text, '')
, coalesce(email, '')
, coalesce(address, '')
, coalesce(city, '')
@ -373,6 +375,7 @@ func mustGetQuote(ctx context.Context, conn *Conn, company *Company, slug string
&quo.TermsAndConditions,
&quo.Notes,
&quo.PaymentInstructions,
&quo.HasQuotee,
&quo.Quotee.Name,
&quo.Quotee.VATIN,
&quo.Quotee.Phone,
@ -488,7 +491,7 @@ func HandleAddQuote(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
mustRenderNewQuoteForm(w, r, form)
return
}
slug := conn.MustGetText(r.Context(), "", "select add_quote($1, $2, $3, $4, $5, $6, $7, $8)", company.Id, form.Date, form.Customer, form.TermsAndConditions, form.Notes, form.PaymentMethod, form.Tags, NewQuoteProductArray(form.Products))
slug := conn.MustGetText(r.Context(), "", "select add_quote($1, $2, $3, $4, $5, $6, $7, $8)", company.Id, form.Date, form.Customer.OrNull(), form.TermsAndConditions, form.Notes, form.PaymentMethod.OrNull(), form.Tags, NewQuoteProductArray(form.Products))
htmxRedirect(w, r, companyURI(company, "/quotes/"+slug))
}
@ -620,6 +623,7 @@ func (form *quoteForm) Parse(r *http.Request) error {
form.QuoteStatus.FillValue(r)
form.Customer.FillValue(r)
form.Date.FillValue(r)
form.TermsAndConditions.FillValue(r)
form.Notes.FillValue(r)
form.Tags.FillValue(r)
form.PaymentMethod.FillValue(r)
@ -745,6 +749,7 @@ func (form *quoteForm) MustFillFromDatabase(ctx context.Context, conn *Conn, slu
, contact_id
, quote_number
, quote_date
, terms_and_conditions
, notes
, payment_method_id
, tags
@ -752,7 +757,7 @@ func (form *quoteForm) MustFillFromDatabase(ctx context.Context, conn *Conn, slu
left join quote_contact using (quote_id)
left join quote_payment_method using (quote_id)
where slug = $1
`, slug).Scan(&quoteId, form.QuoteStatus, form.Customer, &form.Number, form.Date, form.Notes, form.PaymentMethod, form.Tags)) {
`, slug).Scan(&quoteId, form.QuoteStatus, form.Customer, &form.Number, form.Date, form.TermsAndConditions, form.Notes, form.PaymentMethod, form.Tags)) {
form.PaymentMethod.Selected = selectedPaymentMethod
form.QuoteStatus.Selected = selectedQuoteStatus
return false
@ -960,7 +965,7 @@ func HandleUpdateQuote(w http.ResponseWriter, r *http.Request, params httprouter
mustRenderEditQuoteForm(w, r, slug, form)
return
}
slug = conn.MustGetText(r.Context(), "", "select edit_quote($1, $2, $3, $4, $5, $6, $7, $8)", slug, form.QuoteStatus, form.Customer, form.TermsAndConditions, form.Notes, form.PaymentMethod, form.Tags, EditedQuoteProductArray(form.Products))
slug = conn.MustGetText(r.Context(), "", "select edit_quote($1, $2, $3, $4, $5, $6, $7, $8)", slug, form.QuoteStatus, form.Customer.OrNull(), form.TermsAndConditions, form.Notes, form.PaymentMethod.OrNull(), form.Tags, EditedQuoteProductArray(form.Products))
if slug == "" {
http.NotFound(w, r)
return

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-07 16:05+0200\n"
"POT-Creation-Date: 2023-06-08 12:44+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"
@ -65,7 +65,7 @@ msgstr "Nom"
#: web/template/invoices/products.gohtml:50
#: web/template/invoices/view.gohtml:62 web/template/quotes/products.gohtml:50
#: web/template/quotes/view.gohtml:62 web/template/products/index.gohtml:42
#: web/template/quotes/view.gohtml:68 web/template/products/index.gohtml:42
msgctxt "title"
msgid "Price"
msgstr "Preu"
@ -95,15 +95,15 @@ msgstr "Desfes"
#: web/template/invoices/new.gohtml:60 web/template/invoices/view.gohtml:67
#: web/template/invoices/edit.gohtml:61 web/template/quotes/new.gohtml:61
#: web/template/quotes/view.gohtml:67 web/template/quotes/edit.gohtml:62
#: web/template/quotes/view.gohtml:73 web/template/quotes/edit.gohtml:62
msgctxt "title"
msgid "Subtotal"
msgstr "Subtotal"
#: web/template/invoices/new.gohtml:70 web/template/invoices/view.gohtml:71
#: web/template/invoices/view.gohtml:111 web/template/invoices/edit.gohtml:71
#: web/template/quotes/new.gohtml:71 web/template/quotes/view.gohtml:71
#: web/template/quotes/view.gohtml:111 web/template/quotes/edit.gohtml:72
#: web/template/quotes/new.gohtml:71 web/template/quotes/view.gohtml:77
#: web/template/quotes/view.gohtml:117 web/template/quotes/edit.gohtml:72
msgctxt "title"
msgid "Total"
msgstr "Total"
@ -226,22 +226,22 @@ msgctxt "action"
msgid "Download invoice"
msgstr "Descarrega factura"
#: web/template/invoices/view.gohtml:61 web/template/quotes/view.gohtml:61
#: web/template/invoices/view.gohtml:61 web/template/quotes/view.gohtml:67
msgctxt "title"
msgid "Concept"
msgstr "Concepte"
#: web/template/invoices/view.gohtml:64 web/template/quotes/view.gohtml:64
#: web/template/invoices/view.gohtml:64 web/template/quotes/view.gohtml:70
msgctxt "title"
msgid "Discount"
msgstr "Descompte"
#: web/template/invoices/view.gohtml:66 web/template/quotes/view.gohtml:66
#: web/template/invoices/view.gohtml:66 web/template/quotes/view.gohtml:72
msgctxt "title"
msgid "Units"
msgstr "Unitats"
#: web/template/invoices/view.gohtml:101 web/template/quotes/view.gohtml:101
#: web/template/invoices/view.gohtml:101 web/template/quotes/view.gohtml:107
msgctxt "title"
msgid "Tax Base"
msgstr "Base imposable"
@ -353,6 +353,10 @@ msgctxt "action"
msgid "Download quotation"
msgstr "Descarrega pressupost"
#: web/template/quotes/view.gohtml:60
msgid "Terms and Conditions:"
msgstr "Condicions dacceptació:"
#: web/template/quotes/edit.gohtml:2 web/template/quotes/edit.gohtml:19
msgctxt "title"
msgid "Edit Quotation “%s”"
@ -641,13 +645,13 @@ msgstr "No podeu deixar la contrasenya en blanc."
msgid "Invalid user or password."
msgstr "Nom dusuari o contrasenya incorrectes."
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:793 pkg/invoices.go:824
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:801 pkg/invoices.go:824
#: pkg/contacts.go:135
msgctxt "input"
msgid "Name"
msgstr "Nom"
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:606
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:608
#: pkg/expenses.go:202 pkg/expenses.go:361 pkg/invoices.go:189
#: pkg/invoices.go:601 pkg/invoices.go:1123 pkg/contacts.go:140
#: pkg/contacts.go:325
@ -683,39 +687,39 @@ msgstr "Qualsevol"
msgid "Invoices must have at least one of the specified labels."
msgstr "Les factures han de tenir com a mínim una de les etiquetes."
#: pkg/products.go:269 pkg/quote.go:807 pkg/invoices.go:838
#: pkg/products.go:269 pkg/quote.go:815 pkg/invoices.go:838
msgctxt "input"
msgid "Description"
msgstr "Descripció"
#: pkg/products.go:274 pkg/quote.go:811 pkg/invoices.go:842
#: pkg/products.go:274 pkg/quote.go:819 pkg/invoices.go:842
msgctxt "input"
msgid "Price"
msgstr "Preu"
#: pkg/products.go:284 pkg/quote.go:840 pkg/expenses.go:181 pkg/invoices.go:871
#: pkg/products.go:284 pkg/quote.go:848 pkg/expenses.go:181 pkg/invoices.go:871
msgctxt "input"
msgid "Taxes"
msgstr "Imposts"
#: pkg/products.go:309 pkg/quote.go:889 pkg/profile.go:92 pkg/invoices.go:920
#: pkg/products.go:309 pkg/quote.go:897 pkg/profile.go:92 pkg/invoices.go:920
msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc."
#: pkg/products.go:310 pkg/quote.go:890 pkg/invoices.go:921
#: pkg/products.go:310 pkg/quote.go:898 pkg/invoices.go:921
msgid "Price can not be empty."
msgstr "No podeu deixar el preu en blanc."
#: pkg/products.go:311 pkg/quote.go:891 pkg/invoices.go:922
#: pkg/products.go:311 pkg/quote.go:899 pkg/invoices.go:922
msgid "Price must be a number greater than zero."
msgstr "El preu ha de ser un número major a zero."
#: pkg/products.go:313 pkg/quote.go:899 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/products.go:313 pkg/quote.go:907 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:930
msgid "Selected tax is not valid."
msgstr "Heu seleccionat un impost que no és vàlid."
#: pkg/products.go:314 pkg/quote.go:900 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/products.go:314 pkg/quote.go:908 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:931
msgid "You can only select a tax of each class."
msgstr "Només podeu seleccionar un impost de cada classe."
@ -805,7 +809,7 @@ msgstr "No podeu deixar el nom del mètode de pagament en blanc."
msgid "Payment instructions can not be empty."
msgstr "No podeu deixar les instruccions de pagament en blanc."
#: pkg/quote.go:161 pkg/quote.go:585 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/quote.go:161 pkg/quote.go:586 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/invoices.go:584
msgctxt "input"
msgid "Customer"
@ -815,7 +819,7 @@ msgstr "Client"
msgid "All customers"
msgstr "Tots els clients"
#: pkg/quote.go:167 pkg/quote.go:579
#: pkg/quote.go:167 pkg/quote.go:580
msgctxt "input"
msgid "Quotation Status"
msgstr "Estat del pressupost"
@ -847,95 +851,99 @@ msgstr "Els pressuposts han de tenir totes les etiquetes."
msgid "Quotations must have at least one of the specified labels."
msgstr "Els pressuposts han de tenir com a mínim una de les etiquetes."
#: pkg/quote.go:451
msgid "Select a customer to quote."
msgstr "Escolliu un client a pressupostar."
#: pkg/quote.go:527
#: pkg/quote.go:528
msgid "quotations.zip"
msgstr "pressuposts.zip"
#: pkg/quote.go:533 pkg/quote.go:1055 pkg/quote.go:1063 pkg/invoices.go:533
#: pkg/quote.go:534 pkg/quote.go:1063 pkg/quote.go:1071 pkg/invoices.go:533
#: pkg/invoices.go:1098 pkg/invoices.go:1106
msgid "Invalid action"
msgstr "Acció invàlida."
#: pkg/quote.go:590
#: pkg/quote.go:587
msgid "Select a customer to quote."
msgstr "Escolliu un client a pressupostar."
#: pkg/quote.go:592
msgctxt "input"
msgid "Quotation Date"
msgstr "Data del pressupost"
#: pkg/quote.go:596
#: pkg/quote.go:598
msgctxt "input"
msgid "Terms and conditions"
msgstr "Condicions dacceptació"
#: pkg/quote.go:601 pkg/invoices.go:596
#: pkg/quote.go:603 pkg/invoices.go:596
msgctxt "input"
msgid "Notes"
msgstr "Notes"
#: pkg/quote.go:610 pkg/invoices.go:606
#: pkg/quote.go:612 pkg/invoices.go:606
msgctxt "input"
msgid "Payment Method"
msgstr "Mètode de pagament"
#: pkg/quote.go:646
#: pkg/quote.go:613
msgid "Select a payment method."
msgstr "Escolliu un mètode de pagament."
#: pkg/quote.go:649
msgid "Selected quotation status is not valid."
msgstr "Heu seleccionat un estat de pressupost que no és vàlid."
#: pkg/quote.go:647 pkg/invoices.go:643
#: pkg/quote.go:651 pkg/invoices.go:643
msgid "Selected customer is not valid."
msgstr "Heu seleccionat un client que no és vàlid."
#: pkg/quote.go:648
#: pkg/quote.go:653
msgid "Quotation date can not be empty."
msgstr "No podeu deixar la data del pressupost en blanc."
#: pkg/quote.go:649
#: pkg/quote.go:654
msgid "Quotation date must be a valid date."
msgstr "La data del pressupost ha de ser vàlida."
#: pkg/quote.go:651 pkg/invoices.go:647
#: pkg/quote.go:657 pkg/invoices.go:647
msgid "Selected payment method is not valid."
msgstr "Heu seleccionat un mètode de pagament que no és vàlid."
#: pkg/quote.go:783 pkg/quote.go:788 pkg/invoices.go:814 pkg/invoices.go:819
#: pkg/quote.go:791 pkg/quote.go:796 pkg/invoices.go:814 pkg/invoices.go:819
msgctxt "input"
msgid "Id"
msgstr "Identificador"
#: pkg/quote.go:821 pkg/invoices.go:852
#: pkg/quote.go:829 pkg/invoices.go:852
msgctxt "input"
msgid "Quantity"
msgstr "Quantitat"
#: pkg/quote.go:830 pkg/invoices.go:861
#: pkg/quote.go:838 pkg/invoices.go:861
msgctxt "input"
msgid "Discount (%)"
msgstr "Descompte (%)"
#: pkg/quote.go:884
#: pkg/quote.go:892
msgid "Quotation product ID must be a number greater than zero."
msgstr "LID del producte de pressupost ha de ser un número major a zero."
#: pkg/quote.go:887 pkg/invoices.go:918
#: pkg/quote.go:895 pkg/invoices.go:918
msgid "Product ID must be a positive number or zero."
msgstr "LID del producte ha de ser un número positiu o zero."
#: pkg/quote.go:893 pkg/invoices.go:924
#: pkg/quote.go:901 pkg/invoices.go:924
msgid "Quantity can not be empty."
msgstr "No podeu deixar la quantitat en blanc."
#: pkg/quote.go:894 pkg/invoices.go:925
#: pkg/quote.go:902 pkg/invoices.go:925
msgid "Quantity must be a number greater than zero."
msgstr "La quantitat ha de ser un número major a zero."
#: pkg/quote.go:896 pkg/invoices.go:927
#: pkg/quote.go:904 pkg/invoices.go:927
msgid "Discount can not be empty."
msgstr "No podeu deixar el descompte en blanc."
#: pkg/quote.go:897 pkg/invoices.go:928
#: pkg/quote.go:905 pkg/invoices.go:928
msgid "Discount must be a percentage between 0 and 100."
msgstr "El descompte ha de ser un percentatge entre 0 i 100."

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-07 16:05+0200\n"
"POT-Creation-Date: 2023-06-08 12:44+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"
@ -65,7 +65,7 @@ msgstr "Nombre"
#: web/template/invoices/products.gohtml:50
#: web/template/invoices/view.gohtml:62 web/template/quotes/products.gohtml:50
#: web/template/quotes/view.gohtml:62 web/template/products/index.gohtml:42
#: web/template/quotes/view.gohtml:68 web/template/products/index.gohtml:42
msgctxt "title"
msgid "Price"
msgstr "Precio"
@ -95,15 +95,15 @@ msgstr "Deshacer"
#: web/template/invoices/new.gohtml:60 web/template/invoices/view.gohtml:67
#: web/template/invoices/edit.gohtml:61 web/template/quotes/new.gohtml:61
#: web/template/quotes/view.gohtml:67 web/template/quotes/edit.gohtml:62
#: web/template/quotes/view.gohtml:73 web/template/quotes/edit.gohtml:62
msgctxt "title"
msgid "Subtotal"
msgstr "Subtotal"
#: web/template/invoices/new.gohtml:70 web/template/invoices/view.gohtml:71
#: web/template/invoices/view.gohtml:111 web/template/invoices/edit.gohtml:71
#: web/template/quotes/new.gohtml:71 web/template/quotes/view.gohtml:71
#: web/template/quotes/view.gohtml:111 web/template/quotes/edit.gohtml:72
#: web/template/quotes/new.gohtml:71 web/template/quotes/view.gohtml:77
#: web/template/quotes/view.gohtml:117 web/template/quotes/edit.gohtml:72
msgctxt "title"
msgid "Total"
msgstr "Total"
@ -226,22 +226,22 @@ msgctxt "action"
msgid "Download invoice"
msgstr "Descargar factura"
#: web/template/invoices/view.gohtml:61 web/template/quotes/view.gohtml:61
#: web/template/invoices/view.gohtml:61 web/template/quotes/view.gohtml:67
msgctxt "title"
msgid "Concept"
msgstr "Concepto"
#: web/template/invoices/view.gohtml:64 web/template/quotes/view.gohtml:64
#: web/template/invoices/view.gohtml:64 web/template/quotes/view.gohtml:70
msgctxt "title"
msgid "Discount"
msgstr "Descuento"
#: web/template/invoices/view.gohtml:66 web/template/quotes/view.gohtml:66
#: web/template/invoices/view.gohtml:66 web/template/quotes/view.gohtml:72
msgctxt "title"
msgid "Units"
msgstr "Unidades"
#: web/template/invoices/view.gohtml:101 web/template/quotes/view.gohtml:101
#: web/template/invoices/view.gohtml:101 web/template/quotes/view.gohtml:107
msgctxt "title"
msgid "Tax Base"
msgstr "Base imponible"
@ -353,6 +353,10 @@ msgctxt "action"
msgid "Download quotation"
msgstr "Descargar presupuesto"
#: web/template/quotes/view.gohtml:60
msgid "Terms and Conditions:"
msgstr "Condiciones de aceptación:"
#: web/template/quotes/edit.gohtml:2 web/template/quotes/edit.gohtml:19
msgctxt "title"
msgid "Edit Quotation “%s”"
@ -641,13 +645,13 @@ msgstr "No podéis dejar la contraseña en blanco."
msgid "Invalid user or password."
msgstr "Nombre de usuario o contraseña inválido."
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:793 pkg/invoices.go:824
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:801 pkg/invoices.go:824
#: pkg/contacts.go:135
msgctxt "input"
msgid "Name"
msgstr "Nombre"
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:606
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:608
#: pkg/expenses.go:202 pkg/expenses.go:361 pkg/invoices.go:189
#: pkg/invoices.go:601 pkg/invoices.go:1123 pkg/contacts.go:140
#: pkg/contacts.go:325
@ -683,39 +687,39 @@ msgstr "Cualquiera"
msgid "Invoices must have at least one of the specified labels."
msgstr "Las facturas deben tener como mínimo una de las etiquetas."
#: pkg/products.go:269 pkg/quote.go:807 pkg/invoices.go:838
#: pkg/products.go:269 pkg/quote.go:815 pkg/invoices.go:838
msgctxt "input"
msgid "Description"
msgstr "Descripción"
#: pkg/products.go:274 pkg/quote.go:811 pkg/invoices.go:842
#: pkg/products.go:274 pkg/quote.go:819 pkg/invoices.go:842
msgctxt "input"
msgid "Price"
msgstr "Precio"
#: pkg/products.go:284 pkg/quote.go:840 pkg/expenses.go:181 pkg/invoices.go:871
#: pkg/products.go:284 pkg/quote.go:848 pkg/expenses.go:181 pkg/invoices.go:871
msgctxt "input"
msgid "Taxes"
msgstr "Impuestos"
#: pkg/products.go:309 pkg/quote.go:889 pkg/profile.go:92 pkg/invoices.go:920
#: pkg/products.go:309 pkg/quote.go:897 pkg/profile.go:92 pkg/invoices.go:920
msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco."
#: pkg/products.go:310 pkg/quote.go:890 pkg/invoices.go:921
#: pkg/products.go:310 pkg/quote.go:898 pkg/invoices.go:921
msgid "Price can not be empty."
msgstr "No podéis dejar el precio en blanco."
#: pkg/products.go:311 pkg/quote.go:891 pkg/invoices.go:922
#: pkg/products.go:311 pkg/quote.go:899 pkg/invoices.go:922
msgid "Price must be a number greater than zero."
msgstr "El precio tiene que ser un número mayor a cero."
#: pkg/products.go:313 pkg/quote.go:899 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/products.go:313 pkg/quote.go:907 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:930
msgid "Selected tax is not valid."
msgstr "Habéis escogido un impuesto que no es válido."
#: pkg/products.go:314 pkg/quote.go:900 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/products.go:314 pkg/quote.go:908 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:931
msgid "You can only select a tax of each class."
msgstr "Solo podéis escoger un impuesto de cada clase."
@ -805,7 +809,7 @@ msgstr "No podéis dejar el nombre del método de pago en blanco."
msgid "Payment instructions can not be empty."
msgstr "No podéis dejar las instrucciones de pago en blanco."
#: pkg/quote.go:161 pkg/quote.go:585 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/quote.go:161 pkg/quote.go:586 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/invoices.go:584
msgctxt "input"
msgid "Customer"
@ -815,7 +819,7 @@ msgstr "Cliente"
msgid "All customers"
msgstr "Todos los clientes"
#: pkg/quote.go:167 pkg/quote.go:579
#: pkg/quote.go:167 pkg/quote.go:580
msgctxt "input"
msgid "Quotation Status"
msgstr "Estado del presupuesto"
@ -847,95 +851,99 @@ msgstr "Los presupuestos deben tener todas las etiquetas."
msgid "Quotations must have at least one of the specified labels."
msgstr "Los presupuestos deben tener como mínimo una de las etiquetas."
#: pkg/quote.go:451
msgid "Select a customer to quote."
msgstr "Escoged un cliente a presupuestar."
#: pkg/quote.go:527
#: pkg/quote.go:528
msgid "quotations.zip"
msgstr "presupuestos.zip"
#: pkg/quote.go:533 pkg/quote.go:1055 pkg/quote.go:1063 pkg/invoices.go:533
#: pkg/quote.go:534 pkg/quote.go:1063 pkg/quote.go:1071 pkg/invoices.go:533
#: pkg/invoices.go:1098 pkg/invoices.go:1106
msgid "Invalid action"
msgstr "Acción inválida."
#: pkg/quote.go:590
#: pkg/quote.go:587
msgid "Select a customer to quote."
msgstr "Escoged un cliente a presupuestar."
#: pkg/quote.go:592
msgctxt "input"
msgid "Quotation Date"
msgstr "Fecha del presupuesto"
#: pkg/quote.go:596
#: pkg/quote.go:598
msgctxt "input"
msgid "Terms and conditions"
msgstr "Condiciones de aceptación"
#: pkg/quote.go:601 pkg/invoices.go:596
#: pkg/quote.go:603 pkg/invoices.go:596
msgctxt "input"
msgid "Notes"
msgstr "Notas"
#: pkg/quote.go:610 pkg/invoices.go:606
#: pkg/quote.go:612 pkg/invoices.go:606
msgctxt "input"
msgid "Payment Method"
msgstr "Método de pago"
#: pkg/quote.go:646
#: pkg/quote.go:613
msgid "Select a payment method."
msgstr "Escoged un método e pago."
#: pkg/quote.go:649
msgid "Selected quotation status is not valid."
msgstr "Habéis escogido un estado de presupuesto que no es válido."
#: pkg/quote.go:647 pkg/invoices.go:643
#: pkg/quote.go:651 pkg/invoices.go:643
msgid "Selected customer is not valid."
msgstr "Habéis escogido un cliente que no es válido."
#: pkg/quote.go:648
#: pkg/quote.go:653
msgid "Quotation date can not be empty."
msgstr "No podéis dejar la fecha del presupuesto en blanco."
#: pkg/quote.go:649
#: pkg/quote.go:654
msgid "Quotation date must be a valid date."
msgstr "La fecha de presupuesto debe ser válida."
#: pkg/quote.go:651 pkg/invoices.go:647
#: pkg/quote.go:657 pkg/invoices.go:647
msgid "Selected payment method is not valid."
msgstr "Habéis escogido un método de pago que no es válido."
#: pkg/quote.go:783 pkg/quote.go:788 pkg/invoices.go:814 pkg/invoices.go:819
#: pkg/quote.go:791 pkg/quote.go:796 pkg/invoices.go:814 pkg/invoices.go:819
msgctxt "input"
msgid "Id"
msgstr "Identificador"
#: pkg/quote.go:821 pkg/invoices.go:852
#: pkg/quote.go:829 pkg/invoices.go:852
msgctxt "input"
msgid "Quantity"
msgstr "Cantidad"
#: pkg/quote.go:830 pkg/invoices.go:861
#: pkg/quote.go:838 pkg/invoices.go:861
msgctxt "input"
msgid "Discount (%)"
msgstr "Descuento (%)"
#: pkg/quote.go:884
#: pkg/quote.go:892
msgid "Quotation product ID must be a number greater than zero."
msgstr "El ID de producto de presupuesto tiene que ser un número mayor a cero."
#: pkg/quote.go:887 pkg/invoices.go:918
#: pkg/quote.go:895 pkg/invoices.go:918
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/quote.go:893 pkg/invoices.go:924
#: pkg/quote.go:901 pkg/invoices.go:924
msgid "Quantity can not be empty."
msgstr "No podéis dejar la cantidad en blanco."
#: pkg/quote.go:894 pkg/invoices.go:925
#: pkg/quote.go:902 pkg/invoices.go:925
msgid "Quantity must be a number greater than zero."
msgstr "La cantidad tiene que ser un número mayor a cero."
#: pkg/quote.go:896 pkg/invoices.go:927
#: pkg/quote.go:904 pkg/invoices.go:927
msgid "Discount can not be empty."
msgstr "No podéis dejar el descuento en blanco."
#: pkg/quote.go:897 pkg/invoices.go:928
#: pkg/quote.go:905 pkg/invoices.go:928
msgid "Discount must be a percentage between 0 and 100."
msgstr "El descuento tiene que ser un porcentaje entre 0 y 100."

View File

@ -20,7 +20,7 @@
padding: 0 0 0 2.5rem;
}
.invoice .invoicee, .invoice .invoicer {
.invoice .invoicee, .invoice .invoicer, .invoice .quotee, .invoice .quoter {
font-style: normal;
}
@ -28,11 +28,11 @@
margin-top: 2em;
}
.invoice .invoicer {
.invoice .invoicer, .invoice .quoter {
margin-top: 9rem;
}
.invoice .invoicee {
.invoice .invoicee, .invoice .quotee {
margin-top: 1em;
text-align: right;
}
@ -55,11 +55,20 @@
text-align: right;
}
.invoice .notes, .invoice .payment-instructions {
.invoice .notes, .invoice .payment-instructions, .invoice .terms_and_conditions {
white-space: pre-line;
text-align: left;
}
.invoice .terms_and_conditions {
text-transform: uppercase;
font-weight: bold;
}
.invoice .quotee + .terms_and_conditions {
margin-top: 2rem;
}
.invoice .notes + .payment-instructions {
margin-top: 5rem;
}

View File

@ -47,13 +47,19 @@
</header>
<div>
{{ if .HasQuotee -}}
<address class="quotee">
{{ .Quotee.Name }}<br>
{{ .Quotee.VATIN }}<br>
{{ .Quotee.Address }}<br>
{{ .Quotee.City }} ({{ .Quotee.PostalCode}}), {{ .Quotee.Province }}<br>
</address>
{{- end }}
{{ if .TermsAndConditions -}}
<p class="terms_and_conditions">{{(gettext "Terms and Conditions:")}} {{ .TermsAndConditions }}</p>
{{- end }}
{{- $columns := 5 | add (len .TaxClasses) | add (boolToInt .HasDiscounts) -}}
<table>
<thead>