package api import ( "net/http" "strconv" "time" "dana/internal/storage" ) var moscow = func() *time.Location { if loc, err := time.LoadLocation("Europe/Moscow"); err == nil { return loc } return time.FixedZone("MSK", 3*60*60) }() // statsRange разбирает ?from=YYYY-MM-DD&to=YYYY-MM-DD (обе даты включительно, по Москве). // По умолчанию — последние 30 дней. Период — не длиннее двух лет. func statsRange(q map[string][]string, now time.Time) (from, to time.Time, ok bool) { get := func(k string) string { if v := q[k]; len(v) > 0 { return v[0] } return "" } today := time.Date(now.In(moscow).Year(), now.In(moscow).Month(), now.In(moscow).Day(), 0, 0, 0, 0, moscow) to = today.AddDate(0, 0, 1) from = today.AddDate(0, 0, -29) if v := get("from"); v != "" { t, err := time.ParseInLocation("2006-01-02", v, moscow) if err != nil { return from, to, false } from = t } if v := get("to"); v != "" { t, err := time.ParseInLocation("2006-01-02", v, moscow) if err != nil { return from, to, false } to = t.AddDate(0, 0, 1) } if !to.After(from) || to.Sub(from) > 2*366*24*time.Hour { return from, to, false } return from, to, true } func (a *API) adminStats(w http.ResponseWriter, r *http.Request, u *storage.AdminUser) { from, to, valid := statsRange(r.URL.Query(), time.Now()) if !valid { fail(w, http.StatusBadRequest, "bad_request", "Некорректный период: даты в формате ГГГГ-ММ-ДД, не длиннее двух лет") return } branchID, _ := strconv.ParseInt(r.URL.Query().Get("branch_id"), 10, 64) st, err := a.store.Stats(r.Context(), storage.StatsFilter{From: from, To: to, BranchID: branchID}) if err != nil { handleErr(w, err) return } ok(w, st, map[string]any{ "from": from.Format("2006-01-02"), "to": to.AddDate(0, 0, -1).Format("2006-01-02"), "days": int(to.Sub(from).Hours()/24 + 0.5), }) }