140 lines
3.2 KiB
Go
140 lines
3.2 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"encoding/csv"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/evcc-io/evcc/api"
|
|
"github.com/evcc-io/evcc/util/locale"
|
|
"github.com/fatih/structs"
|
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
"golang.org/x/text/language"
|
|
"golang.org/x/text/message"
|
|
"golang.org/x/text/number"
|
|
)
|
|
|
|
// Session is a single charging session
|
|
type Session struct {
|
|
ID uint `json:"id" csv:"-" gorm:"primarykey"`
|
|
Created time.Time `json:"created"`
|
|
Finished time.Time `json:"finished"`
|
|
Loadpoint string `json:"loadpoint"`
|
|
Identifier string `json:"identifier"`
|
|
Vehicle string `json:"vehicle"`
|
|
Odometer float64 `json:"odometer" format:"int"`
|
|
MeterStart float64 `json:"meterStart" csv:"Meter Start (kWh)" gorm:"column:meter_start_kwh"`
|
|
MeterStop float64 `json:"meterStop" csv:"Meter Stop (kWh)" gorm:"column:meter_end_kwh"`
|
|
ChargedEnergy float64 `json:"chargedEnergy" csv:"Charged Energy (kWh)" gorm:"column:charged_kwh"`
|
|
}
|
|
|
|
// Sessions is a list of sessions
|
|
type Sessions []Session
|
|
|
|
var _ api.CsvWriter = (*Sessions)(nil)
|
|
|
|
func (t *Sessions) writeHeader(ctx context.Context, ww *csv.Writer) error {
|
|
localizer := locale.Localizer
|
|
if val := ctx.Value(locale.Locale).(string); val != "" {
|
|
localizer = i18n.NewLocalizer(locale.Bundle, val, locale.Language)
|
|
}
|
|
|
|
var row []string
|
|
for _, f := range structs.Fields(Session{}) {
|
|
csv := f.Tag("csv")
|
|
if csv == "-" {
|
|
continue
|
|
}
|
|
|
|
caption, err := localizer.Localize(&locale.Config{
|
|
MessageID: "sessions.csv." + strings.ToLower(f.Name()),
|
|
})
|
|
|
|
if err != nil {
|
|
if csv != "" {
|
|
caption = csv
|
|
} else {
|
|
caption = f.Name()
|
|
}
|
|
}
|
|
|
|
row = append(row, caption)
|
|
}
|
|
|
|
return ww.Write(row)
|
|
}
|
|
|
|
func (t *Sessions) writeRow(ww *csv.Writer, mp *message.Printer, r Session) error {
|
|
var row []string
|
|
for _, f := range structs.Fields(r) {
|
|
if f.Tag("csv") == "-" {
|
|
continue
|
|
}
|
|
|
|
var val string
|
|
format := f.Tag("format")
|
|
|
|
switch v := f.Value().(type) {
|
|
case float64:
|
|
switch format {
|
|
case "int":
|
|
val = mp.Sprint(number.Decimal(v, number.NoSeparator(), number.MaxFractionDigits(0)))
|
|
default:
|
|
val = mp.Sprint(number.Decimal(v, number.NoSeparator(), number.MaxFractionDigits(3)))
|
|
}
|
|
case time.Time:
|
|
if !v.IsZero() {
|
|
val = v.Local().Format("2006-01-02 15:04:05")
|
|
}
|
|
default:
|
|
val = fmt.Sprintf("%v", f.Value())
|
|
}
|
|
|
|
row = append(row, val)
|
|
}
|
|
|
|
return ww.Write(row)
|
|
}
|
|
|
|
// WriteCsv implements the api.CsvWriter interface
|
|
func (t *Sessions) WriteCsv(ctx context.Context, w io.Writer) error {
|
|
if _, err := w.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// get context language
|
|
lang := locale.Language
|
|
if language, ok := ctx.Value(locale.Locale).(string); ok && language != "" {
|
|
lang = language
|
|
}
|
|
|
|
tag, err := language.Parse(lang)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ww := csv.NewWriter(w)
|
|
|
|
// set separator according to locale
|
|
if b, _ := tag.Base(); b.String() == language.German.String() {
|
|
ww.Comma = ';'
|
|
}
|
|
|
|
if err := t.writeHeader(ctx, ww); err != nil {
|
|
return err
|
|
}
|
|
|
|
mp := message.NewPrinter(tag)
|
|
for _, r := range *t {
|
|
if err := t.writeRow(ww, mp, r); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
ww.Flush()
|
|
|
|
return ww.Error()
|
|
}
|