Begin the dashboard with expenses, gross income, net income, and taxes

For now i use a too-long SQL query for that, but will probably replace
it with a view.  I have to check that it is correct before i do so,
however.
This commit is contained in:
jordi fita mas 2023-05-16 14:56:49 +02:00
parent 7921b9cf80
commit ce42880697
7 changed files with 304 additions and 76 deletions

64
pkg/dashboard.go Normal file
View File

@ -0,0 +1,64 @@
package pkg
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
type DashboardPage struct {
Sales string
Income string
Expenses string
VAT string
IRPF string
NetIncome string
}
func ServeDashboard(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
company := mustGetCompany(r)
conn := getConn(r)
rows := conn.MustQuery(r.Context(), `
select to_price(0, decimal_digits) as sales
, to_price(invoice.total, decimal_digits) as income
, to_price(expense.total, decimal_digits) as expenses
, to_price(tax.vat, decimal_digits) as vat
, to_price(tax.irpf, decimal_digits) as irpf
, to_price(invoice.total - expense.total - tax.vat + tax.irpf, decimal_digits) as net_income
from company
left join (
select company_id, sum(total)::integer as total
from invoice
join invoice_amount using (invoice_id)
group by company_id
) as invoice using (company_id)
left join (
select company_id, sum(amount)::integer as total
from expense
group by company_id
) as expense using (company_id)
left join (
select invoice.company_id
, sum(case when tax_class.name = 'IVA' then invoice_tax_amount.amount else 0 end)::integer as vat
, sum(case when tax_class.name = 'IRPF' then invoice_tax_amount.amount else 0 end)::integer as irpf
from invoice
join invoice_tax_amount using (invoice_id)
join tax using (tax_id)
join tax_class using (tax_class_id)
group by invoice.company_id
) as tax using (company_id)
join currency using (currency_code)
where company_id = $1
`, company.Id)
defer rows.Close()
dashboard := &DashboardPage{}
for rows.Next() {
if err := rows.Scan(&dashboard.Sales, &dashboard.Income, &dashboard.Expenses, &dashboard.VAT, &dashboard.IRPF, &dashboard.NetIncome); err != nil {
panic(err)
}
}
if rows.Err() != nil {
panic(rows.Err())
}
mustRenderMainTemplate(w, r, "dashboard.gohtml", dashboard)
}

View File

@ -45,9 +45,7 @@ func NewRouter(db *Db) http.Handler {
companyRouter.PUT("/expenses/:slug/tags", HandleUpdateExpenseTags) companyRouter.PUT("/expenses/:slug/tags", HandleUpdateExpenseTags)
companyRouter.GET("/expenses/:slug/tags/edit", ServeEditExpenseTags) companyRouter.GET("/expenses/:slug/tags/edit", ServeEditExpenseTags)
companyRouter.GET("/expenses/:slug/download/:filename", ServeExpenseAttachment) companyRouter.GET("/expenses/:slug/download/:filename", ServeExpenseAttachment)
companyRouter.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { companyRouter.GET("/", ServeDashboard)
mustRenderMainTemplate(w, r, "dashboard.gohtml", nil)
})
router := httprouter.New() router := httprouter.New()
router.ServeFiles("/static/*filepath", http.Dir("web/static")) router.ServeFiles("/static/*filepath", http.Dir("web/static"))

View File

