Split the tax details “mega dialog” into separate pages

I needed to place the payment accounts section somewhere, and the most
logical place seemed to be that dialog, where users can set up company
parameters.

However, that dialog was already saturated with related, but ultimately
independent forms, and adding the account section would make things
even worse, specially given that we need to be able to edit those
accounts in a separate page.

We agreed to separate that dialog into tabs, which means separate pages.
When i had everything in a separated page, then i did not know how to
actually share the code for the tabs, and decided that, for now, these
“tabs” would be items from the profile menu.  Same function, different
presentation.
This commit is contained in:
jordi fita mas 2024-08-14 04:08:13 +02:00
parent e626c7b4bd
commit f95936c523
11 changed files with 993 additions and 796 deletions

View File

@ -98,11 +98,6 @@ type taxDetailsForm struct {
PostalCode *InputField PostalCode *InputField
Country *SelectField Country *SelectField
Currency *SelectField Currency *SelectField
InvoiceNumberFormat *InputField
NextInvoiceNumber *InputField
QuoteNumberFormat *InputField
NextQuoteNumber *InputField
LegalDisclaimer *InputField
} }
func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDetailsForm { func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDetailsForm {
@ -202,6 +197,206 @@ func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDeta
Required: true, Required: true,
Selected: []string{"EUR"}, Selected: []string{"EUR"},
}, },
}
}
func (form *taxDetailsForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
form.TradeName.FillValue(r)
form.BusinessName.FillValue(r)
form.VATIN.FillValue(r)
form.Phone.FillValue(r)
form.Email.FillValue(r)
form.Web.FillValue(r)
form.Address.FillValue(r)
form.City.FillValue(r)
form.Province.FillValue(r)
form.PostalCode.FillValue(r)
form.Country.FillValue(r)
form.Currency.FillValue(r)
return nil
}
func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool {
validator := newFormValidator()
country := ""
if validator.CheckValidSelectOption(form.Country, gettext("Selected country is not valid.", form.locale)) {
country = form.Country.Selected[0]
}
validator.CheckRequiredInput(form.BusinessName, gettext("Business name can not be empty.", form.locale))
validator.CheckInputMinLength(form.BusinessName, 2, gettext("Business name must have at least two letters.", form.locale))
if validator.CheckRequiredInput(form.VATIN, gettext("VAT number can not be empty.", form.locale)) {
validator.CheckValidVATINInput(ctx, conn, form.VATIN, country, gettext("This value is not a valid VAT number.", form.locale))
}
if validator.CheckRequiredInput(form.Phone, gettext("Phone can not be empty.", form.locale)) {
validator.CheckValidPhoneInput(ctx, conn, form.Phone, country, gettext("This value is not a valid phone number.", form.locale))
}
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
validator.CheckValidEmailInput(form.Email, gettext("This value is not a valid email. It should be like name@domain.com.", form.locale))
}
if form.Web.Val != "" {
validator.CheckValidURL(form.Web, gettext("This value is not a valid web address. It should be like https://domain.com/.", form.locale))
}
validator.CheckRequiredInput(form.Address, gettext("Address can not be empty.", form.locale))
validator.CheckRequiredInput(form.City, gettext("City can not be empty.", form.locale))
validator.CheckRequiredInput(form.Province, gettext("Province can not be empty.", form.locale))
if validator.CheckRequiredInput(form.PostalCode, gettext("Postal code can not be empty.", form.locale)) {
validator.CheckValidPostalCode(ctx, conn, form.PostalCode, country, gettext("This value is not a valid postal code.", form.locale))
}
validator.CheckValidSelectOption(form.Currency, gettext("Selected currency is not valid.", form.locale))
return validator.AllOK()
}
func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn, company *Company) *taxDetailsForm {
err := conn.QueryRow(ctx, `
select business_name
, substr(vatin::text, 3)
, trade_name
, phone
, email
, web
, address
, city
, province
, postal_code
, country_code
, currency_code
from company
where company.company_id = $1`, company.Id).Scan(
form.BusinessName,
form.VATIN,
form.TradeName,
form.Phone,
form.Email,
form.Web,
form.Address,
form.City,
form.Province,
form.PostalCode,
form.Country,
form.Currency,
)
if err != nil {
panic(err)
}
return form
}
type TaxDetailsPage struct {
DetailsForm *taxDetailsForm
}
func (page *TaxDetailsPage) MustRender(w http.ResponseWriter, r *http.Request) {
mustRenderMainTemplate(w, r, "company/tax-details.gohtml", page)
}
func GetCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
mustRenderTaxDetailsForm(w, r, newTaxDetailsFormFromDatabase(r))
}
func newTaxDetailsFormFromDatabase(r *http.Request) *taxDetailsForm {
locale := getLocale(r)
conn := getConn(r)
form := newTaxDetailsForm(r.Context(), conn, locale)
company := mustGetCompany(r)
form.mustFillFromDatabase(r.Context(), conn, company)
return form
}
func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
locale := getLocale(r)
conn := getConn(r)
form := newTaxDetailsForm(r.Context(), conn, 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 ok := form.Validate(r.Context(), conn); !ok {
if !IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity)
}
mustRenderTaxDetailsForm(w, r, form)
return
}
company := mustGetCompany(r)
conn.MustExec(r.Context(), `
update company
set business_name = $1
, vatin = ($11 || $2)::vatin
, trade_name = $3
, phone = parse_packed_phone_number($4, $11)
, email = $5
, web = $6
, address = $7
, city = $8
, province = $9
, postal_code = $10
, country_code = $11
, currency_code = $12
where company_id = $13
`,
form.BusinessName,
form.VATIN,
form.TradeName,
form.Phone,
form.Email,
form.Web,
form.Address,
form.City,
form.Province,
form.PostalCode,
form.Country,
form.Currency,
company.Id)
htmxRedirect(w, r, companyURI(company, "/tax-details"))
}
func mustRenderTaxDetailsForm(w http.ResponseWriter, r *http.Request, form *taxDetailsForm) {
page := &TaxDetailsPage{
DetailsForm: form,
}
page.MustRender(w, r)
}
func mustGetCompany(r *http.Request) *Company {
company := getCompany(r)
if company == nil {
panic(errors.New("company: required but not found"))
}
return company
}
func serveCompanyInvoicingForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
conn := getConn(r)
company := mustGetCompany(r)
locale := getLocale(r)
form := newInvoicingFormFromDatabase(r.Context(), conn, company, locale)
form.MustRender(w, r)
}
type InvoicingForm struct {
locale *Locale
InvoiceNumberFormat *InputField
NextInvoiceNumber *InputField
QuoteNumberFormat *InputField
NextQuoteNumber *InputField
LegalDisclaimer *InputField
}
func newInvoicingForm(locale *Locale) *InvoicingForm {
return &InvoicingForm{
locale: locale,
InvoiceNumberFormat: &InputField{ InvoiceNumberFormat: &InputField{
Name: "invoice_number_format", Name: "invoice_number_format",
Label: pgettext("input", "Invoice number format", locale), Label: pgettext("input", "Invoice number format", locale),
@ -240,82 +435,15 @@ func newTaxDetailsForm(ctx context.Context, conn *Conn, locale *Locale) *taxDeta
} }
} }
func (form *taxDetailsForm) Parse(r *http.Request) error { func newInvoicingFormFromDatabase(ctx context.Context, conn *Conn, company *Company, locale *Locale) *InvoicingForm {
if err := r.ParseForm(); err != nil { form := newInvoicingForm(locale)
return err form.mustFillFromDatabase(ctx, conn, company)
} return form
form.TradeName.FillValue(r)
form.BusinessName.FillValue(r)
form.VATIN.FillValue(r)
form.Phone.FillValue(r)
form.Email.FillValue(r)
form.Web.FillValue(r)
form.Address.FillValue(r)
form.City.FillValue(r)
form.Province.FillValue(r)
form.PostalCode.FillValue(r)
form.Country.FillValue(r)
form.Currency.FillValue(r)
form.InvoiceNumberFormat.FillValue(r)
form.NextInvoiceNumber.FillValue(r)
form.QuoteNumberFormat.FillValue(r)
form.NextQuoteNumber.FillValue(r)
form.LegalDisclaimer.FillValue(r)
return nil
} }
func (form *taxDetailsForm) Validate(ctx context.Context, conn *Conn) bool { func (form *InvoicingForm) mustFillFromDatabase(ctx context.Context, conn *Conn, company *Company) {
validator := newFormValidator()
country := ""
if validator.CheckValidSelectOption(form.Country, gettext("Selected country is not valid.", form.locale)) {
country = form.Country.Selected[0]
}
validator.CheckRequiredInput(form.BusinessName, gettext("Business name can not be empty.", form.locale))
validator.CheckInputMinLength(form.BusinessName, 2, gettext("Business name must have at least two letters.", form.locale))
if validator.CheckRequiredInput(form.VATIN, gettext("VAT number can not be empty.", form.locale)) {
validator.CheckValidVATINInput(ctx, conn, form.VATIN, country, gettext("This value is not a valid VAT number.", form.locale))
}
if validator.CheckRequiredInput(form.Phone, gettext("Phone can not be empty.", form.locale)) {
validator.CheckValidPhoneInput(ctx, conn, form.Phone, country, gettext("This value is not a valid phone number.", form.locale))
}
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
validator.CheckValidEmailInput(form.Email, gettext("This value is not a valid email. It should be like name@domain.com.", form.locale))
}
if form.Web.Val != "" {
validator.CheckValidURL(form.Web, gettext("This value is not a valid web address. It should be like https://domain.com/.", form.locale))
}
validator.CheckRequiredInput(form.Address, gettext("Address can not be empty.", form.locale))
validator.CheckRequiredInput(form.City, gettext("City can not be empty.", form.locale))
validator.CheckRequiredInput(form.Province, gettext("Province can not be empty.", form.locale))
if validator.CheckRequiredInput(form.PostalCode, gettext("Postal code can not be empty.", form.locale)) {
validator.CheckValidPostalCode(ctx, conn, form.PostalCode, country, gettext("This value is not a valid postal code.", form.locale))
}
validator.CheckValidSelectOption(form.Currency, gettext("Selected currency is not valid.", form.locale))
validator.CheckRequiredInput(form.InvoiceNumberFormat, gettext("Invoice number format can not be empty.", form.locale))
validator.CheckValidInteger(form.NextInvoiceNumber, 1, math.MaxInt32, gettext("Next invoice number must be a number greater than zero.", form.locale))
validator.CheckRequiredInput(form.QuoteNumberFormat, gettext("Quotation number format can not be empty.", form.locale))
validator.CheckValidInteger(form.NextQuoteNumber, 1, math.MaxInt32, gettext("Next quotation number must be a number greater than zero.", form.locale))
return validator.AllOK()
}
func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn, company *Company) *taxDetailsForm {
err := conn.QueryRow(ctx, ` err := conn.QueryRow(ctx, `
select business_name select invoice_number_format
, substr(vatin::text, 3)
, trade_name
, phone
, email
, web
, address
, city
, province
, postal_code
, country_code
, currency_code
, invoice_number_format
, quote_number_format , quote_number_format
, legal_disclaimer , legal_disclaimer
, coalesce(invoice_number_counter.currval, 0) + 1 , coalesce(invoice_number_counter.currval, 0) + 1
@ -328,18 +456,6 @@ func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn
on quote_number_counter.company_id = company.company_id on quote_number_counter.company_id = company.company_id
and quote_number_counter.year = date_part('year', current_date) and quote_number_counter.year = date_part('year', current_date)
where company.company_id = $1`, company.Id).Scan( where company.company_id = $1`, company.Id).Scan(
form.BusinessName,
form.VATIN,
form.TradeName,
form.Phone,
form.Email,
form.Web,
form.Address,
form.City,
form.Province,
form.PostalCode,
form.Country,
form.Currency,
form.InvoiceNumberFormat, form.InvoiceNumberFormat,
form.QuoteNumberFormat, form.QuoteNumberFormat,
form.LegalDisclaimer, form.LegalDisclaimer,
@ -349,36 +465,39 @@ func (form *taxDetailsForm) mustFillFromDatabase(ctx context.Context, conn *Conn
if err != nil { if err != nil {
panic(err) panic(err)
} }
return form
} }
type TaxDetailsPage struct { func (form *InvoicingForm) MustRender(w http.ResponseWriter, r *http.Request) {
DetailsForm *taxDetailsForm mustRenderMainTemplate(w, r, "company/invoicing.gohtml", form)
NewTaxForm *taxForm
Taxes []*Tax
NewPaymentMethodForm *paymentMethodForm
PaymentMethods []*PaymentMethod
} }
func GetCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (form *InvoicingForm) Parse(r *http.Request) error {
mustRenderTaxDetailsForm(w, r, newTaxDetailsFormFromDatabase(r)) if err := r.ParseForm(); err != nil {
return err
}
form.InvoiceNumberFormat.FillValue(r)
form.NextInvoiceNumber.FillValue(r)
form.QuoteNumberFormat.FillValue(r)
form.NextQuoteNumber.FillValue(r)
form.LegalDisclaimer.FillValue(r)
return nil
} }
func newTaxDetailsFormFromDatabase(r *http.Request) *taxDetailsForm { func (form *InvoicingForm) Validate() bool {
validator := newFormValidator()
validator.CheckRequiredInput(form.InvoiceNumberFormat, gettext("Invoice number format can not be empty.", form.locale))
validator.CheckValidInteger(form.NextInvoiceNumber, 1, math.MaxInt32, gettext("Next invoice number must be a number greater than zero.", form.locale))
validator.CheckRequiredInput(form.QuoteNumberFormat, gettext("Quotation number format can not be empty.", form.locale))
validator.CheckValidInteger(form.NextQuoteNumber, 1, math.MaxInt32, gettext("Next quotation number must be a number greater than zero.", form.locale))
return validator.AllOK()
}
func handleCompanyInvoicingForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
locale := getLocale(r) locale := getLocale(r)
conn := getConn(r) conn := getConn(r)
form := newTaxDetailsForm(r.Context(), conn, locale) form := newInvoicingForm(locale)
company := mustGetCompany(r)
form.mustFillFromDatabase(r.Context(), conn, company)
return form
}
func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
locale := getLocale(r)
conn := getConn(r)
form := newTaxDetailsForm(r.Context(), conn, locale)
if err := form.Parse(r); err != nil { if err := form.Parse(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@ -387,11 +506,11 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr
http.Error(w, err.Error(), http.StatusForbidden) http.Error(w, err.Error(), http.StatusForbidden)
return return
} }
if ok := form.Validate(r.Context(), conn); !ok { if ok := form.Validate(); !ok {
if !IsHTMxRequest(r) { if !IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity) w.WriteHeader(http.StatusUnprocessableEntity)
} }
mustRenderTaxDetailsForm(w, r, form) form.MustRender(w, r)
return return
} }
company := mustGetCompany(r) company := mustGetCompany(r)
@ -399,35 +518,11 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr
defer tx.MustRollback(r.Context()) defer tx.MustRollback(r.Context())
tx.MustExec(r.Context(), ` tx.MustExec(r.Context(), `
update company update company
set business_name = $1 set invoice_number_format = $1
, vatin = ($11 || $2)::vatin , quote_number_format = $2
, trade_name = $3 , legal_disclaimer = $3
, phone = parse_packed_phone_number($4, $11) where company_id = $4
, email = $5
, web = $6
, address = $7
, city = $8
, province = $9
, postal_code = $10
, country_code = $11
, currency_code = $12
, invoice_number_format = $13
, quote_number_format = $14
, legal_disclaimer = $15
where company_id = $16
`, `,
form.BusinessName,
form.VATIN,
form.TradeName,
form.Phone,
form.Email,
form.Web,
form.Address,
form.City,
form.Province,
form.PostalCode,
form.Country,
form.Currency,
form.InvoiceNumberFormat, form.InvoiceNumberFormat,
form.QuoteNumberFormat, form.QuoteNumberFormat,
form.LegalDisclaimer, form.LegalDisclaimer,
@ -449,60 +544,39 @@ func HandleCompanyTaxDetailsForm(w http.ResponseWriter, r *http.Request, _ httpr
company.Id, company.Id,
form.NextQuoteNumber.Integer()-1) form.NextQuoteNumber.Integer()-1)
tx.MustCommit(r.Context()) tx.MustCommit(r.Context())
if IsHTMxRequest(r) { htmxRedirect(w, r, companyURI(company, "/invoicing"))
w.Header().Set(HxTrigger, "closeModal")
w.WriteHeader(http.StatusNoContent)
} else {
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther)
}
} }
func mustRenderTaxDetailsForm(w http.ResponseWriter, r *http.Request, form *taxDetailsForm) { func serveCompanyTaxes(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
conn := getConn(r)
locale := getLocale(r)
page := &TaxDetailsPage{
DetailsForm: form,
NewTaxForm: newTaxForm(r.Context(), conn, mustGetCompany(r), locale),
NewPaymentMethodForm: newPaymentMethodForm(locale),
}
mustRenderTexDetailsPage(w, r, page)
}
func mustRenderTaxForm(w http.ResponseWriter, r *http.Request, form *taxForm) {
page := &TaxDetailsPage{
DetailsForm: newTaxDetailsFormFromDatabase(r),
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)
}
func mustRenderTexDetailsPage(w http.ResponseWriter, r *http.Request, page *TaxDetailsPage) {
conn := getConn(r) conn := getConn(r)
company := mustGetCompany(r) company := mustGetCompany(r)
page.Taxes = mustGetTaxes(r.Context(), conn, company) locale := getLocale(r)
page.PaymentMethods = mustCollectPaymentMethods(r.Context(), conn, company) page := newTaxesPage(r.Context(), conn, company, locale)
mustRenderModalTemplate(w, r, "tax-details.gohtml", page) page.MustRender(w, r)
} }
func mustGetCompany(r *http.Request) *Company { type TaxesPage struct {
company := getCompany(r) Taxes []*Tax
if company == nil { Form *taxForm
panic(errors.New("company: required but not found")) }
func newTaxesPage(ctx context.Context, conn *Conn, company *Company, locale *Locale) *TaxesPage {
form := newTaxForm(ctx, conn, company, locale)
return newTaxesPageWithForm(ctx, conn, company, form)
}
func newTaxesPageWithForm(ctx context.Context, conn *Conn, company *Company, form *taxForm) *TaxesPage {
return &TaxesPage{
Taxes: mustCollectTaxes(ctx, conn, company),
Form: form,
} }
return company
} }
func mustGetTaxes(ctx context.Context, conn *Conn, company *Company) []*Tax { func (page *TaxesPage) MustRender(w http.ResponseWriter, r *http.Request) {
mustRenderMainTemplate(w, r, "company/taxes.gohtml", page)
}
func mustCollectTaxes(ctx context.Context, conn *Conn, company *Company) []*Tax {
rows, err := conn.Query(ctx, "select tax_id, tax.name, tax_class.name, (rate * 100)::integer from tax join tax_class using (tax_class_id) where tax.company_id = $1 order by rate, tax.name", company.Id) rows, err := conn.Query(ctx, "select tax_id, tax.name, tax_class.name, (rate * 100)::integer from tax join tax_class using (tax_class_id) where tax.company_id = $1 order by rate, tax.name", company.Id)
if err != nil { if err != nil {
panic(err) panic(err)
@ -525,29 +599,6 @@ 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
@ -604,25 +655,6 @@ func (form *taxForm) Validate() bool {
return validator.AllOK() return validator.AllOK()
} }
func HandleDeleteCompanyTax(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
taxId, 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 tax where tax_id = $1", taxId)
if IsHTMxRequest(r) {
w.WriteHeader(http.StatusOK)
} else {
http.Redirect(w, r, companyURI(mustGetCompany(r), "/tax-details"), http.StatusSeeOther)
}
}
func HandleAddCompanyTax(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func HandleAddCompanyTax(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
locale := getLocale(r) locale := getLocale(r)
conn := getConn(r) conn := getConn(r)
@ -640,15 +672,80 @@ func HandleAddCompanyTax(w http.ResponseWriter, r *http.Request, _ httprouter.Pa
if !IsHTMxRequest(r) { if !IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity) w.WriteHeader(http.StatusUnprocessableEntity)
} }
mustRenderTaxForm(w, r, form) page := newTaxesPageWithForm(r.Context(), conn, company, form)
page.MustRender(w, r)
return return
} }
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())
if IsHTMxRequest(r) { htmxRedirect(w, r, companyURI(company, "/taxes"))
mustRenderTaxForm(w, r, newTaxForm(r.Context(), conn, company, locale)) }
} else {
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther) func HandleDeleteCompanyTax(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
taxId, 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 tax where tax_id = $1", taxId)
company := mustGetCompany(r)
htmxRedirect(w, r, companyURI(company, "/taxes"))
}
func servePaymentMethods(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
conn := getConn(r)
company := mustGetCompany(r)
locale := getLocale(r)
page := newPaymentMethodsPage(r.Context(), conn, company, locale)
page.MustRender(w, r)
}
type PaymentMethodsPage struct {
PaymentMethods []*PaymentMethod
Form *paymentMethodForm
}
func newPaymentMethodsPage(ctx context.Context, conn *Conn, company *Company, locale *Locale) *PaymentMethodsPage {
form := newPaymentMethodForm(locale)
return newPaymentMethodsPageWithForm(ctx, conn, company, form)
}
func newPaymentMethodsPageWithForm(ctx context.Context, conn *Conn, company *Company, form *paymentMethodForm) *PaymentMethodsPage {
return &PaymentMethodsPage{
PaymentMethods: mustCollectPaymentMethods(ctx, conn, company),
Form: form,
}
}
func (page *PaymentMethodsPage) MustRender(w http.ResponseWriter, r *http.Request) {
mustRenderMainTemplate(w, r, "company/payment_methods.gohtml", page)
}
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 paymentMethodForm struct { type paymentMethodForm struct {
@ -691,25 +788,6 @@ func (form *paymentMethodForm) Validate() bool {
return validator.AllOK() 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)
if IsHTMxRequest(r) {
w.WriteHeader(http.StatusOK)
} else {
http.Redirect(w, r, companyURI(mustGetCompany(r), "/tax-details"), http.StatusSeeOther)
}
}
func HandleAddPaymentMethod(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func HandleAddPaymentMethod(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
locale := getLocale(r) locale := getLocale(r)
conn := getConn(r) conn := getConn(r)
@ -727,15 +805,28 @@ func HandleAddPaymentMethod(w http.ResponseWriter, r *http.Request, _ httprouter
if !IsHTMxRequest(r) { if !IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity) w.WriteHeader(http.StatusUnprocessableEntity)
} }
mustRenderPaymentMethodForm(w, r, form) page := newPaymentMethodsPageWithForm(r.Context(), conn, company, form)
page.MustRender(w, r)
return return
} }
conn.MustExec(r.Context(), "insert into payment_method (company_id, name, instructions) values ($1, $2, $3)", company.Id, form.Name, form.Instructions) conn.MustExec(r.Context(), "insert into payment_method (company_id, name, instructions) values ($1, $2, $3)", company.Id, form.Name, form.Instructions)
if IsHTMxRequest(r) { htmxRedirect(w, r, companyURI(company, "/payment-methods"))
mustRenderPaymentMethodForm(w, r, newPaymentMethodForm(locale)) }
} else {
http.Redirect(w, r, companyURI(company, "/tax-details"), http.StatusSeeOther) 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)
company := mustGetCompany(r)
htmxRedirect(w, r, companyURI(company, "/payment-methods"))
} }
func GetCompanySwitcher(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func GetCompanySwitcher(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
@ -755,7 +846,7 @@ type UserCompany struct {
} }
func (page *CompanySwitchPage) MustRender(w http.ResponseWriter, r *http.Request) { func (page *CompanySwitchPage) MustRender(w http.ResponseWriter, r *http.Request) {
mustRenderModalTemplate(w, r, "switch-company.gohtml", page) mustRenderModalTemplate(w, r, "company/switch.gohtml", page)
} }
func mustCollectUserCompanies(ctx context.Context, conn *Conn) []*UserCompany { func mustCollectUserCompanies(ctx context.Context, conn *Conn) []*UserCompany {

View File

@ -11,12 +11,16 @@ func NewRouter(db *Db, demo bool) http.Handler {
companyRouter.GET("/profile", GetProfileForm) companyRouter.GET("/profile", GetProfileForm)
companyRouter.POST("/profile", HandleProfileForm) companyRouter.POST("/profile", HandleProfileForm)
companyRouter.GET("/tax-details", GetCompanyTaxDetailsForm) companyRouter.GET("/tax-details", GetCompanyTaxDetailsForm)
companyRouter.GET("/switch-company", GetCompanySwitcher)
companyRouter.POST("/tax-details", HandleCompanyTaxDetailsForm) companyRouter.POST("/tax-details", HandleCompanyTaxDetailsForm)
companyRouter.POST("/tax", HandleAddCompanyTax) companyRouter.GET("/invoicing", serveCompanyInvoicingForm)
companyRouter.DELETE("/tax/:taxId", HandleDeleteCompanyTax) companyRouter.POST("/invoicing", handleCompanyInvoicingForm)
companyRouter.POST("/payment-method", HandleAddPaymentMethod) companyRouter.GET("/switch-company", GetCompanySwitcher)
companyRouter.DELETE("/payment-method/:paymentMethodId", HandleDeletePaymentMethod) companyRouter.GET("/taxes", serveCompanyTaxes)
companyRouter.POST("/taxes", HandleAddCompanyTax)
companyRouter.DELETE("/taxes/:taxId", HandleDeleteCompanyTax)
companyRouter.GET("/payment-methods", servePaymentMethods)
companyRouter.POST("/payment-methods", HandleAddPaymentMethod)
companyRouter.DELETE("/payment-methods/:paymentMethodId", HandleDeletePaymentMethod)
companyRouter.GET("/contacts", IndexContacts) companyRouter.GET("/contacts", IndexContacts)
companyRouter.POST("/contacts", HandleAddContact) companyRouter.POST("/contacts", HandleAddContact)
companyRouter.POST("/contacts/import", HandleImportContacts) companyRouter.POST("/contacts/import", HandleImportContacts)

359
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: numerus\n" "Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-08-13 02:06+0200\n" "POT-Creation-Date: 2024-08-14 04:02+0200\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n" "PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n" "Language-Team: Catalan <ca@dodds.net>\n"
@ -26,17 +26,20 @@ msgstr "Afegeix productes a la factura"
#: web/template/invoices/products.gohtml:9 web/template/invoices/new.gohtml:9 #: web/template/invoices/products.gohtml:9 web/template/invoices/new.gohtml:9
#: web/template/invoices/index.gohtml:9 web/template/invoices/view.gohtml:9 #: web/template/invoices/index.gohtml:9 web/template/invoices/view.gohtml:9
#: web/template/invoices/edit.gohtml:9 web/template/home.gohtml:2 #: web/template/invoices/edit.gohtml:9 web/template/home.gohtml:2
#: web/template/switch-company.gohtml:9 web/template/quotes/products.gohtml:9 #: web/template/quotes/products.gohtml:9 web/template/quotes/new.gohtml:9
#: web/template/quotes/new.gohtml:9 web/template/quotes/index.gohtml:9 #: web/template/quotes/index.gohtml:9 web/template/quotes/view.gohtml:9
#: web/template/quotes/view.gohtml:9 web/template/quotes/edit.gohtml:9 #: web/template/quotes/edit.gohtml:9 web/template/contacts/new.gohtml:9
#: web/template/contacts/new.gohtml:9 web/template/contacts/index.gohtml:9 #: web/template/contacts/index.gohtml:9 web/template/contacts/edit.gohtml:10
#: web/template/contacts/edit.gohtml:10 web/template/contacts/import.gohtml:8 #: web/template/contacts/import.gohtml:8 web/template/profile.gohtml:9
#: web/template/profile.gohtml:9 web/template/expenses/new.gohtml:10 #: web/template/expenses/new.gohtml:10 web/template/expenses/index.gohtml:10
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10 #: web/template/expenses/edit.gohtml:10 web/template/company/taxes.gohtml:10
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9 #: web/template/company/switch.gohtml:9
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10 #: web/template/company/tax-details.gohtml:9
#: web/template/payments/new.gohtml:10 web/template/payments/index.gohtml:10 #: web/template/company/invoicing.gohtml:10
#: web/template/payments/edit.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:10
#: web/template/payments/accounts/new.gohtml:10 #: web/template/payments/accounts/new.gohtml:10
#: web/template/payments/accounts/index.gohtml:10 #: web/template/payments/accounts/index.gohtml:10
#: web/template/payments/accounts/edit.gohtml:10 #: web/template/payments/accounts/edit.gohtml:10
@ -64,7 +67,7 @@ msgid "All"
msgstr "Tots" msgstr "Tots"
#: web/template/invoices/products.gohtml:49 #: web/template/invoices/products.gohtml:49
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49 #: web/template/quotes/products.gohtml:49 web/template/company/switch.gohtml:22
#: web/template/products/index.gohtml:45 #: web/template/products/index.gohtml:45
#: web/template/payments/accounts/index.gohtml:25 #: web/template/payments/accounts/index.gohtml:25
msgctxt "title" msgctxt "title"
@ -214,9 +217,9 @@ msgctxt "title"
msgid "Download" msgid "Download"
msgstr "Descàrrega" msgstr "Descàrrega"
#: web/template/invoices/index.gohtml:74 web/template/switch-company.gohtml:23 #: web/template/invoices/index.gohtml:74 web/template/quotes/index.gohtml:74
#: web/template/quotes/index.gohtml:74 web/template/contacts/index.gohtml:51 #: web/template/contacts/index.gohtml:51 web/template/expenses/index.gohtml:76
#: web/template/expenses/index.gohtml:76 web/template/products/index.gohtml:48 #: web/template/company/switch.gohtml:23 web/template/products/index.gohtml:48
#: web/template/payments/index.gohtml:31 #: web/template/payments/index.gohtml:31
msgctxt "title" msgctxt "title"
msgid "Actions" msgid "Actions"
@ -342,17 +345,6 @@ msgctxt "action"
msgid "Filters" msgid "Filters"
msgstr "Filtra" msgstr "Filtra"
#: web/template/switch-company.gohtml:2 web/template/switch-company.gohtml:10
#: web/template/switch-company.gohtml:18
msgctxt "title"
msgid "Company Switch"
msgstr "Canvi dempresa"
#: web/template/switch-company.gohtml:30
msgctxt "action"
msgid "Switch"
msgstr "Canvia"
#: web/template/dashboard.gohtml:3 #: web/template/dashboard.gohtml:3
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
@ -468,52 +460,75 @@ msgctxt "menu"
msgid "Tax Details" msgid "Tax Details"
msgstr "Configuració fiscal" msgstr "Configuració fiscal"
#: web/template/app.gohtml:36 #: web/template/app.gohtml:36 web/template/company/invoicing.gohtml:3
msgctxt "title"
msgid "Invoicing and Quoting"
msgstr "Facturació i pressuposts"
#: web/template/app.gohtml:42 web/template/company/taxes.gohtml:3
msgctxt "title"
msgid "Taxes"
msgstr "Imposts"
#: web/template/app.gohtml:48 web/template/company/payment_methods.gohtml:3
msgctxt "title"
msgid "Payment Methods"
msgstr "Mètodes de pagament"
#: web/template/app.gohtml:54 web/template/payments/accounts/new.gohtml:11
#: web/template/payments/accounts/index.gohtml:3
#: web/template/payments/accounts/index.gohtml:11
#: web/template/payments/accounts/edit.gohtml:11
msgctxt "title"
msgid "Payment Accounts"
msgstr "Comptes de pagament"
#: web/template/app.gohtml:60
msgctxt "menu" msgctxt "menu"
msgid "Switch Company" msgid "Switch Company"
msgstr "Canvi dempresa" msgstr "Canvi dempresa"
#: web/template/app.gohtml:44 #: web/template/app.gohtml:68
msgctxt "action" msgctxt "action"
msgid "Logout" msgid "Logout"
msgstr "Surt" msgstr "Surt"
#: web/template/app.gohtml:53 #: web/template/app.gohtml:77
msgctxt "nav" msgctxt "nav"
msgid "Dashboard" msgid "Dashboard"
msgstr "Tauler" msgstr "Tauler"
#: web/template/app.gohtml:54 #: web/template/app.gohtml:78
msgctxt "nav" msgctxt "nav"
msgid "Quotations" msgid "Quotations"
msgstr "Pressuposts" msgstr "Pressuposts"
#: web/template/app.gohtml:55 #: web/template/app.gohtml:79
msgctxt "nav" msgctxt "nav"
msgid "Invoices" msgid "Invoices"
msgstr "Factures" msgstr "Factures"
#: web/template/app.gohtml:56 #: web/template/app.gohtml:80
msgctxt "nav" msgctxt "nav"
msgid "Expenses" msgid "Expenses"
msgstr "Despeses" msgstr "Despeses"
#: web/template/app.gohtml:57 #: web/template/app.gohtml:81
msgctxt "nav" msgctxt "nav"
msgid "Payments" msgid "Payments"
msgstr "Pagaments" msgstr "Pagaments"
#: web/template/app.gohtml:58 #: web/template/app.gohtml:82
msgctxt "nav" msgctxt "nav"
msgid "Products" msgid "Products"
msgstr "Productes" msgstr "Productes"
#: web/template/app.gohtml:59 #: web/template/app.gohtml:83
msgctxt "nav" msgctxt "nav"
msgid "Contacts" msgid "Contacts"
msgstr "Contactes" msgstr "Contactes"
#: web/template/app.gohtml:67 #: web/template/app.gohtml:91
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s" msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versió: %s" msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versió: %s"
@ -604,7 +619,8 @@ msgctxt "title"
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:175 #: web/template/profile.gohtml:39 web/template/company/tax-details.gohtml:36
#: web/template/company/invoicing.gohtml:31
msgctxt "action" msgctxt "action"
msgid "Save changes" msgid "Save changes"
msgstr "Desa canvis" msgstr "Desa canvis"
@ -649,70 +665,75 @@ msgctxt "title"
msgid "Edit Expense “%s”" msgid "Edit Expense “%s”"
msgstr "Edició de la despesa «%s»" msgstr "Edició de la despesa «%s»"
#: web/template/tax-details.gohtml:2 web/template/tax-details.gohtml:10 #: web/template/company/taxes.gohtml:23
#: web/template/tax-details.gohtml:18
msgctxt "title"
msgid "Tax Details"
msgstr "Configuració fiscal"
#: web/template/tax-details.gohtml:35
msgctxt "title"
msgid "Currency"
msgstr "Moneda"
#: web/template/tax-details.gohtml:41
msgctxt "title"
msgid "Invoicing and Quoting"
msgstr "Facturació i pressuposts"
#: web/template/tax-details.gohtml:56
msgid "Are you sure?"
msgstr "Nesteu segur?"
#: web/template/tax-details.gohtml:62
msgctxt "title" msgctxt "title"
msgid "Tax Name" msgid "Tax Name"
msgstr "Nom impost" msgstr "Nom impost"
#: web/template/tax-details.gohtml:63 #: web/template/company/taxes.gohtml:24
msgctxt "title" msgctxt "title"
msgid "Rate (%)" msgid "Rate (%)"
msgstr "Percentatge" msgstr "Percentatge"
#: web/template/tax-details.gohtml:64 #: web/template/company/taxes.gohtml:25
msgctxt "title" msgctxt "title"
msgid "Class" msgid "Class"
msgstr "Classe" msgstr "Classe"
#: web/template/tax-details.gohtml:88 #: web/template/company/taxes.gohtml:29
#: web/template/company/payment_methods.gohtml:28
msgid "Are you sure?"
msgstr "Nesteu segur?"
#: web/template/company/taxes.gohtml:49
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:94 web/template/tax-details.gohtml:155 #: web/template/company/taxes.gohtml:56
msgctxt "title" msgctxt "title"
msgid "New Line" msgid "New Tax"
msgstr "Nova línia" msgstr "Nou impost"
#: web/template/tax-details.gohtml:108 #: web/template/company/taxes.gohtml:66
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:124 #: web/template/company/switch.gohtml:2
msgctxt "title"
msgid "Company Switch"
msgstr "Canvi dempresa"
#: web/template/company/switch.gohtml:30
msgctxt "action"
msgid "Switch"
msgstr "Canvia"
#: web/template/company/tax-details.gohtml:2
msgctxt "title"
msgid "Tax Details"
msgstr "Configuració fiscal"
#: web/template/company/payment_methods.gohtml:23
msgctxt "title" msgctxt "title"
msgid "Payment Method" msgid "Payment Method"
msgstr "Mètode de pagament" msgstr "Mètode de pagament"
#: web/template/tax-details.gohtml:125 #: web/template/company/payment_methods.gohtml:24
msgctxt "title" msgctxt "title"
msgid "Instructions" msgid "Instructions"
msgstr "Instruccions" msgstr "Instruccions"
#: web/template/tax-details.gohtml:149 #: web/template/company/payment_methods.gohtml:48
msgid "No payment methods added yet." msgid "No payment methods added yet."
msgstr "No hi ha cap mètode de pagament." msgstr "No hi ha cap mètode de pagament."
#: web/template/tax-details.gohtml:167 #: web/template/company/payment_methods.gohtml:55
msgctxt "title"
msgid "New Payment Method"
msgstr "Nou mètode de pagament"
#: web/template/company/payment_methods.gohtml:64
msgctxt "action" msgctxt "action"
msgid "Add new payment method" msgid "Add new payment method"
msgstr "Afegeix nou mètode de pagament" msgstr "Afegeix nou mètode de pagament"
@ -801,14 +822,6 @@ msgctxt "title"
msgid "New Payment Account" msgid "New Payment Account"
msgstr "Nou compte de pagament" msgstr "Nou compte de pagament"
#: web/template/payments/accounts/new.gohtml:11
#: web/template/payments/accounts/index.gohtml:3
#: web/template/payments/accounts/index.gohtml:11
#: web/template/payments/accounts/edit.gohtml:11
msgctxt "title"
msgid "Payment Accounts"
msgstr "Comptes de pagament"
#: web/template/payments/accounts/index.gohtml:16 #: web/template/payments/accounts/index.gohtml:16
msgctxt "action" msgctxt "action"
msgid "New payment account" msgid "New payment account"
@ -843,7 +856,7 @@ msgctxt "title"
msgid "VAT number" msgid "VAT number"
msgstr "DNI / NIF" msgstr "DNI / NIF"
#: pkg/login.go:38 pkg/company.go:127 pkg/profile.go:40 pkg/contacts.go:276 #: pkg/login.go:38 pkg/company.go:122 pkg/profile.go:40 pkg/contacts.go:276
msgctxt "input" msgctxt "input"
msgid "Email" msgid "Email"
msgstr "Correu-e" msgstr "Correu-e"
@ -853,11 +866,11 @@ msgctxt "input"
msgid "Password" msgid "Password"
msgstr "Contrasenya" msgstr "Contrasenya"
#: pkg/login.go:76 pkg/company.go:283 pkg/profile.go:89 #: pkg/login.go:76 pkg/company.go:238 pkg/profile.go:89
msgid "Email can not be empty." msgid "Email can not be empty."
msgstr "No podeu deixar el correu-e en blanc." msgstr "No podeu deixar el correu-e en blanc."
#: pkg/login.go:77 pkg/company.go:284 pkg/profile.go:90 pkg/contacts.go:420 #: pkg/login.go:77 pkg/company.go:239 pkg/profile.go:90 pkg/contacts.go:420
msgid "This value is not a valid email. It should be like name@domain.com." msgid "This value is not a valid email. It should be like name@domain.com."
msgstr "Aquest valor no és un correu-e vàlid. Hauria de ser similar a nom@domini.cat." msgstr "Aquest valor no és un correu-e vàlid. Hauria de ser similar a nom@domini.cat."
@ -951,208 +964,208 @@ msgstr "Heu seleccionat un impost que no és vàlid."
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:113 #: pkg/company.go:108
msgctxt "input" msgctxt "input"
msgid "Trade name" msgid "Trade name"
msgstr "Nom comercial" msgstr "Nom comercial"
#: pkg/company.go:118 pkg/contacts.go:268 #: pkg/company.go:113 pkg/contacts.go:268
msgctxt "input" msgctxt "input"
msgid "Phone" msgid "Phone"
msgstr "Telèfon" msgstr "Telèfon"
#: pkg/company.go:136 pkg/contacts.go:284 #: pkg/company.go:131 pkg/contacts.go:284
msgctxt "input" msgctxt "input"
msgid "Web" msgid "Web"
msgstr "Web" msgstr "Web"
#: pkg/company.go:144 pkg/contacts.go:296 #: pkg/company.go:139 pkg/contacts.go:296
msgctxt "input" msgctxt "input"
msgid "Business name" msgid "Business name"
msgstr "Nom i cognoms" msgstr "Nom i cognoms"
#: pkg/company.go:154 pkg/contacts.go:306 #: pkg/company.go:149 pkg/contacts.go:306
msgctxt "input" msgctxt "input"
msgid "VAT number" msgid "VAT number"
msgstr "DNI / NIF" msgstr "DNI / NIF"
#: pkg/company.go:160 pkg/contacts.go:312 #: pkg/company.go:155 pkg/contacts.go:312
msgctxt "input" msgctxt "input"
msgid "Address" msgid "Address"
msgstr "Adreça" msgstr "Adreça"
#: pkg/company.go:169 pkg/contacts.go:321 #: pkg/company.go:164 pkg/contacts.go:321
msgctxt "input" msgctxt "input"
msgid "City" msgid "City"
msgstr "Població" msgstr "Població"
#: pkg/company.go:175 pkg/contacts.go:327 #: pkg/company.go:170 pkg/contacts.go:327
msgctxt "input" msgctxt "input"
msgid "Province" msgid "Province"
msgstr "Província" msgstr "Província"
#: pkg/company.go:181 pkg/contacts.go:333 #: pkg/company.go:176 pkg/contacts.go:333
msgctxt "input" msgctxt "input"
msgid "Postal code" msgid "Postal code"
msgstr "Codi postal" msgstr "Codi postal"
#: pkg/company.go:190 pkg/contacts.go:342 #: pkg/company.go:185 pkg/contacts.go:342
msgctxt "input" msgctxt "input"
msgid "Country" msgid "Country"
msgstr "País" msgstr "País"
#: pkg/company.go:200 #: pkg/company.go:195
msgctxt "input" msgctxt "input"
msgid "Currency" msgid "Currency"
msgstr "Moneda" msgstr "Moneda"
#: pkg/company.go:207 #: pkg/company.go:226 pkg/contacts.go:394
msgid "Selected country is not valid."
msgstr "Heu seleccionat un país que no és vàlid."
#: pkg/company.go:230 pkg/contacts.go:397
msgid "Business name can not be empty."
msgstr "No podeu deixar el nom i els cognoms en blanc."
#: pkg/company.go:231 pkg/contacts.go:398
msgid "Business name must have at least two letters."
msgstr "Nom i cognoms han de tenir com a mínim dues lletres."
#: pkg/company.go:232 pkg/contacts.go:400
msgid "VAT number can not be empty."
msgstr "No podeu deixar el DNI o NIF en blanc."
#: pkg/company.go:233 pkg/contacts.go:401
msgid "This value is not a valid VAT number."
msgstr "Aquest valor no és un DNI o NIF vàlid."
#: pkg/company.go:235
msgid "Phone can not be empty."
msgstr "No podeu deixar el telèfon en blanc."
#: pkg/company.go:236 pkg/contacts.go:417
msgid "This value is not a valid phone number."
msgstr "Aquest valor no és un telèfon vàlid."
#: pkg/company.go:242 pkg/contacts.go:423
msgid "This value is not a valid web address. It should be like https://domain.com/."
msgstr "Aquest valor no és una adreça web vàlida. Hauria de ser similar a https://domini.cat/."
#: pkg/company.go:244 pkg/contacts.go:403
msgid "Address can not be empty."
msgstr "No podeu deixar ladreça en blanc."
#: pkg/company.go:245 pkg/contacts.go:404
msgid "City can not be empty."
msgstr "No podeu deixar la població en blanc."
#: pkg/company.go:246 pkg/contacts.go:405
msgid "Province can not be empty."
msgstr "No podeu deixar la província en blanc."
#: pkg/company.go:247 pkg/contacts.go:407
msgid "Postal code can not be empty."
msgstr "No podeu deixar el codi postal en blanc."
#: pkg/company.go:248 pkg/contacts.go:408
msgid "This value is not a valid postal code."
msgstr "Aquest valor no és un codi postal vàlid."
#: pkg/company.go:250
msgid "Selected currency is not valid."
msgstr "Heu seleccionat una moneda que no és vàlida."
#: pkg/company.go:402
msgctxt "input" msgctxt "input"
msgid "Invoice number format" msgid "Invoice number format"
msgstr "Format del número de factura" msgstr "Format del número de factura"
#: pkg/company.go:213 #: pkg/company.go:408
msgctxt "input" msgctxt "input"
msgid "Next invoice number" msgid "Next invoice number"
msgstr "Següent número de factura" msgstr "Següent número de factura"
#: pkg/company.go:222 #: pkg/company.go:417
msgctxt "input" msgctxt "input"
msgid "Quotation number format" msgid "Quotation number format"
msgstr "Format del número de pressupost" msgstr "Format del número de pressupost"
#: pkg/company.go:228 #: pkg/company.go:423
msgctxt "input" msgctxt "input"
msgid "Next quotation number" msgid "Next quotation number"
msgstr "Següent número de pressupost" msgstr "Següent número de pressupost"
#: pkg/company.go:237 #: pkg/company.go:432
msgctxt "input" msgctxt "input"
msgid "Legal disclaimer" msgid "Legal disclaimer"
msgstr "Nota legal" msgstr "Nota legal"
#: pkg/company.go:271 pkg/contacts.go:394 #: pkg/company.go:489
msgid "Selected country is not valid."
msgstr "Heu seleccionat un país que no és vàlid."
#: pkg/company.go:275 pkg/contacts.go:397
msgid "Business name can not be empty."
msgstr "No podeu deixar el nom i els cognoms en blanc."
#: pkg/company.go:276 pkg/contacts.go:398
msgid "Business name must have at least two letters."
msgstr "Nom i cognoms han de tenir com a mínim dues lletres."
#: pkg/company.go:277 pkg/contacts.go:400
msgid "VAT number can not be empty."
msgstr "No podeu deixar el DNI o NIF en blanc."
#: pkg/company.go:278 pkg/contacts.go:401
msgid "This value is not a valid VAT number."
msgstr "Aquest valor no és un DNI o NIF vàlid."
#: pkg/company.go:280
msgid "Phone can not be empty."
msgstr "No podeu deixar el telèfon en blanc."
#: pkg/company.go:281 pkg/contacts.go:417
msgid "This value is not a valid phone number."
msgstr "Aquest valor no és un telèfon vàlid."
#: pkg/company.go:287 pkg/contacts.go:423
msgid "This value is not a valid web address. It should be like https://domain.com/."
msgstr "Aquest valor no és una adreça web vàlida. Hauria de ser similar a https://domini.cat/."
#: pkg/company.go:289 pkg/contacts.go:403
msgid "Address can not be empty."
msgstr "No podeu deixar ladreça en blanc."
#: pkg/company.go:290 pkg/contacts.go:404
msgid "City can not be empty."
msgstr "No podeu deixar la població en blanc."
#: pkg/company.go:291 pkg/contacts.go:405
msgid "Province can not be empty."
msgstr "No podeu deixar la província en blanc."
#: pkg/company.go:292 pkg/contacts.go:407
msgid "Postal code can not be empty."
msgstr "No podeu deixar el codi postal en blanc."
#: pkg/company.go:293 pkg/contacts.go:408
msgid "This value is not a valid postal code."
msgstr "Aquest valor no és un codi postal vàlid."
#: pkg/company.go:295
msgid "Selected currency is not valid."
msgstr "Heu seleccionat una moneda que no és vàlida."
#: pkg/company.go:296
msgid "Invoice number format can not be empty." msgid "Invoice number format can not be empty."
msgstr "No podeu deixar el format del número de factura en blanc." msgstr "No podeu deixar el format del número de factura en blanc."
#: pkg/company.go:297 #: pkg/company.go:490
msgid "Next invoice number must be a number greater than zero." msgid "Next invoice number must be a number greater than zero."
msgstr "El següent número de factura ha de ser un número major a zero." msgstr "El següent número de factura ha de ser un número major a zero."
#: pkg/company.go:298 #: pkg/company.go:491
msgid "Quotation number format can not be empty." msgid "Quotation number format can not be empty."
msgstr "No podeu deixar el format del número de pressupost en blanc." msgstr "No podeu deixar el format del número de pressupost en blanc."
#: pkg/company.go:299 #: pkg/company.go:492
msgid "Next quotation number must be a number greater than zero." msgid "Next quotation number must be a number greater than zero."
msgstr "El següent número de pressupost ha de ser un número major a zero." msgstr "El següent número de pressupost ha de ser un número major a zero."
#: pkg/company.go:563 #: pkg/company.go:614
msgctxt "input" msgctxt "input"
msgid "Tax name" msgid "Tax name"
msgstr "Nom impost" msgstr "Nom impost"
#: pkg/company.go:569 #: pkg/company.go:620
msgctxt "input" msgctxt "input"
msgid "Tax Class" msgid "Tax Class"
msgstr "Classe dimpost" msgstr "Classe dimpost"
#: pkg/company.go:572 #: pkg/company.go:623
msgid "Select a tax class" msgid "Select a tax class"
msgstr "Escolliu una classe dimpost" msgstr "Escolliu una classe dimpost"
#: pkg/company.go:576 #: pkg/company.go:627
msgctxt "input" msgctxt "input"
msgid "Rate (%)" msgid "Rate (%)"
msgstr "Percentatge" msgstr "Percentatge"
#: pkg/company.go:599 #: pkg/company.go:650
msgid "Tax name can not be empty." msgid "Tax name can not be empty."
msgstr "No podeu deixar el nom de limpost en blanc." msgstr "No podeu deixar el nom de limpost en blanc."
#: pkg/company.go:600 #: pkg/company.go:651
msgid "Selected tax class is not valid." msgid "Selected tax class is not valid."
msgstr "Heu seleccionat una classe dimpost que no és vàlida." msgstr "Heu seleccionat una classe dimpost que no és vàlida."
#: pkg/company.go:601 #: pkg/company.go:652
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:602 #: pkg/company.go:653
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:665 #: pkg/company.go:762
msgctxt "input" msgctxt "input"
msgid "Payment method name" msgid "Payment method name"
msgstr "Nom del mètode de pagament" msgstr "Nom del mètode de pagament"
#: pkg/company.go:671 #: pkg/company.go:768
msgctxt "input" msgctxt "input"
msgid "Instructions" msgid "Instructions"
msgstr "Instruccions" msgstr "Instruccions"
#: pkg/company.go:689 #: pkg/company.go:786
msgid "Payment method name can not be empty." msgid "Payment method name can not be empty."
msgstr "No podeu deixar el nom del mètode de pagament en blanc." msgstr "No podeu deixar el nom del mètode de pagament en blanc."
#: pkg/company.go:690 #: pkg/company.go:787
msgid "Payment instructions can not be empty." msgid "Payment instructions can not be empty."
msgstr "No podeu deixar les instruccions de pagament en blanc." msgstr "No podeu deixar les instruccions de pagament en blanc."
@ -1567,6 +1580,14 @@ msgctxt "input"
msgid "Holded Excel file" msgid "Holded Excel file"
msgstr "Fitxer Excel del Holded" msgstr "Fitxer Excel del Holded"
#~ msgctxt "title"
#~ msgid "Currency"
#~ msgstr "Moneda"
#~ msgctxt "title"
#~ msgid "New Line"
#~ msgstr "Nova línia"
#~ msgid "Selected expense status is not valid." #~ msgid "Selected expense status is not valid."
#~ msgstr "Heu seleccionat un estat de despesa que no és vàlid." #~ msgstr "Heu seleccionat un estat de despesa que no és vàlid."

359
po/es.po
View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: numerus\n" "Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-08-13 02:06+0200\n" "POT-Creation-Date: 2024-08-14 04:02+0200\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n" "PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n" "Language-Team: Spanish <es@tp.org.es>\n"
@ -26,17 +26,20 @@ msgstr "Añadir productos a la factura"
#: web/template/invoices/products.gohtml:9 web/template/invoices/new.gohtml:9 #: web/template/invoices/products.gohtml:9 web/template/invoices/new.gohtml:9
#: web/template/invoices/index.gohtml:9 web/template/invoices/view.gohtml:9 #: web/template/invoices/index.gohtml:9 web/template/invoices/view.gohtml:9
#: web/template/invoices/edit.gohtml:9 web/template/home.gohtml:2 #: web/template/invoices/edit.gohtml:9 web/template/home.gohtml:2
#: web/template/switch-company.gohtml:9 web/template/quotes/products.gohtml:9 #: web/template/quotes/products.gohtml:9 web/template/quotes/new.gohtml:9
#: web/template/quotes/new.gohtml:9 web/template/quotes/index.gohtml:9 #: web/template/quotes/index.gohtml:9 web/template/quotes/view.gohtml:9
#: web/template/quotes/view.gohtml:9 web/template/quotes/edit.gohtml:9 #: web/template/quotes/edit.gohtml:9 web/template/contacts/new.gohtml:9
#: web/template/contacts/new.gohtml:9 web/template/contacts/index.gohtml:9 #: web/template/contacts/index.gohtml:9 web/template/contacts/edit.gohtml:10
#: web/template/contacts/edit.gohtml:10 web/template/contacts/import.gohtml:8 #: web/template/contacts/import.gohtml:8 web/template/profile.gohtml:9
#: web/template/profile.gohtml:9 web/template/expenses/new.gohtml:10 #: web/template/expenses/new.gohtml:10 web/template/expenses/index.gohtml:10
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10 #: web/template/expenses/edit.gohtml:10 web/template/company/taxes.gohtml:10
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9 #: web/template/company/switch.gohtml:9
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10 #: web/template/company/tax-details.gohtml:9
#: web/template/payments/new.gohtml:10 web/template/payments/index.gohtml:10 #: web/template/company/invoicing.gohtml:10
#: web/template/payments/edit.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:10
#: web/template/payments/accounts/new.gohtml:10 #: web/template/payments/accounts/new.gohtml:10
#: web/template/payments/accounts/index.gohtml:10 #: web/template/payments/accounts/index.gohtml:10
#: web/template/payments/accounts/edit.gohtml:10 #: web/template/payments/accounts/edit.gohtml:10
@ -64,7 +67,7 @@ msgid "All"
msgstr "Todos" msgstr "Todos"
#: web/template/invoices/products.gohtml:49 #: web/template/invoices/products.gohtml:49
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49 #: web/template/quotes/products.gohtml:49 web/template/company/switch.gohtml:22
#: web/template/products/index.gohtml:45 #: web/template/products/index.gohtml:45
#: web/template/payments/accounts/index.gohtml:25 #: web/template/payments/accounts/index.gohtml:25
msgctxt "title" msgctxt "title"
@ -214,9 +217,9 @@ msgctxt "title"
msgid "Download" msgid "Download"
msgstr "Descargar" msgstr "Descargar"
#: web/template/invoices/index.gohtml:74 web/template/switch-company.gohtml:23 #: web/template/invoices/index.gohtml:74 web/template/quotes/index.gohtml:74
#: web/template/quotes/index.gohtml:74 web/template/contacts/index.gohtml:51 #: web/template/contacts/index.gohtml:51 web/template/expenses/index.gohtml:76
#: web/template/expenses/index.gohtml:76 web/template/products/index.gohtml:48 #: web/template/company/switch.gohtml:23 web/template/products/index.gohtml:48
#: web/template/payments/index.gohtml:31 #: web/template/payments/index.gohtml:31
msgctxt "title" msgctxt "title"
msgid "Actions" msgid "Actions"
@ -342,17 +345,6 @@ msgctxt "action"
msgid "Filters" msgid "Filters"
msgstr "Filtrar" msgstr "Filtrar"
#: web/template/switch-company.gohtml:2 web/template/switch-company.gohtml:10
#: web/template/switch-company.gohtml:18
msgctxt "title"
msgid "Company Switch"
msgstr "Cambio de empresa"
#: web/template/switch-company.gohtml:30
msgctxt "action"
msgid "Switch"
msgstr "Cambiar"
#: web/template/dashboard.gohtml:3 #: web/template/dashboard.gohtml:3
msgctxt "title" msgctxt "title"
msgid "Dashboard" msgid "Dashboard"
@ -468,52 +460,75 @@ msgctxt "menu"
msgid "Tax Details" msgid "Tax Details"
msgstr "Configuración fiscal" msgstr "Configuración fiscal"
#: web/template/app.gohtml:36 #: web/template/app.gohtml:36 web/template/company/invoicing.gohtml:3
msgctxt "title"
msgid "Invoicing and Quoting"
msgstr "Facturación y presupuestos"
#: web/template/app.gohtml:42 web/template/company/taxes.gohtml:3
msgctxt "title"
msgid "Taxes"
msgstr "Impuestos"
#: web/template/app.gohtml:48 web/template/company/payment_methods.gohtml:3
msgctxt "title"
msgid "Payment Methods"
msgstr "Métodos de pago"
#: web/template/app.gohtml:54 web/template/payments/accounts/new.gohtml:11
#: web/template/payments/accounts/index.gohtml:3
#: web/template/payments/accounts/index.gohtml:11
#: web/template/payments/accounts/edit.gohtml:11
msgctxt "title"
msgid "Payment Accounts"
msgstr "Cuenta de pago"
#: web/template/app.gohtml:60
msgctxt "menu" msgctxt "menu"
msgid "Switch Company" msgid "Switch Company"
msgstr "Cambio de empresa" msgstr "Cambio de empresa"
#: web/template/app.gohtml:44 #: web/template/app.gohtml:68
msgctxt "action" msgctxt "action"
msgid "Logout" msgid "Logout"
msgstr "Salir" msgstr "Salir"
#: web/template/app.gohtml:53 #: web/template/app.gohtml:77
msgctxt "nav" msgctxt "nav"
msgid "Dashboard" msgid "Dashboard"
msgstr "Panel" msgstr "Panel"
#: web/template/app.gohtml:54 #: web/template/app.gohtml:78
msgctxt "nav" msgctxt "nav"
msgid "Quotations" msgid "Quotations"
msgstr "Presupuestos" msgstr "Presupuestos"
#: web/template/app.gohtml:55 #: web/template/app.gohtml:79
msgctxt "nav" msgctxt "nav"
msgid "Invoices" msgid "Invoices"
msgstr "Facturas" msgstr "Facturas"
#: web/template/app.gohtml:56 #: web/template/app.gohtml:80
msgctxt "nav" msgctxt "nav"
msgid "Expenses" msgid "Expenses"
msgstr "Gastos" msgstr "Gastos"
#: web/template/app.gohtml:57 #: web/template/app.gohtml:81
msgctxt "nav" msgctxt "nav"
msgid "Payments" msgid "Payments"
msgstr "Pagos" msgstr "Pagos"
#: web/template/app.gohtml:58 #: web/template/app.gohtml:82
msgctxt "nav" msgctxt "nav"
msgid "Products" msgid "Products"
msgstr "Productos" msgstr "Productos"
#: web/template/app.gohtml:59 #: web/template/app.gohtml:83
msgctxt "nav" msgctxt "nav"
msgid "Contacts" msgid "Contacts"
msgstr "Contactos" msgstr "Contactos"
#: web/template/app.gohtml:67 #: web/template/app.gohtml:91
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s" msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versión: %s" msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versión: %s"
@ -604,7 +619,8 @@ msgctxt "title"
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
#: web/template/profile.gohtml:39 web/template/tax-details.gohtml:175 #: web/template/profile.gohtml:39 web/template/company/tax-details.gohtml:36
#: web/template/company/invoicing.gohtml:31
msgctxt "action" msgctxt "action"
msgid "Save changes" msgid "Save changes"
msgstr "Guardar cambios" msgstr "Guardar cambios"
@ -649,70 +665,75 @@ msgctxt "title"
msgid "Edit Expense “%s”" msgid "Edit Expense “%s”"
msgstr "Edición del gasto «%s»" msgstr "Edición del gasto «%s»"
#: web/template/tax-details.gohtml:2 web/template/tax-details.gohtml:10 #: web/template/company/taxes.gohtml:23
#: web/template/tax-details.gohtml:18
msgctxt "title"
msgid "Tax Details"
msgstr "Configuración fiscal"
#: web/template/tax-details.gohtml:35
msgctxt "title"
msgid "Currency"
msgstr "Moneda"
#: web/template/tax-details.gohtml:41
msgctxt "title"
msgid "Invoicing and Quoting"
msgstr "Facturación y presupuestos"
#: web/template/tax-details.gohtml:56
msgid "Are you sure?"
msgstr "¿Estáis seguro?"
#: web/template/tax-details.gohtml:62
msgctxt "title" msgctxt "title"
msgid "Tax Name" msgid "Tax Name"
msgstr "Nombre impuesto" msgstr "Nombre impuesto"
#: web/template/tax-details.gohtml:63 #: web/template/company/taxes.gohtml:24
msgctxt "title" msgctxt "title"
msgid "Rate (%)" msgid "Rate (%)"
msgstr "Porcentaje" msgstr "Porcentaje"
#: web/template/tax-details.gohtml:64 #: web/template/company/taxes.gohtml:25
msgctxt "title" msgctxt "title"
msgid "Class" msgid "Class"
msgstr "Clase" msgstr "Clase"
#: web/template/tax-details.gohtml:88 #: web/template/company/taxes.gohtml:29
#: web/template/company/payment_methods.gohtml:28
msgid "Are you sure?"
msgstr "¿Estáis seguro?"
#: web/template/company/taxes.gohtml:49
msgid "No taxes added yet." msgid "No taxes added yet."
msgstr "No hay impuestos." msgstr "No hay impuestos."
#: web/template/tax-details.gohtml:94 web/template/tax-details.gohtml:155 #: web/template/company/taxes.gohtml:56
msgctxt "title" msgctxt "title"
msgid "New Line" msgid "New Tax"
msgstr "Nueva línea" msgstr "Nuevo impuesto"
#: web/template/tax-details.gohtml:108 #: web/template/company/taxes.gohtml:66
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:124 #: web/template/company/switch.gohtml:2
msgctxt "title"
msgid "Company Switch"
msgstr "Cambio de empresa"
#: web/template/company/switch.gohtml:30
msgctxt "action"
msgid "Switch"
msgstr "Cambiar"
#: web/template/company/tax-details.gohtml:2
msgctxt "title"
msgid "Tax Details"
msgstr "Configuración fiscal"
#: web/template/company/payment_methods.gohtml:23
msgctxt "title" msgctxt "title"
msgid "Payment Method" msgid "Payment Method"
msgstr "Método de pago" msgstr "Método de pago"
#: web/template/tax-details.gohtml:125 #: web/template/company/payment_methods.gohtml:24
msgctxt "title" msgctxt "title"
msgid "Instructions" msgid "Instructions"
msgstr "Instrucciones" msgstr "Instrucciones"
#: web/template/tax-details.gohtml:149 #: web/template/company/payment_methods.gohtml:48
msgid "No payment methods added yet." msgid "No payment methods added yet."
msgstr "No hay métodos de pago." msgstr "No hay métodos de pago."
#: web/template/tax-details.gohtml:167 #: web/template/company/payment_methods.gohtml:55
msgctxt "title"
msgid "New Payment Method"
msgstr "Nuevo método de pago"
#: web/template/company/payment_methods.gohtml:64
msgctxt "action" msgctxt "action"
msgid "Add new payment method" msgid "Add new payment method"
msgstr "Añadir nuevo método de pago" msgstr "Añadir nuevo método de pago"
@ -801,14 +822,6 @@ msgctxt "title"
msgid "New Payment Account" msgid "New Payment Account"
msgstr "Nueva cuenta de pago" msgstr "Nueva cuenta de pago"
#: web/template/payments/accounts/new.gohtml:11
#: web/template/payments/accounts/index.gohtml:3
#: web/template/payments/accounts/index.gohtml:11
#: web/template/payments/accounts/edit.gohtml:11
msgctxt "title"
msgid "Payment Accounts"
msgstr "Cuenta de pago"
#: web/template/payments/accounts/index.gohtml:16 #: web/template/payments/accounts/index.gohtml:16
msgctxt "action" msgctxt "action"
msgid "New payment account" msgid "New payment account"
@ -843,7 +856,7 @@ msgctxt "title"
msgid "VAT number" msgid "VAT number"
msgstr "DNI / NIF" msgstr "DNI / NIF"
#: pkg/login.go:38 pkg/company.go:127 pkg/profile.go:40 pkg/contacts.go:276 #: pkg/login.go:38 pkg/company.go:122 pkg/profile.go:40 pkg/contacts.go:276
msgctxt "input" msgctxt "input"
msgid "Email" msgid "Email"
msgstr "Correo-e" msgstr "Correo-e"
@ -853,11 +866,11 @@ msgctxt "input"
msgid "Password" msgid "Password"
msgstr "Contraseña" msgstr "Contraseña"
#: pkg/login.go:76 pkg/company.go:283 pkg/profile.go:89 #: pkg/login.go:76 pkg/company.go:238 pkg/profile.go:89
msgid "Email can not be empty." msgid "Email can not be empty."
msgstr "No podéis dejar el correo-e en blanco." msgstr "No podéis dejar el correo-e en blanco."
#: pkg/login.go:77 pkg/company.go:284 pkg/profile.go:90 pkg/contacts.go:420 #: pkg/login.go:77 pkg/company.go:239 pkg/profile.go:90 pkg/contacts.go:420
msgid "This value is not a valid email. It should be like name@domain.com." msgid "This value is not a valid email. It should be like name@domain.com."
msgstr "Este valor no es un correo-e válido. Tiene que ser parecido a nombre@dominio.es." msgstr "Este valor no es un correo-e válido. Tiene que ser parecido a nombre@dominio.es."
@ -951,208 +964,208 @@ msgstr "Habéis escogido un impuesto que no es válido."
msgid "You can only select a tax of each class." msgid "You can only select a tax of each class."
msgstr "Solo podéis escoger un impuesto de cada clase." msgstr "Solo podéis escoger un impuesto de cada clase."
#: pkg/company.go:113 #: pkg/company.go:108
msgctxt "input" msgctxt "input"
msgid "Trade name" msgid "Trade name"
msgstr "Nombre comercial" msgstr "Nombre comercial"
#: pkg/company.go:118 pkg/contacts.go:268 #: pkg/company.go:113 pkg/contacts.go:268
msgctxt "input" msgctxt "input"
msgid "Phone" msgid "Phone"
msgstr "Teléfono" msgstr "Teléfono"
#: pkg/company.go:136 pkg/contacts.go:284 #: pkg/company.go:131 pkg/contacts.go:284
msgctxt "input" msgctxt "input"
msgid "Web" msgid "Web"
msgstr "Web" msgstr "Web"
#: pkg/company.go:144 pkg/contacts.go:296 #: pkg/company.go:139 pkg/contacts.go:296
msgctxt "input" msgctxt "input"
msgid "Business name" msgid "Business name"
msgstr "Nombre y apellidos" msgstr "Nombre y apellidos"
#: pkg/company.go:154 pkg/contacts.go:306 #: pkg/company.go:149 pkg/contacts.go:306
msgctxt "input" msgctxt "input"
msgid "VAT number" msgid "VAT number"
msgstr "DNI / NIF" msgstr "DNI / NIF"
#: pkg/company.go:160 pkg/contacts.go:312 #: pkg/company.go:155 pkg/contacts.go:312
msgctxt "input" msgctxt "input"
msgid "Address" msgid "Address"
msgstr "Dirección" msgstr "Dirección"
#: pkg/company.go:169 pkg/contacts.go:321 #: pkg/company.go:164 pkg/contacts.go:321
msgctxt "input" msgctxt "input"
msgid "City" msgid "City"
msgstr "Población" msgstr "Población"
#: pkg/company.go:175 pkg/contacts.go:327 #: pkg/company.go:170 pkg/contacts.go:327
msgctxt "input" msgctxt "input"
msgid "Province" msgid "Province"
msgstr "Provincia" msgstr "Provincia"
#: pkg/company.go:181 pkg/contacts.go:333 #: pkg/company.go:176 pkg/contacts.go:333
msgctxt "input" msgctxt "input"
msgid "Postal code" msgid "Postal code"
msgstr "Código postal" msgstr "Código postal"
#: pkg/company.go:190 pkg/contacts.go:342 #: pkg/company.go:185 pkg/contacts.go:342
msgctxt "input" msgctxt "input"
msgid "Country" msgid "Country"
msgstr "País" msgstr "País"
#: pkg/company.go:200 #: pkg/company.go:195
msgctxt "input" msgctxt "input"
msgid "Currency" msgid "Currency"
msgstr "Moneda" msgstr "Moneda"
#: pkg/company.go:207 #: pkg/company.go:226 pkg/contacts.go:394
msgid "Selected country is not valid."
msgstr "Habéis escogido un país que no es válido."
#: pkg/company.go:230 pkg/contacts.go:397
msgid "Business name can not be empty."
msgstr "No podéis dejar el nombre y los apellidos en blanco."
#: pkg/company.go:231 pkg/contacts.go:398
msgid "Business name must have at least two letters."
msgstr "El nombre y los apellidos deben contener como mínimo dos letras."
#: pkg/company.go:232 pkg/contacts.go:400
msgid "VAT number can not be empty."
msgstr "No podéis dejar el DNI o NIF en blanco."
#: pkg/company.go:233 pkg/contacts.go:401
msgid "This value is not a valid VAT number."
msgstr "Este valor no es un DNI o NIF válido."
#: pkg/company.go:235
msgid "Phone can not be empty."
msgstr "No podéis dejar el teléfono en blanco."
#: pkg/company.go:236 pkg/contacts.go:417
msgid "This value is not a valid phone number."
msgstr "Este valor no es un teléfono válido."
#: pkg/company.go:242 pkg/contacts.go:423
msgid "This value is not a valid web address. It should be like https://domain.com/."
msgstr "Este valor no es una dirección web válida. Tiene que ser parecida a https://dominio.es/."
#: pkg/company.go:244 pkg/contacts.go:403
msgid "Address can not be empty."
msgstr "No podéis dejar la dirección en blanco."
#: pkg/company.go:245 pkg/contacts.go:404
msgid "City can not be empty."
msgstr "No podéis dejar la población en blanco."
#: pkg/company.go:246 pkg/contacts.go:405
msgid "Province can not be empty."
msgstr "No podéis dejar la provincia en blanco."
#: pkg/company.go:247 pkg/contacts.go:407
msgid "Postal code can not be empty."
msgstr "No podéis dejar el código postal en blanco."
#: pkg/company.go:248 pkg/contacts.go:408
msgid "This value is not a valid postal code."
msgstr "Este valor no es un código postal válido válido."
#: pkg/company.go:250
msgid "Selected currency is not valid."
msgstr "Habéis escogido una moneda que no es válida."
#: pkg/company.go:402
msgctxt "input" msgctxt "input"
msgid "Invoice number format" msgid "Invoice number format"
msgstr "Formato del número de factura" msgstr "Formato del número de factura"
#: pkg/company.go:213 #: pkg/company.go:408
msgctxt "input" msgctxt "input"
msgid "Next invoice number" msgid "Next invoice number"
msgstr "Siguiente número de factura" msgstr "Siguiente número de factura"
#: pkg/company.go:222 #: pkg/company.go:417
msgctxt "input" msgctxt "input"
msgid "Quotation number format" msgid "Quotation number format"
msgstr "Formato del número de presupuesto" msgstr "Formato del número de presupuesto"
#: pkg/company.go:228 #: pkg/company.go:423
msgctxt "input" msgctxt "input"
msgid "Next quotation number" msgid "Next quotation number"
msgstr "Siguiente número de presupuesto" msgstr "Siguiente número de presupuesto"
#: pkg/company.go:237 #: pkg/company.go:432
msgctxt "input" msgctxt "input"
msgid "Legal disclaimer" msgid "Legal disclaimer"
msgstr "Nota legal" msgstr "Nota legal"
#: pkg/company.go:271 pkg/contacts.go:394 #: pkg/company.go:489
msgid "Selected country is not valid."
msgstr "Habéis escogido un país que no es válido."
#: pkg/company.go:275 pkg/contacts.go:397
msgid "Business name can not be empty."
msgstr "No podéis dejar el nombre y los apellidos en blanco."
#: pkg/company.go:276 pkg/contacts.go:398
msgid "Business name must have at least two letters."
msgstr "El nombre y los apellidos deben contener como mínimo dos letras."
#: pkg/company.go:277 pkg/contacts.go:400
msgid "VAT number can not be empty."
msgstr "No podéis dejar el DNI o NIF en blanco."
#: pkg/company.go:278 pkg/contacts.go:401
msgid "This value is not a valid VAT number."
msgstr "Este valor no es un DNI o NIF válido."
#: pkg/company.go:280
msgid "Phone can not be empty."
msgstr "No podéis dejar el teléfono en blanco."
#: pkg/company.go:281 pkg/contacts.go:417
msgid "This value is not a valid phone number."
msgstr "Este valor no es un teléfono válido."
#: pkg/company.go:287 pkg/contacts.go:423
msgid "This value is not a valid web address. It should be like https://domain.com/."
msgstr "Este valor no es una dirección web válida. Tiene que ser parecida a https://dominio.es/."
#: pkg/company.go:289 pkg/contacts.go:403
msgid "Address can not be empty."
msgstr "No podéis dejar la dirección en blanco."
#: pkg/company.go:290 pkg/contacts.go:404
msgid "City can not be empty."
msgstr "No podéis dejar la población en blanco."
#: pkg/company.go:291 pkg/contacts.go:405
msgid "Province can not be empty."
msgstr "No podéis dejar la provincia en blanco."
#: pkg/company.go:292 pkg/contacts.go:407
msgid "Postal code can not be empty."
msgstr "No podéis dejar el código postal en blanco."
#: pkg/company.go:293 pkg/contacts.go:408
msgid "This value is not a valid postal code."
msgstr "Este valor no es un código postal válido válido."
#: pkg/company.go:295
msgid "Selected currency is not valid."
msgstr "Habéis escogido una moneda que no es válida."
#: pkg/company.go:296
msgid "Invoice number format can not be empty." msgid "Invoice number format can not be empty."
msgstr "No podéis dejar el formato del número de factura en blanco." msgstr "No podéis dejar el formato del número de factura en blanco."
#: pkg/company.go:297 #: pkg/company.go:490
msgid "Next invoice number must be a number greater than zero." msgid "Next invoice number must be a number greater than zero."
msgstr "El siguiente número de factura tiene que ser un número mayor a cero." msgstr "El siguiente número de factura tiene que ser un número mayor a cero."
#: pkg/company.go:298 #: pkg/company.go:491
msgid "Quotation number format can not be empty." msgid "Quotation number format can not be empty."
msgstr "No podéis dejar el formato del número de presupuesto en blanco." msgstr "No podéis dejar el formato del número de presupuesto en blanco."
#: pkg/company.go:299 #: pkg/company.go:492
msgid "Next quotation number must be a number greater than zero." msgid "Next quotation number must be a number greater than zero."
msgstr "El siguiente número de presupuesto tiene que ser un número mayor a cero." msgstr "El siguiente número de presupuesto tiene que ser un número mayor a cero."
#: pkg/company.go:563 #: pkg/company.go:614
msgctxt "input" msgctxt "input"
msgid "Tax name" msgid "Tax name"
msgstr "Nombre impuesto" msgstr "Nombre impuesto"
#: pkg/company.go:569 #: pkg/company.go:620
msgctxt "input" msgctxt "input"
msgid "Tax Class" msgid "Tax Class"
msgstr "Clase de impuesto" msgstr "Clase de impuesto"
#: pkg/company.go:572 #: pkg/company.go:623
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:576 #: pkg/company.go:627
msgctxt "input" msgctxt "input"
msgid "Rate (%)" msgid "Rate (%)"
msgstr "Porcentaje" msgstr "Porcentaje"
#: pkg/company.go:599 #: pkg/company.go:650
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:600 #: pkg/company.go:651
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:601 #: pkg/company.go:652
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:602 #: pkg/company.go:653
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:665 #: pkg/company.go:762
msgctxt "input" msgctxt "input"
msgid "Payment method name" msgid "Payment method name"
msgstr "Nombre del método de pago" msgstr "Nombre del método de pago"
#: pkg/company.go:671 #: pkg/company.go:768
msgctxt "input" msgctxt "input"
msgid "Instructions" msgid "Instructions"
msgstr "Instrucciones" msgstr "Instrucciones"
#: pkg/company.go:689 #: pkg/company.go:786
msgid "Payment method name can not be empty." msgid "Payment method name can not be empty."
msgstr "No podéis dejar el nombre del método de pago en blanco." msgstr "No podéis dejar el nombre del método de pago en blanco."
#: pkg/company.go:690 #: pkg/company.go:787
msgid "Payment instructions can not be empty." msgid "Payment instructions can not be empty."
msgstr "No podéis dejar las instrucciones de pago en blanco." msgstr "No podéis dejar las instrucciones de pago en blanco."
@ -1567,6 +1580,14 @@ msgctxt "input"
msgid "Holded Excel file" msgid "Holded Excel file"
msgstr "Archivo Excel de Holded" msgstr "Archivo Excel de Holded"
#~ msgctxt "title"
#~ msgid "Currency"
#~ msgstr "Moneda"
#~ msgctxt "title"
#~ msgid "New Line"
#~ msgstr "Nueva línea"
#~ msgid "Selected expense status is not valid." #~ msgid "Selected expense status is not valid."
#~ msgstr "Habéis escogido un estado de gasto que no es válido." #~ msgstr "Habéis escogido un estado de gasto que no es válido."

View File

@ -25,11 +25,35 @@
</a> </a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a role="menuitem" href="{{ companyURI "/tax-details" }}" data-hx-boost="true"> <a role="menuitem" href="{{ companyURI "/tax-details" }}">
<i class="ri-vip-diamond-line"></i> <i class="ri-vip-diamond-line"></i>
{{( pgettext "Tax Details" "menu" )}} {{( pgettext "Tax Details" "menu" )}}
</a> </a>
</li> </li>
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/invoicing"}}">
<i class="ri-file-paper-2-line"></i>
{{( pgettext "Invoicing and Quoting" "title" )}}
</a>
</li>
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/taxes"}}">
<i class="ri-government-line"></i>
{{( pgettext "Taxes" "title" )}}
</a>
</li>
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/payment-methods"}}">
<i class="ri-money-euro-circle-line"></i>
{{( pgettext "Payment Methods" "title" )}}
</a>
</li>
<li role="presentation">
<a role="menuitem" href="{{ companyURI "/payment-accounts"}}">
<i class="ri-bank-card-2-line"></i>
{{( pgettext "Payment Accounts" "title" )}}
</a>
</li>
<li role="presentation"> <li role="presentation">
<a role="menuitem" href="{{ companyURI "/switch-company" }}" data-hx-boost="true"> <a role="menuitem" href="{{ companyURI "/switch-company" }}" data-hx-boost="true">
<i class="ri-briefcase-line"></i> <i class="ri-briefcase-line"></i>

View File

@ -0,0 +1,35 @@
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicingForm*/ -}}
{{( pgettext "Invoicing and Quoting" "title" )}}
{{- end }}
{{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicingForm*/ -}}
<nav data-hx-target="main" data-hx-boost="true">
<p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{ template "title" . }}</a>
</p>
</nav>
{{- end }}
{{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicingForm*/ -}}
<section data-hx-target="main" data-hx-swap="innerHTML show:false">
<h2>{{ template "title" . }}</h2>
<form method="POST" action="{{ companyURI "/invoicing" }}" data-hx-boost="true">
<fieldset id="invoicing">
{{ csrfToken }}
{{ template "input-field" .InvoiceNumberFormat }}
{{ template "input-field" .NextInvoiceNumber }}
{{ template "input-field" .QuoteNumberFormat }}
{{ template "input-field" .NextQuoteNumber }}
{{ template "input-field" .LegalDisclaimer }}
</fieldset>
<footer>
<button form="details" type="submit">{{( pgettext "Save changes" "action" )}}</button>
</footer>
</form>
</section>
{{- end }}

View File

@ -0,0 +1,68 @@
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.PaymentMethodsPage*/ -}}
{{( pgettext "Payment Methods" "title" )}}
{{- end }}
{{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.PaymentMethodsPage*/ -}}
<nav data-hx-target="main" data-hx-boost="true">
<p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{ template "title" . }}</a>
</p>
</nav>
{{- end }}
{{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.PaymentMethodsPage*/ -}}
<section data-hx-target="main" data-hx-swap="innerHTML show:false">
<h2>{{ template "title" . }}</h2>
<table>
<thead>
<tr>
<th>{{( pgettext "Payment Method" "title" )}}</th>
<th>{{( pgettext "Instructions" "title" )}}</th>
<th></th>
</tr>
</thead>
{{ $confirm := ( gettext "Are you sure?" )}}
<tbody data-hx-confirm="{{ $confirm }}" data-hx-target="closest tr" data-hx-swap="outerHTML swap:1s">
{{ with .PaymentMethods }}
{{- range $method := . }}
<tr>
<td>{{ .Name }}</td>
<td>{{ .Instructions }}</td>
<td>
<form method="POST" action="{{ companyURI "/payment-methods"}}/{{ .Id }}"
data-hx-boost="true">
{{ csrfToken }}
{{ deleteMethod }}
<button class="icon" aria-label="{{( gettext "Delete payment method" )}}"
><i class="ri-delete-back-2-line"></i></button>
</form>
</td>
</tr>
{{- end }}
{{ else }}
<tr>
<td colspan="3">{{( gettext "No payment methods added yet." )}}</td>
</tr>
{{ end }}
</tbody>
</table>
<form method="POST" action="{{ companyURI "/payment-methods" }}" data-hx-boost="true">
<h3>{{( pgettext "New Payment Method" "title")}}</h3>
<fieldset>
{{ csrfToken }}
{{ with .Form -}}
{{ template "input-field" .Name }}
{{ template "input-field" .Instructions }}
{{- end }}
</fieldset>
<footer>
<button>{{( pgettext "Add new payment method" "action" )}}</button>
</footer>
</form>
</section>
{{- end }}

