Add the payment method relation and corresponding form
This commit is contained in:
parent
b84f1774f9
commit
9894925742
|
@ -0,0 +1,35 @@
|
||||||
|
-- Deploy numerus:payment_method to pg
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: company
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_method (
|
||||||
|
payment_method_id serial primary key,
|
||||||
|
company_id integer not null references company,
|
||||||
|
name text not null constraint name_not_empty check(length(trim(name)) > 0),
|
||||||
|
instructions text not null
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table payment_method to invoicer;
|
||||||
|
grant select, insert, update, delete on table payment_method to admin;
|
||||||
|
|
||||||
|
grant usage on sequence payment_method_payment_method_id_seq to invoicer;
|
||||||
|
grant usage on sequence payment_method_payment_method_id_seq to admin;
|
||||||
|
|
||||||
|
alter table payment_method enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on payment_method
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from company_user
|
||||||
|
join user_profile using (user_id)
|
||||||
|
where company_user.company_id = payment_method.company_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
commit;
|
136
pkg/company.go
136
pkg/company.go
|
@ -77,6 +77,12 @@ type Tax struct {
|
||||||
Rate int
|
Rate int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PaymentMethod struct {
|
||||||
|
Id int
|
||||||
|
Name string
|
||||||
|
Instructions string
|
||||||
|
}
|
||||||
|
|
||||||
type taxDetailsForm struct {
|
type taxDetailsForm struct {
|
||||||
*contactForm
|
*contactForm
|
||||||
Currency *SelectField
|
Currency *SelectField
|
||||||
|
@ -134,9 +140,11 @@ func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaxDetailsPage struct {
|
type TaxDetailsPage struct {
|
||||||
DetailsForm *taxDetailsForm
|
DetailsForm *taxDetailsForm
|
||||||
NewTaxForm *taxForm
|
NewTaxForm *taxForm
|
||||||
Taxes []*Tax
|
Taxes []*Tax
|
||||||
|
NewPaymentMethodForm *paymentMethodForm
|
||||||
|
PaymentMethods []*PaymentMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
func GetCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
@ -178,17 +186,30 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustRenderTaxDetailsForm(w http.ResponseWriter, r *http.Request, form *taxDetailsForm) {
|
func mustRenderTaxDetailsForm(w http.ResponseWriter, r *http.Request, form *taxDetailsForm) {
|
||||||
|
conn := getConn(r)
|
||||||
|
locale := getLocale(r)
|
||||||
page := &TaxDetailsPage{
|
page := &TaxDetailsPage{
|
||||||
DetailsForm: form,
|
DetailsForm: form,
|
||||||
NewTaxForm: newTaxForm(r.Context(), getConn(r), mustGetCompany(r), getLocale(r)),
|
NewTaxForm: newTaxForm(r.Context(), conn, mustGetCompany(r), locale),
|
||||||
|
NewPaymentMethodForm: newPaymentMethodForm(locale),
|
||||||
}
|
}
|
||||||
mustRenderTexDetailsPage(w, r, page)
|
mustRenderTexDetailsPage(w, r, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustRenderTaxForm(w http.ResponseWriter, r *http.Request, form *taxForm) {
|
func mustRenderTaxForm(w http.ResponseWriter, r *http.Request, form *taxForm) {
|
||||||
page := &TaxDetailsPage{
|
page := &TaxDetailsPage{
|
||||||
DetailsForm: newTaxDetailsFormFromDatabase(r),
|
DetailsForm: newTaxDetailsFormFromDatabase(r),
|
||||||
NewTaxForm: form,
|
NewTaxForm: form,
|
||||||
|
NewPaymentMethodForm: newPaymentMethodForm(getLocale(r)),
|
||||||
|
}
|
||||||
|
mustRenderTexDetailsPage(w, r, page)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustRenderPaymentMethodForm(w http.ResponseWriter, r *http.Request, form *paymentMethodForm) {
|
||||||
|
page := &TaxDetailsPage{
|
||||||
|
DetailsForm: newTaxDetailsFormFromDatabase(r),
|
||||||
|
NewTaxForm: newTaxForm(r.Context(), getConn(r), mustGetCompany(r), getLocale(r)),
|
||||||
|
NewPaymentMethodForm: form,
|
||||||
}
|
}
|
||||||
mustRenderTexDetailsPage(w, r, page)
|
mustRenderTexDetailsPage(w, r, page)
|
||||||
}
|
}
|
||||||
|
@ -197,6 +218,7 @@ func mustRenderTexDetailsPage(w http.ResponseWriter, r *http.Request, page *TaxD
|
||||||
conn := getConn(r)
|
conn := getConn(r)
|
||||||
company := mustGetCompany(r)
|
company := mustGetCompany(r)
|
||||||
page.Taxes = mustGetTaxes(r.Context(), conn, company)
|
page.Taxes = mustGetTaxes(r.Context(), conn, company)
|
||||||
|
page.PaymentMethods = mustCollectPaymentMethods(r.Context(), conn, company)
|
||||||
mustRenderAppTemplate(w, r, "tax-details.gohtml", page)
|
mustRenderAppTemplate(w, r, "tax-details.gohtml", page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +253,29 @@ func mustGetTaxes(ctx context.Context, conn *Conn, company *Company) []*Tax {
|
||||||
return taxes
|
return taxes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustCollectPaymentMethods(ctx context.Context, conn *Conn, company *Company) []*PaymentMethod {
|
||||||
|
rows, err := conn.Query(ctx, "select payment_method_id, name, instructions from payment_method where company_id = $1 order by name", company.Id)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var methods []*PaymentMethod
|
||||||
|
for rows.Next() {
|
||||||
|
method := &PaymentMethod{}
|
||||||
|
err = rows.Scan(&method.Id, &method.Name, &method.Instructions)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
methods = append(methods, method)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
panic(rows.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
type taxForm struct {
|
type taxForm struct {
|
||||||
locale *Locale
|
locale *Locale
|
||||||
Name *InputField
|
Name *InputField
|
||||||
|
@ -323,3 +368,80 @@ func HandleAddCompanyTax(w http.ResponseWriter, r *http.Request, _ httprouter.Pa
|
||||||
conn.MustExec(r.Context(), "insert into tax (company_id, tax_class_id, name, rate) values ($1, $2, $3, $4 / 100::decimal)", company.Id, form.Class, form.Name, form.Rate.Integer())
|
conn.MustExec(r.Context(), "insert into tax (company_id, tax_class_id, name, rate) values ($1, $2, $3, $4 / 100::decimal)", company.Id, form.Class, form.Name, form.Rate.Integer())
|
||||||
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther)
|
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type paymentMethodForm struct {
|
||||||
|
locale *Locale
|
||||||
|
Name *InputField
|
||||||
|
Instructions *InputField
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPaymentMethodForm(locale *Locale) *paymentMethodForm {
|
||||||
|
return &paymentMethodForm{
|
||||||
|
locale: locale,
|
||||||
|
Name: &InputField{
|
||||||
|
Name: "method_name",
|
||||||
|
Label: pgettext("input", "Payment method name", locale),
|
||||||
|
Type: "text",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
Instructions: &InputField{
|
||||||
|
Name: "method_instructions",
|
||||||
|
Label: pgettext("input", "Instructions", locale),
|
||||||
|
Type: "textarea",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (form *paymentMethodForm) Parse(r *http.Request) error {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
form.Name.FillValue(r)
|
||||||
|
form.Instructions.FillValue(r)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (form *paymentMethodForm) Validate() bool {
|
||||||
|
validator := newFormValidator()
|
||||||
|
validator.CheckRequiredInput(form.Name, gettext("Payment method name can not be empty.", form.locale))
|
||||||
|
validator.CheckRequiredInput(form.Instructions, gettext("Payment instructions can not be empty.", form.locale))
|
||||||
|
return validator.AllOK()
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleDeletePaymentMethod(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
paymentMethodId, err := strconv.Atoi(params[0].Value)
|
||||||
|
if err != nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn := getConn(r)
|
||||||
|
conn.MustExec(r.Context(), "delete from payment_method where payment_method_id = $1", paymentMethodId)
|
||||||
|
http.Redirect(w, r, companyURI(mustGetCompany(r), "/tax-details"), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleAddPaymentMethod(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
locale := getLocale(r)
|
||||||
|
conn := getConn(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentMethodForm(locale)
|
||||||
|
if err := form.Parse(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.Validate() {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
mustRenderPaymentMethodForm(w, r, form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.MustExec(r.Context(), "insert into payment_method (company_id, name, instructions) values ($1, $2, $3)", company.Id, form.Name, form.Instructions)
|
||||||
|
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ func NewRouter(db *Db) http.Handler {
|
||||||
companyRouter.POST("/tax-details", HandleCompanyTaxDetailsForm)
|
companyRouter.POST("/tax-details", HandleCompanyTaxDetailsForm)
|
||||||
companyRouter.POST("/tax", HandleAddCompanyTax)
|
companyRouter.POST("/tax", HandleAddCompanyTax)
|
||||||
companyRouter.DELETE("/tax/:taxId", HandleDeleteCompanyTax)
|
companyRouter.DELETE("/tax/:taxId", HandleDeleteCompanyTax)
|
||||||
|
companyRouter.POST("/payment-method", HandleAddPaymentMethod)
|
||||||
|
companyRouter.DELETE("/payment-method/:paymentMethodId", HandleDeletePaymentMethod)
|
||||||
companyRouter.GET("/contacts", IndexContacts)
|
companyRouter.GET("/contacts", IndexContacts)
|
||||||
companyRouter.POST("/contacts", HandleAddContact)
|
companyRouter.POST("/contacts", HandleAddContact)
|
||||||
companyRouter.GET("/contacts/:slug", GetContactForm)
|
companyRouter.GET("/contacts/:slug", GetContactForm)
|
||||||
|
|
158
po/ca.po
158
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-03-01 14:00+0100\n"
|
"POT-Creation-Date: 2023-03-03 16:38+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:60 web/template/products/index.gohtml:23
|
#: web/template/invoices/view.gohtml:53 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:65
|
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:58
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Subtotal"
|
msgstr "Subtotal"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:69
|
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:62
|
||||||
#: web/template/invoices/view.gohtml:109
|
#: web/template/invoices/view.gohtml:102
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -149,22 +149,22 @@ msgctxt "action"
|
||||||
msgid "Download invoice"
|
msgid "Download invoice"
|
||||||
msgstr "Descarrega factura"
|
msgstr "Descarrega factura"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:59
|
#: web/template/invoices/view.gohtml:52
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Concept"
|
msgid "Concept"
|
||||||
msgstr "Concepte"
|
msgstr "Concepte"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:62
|
#: web/template/invoices/view.gohtml:55
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Discount"
|
msgid "Discount"
|
||||||
msgstr "Descompte"
|
msgstr "Descompte"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:64
|
#: web/template/invoices/view.gohtml:57
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Units"
|
msgid "Units"
|
||||||
msgstr "Unitats"
|
msgstr "Unitats"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:99
|
#: web/template/invoices/view.gohtml:92
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tax Base"
|
msgid "Tax Base"
|
||||||
msgstr "Base imposable"
|
msgstr "Base imposable"
|
||||||
|
@ -286,7 +286,7 @@ msgctxt "title"
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Idioma"
|
msgstr "Idioma"
|
||||||
|
|
||||||
#: web/template/profile.gohtml:35 web/template/tax-details.gohtml:101
|
#: web/template/profile.gohtml:35 web/template/tax-details.gohtml:165
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Save changes"
|
msgid "Save changes"
|
||||||
msgstr "Desa canvis"
|
msgstr "Desa canvis"
|
||||||
|
@ -302,35 +302,59 @@ msgctxt "title"
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr "Moneda"
|
msgstr "Moneda"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:47
|
#: web/template/tax-details.gohtml:37
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Invoicing"
|
||||||
|
msgstr "Facturació"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:54
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tax Name"
|
msgid "Tax Name"
|
||||||
msgstr "Nom impost"
|
msgstr "Nom impost"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:48
|
#: web/template/tax-details.gohtml:55
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Rate (%)"
|
msgid "Rate (%)"
|
||||||
msgstr "Percentatge"
|
msgstr "Percentatge"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:49
|
#: web/template/tax-details.gohtml:56
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Class"
|
msgid "Class"
|
||||||
msgstr "Classe"
|
msgstr "Classe"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:73
|
#: web/template/tax-details.gohtml:80
|
||||||
msgid "No taxes added yet."
|
msgid "No taxes added yet."
|
||||||
msgstr "No hi ha cap impost."
|
msgstr "No hi ha cap impost."
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:79
|
#: web/template/tax-details.gohtml:86 web/template/tax-details.gohtml:146
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "New Line"
|
msgid "New Line"
|
||||||
msgstr "Nova línia"
|
msgstr "Nova línia"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:93
|
#: web/template/tax-details.gohtml:100
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Add new tax"
|
msgid "Add new tax"
|
||||||
msgstr "Afegeix nou impost"
|
msgstr "Afegeix nou impost"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:116
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Method"
|
||||||
|
msgstr "Mètode de pagament"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:117
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Instructions"
|
||||||
|
msgstr "Instruccions"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:140
|
||||||
|
msgid "No payment methods added yet."
|
||||||
|
msgstr "No hi ha cap mètode de pagament."
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:157
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "Add new payment method"
|
||||||
|
msgstr "Afegeix nou mètode de pagament"
|
||||||
|
|
||||||
#: web/template/products/new.gohtml:2 web/template/products/new.gohtml:11
|
#: web/template/products/new.gohtml:2 web/template/products/new.gohtml:11
|
||||||
#: web/template/products/new.gohtml:15
|
#: web/template/products/new.gohtml:15
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
|
@ -384,91 +408,123 @@ 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:468
|
#: pkg/products.go:165 pkg/invoices.go:469
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: pkg/products.go:171 pkg/invoices.go:473
|
#: pkg/products.go:171 pkg/invoices.go:474
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
#: pkg/products.go:176 pkg/invoices.go:477
|
#: pkg/products.go:176 pkg/invoices.go:478
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Preu"
|
msgstr "Preu"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/invoices.go:366 pkg/invoices.go:503
|
#: pkg/products.go:186 pkg/invoices.go:367 pkg/invoices.go:504
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Taxes"
|
msgid "Taxes"
|
||||||
msgstr "Imposts"
|
msgstr "Imposts"
|
||||||
|
|
||||||
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:399
|
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:400
|
||||||
#: pkg/invoices.go:539
|
#: pkg/invoices.go:540
|
||||||
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:540
|
#: pkg/products.go:207 pkg/invoices.go:541
|
||||||
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:541
|
#: pkg/products.go:208 pkg/invoices.go:542
|
||||||
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:403 pkg/invoices.go:549
|
#: pkg/products.go:210 pkg/invoices.go:404 pkg/invoices.go:550
|
||||||
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:211 pkg/invoices.go:550
|
#: pkg/products.go:211 pkg/invoices.go:551
|
||||||
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."
|
||||||
|
|
||||||
#: pkg/company.go:90
|
#: pkg/company.go:98
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr "Moneda"
|
msgstr "Moneda"
|
||||||
|
|
||||||
#: pkg/company.go:108
|
#: pkg/company.go:105
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Invoice number format"
|
||||||
|
msgstr "Format del número de factura"
|
||||||
|
|
||||||
|
#: pkg/company.go:111
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Legal disclaimer"
|
||||||
|
msgstr "Nota legal"
|
||||||
|
|
||||||
|
#: pkg/company.go:129
|
||||||
msgid "Selected currency is not valid."
|
msgid "Selected currency is not valid."
|
||||||
msgstr "Heu seleccionat una moneda que no és vàlida."
|
msgstr "Heu seleccionat una moneda que no és vàlida."
|
||||||
|
|
||||||
#: pkg/company.go:230
|
#: pkg/company.go:130
|
||||||
|
msgid "Invoice number format can not be empty."
|
||||||
|
msgstr "No podeu deixar el format del número de factura en blanc."
|
||||||
|
|
||||||
|
#: pkg/company.go:291
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tax name"
|
msgid "Tax name"
|
||||||
msgstr "Nom impost"
|
msgstr "Nom impost"
|
||||||
|
|
||||||
#: pkg/company.go:236
|
#: pkg/company.go:297
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tax Class"
|
msgid "Tax Class"
|
||||||
msgstr "Classe d’impost"
|
msgstr "Classe d’impost"
|
||||||
|
|
||||||
#: pkg/company.go:239
|
#: pkg/company.go:300
|
||||||
msgid "Select a tax class"
|
msgid "Select a tax class"
|
||||||
msgstr "Escolliu una classe d’impost"
|
msgstr "Escolliu una classe d’impost"
|
||||||
|
|
||||||
#: pkg/company.go:243
|
#: pkg/company.go:304
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Rate (%)"
|
msgid "Rate (%)"
|
||||||
msgstr "Percentatge"
|
msgstr "Percentatge"
|
||||||
|
|
||||||
#: pkg/company.go:266
|
#: pkg/company.go:327
|
||||||
msgid "Tax name can not be empty."
|
msgid "Tax name can not be empty."
|
||||||
msgstr "No podeu deixar el nom de l’impost en blanc."
|
msgstr "No podeu deixar el nom de l’impost en blanc."
|
||||||
|
|
||||||
#: pkg/company.go:267
|
#: pkg/company.go:328
|
||||||
msgid "Selected tax class is not valid."
|
msgid "Selected tax class is not valid."
|
||||||
msgstr "Heu seleccionat una classe d’impost que no és vàlida."
|
msgstr "Heu seleccionat una classe d’impost que no és vàlida."
|
||||||
|
|
||||||
#: pkg/company.go:268
|
#: pkg/company.go:329
|
||||||
msgid "Tax rate can not be empty."
|
msgid "Tax rate can not be empty."
|
||||||
msgstr "No podeu deixar percentatge en blanc."
|
msgstr "No podeu deixar percentatge en blanc."
|
||||||
|
|
||||||
#: pkg/company.go:269
|
#: pkg/company.go:330
|
||||||
msgid "Tax rate must be an integer between -99 and 99."
|
msgid "Tax rate must be an integer between -99 and 99."
|
||||||
msgstr "El percentatge ha de ser entre -99 i 99."
|
msgstr "El percentatge ha de ser entre -99 i 99."
|
||||||
|
|
||||||
|
#: pkg/company.go:383
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Payment method name"
|
||||||
|
msgstr "Nom del mètode de pagament"
|
||||||
|
|
||||||
|
#: pkg/company.go:389
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Instructions"
|
||||||
|
msgstr "Instruccions"
|
||||||
|
|
||||||
|
#: pkg/company.go:407
|
||||||
|
msgid "Payment method name can not be empty."
|
||||||
|
msgstr "No podeu deixar el nom del mètode de pagament en blanc."
|
||||||
|
|
||||||
|
#: pkg/company.go:408
|
||||||
|
msgid "Payment instructions can not be empty."
|
||||||
|
msgstr "No podeu deixar les instruccions de pagament en blanc."
|
||||||
|
|
||||||
#: pkg/profile.go:25
|
#: pkg/profile.go:25
|
||||||
msgctxt "language option"
|
msgctxt "language option"
|
||||||
msgid "Automatic"
|
msgid "Automatic"
|
||||||
|
@ -497,70 +553,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:229
|
#: pkg/invoices.go:230
|
||||||
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:322
|
#: pkg/invoices.go:323
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acció invàlida."
|
msgstr "Acció invàlida."
|
||||||
|
|
||||||
#: pkg/invoices.go:343
|
#: pkg/invoices.go:344
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Customer"
|
msgid "Customer"
|
||||||
msgstr "Client"
|
msgstr "Client"
|
||||||
|
|
||||||
#: pkg/invoices.go:349
|
#: pkg/invoices.go:350
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
#: pkg/invoices.go:355
|
#: pkg/invoices.go:356
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Date"
|
msgid "Invoice Date"
|
||||||
msgstr "Data de factura"
|
msgstr "Data de factura"
|
||||||
|
|
||||||
#: pkg/invoices.go:361
|
#: pkg/invoices.go:362
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
msgstr "Notes"
|
msgstr "Notes"
|
||||||
|
|
||||||
#: pkg/invoices.go:400
|
#: pkg/invoices.go:401
|
||||||
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:401
|
#: pkg/invoices.go:402
|
||||||
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:463
|
#: pkg/invoices.go:464
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identificador"
|
msgstr "Identificador"
|
||||||
|
|
||||||
#: pkg/invoices.go:486
|
#: pkg/invoices.go:487
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Quantitat"
|
msgstr "Quantitat"
|
||||||
|
|
||||||
#: pkg/invoices.go:494
|
#: pkg/invoices.go:495
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Discount (%)"
|
msgid "Discount (%)"
|
||||||
msgstr "Descompte (%)"
|
msgstr "Descompte (%)"
|
||||||
|
|
||||||
#: pkg/invoices.go:543
|
#: pkg/invoices.go:544
|
||||||
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:544
|
#: pkg/invoices.go:545
|
||||||
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:546
|
#: pkg/invoices.go:547
|
||||||
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:547
|
#: pkg/invoices.go:548
|
||||||
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."
|
||||||
|
|
||||||
|
|
158
po/es.po
158
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-03-01 14:00+0100\n"
|
"POT-Creation-Date: 2023-03-03 16:38+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:60 web/template/products/index.gohtml:23
|
#: web/template/invoices/view.gohtml:53 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:65
|
#: web/template/invoices/new.gohtml:41 web/template/invoices/view.gohtml:58
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Subtotal"
|
msgstr "Subtotal"
|
||||||
|
|
||||||
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:69
|
#: web/template/invoices/new.gohtml:51 web/template/invoices/view.gohtml:62
|
||||||
#: web/template/invoices/view.gohtml:109
|
#: web/template/invoices/view.gohtml:102
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -149,22 +149,22 @@ msgctxt "action"
|
||||||
msgid "Download invoice"
|
msgid "Download invoice"
|
||||||
msgstr "Descargar factura"
|
msgstr "Descargar factura"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:59
|
#: web/template/invoices/view.gohtml:52
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Concept"
|
msgid "Concept"
|
||||||
msgstr "Concepto"
|
msgstr "Concepto"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:62
|
#: web/template/invoices/view.gohtml:55
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Discount"
|
msgid "Discount"
|
||||||
msgstr "Descuento"
|
msgstr "Descuento"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:64
|
#: web/template/invoices/view.gohtml:57
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Units"
|
msgid "Units"
|
||||||
msgstr "Unidades"
|
msgstr "Unidades"
|
||||||
|
|
||||||
#: web/template/invoices/view.gohtml:99
|
#: web/template/invoices/view.gohtml:92
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tax Base"
|
msgid "Tax Base"
|
||||||
msgstr "Base imponible"
|
msgstr "Base imponible"
|
||||||
|
@ -286,7 +286,7 @@ msgctxt "title"
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Idioma"
|
msgstr "Idioma"
|
||||||
|
|
||||||
#: web/template/profile.gohtml:35 web/template/tax-details.gohtml:101
|
#: web/template/profile.gohtml:35 web/template/tax-details.gohtml:165
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Save changes"
|
msgid "Save changes"
|
||||||
msgstr "Guardar cambios"
|
msgstr "Guardar cambios"
|
||||||
|
@ -302,35 +302,59 @@ msgctxt "title"
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr "Moneda"
|
msgstr "Moneda"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:47
|
#: web/template/tax-details.gohtml:37
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Invoicing"
|
||||||
|
msgstr "Facturació"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:54
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tax Name"
|
msgid "Tax Name"
|
||||||
msgstr "Nombre impuesto"
|
msgstr "Nombre impuesto"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:48
|
#: web/template/tax-details.gohtml:55
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Rate (%)"
|
msgid "Rate (%)"
|
||||||
msgstr "Porcentaje"
|
msgstr "Porcentaje"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:49
|
#: web/template/tax-details.gohtml:56
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Class"
|
msgid "Class"
|
||||||
msgstr "Clase"
|
msgstr "Clase"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:73
|
#: web/template/tax-details.gohtml:80
|
||||||
msgid "No taxes added yet."
|
msgid "No taxes added yet."
|
||||||
msgstr "No hay impuestos."
|
msgstr "No hay impuestos."
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:79
|
#: web/template/tax-details.gohtml:86 web/template/tax-details.gohtml:146
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "New Line"
|
msgid "New Line"
|
||||||
msgstr "Nueva línea"
|
msgstr "Nueva línea"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:93
|
#: web/template/tax-details.gohtml:100
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Add new tax"
|
msgid "Add new tax"
|
||||||
msgstr "Añadir nuevo impuesto"
|
msgstr "Añadir nuevo impuesto"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:116
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Method"
|
||||||
|
msgstr "Método de pago"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:117
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Instructions"
|
||||||
|
msgstr "Instrucciones"
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:140
|
||||||
|
msgid "No payment methods added yet."
|
||||||
|
msgstr "No hay métodos de pago."
|
||||||
|
|
||||||
|
#: web/template/tax-details.gohtml:157
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "Add new payment method"
|
||||||
|
msgstr "Añadir nuevo método de pago"
|
||||||
|
|
||||||
#: web/template/products/new.gohtml:2 web/template/products/new.gohtml:11
|
#: web/template/products/new.gohtml:2 web/template/products/new.gohtml:11
|
||||||
#: web/template/products/new.gohtml:15
|
#: web/template/products/new.gohtml:15
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
|
@ -384,91 +408,123 @@ 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:468
|
#: pkg/products.go:165 pkg/invoices.go:469
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: pkg/products.go:171 pkg/invoices.go:473
|
#: pkg/products.go:171 pkg/invoices.go:474
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripción"
|
msgstr "Descripción"
|
||||||
|
|
||||||
#: pkg/products.go:176 pkg/invoices.go:477
|
#: pkg/products.go:176 pkg/invoices.go:478
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Precio"
|
msgstr "Precio"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/invoices.go:366 pkg/invoices.go:503
|
#: pkg/products.go:186 pkg/invoices.go:367 pkg/invoices.go:504
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Taxes"
|
msgid "Taxes"
|
||||||
msgstr "Impuestos"
|
msgstr "Impuestos"
|
||||||
|
|
||||||
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:399
|
#: pkg/products.go:206 pkg/profile.go:92 pkg/invoices.go:400
|
||||||
#: pkg/invoices.go:539
|
#: pkg/invoices.go:540
|
||||||
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:540
|
#: pkg/products.go:207 pkg/invoices.go:541
|
||||||
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:541
|
#: pkg/products.go:208 pkg/invoices.go:542
|
||||||
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:403 pkg/invoices.go:549
|
#: pkg/products.go:210 pkg/invoices.go:404 pkg/invoices.go:550
|
||||||
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:211 pkg/invoices.go:550
|
#: pkg/products.go:211 pkg/invoices.go:551
|
||||||
msgid "You can only select a tax of each class."
|
msgid "You can only select a tax of each class."
|
||||||
msgstr "Solo podéis escojer un impuesto de cada clase."
|
msgstr "Solo podéis escojer un impuesto de cada clase."
|
||||||
|
|
||||||
#: pkg/company.go:90
|
#: pkg/company.go:98
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr "Moneda"
|
msgstr "Moneda"
|
||||||
|
|
||||||
#: pkg/company.go:108
|
#: pkg/company.go:105
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Invoice number format"
|
||||||
|
msgstr "Formato del número de factura"
|
||||||
|
|
||||||
|
#: pkg/company.go:111
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Legal disclaimer"
|
||||||
|
msgstr "Nota legal"
|
||||||
|
|
||||||
|
#: pkg/company.go:129
|
||||||
msgid "Selected currency is not valid."
|
msgid "Selected currency is not valid."
|
||||||
msgstr "Habéis escogido una moneda que no es válida."
|
msgstr "Habéis escogido una moneda que no es válida."
|
||||||
|
|
||||||
#: pkg/company.go:230
|
#: pkg/company.go:130
|
||||||
|
msgid "Invoice number format can not be empty."
|
||||||
|
msgstr "No podéis dejar el formato del número de factura en blanco."
|
||||||
|
|
||||||
|
#: pkg/company.go:291
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tax name"
|
msgid "Tax name"
|
||||||
msgstr "Nombre impuesto"
|
msgstr "Nombre impuesto"
|
||||||
|
|
||||||
#: pkg/company.go:236
|
#: pkg/company.go:297
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tax Class"
|
msgid "Tax Class"
|
||||||
msgstr "Clase de impuesto"
|
msgstr "Clase de impuesto"
|
||||||
|
|
||||||
#: pkg/company.go:239
|
#: pkg/company.go:300
|
||||||
msgid "Select a tax class"
|
msgid "Select a tax class"
|
||||||
msgstr "Escoged una clase de impuesto"
|
msgstr "Escoged una clase de impuesto"
|
||||||
|
|
||||||
#: pkg/company.go:243
|
#: pkg/company.go:304
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Rate (%)"
|
msgid "Rate (%)"
|
||||||
msgstr "Porcentaje"
|
msgstr "Porcentaje"
|
||||||
|
|
||||||
#: pkg/company.go:266
|
#: pkg/company.go:327
|
||||||
msgid "Tax name can not be empty."
|
msgid "Tax name can not be empty."
|
||||||
msgstr "No podéis dejar el nombre del impuesto en blanco."
|
msgstr "No podéis dejar el nombre del impuesto en blanco."
|
||||||
|
|
||||||
#: pkg/company.go:267
|
#: pkg/company.go:328
|
||||||
msgid "Selected tax class is not valid."
|
msgid "Selected tax class is not valid."
|
||||||
msgstr "Habéis escogido una clase impuesto que no es válida."
|
msgstr "Habéis escogido una clase impuesto que no es válida."
|
||||||
|
|
||||||
#: pkg/company.go:268
|
#: pkg/company.go:329
|
||||||
msgid "Tax rate can not be empty."
|
msgid "Tax rate can not be empty."
|
||||||
msgstr "No podéis dejar el porcentaje en blanco."
|
msgstr "No podéis dejar el porcentaje en blanco."
|
||||||
|
|
||||||
#: pkg/company.go:269
|
#: pkg/company.go:330
|
||||||
msgid "Tax rate must be an integer between -99 and 99."
|
msgid "Tax rate must be an integer between -99 and 99."
|
||||||
msgstr "El porcentaje tiene que estar entre -99 y 99."
|
msgstr "El porcentaje tiene que estar entre -99 y 99."
|
||||||
|
|
||||||
|
#: pkg/company.go:383
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Payment method name"
|
||||||
|
msgstr "Nombre del método de pago"
|
||||||
|
|
||||||
|
#: pkg/company.go:389
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Instructions"
|
||||||
|
msgstr "Instrucciones"
|
||||||
|
|
||||||
|
#: pkg/company.go:407
|
||||||
|
msgid "Payment method name can not be empty."
|
||||||
|
msgstr "No podéis dejar el nombre del método de pago en blanco."
|
||||||
|
|
||||||
|
#: pkg/company.go:408
|
||||||
|
msgid "Payment instructions can not be empty."
|
||||||
|
msgstr "No podéis dejar las instrucciones de pago en blanco."
|
||||||
|
|
||||||
#: pkg/profile.go:25
|
#: pkg/profile.go:25
|
||||||
msgctxt "language option"
|
msgctxt "language option"
|
||||||
msgid "Automatic"
|
msgid "Automatic"
|
||||||
|
@ -497,70 +553,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:229
|
#: pkg/invoices.go:230
|
||||||
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:322
|
#: pkg/invoices.go:323
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acción inválida."
|
msgstr "Acción inválida."
|
||||||
|
|
||||||
#: pkg/invoices.go:343
|
#: pkg/invoices.go:344
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Customer"
|
msgid "Customer"
|
||||||
msgstr "Cliente"
|
msgstr "Cliente"
|
||||||
|
|
||||||
#: pkg/invoices.go:349
|
#: pkg/invoices.go:350
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
#: pkg/invoices.go:355
|
#: pkg/invoices.go:356
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Date"
|
msgid "Invoice Date"
|
||||||
msgstr "Fecha de factura"
|
msgstr "Fecha de factura"
|
||||||
|
|
||||||
#: pkg/invoices.go:361
|
#: pkg/invoices.go:362
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
msgstr "Notas"
|
msgstr "Notas"
|
||||||
|
|
||||||
#: pkg/invoices.go:400
|
#: pkg/invoices.go:401
|
||||||
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:401
|
#: pkg/invoices.go:402
|
||||||
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:463
|
#: pkg/invoices.go:464
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identificador"
|
msgstr "Identificador"
|
||||||
|
|
||||||
#: pkg/invoices.go:486
|
#: pkg/invoices.go:487
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Cantidad"
|
msgstr "Cantidad"
|
||||||
|
|
||||||
#: pkg/invoices.go:494
|
#: pkg/invoices.go:495
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Discount (%)"
|
msgid "Discount (%)"
|
||||||
msgstr "Descuento (%)"
|
msgstr "Descuento (%)"
|
||||||
|
|
||||||
#: pkg/invoices.go:543
|
#: pkg/invoices.go:544
|
||||||
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:544
|
#: pkg/invoices.go:545
|
||||||
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:546
|
#: pkg/invoices.go:547
|
||||||
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:547
|
#: pkg/invoices.go:548
|
||||||
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."
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_method from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_method;
|
||||||
|
|
||||||
|
commit;
|
|
@ -62,3 +62,4 @@ invoice_product_amount [schema_numerus invoice_product invoice_product_tax] 2023
|
||||||
invoice_amount [schema_numerus invoice_product invoice_product_amount] 2023-02-22T12:58:46Z jordi fita mas <jordi@tandem.blog> # Add view to compute subtotal and total for invoices
|
invoice_amount [schema_numerus invoice_product invoice_product_amount] 2023-02-22T12:58:46Z jordi fita mas <jordi@tandem.blog> # Add view to compute subtotal and total for invoices
|
||||||
new_invoice_amount [schema_numerus] 2023-02-23T12:08:25Z jordi fita mas <jordi@tandem.blog> # Add type to return when computing new invoice amounts
|
new_invoice_amount [schema_numerus] 2023-02-23T12:08:25Z jordi fita mas <jordi@tandem.blog> # Add type to return when computing new invoice amounts
|
||||||
compute_new_invoice_amount [schema_numerus company currency tax new_invoice_product new_invoice_amount] 2023-02-23T12:20:13Z jordi fita mas <jordi@tandem.blog> # Add function to compute the subtotal, taxes, and total amounts for a new invoice
|
compute_new_invoice_amount [schema_numerus company currency tax new_invoice_product new_invoice_amount] 2023-02-23T12:20:13Z jordi fita mas <jordi@tandem.blog> # Add function to compute the subtotal, taxes, and total amounts for a new invoice
|
||||||
|
payment_method [schema_numerus company] 2023-03-03T15:00:41Z jordi fita mas <jordi@tandem.blog> # Add relation of payment method
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
-- Test payment_method
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(36);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('payment_method');
|
||||||
|
select has_pk('payment_method' );
|
||||||
|
select table_privs_are('payment_method', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_method', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_method', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_method', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_sequence('payment_method_payment_method_id_seq');
|
||||||
|
select sequence_privs_are('payment_method_payment_method_id_seq', 'guest', array[]::text[]);
|
||||||
|
select sequence_privs_are('payment_method_payment_method_id_seq', 'invoicer', array['USAGE']);
|
||||||
|
select sequence_privs_are('payment_method_payment_method_id_seq', 'admin', array['USAGE']);
|
||||||
|
select sequence_privs_are('payment_method_payment_method_id_seq', 'authenticator', array[]::text[]);
|
||||||
|
|
||||||
|
select has_column('payment_method', 'payment_method_id');
|
||||||
|
select col_is_pk('payment_method', 'payment_method_id');
|
||||||
|
select col_type_is('payment_method', 'payment_method_id', 'integer');
|
||||||
|
select col_not_null('payment_method', 'payment_method_id');
|
||||||
|
select col_has_default('payment_method', 'payment_method_id');
|
||||||
|
select col_default_is('payment_method', 'payment_method_id', 'nextval(''payment_method_payment_method_id_seq''::regclass)');
|
||||||
|
|
||||||
|
select has_column('payment_method', 'company_id');
|
||||||
|
select col_is_fk('payment_method', 'company_id');
|
||||||
|
select fk_ok('payment_method', 'company_id', 'company', 'company_id');
|
||||||
|
select col_type_is('payment_method', 'company_id', 'integer');
|
||||||
|
select col_not_null('payment_method', 'company_id');
|
||||||
|
select col_hasnt_default('payment_method', 'company_id');
|
||||||
|
|
||||||
|
select has_column('payment_method', 'name');
|
||||||
|
select col_type_is('payment_method', 'name', 'text');
|
||||||
|
select col_not_null('payment_method', 'name');
|
||||||
|
select col_hasnt_default('payment_method', 'name');
|
||||||
|
|
||||||
|
select has_column('payment_method', 'instructions');
|
||||||
|
select col_type_is('payment_method', 'instructions', 'text');
|
||||||
|
select col_not_null('payment_method', 'instructions');
|
||||||
|
select col_hasnt_default('payment_method', 'instructions');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR')
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method(company_id, name, instructions)
|
||||||
|
values (2, 'Cash', 'Payment in cash.')
|
||||||
|
, (2, 'Wire Transfer', 'Please, transfer money to my Nigerian bank')
|
||||||
|
, (4, 'Pigeon', 'Send money via carrier pigeon.')
|
||||||
|
;
|
||||||
|
|
||||||
|
prepare payment_method_data as
|
||||||
|
select company_id, name, instructions
|
||||||
|
from payment_method;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('payment_method_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_method_data',
|
||||||
|
$$ values ( 2, 'Cash', 'Payment in cash.' )
|
||||||
|
, ( 2, 'Wire Transfer', 'Please, transfer money to my Nigerian bank' )
|
||||||
|
$$,
|
||||||
|
'Should only list payment methods of the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_method_data',
|
||||||
|
$$ values (4, 'Pigeon', 'Send money via carrier pigeon.' )
|
||||||
|
$$,
|
||||||
|
'Should only list payment methods of the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'payment_method_data',
|
||||||
|
'42501', 'permission denied for table payment_method',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_method (company_id, name, instructions)
|
||||||
|
values (2, ' ', 'atasht')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_method" violates check constraint "name_not_empty"',
|
||||||
|
'Should not allow payment methods with blank name'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- Verify numerus:payment_method on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_method_id
|
||||||
|
, company_id
|
||||||
|
, name
|
||||||
|
, instructions
|
||||||
|
from numerus.payment_method
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.payment_method'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.payment_method'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -104,6 +104,63 @@
|
||||||
</table>
|
</table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<form id="new-payment-method" method="POST" action="{{ companyURI "/payment-method" }}">
|
||||||
|
{{ csrfToken }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50%"></th>
|
||||||
|
<th>{{( pgettext "Payment Method" "title" )}}</th>
|
||||||
|
<th>{{( pgettext "Instructions" "title" )}}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ with .PaymentMethods }}
|
||||||
|
{{- range $method := . }}
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>{{ .Name }}</td>
|
||||||
|
<td>{{ .Instructions }}</td>
|
||||||
|
<td>
|
||||||
|
<form method="POST" action="{{ companyURI "/payment-method"}}/{{ .Id }}">
|
||||||
|
{{ csrfToken }}
|
||||||
|
{{ deleteMethod }}
|
||||||
|
<button class="icon" aria-label="{{( gettext "Delete payment method" )}}" type="submit"><i
|
||||||
|
class="ri-delete-back-2-line"></i></button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{- end }}
|
||||||
|
{{ else }}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">{{( gettext "No payment methods added yet." )}}</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{( pgettext "New Line" "title")}}</th>
|
||||||
|
<td>
|
||||||
|
{{ template "input-field" .NewPaymentMethodForm.Name | addInputAttr `form="new-payment-method"` }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ template "input-field" .NewPaymentMethodForm.Instructions | addInputAttr `form="new-payment-method"` }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"></td>
|
||||||
|
<td colspan="2">
|
||||||
|
<button form="new-payment-method" type="submit">{{( pgettext "Add new payment method" "action" )}}</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<button form="details" type="submit">{{( pgettext "Save changes" "action" )}}</button>
|
<button form="details" type="submit">{{( pgettext "Save changes" "action" )}}</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
Loading…
Reference in New Issue