@ -2,6 +2,7 @@ package pkg
import ( import (
"fmt" "fmt"
"golang.org/x/text/language"
"golang.org/x/text/message" "golang.org/x/text/message"
"golang.org/x/text/number" "golang.org/x/text/number"
"html/template" "html/template"
@ -33,12 +34,10 @@ func mustRenderTemplate(wr io.Writer, r *http.Request, layout string, filename s
return companyURI(company, uri) return companyURI(company, uri)
}, },
"formatPrice": func(price string) string { "formatPrice": func(price string) string {
p := message.NewPrinter(locale.Language) return formatPrice(price, locale.Language, locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol)
f, err := strconv.ParseFloat(price, 64) },
if err != nil { "formatPriceSpan": func(price string) template.HTML {
f = math.NaN() return template.HTML(formatPrice(price, locale.Language, locale.CurrencyPattern, company.DecimalDigits, "<span>"+company.CurrencySymbol+"</span>"))
}
return p.Sprintf(locale.CurrencyPattern, company.DecimalDigits, number.Decimal(f), company.CurrencySymbol)
}, },
"formatDate": func(time time.Time) template.HTML { "formatDate": func(time time.Time) template.HTML {
return template.HTML(`<time datetime="` + time.Format("2006-01-02") + `">` + time.Format("02/01/2006") + "</time>") return template.HTML(`<time datetime="` + time.Format("2006-01-02") + `">` + time.Format("02/01/2006") + "</time>")
@ -152,3 +151,12 @@ func humanizeBytes(s int64, base float64, sizes []string) string {
func logn(n, b float64) float64 { func logn(n, b float64) float64 {
return math.Log(n) / math.Log(b) return math.Log(n) / math.Log(b)
} }
func formatPrice(price string, language language.Tag, currencyPattern string, decimalDigits int, currencySymbol string) string {
p := message.NewPrinter(language)
f, err := strconv.ParseFloat(price, 64)
if err != nil {
f = math.NaN()
}
return p.Sprintf(currencyPattern, decimalDigits, number.Decimal(f), currencySymbol)
}

106
po/ca.po
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-11 23:31+0200\n" "POT-Creation-Date: 2023-05-16 14:50+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"
@ -146,13 +146,13 @@ msgctxt "title"
msgid "Amount" msgid "Amount"
msgstr "Import" msgstr "Import"
#: web/template/invoices/index.gohtml:53 #: web/template/invoices/index.gohtml:53 web/template/expenses/index.gohtml:46
msgctxt "title" msgctxt "title"
msgid "Download" msgid "Download"
msgstr "Descàrrega" msgstr "Descàrrega"
#: web/template/invoices/index.gohtml:54 web/template/contacts/index.gohtml:43 #: web/template/invoices/index.gohtml:54 web/template/contacts/index.gohtml:43
#: web/template/expenses/index.gohtml:46 web/template/products/index.gohtml:42 #: web/template/expenses/index.gohtml:47 web/template/products/index.gohtml:42
msgctxt "title" msgctxt "title"
msgid "Actions" msgid "Actions"
msgstr "Accions" msgstr "Accions"
@ -163,7 +163,7 @@ msgid "Select invoice %v"
msgstr "Selecciona factura %v" msgstr "Selecciona factura %v"
#: web/template/invoices/index.gohtml:116 web/template/invoices/view.gohtml:19 #: web/template/invoices/index.gohtml:116 web/template/invoices/view.gohtml:19
#: web/template/contacts/index.gohtml:69 web/template/expenses/index.gohtml:77 #: web/template/contacts/index.gohtml:73 web/template/expenses/index.gohtml:86
#: web/template/products/index.gohtml:71 #: web/template/products/index.gohtml:71
msgctxt "action" msgctxt "action"
msgid "Edit" msgid "Edit"
@ -218,11 +218,46 @@ msgctxt "action"
msgid "Edit invoice" msgid "Edit invoice"
msgstr "Edita factura" msgstr "Edita factura"
#: web/template/dashboard.gohtml:2 #: web/template/form.gohtml:36
msgctxt "label"
msgid "(Max. %s)"
msgstr "(Màx. %s)"
#: web/template/dashboard.gohtml:3
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
msgstr "Tauler" msgstr "Tauler"
#: web/template/dashboard.gohtml:14
msgctxt "term"
msgid "Sales"
msgstr "Vendes"
#: web/template/dashboard.gohtml:18
msgctxt "term"
msgid "Income"
msgstr "Ingressos"
#: web/template/dashboard.gohtml:22
msgctxt "term"
msgid "Expenses"
msgstr "Despeses"
#: web/template/dashboard.gohtml:26
msgctxt "term"
msgid "VAT"
msgstr "IVA"
#: web/template/dashboard.gohtml:30
msgctxt "term"
msgid "IRPF"
msgstr "IRPF"
#: web/template/dashboard.gohtml:34
msgctxt "term"
msgid "Net Income"
msgstr "Ingressos nets"
#: web/template/app.gohtml:23 #: web/template/app.gohtml:23
msgctxt "menu" msgctxt "menu"
msgid "Account" msgid "Account"
@ -295,7 +330,7 @@ msgctxt "title"
msgid "Phone" msgid "Phone"
msgstr "Telèfon" msgstr "Telèfon"
#: web/template/contacts/index.gohtml:79 #: web/template/contacts/index.gohtml:83
msgid "No contacts added yet." msgid "No contacts added yet."
msgstr "No hi ha cap contacte." msgstr "No hi ha cap contacte."
@ -357,7 +392,7 @@ msgctxt "title"
msgid "Expenses" msgid "Expenses"
msgstr "Despeses" msgstr "Despeses"
#: web/template/expenses/new.gohtml:32 web/template/expenses/index.gohtml:15 #: web/template/expenses/new.gohtml:33 web/template/expenses/index.gohtml:15
msgctxt "action" msgctxt "action"
msgid "New expense" msgid "New expense"
msgstr "Nova despesa" msgstr "Nova despesa"
@ -382,7 +417,7 @@ msgctxt "title"
msgid "Invoice Number" msgid "Invoice Number"
msgstr "Número de factura" msgstr "Número de factura"
#: web/template/expenses/index.gohtml:87 #: web/template/expenses/index.gohtml:96
msgid "No expenses added yet." msgid "No expenses added yet."
msgstr "No hi ha cap despesa." msgstr "No hi ha cap despesa."
@ -391,7 +426,7 @@ msgctxt "title"
msgid "Edit Expense “%s”" msgid "Edit Expense “%s”"
msgstr "Edició de la despesa «%s»" msgstr "Edició de la despesa «%s»"
#: web/template/expenses/edit.gohtml:35 #: web/template/expenses/edit.gohtml:36
msgctxt "action" msgctxt "action"
msgid "Update expense" msgid "Update expense"
msgstr "Actualitza despesa" msgstr "Actualitza despesa"
@ -527,37 +562,37 @@ msgctxt "input"
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
#: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:193 #: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202
#: pkg/expenses.go:343 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:1044 pkg/contacts.go:140 pkg/contacts.go:325
msgctxt "input" msgctxt "input"
msgid "Tags" msgid "Tags"
msgstr "Etiquetes" msgstr "Etiquetes"
#: pkg/products.go:173 pkg/expenses.go:347 pkg/invoices.go:191 #: pkg/products.go:173 pkg/expenses.go:365 pkg/invoices.go:191
#: pkg/contacts.go:144 #: pkg/contacts.go:144
msgctxt "input" msgctxt "input"
msgid "Tags Condition" msgid "Tags Condition"
msgstr "Condició de les etiquetes" msgstr "Condició de les etiquetes"
#: pkg/products.go:177 pkg/expenses.go:351 pkg/invoices.go:195 #: pkg/products.go:177 pkg/expenses.go:369 pkg/invoices.go:195
#: pkg/contacts.go:148 #: pkg/contacts.go:148
msgctxt "tag condition" msgctxt "tag condition"
msgid "All" msgid "All"
msgstr "Totes" msgstr "Totes"
#: pkg/products.go:178 pkg/expenses.go:352 pkg/invoices.go:196 #: pkg/products.go:178 pkg/expenses.go:370 pkg/invoices.go:196
#: pkg/contacts.go:149 #: pkg/contacts.go:149
msgid "Invoices must have all the specified labels." msgid "Invoices must have all the specified labels."
msgstr "Les factures han de tenir totes les etiquetes." msgstr "Les factures han de tenir totes les etiquetes."
#: pkg/products.go:182 pkg/expenses.go:356 pkg/invoices.go:200 #: pkg/products.go:182 pkg/expenses.go:374 pkg/invoices.go:200
#: pkg/contacts.go:153 #: pkg/contacts.go:153
msgctxt "tag condition" msgctxt "tag condition"
msgid "Any" msgid "Any"
msgstr "Qualsevol" msgstr "Qualsevol"
#: pkg/products.go:183 pkg/expenses.go:357 pkg/invoices.go:201 #: pkg/products.go:183 pkg/expenses.go:375 pkg/invoices.go:201
#: pkg/contacts.go:154 #: pkg/contacts.go:154
msgid "Invoices must have at least one of the specified labels." 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." msgstr "Les factures han de tenir com a mínim una de les etiquetes."
@ -572,7 +607,7 @@ msgctxt "input"
msgid "Price" msgid "Price"
msgstr "Preu" msgstr "Preu"
#: pkg/products.go:284 pkg/expenses.go:177 pkg/invoices.go:823 #: pkg/products.go:284 pkg/expenses.go:181 pkg/invoices.go:823
msgctxt "input" msgctxt "input"
msgid "Taxes" msgid "Taxes"
msgstr "Imposts" msgstr "Imposts"
@ -589,12 +624,12 @@ msgstr "No podeu deixar el preu en blanc."
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:215 pkg/expenses.go:220 #: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:877 #: pkg/invoices.go:877
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:216 pkg/expenses.go:221 #: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:878 #: pkg/invoices.go:878
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."
@ -703,66 +738,71 @@ 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/expenses.go:126 #: pkg/expenses.go:129
msgid "Select a contact." msgid "Select a contact."
msgstr "Escolliu un contacte." msgstr "Escolliu un contacte."
#: pkg/expenses.go:160 #: pkg/expenses.go:164
msgctxt "input" msgctxt "input"
msgid "Contact" msgid "Contact"
msgstr "Contacte" msgstr "Contacte"
#: pkg/expenses.go:166 #: pkg/expenses.go:170
msgctxt "input" msgctxt "input"
msgid "Invoice number" msgid "Invoice number"
msgstr "Número de factura" msgstr "Número de factura"
#: pkg/expenses.go:171 pkg/invoices.go:586 #: pkg/expenses.go:175 pkg/invoices.go:586
msgctxt "input" msgctxt "input"
msgid "Invoice Date" msgid "Invoice Date"
msgstr "Data de factura" msgstr "Data de factura"
#: pkg/expenses.go:183 #: pkg/expenses.go:187
msgctxt "input" msgctxt "input"
msgid "Amount" msgid "Amount"
msgstr "Import" msgstr "Import"
#: pkg/expenses.go:213 #: pkg/expenses.go:197
msgctxt "input"
msgid "File"
msgstr "Fitxer"
#: pkg/expenses.go:225
msgid "Selected contact is not valid." msgid "Selected contact is not valid."
msgstr "Heu seleccionat un contacte que no és vàlid." msgstr "Heu seleccionat un contacte que no és vàlid."
#: pkg/expenses.go:214 pkg/invoices.go:641 #: pkg/expenses.go:226 pkg/invoices.go:641
msgid "Invoice date must be a valid date." msgid "Invoice date must be a valid date."
msgstr "La data de facturació ha de ser vàlida." msgstr "La data de facturació ha de ser vàlida."
#: pkg/expenses.go:217 #: pkg/expenses.go:229
msgid "Amount can not be empty." msgid "Amount can not be empty."
msgstr "No podeu deixar limport en blanc." msgstr "No podeu deixar limport en blanc."
#: pkg/expenses.go:218 #: pkg/expenses.go:230
msgid "Amount must be a number greater than zero." msgid "Amount must be a number greater than zero."
msgstr "Limport ha de ser un número major a zero." msgstr "Limport ha de ser un número major a zero."
#: pkg/expenses.go:322 pkg/invoices.go:160 pkg/invoices.go:580 #: pkg/expenses.go:340 pkg/invoices.go:160 pkg/invoices.go:580
msgctxt "input" msgctxt "input"
msgid "Customer" msgid "Customer"
msgstr "Client" msgstr "Client"
#: pkg/expenses.go:323 pkg/invoices.go:161 #: pkg/expenses.go:341 pkg/invoices.go:161
msgid "All customers" msgid "All customers"
msgstr "Tots els clients" msgstr "Tots els clients"
#: pkg/expenses.go:328 pkg/invoices.go:172 #: pkg/expenses.go:346 pkg/invoices.go:172
msgctxt "input" msgctxt "input"
msgid "Invoice Number" msgid "Invoice Number"
msgstr "Número de factura" msgstr "Número de factura"
#: pkg/expenses.go:333 pkg/invoices.go:177 #: pkg/expenses.go:351 pkg/invoices.go:177
msgctxt "input" msgctxt "input"
msgid "From Date" msgid "From Date"
msgstr "A partir de la data" msgstr "A partir de la data"
#: pkg/expenses.go:338 pkg/invoices.go:182 #: pkg/expenses.go:356 pkg/invoices.go:182
msgctxt "input" msgctxt "input"
msgid "To Date" msgid "To Date"
msgstr "Fins la data" msgstr "Fins la data"

106
po/es.po
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-11 23:31+0200\n" "POT-Creation-Date: 2023-05-16 14:50+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"
@ -146,13 +146,13 @@ msgctxt "title"
msgid "Amount" msgid "Amount"
msgstr "Importe" msgstr "Importe"
#: web/template/invoices/index.gohtml:53 #: web/template/invoices/index.gohtml:53 web/template/expenses/index.gohtml:46
msgctxt "title" msgctxt "title"
msgid "Download" msgid "Download"
msgstr "Descargar" msgstr "Descargar"
#: web/template/invoices/index.gohtml:54 web/template/contacts/index.gohtml:43 #: web/template/invoices/index.gohtml:54 web/template/contacts/index.gohtml:43
#: web/template/expenses/index.gohtml:46 web/template/products/index.gohtml:42 #: web/template/expenses/index.gohtml:47 web/template/products/index.gohtml:42
msgctxt "title" msgctxt "title"
msgid "Actions" msgid "Actions"
msgstr "Acciones" msgstr "Acciones"
@ -163,7 +163,7 @@ msgid "Select invoice %v"
msgstr "Seleccionar factura %v" msgstr "Seleccionar factura %v"
#: web/template/invoices/index.gohtml:116 web/template/invoices/view.gohtml:19 #: web/template/invoices/index.gohtml:116 web/template/invoices/view.gohtml:19
#: web/template/contacts/index.gohtml:69 web/template/expenses/index.gohtml:77 #: web/template/contacts/index.gohtml:73 web/template/expenses/index.gohtml:86
#: web/template/products/index.gohtml:71 #: web/template/products/index.gohtml:71
msgctxt "action" msgctxt "action"
msgid "Edit" msgid "Edit"
@ -218,11 +218,46 @@ msgctxt "action"
msgid "Edit invoice" msgid "Edit invoice"
msgstr "Editar factura" msgstr "Editar factura"
#: web/template/dashboard.gohtml:2 #: web/template/form.gohtml:36
msgctxt "label"
msgid "(Max. %s)"
msgstr "(Máx. %s)"
#: web/template/dashboard.gohtml:3
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
msgstr "Panel" msgstr "Panel"
#: web/template/dashboard.gohtml:14
msgctxt "term"
msgid "Sales"
msgstr "Ventas"
#: web/template/dashboard.gohtml:18
msgctxt "term"
msgid "Income"
msgstr "Ingresos"
#: web/template/dashboard.gohtml:22
msgctxt "term"
msgid "Expenses"
msgstr "Gastos"
#: web/template/dashboard.gohtml:26
msgctxt "term"
msgid "VAT"
msgstr "IVA"
#: web/template/dashboard.gohtml:30
msgctxt "term"
msgid "IRPF"
msgstr "IRPF"
#: web/template/dashboard.gohtml:34
msgctxt "term"
msgid "Net Income"
msgstr "Ingresos netos"
#: web/template/app.gohtml:23 #: web/template/app.gohtml:23
msgctxt "menu" msgctxt "menu"
msgid "Account" msgid "Account"
@ -295,7 +330,7 @@ msgctxt "title"
msgid "Phone" msgid "Phone"
msgstr "Teléfono" msgstr "Teléfono"
#: web/template/contacts/index.gohtml:79 #: web/template/contacts/index.gohtml:83
msgid "No contacts added yet." msgid "No contacts added yet."
msgstr "No hay contactos." msgstr "No hay contactos."
@ -357,7 +392,7 @@ msgctxt "title"
msgid "Expenses" msgid "Expenses"
msgstr "Gastos" msgstr "Gastos"
#: web/template/expenses/new.gohtml:32 web/template/expenses/index.gohtml:15 #: web/template/expenses/new.gohtml:33 web/template/expenses/index.gohtml:15
msgctxt "action" msgctxt "action"
msgid "New expense" msgid "New expense"
msgstr "Nuevo gasto" msgstr "Nuevo gasto"
@ -382,7 +417,7 @@ msgctxt "title"
msgid "Invoice Number" msgid "Invoice Number"
msgstr "Número de factura" msgstr "Número de factura"
#: web/template/expenses/index.gohtml:87 #: web/template/expenses/index.gohtml:96
msgid "No expenses added yet." msgid "No expenses added yet."
msgstr "No hay gastos." msgstr "No hay gastos."
@ -391,7 +426,7 @@ msgctxt "title"
msgid "Edit Expense “%s”" msgid "Edit Expense “%s”"
msgstr "Edición del gasto «%s»" msgstr "Edición del gasto «%s»"
#: web/template/expenses/edit.gohtml:35 #: web/template/expenses/edit.gohtml:36
msgctxt "action" msgctxt "action"
msgid "Update expense" msgid "Update expense"
msgstr "Actualizar gasto" msgstr "Actualizar gasto"
@ -527,37 +562,37 @@ msgctxt "input"
msgid "Name" msgid "Name"
msgstr "Nombre" msgstr "Nombre"
#: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:193 #: pkg/products.go:169 pkg/products.go:290 pkg/expenses.go:202
#: pkg/expenses.go:343 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:1044 pkg/contacts.go:140 pkg/contacts.go:325
msgctxt "input" msgctxt "input"
msgid "Tags" msgid "Tags"
msgstr "Etiquetes" msgstr "Etiquetes"
#: pkg/products.go:173 pkg/expenses.go:347 pkg/invoices.go:191 #: pkg/products.go:173 pkg/expenses.go:365 pkg/invoices.go:191
#: pkg/contacts.go:144 #: pkg/contacts.go:144
msgctxt "input" msgctxt "input"
msgid "Tags Condition" msgid "Tags Condition"
msgstr "Condición de las etiquetas" msgstr "Condición de las etiquetas"
#: pkg/products.go:177 pkg/expenses.go:351 pkg/invoices.go:195 #: pkg/products.go:177 pkg/expenses.go:369 pkg/invoices.go:195
#: pkg/contacts.go:148 #: pkg/contacts.go:148
msgctxt "tag condition" msgctxt "tag condition"
msgid "All" msgid "All"
msgstr "Todas" msgstr "Todas"
#: pkg/products.go:178 pkg/expenses.go:352 pkg/invoices.go:196 #: pkg/products.go:178 pkg/expenses.go:370 pkg/invoices.go:196
#: pkg/contacts.go:149 #: pkg/contacts.go:149
msgid "Invoices must have all the specified labels." msgid "Invoices must have all the specified labels."
msgstr "Las facturas deben tener todas las etiquetas." msgstr "Las facturas deben tener todas las etiquetas."
#: pkg/products.go:182 pkg/expenses.go:356 pkg/invoices.go:200 #: pkg/products.go:182 pkg/expenses.go:374 pkg/invoices.go:200
#: pkg/contacts.go:153 #: pkg/contacts.go:153
msgctxt "tag condition" msgctxt "tag condition"
msgid "Any" msgid "Any"
msgstr "Cualquiera" msgstr "Cualquiera"
#: pkg/products.go:183 pkg/expenses.go:357 pkg/invoices.go:201 #: pkg/products.go:183 pkg/expenses.go:375 pkg/invoices.go:201
#: pkg/contacts.go:154 #: pkg/contacts.go:154
msgid "Invoices must have at least one of the specified labels." msgid "Invoices must have at least one of the specified labels."
msgstr "Las facturas debent tener como mínimo una de las etiquetas." msgstr "Las facturas debent tener como mínimo una de las etiquetas."
@ -572,7 +607,7 @@ msgctxt "input"
msgid "Price" msgid "Price"
msgstr "Precio" msgstr "Precio"
#: pkg/products.go:284 pkg/expenses.go:177 pkg/invoices.go:823 #: pkg/products.go:284 pkg/expenses.go:181 pkg/invoices.go:823
msgctxt "input" msgctxt "input"
msgid "Taxes" msgid "Taxes"
msgstr "Impuestos" msgstr "Impuestos"
@ -589,12 +624,12 @@ msgstr "No podéis dejar el precio en blanco."
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:215 pkg/expenses.go:220 #: pkg/products.go:313 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:877 #: pkg/invoices.go:877
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:216 pkg/expenses.go:221 #: pkg/products.go:314 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:878 #: pkg/invoices.go:878
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."
@ -703,66 +738,71 @@ 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/expenses.go:126 #: pkg/expenses.go:129
msgid "Select a contact." msgid "Select a contact."
msgstr "Escoged un contacto" msgstr "Escoged un contacto"
#: pkg/expenses.go:160 #: pkg/expenses.go:164
msgctxt "input" msgctxt "input"
msgid "Contact" msgid "Contact"
msgstr "Contacto" msgstr "Contacto"
#: pkg/expenses.go:166 #: pkg/expenses.go:170
msgctxt "input" msgctxt "input"
msgid "Invoice number" msgid "Invoice number"
msgstr "Número de factura" msgstr "Número de factura"
#: pkg/expenses.go:171 pkg/invoices.go:586 #: pkg/expenses.go:175 pkg/invoices.go:586
msgctxt "input" msgctxt "input"
msgid "Invoice Date" msgid "Invoice Date"
msgstr "Fecha de factura" msgstr "Fecha de factura"
#: pkg/expenses.go:183 #: pkg/expenses.go:187
msgctxt "input" msgctxt "input"
msgid "Amount" msgid "Amount"
msgstr "Importe" msgstr "Importe"
#: pkg/expenses.go:213 #: pkg/expenses.go:197
msgctxt "input"
msgid "File"
msgstr "Archivo"
#: pkg/expenses.go:225
msgid "Selected contact is not valid." msgid "Selected contact is not valid."
msgstr "Habéis escogido un contacto que no es válido." msgstr "Habéis escogido un contacto que no es válido."
#: pkg/expenses.go:214 pkg/invoices.go:641 #: pkg/expenses.go:226 pkg/invoices.go:641
msgid "Invoice date must be a valid date." msgid "Invoice date must be a valid date."
msgstr "La fecha de factura debe ser válida." msgstr "La fecha de factura debe ser válida."
#: pkg/expenses.go:217 #: pkg/expenses.go:229
msgid "Amount can not be empty." msgid "Amount can not be empty."
msgstr "No podéis dejar el importe en blanco." msgstr "No podéis dejar el importe en blanco."
#: pkg/expenses.go:218 #: pkg/expenses.go:230
msgid "Amount must be a number greater than zero." msgid "Amount must be a number greater than zero."
msgstr "El importe tiene que ser un número mayor a cero." msgstr "El importe tiene que ser un número mayor a cero."
#: pkg/expenses.go:322 pkg/invoices.go:160 pkg/invoices.go:580 #: pkg/expenses.go:340 pkg/invoices.go:160 pkg/invoices.go:580
msgctxt "input" msgctxt "input"
msgid "Customer" msgid "Customer"
msgstr "Cliente" msgstr "Cliente"
#: pkg/expenses.go:323 pkg/invoices.go:161 #: pkg/expenses.go:341 pkg/invoices.go:161
msgid "All customers" msgid "All customers"
msgstr "Todos los clientes" msgstr "Todos los clientes"
#: pkg/expenses.go:328 pkg/invoices.go:172 #: pkg/expenses.go:346 pkg/invoices.go:172
msgctxt "input" msgctxt "input"
msgid "Invoice Number" msgid "Invoice Number"
msgstr "Número de factura" msgstr "Número de factura"
#: pkg/expenses.go:333 pkg/invoices.go:177 #: pkg/expenses.go:351 pkg/invoices.go:177
msgctxt "input" msgctxt "input"
msgid "From Date" msgid "From Date"
msgstr "A partir de la fecha" msgstr "A partir de la fecha"
#: pkg/expenses.go:338 pkg/invoices.go:182 #: pkg/expenses.go:356 pkg/invoices.go:182
msgctxt "input" msgctxt "input"
msgid "To Date" msgid "To Date"
msgstr "Hasta la fecha" msgstr "Hasta la fecha"

View File

@ -824,6 +824,55 @@ div[x-data="snackbar"] div[role="alert"].enter.end, div[x-data="snackbar"] div[r
transform: translateY(0); transform: translateY(0);
} }
/* Dashboard */
#income-statement {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
#income-statement div {
display: block;
padding: 2rem;
width: calc(100%/3);
min-width: 33rem;
}
#income-statement div:first-child {
background-color: var(--numerus--color--yellow);
}
#income-statement div:nth-child(2) {
background-color: var(--numerus--color--green);
}
#income-statement div:nth-child(3) {
background-color: var(--numerus--color--red);
}
#income-statement div:nth-child(4),
#income-statement div:nth-child(5) {
color: var(--numerus--color--dark-gray);
}
#income-statement div:last-child {
background-color: var(--numerus--color--black);
color: var(--numerus--color--white);
}
#income-statement dt {
text-transform: lowercase;
}
#income-statement dd {
text-align: right;
font-size: 4rem;
}
#income-statement dd span {
font-size: .66666em;
}
/* Remix Icon */ /* Remix Icon */
@font-face { @font-face {

View File

@ -1,9 +1,38 @@
{{ define "title" -}} {{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.DashboardPage*/ -}}
{{( pgettext "Dashboard" "title" )}} {{( pgettext "Dashboard" "title" )}}
{{- end }} {{- end }}
{{ define "breadcrumbs" -}} {{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.DashboardPage*/ -}}
{{- end }} {{- end }}
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.DashboardPage*/ -}}
<dl id="income-statement">
<div>
<dt>{{ (pgettext "Sales" "term") }}</dt>
<dd>{{ formatPriceSpan .Sales }}</dd>
</div>
<div>
<dt>{{ (pgettext "Income" "term") }}</dt>
<dd>{{ formatPriceSpan .Income }}</dd>
</div>
<div>
<dt>{{ (pgettext "Expenses" "term") }}</dt>
<dd>{{ formatPriceSpan .Expenses }}</dd>
</div>
<div>
<dt>{{ (pgettext "VAT" "term") }}</dt>
<dd>{{ formatPriceSpan .VAT }}</dd>
</div>
<div>
<dt>{{ (pgettext "IRPF" "term") }}</dt>
<dd>{{ formatPriceSpan .IRPF }}</dd>
</div>
<div>
<dt>{{ (pgettext "Net Income" "term") }}</dt>
<dd>{{ formatPriceSpan .NetIncome }}</dd>
</div>
</dl>
{{- end }} {{- end }}