View File

@ -7,7 +7,7 @@
<nav data-hx-target="main" data-hx-boost="true"> <nav data-hx-target="main" data-hx-boost="true">
<p> <p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> / <a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{( pgettext "Company Switch" "title" )}}</a> <a>{{ template "title" . }}</a>
</p> </p>
</nav> </nav>
{{- end }} {{- end }}
@ -15,7 +15,7 @@
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.CompanySwitchPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.CompanySwitchPage*/ -}}
<section class="dialog-content" id="switch-company-dialog-content" data-hx-target="this"> <section class="dialog-content" id="switch-company-dialog-content" data-hx-target="this">
<h2>{{(pgettext "Company Switch" "title")}}</h2> <h2>{{ template "title" . }}</h2>
<table> <table>
<thead> <thead>
<tr> <tr>

View File

@ -0,0 +1,41 @@
{{ define "title" -}}
{{( pgettext "Tax Details" "title" )}}
{{- end }}
{{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxDetailsPage*/ -}}
<nav data-hx-target="main" data-hx-boost="true">
<p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{ template "title" . }}</a>
</p>
</nav>
{{- end }}
{{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxDetailsPage*/ -}}
<section data-hx-target="main" data-hx-swap="innerHTML show:false">
<h2>{{ template "title" . }}</h2>
{{ with .DetailsForm }}
<form method="POST" action="{{ companyURI "/tax-details" }}" data-hx-boost="true">
{{ csrfToken }}
{{ template "input-field" .BusinessName }}
{{ template "input-field" .VATIN }}
{{ template "input-field" .TradeName }}
{{ template "input-field" .Phone }}
{{ template "input-field" .Email }}
{{ template "input-field" .Web }}
{{ template "input-field" .Address | addInputAttr `class="width-2x"` }}
{{ template "input-field" .City }}
{{ template "input-field" .Province }}
{{ template "input-field" .PostalCode }}
{{ template "select-field" .Country | addSelectAttr `class="width-fixed"` }}
{{ template "select-field" .Currency }}
<fieldset>
<button type="submit">{{( pgettext "Save changes" "action" )}}</button>
</fieldset>
</form>
{{ end }}
</section>
{{- end }}

