功能:完善里程边界与氢耗流式统计
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const HydrogenEnergyParameterTableSQL = `CREATE TABLE IF NOT EXISTS vehicle_hydrogen_energy_parameter (
|
||||
vin VARCHAR(64) NOT NULL,
|
||||
battery_capacity_kwh DECIMAL(12,3) NOT NULL,
|
||||
hydrogen_energy_kwh_per_kg DECIMAL(12,3) NOT NULL DEFAULT 16.000,
|
||||
confirmed_by VARCHAR(96) NOT NULL DEFAULT '',
|
||||
source_note VARCHAR(255) NOT NULL DEFAULT '',
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE NULL,
|
||||
active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (vin, effective_from),
|
||||
KEY idx_hydrogen_energy_parameter_active (active, effective_from, effective_to, vin),
|
||||
CONSTRAINT chk_hydrogen_energy_parameter_capacity CHECK (battery_capacity_kwh > 0 AND battery_capacity_kwh <= 500),
|
||||
CONSTRAINT chk_hydrogen_energy_parameter_conversion CHECK (hydrogen_energy_kwh_per_kg > 0 AND hydrogen_energy_kwh_per_kg <= 50),
|
||||
CONSTRAINT chk_hydrogen_energy_parameter_dates CHECK (effective_to IS NULL OR effective_to >= effective_from)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
|
||||
|
||||
const (
|
||||
hydrogenEnergyAssetSourceNote = "ln_asset_management.vehicle_model.battery_capacity"
|
||||
hydrogenEnergyAssetConfirmedBy = "资产车型主数据自动同步"
|
||||
hydrogenEnergyAssetEffectiveAt = "1970-01-01"
|
||||
)
|
||||
|
||||
type HydrogenEnergyParameterSyncResult struct {
|
||||
Read int
|
||||
Written int
|
||||
Deactivated int64
|
||||
}
|
||||
|
||||
type hydrogenEnergyParameterRow struct {
|
||||
VIN string
|
||||
SourceVehicleID int64
|
||||
CapacityKWh float64
|
||||
SourceUpdatedAt sql.NullTime
|
||||
}
|
||||
|
||||
// SyncHydrogenEnergyParameters projects each active hydrogen vehicle's rated
|
||||
// battery capacity from the asset model master into the VIN-scoped calculation
|
||||
// parameter table. The fixed, oldest effective date lets a later effective-dated
|
||||
// business override win without disabling automatic master-data synchronization.
|
||||
func SyncHydrogenEnergyParameters(ctx context.Context, db *sql.DB, sourceSchema string) (HydrogenEnergyParameterSyncResult, error) {
|
||||
result := HydrogenEnergyParameterSyncResult{}
|
||||
if db == nil {
|
||||
return result, fmt.Errorf("mysql database is required")
|
||||
}
|
||||
sourceSchema = strings.TrimSpace(sourceSchema)
|
||||
if !mysqlIdentifier.MatchString(sourceSchema) {
|
||||
return result, fmt.Errorf("invalid asset schema %q", sourceSchema)
|
||||
}
|
||||
query := fmt.Sprintf(`SELECT vi.id,UPPER(TRIM(vi.vin)),vm.battery_capacity,
|
||||
CASE
|
||||
WHEN vi.update_time IS NULL THEN vm.update_time
|
||||
WHEN vm.update_time IS NULL THEN vi.update_time
|
||||
ELSE GREATEST(vi.update_time,vm.update_time)
|
||||
END
|
||||
FROM %s.vehicle_info vi
|
||||
JOIN %s.vehicle_model vm ON vm.id=vi.vehicle_model_id
|
||||
WHERE COALESCE(vi.del_flag,'0')='0' AND COALESCE(vm.del_flag,'0')='0'
|
||||
AND LENGTH(TRIM(vi.vin))=17
|
||||
AND vm.tank_capacity>0
|
||||
AND vm.battery_capacity>0 AND vm.battery_capacity<=500`, sourceSchema, sourceSchema)
|
||||
rows, err := db.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("read asset hydrogen energy parameters: %w", err)
|
||||
}
|
||||
byVIN := map[string]hydrogenEnergyParameterRow{}
|
||||
for rows.Next() {
|
||||
var row hydrogenEnergyParameterRow
|
||||
if err := rows.Scan(&row.SourceVehicleID, &row.VIN, &row.CapacityKWh, &row.SourceUpdatedAt); err != nil {
|
||||
rows.Close()
|
||||
return result, err
|
||||
}
|
||||
result.Read++
|
||||
if row.CapacityKWh <= 0 || row.CapacityKWh > 500 {
|
||||
continue
|
||||
}
|
||||
if previous, exists := byVIN[row.VIN]; !exists || newerEnergyParameterRow(row, previous) {
|
||||
byVIN[row.VIN] = row
|
||||
}
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
if _, err := tx.ExecContext(ctx, `UPDATE vehicle_hydrogen_energy_parameter
|
||||
SET active=0
|
||||
WHERE active=1 AND source_note=?`, hydrogenEnergyAssetSourceNote); err != nil {
|
||||
return result, err
|
||||
}
|
||||
const upsert = `INSERT INTO vehicle_hydrogen_energy_parameter(
|
||||
vin,battery_capacity_kwh,hydrogen_energy_kwh_per_kg,confirmed_by,source_note,effective_from,effective_to,active
|
||||
) VALUES(?,?,16.000,?,?,?,NULL,1)
|
||||
ON DUPLICATE KEY UPDATE battery_capacity_kwh=VALUES(battery_capacity_kwh),
|
||||
confirmed_by=VALUES(confirmed_by),source_note=VALUES(source_note),effective_to=NULL,active=1`
|
||||
vins := make([]string, 0, len(byVIN))
|
||||
for vin := range byVIN {
|
||||
vins = append(vins, vin)
|
||||
}
|
||||
sort.Strings(vins)
|
||||
for _, vin := range vins {
|
||||
row := byVIN[vin]
|
||||
if _, err := tx.ExecContext(ctx, upsert, row.VIN, row.CapacityKWh, hydrogenEnergyAssetConfirmedBy, hydrogenEnergyAssetSourceNote, hydrogenEnergyAssetEffectiveAt); err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Written++
|
||||
}
|
||||
if err := tx.QueryRowContext(ctx, `SELECT COUNT(*)
|
||||
FROM vehicle_hydrogen_energy_parameter
|
||||
WHERE active=0 AND source_note=?`, hydrogenEnergyAssetSourceNote).Scan(&result.Deactivated); err != nil {
|
||||
return result, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func newerEnergyParameterRow(left, right hydrogenEnergyParameterRow) bool {
|
||||
if left.SourceUpdatedAt.Valid != right.SourceUpdatedAt.Valid {
|
||||
return left.SourceUpdatedAt.Valid
|
||||
}
|
||||
if left.SourceUpdatedAt.Valid && !left.SourceUpdatedAt.Time.Equal(right.SourceUpdatedAt.Time) {
|
||||
return left.SourceUpdatedAt.Time.After(right.SourceUpdatedAt.Time)
|
||||
}
|
||||
return left.SourceVehicleID > right.SourceVehicleID
|
||||
}
|
||||
Reference in New Issue
Block a user