Compare commits
2 Commits
eb47988464
...
46b079cb0b
Author | SHA1 | Date |
---|---|---|
jordi fita mas | 46b079cb0b | |
jordi fita mas | 02a4fad443 |
|
@ -8,6 +8,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -60,7 +61,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, company, periodStart, periodEnd, filters.Period.Selected),
|
Chart: buildDashboardChart(r.Context(), conn, locale, 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
|
||||||
|
@ -173,17 +174,23 @@ func (form *dashboardFilterForm) Parse(r *http.Request) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildDashboardChart(ctx context.Context, conn *Conn, company *Company, periodStart string, periodEnd string, selectedPeriod string) template.HTML {
|
func buildDashboardChart(ctx context.Context, conn *Conn, locale *Locale, 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
|
||||||
, 0 as sales
|
, to_date(date::text, '%[3]s')
|
||||||
|
, 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
|
||||||
|
@ -200,14 +207,18 @@ func buildDashboardChart(ctx context.Context, conn *Conn, company *Company, peri
|
||||||
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)
|
`, periodStart, periodEnd, group), company.Id, company.DecimalDigits)
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
type value struct {
|
type value struct {
|
||||||
date int
|
index int
|
||||||
sales float64
|
date time.Time
|
||||||
income float64
|
sales float64
|
||||||
expenses float64
|
salesPrice string
|
||||||
|
income float64
|
||||||
|
incomePrice string
|
||||||
|
expenses float64
|
||||||
|
expensesPrice string
|
||||||
}
|
}
|
||||||
var values []value
|
var values []value
|
||||||
var max = 0.
|
var max = 0.
|
||||||
|
@ -216,7 +227,7 @@ func buildDashboardChart(ctx context.Context, conn *Conn, company *Company, peri
|
||||||
var sales int
|
var sales int
|
||||||
var income int
|
var income int
|
||||||
var expenses int
|
var expenses int
|
||||||
if err := rows.Scan(&v.date, &sales, &income, &expenses); err != nil {
|
if err := rows.Scan(&v.index, &v.date, &sales, &v.salesPrice, &income, &v.incomePrice, &expenses, &v.expensesPrice); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
v.sales = float64(sales)
|
v.sales = float64(sales)
|
||||||
|
@ -240,25 +251,26 @@ func buildDashboardChart(ctx context.Context, conn *Conn, company *Company, peri
|
||||||
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%'/>")
|
||||||
sb.WriteString("<polyline points='")
|
writePolyline := func(value func(value) float64) {
|
||||||
for i, v := range values {
|
sb.WriteString("<polyline points='")
|
||||||
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.sales/max*height))
|
for i, v := range values {
|
||||||
|
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-value(v)/max*height))
|
||||||
|
}
|
||||||
|
sb.WriteString("'/>")
|
||||||
}
|
}
|
||||||
sb.WriteString("'/>")
|
writePolyline(func(v value) float64 { return v.sales })
|
||||||
sb.WriteString("<polyline points='")
|
writePolyline(func(v value) float64 { return v.income })
|
||||||
for i, v := range values {
|
writePolyline(func(v value) float64 { return v.expenses })
|
||||||
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.income/max*height))
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
sb.WriteString("'/>")
|
|
||||||
sb.WriteString("<polyline points='")
|
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
sb.WriteString(fmt.Sprintf(" %f,%f", float64(i)/dataPoints*width, height-v.expenses/max*height))
|
writeCircle(i, v.date, v.salesPrice, v.sales)
|
||||||
}
|
writeCircle(i, v.date, v.incomePrice, v.income)
|
||||||
sb.WriteString("'/>")
|
writeCircle(i, v.date, v.expensesPrice, v.expenses)
|
||||||
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())
|
||||||
|
|
Loading…
Reference in New Issue