153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
|
package pkg
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"github.com/julienschmidt/httprouter"
|
||
|
"html/template"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type InvoicesIndexPage struct {
|
||
|
}
|
||
|
|
||
|
func IndexInvoices(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||
|
page := &InvoicesIndexPage{}
|
||
|
mustRenderAppTemplate(w, r, "invoices/index.gohtml", page)
|
||
|
}
|
||
|
|
||
|
func GetInvoiceForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||
|
locale := getLocale(r)
|
||
|
conn := getConn(r)
|
||
|
company := mustGetCompany(r)
|
||
|
form := newInvoiceForm(r.Context(), conn, locale, company)
|
||
|
slug := params[0].Value
|
||
|
if slug == "new" {
|
||
|
form.Customer.EmptyLabel = gettext("Select a customer to bill.", locale)
|
||
|
form.Date.Val = time.Now().Format("2006-01-02")
|
||
|
w.WriteHeader(http.StatusOK)
|
||
|
mustRenderNewInvoiceForm(w, r, form)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func mustRenderNewInvoiceForm(w http.ResponseWriter, r *http.Request, form *invoiceForm) {
|
||
|
mustRenderAppTemplate(w, r, "invoices/new.gohtml", form)
|
||
|
}
|
||
|
|
||
|
func HandleAddInvoice(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||
|
r.ParseForm()
|
||
|
w.Write([]byte("OK"))
|
||
|
}
|
||
|
|
||
|
type invoiceProductForm struct {
|
||
|
ProductId *InputField
|
||
|
Name *InputField
|
||
|
Description *InputField
|
||
|
Price *InputField
|
||
|
Quantity *InputField
|
||
|
Discount *InputField
|
||
|
Tax *SelectField
|
||
|
}
|
||
|
|
||
|
type invoiceForm struct {
|
||
|
locale *Locale
|
||
|
company *Company
|
||
|
Customer *SelectField
|
||
|
Number *InputField
|
||
|
Date *InputField
|
||
|
Notes *InputField
|
||
|
Products []*invoiceProductForm
|
||
|
}
|
||
|
|
||
|
func newInvoiceForm(ctx context.Context, conn *Conn, locale *Locale, company *Company) *invoiceForm {
|
||
|
return &invoiceForm{
|
||
|
locale: locale,
|
||
|
company: company,
|
||
|
Customer: &SelectField{
|
||
|
Name: "customer",
|
||
|
Label: pgettext("input", "Customer", locale),
|
||
|
Required: true,
|
||
|
Options: MustGetOptions(ctx, conn, "select contact_id::text, business_name from contact where company_id = $1 order by business_name", company.Id),
|
||
|
},
|
||
|
Number: &InputField{
|
||
|
Name: "number",
|
||
|
Label: pgettext("input", "Number", locale),
|
||
|
Type: "text",
|
||
|
Required: false,
|
||
|
},
|
||
|
Date: &InputField{
|
||
|
Name: "date",
|
||
|
Label: pgettext("input", "Invoice Date", locale),
|
||
|
Type: "date",
|
||
|
Required: true,
|
||
|
},
|
||
|
Notes: &InputField{
|
||
|
Name: "description",
|
||
|
Label: pgettext("input", "Notes", locale),
|
||
|
Type: "textarea",
|
||
|
},
|
||
|
Products: []*invoiceProductForm{
|
||
|
newInvoiceProductForm(ctx, conn, company, locale),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func newInvoiceProductForm(ctx context.Context, conn *Conn, company *Company, locale *Locale) *invoiceProductForm {
|
||
|
return &invoiceProductForm{
|
||
|
ProductId: &InputField{
|
||
|
Name: "product[][id]",
|
||
|
Label: pgettext("input", "Id", locale),
|
||
|
Type: "hidden",
|
||
|
Required: true,
|
||
|
},
|
||
|
Name: &InputField{
|
||
|
Name: "product[][name]",
|
||
|
Label: pgettext("input", "Name", locale),
|
||
|
Type: "text",
|
||
|
Required: true,
|
||
|
},
|
||
|
Description: &InputField{
|
||
|
Name: "product[][description]",
|
||
|
Label: pgettext("input", "Description", locale),
|
||
|
Type: "textarea",
|
||
|
},
|
||
|
Price: &InputField{
|
||
|
Name: "product[][price]",
|
||
|
Label: pgettext("input", "Price", locale),
|
||
|
Type: "number",
|
||
|
Required: true,
|
||
|
Attributes: []template.HTMLAttr{
|
||
|
`min="0"`,
|
||
|
template.HTMLAttr(fmt.Sprintf(`step="%v"`, company.MinCents())),
|
||
|
},
|
||
|
},
|
||
|
Quantity: &InputField{
|
||
|
Name: "product[][quantity]",
|
||
|
Label: pgettext("input", "Quantity", locale),
|
||
|
Type: "number",
|
||
|
Required: true,
|
||
|
Attributes: []template.HTMLAttr{
|
||
|
`min="0"`,
|
||
|
},
|
||
|
},
|
||
|
Discount: &InputField{
|
||
|
Name: "product[][discount]",
|
||
|
Label: pgettext("input", "Discount (%)", locale),
|
||
|
Type: "number",
|
||
|
Required: true,
|
||
|
Attributes: []template.HTMLAttr{
|
||
|
`min="0"`,
|
||
|
`max="100"`,
|
||
|
},
|
||
|
},
|
||
|
Tax: &SelectField{
|
||
|
Name: "product[][tax]",
|
||
|
Label: pgettext("input", "Taxes", locale),
|
||
|
Multiple: true,
|
||
|
Options: MustGetOptions(ctx, conn, "select tax_id::text, name from tax where company_id = $1 order by name", company.Id),
|
||
|
},
|
||
|
}
|
||
|
}
|