Add a new collection “subsection” for invoices

This is mostly the same subsection as payments is for expense, added in
4f646e35d.  In this case i call it “collections”, but it is actually
the same payments section.
This commit is contained in:
jordi fita mas 2024-08-21 11:22:53 +02:00
parent 7f31b10cce
commit d4ef6c3254
9 changed files with 423 additions and 124 deletions

View File

@ -39,10 +39,26 @@ func serveExpensePaymentIndex(w http.ResponseWriter, r *http.Request, params htt
page.MustRender(w, r)
}
func serveInvoiceCollectionIndex(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
invoiceSlug := params[0].Value
conn := getConn(r)
company := mustGetCompany(r)
locale := getLocale(r)
invoice := mustGetCollectionInvoice(r.Context(), conn, invoiceSlug)
if invoice == nil {
http.NotFound(w, r)
return
}
page := NewPaymentIndexPageForInvoice(r.Context(), conn, company, locale, invoice)
page.MustRender(w, r)
}
type PaymentIndexPage struct {
Payments []*PaymentEntry
BaseURI string
Expense *PaymentExpense
Invoice *CollectionInvoice
}
func NewPaymentIndexPage(ctx context.Context, conn *Conn, company *Company, locale *Locale) *PaymentIndexPage {
@ -55,11 +71,19 @@ func NewPaymentIndexPage(ctx context.Context, conn *Conn, company *Company, loca
func NewPaymentIndexPageForExpense(ctx context.Context, conn *Conn, company *Company, locale *Locale, expense *PaymentExpense) *PaymentIndexPage {
return &PaymentIndexPage{
Payments: mustCollectPaymentEntries(ctx, conn, company, locale, PaymentTypePayment, expense.Id),
BaseURI: companyURI(company, "/expenses/"+expense.Slug+"/payments"),
BaseURI: expense.BaseURI(company),
Expense: expense,
}
}
func NewPaymentIndexPageForInvoice(ctx context.Context, conn *Conn, company *Company, locale *Locale, invoice *CollectionInvoice) *PaymentIndexPage {
return &PaymentIndexPage{
Payments: mustCollectPaymentEntries(ctx, conn, company, locale, PaymentTypeCollection, invoice.Id),
BaseURI: invoice.BaseURI(company),
Invoice: invoice,
}
}
func (page *PaymentIndexPage) MustRender(w http.ResponseWriter, r *http.Request) {
mustRenderMainTemplate(w, r, "payments/index.gohtml", page)
}
@ -91,6 +115,10 @@ func mustGetPaymentExpense(ctx context.Context, conn *Conn, expenseSlug string)
return expense
}
func (expense *PaymentExpense) BaseURI(company *Company) string {
return companyURI(company, "/expenses/"+expense.Slug+"/payments")
}
func (expense *PaymentExpense) calcRemainingPaymentAmount(ctx context.Context, conn *Conn) string {
return conn.MustGetText(ctx, "", `
select to_price(greatest(0, expense.amount + tax_amount - paid_amount)::int, decimal_digits)
@ -114,6 +142,57 @@ func (expense *PaymentExpense) calcRemainingPaymentAmount(ctx context.Context, c
`, expense.Id)
}
type CollectionInvoice struct {
Id int
Slug string
InvoiceNumber string
}
func mustGetCollectionInvoice(ctx context.Context, conn *Conn, invoiceSlug string) *CollectionInvoice {
if !ValidUuid(invoiceSlug) {
return nil
}
invoice := &CollectionInvoice{}
if notFoundErrorOrPanic(conn.QueryRow(ctx, `
select invoice_id
, slug
, invoice_number
from invoice
where invoice.slug = $1
`, invoiceSlug).Scan(
&invoice.Id,
&invoice.Slug,
&invoice.InvoiceNumber)) {
return nil
}
return invoice
}
func (invoice *CollectionInvoice) BaseURI(company *Company) string {
return companyURI(company, "/invoices/"+invoice.Slug+"/collections")
}
func (invoice *CollectionInvoice) calcRemainingPaymentAmount(ctx context.Context, conn *Conn) string {
return conn.MustGetText(ctx, "", `
select to_price(greatest(0, invoice_amount.total - collected_amount)::int, decimal_digits)
from (
select coalesce (sum(collection.amount), 0) as collected_amount
from invoice_collection
join collection using (collection_id)
where invoice_collection.invoice_id = $1
) as collection
cross join (
select total
, decimal_digits
from invoice_amount
join invoice using (invoice_id)
join currency using (currency_code)
where invoice_id = $1
) as invoice_amount
`, invoice.Id)
}
type PaymentEntry struct {
ID int
Type string
@ -243,12 +322,43 @@ func serveExpensePaymentForm(w http.ResponseWriter, r *http.Request, params http
form.MustRender(w, r)
}
func serveInvoiceCollectionForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
locale := getLocale(r)
conn := getConn(r)
company := mustGetCompany(r)
invoiceSlug := params[0].Value
invoice := mustGetCollectionInvoice(r.Context(), conn, invoiceSlug)
if invoice == nil {
http.NotFound(w, r)
return
}
form := newPaymentFormForInvoice(r.Context(), conn, locale, company, invoice)
paymentSlug := params[1].Value
if paymentSlug == "new" {
form.PaymentDate.Val = time.Now().Format("2006-01-02")
form.Description.Val = fmt.Sprintf(gettext("Collection of %s", locale), form.Invoice.InvoiceNumber)
form.Amount.Val = form.Invoice.calcRemainingPaymentAmount(r.Context(), conn)
form.MustRender(w, r)
return
}
if !ValidUuid(paymentSlug) {
http.NotFound(w, r)
return
}
if !form.MustFillFromDatabase(r.Context(), conn, paymentSlug) {
http.NotFound(w, r)
return
}
form.MustRender(w, r)
}
type PaymentForm struct {
locale *Locale
company *Company
Slug string
BaseURI string
Expense *PaymentExpense
Invoice *CollectionInvoice
Type *SelectField
Description *InputField
PaymentDate *InputField
@ -315,11 +425,19 @@ func newPaymentForm(ctx context.Context, conn *Conn, locale *Locale, company *Co
func newPaymentFormForExpense(ctx context.Context, conn *Conn, locale *Locale, company *Company, expense *PaymentExpense) *PaymentForm {
form := newPaymentForm(ctx, conn, locale, company)
form.Type.Selected = []string{PaymentTypePayment}
form.BaseURI = companyURI(company, "/expenses/"+expense.Slug+"/payments")
form.BaseURI = expense.BaseURI(company)
form.Expense = expense
return form
}
func newPaymentFormForInvoice(ctx context.Context, conn *Conn, locale *Locale, company *Company, invoice *CollectionInvoice) *PaymentForm {
form := newPaymentForm(ctx, conn, locale, company)
form.Type.Selected = []string{PaymentTypeCollection}
form.BaseURI = invoice.BaseURI(company)
form.Invoice = invoice
return form
}
func (f *PaymentForm) MustRender(w http.ResponseWriter, r *http.Request) {
if f.Slug == "" {
f.Type.EmptyLabel = gettext("Select a type.", f.locale)
@ -422,15 +540,18 @@ func handleAddPaymentForm(w http.ResponseWriter, r *http.Request, conn *Conn, co
return
}
var documentId any
if form.Type.String() == PaymentTypePayment {
if form.Expense != nil {
documentId = form.Expense.Id
}
if form.Type.String() == PaymentTypePayment {
slug := conn.MustGetText(r.Context(), "", "select add_payment($1, $2, $3, $4, $5, $6, $7)", company.Id, documentId, form.PaymentDate, form.PaymentAccount, form.Description, form.Amount, form.Tags)
if len(form.File.Content) > 0 {
conn.MustQuery(r.Context(), "select attach_to_payment($1, $2, $3, $4)", slug, form.File.OriginalFileName, form.File.ContentType, form.File.Content)
}
} else {
if form.Invoice != nil {
documentId = form.Invoice.Id
}
slug := conn.MustGetText(r.Context(), "", "select add_collection($1, $2, $3, $4, $5, $6, $7)", company.Id, documentId, form.PaymentDate, form.PaymentAccount, form.Description, form.Amount, form.Tags)
if len(form.File.Content) > 0 {
conn.MustQuery(r.Context(), "select attach_to_collection($1, $2, $3, $4)", slug, form.File.OriginalFileName, form.File.ContentType, form.File.Content)
@ -454,6 +575,21 @@ func handleAddExpensePayment(w http.ResponseWriter, r *http.Request, params http
handleAddPaymentForm(w, r, conn, company, form)
}
func handleAddInvoiceCollection(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
invoiceSlug := params[0].Value
locale := getLocale(r)
conn := getConn(r)
company := mustGetCompany(r)
invoice := mustGetCollectionInvoice(r.Context(), conn, invoiceSlug)
if invoice == nil {
http.NotFound(w, r)
return
}
form := newPaymentFormForInvoice(r.Context(), conn, locale, company, invoice)
handleAddPaymentForm(w, r, conn, company, form)
}
func handleEditPayment(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
locale := getLocale(r)
@ -519,6 +655,22 @@ func handleEditExpensePayment(w http.ResponseWriter, r *http.Request, params htt
handleEditPaymentForm(w, r, conn, form)
}
func handleEditInvoiceCollection(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
locale := getLocale(r)
company := mustGetCompany(r)
invoiceSlug := params[0].Value
invoice := mustGetCollectionInvoice(r.Context(), conn, invoiceSlug)
if invoice == nil {
http.NotFound(w, r)
return
}
form := newPaymentFormForInvoice(r.Context(), conn, locale, company, invoice)
form.Slug = params[1].Value
handleEditPaymentForm(w, r, conn, form)
}
func handleRemovePayment(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
company := mustGetCompany(r)
removePayment(w, r, params[0].Value, companyURI(company, "/payments"))
@ -550,7 +702,20 @@ func handleRemoveExpensePayment(w http.ResponseWriter, r *http.Request, params h
}
company := mustGetCompany(r)
removePayment(w, r, params[1].Value, companyURI(company, "/expenses/"+expense.Slug+"/payments"))
removePayment(w, r, params[1].Value, expense.BaseURI(company))
}
func handleRemoveInvoiceCollection(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
invoiceSlug := params[0].Value
invoice := mustGetCollectionInvoice(r.Context(), conn, invoiceSlug)
if invoice == nil {
http.NotFound(w, r)
return
}
company := mustGetCompany(r)
removePayment(w, r, params[1].Value, invoice.BaseURI(company))
}
func servePaymentAttachment(w http.ResponseWriter, r *http.Request, params httprouter.Params) {

View File

@ -44,6 +44,11 @@ func NewRouter(db *Db, demo bool) http.Handler {
companyRouter.PUT("/invoices/:slug/tags", HandleUpdateInvoiceTags)
companyRouter.GET("/invoices/:slug/tags/edit", ServeEditInvoiceTags)
companyRouter.GET("/invoices/:slug/download/:filename", ServeInvoiceAttachment)
companyRouter.GET("/invoices/:slug/collections", serveInvoiceCollectionIndex)
companyRouter.POST("/invoices/:slug/collections", handleAddInvoiceCollection)
companyRouter.GET("/invoices/:slug/collections/:slug", serveInvoiceCollectionForm)
companyRouter.PUT("/invoices/:slug/collections/:slug", handleEditInvoiceCollection)
companyRouter.DELETE("/invoices/:slug/collections/:slug", handleRemoveInvoiceCollection)
companyRouter.GET("/quotes", IndexQuotes)
companyRouter.POST("/quotes", HandleAddQuote)
companyRouter.GET("/quotes/:slug", ServeQuote)

132
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-08-21 03:28+0200\n"
"POT-Creation-Date: 2024-08-21 11:12+0200\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n"
@ -38,8 +38,8 @@ msgstr "Afegeix productes a la factura"
#: web/template/company/invoicing.gohtml:10
#: web/template/company/payment_methods.gohtml:10
#: web/template/products/new.gohtml:9 web/template/products/index.gohtml:9
#: web/template/products/edit.gohtml:10 web/template/payments/new.gohtml:10
#: web/template/payments/index.gohtml:10 web/template/payments/edit.gohtml:14
#: web/template/products/edit.gohtml:10 web/template/payments/new.gohtml:14
#: web/template/payments/index.gohtml:14 web/template/payments/edit.gohtml:14
#: web/template/payments/accounts/new.gohtml:10
#: web/template/payments/accounts/index.gohtml:10
#: web/template/payments/accounts/edit.gohtml:10
@ -50,6 +50,8 @@ msgstr "Inici"
#: web/template/invoices/products.gohtml:10 web/template/invoices/new.gohtml:10
#: web/template/invoices/index.gohtml:2 web/template/invoices/index.gohtml:10
#: web/template/invoices/view.gohtml:10 web/template/invoices/edit.gohtml:10
#: web/template/payments/new.gohtml:19 web/template/payments/index.gohtml:19
#: web/template/payments/edit.gohtml:19
msgctxt "title"
msgid "Invoices"
msgstr "Factures"
@ -116,7 +118,7 @@ msgstr "Subtotal"
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
#: web/template/expenses/new.gohtml:46 web/template/expenses/index.gohtml:74
#: web/template/expenses/edit.gohtml:48 web/template/payments/index.gohtml:34
#: web/template/expenses/edit.gohtml:48 web/template/payments/index.gohtml:56
msgctxt "title"
msgid "Total"
msgstr "Total"
@ -124,7 +126,7 @@ msgstr "Total"
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
#: web/template/expenses/new.gohtml:56 web/template/expenses/edit.gohtml:58
#: web/template/payments/edit.gohtml:46
#: web/template/payments/edit.gohtml:55
#: web/template/payments/accounts/edit.gohtml:38
msgctxt "action"
msgid "Update"
@ -135,7 +137,7 @@ msgstr "Actualitza"
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
#: web/template/expenses/new.gohtml:59 web/template/expenses/edit.gohtml:61
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
#: web/template/payments/new.gohtml:44
#: web/template/payments/new.gohtml:57
#: web/template/payments/accounts/new.gohtml:41
msgctxt "action"
msgid "Save"
@ -193,14 +195,14 @@ msgid "Customer"
msgstr "Client"
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:32
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:54
msgctxt "title"
msgid "Status"
msgstr "Estat"
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:33
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:55
msgctxt "title"
msgid "Tags"
msgstr "Etiquetes"
@ -212,7 +214,7 @@ msgid "Amount"
msgstr "Import"
#: web/template/invoices/index.gohtml:73 web/template/quotes/index.gohtml:73
#: web/template/expenses/index.gohtml:75 web/template/payments/index.gohtml:35
#: web/template/expenses/index.gohtml:75 web/template/payments/index.gohtml:57
msgctxt "title"
msgid "Download"
msgstr "Descàrrega"
@ -220,7 +222,7 @@ msgstr "Descàrrega"
#: web/template/invoices/index.gohtml:74 web/template/quotes/index.gohtml:74
#: web/template/contacts/index.gohtml:51 web/template/expenses/index.gohtml:76
#: web/template/company/switch.gohtml:23 web/template/products/index.gohtml:48
#: web/template/payments/index.gohtml:36
#: web/template/payments/index.gohtml:58
msgctxt "title"
msgid "Actions"
msgstr "Accions"
@ -242,7 +244,7 @@ msgstr "Accions per la factura %s"
#: web/template/invoices/index.gohtml:139 web/template/invoices/view.gohtml:19
#: web/template/quotes/index.gohtml:137 web/template/quotes/view.gohtml:22
#: web/template/contacts/index.gohtml:82 web/template/expenses/index.gohtml:125
#: web/template/products/index.gohtml:78 web/template/payments/index.gohtml:85
#: web/template/products/index.gohtml:78 web/template/payments/index.gohtml:109
msgctxt "action"
msgid "Edit"
msgstr "Edita"
@ -253,11 +255,18 @@ msgctxt "action"
msgid "Duplicate"
msgstr "Duplica"
#: web/template/invoices/index.gohtml:157
#: web/template/invoices/index.gohtml:153 web/template/payments/new.gohtml:24
#: web/template/payments/index.gohtml:4 web/template/payments/index.gohtml:21
#: web/template/payments/edit.gohtml:24
msgctxt "title"
msgid "Collections"
msgstr "Cobraments"
#: web/template/invoices/index.gohtml:163
msgid "No invoices added yet."
msgstr "No hi ha cap factura."
#: web/template/invoices/index.gohtml:164 web/template/quotes/index.gohtml:170
#: web/template/invoices/index.gohtml:170 web/template/quotes/index.gohtml:170
#: web/template/expenses/index.gohtml:148
msgid "Total"
msgstr "Total"
@ -633,7 +642,7 @@ msgstr "Nova despesa"
#: web/template/expenses/new.gohtml:11 web/template/expenses/index.gohtml:3
#: web/template/expenses/index.gohtml:11 web/template/expenses/edit.gohtml:11
#: web/template/payments/new.gohtml:12 web/template/payments/index.gohtml:12
#: web/template/payments/new.gohtml:16 web/template/payments/index.gohtml:16
#: web/template/payments/edit.gohtml:16
msgctxt "title"
msgid "Expenses"
@ -658,8 +667,9 @@ msgstr "Número de factura"
msgid "Actions for expense %s"
msgstr "Accions per la despesa %s"
#: web/template/expenses/index.gohtml:131
msgctxt "action"
#: web/template/expenses/index.gohtml:131 web/template/payments/new.gohtml:26
#: web/template/payments/index.gohtml:6 web/template/payments/edit.gohtml:26
msgctxt "title"
msgid "Payments"
msgstr "Pagaments"
@ -775,51 +785,68 @@ msgctxt "title"
msgid "Edit Product “%s”"
msgstr "Edició del producte «%s»"
#: web/template/payments/new.gohtml:3 web/template/payments/new.gohtml:16
#: web/template/payments/new.gohtml:4
msgctxt "title"
msgid "New Collection"
msgstr "Nou cobrament"
#: web/template/payments/new.gohtml:6
msgctxt "title"
msgid "New Payment"
msgstr "Nou pagament"
#: web/template/payments/new.gohtml:15 web/template/payments/index.gohtml:3
#: web/template/payments/index.gohtml:15 web/template/payments/edit.gohtml:19
msgctxt "title"
msgid "Payments"
msgstr "Pagaments"
#: web/template/payments/index.gohtml:30
msgctxt "action"
msgid "New collection"
msgstr "Nou cobrament"
#: web/template/payments/index.gohtml:20
#: web/template/payments/index.gohtml:32
msgctxt "action"
msgid "New payment"
msgstr "Nou pagament"
#: web/template/payments/index.gohtml:29
#: web/template/payments/index.gohtml:45
msgctxt "title"
msgid "Collection Date"
msgstr "Data del cobrament"
#: web/template/payments/index.gohtml:47
msgctxt "title"
msgid "Payment Date"
msgstr "Data del pagament"
#: web/template/payments/index.gohtml:30
#: web/template/payments/index.gohtml:50
msgctxt "title"
msgid "Description"
msgstr "Descripció"
#: web/template/payments/index.gohtml:31
#: web/template/payments/index.gohtml:52
msgctxt "title"
msgid "Document"
msgstr "Document"
#: web/template/payments/index.gohtml:41
#: web/template/payments/index.gohtml:62
msgid "Are you sure you wish to delete this collection?"
msgstr "Esteu segur de voler esborrar aquest cobrament?"
#: web/template/payments/index.gohtml:62
msgid "Are you sure you wish to delete this payment?"
msgstr "Esteu segur de voler esborrar aquest pagament?"
#: web/template/payments/index.gohtml:77
#: web/template/payments/index.gohtml:101
msgid "Actions for payment %s"
msgstr "Accions pel pagament %s"
#: web/template/payments/index.gohtml:96
#: web/template/payments/index.gohtml:120
msgctxt "action"
msgid "Remove"
msgstr "Esborra"
#: web/template/payments/index.gohtml:106
#: web/template/payments/index.gohtml:132
msgid "No collections added yet."
msgstr "No hi ha cap cobrament."
#: web/template/payments/index.gohtml:134
msgid "No payments added yet."
msgstr "No hi ha cap pagament."
@ -906,7 +933,7 @@ msgid "Name"
msgstr "Nom"
#: pkg/products.go:177 pkg/products.go:303 pkg/tags.go:37 pkg/quote.go:174
#: pkg/quote.go:708 pkg/payments.go:310 pkg/expenses.go:335 pkg/expenses.go:485
#: pkg/quote.go:708 pkg/payments.go:420 pkg/expenses.go:335 pkg/expenses.go:485
#: pkg/invoices.go:177 pkg/invoices.go:877 pkg/contacts.go:154
#: pkg/contacts.go:362
msgctxt "input"
@ -941,7 +968,7 @@ msgstr "Qualsevol"
msgid "Invoices must have at least one of the specified labels."
msgstr "Les factures han de tenir com a mínim una de les etiquetes."
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:277
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:387
#: pkg/invoices.go:1161
msgctxt "input"
msgid "Description"
@ -1356,75 +1383,80 @@ 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/payments.go:230
#: pkg/payments.go:309
#, c-format
msgid "Payment of %s"
msgstr "Pagament de %s"
#: pkg/payments.go:268 pkg/accounts.go:131
#: pkg/payments.go:339
#, c-format
msgid "Collection of %s"
msgstr "Cobrament de %s"
#: pkg/payments.go:378 pkg/accounts.go:131
msgctxt "input"
msgid "Type"
msgstr "Tipus"
#: pkg/payments.go:271
#: pkg/payments.go:381
msgctxt "payment type"
msgid "Payment"
msgstr "Pagament"
#: pkg/payments.go:272
#: pkg/payments.go:382
msgctxt "payment type"
msgid "Collection"
msgstr "Cobrament"
#: pkg/payments.go:283
#: pkg/payments.go:393
msgctxt "input"
msgid "Payment Date"
msgstr "Data del pagament"
#: pkg/payments.go:289
#: pkg/payments.go:399
msgctxt "input"
msgid "Account"
msgstr "Compte"
#: pkg/payments.go:295 pkg/expenses.go:319
#: pkg/payments.go:405 pkg/expenses.go:319
msgctxt "input"
msgid "Amount"
msgstr "Import"
#: pkg/payments.go:305 pkg/expenses.go:330 pkg/invoices.go:888
#: pkg/payments.go:415 pkg/expenses.go:330 pkg/invoices.go:888
msgctxt "input"
msgid "File"
msgstr "Fitxer"
#: pkg/payments.go:325
#: pkg/payments.go:443
msgid "Select a type."
msgstr "Escolliu un tipus."
#: pkg/payments.go:326
#: pkg/payments.go:444
msgid "Select an account."
msgstr "Escolliu un compte."
#: pkg/payments.go:390
#: pkg/payments.go:508
msgid "Selected payment type is not valid."
msgstr "Heu seleccionat un tipus de pagament que no és vàlid."
#: pkg/payments.go:391
#: pkg/payments.go:509
msgid "Description can not be empty."
msgstr "No podeu deixar la descripció en blanc."
#: pkg/payments.go:392
#: pkg/payments.go:510
msgid "Selected payment account is not valid."
msgstr "Heu seleccionat un compte de pagament que no és vàlid."
#: pkg/payments.go:393
#: pkg/payments.go:511
msgid "Payment date must be a valid date."
msgstr "La data de pagament ha de ser vàlida."
#: pkg/payments.go:394 pkg/expenses.go:372
#: pkg/payments.go:512 pkg/expenses.go:372
msgid "Amount can not be empty."
msgstr "No podeu deixar limport en blanc."
#: pkg/payments.go:395 pkg/expenses.go:373
#: pkg/payments.go:513 pkg/expenses.go:373
msgid "Amount must be a number greater than zero."
msgstr "Limport ha de ser un número major a zero."
@ -1625,6 +1657,10 @@ msgctxt "input"
msgid "Holded Excel file"
msgstr "Fitxer Excel del Holded"
#~ msgctxt "action"
#~ msgid "Payments"
#~ msgstr "Pagaments"
#~ msgctxt "title"
#~ msgid "Currency"
#~ msgstr "Moneda"

132
po/es.po
View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-08-21 03:28+0200\n"
"POT-Creation-Date: 2024-08-21 11:12+0200\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
@ -38,8 +38,8 @@ msgstr "Añadir productos a la factura"
#: web/template/company/invoicing.gohtml:10
#: web/template/company/payment_methods.gohtml:10
#: web/template/products/new.gohtml:9 web/template/products/index.gohtml:9
#: web/template/products/edit.gohtml:10 web/template/payments/new.gohtml:10
#: web/template/payments/index.gohtml:10 web/template/payments/edit.gohtml:14
#: web/template/products/edit.gohtml:10 web/template/payments/new.gohtml:14
#: web/template/payments/index.gohtml:14 web/template/payments/edit.gohtml:14
#: web/template/payments/accounts/new.gohtml:10
#: web/template/payments/accounts/index.gohtml:10
#: web/template/payments/accounts/edit.gohtml:10
@ -50,6 +50,8 @@ msgstr "Inicio"
#: web/template/invoices/products.gohtml:10 web/template/invoices/new.gohtml:10
#: web/template/invoices/index.gohtml:2 web/template/invoices/index.gohtml:10
#: web/template/invoices/view.gohtml:10 web/template/invoices/edit.gohtml:10
#: web/template/payments/new.gohtml:19 web/template/payments/index.gohtml:19
#: web/template/payments/edit.gohtml:19
msgctxt "title"
msgid "Invoices"
msgstr "Facturas"
@ -116,7 +118,7 @@ msgstr "Subtotal"
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
#: web/template/expenses/new.gohtml:46 web/template/expenses/index.gohtml:74
#: web/template/expenses/edit.gohtml:48 web/template/payments/index.gohtml:34
#: web/template/expenses/edit.gohtml:48 web/template/payments/index.gohtml:56
msgctxt "title"
msgid "Total"
msgstr "Total"
@ -124,7 +126,7 @@ msgstr "Total"
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
#: web/template/expenses/new.gohtml:56 web/template/expenses/edit.gohtml:58
#: web/template/payments/edit.gohtml:46
#: web/template/payments/edit.gohtml:55
#: web/template/payments/accounts/edit.gohtml:38
msgctxt "action"
msgid "Update"
@ -135,7 +137,7 @@ msgstr "Actualizar"
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
#: web/template/expenses/new.gohtml:59 web/template/expenses/edit.gohtml:61
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
#: web/template/payments/new.gohtml:44
#: web/template/payments/new.gohtml:57
#: web/template/payments/accounts/new.gohtml:41
msgctxt "action"
msgid "Save"
@ -193,14 +195,14 @@ msgid "Customer"
msgstr "Cliente"
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:32
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:54
msgctxt "title"
msgid "Status"
msgstr "Estado"
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:33
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:55
msgctxt "title"
msgid "Tags"
msgstr "Etiquetes"
@ -212,7 +214,7 @@ msgid "Amount"
msgstr "Importe"
#: web/template/invoices/index.gohtml:73 web/template/quotes/index.gohtml:73
#: web/template/expenses/index.gohtml:75 web/template/payments/index.gohtml:35
#: web/template/expenses/index.gohtml:75 web/template/payments/index.gohtml:57
msgctxt "title"
msgid "Download"
msgstr "Descargar"
@ -220,7 +222,7 @@ msgstr "Descargar"
#: web/template/invoices/index.gohtml:74 web/template/quotes/index.gohtml:74
#: web/template/contacts/index.gohtml:51 web/template/expenses/index.gohtml:76
#: web/template/company/switch.gohtml:23 web/template/products/index.gohtml:48
#: web/template/payments/index.gohtml:36
#: web/template/payments/index.gohtml:58
msgctxt "title"
msgid "Actions"
msgstr "Acciones"
@ -242,7 +244,7 @@ msgstr "Acciones para la factura %s"
#: web/template/invoices/index.gohtml:139 web/template/invoices/view.gohtml:19
#: web/template/quotes/index.gohtml:137 web/template/quotes/view.gohtml:22
#: web/template/contacts/index.gohtml:82 web/template/expenses/index.gohtml:125
#: web/template/products/index.gohtml:78 web/template/payments/index.gohtml:85
#: web/template/products/index.gohtml:78 web/template/payments/index.gohtml:109
msgctxt "action"
msgid "Edit"
msgstr "Editar"
@ -253,11 +255,18 @@ msgctxt "action"
msgid "Duplicate"
msgstr "Duplicar"
#: web/template/invoices/index.gohtml:157
#: web/template/invoices/index.gohtml:153 web/template/payments/new.gohtml:24
#: web/template/payments/index.gohtml:4 web/template/payments/index.gohtml:21
#: web/template/payments/edit.gohtml:24
msgctxt "title"
msgid "Collections"
msgstr "Cobros"
#: web/template/invoices/index.gohtml:163
msgid "No invoices added yet."
msgstr "No hay facturas."
#: web/template/invoices/index.gohtml:164 web/template/quotes/index.gohtml:170
#: web/template/invoices/index.gohtml:170 web/template/quotes/index.gohtml:170
#: web/template/expenses/index.gohtml:148
msgid "Total"
msgstr "Total"
@ -633,7 +642,7 @@ msgstr "Nuevo gasto"
#: web/template/expenses/new.gohtml:11 web/template/expenses/index.gohtml:3
#: web/template/expenses/index.gohtml:11 web/template/expenses/edit.gohtml:11
#: web/template/payments/new.gohtml:12 web/template/payments/index.gohtml:12
#: web/template/payments/new.gohtml:16 web/template/payments/index.gohtml:16
#: web/template/payments/edit.gohtml:16
msgctxt "title"
msgid "Expenses"
@ -658,8 +667,9 @@ msgstr "Número de factura"
msgid "Actions for expense %s"
msgstr "Acciones para el gasto %s"
#: web/template/expenses/index.gohtml:131
msgctxt "action"
#: web/template/expenses/index.gohtml:131 web/template/payments/new.gohtml:26
#: web/template/payments/index.gohtml:6 web/template/payments/edit.gohtml:26
msgctxt "title"
msgid "Payments"
msgstr "Pagos"
@ -775,51 +785,68 @@ msgctxt "title"
msgid "Edit Product “%s”"
msgstr "Edición del producto «%s»"
#: web/template/payments/new.gohtml:3 web/template/payments/new.gohtml:16
#: web/template/payments/new.gohtml:4
msgctxt "title"
msgid "New Collection"
msgstr "Nuevo cobro"
#: web/template/payments/new.gohtml:6
msgctxt "title"
msgid "New Payment"
msgstr "Nuevo pago"
#: web/template/payments/new.gohtml:15 web/template/payments/index.gohtml:3
#: web/template/payments/index.gohtml:15 web/template/payments/edit.gohtml:19
msgctxt "title"
msgid "Payments"
msgstr "Pagos"
#: web/template/payments/index.gohtml:30
msgctxt "action"
msgid "New collection"
msgstr "Nuevo cobro"
#: web/template/payments/index.gohtml:20
#: web/template/payments/index.gohtml:32
msgctxt "action"
msgid "New payment"
msgstr "Nuevo pago"
#: web/template/payments/index.gohtml:29
#: web/template/payments/index.gohtml:45
msgctxt "title"
msgid "Collection Date"
msgstr "Fecha del cobro"
#: web/template/payments/index.gohtml:47
msgctxt "title"
msgid "Payment Date"
msgstr "Fecha del pago"
#: web/template/payments/index.gohtml:30
#: web/template/payments/index.gohtml:50
msgctxt "title"
msgid "Description"
msgstr "Descripción"
#: web/template/payments/index.gohtml:31
#: web/template/payments/index.gohtml:52
msgctxt "title"
msgid "Document"
msgstr "Documento"
#: web/template/payments/index.gohtml:41
#: web/template/payments/index.gohtml:62
msgid "Are you sure you wish to delete this collection?"
msgstr "¿Estáis seguro de querer borrar este cobro?"
#: web/template/payments/index.gohtml:62
msgid "Are you sure you wish to delete this payment?"
msgstr "¿Estáis seguro de querer borrar este pago?"
#: web/template/payments/index.gohtml:77
#: web/template/payments/index.gohtml:101
msgid "Actions for payment %s"
msgstr "Acciones para el pago %s"
#: web/template/payments/index.gohtml:96
#: web/template/payments/index.gohtml:120
msgctxt "action"
msgid "Remove"
msgstr "Borrar"
#: web/template/payments/index.gohtml:106
#: web/template/payments/index.gohtml:132
msgid "No collections added yet."
msgstr "No hay cobros."
#: web/template/payments/index.gohtml:134
msgid "No payments added yet."
msgstr "No hay pagos."
@ -906,7 +933,7 @@ msgid "Name"
msgstr "Nombre"
#: pkg/products.go:177 pkg/products.go:303 pkg/tags.go:37 pkg/quote.go:174
#: pkg/quote.go:708 pkg/payments.go:310 pkg/expenses.go:335 pkg/expenses.go:485
#: pkg/quote.go:708 pkg/payments.go:420 pkg/expenses.go:335 pkg/expenses.go:485
#: pkg/invoices.go:177 pkg/invoices.go:877 pkg/contacts.go:154
#: pkg/contacts.go:362
msgctxt "input"
@ -941,7 +968,7 @@ msgstr "Cualquiera"
msgid "Invoices must have at least one of the specified labels."
msgstr "Las facturas deben tener como mínimo una de las etiquetas."
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:277
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:387
#: pkg/invoices.go:1161
msgctxt "input"
msgid "Description"
@ -1356,75 +1383,80 @@ 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/payments.go:230
#: pkg/payments.go:309
#, c-format
msgid "Payment of %s"
msgstr "Pago de %s"
#: pkg/payments.go:268 pkg/accounts.go:131
#: pkg/payments.go:339
#, c-format
msgid "Collection of %s"
msgstr "Cobro de %s"
#: pkg/payments.go:378 pkg/accounts.go:131
msgctxt "input"
msgid "Type"
msgstr "Tipo"
#: pkg/payments.go:271
#: pkg/payments.go:381
msgctxt "payment type"
msgid "Payment"
msgstr "Pago"
#: pkg/payments.go:272
#: pkg/payments.go:382
msgctxt "payment type"
msgid "Collection"
msgstr "Cobro"
#: pkg/payments.go:283
#: pkg/payments.go:393
msgctxt "input"
msgid "Payment Date"
msgstr "Fecha del pago"
#: pkg/payments.go:289
#: pkg/payments.go:399
msgctxt "input"
msgid "Account"
msgstr "Cuenta"
#: pkg/payments.go:295 pkg/expenses.go:319
#: pkg/payments.go:405 pkg/expenses.go:319
msgctxt "input"
msgid "Amount"
msgstr "Importe"
#: pkg/payments.go:305 pkg/expenses.go:330 pkg/invoices.go:888
#: pkg/payments.go:415 pkg/expenses.go:330 pkg/invoices.go:888
msgctxt "input"
msgid "File"
msgstr "Archivo"
#: pkg/payments.go:325
#: pkg/payments.go:443
msgid "Select a type."
msgstr "Escoged un tipo."
#: pkg/payments.go:326
#: pkg/payments.go:444
msgid "Select an account."
msgstr "Escoged una cuenta."
#: pkg/payments.go:390
#: pkg/payments.go:508
msgid "Selected payment type is not valid."
msgstr "Habéis escogido un tipo de pago que no es válido."
#: pkg/payments.go:391
#: pkg/payments.go:509
msgid "Description can not be empty."
msgstr "No podéis dejar la descripción en blanco."
#: pkg/payments.go:392
#: pkg/payments.go:510
msgid "Selected payment account is not valid."
msgstr "Habéis escogido una cuenta de pago que no es válida."
#: pkg/payments.go:393
#: pkg/payments.go:511
msgid "Payment date must be a valid date."
msgstr "La fecha de pago debe ser válida."
#: pkg/payments.go:394 pkg/expenses.go:372
#: pkg/payments.go:512 pkg/expenses.go:372
msgid "Amount can not be empty."
msgstr "No podéis dejar el importe en blanco."
#: pkg/payments.go:395 pkg/expenses.go:373
#: pkg/payments.go:513 pkg/expenses.go:373
msgid "Amount must be a number greater than zero."
msgstr "El importe tiene que ser un número mayor a cero."
@ -1625,6 +1657,10 @@ msgctxt "input"
msgid "Holded Excel file"
msgstr "Archivo Excel de Holded"
#~ msgctxt "action"
#~ msgid "Payments"
#~ msgstr "Pagos"
#~ msgctxt "title"
#~ msgid "Currency"
#~ msgstr "Moneda"

View File

@ -128,7 +128,7 @@
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/expenses"}}/{{ .Slug }}/payments">
<i class="ri-bank-card-2-line"></i>
{{( pgettext "Payments" "action" )}}
{{( pgettext "Payments" "title" )}}
</a>
</li>
</ul>

View File

@ -147,6 +147,12 @@
{{( pgettext "Duplicate" "action" )}}
</a>
</li>
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/invoices"}}/{{ .Slug }}/collections">
<i class="ri-bank-card-2-line"></i>
{{( pgettext "Collections" "title" )}}
</a>
</li>
</ul>
</details>
</td>

View File

@ -15,8 +15,17 @@
{{ if .Expense }}
<a href="{{ companyURI "/expenses" }}">{{( pgettext "Expenses" "title" )}}</a> /
<a href="{{ companyURI "/expenses/" }}{{ .Expense.Slug }}">{{ .Expense.InvoiceNumber }}</a> /
{{ else if .Invoice }}
<a href="{{ companyURI "/invoices" }}">{{( pgettext "Invoices" "title" )}}</a> /
<a href="{{ companyURI "/invoices/" }}{{ .Invoice.Slug }}">{{ .Invoice.InvoiceNumber }}</a> /
{{ end }}
<a href="{{ .BaseURI }}">{{( pgettext "Payments" "title" )}}</a> /
<a href="{{ .BaseURI }}">
{{- if .Invoice -}}
{{( pgettext "Collections" "title" )}}
{{- else -}}
{{( pgettext "Payments" "title" )}}
{{- end -}}
</a> /
<a>{{ .Description }}</a>
</p>
</nav>

View File

@ -1,6 +1,10 @@
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.PaymentIndexPage*/ -}}
{{- if .Invoice -}}
{{( pgettext "Collections" "title" )}}
{{- else -}}
{{( pgettext "Payments" "title" )}}
{{- end -}}
{{- end }}
{{ define "breadcrumbs" -}}
@ -11,13 +15,22 @@
{{ if .Expense }}
<a href="{{ companyURI "/expenses" }}">{{( pgettext "Expenses" "title" )}}</a> /
<a href="{{ companyURI "/expenses/" }}{{ .Expense.Slug }}">{{ .Expense.InvoiceNumber }}</a> /
{{ else if .Invoice }}
<a href="{{ companyURI "/invoices" }}">{{( pgettext "Invoices" "title" )}}</a> /
<a href="{{ companyURI "/invoices/" }}{{ .Invoice.Slug }}">{{ .Invoice.InvoiceNumber }}</a> /
{{ end }}
<a>{{( pgettext "Payments" "title" )}}</a>
<a>{{ template "title" . }}</a>
</p>
<a class="primary button"
data-hx-boost="true"
href="{{ .BaseURI }}/new">{{( pgettext "New payment" "action" )}}</a>
href="{{ .BaseURI }}/new">
{{- if .Invoice -}}
{{( pgettext "New collection" "action" )}}
{{- else -}}
{{( pgettext "New payment" "action" )}}
{{- end -}}
</a>
</nav>
{{- end }}
@ -26,9 +39,17 @@
<table>
<thead>
<tr>
<th>{{( pgettext "Payment Date" "title" )}}</th>
<th>
{{- if .Invoice -}}
{{( pgettext "Collection Date" "title" )}}
{{- else -}}
{{( pgettext "Payment Date" "title" )}}
{{- end -}}
</th>
<th>{{( pgettext "Description" "title" )}}</th>
{{ if not (or .Invoice .Expense)}}
<th>{{( pgettext "Document" "title" )}}</th>
{{ end }}
<th>{{( pgettext "Status" "title" )}}</th>
<th>{{( pgettext "Tags" "title" )}}</th>
<th class="numeric">{{( pgettext "Total" "title" )}}</th>
@ -37,12 +58,13 @@
</tr>
</thead>
<tbody>
{{ $confirm := or (and .Invoice (gettext "Are you sure you wish to delete this collection?")) (gettext "Are you sure you wish to delete this payment?") }}
{{ with .Payments }}
{{ $confirm := (gettext "Are you sure you wish to delete this payment?")}}
{{- range $payment := . }}
<tr>
<td>{{ .PaymentDate|formatDate }}</td>
<td><a href="{{ $.BaseURI }}/{{ .Slug }}">{{ .Description }}</a></td>
{{ if not (or $.Invoice $.Expense)}}
<td>
{{- if .InvoiceNumber -}}
{{- if eq .Type "P" -}}
@ -52,6 +74,7 @@
{{- end -}}
{{- end -}}
</td>
{{ end }}
<td class="payment-status-{{ .Status }}">{{ .StatusLabel }}</td>
<td
data-hx-get="{{ companyURI "/payments/" }}{{ .Slug }}/tags/edit"
@ -103,7 +126,13 @@
{{- end }}
{{ else }}
<tr>
<td colspan="8">{{( gettext "No payments added yet." )}}</td>
<td colspan="8">
{{- if .Invoice -}}
{{( gettext "No collections added yet." )}}
{{- else -}}
{{( gettext "No payments added yet." )}}
{{- end -}}
</td>
</tr>
{{ end }}
</tbody>

View File

@ -1,6 +1,10 @@
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.PaymentForm*/ -}}
{{- if .Invoice -}}
{{( pgettext "New Collection" "title" )}}
{{- else -}}
{{( pgettext "New Payment" "title" )}}
{{- end -}}
{{- end }}
{{ define "breadcrumbs" -}}
@ -11,9 +15,18 @@
{{ if .Expense }}
<a href="{{ companyURI "/expenses" }}">{{( pgettext "Expenses" "title" )}}</a> /
<a href="{{ companyURI "/expenses/" }}{{ .Expense.Slug }}">{{ .Expense.InvoiceNumber }}</a> /
{{ else if .Invoice }}
<a href="{{ companyURI "/invoices" }}">{{( pgettext "Invoices" "title" )}}</a> /
<a href="{{ companyURI "/invoices/" }}{{ .Invoice.Slug }}">{{ .Invoice.InvoiceNumber }}</a> /
{{ end }}
<a href="{{ .BaseURI }}">{{( pgettext "Payments" "title" )}}</a> /
<a>{{( pgettext "New Payment" "title" )}}</a>
<a href="{{ .BaseURI }}">
{{- if .Invoice -}}
{{( pgettext "Collections" "title" )}}
{{- else -}}
{{( pgettext "Payments" "title" )}}
{{- end -}}
</a> /
<a>{{ template "title" . }}</a>
</p>
</nav>
{{- end }}
@ -28,11 +41,11 @@
data-hx-boost="true">
{{ csrfToken }}
{{- if .Expense -}}
{{ if or .Expense .Invoice -}}
{{ template "hidden-select-field" .Type }}
{{- else -}}
{{ template "select-field" .Type }}
{{- end -}}
{{- end }}
{{ template "select-field" .PaymentAccount }}
{{ template "input-field" .Description }}
{{ template "input-field" .PaymentDate }}