View File

@ -0,0 +1,70 @@
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxesPage*/ -}}
{{( pgettext "Taxes" "title" )}}
{{- end }}
{{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxesPage*/ -}}
<nav data-hx-target="main" data-hx-boost="true">
<p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{ template "title" . }}</a>
</p>
</nav>
{{- end }}
{{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxesPage*/ -}}
<section data-hx-target="main" data-hx-swap="innerHTML show:false">
<h2>{{ template "title" . }}</h2>
<table>
<thead>
<tr>
<th>{{( pgettext "Tax Name" "title" )}}</th>
<th class="numeric">{{( pgettext "Rate (%)" "title" )}}</th>
<th>{{( pgettext "Class" "title" )}}</th>
<th></th>
</tr>
</thead>
{{ $confirm := ( gettext "Are you sure?" )}}
<tbody data-hx-confirm="{{ $confirm }}" data-hx-target="closest tr" data-hx-swap="outerHTML swap:1s">
{{ with .Taxes }}
{{- range $tax := . }}
<tr>
<td>{{ .Name }}</td>
<td class="numeric">{{ .Rate }}</td>
<td>{{ .Class }}</td>
<td>
<form method="POST" action="{{ companyURI "/taxes"}}/{{ .Id }}" data-hx-boost="true">
{{ csrfToken }}
{{ deleteMethod }}
<button class="icon" aria-label="{{( gettext "Delete tax" )}}"
><i class="ri-delete-back-2-line"></i></button>
</form>
</td>
</tr>
{{- end }}
{{ else }}
<tr>
<td colspan="4">{{( gettext "No taxes added yet." )}}</td>
</tr>
{{ end }}
</tbody>
</table>
<form method="POST" action="{{ companyURI "/taxes" }}" data-hx-boost="true">
<h3>{{( pgettext "New Tax" "title")}}</h3>
<fieldset>
{{ csrfToken }}
{{ with .Form -}}
{{ template "input-field" .Name }}
{{ template "input-field" .Rate }}
{{ template "select-field" .Class }}
{{- end }}
</fieldset>
<footer>
<button>{{( pgettext "Add new tax" "action" )}}</button>
</footer>
</form>
</section>
{{- end }}

