Compare commits
2 Commits
843f7746cf
...
4d2379555e
Author | SHA1 | Date |
---|---|---|
jordi fita mas | 4d2379555e | |
jordi fita mas | 47d3e1940c |
|
@ -32,7 +32,7 @@ Depends:
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
golang-github-jackc-pgx-v4-dev
|
golang-github-jackc-pgx-v4-dev
|
||||||
Description: Simple invoicing and accounting web application
|
Description: Simple invoicing and accounting web application
|
||||||
A simple web application to keep invoice and accouting records, intended for
|
A simple web application to keep invoice and accounting records, intended for
|
||||||
freelancers working in Spain.
|
freelancers working in Spain.
|
||||||
.
|
.
|
||||||
This is the dev package.
|
This is the dev package.
|
||||||
|
@ -41,7 +41,8 @@ Package: numerus
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends:
|
Depends:
|
||||||
${shlibs:Depends},
|
${shlibs:Depends},
|
||||||
${misc:Depends}
|
${misc:Depends},
|
||||||
|
weasyprint
|
||||||
Built-Using: ${misc:Built-Using}
|
Built-Using: ${misc:Built-Using}
|
||||||
Description: Simple invoicing and accounting web application
|
Description: Simple invoicing and accounting web application
|
||||||
A simple web application to keep invoice and accouting records, intended for
|
A simple web application to keep invoice and accouting records, intended for
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,7 +57,7 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetInvoiceForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
func ServeInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
locale := getLocale(r)
|
locale := getLocale(r)
|
||||||
conn := getConn(r)
|
conn := getConn(r)
|
||||||
company := mustGetCompany(r)
|
company := mustGetCompany(r)
|
||||||
|
@ -65,16 +70,52 @@ func GetInvoiceForm(w http.ResponseWriter, r *http.Request, params httprouter.Pa
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pdf := false
|
||||||
|
if strings.HasSuffix(slug, ".pdf") {
|
||||||
|
pdf = true
|
||||||
|
slug = slug[:len(slug)-len(".pdf")]
|
||||||
|
}
|
||||||
invoice := mustGetInvoice(r.Context(), conn, company, slug)
|
invoice := mustGetInvoice(r.Context(), conn, company, slug)
|
||||||
if invoice == nil {
|
if invoice == nil {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if pdf {
|
||||||
|
cmd := exec.Command("weasyprint", "--stylesheet", "web/static/invoice.css", "-", "-")
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer stdout.Close()
|
||||||
|
if err = cmd.Start(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
defer stdin.Close()
|
||||||
|
mustRenderAppTemplate(stdin, r, "invoices/view.gohtml", invoice)
|
||||||
|
}()
|
||||||
|
w.Header().Set("Content-Type", "application/pdf")
|
||||||
|
if _, err = io.Copy(w, stdout); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Printf("ERR - %v\n", stderr.String())
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
mustRenderAppTemplate(w, r, "invoices/view.gohtml", invoice)
|
mustRenderAppTemplate(w, r, "invoices/view.gohtml", invoice)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type invoice struct {
|
type invoice struct {
|
||||||
Number string
|
Number string
|
||||||
|
Slug string
|
||||||
Date time.Time
|
Date time.Time
|
||||||
Invoicer taxDetails
|
Invoicer taxDetails
|
||||||
Invoicee taxDetails
|
Invoicee taxDetails
|
||||||
|
@ -105,7 +146,9 @@ type invoiceProduct struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustGetInvoice(ctx context.Context, conn *Conn, company *Company, slug string) *invoice {
|
func mustGetInvoice(ctx context.Context, conn *Conn, company *Company, slug string) *invoice {
|
||||||
inv := &invoice{}
|
inv := &invoice{
|
||||||
|
Slug: slug,
|
||||||
|
}
|
||||||
var invoiceId int
|
var invoiceId int
|
||||||
var decimalDigits int
|
var decimalDigits int
|
||||||
if notFoundErrorOrPanic(conn.QueryRow(ctx, "select invoice_id, decimal_digits, invoice_number, invoice_date, notes, business_name, vatin, phone, email, address, city, province, postal_code, to_price(subtotal, decimal_digits), to_price(total, decimal_digits) from invoice join contact using (contact_id) join invoice_amount using (invoice_id) join currency using (currency_code) where invoice.slug = $1", slug).Scan(&invoiceId, &decimalDigits, &inv.Number, &inv.Date, &inv.Notes, &inv.Invoicee.Name, &inv.Invoicee.VATIN, &inv.Invoicee.Phone, &inv.Invoicee.Email, &inv.Invoicee.Address, &inv.Invoicee.City, &inv.Invoicee.Province, &inv.Invoicee.PostalCode, &inv.Subtotal, &inv.Total)) {
|
if notFoundErrorOrPanic(conn.QueryRow(ctx, "select invoice_id, decimal_digits, invoice_number, invoice_date, notes, business_name, vatin, phone, email, address, city, province, postal_code, to_price(subtotal, decimal_digits), to_price(total, decimal_digits) from invoice join contact using (contact_id) join invoice_amount using (invoice_id) join currency using (currency_code) where invoice.slug = $1", slug).Scan(&invoiceId, &decimalDigits, &inv.Number, &inv.Date, &inv.Notes, &inv.Invoicee.Name, &inv.Invoicee.VATIN, &inv.Invoicee.Phone, &inv.Invoicee.Email, &inv.Invoicee.Address, &inv.Invoicee.City, &inv.Invoicee.Province, &inv.Invoicee.PostalCode, &inv.Subtotal, &inv.Total)) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ func NewRouter(db *Db) http.Handler {
|
||||||
companyRouter.PUT("/products/:slug", HandleUpdateProduct)
|
companyRouter.PUT("/products/:slug", HandleUpdateProduct)
|
||||||
companyRouter.GET("/invoices", IndexInvoices)
|
companyRouter.GET("/invoices", IndexInvoices)
|
||||||
companyRouter.POST("/invoices", HandleAddInvoice)
|
companyRouter.POST("/invoices", HandleAddInvoice)
|
||||||
companyRouter.GET("/invoices/:slug", GetInvoiceForm)
|
companyRouter.GET("/invoices/:slug", ServeInvoice)
|
||||||
companyRouter.POST("/invoices/new/products", HandleAddProductsToInvoice)
|
companyRouter.POST("/invoices/new/products", HandleAddProductsToInvoice)
|
||||||
companyRouter.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
companyRouter.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
mustRenderAppTemplate(w, r, "dashboard.gohtml", nil)
|
mustRenderAppTemplate(w, r, "dashboard.gohtml", nil)
|
||||||
|
|
73
po/ca.po
73
po/ca.po
|
@ -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-02-24 11:52+0100\n"
|
"POT-Creation-Date: 2023-02-26 17:11+0100\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"
|
||||||
|
@ -59,7 +59,7 @@ msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: web/template/invoices/products.gohtml:43
|
#: web/template/invoices/products.gohtml:43
|
||||||
#: web/template/invoices/view.gohtml:42 web/template/products/index.gohtml:23
|
#: web/template/invoices/view.gohtml:59 web/template/products/index.gohtml:23
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Preu"
|
msgstr "Preu"
|
||||||
|
@ -74,13 +74,13 @@ msgctxt "action"
|
||||||
msgid "Add products"
|
msgid "Add products"
|
||||||
msgstr "Afegeix productes"
|
msgstr "Afegeix productes"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:44
|
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:61
|
||||||
#: web/template/invoices/view.gohtml:71
|
#: web/template/invoices/view.gohtml:87
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Subtotal"
|
msgstr "Subtotal"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:81
|
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:97
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -100,7 +100,7 @@ msgctxt "invoice"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Totes"
|
msgstr "Totes"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:22 web/template/invoices/view.gohtml:18
|
#: web/template/invoices/index.gohtml:22 web/template/invoices/view.gohtml:25
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Data"
|
msgstr "Data"
|
||||||
|
@ -135,21 +135,26 @@ msgctxt "title"
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Descàrrega"
|
msgstr "Descàrrega"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:47
|
#: web/template/invoices/index.gohtml:50
|
||||||
msgid "No invoices added yet."
|
msgid "No invoices added yet."
|
||||||
msgstr "No hi ha cap factura."
|
msgstr "No hi ha cap factura."
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:17
|
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:24
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Invoice %s"
|
msgid "Invoice %s"
|
||||||
msgstr "Factura %s"
|
msgstr "Factura %s"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:41
|
#: web/template/invoices/view.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "Download invoice"
|
||||||
|
msgstr "Descarrega factura"
|
||||||
|
|
||||||
|
#: web/template/invoices/view.gohtml:58
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Concept"
|
msgid "Concept"
|
||||||
msgstr "Concepte"
|
msgstr "Concepte"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:43
|
#: web/template/invoices/view.gohtml:60
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Units"
|
msgid "Units"
|
||||||
msgstr "Unitats"
|
msgstr "Unitats"
|
||||||
|
@ -364,40 +369,40 @@ msgstr "No podeu deixar la contrasenya en blanc."
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nom d’usuari o contrasenya incorrectes."
|
msgstr "Nom d’usuari o contrasenya incorrectes."
|
||||||
|
|
||||||
#: pkg/products.go:165 pkg/invoices.go:392
|
#: pkg/products.go:165 pkg/invoices.go:435
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: pkg/products.go:171 pkg/invoices.go:397
|
#: pkg/products.go:171 pkg/invoices.go:440
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
#: pkg/products.go:176 pkg/invoices.go:401
|
#: pkg/products.go:176 pkg/invoices.go:444
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Preu"
|
msgstr "Preu"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/invoices.go:307 pkg/invoices.go:427
|
#: pkg/products.go:186 pkg/invoices.go:350 pkg/invoices.go:470
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Taxes"
|
msgid "Taxes"
|
||||||
msgstr "Imposts"
|
msgstr "Imposts"
|
||||||
|
|
||||||
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:340
|
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:383
|
||||||
#: pkg/invoices.go:463
|
#: pkg/invoices.go:506
|
||||||
msgid "Name can not be empty."
|
msgid "Name can not be empty."
|
||||||
msgstr "No podeu deixar el nom en blanc."
|
msgstr "No podeu deixar el nom en blanc."
|
||||||
|
|
||||||
#: pkg/products.go:207 pkg/invoices.go:464
|
#: pkg/products.go:207 pkg/invoices.go:507
|
||||||
msgid "Price can not be empty."
|
msgid "Price can not be empty."
|
||||||
msgstr "No podeu deixar el preu en blanc."
|
msgstr "No podeu deixar el preu en blanc."
|
||||||
|
|
||||||
#: pkg/products.go:208 pkg/invoices.go:465
|
#: pkg/products.go:208 pkg/invoices.go:508
|
||||||
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:210 pkg/invoices.go:344 pkg/invoices.go:473
|
#: pkg/products.go:210 pkg/invoices.go:387 pkg/invoices.go:516
|
||||||
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."
|
||||||
|
|
||||||
|
@ -460,70 +465,70 @@ 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/invoices.go:158
|
#: pkg/invoices.go:201
|
||||||
msgid "Select a customer to bill."
|
msgid "Select a customer to bill."
|
||||||
msgstr "Escolliu un client a facturar."
|
msgstr "Escolliu un client a facturar."
|
||||||
|
|
||||||
#: pkg/invoices.go:233
|
#: pkg/invoices.go:276
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acció invàlida."
|
msgstr "Acció invàlida."
|
||||||
|
|
||||||
#: pkg/invoices.go:284
|
#: pkg/invoices.go:327
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Customer"
|
msgid "Customer"
|
||||||
msgstr "Client"
|
msgstr "Client"
|
||||||
|
|
||||||
#: pkg/invoices.go:290
|
#: pkg/invoices.go:333
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
#: pkg/invoices.go:296
|
#: pkg/invoices.go:339
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Date"
|
msgid "Invoice Date"
|
||||||
msgstr "Data de factura"
|
msgstr "Data de factura"
|
||||||
|
|
||||||
#: pkg/invoices.go:302
|
#: pkg/invoices.go:345
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
msgstr "Notes"
|
msgstr "Notes"
|
||||||
|
|
||||||
#: pkg/invoices.go:341
|
#: pkg/invoices.go:384
|
||||||
msgid "Invoice date can not be empty."
|
msgid "Invoice date can not be empty."
|
||||||
msgstr "No podeu deixar la data de la factura en blanc."
|
msgstr "No podeu deixar la data de la factura en blanc."
|
||||||
|
|
||||||
#: pkg/invoices.go:342
|
#: pkg/invoices.go:385
|
||||||
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/invoices.go:387
|
#: pkg/invoices.go:430
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identificador"
|
msgstr "Identificador"
|
||||||
|
|
||||||
#: pkg/invoices.go:410
|
#: pkg/invoices.go:453
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Quantitat"
|
msgstr "Quantitat"
|
||||||
|
|
||||||
#: pkg/invoices.go:418
|
#: pkg/invoices.go:461
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Discount (%)"
|
msgid "Discount (%)"
|
||||||
msgstr "Descompte (%)"
|
msgstr "Descompte (%)"
|
||||||
|
|
||||||
#: pkg/invoices.go:467
|
#: pkg/invoices.go:510
|
||||||
msgid "Quantity can not be empty."
|
msgid "Quantity can not be empty."
|
||||||
msgstr "No podeu deixar la quantitat en blanc."
|
msgstr "No podeu deixar la quantitat en blanc."
|
||||||
|
|
||||||
#: pkg/invoices.go:468
|
#: pkg/invoices.go:511
|
||||||
msgid "Quantity must be a number greater than zero."
|
msgid "Quantity must be a number greater than zero."
|
||||||
msgstr "La quantitat ha de ser un número major a zero."
|
msgstr "La quantitat ha de ser un número major a zero."
|
||||||
|
|
||||||
#: pkg/invoices.go:470
|
#: pkg/invoices.go:513
|
||||||
msgid "Discount can not be empty."
|
msgid "Discount can not be empty."
|
||||||
msgstr "No podeu deixar el descompte en blanc."
|
msgstr "No podeu deixar el descompte en blanc."
|
||||||
|
|
||||||
#: pkg/invoices.go:471
|
#: pkg/invoices.go:514
|
||||||
msgid "Discount must be a percentage between 0 and 100."
|
msgid "Discount must be a percentage between 0 and 100."
|
||||||
msgstr "El descompte ha de ser un percentatge entre 0 i 100."
|
msgstr "El descompte ha de ser un percentatge entre 0 i 100."
|
||||||
|
|
||||||
|
|
73
po/es.po
73
po/es.po
|
@ -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-02-24 11:52+0100\n"
|
"POT-Creation-Date: 2023-02-26 17:11+0100\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"
|
||||||
|
@ -59,7 +59,7 @@ msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: web/template/invoices/products.gohtml:43
|
#: web/template/invoices/products.gohtml:43
|
||||||
#: web/template/invoices/view.gohtml:42 web/template/products/index.gohtml:23
|
#: web/template/invoices/view.gohtml:59 web/template/products/index.gohtml:23
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Precio"
|
msgstr "Precio"
|
||||||
|
@ -74,13 +74,13 @@ msgctxt "action"
|
||||||
msgid "Add products"
|
msgid "Add products"
|
||||||
msgstr "Añadir productos"
|
msgstr "Añadir productos"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:44
|
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:61
|
||||||
#: web/template/invoices/view.gohtml:71
|
#: web/template/invoices/view.gohtml:87
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Subtotal"
|
msgstr "Subtotal"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:81
|
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:97
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -100,7 +100,7 @@ msgctxt "invoice"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todas"
|
msgstr "Todas"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:22 web/template/invoices/view.gohtml:18
|
#: web/template/invoices/index.gohtml:22 web/template/invoices/view.gohtml:25
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Fecha"
|
msgstr "Fecha"
|
||||||
|
@ -135,21 +135,26 @@ msgctxt "title"
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Descargar"
|
msgstr "Descargar"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:47
|
#: web/template/invoices/index.gohtml:50
|
||||||
msgid "No invoices added yet."
|
msgid "No invoices added yet."
|
||||||
msgstr "No hay facturas."
|
msgstr "No hay facturas."
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:17
|
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:24
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Invoice %s"
|
msgid "Invoice %s"
|
||||||
msgstr "Factura %s"
|
msgstr "Factura %s"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:41
|
#: web/template/invoices/view.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "Download invoice"
|
||||||
|
msgstr "Descargar factura"
|
||||||
|
|
||||||
|
#: web/template/invoices/view.gohtml:58
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Concept"
|
msgid "Concept"
|
||||||
msgstr "Concepto"
|
msgstr "Concepto"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:43
|
#: web/template/invoices/view.gohtml:60
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Units"
|
msgid "Units"
|
||||||
msgstr "Unidades"
|
msgstr "Unidades"
|
||||||
|
@ -364,40 +369,40 @@ msgstr "No podéis dejar la contraseña en blanco."
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nombre de usuario o contraseña inválido."
|
msgstr "Nombre de usuario o contraseña inválido."
|
||||||
|
|
||||||
#: pkg/products.go:165 pkg/invoices.go:392
|
#: pkg/products.go:165 pkg/invoices.go:435
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: pkg/products.go:171 pkg/invoices.go:397
|
#: pkg/products.go:171 pkg/invoices.go:440
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripción"
|
msgstr "Descripción"
|
||||||
|
|
||||||
#: pkg/products.go:176 pkg/invoices.go:401
|
#: pkg/products.go:176 pkg/invoices.go:444
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Precio"
|
msgstr "Precio"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/invoices.go:307 pkg/invoices.go:427
|
#: pkg/products.go:186 pkg/invoices.go:350 pkg/invoices.go:470
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Taxes"
|
msgid "Taxes"
|
||||||
msgstr "Impuestos"
|
msgstr "Impuestos"
|
||||||
|
|
||||||
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:340
|
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:383
|
||||||
#: pkg/invoices.go:463
|
#: pkg/invoices.go:506
|
||||||
msgid "Name can not be empty."
|
msgid "Name can not be empty."
|
||||||
msgstr "No podéis dejar el nombre en blanco."
|
msgstr "No podéis dejar el nombre en blanco."
|
||||||
|
|
||||||
#: pkg/products.go:207 pkg/invoices.go:464
|
#: pkg/products.go:207 pkg/invoices.go:507
|
||||||
msgid "Price can not be empty."
|
msgid "Price can not be empty."
|
||||||
msgstr "No podéis dejar el precio en blanco."
|
msgstr "No podéis dejar el precio en blanco."
|
||||||
|
|
||||||
#: pkg/products.go:208 pkg/invoices.go:465
|
#: pkg/products.go:208 pkg/invoices.go:508
|
||||||
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:210 pkg/invoices.go:344 pkg/invoices.go:473
|
#: pkg/products.go:210 pkg/invoices.go:387 pkg/invoices.go:516
|
||||||
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."
|
||||||
|
|
||||||
|
@ -460,70 +465,70 @@ 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/invoices.go:158
|
#: pkg/invoices.go:201
|
||||||
msgid "Select a customer to bill."
|
msgid "Select a customer to bill."
|
||||||
msgstr "Escoged un cliente a facturar."
|
msgstr "Escoged un cliente a facturar."
|
||||||
|
|
||||||
#: pkg/invoices.go:233
|
#: pkg/invoices.go:276
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acción inválida."
|
msgstr "Acción inválida."
|
||||||
|
|
||||||
#: pkg/invoices.go:284
|
#: pkg/invoices.go:327
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Customer"
|
msgid "Customer"
|
||||||
msgstr "Cliente"
|
msgstr "Cliente"
|
||||||
|
|
||||||
#: pkg/invoices.go:290
|
#: pkg/invoices.go:333
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
#: pkg/invoices.go:296
|
#: pkg/invoices.go:339
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Date"
|
msgid "Invoice Date"
|
||||||
msgstr "Fecha de factura"
|
msgstr "Fecha de factura"
|
||||||
|
|
||||||
#: pkg/invoices.go:302
|
#: pkg/invoices.go:345
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
msgstr "Notas"
|
msgstr "Notas"
|
||||||
|
|
||||||
#: pkg/invoices.go:341
|
#: pkg/invoices.go:384
|
||||||
msgid "Invoice date can not be empty."
|
msgid "Invoice date can not be empty."
|
||||||
msgstr "No podéis dejar la fecha de la factura en blanco."
|
msgstr "No podéis dejar la fecha de la factura en blanco."
|
||||||
|
|
||||||
#: pkg/invoices.go:342
|
#: pkg/invoices.go:385
|
||||||
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/invoices.go:387
|
#: pkg/invoices.go:430
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identificador"
|
msgstr "Identificador"
|
||||||
|
|
||||||
#: pkg/invoices.go:410
|
#: pkg/invoices.go:453
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Cantidad"
|
msgstr "Cantidad"
|
||||||
|
|
||||||
#: pkg/invoices.go:418
|
#: pkg/invoices.go:461
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Discount (%)"
|
msgid "Discount (%)"
|
||||||
msgstr "Descuento (%)"
|
msgstr "Descuento (%)"
|
||||||
|
|
||||||
#: pkg/invoices.go:467
|
#: pkg/invoices.go:510
|
||||||
msgid "Quantity can not be empty."
|
msgid "Quantity can not be empty."
|
||||||
msgstr "No podéis dejar la cantidad en blanco."
|
msgstr "No podéis dejar la cantidad en blanco."
|
||||||
|
|
||||||
#: pkg/invoices.go:468
|
#: pkg/invoices.go:511
|
||||||
msgid "Quantity must be a number greater than zero."
|
msgid "Quantity must be a number greater than zero."
|
||||||
msgstr "La cantidad tiene que ser un número mayor a cero."
|
msgstr "La cantidad tiene que ser un número mayor a cero."
|
||||||
|
|
||||||
#: pkg/invoices.go:470
|
#: pkg/invoices.go:513
|
||||||
msgid "Discount can not be empty."
|
msgid "Discount can not be empty."
|
||||||
msgstr "No podéis dejar el descuento en blanco."
|
msgstr "No podéis dejar el descuento en blanco."
|
||||||
|
|
||||||
#: pkg/invoices.go:471
|
#: pkg/invoices.go:514
|
||||||
msgid "Discount must be a percentage between 0 and 100."
|
msgid "Discount must be a percentage between 0 and 100."
|
||||||
msgstr "El descuento tiene que ser un percentage entre 0 y 100."
|
msgstr "El descuento tiene que ser un percentage entre 0 y 100."
|
||||||
|
|
||||||
|
|
|
@ -508,6 +508,15 @@ main > nav {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invoice-download {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-download a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remix Icon */
|
/* Remix Icon */
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
|
@ -39,7 +39,10 @@
|
||||||
<td class="invoice-status-{{ .Status }}">{{ .StatusLabel }}</td>
|
<td class="invoice-status-{{ .Status }}">{{ .StatusLabel }}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td class="numeric">{{ .Total|formatPrice }}</td>
|
<td class="numeric">{{ .Total|formatPrice }}</td>
|
||||||
<td></td>
|
<td class="invoice-download"><a href="{{ companyURI "/invoices/"}}{{ .Slug }}.pdf" download="{{ .Number}}.pdf"
|
||||||
|
title="{{( pgettext "Download invoice" "action" )}}"
|
||||||
|
aria-label="{{( pgettext "Download invoice %s" "action" )}}"><i
|
||||||
|
class="ri-download-line"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
|
|
|
@ -10,7 +10,13 @@
|
||||||
<a href="{{ companyURI "/invoices"}}">{{( pgettext "Invoices" "title" )}}</a> /
|
<a href="{{ companyURI "/invoices"}}">{{( pgettext "Invoices" "title" )}}</a> /
|
||||||
<a>{{ .Number }}</a>
|
<a>{{ .Number }}</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="primary button"
|
||||||
|
href="{{ companyURI "/invoices/" }}{{ .Slug }}.pdf"
|
||||||
|
download="{{ .Number}}.pdf">{{( pgettext "Download invoice" "action" )}}</a>
|
||||||
|
</p>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="/static/invoice.css">
|
<link rel="stylesheet" type="text/css" href="/static/invoice.css">
|
||||||
<article class="invoice">
|
<article class="invoice">
|
||||||
<header>
|
<header>
|
||||||
|
|
Loading…
Reference in New Issue