Compare commits

..

No commits in common. "46b079cb0b4f6751b0f97533a5af6dd3acf3f72d" and "eb47988464084b0a72619ba5fa90353d4a580fe1" have entirely different histories.

1 changed files with 27 additions and 39 deletions

View File

@ -8,7 +8,6 @@ import (
"math" "math"
"net/http" "net/http"
"strings" "strings"
"time"
) )
const ( const (
@ -61,7 +60,7 @@ func ServeDashboard(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
conn := getConn(r) conn := getConn(r)
dashboard := &DashboardPage{ dashboard := &DashboardPage{
Filters: filters, Filters: filters,
Chart: buildDashboardChart(r.Context(), conn, locale, company, periodStart, periodEnd, filters.Period.Selected), Chart: buildDashboardChart(r.Context(), conn, company, periodStart, periodEnd, filters.Period.Selected),
} }
rows := conn.MustQuery(r.Context(), fmt.Sprintf(` rows := conn.MustQuery(r.Context(), fmt.Sprintf(`
select to_price(0, decimal_digits) as sales select to_price(0, decimal_digits) as sales
@ -174,23 +173,17 @@ func (form *dashboardFilterForm) Parse(r *http.Request) error {
return nil return nil
} }
func buildDashboardChart(ctx context.Context, conn *Conn, locale *Locale, company *Company, periodStart string, periodEnd string, selectedPeriod string) template.HTML { func buildDashboardChart(ctx context.Context, conn *Conn, company *Company, periodStart string, periodEnd string, selectedPeriod string) template.HTML {
group := "yyyymmdd" group := "yyyymmdd"
dateFormat := "02/01/2006"
switch selectedPeriod { switch selectedPeriod {
case YearPeriod, YesteryearPeriod: case YearPeriod, YesteryearPeriod:
group = "yyyymm" group = "yyyymm"
dateFormat = "01/2006"
} }
rows := conn.MustQuery(ctx, fmt.Sprintf(` rows := conn.MustQuery(ctx, fmt.Sprintf(`
select date select date
, to_date(date::text, '%[3]s') , 0 as sales
, 0 as sales
, to_price(0, $2) as sales_price
, coalesce(invoice.total, 0) as income , coalesce(invoice.total, 0) as income
, to_price(coalesce(invoice.total, 0), $2) as income_price
, coalesce(expense.total, 0) as expenses , coalesce(expense.total, 0) as expenses
, to_price(coalesce(expense.total, 0), $2) as expenses_price
from ( from (
select to_char(date.invoice_date, '%[3]s')::integer as date select to_char(date.invoice_date, '%[3]s')::integer as date
, sum(total)::integer as total , sum(total)::integer as total
@ -207,18 +200,14 @@ func buildDashboardChart(ctx context.Context, conn *Conn, locale *Locale, compan
group by date group by date
) as expense using (date) ) as expense using (date)
order by date order by date
`, periodStart, periodEnd, group), company.Id, company.DecimalDigits) `, periodStart, periodEnd, group), company.Id)
defer rows.Close() defer rows.Close()
type value struct { type value struct {
index int date int
date time.Time sales float64
sales float64 income float64
salesPrice string expenses float64
income float64
incomePrice string
expenses float64
expensesPrice string
} }
var values []value var values []value
var max = 0. var max = 0.
@ -227,7 +216,7 @@ func buildDashboardChart(ctx context.Context, conn *Conn, locale *Locale, compan
var sales int var sales int
var income int var income int
var expenses int var expenses int
if err := rows.Scan(&v.index, &v.date, &sales, &v.salesPrice, &income, &v.incomePrice, &expenses, &v.expensesPrice); err != nil { if err := rows.Scan(&v.date, &sales, &income, &expenses); err != nil {
panic(err) panic(err)
} }
v.sales = float64(sales) v.sales = float64(sales)
@ -251,26 +240,25 @@ func buildDashboardChart(ctx context.Context, conn *Conn, locale *Locale, compan
var sb strings.Builder var sb strings.Builder
sb.WriteString(fmt.Sprintf("<svg id='income-chart' viewBox='-10 -10 %d %d'>", int(width)+20, int(height)+20)) sb.WriteString(fmt.Sprintf("<svg id='income-chart' viewBox='-10 -10 %d %d'>", int(width)+20, int(height)+20))
sb.WriteString("<rect x='-10' y='-10' width='100%', height='100%'/>") sb.WriteString("<rect x='-10' y='-10' width='100%', height='100%'/>")
writePolyline := func(value func(value) float64) { sb.WriteString("<polyline points='")
sb.WriteString("<polyline points='")
for i, v := range values {
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-value(v)/max*height))
}
sb.WriteString("'/>")
}
writePolyline(func(v value) float64 { return v.sales })
writePolyline(func(v value) float64 { return v.income })
writePolyline(func(v value) float64 { return v.expenses })
writeCircle := func(i int, time time.Time, p string, v float64) {
price := formatPrice(p, locale.Language, locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol)
date := time.Format(dateFormat)
sb.WriteString(fmt.Sprintf("<circle cx='%f' cy='%f' r='4'><title>%s\n%s</title></circle>", float64(i)/dataPoints*width, height-v/max*height, date, price))
}
for i, v := range values { for i, v := range values {
writeCircle(i, v.date, v.salesPrice, v.sales) sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.sales/max*height))
writeCircle(i, v.date, v.incomePrice, v.income) }
writeCircle(i, v.date, v.expensesPrice, v.expenses) sb.WriteString("'/>")
sb.WriteString("<polyline points='")
for i, v := range values {
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.income/max*height))
}
sb.WriteString("'/>")
sb.WriteString("<polyline points='")
for i, v := range values {
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.expenses/max*height))
}
sb.WriteString("'/>")
for i, v := range values {
sb.WriteString(fmt.Sprintf("<circle cx='%f' cy='%f' r='4'/>", float64(i)/dataPoints*width, height-v.sales/max*height))
sb.WriteString(fmt.Sprintf("<circle cx='%f' cy='%f' r='4'/>", float64(i)/dataPoints*width, height-v.income/max*height))
sb.WriteString(fmt.Sprintf("<circle cx='%f' cy='%f' r='4'/>", float64(i)/dataPoints*width, height-v.expenses/max*height))
} }
sb.WriteString("</svg>") sb.WriteString("</svg>")
return template.HTML(sb.String()) return template.HTML(sb.String())