fix: tighten source-aware mileage projection
This commit is contained in:
@@ -2,6 +2,7 @@ package stats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -127,6 +128,17 @@ func ProjectDailyMileage(ctx context.Context, exec Execer, vin string, statDate
|
||||
statDate,
|
||||
string(protocol),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = exec.ExecContext(ctx, cleanupProjectedDailyMileageSQL,
|
||||
vin,
|
||||
statDate,
|
||||
string(protocol),
|
||||
vin,
|
||||
statDate,
|
||||
string(protocol),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -257,3 +269,70 @@ JOIN (
|
||||
SET s.is_selected = 1
|
||||
WHERE s.vin = ? AND s.stat_date = ? AND s.protocol = ?
|
||||
`
|
||||
|
||||
const cleanupProjectedDailyMileageSQL = `
|
||||
DELETE FROM vehicle_daily_mileage
|
||||
WHERE vin = ? AND stat_date = ? AND protocol = ?
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM vehicle_daily_mileage_source
|
||||
WHERE vin = ? AND stat_date = ? AND protocol = ? AND is_selected = 1
|
||||
)
|
||||
`
|
||||
|
||||
type sourceBaseline struct {
|
||||
LatestTotalKM float64
|
||||
LatestEventTime time.Time
|
||||
}
|
||||
|
||||
func lookupPreviousSourceBaseline(ctx context.Context, query Queryer, vin string, statDate string, protocol envelope.Protocol, sourceKey string) (sourceBaseline, bool, error) {
|
||||
if query == nil || strings.TrimSpace(vin) == "" || strings.TrimSpace(statDate) == "" || strings.TrimSpace(sourceKey) == "" {
|
||||
return sourceBaseline{}, false, nil
|
||||
}
|
||||
previousDate, ok := previousStatDate(statDate)
|
||||
if !ok {
|
||||
return sourceBaseline{}, false, nil
|
||||
}
|
||||
rows, err := query.QueryContext(ctx, previousSourceBaselineSQL, vin, previousDate, string(protocol), sourceKey)
|
||||
if err != nil {
|
||||
return sourceBaseline{}, false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
if !rows.Next() {
|
||||
if err := rows.Err(); err != nil {
|
||||
return sourceBaseline{}, false, err
|
||||
}
|
||||
return sourceBaseline{}, false, nil
|
||||
}
|
||||
var latestTotal sql.NullFloat64
|
||||
var latestEvent sql.NullTime
|
||||
if err := rows.Scan(&latestTotal, &latestEvent); err != nil {
|
||||
return sourceBaseline{}, false, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return sourceBaseline{}, false, err
|
||||
}
|
||||
return sourceBaseline{
|
||||
LatestTotalKM: latestTotal.Float64,
|
||||
LatestEventTime: latestEvent.Time,
|
||||
}, latestTotal.Valid, nil
|
||||
}
|
||||
|
||||
func previousStatDate(statDate string) (string, bool) {
|
||||
day, err := time.Parse("2006-01-02", strings.TrimSpace(statDate))
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return day.AddDate(0, 0, -1).Format("2006-01-02"), true
|
||||
}
|
||||
|
||||
const previousSourceBaselineSQL = `
|
||||
SELECT latest_total_mileage_km, latest_event_time
|
||||
FROM vehicle_daily_mileage_source
|
||||
WHERE vin = ?
|
||||
AND stat_date = ?
|
||||
AND protocol = ?
|
||||
AND source_key = ?
|
||||
ORDER BY latest_event_time DESC
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user