From b7881c505f1eec3e0d6256d11e72626059a4cf76 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Wed, 29 Mar 2023 16:16:31 +0200 Subject: [PATCH] Add filters form for invoices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using links in the invoice tags, that we will replace with a “click-to-edit field”, with Oriol agreed to add a form with filters that includes not only the tags but also dates, customer, status, and the invoice number. This means i now need dynamic SQL, and i do not think this belongs to the database (i.e., no PL/pgSQL function for that). I have looked at query builder libraries for Golang, and did not find anything that suited me: either they wanted to manage not only the SQL query but also all structs, or they managed to confuse Goland’s SQL analyzer. For now, at least, i am using a very simple approach with arrays, that still confuses Goland’s analyzer, but just in a very specific part, which i find tolerable—not that their analyzer is that great to begin with, but that’s a story for another day. --- pkg/form.go | 8 +- pkg/invoices.go | 109 +++++++++++++++++++-- po/ca.po | 151 +++++++++++++++++------------ po/es.po | 151 +++++++++++++++++------------ web/template/invoices/index.gohtml | 18 +++- 5 files changed, 300 insertions(+), 137 deletions(-) diff --git a/pkg/form.go b/pkg/form.go index 6f74a86..4ad8d08 100644 --- a/pkg/form.go +++ b/pkg/form.go @@ -116,10 +116,14 @@ func (field *SelectField) Scan(value interface{}) error { } func (field *SelectField) Value() (driver.Value, error) { + return field.String(), nil +} + +func (field *SelectField) String() string { if field.Selected == nil { - return "", nil + return "" } - return field.Selected[0], nil + return field.Selected[0] } func (field *SelectField) FillValue(r *http.Request) { diff --git a/pkg/invoices.go b/pkg/invoices.go index 305ca44..e237b2c 100644 --- a/pkg/invoices.go +++ b/pkg/invoices.go @@ -33,22 +33,55 @@ type InvoiceEntry struct { type InvoicesIndexPage struct { Invoices []*InvoiceEntry + Filters *invoiceFilterForm InvoiceStatuses map[string]string } func IndexInvoices(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { conn := getConn(r) locale := getLocale(r) - tag := r.URL.Query().Get("tag") + company := mustGetCompany(r) + filters := newInvoiceFilterForm(r.Context(), conn, locale, company) + if err := filters.Parse(r); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } page := &InvoicesIndexPage{ - Invoices: mustCollectInvoiceEntries(r.Context(), conn, mustGetCompany(r), locale, tag), + Invoices: mustCollectInvoiceEntries(r.Context(), conn, company, locale, filters), + Filters: filters, InvoiceStatuses: mustCollectInvoiceStatuses(r.Context(), conn, locale), } mustRenderMainTemplate(w, r, "invoices/index.gohtml", page) } -func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, tag string) []*InvoiceEntry { - rows := conn.MustQuery(ctx, ` +func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, filters *invoiceFilterForm) []*InvoiceEntry { + args := []interface{}{locale.Language.String(), company.Id} + where := []string{"invoice.company_id = $2"} + appendWhere := func(expression string, value interface{}) { + args = append(args, value) + where = append(where, fmt.Sprintf(expression, len(args))) + } + maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) { + if value != "" { + if conv == nil { + appendWhere(expression, value) + } else { + appendWhere(expression, conv(value)) + } + } + } + maybeAppendWhere("contact_id = $%d", filters.Customer.String(), func(v string) interface{} { + customerId, _ := strconv.Atoi(filters.Customer.Selected[0]) + return customerId + }) + maybeAppendWhere("invoice.invoice_status = $%d", filters.InvoiceStatus.String(), nil) + maybeAppendWhere("invoice_number = $%d", filters.InvoiceNumber.String(), nil) + maybeAppendWhere("invoice_date >= $%d", filters.FromDate.String(), nil) + maybeAppendWhere("invoice_date <= $%d", filters.ToDate.String(), nil) + if len(filters.Tags.Tags) > 0 { + appendWhere("exists (select 1 from invoice_tag join tag using (tag_id) where invoice_tag.invoice_id = invoice.invoice_id and tag.name = any($%d))", filters.Tags) + } + rows := conn.MustQuery(ctx, fmt.Sprintf(` select invoice.slug , invoice_date , invoice_number @@ -61,10 +94,10 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company left join invoice_tag using (invoice_id) left join tag using(tag_id) join contact using (contact_id) - join invoice_status_i18n isi18n on invoice.invoice_status = isi18n.invoice_status and isi18n.lang_tag = $2 + join invoice_status_i18n isi18n on invoice.invoice_status = isi18n.invoice_status and isi18n.lang_tag = $1 join invoice_amount using (invoice_id) join currency using (currency_code) - where invoice.company_id = $1 and (($3 = '') or (tag.name = $3)) + where (%s) group by invoice.slug , invoice_date , invoice_number @@ -75,7 +108,7 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company , decimal_digits order by invoice_date desc , invoice_number desc - `, company.Id, locale.Language.String(), tag) + `, strings.Join(where, ") AND (")), args...) defer rows.Close() var entries []*InvoiceEntry @@ -112,6 +145,68 @@ func mustCollectInvoiceStatuses(ctx context.Context, conn *Conn, locale *Locale) return statuses } +type invoiceFilterForm struct { + locale *Locale + company *Company + Customer *SelectField + InvoiceStatus *SelectField + InvoiceNumber *InputField + FromDate *InputField + ToDate *InputField + Tags *TagsField +} + +func newInvoiceFilterForm(ctx context.Context, conn *Conn, locale *Locale, company *Company) *invoiceFilterForm { + return &invoiceFilterForm{ + locale: locale, + company: company, + Customer: &SelectField{ + Name: "customer", + Label: pgettext("input", "Customer", locale), + EmptyLabel: gettext("All customers", locale), + Options: MustGetOptions(ctx, conn, "select contact_id::text, business_name from contact where company_id = $1 order by business_name", company.Id), + }, + InvoiceStatus: &SelectField{ + Name: "invoice_status", + Label: pgettext("input", "Invoice Status", locale), + EmptyLabel: gettext("All status", locale), + Options: MustGetOptions(ctx, conn, "select invoice_status.invoice_status, isi18n.name from invoice_status join invoice_status_i18n isi18n using(invoice_status) where isi18n.lang_tag = $1 order by invoice_status", locale.Language.String()), + }, + InvoiceNumber: &InputField{ + Name: "number", + Label: pgettext("input", "Invoice Number", locale), + Type: "text", + }, + FromDate: &InputField{ + Name: "from_date", + Label: pgettext("input", "From Date", locale), + Type: "date", + }, + ToDate: &InputField{ + Name: "to_date", + Label: pgettext("input", "To Date", locale), + Type: "date", + }, + Tags: &TagsField{ + Name: "tags", + Label: pgettext("input", "Tags", locale), + }, + } +} + +func (form *invoiceFilterForm) Parse(r *http.Request) error { + if err := r.ParseForm(); err != nil { + return err + } + form.Customer.FillValue(r) + form.InvoiceStatus.FillValue(r) + form.InvoiceNumber.FillValue(r) + form.FromDate.FillValue(r) + form.ToDate.FillValue(r) + form.Tags.FillValue(r) + return nil +} + func ServeInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Params) { conn := getConn(r) company := mustGetCompany(r) diff --git a/po/ca.po b/po/ca.po index cdea738..39ec98d 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: numerus\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-03-27 09:43+0200\n" +"POT-Creation-Date: 2023-03-29 16:08+0200\n" "PO-Revision-Date: 2023-01-18 17:08+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -103,68 +103,73 @@ msgctxt "action" msgid "Download invoices" msgstr "Descarrega factures" -#: web/template/invoices/index.gohtml:31 +#: web/template/invoices/index.gohtml:38 +msgctxt "action" +msgid "Filter" +msgstr "Filtra" + +#: web/template/invoices/index.gohtml:44 msgctxt "invoice" msgid "All" msgstr "Totes" -#: web/template/invoices/index.gohtml:32 web/template/invoices/view.gohtml:31 +#: web/template/invoices/index.gohtml:45 web/template/invoices/view.gohtml:31 msgctxt "title" msgid "Date" msgstr "Data" -#: web/template/invoices/index.gohtml:33 +#: web/template/invoices/index.gohtml:46 msgctxt "title" msgid "Invoice Num." msgstr "Núm. factura" -#: web/template/invoices/index.gohtml:34 web/template/contacts/index.gohtml:26 +#: web/template/invoices/index.gohtml:47 web/template/contacts/index.gohtml:26 msgctxt "title" msgid "Customer" msgstr "Client" -#: web/template/invoices/index.gohtml:35 +#: web/template/invoices/index.gohtml:48 msgctxt "title" msgid "Status" msgstr "Estat" -#: web/template/invoices/index.gohtml:36 web/template/contacts/index.gohtml:29 +#: web/template/invoices/index.gohtml:49 web/template/contacts/index.gohtml:29 #: web/template/products/index.gohtml:27 msgctxt "title" msgid "Tags" msgstr "Etiquetes" -#: web/template/invoices/index.gohtml:37 +#: web/template/invoices/index.gohtml:50 msgctxt "title" msgid "Amount" msgstr "Import" -#: web/template/invoices/index.gohtml:38 +#: web/template/invoices/index.gohtml:51 msgctxt "title" msgid "Download" msgstr "Descàrrega" -#: web/template/invoices/index.gohtml:39 +#: web/template/invoices/index.gohtml:52 msgctxt "title" msgid "Actions" msgstr "Accions" -#: web/template/invoices/index.gohtml:46 +#: web/template/invoices/index.gohtml:59 msgctxt "action" msgid "Select invoice %v" msgstr "Selecciona factura %v" -#: web/template/invoices/index.gohtml:95 web/template/invoices/view.gohtml:16 +#: web/template/invoices/index.gohtml:109 web/template/invoices/view.gohtml:16 msgctxt "action" msgid "Edit" msgstr "Edita" -#: web/template/invoices/index.gohtml:101 web/template/invoices/view.gohtml:15 +#: web/template/invoices/index.gohtml:115 web/template/invoices/view.gohtml:15 msgctxt "action" msgid "Duplicate" msgstr "Duplica" -#: web/template/invoices/index.gohtml:111 +#: web/template/invoices/index.gohtml:125 msgid "No invoices added yet." msgstr "No hi ha cap factura." @@ -451,48 +456,49 @@ msgstr "No podeu deixar la contrasenya en blanc." msgid "Invalid user or password." msgstr "Nom d’usuari o contrasenya incorrectes." -#: pkg/products.go:209 pkg/invoices.go:636 +#: pkg/products.go:209 pkg/invoices.go:728 msgctxt "input" msgid "Name" msgstr "Nom" -#: pkg/products.go:215 pkg/invoices.go:641 +#: pkg/products.go:215 pkg/invoices.go:733 msgctxt "input" msgid "Description" msgstr "Descripció" -#: pkg/products.go:220 pkg/invoices.go:645 +#: pkg/products.go:220 pkg/invoices.go:737 msgctxt "input" msgid "Price" msgstr "Preu" -#: pkg/products.go:230 pkg/invoices.go:671 +#: pkg/products.go:230 pkg/invoices.go:763 msgctxt "input" msgid "Taxes" msgstr "Imposts" -#: pkg/products.go:236 pkg/invoices.go:479 pkg/contacts.go:273 +#: pkg/products.go:236 pkg/invoices.go:192 pkg/invoices.go:571 +#: pkg/contacts.go:273 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:255 pkg/profile.go:92 pkg/invoices.go:710 +#: pkg/products.go:255 pkg/profile.go:92 pkg/invoices.go:802 msgid "Name can not be empty." msgstr "No podeu deixar el nom en blanc." -#: pkg/products.go:256 pkg/invoices.go:711 +#: pkg/products.go:256 pkg/invoices.go:803 msgid "Price can not be empty." msgstr "No podeu deixar el preu en blanc." -#: pkg/products.go:257 pkg/invoices.go:712 +#: pkg/products.go:257 pkg/invoices.go:804 msgid "Price must be a number greater than zero." msgstr "El preu ha de ser un número major a zero." -#: pkg/products.go:259 pkg/invoices.go:720 +#: pkg/products.go:259 pkg/invoices.go:812 msgid "Selected tax is not valid." msgstr "Heu seleccionat un impost que no és vàlid." -#: pkg/products.go:260 pkg/invoices.go:721 +#: pkg/products.go:260 pkg/invoices.go:813 msgid "You can only select a tax of each class." msgstr "Només podeu seleccionar un impost de cada classe." @@ -600,100 +606,123 @@ msgstr "La confirmació no és igual a la contrasenya." msgid "Selected language is not valid." msgstr "Heu seleccionat un idioma que no és vàlid." -#: pkg/invoices.go:302 -msgid "Select a customer to bill." -msgstr "Escolliu un client a facturar." - -#: pkg/invoices.go:401 -msgid "invoices.zip" -msgstr "factures.zip" - -#: pkg/invoices.go:407 pkg/invoices.go:829 -msgid "Invalid action" -msgstr "Acció invàlida." - -#: pkg/invoices.go:451 -msgctxt "input" -msgid "Invoice Status" -msgstr "Estat de la factura" - -#: pkg/invoices.go:457 +#: pkg/invoices.go:165 pkg/invoices.go:549 msgctxt "input" msgid "Customer" msgstr "Client" -#: pkg/invoices.go:463 +#: pkg/invoices.go:166 +msgid "All customers" +msgstr "Tots els clients" + +#: pkg/invoices.go:171 pkg/invoices.go:543 +msgctxt "input" +msgid "Invoice Status" +msgstr "Estat de la factura" + +#: pkg/invoices.go:172 +msgid "All status" +msgstr "Tots els estats" + +#: pkg/invoices.go:177 +msgctxt "input" +msgid "Invoice Number" +msgstr "Número de factura" + +#: pkg/invoices.go:182 +msgctxt "input" +msgid "From Date" +msgstr "De la data" + +#: pkg/invoices.go:187 +msgctxt "input" +msgid "To Date" +msgstr "A la data" + +#: pkg/invoices.go:394 +msgid "Select a customer to bill." +msgstr "Escolliu un client a facturar." + +#: pkg/invoices.go:493 +msgid "invoices.zip" +msgstr "factures.zip" + +#: pkg/invoices.go:499 pkg/invoices.go:921 +msgid "Invalid action" +msgstr "Acció invàlida." + +#: pkg/invoices.go:555 msgctxt "input" msgid "Number" msgstr "Número" -#: pkg/invoices.go:468 +#: pkg/invoices.go:560 msgctxt "input" msgid "Invoice Date" msgstr "Data de factura" -#: pkg/invoices.go:474 +#: pkg/invoices.go:566 msgctxt "input" msgid "Notes" msgstr "Notes" -#: pkg/invoices.go:484 +#: pkg/invoices.go:576 msgctxt "input" msgid "Payment Method" msgstr "Mètode de pagament" -#: pkg/invoices.go:521 +#: pkg/invoices.go:613 msgid "Selected invoice status is not valid." msgstr "Heu seleccionat un estat de factura que no és vàlid." -#: pkg/invoices.go:522 +#: pkg/invoices.go:614 msgid "Selected customer is not valid." msgstr "Heu seleccionat un client que no és vàlid." -#: pkg/invoices.go:523 +#: pkg/invoices.go:615 msgid "Invoice date can not be empty." msgstr "No podeu deixar la data de la factura en blanc." -#: pkg/invoices.go:524 +#: pkg/invoices.go:616 msgid "Invoice date must be a valid date." msgstr "La data de facturació ha de ser vàlida." -#: pkg/invoices.go:526 +#: pkg/invoices.go:618 msgid "Selected payment method is not valid." msgstr "Heu seleccionat un mètode de pagament que no és vàlid." -#: pkg/invoices.go:626 pkg/invoices.go:631 +#: pkg/invoices.go:718 pkg/invoices.go:723 msgctxt "input" msgid "Id" msgstr "Identificador" -#: pkg/invoices.go:654 +#: pkg/invoices.go:746 msgctxt "input" msgid "Quantity" msgstr "Quantitat" -#: pkg/invoices.go:662 +#: pkg/invoices.go:754 msgctxt "input" msgid "Discount (%)" msgstr "Descompte (%)" -#: pkg/invoices.go:709 +#: pkg/invoices.go:801 msgid "Product ID can not be empty." msgstr "No podeu deixar l’identificador del producte en blanc." -#: pkg/invoices.go:714 +#: pkg/invoices.go:806 msgid "Quantity can not be empty." msgstr "No podeu deixar la quantitat en blanc." -#: pkg/invoices.go:715 +#: pkg/invoices.go:807 msgid "Quantity must be a number greater than zero." msgstr "La quantitat ha de ser un número major a zero." -#: pkg/invoices.go:717 +#: pkg/invoices.go:809 msgid "Discount can not be empty." msgstr "No podeu deixar el descompte en blanc." -#: pkg/invoices.go:718 +#: pkg/invoices.go:810 msgid "Discount must be a percentage between 0 and 100." msgstr "El descompte ha de ser un percentatge entre 0 i 100." @@ -806,10 +835,6 @@ msgstr "Aquest valor no és un codi postal vàlid." #~ msgid "Tax" #~ msgstr "Impost" -#~ msgctxt "nav" -#~ msgid "Customers" -#~ msgstr "Clients" - #~ msgctxt "title" #~ msgid "Customers" #~ msgstr "Clients" diff --git a/po/es.po b/po/es.po index 16004da..09cae67 100644 --- a/po/es.po +++ b/po/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: numerus\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-03-27 09:43+0200\n" +"POT-Creation-Date: 2023-03-29 16:08+0200\n" "PO-Revision-Date: 2023-01-18 17:45+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -103,68 +103,73 @@ msgctxt "action" msgid "Download invoices" msgstr "Descargar facturas" -#: web/template/invoices/index.gohtml:31 +#: web/template/invoices/index.gohtml:38 +msgctxt "action" +msgid "Filter" +msgstr "Filtrar" + +#: web/template/invoices/index.gohtml:44 msgctxt "invoice" msgid "All" msgstr "Todas" -#: web/template/invoices/index.gohtml:32 web/template/invoices/view.gohtml:31 +#: web/template/invoices/index.gohtml:45 web/template/invoices/view.gohtml:31 msgctxt "title" msgid "Date" msgstr "Fecha" -#: web/template/invoices/index.gohtml:33 +#: web/template/invoices/index.gohtml:46 msgctxt "title" msgid "Invoice Num." msgstr "Nº factura" -#: web/template/invoices/index.gohtml:34 web/template/contacts/index.gohtml:26 +#: web/template/invoices/index.gohtml:47 web/template/contacts/index.gohtml:26 msgctxt "title" msgid "Customer" msgstr "Cliente" -#: web/template/invoices/index.gohtml:35 +#: web/template/invoices/index.gohtml:48 msgctxt "title" msgid "Status" msgstr "Estado" -#: web/template/invoices/index.gohtml:36 web/template/contacts/index.gohtml:29 +#: web/template/invoices/index.gohtml:49 web/template/contacts/index.gohtml:29 #: web/template/products/index.gohtml:27 msgctxt "title" msgid "Tags" msgstr "Etiquetes" -#: web/template/invoices/index.gohtml:37 +#: web/template/invoices/index.gohtml:50 msgctxt "title" msgid "Amount" msgstr "Importe" -#: web/template/invoices/index.gohtml:38 +#: web/template/invoices/index.gohtml:51 msgctxt "title" msgid "Download" msgstr "Descargar" -#: web/template/invoices/index.gohtml:39 +#: web/template/invoices/index.gohtml:52 msgctxt "title" msgid "Actions" msgstr "Acciones" -#: web/template/invoices/index.gohtml:46 +#: web/template/invoices/index.gohtml:59 msgctxt "action" msgid "Select invoice %v" msgstr "Seleccionar factura %v" -#: web/template/invoices/index.gohtml:95 web/template/invoices/view.gohtml:16 +#: web/template/invoices/index.gohtml:109 web/template/invoices/view.gohtml:16 msgctxt "action" msgid "Edit" msgstr "Editar" -#: web/template/invoices/index.gohtml:101 web/template/invoices/view.gohtml:15 +#: web/template/invoices/index.gohtml:115 web/template/invoices/view.gohtml:15 msgctxt "action" msgid "Duplicate" msgstr "Duplicar" -#: web/template/invoices/index.gohtml:111 +#: web/template/invoices/index.gohtml:125 msgid "No invoices added yet." msgstr "No hay facturas." @@ -451,48 +456,49 @@ 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:209 pkg/invoices.go:636 +#: pkg/products.go:209 pkg/invoices.go:728 msgctxt "input" msgid "Name" msgstr "Nombre" -#: pkg/products.go:215 pkg/invoices.go:641 +#: pkg/products.go:215 pkg/invoices.go:733 msgctxt "input" msgid "Description" msgstr "Descripción" -#: pkg/products.go:220 pkg/invoices.go:645 +#: pkg/products.go:220 pkg/invoices.go:737 msgctxt "input" msgid "Price" msgstr "Precio" -#: pkg/products.go:230 pkg/invoices.go:671 +#: pkg/products.go:230 pkg/invoices.go:763 msgctxt "input" msgid "Taxes" msgstr "Impuestos" -#: pkg/products.go:236 pkg/invoices.go:479 pkg/contacts.go:273 +#: pkg/products.go:236 pkg/invoices.go:192 pkg/invoices.go:571 +#: pkg/contacts.go:273 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:255 pkg/profile.go:92 pkg/invoices.go:710 +#: pkg/products.go:255 pkg/profile.go:92 pkg/invoices.go:802 msgid "Name can not be empty." msgstr "No podéis dejar el nombre en blanco." -#: pkg/products.go:256 pkg/invoices.go:711 +#: pkg/products.go:256 pkg/invoices.go:803 msgid "Price can not be empty." msgstr "No podéis dejar el precio en blanco." -#: pkg/products.go:257 pkg/invoices.go:712 +#: pkg/products.go:257 pkg/invoices.go:804 msgid "Price must be a number greater than zero." msgstr "El precio tiene que ser un número mayor a cero." -#: pkg/products.go:259 pkg/invoices.go:720 +#: pkg/products.go:259 pkg/invoices.go:812 msgid "Selected tax is not valid." msgstr "Habéis escogido un impuesto que no es válido." -#: pkg/products.go:260 pkg/invoices.go:721 +#: pkg/products.go:260 pkg/invoices.go:813 msgid "You can only select a tax of each class." msgstr "Solo podéis escoger un impuesto de cada clase." @@ -600,100 +606,123 @@ msgstr "La confirmación no corresponde con la contraseña." msgid "Selected language is not valid." msgstr "Habéis escogido un idioma que no es válido." -#: pkg/invoices.go:302 -msgid "Select a customer to bill." -msgstr "Escoged un cliente a facturar." - -#: pkg/invoices.go:401 -msgid "invoices.zip" -msgstr "facturas.zip" - -#: pkg/invoices.go:407 pkg/invoices.go:829 -msgid "Invalid action" -msgstr "Acción inválida." - -#: pkg/invoices.go:451 -msgctxt "input" -msgid "Invoice Status" -msgstr "Estado de la factura" - -#: pkg/invoices.go:457 +#: pkg/invoices.go:165 pkg/invoices.go:549 msgctxt "input" msgid "Customer" msgstr "Cliente" -#: pkg/invoices.go:463 +#: pkg/invoices.go:166 +msgid "All customers" +msgstr "Todos los clientes" + +#: pkg/invoices.go:171 pkg/invoices.go:543 +msgctxt "input" +msgid "Invoice Status" +msgstr "Estado de la factura" + +#: pkg/invoices.go:172 +msgid "All status" +msgstr "Todos los estados" + +#: pkg/invoices.go:177 +msgctxt "input" +msgid "Invoice Number" +msgstr "Número de factura" + +#: pkg/invoices.go:182 +msgctxt "input" +msgid "From Date" +msgstr "De la fecha" + +#: pkg/invoices.go:187 +msgctxt "input" +msgid "To Date" +msgstr "A la fecha" + +#: pkg/invoices.go:394 +msgid "Select a customer to bill." +msgstr "Escoged un cliente a facturar." + +#: pkg/invoices.go:493 +msgid "invoices.zip" +msgstr "facturas.zip" + +#: pkg/invoices.go:499 pkg/invoices.go:921 +msgid "Invalid action" +msgstr "Acción inválida." + +#: pkg/invoices.go:555 msgctxt "input" msgid "Number" msgstr "Número" -#: pkg/invoices.go:468 +#: pkg/invoices.go:560 msgctxt "input" msgid "Invoice Date" msgstr "Fecha de factura" -#: pkg/invoices.go:474 +#: pkg/invoices.go:566 msgctxt "input" msgid "Notes" msgstr "Notas" -#: pkg/invoices.go:484 +#: pkg/invoices.go:576 msgctxt "input" msgid "Payment Method" msgstr "Método de pago" -#: pkg/invoices.go:521 +#: pkg/invoices.go:613 msgid "Selected invoice status is not valid." msgstr "Habéis escogido un estado de factura que no es válido." -#: pkg/invoices.go:522 +#: pkg/invoices.go:614 msgid "Selected customer is not valid." msgstr "Habéis escogido un cliente que no es válido." -#: pkg/invoices.go:523 +#: pkg/invoices.go:615 msgid "Invoice date can not be empty." msgstr "No podéis dejar la fecha de la factura en blanco." -#: pkg/invoices.go:524 +#: pkg/invoices.go:616 msgid "Invoice date must be a valid date." msgstr "La fecha de factura debe ser válida." -#: pkg/invoices.go:526 +#: pkg/invoices.go:618 msgid "Selected payment method is not valid." msgstr "Habéis escogido un método de pago que no es válido." -#: pkg/invoices.go:626 pkg/invoices.go:631 +#: pkg/invoices.go:718 pkg/invoices.go:723 msgctxt "input" msgid "Id" msgstr "Identificador" -#: pkg/invoices.go:654 +#: pkg/invoices.go:746 msgctxt "input" msgid "Quantity" msgstr "Cantidad" -#: pkg/invoices.go:662 +#: pkg/invoices.go:754 msgctxt "input" msgid "Discount (%)" msgstr "Descuento (%)" -#: pkg/invoices.go:709 +#: pkg/invoices.go:801 msgid "Product ID can not be empty." msgstr "No podéis dejar el identificador de producto en blanco." -#: pkg/invoices.go:714 +#: pkg/invoices.go:806 msgid "Quantity can not be empty." msgstr "No podéis dejar la cantidad en blanco." -#: pkg/invoices.go:715 +#: pkg/invoices.go:807 msgid "Quantity must be a number greater than zero." msgstr "La cantidad tiene que ser un número mayor a cero." -#: pkg/invoices.go:717 +#: pkg/invoices.go:809 msgid "Discount can not be empty." msgstr "No podéis dejar el descuento en blanco." -#: pkg/invoices.go:718 +#: pkg/invoices.go:810 msgid "Discount must be a percentage between 0 and 100." msgstr "El descuento tiene que ser un porcentaje entre 0 y 100." @@ -806,10 +835,6 @@ msgstr "Este valor no es un código postal válido válido." #~ msgid "Tax" #~ msgstr "Impuesto" -#~ msgctxt "nav" -#~ msgid "Customers" -#~ msgstr "Clientes" - #~ msgctxt "title" #~ msgid "Customers" #~ msgstr "Clientes" diff --git a/web/template/invoices/index.gohtml b/web/template/invoices/index.gohtml index d057c7a..5dfafc4 100644 --- a/web/template/invoices/index.gohtml +++ b/web/template/invoices/index.gohtml @@ -25,6 +25,19 @@ {{ define "content" }} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicesIndexPage*/ -}} +
+
+ {{ with .Filters }} + {{ template "select-field" .Customer }} + {{ template "select-field" .InvoiceStatus }} + {{ template "input-field" .FromDate }} + {{ template "input-field" .ToDate }} + {{ template "input-field" .InvoiceNumber }} + {{ template "tags-field" .Tags }} + {{ end }} + +
+
@@ -49,7 +62,8 @@ aria-label="{{ $title }}" title="{{ $title }}"/> - +
{{ .Date|formatDate }}{{ .Number }}{{ .Number }} {{ .CustomerName }} {{- range $index, $tag := .Tags }} {{- if gt $index 0 }}, {{ end -}} - {{ . }} + {{ . }} {{- end }} {{ .Total|formatPrice }}