View File

@ -1,178 +0,0 @@
{{ define "title" -}}
{{( pgettext "Tax Details" "title" )}}
{{- end }}
{{ define "breadcrumbs" -}}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxDetailsPage*/ -}}
<nav data-hx-target="main" data-hx-boost="true">
<p>
<a href="{{ companyURI "/" }}">{{( pgettext "Home" "title" )}}</a> /
<a>{{( pgettext "Tax Details" "title" )}}</a>
</p>
</nav>
{{- end }}
{{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.TaxDetailsPage*/ -}}
<section class="dialog-content" id="tax-details-dialog-content" data-hx-target="this">
<h2>{{(pgettext "Tax Details" "title")}}</h2>
{{ with .DetailsForm }}
<form id="details" method="POST" action="{{ companyURI "/tax-details" }}" data-hx-boost="true" data-hx-select="#tax-details-dialog-content">
{{ csrfToken }}
{{ template "input-field" .BusinessName }}
{{ template "input-field" .VATIN }}
{{ template "input-field" .TradeName }}
{{ template "input-field" .Phone }}
{{ template "input-field" .Email }}
{{ template "input-field" .Web }}
{{ template "input-field" .Address | addInputAttr `class="width-2x"` }}
{{ template "input-field" .City }}
{{ template "input-field" .Province }}
{{ template "input-field" .PostalCode }}
{{ template "select-field" .Country | addSelectAttr `class="width-fixed"` }}
<fieldset>
<legend id="currency-legend">{{( pgettext "Currency" "title" )}}</legend>
{{ template "select-field" .Currency }}
</fieldset>
<fieldset id="invoicing">
<legend>{{( pgettext "Invoicing and Quoting" "title" )}}</legend>
{{ template "input-field" .InvoiceNumberFormat }}
{{ template "input-field" .NextInvoiceNumber }}
{{ template "input-field" .QuoteNumberFormat }}
{{ template "input-field" .NextQuoteNumber }}
{{ template "input-field" .LegalDisclaimer }}
</fieldset>
</form>
{{ end }}
<form id="newtax" method="POST" action="{{ companyURI "/tax" }}" data-hx-boost="true" data-hx-select="#tax-details-dialog-content">
{{ csrfToken }}
</form>
{{ $confirm := ( gettext "Are you sure?" )}}
<fieldset>
<table>
<thead>
<tr>
<th width="50%"></th>
<th>{{( pgettext "Tax Name" "title" )}}</th>
<th>{{( pgettext "Rate (%)" "title" )}}</th>
<th>{{( pgettext "Class" "title" )}}</th>
<th></th>
</tr>
</thead>
<tbody data-hx-confirm="{{ $confirm }}" data-hx-target="closest tr" data-hx-swap="outerHTML swap:1s">
{{ with .Taxes }}
{{- range $tax := . }}
<tr>
<td></td>
<td>{{ .Name }}</td>
<td>{{ .Rate }}</td>
<td>{{ .Class }}</td>
<td>
<form method="POST" action="{{ companyURI "/tax"}}/{{ .Id }}" data-hx-boost="true">
{{ csrfToken }}
{{ deleteMethod }}
<button class="icon" aria-label="{{( gettext "Delete tax" )}}" type="submit"><i
class="ri-delete-back-2-line"></i></button>
</form>
</td>
</tr>
{{- end }}
{{ else }}
<tr>
<td colspan="4">{{( gettext "No taxes added yet." )}}</td>
</tr>
{{ end }}
</tbody>
<tfoot>
<tr>
<th scope="row">{{( pgettext "New Line" "title")}}</th>
<td>
{{ template "input-field" .NewTaxForm.Name | addInputAttr `form="newtax"` }}
</td>
<td>
{{ template "input-field" .NewTaxForm.Rate | addInputAttr `form="newtax"` }}
</td>
<td>
{{ template "select-field" .NewTaxForm.Class | addSelectAttr `form="newtax"` }}
</td>
</tr>
<tr>
<td colspan="2"></td>
<td colspan="2">
<button form="newtax" type="submit">{{( pgettext "Add new tax" "action" )}}</button>
</td>
</tr>
</tfoot>
</table>
</fieldset>
<form id="new-payment-method" method="POST" action="{{ companyURI "/payment-method" }}" data-hx-boost="true" data-hx-select="#tax-details-dialog-content">
{{ 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 data-hx-confirm="{{ $confirm }}" data-hx-target="closest tr" data-hx-swap="outerHTML swap:1s">
{{ with .PaymentMethods }}
{{- range $method := . }}
<tr>
<td></td>
<td>{{ .Name }}</td>
<td>{{ .Instructions }}</td>
<td>
<form method="POST" action="{{ companyURI "/payment-method"}}/{{ .Id }}" data-hx-boost="true">
{{ 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>
<button form="details" type="submit">{{( pgettext "Save changes" "action" )}}</button>
</fieldset>
</section>
{{- end }}