diff --git a/pkg/expenses.go b/pkg/expenses.go index c3e4c98..06360a5 100644 --- a/pkg/expenses.go +++ b/pkg/expenses.go @@ -28,7 +28,9 @@ type ExpenseEntry struct { type expensesIndexPage struct { Expenses []*ExpenseEntry - TotalAmount string + SumAmount string + SumTaxes map[string]string + SumTotal string Filters *expenseFilterForm TaxClasses []string ExpenseStatuses map[string]string @@ -45,11 +47,11 @@ func IndexExpenses(w http.ResponseWriter, r *http.Request, _ httprouter.Params) } page := &expensesIndexPage{ Expenses: mustCollectExpenseEntries(r.Context(), conn, locale, filters), - TotalAmount: mustComputeExpensesTotalAmount(r.Context(), conn, filters), ExpenseStatuses: mustCollectExpenseStatuses(r.Context(), conn, locale), TaxClasses: mustCollectTaxClasses(r.Context(), conn, company), Filters: filters, } + page.mustComputeExpensesTotalAmount(r.Context(), conn, filters) mustRenderMainTemplate(w, r, "expenses/index.gohtml", page) } @@ -136,10 +138,11 @@ func mustCollectExpenseStatuses(ctx context.Context, conn *Conn, locale *Locale) return statuses } -func mustComputeExpensesTotalAmount(ctx context.Context, conn *Conn, filters *expenseFilterForm) string { +func (page *expensesIndexPage) mustComputeExpensesTotalAmount(ctx context.Context, conn *Conn, filters *expenseFilterForm) { where, args := filters.BuildQuery(nil) - return conn.MustGetText(ctx, "0", fmt.Sprintf(` - select to_price(sum(subtotal + taxes)::integer, decimal_digits) + row := conn.QueryRow(ctx, fmt.Sprintf(` + select to_price(sum(subtotal)::integer, decimal_digits) + , to_price(sum(subtotal + taxes)::integer, decimal_digits) from ( select expense_id , expense.amount as subtotal @@ -155,6 +158,35 @@ func mustComputeExpensesTotalAmount(ctx context.Context, conn *Conn, filters *ex join currency using (currency_code) group by decimal_digits `, where), args...) + if err := row.Scan(&page.SumAmount, &page.SumTotal); err != nil { + panic(err) + } + + row = conn.QueryRow(ctx, fmt.Sprintf(` + select array_agg(array[tax_class_name, to_price(coalesce(tax_amount, 0), decimal_digits)]) filter (where tax_class_name is not null) + from ( + select tax_class.name as tax_class_name + , coalesce(sum(expense_tax.amount)::integer, 0) as tax_amount + , currency_code + from expense + left join expense_tax_amount as expense_tax using (expense_id) + left join tax using (tax_id) + left join tax_class using (tax_class_id) + where (%s) + group by tax_class.name + , currency_code + ) as tax + join currency using (currency_code) + group by decimal_digits + `, where), args...) + var taxes [][]string + if err := row.Scan(&taxes); err != nil { + panic(err) + } + page.SumTaxes = make(map[string]string) + for _, tax := range taxes { + page.SumTaxes[tax[0]] = tax[1] + } } func mustCollectTaxClasses(ctx context.Context, conn *Conn, company *Company) []string { diff --git a/po/ca.po b/po/ca.po index a5ffdab..3635e34 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-10-02 12:49+0200\n" +"POT-Creation-Date: 2023-10-02 16:35+0200\n" "PO-Revision-Date: 2023-01-18 17:08+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -735,37 +735,37 @@ msgid "Name" msgstr "Nom" #: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708 -#: pkg/expenses.go:307 pkg/expenses.go:475 pkg/invoices.go:174 +#: pkg/expenses.go:339 pkg/expenses.go:507 pkg/invoices.go:174 #: pkg/invoices.go:746 pkg/invoices.go:1331 pkg/contacts.go:154 #: pkg/contacts.go:362 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:485 pkg/invoices.go:178 +#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:517 pkg/invoices.go:178 #: pkg/contacts.go:158 msgctxt "input" msgid "Tags Condition" msgstr "Condició de les etiquetes" -#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:489 pkg/invoices.go:182 +#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:521 pkg/invoices.go:182 #: pkg/contacts.go:162 msgctxt "tag condition" msgid "All" msgstr "Totes" -#: pkg/products.go:186 pkg/expenses.go:490 pkg/invoices.go:183 +#: pkg/products.go:186 pkg/expenses.go:522 pkg/invoices.go:183 #: pkg/contacts.go:163 msgid "Invoices must have all the specified labels." msgstr "Les factures han de tenir totes les etiquetes." -#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:494 pkg/invoices.go:187 +#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:526 pkg/invoices.go:187 #: pkg/contacts.go:167 msgctxt "tag condition" msgid "Any" msgstr "Qualsevol" -#: pkg/products.go:191 pkg/expenses.go:495 pkg/invoices.go:188 +#: pkg/products.go:191 pkg/expenses.go:527 pkg/invoices.go:188 #: pkg/contacts.go:168 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." @@ -780,7 +780,7 @@ msgctxt "input" msgid "Price" msgstr "Preu" -#: pkg/products.go:297 pkg/quote.go:948 pkg/expenses.go:275 +#: pkg/products.go:297 pkg/quote.go:948 pkg/expenses.go:307 #: pkg/invoices.go:1063 msgctxt "input" msgid "Taxes" @@ -799,12 +799,12 @@ msgstr "No podeu deixar el preu en blanc." msgid "Price must be a number greater than zero." msgstr "El preu ha de ser un número major a zero." -#: pkg/products.go:326 pkg/quote.go:1007 pkg/expenses.go:343 +#: pkg/products.go:326 pkg/quote.go:1007 pkg/expenses.go:375 #: pkg/invoices.go:1122 msgid "Selected tax is not valid." msgstr "Heu seleccionat un impost que no és vàlid." -#: pkg/products.go:327 pkg/quote.go:1008 pkg/expenses.go:344 +#: pkg/products.go:327 pkg/quote.go:1008 pkg/expenses.go:376 #: pkg/invoices.go:1123 msgid "You can only select a tax of each class." msgstr "Només podeu seleccionar un impost de cada classe." @@ -1028,7 +1028,7 @@ msgctxt "input" msgid "Quotation Status" msgstr "Estat del pressupost" -#: pkg/quote.go:154 pkg/expenses.go:480 pkg/invoices.go:154 +#: pkg/quote.go:154 pkg/expenses.go:512 pkg/invoices.go:154 msgid "All status" msgstr "Tots els estats" @@ -1037,12 +1037,12 @@ msgctxt "input" msgid "Quotation Number" msgstr "Número de pressupost" -#: pkg/quote.go:164 pkg/expenses.go:465 pkg/invoices.go:164 +#: pkg/quote.go:164 pkg/expenses.go:497 pkg/invoices.go:164 msgctxt "input" msgid "From Date" msgstr "A partir de la data" -#: pkg/quote.go:169 pkg/expenses.go:470 pkg/invoices.go:169 +#: pkg/quote.go:169 pkg/expenses.go:502 pkg/invoices.go:169 msgctxt "input" msgid "To Date" msgstr "Fins la data" @@ -1063,8 +1063,8 @@ msgstr "pressuposts.zip" msgid "quotations.ods" msgstr "pressuposts.ods" -#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:684 -#: pkg/expenses.go:710 pkg/invoices.go:677 pkg/invoices.go:1306 +#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:716 +#: pkg/expenses.go:742 pkg/invoices.go:677 pkg/invoices.go:1306 #: pkg/invoices.go:1314 msgid "Invalid action" msgstr "Acció invàlida." @@ -1219,70 +1219,70 @@ msgctxt "period option" msgid "Previous year" msgstr "Any anterior" -#: pkg/expenses.go:201 +#: pkg/expenses.go:233 msgid "Select a contact." msgstr "Escolliu un contacte." -#: pkg/expenses.go:258 pkg/expenses.go:454 +#: pkg/expenses.go:290 pkg/expenses.go:486 msgctxt "input" msgid "Contact" msgstr "Contacte" -#: pkg/expenses.go:264 +#: pkg/expenses.go:296 msgctxt "input" msgid "Invoice number" msgstr "Número de factura" -#: pkg/expenses.go:269 pkg/invoices.go:735 +#: pkg/expenses.go:301 pkg/invoices.go:735 msgctxt "input" msgid "Invoice Date" msgstr "Data de factura" -#: pkg/expenses.go:284 +#: pkg/expenses.go:316 msgctxt "input" msgid "Amount" msgstr "Import" -#: pkg/expenses.go:295 pkg/invoices.go:757 +#: pkg/expenses.go:327 pkg/invoices.go:757 msgctxt "input" msgid "File" msgstr "Fitxer" -#: pkg/expenses.go:301 pkg/expenses.go:479 +#: pkg/expenses.go:333 pkg/expenses.go:511 msgctxt "input" msgid "Expense Status" msgstr "Estat de la despesa" -#: pkg/expenses.go:341 +#: pkg/expenses.go:373 msgid "Selected contact is not valid." msgstr "Heu seleccionat un contacte que no és vàlid." -#: pkg/expenses.go:342 pkg/invoices.go:808 +#: pkg/expenses.go:374 pkg/invoices.go:808 msgid "Invoice date must be a valid date." msgstr "La data de facturació ha de ser vàlida." -#: pkg/expenses.go:345 +#: pkg/expenses.go:377 msgid "Amount can not be empty." msgstr "No podeu deixar l’import en blanc." -#: pkg/expenses.go:346 +#: pkg/expenses.go:378 msgid "Amount must be a number greater than zero." msgstr "L’import ha de ser un número major a zero." -#: pkg/expenses.go:348 +#: pkg/expenses.go:380 msgid "Selected expense status is not valid." msgstr "Heu seleccionat un estat de despesa que no és vàlid." -#: pkg/expenses.go:455 +#: pkg/expenses.go:487 msgid "All contacts" msgstr "Tots els contactes" -#: pkg/expenses.go:460 pkg/invoices.go:159 +#: pkg/expenses.go:492 pkg/invoices.go:159 msgctxt "input" msgid "Invoice Number" msgstr "Número de factura" -#: pkg/expenses.go:708 +#: pkg/expenses.go:740 msgid "expenses.ods" msgstr "despeses.ods" diff --git a/po/es.po b/po/es.po index fb127c6..cea06f0 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-10-02 12:49+0200\n" +"POT-Creation-Date: 2023-10-02 16:35+0200\n" "PO-Revision-Date: 2023-01-18 17:45+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -735,37 +735,37 @@ msgid "Name" msgstr "Nombre" #: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708 -#: pkg/expenses.go:307 pkg/expenses.go:475 pkg/invoices.go:174 +#: pkg/expenses.go:339 pkg/expenses.go:507 pkg/invoices.go:174 #: pkg/invoices.go:746 pkg/invoices.go:1331 pkg/contacts.go:154 #: pkg/contacts.go:362 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:485 pkg/invoices.go:178 +#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:517 pkg/invoices.go:178 #: pkg/contacts.go:158 msgctxt "input" msgid "Tags Condition" msgstr "Condición de las etiquetas" -#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:489 pkg/invoices.go:182 +#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:521 pkg/invoices.go:182 #: pkg/contacts.go:162 msgctxt "tag condition" msgid "All" msgstr "Todas" -#: pkg/products.go:186 pkg/expenses.go:490 pkg/invoices.go:183 +#: pkg/products.go:186 pkg/expenses.go:522 pkg/invoices.go:183 #: pkg/contacts.go:163 msgid "Invoices must have all the specified labels." msgstr "Las facturas deben tener todas las etiquetas." -#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:494 pkg/invoices.go:187 +#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:526 pkg/invoices.go:187 #: pkg/contacts.go:167 msgctxt "tag condition" msgid "Any" msgstr "Cualquiera" -#: pkg/products.go:191 pkg/expenses.go:495 pkg/invoices.go:188 +#: pkg/products.go:191 pkg/expenses.go:527 pkg/invoices.go:188 #: pkg/contacts.go:168 msgid "Invoices must have at least one of the specified labels." msgstr "Las facturas deben tener como mínimo una de las etiquetas." @@ -780,7 +780,7 @@ msgctxt "input" msgid "Price" msgstr "Precio" -#: pkg/products.go:297 pkg/quote.go:948 pkg/expenses.go:275 +#: pkg/products.go:297 pkg/quote.go:948 pkg/expenses.go:307 #: pkg/invoices.go:1063 msgctxt "input" msgid "Taxes" @@ -799,12 +799,12 @@ msgstr "No podéis dejar el precio en blanco." msgid "Price must be a number greater than zero." msgstr "El precio tiene que ser un número mayor a cero." -#: pkg/products.go:326 pkg/quote.go:1007 pkg/expenses.go:343 +#: pkg/products.go:326 pkg/quote.go:1007 pkg/expenses.go:375 #: pkg/invoices.go:1122 msgid "Selected tax is not valid." msgstr "Habéis escogido un impuesto que no es válido." -#: pkg/products.go:327 pkg/quote.go:1008 pkg/expenses.go:344 +#: pkg/products.go:327 pkg/quote.go:1008 pkg/expenses.go:376 #: pkg/invoices.go:1123 msgid "You can only select a tax of each class." msgstr "Solo podéis escoger un impuesto de cada clase." @@ -1028,7 +1028,7 @@ msgctxt "input" msgid "Quotation Status" msgstr "Estado del presupuesto" -#: pkg/quote.go:154 pkg/expenses.go:480 pkg/invoices.go:154 +#: pkg/quote.go:154 pkg/expenses.go:512 pkg/invoices.go:154 msgid "All status" msgstr "Todos los estados" @@ -1037,12 +1037,12 @@ msgctxt "input" msgid "Quotation Number" msgstr "Número de presupuesto" -#: pkg/quote.go:164 pkg/expenses.go:465 pkg/invoices.go:164 +#: pkg/quote.go:164 pkg/expenses.go:497 pkg/invoices.go:164 msgctxt "input" msgid "From Date" msgstr "A partir de la fecha" -#: pkg/quote.go:169 pkg/expenses.go:470 pkg/invoices.go:169 +#: pkg/quote.go:169 pkg/expenses.go:502 pkg/invoices.go:169 msgctxt "input" msgid "To Date" msgstr "Hasta la fecha" @@ -1063,8 +1063,8 @@ msgstr "presupuestos.zip" msgid "quotations.ods" msgstr "presupuestos.ods" -#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:684 -#: pkg/expenses.go:710 pkg/invoices.go:677 pkg/invoices.go:1306 +#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:716 +#: pkg/expenses.go:742 pkg/invoices.go:677 pkg/invoices.go:1306 #: pkg/invoices.go:1314 msgid "Invalid action" msgstr "Acción inválida." @@ -1219,70 +1219,70 @@ msgctxt "period option" msgid "Previous year" msgstr "Año anterior" -#: pkg/expenses.go:201 +#: pkg/expenses.go:233 msgid "Select a contact." msgstr "Escoged un contacto" -#: pkg/expenses.go:258 pkg/expenses.go:454 +#: pkg/expenses.go:290 pkg/expenses.go:486 msgctxt "input" msgid "Contact" msgstr "Contacto" -#: pkg/expenses.go:264 +#: pkg/expenses.go:296 msgctxt "input" msgid "Invoice number" msgstr "Número de factura" -#: pkg/expenses.go:269 pkg/invoices.go:735 +#: pkg/expenses.go:301 pkg/invoices.go:735 msgctxt "input" msgid "Invoice Date" msgstr "Fecha de factura" -#: pkg/expenses.go:284 +#: pkg/expenses.go:316 msgctxt "input" msgid "Amount" msgstr "Importe" -#: pkg/expenses.go:295 pkg/invoices.go:757 +#: pkg/expenses.go:327 pkg/invoices.go:757 msgctxt "input" msgid "File" msgstr "Archivo" -#: pkg/expenses.go:301 pkg/expenses.go:479 +#: pkg/expenses.go:333 pkg/expenses.go:511 msgctxt "input" msgid "Expense Status" msgstr "Estado del gasto" -#: pkg/expenses.go:341 +#: pkg/expenses.go:373 msgid "Selected contact is not valid." msgstr "Habéis escogido un contacto que no es válido." -#: pkg/expenses.go:342 pkg/invoices.go:808 +#: pkg/expenses.go:374 pkg/invoices.go:808 msgid "Invoice date must be a valid date." msgstr "La fecha de factura debe ser válida." -#: pkg/expenses.go:345 +#: pkg/expenses.go:377 msgid "Amount can not be empty." msgstr "No podéis dejar el importe en blanco." -#: pkg/expenses.go:346 +#: pkg/expenses.go:378 msgid "Amount must be a number greater than zero." msgstr "El importe tiene que ser un número mayor a cero." -#: pkg/expenses.go:348 +#: pkg/expenses.go:380 msgid "Selected expense status is not valid." msgstr "Habéis escogido un estado de gasto que no es válido." -#: pkg/expenses.go:455 +#: pkg/expenses.go:487 msgid "All contacts" msgstr "Todos los contactos" -#: pkg/expenses.go:460 pkg/invoices.go:159 +#: pkg/expenses.go:492 pkg/invoices.go:159 msgctxt "input" msgid "Invoice Number" msgstr "Número de factura" -#: pkg/expenses.go:708 +#: pkg/expenses.go:740 msgid "expenses.ods" msgstr "gastos.ods" diff --git a/web/template/expenses/index.gohtml b/web/template/expenses/index.gohtml index ae16c22..245a8c1 100644 --- a/web/template/expenses/index.gohtml +++ b/web/template/expenses/index.gohtml @@ -157,8 +157,13 @@ {{ if .Expenses }} - {{( gettext "Total" )}} - {{ .TotalAmount|formatPrice }} + {{( gettext "Total" )}} + {{ .SumAmount | formatPrice }} + {{ range $class := $.TaxClasses -}} + {{ $tax := index $.SumTaxes $class }} + {{ if $tax }}{{ $tax | formatPrice }}{{ else }}{{ "0.0" | formatPrice }}{{ end }} + {{- end }} + {{ .SumTotal | formatPrice }}