fleetmap-reports 2.0.375 → 2.0.377
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/fuel-consumption-report.js +15 -29
- package/src/util/trips.js +10 -0
package/package.json
CHANGED
|
@@ -12,16 +12,6 @@ const { calculateConsumption, calculateTotalFuelFromSensor } = require('./util/f
|
|
|
12
12
|
const { getSummary } = require('./util/traccar')
|
|
13
13
|
const { calculatePartialTrip } = require('./util/trips')
|
|
14
14
|
|
|
15
|
-
// --- Timezone-consistent day bucketing (fuel-consumption report only) --------
|
|
16
|
-
// The shared getDates / getSummaryByDay / getDataByDay helpers resolve calendar
|
|
17
|
-
// day boundaries from the JS engine's timezone when they run in the browser, but
|
|
18
|
-
// from the user's configured timezone when they run on the server. So the same
|
|
19
|
-
// report computed client-side and server-side attributes midnight-straddling
|
|
20
|
-
// trips (and their distance / fuel / duration) to different days. The helpers
|
|
21
|
-
// below always key off the user's timezone, matching the server, so both
|
|
22
|
-
// execution paths produce identical daily figures. They are local on purpose -
|
|
23
|
-
// changing the shared helpers would move every other report's numbers.
|
|
24
|
-
|
|
25
15
|
function getReportTimezone (userData) {
|
|
26
16
|
const tz = userData.user.attributes.timezone || getUserPartner(userData.user).timezone
|
|
27
17
|
try {
|
|
@@ -84,24 +74,23 @@ function getDayWindow (date, tz) {
|
|
|
84
74
|
return [zonedToUTC(year, month, day, 0, 0, 0, tz), zonedToUTC(year, month, day, 23, 59, 59, tz)]
|
|
85
75
|
}
|
|
86
76
|
|
|
87
|
-
|
|
88
|
-
async function getReportSummaryByDay (dates, userData, traccar, devices, tz, from, to) {
|
|
77
|
+
async function getReportSummaryByDay (dates, userData, traccar, devices, tz, reportFrom, reportTo, firstDate, lastDate) {
|
|
89
78
|
const days = []
|
|
90
|
-
for (const
|
|
79
|
+
for (const date of dates) {
|
|
91
80
|
const { year, month, day } = zonedParts(date, tz)
|
|
92
81
|
|
|
93
82
|
let startDate = zonedToUTC(year, month, day, ...parseHMS(userData.dayHours.startTime), tz)
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
83
|
+
if (date.getTime() === firstDate.getTime()) {
|
|
84
|
+
const p = zonedParts(reportFrom, tz)
|
|
85
|
+
const clamp = zonedToUTC(year, month, day, p.hour, p.minute, p.second, tz)
|
|
86
|
+
if (clamp.getTime() > startDate.getTime()) startDate = clamp
|
|
98
87
|
}
|
|
99
88
|
|
|
100
89
|
let endDate = zonedToUTC(year, month, day, ...parseHMS(userData.dayHours.endTime), tz)
|
|
101
|
-
if (
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
90
|
+
if (date.getTime() === lastDate.getTime()) {
|
|
91
|
+
const p = zonedParts(reportTo, tz)
|
|
92
|
+
const clamp = zonedToUTC(year, month, day, p.hour, p.minute, p.second, tz)
|
|
93
|
+
if (clamp.getTime() < endDate.getTime()) endDate = clamp
|
|
105
94
|
}
|
|
106
95
|
|
|
107
96
|
const summary = await getSummary(traccar, startDate, endDate, devices)
|
|
@@ -154,22 +143,19 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
154
143
|
|
|
155
144
|
const daysByDevice = new Map()
|
|
156
145
|
|
|
157
|
-
// Process the period in chunks of whole calendar days (computed once up front, then grouped) so
|
|
158
|
-
// we never hold more than ~a week of raw GPS positions for the whole device set in memory at
|
|
159
|
-
// once - a single busy device can have tens of thousands of positions over a month. Chunking the
|
|
160
|
-
// already-computed dates list, rather than re-deriving dates per raw millisecond sub-range, avoids
|
|
161
|
-
// any risk of a boundary day being counted twice (or dropped) due to timezone rounding.
|
|
162
146
|
const timezone = getReportTimezone(userData)
|
|
163
147
|
const allDates = getReportDates(from, to, timezone)
|
|
164
148
|
const dateGroups = automaticReports.sliceArray(allDates, 7)
|
|
149
|
+
const firstDate = allDates[0]
|
|
150
|
+
const lastDate = allDates[allDates.length - 1]
|
|
165
151
|
|
|
166
152
|
for (let chunkIndex = 0; chunkIndex < dateGroups.length; chunkIndex++) {
|
|
167
153
|
const dates = dateGroups[chunkIndex]
|
|
168
|
-
const chunkFrom = chunkIndex === 0 ? from : dates[0]
|
|
169
|
-
const chunkTo = chunkIndex === dateGroups.length - 1 ? to :
|
|
154
|
+
const chunkFrom = chunkIndex === 0 ? from : getDayWindow(dates[0], timezone)[0]
|
|
155
|
+
const chunkTo = chunkIndex === dateGroups.length - 1 ? to : getDayWindow(dates[dates.length - 1], timezone)[1]
|
|
170
156
|
|
|
171
157
|
const allInOne = await traccarHelper.getAllInOne(traccar, chunkFrom, chunkTo, devices, true, true, true, false)
|
|
172
|
-
const summary = await getReportSummaryByDay(dates, userData, traccar, devices, timezone,
|
|
158
|
+
const summary = await getReportSummaryByDay(dates, userData, traccar, devices, timezone, from, to, firstDate, lastDate)
|
|
173
159
|
|
|
174
160
|
const fuelServicesData = []
|
|
175
161
|
if (devices.some(d => d.attributes.odooId)) {
|
package/src/util/trips.js
CHANGED
|
@@ -133,6 +133,9 @@ function isInsideTimetable (t, userData) {
|
|
|
133
133
|
function updateTrip (device, t, route) {
|
|
134
134
|
route = route.filter(p => p && p.attributes.ignition)
|
|
135
135
|
if (!route.length) { return }
|
|
136
|
+
const originalDistance = t.distance
|
|
137
|
+
const originalDuration = t.duration
|
|
138
|
+
const originalSpentFuel = t.spentFuel
|
|
136
139
|
const distance = calculateDistance(route, device ? device.attributes['report.ignoreOdometer'] : true) * 1000
|
|
137
140
|
t.distance = distance
|
|
138
141
|
t.duration = new Date(route[route.length - 1].fixTime).getTime() - new Date(route[0].fixTime).getTime()
|
|
@@ -140,6 +143,13 @@ function updateTrip (device, t, route) {
|
|
|
140
143
|
t.averageSpeed = distance > 0 ? ((route.reduce((a, b) => a + b.speed, 0)) / route.length) : 0
|
|
141
144
|
t.startOdometer = device && !device.attributes['report.ignoreOdometer'] && route[0].attributes.odometer ? route[0].attributes.odometer : route[0].attributes.totalDistance
|
|
142
145
|
t.endOdometer = device && !device.attributes['report.ignoreOdometer'] && route[route.length - 1].attributes.odometer ? route[route.length - 1].attributes.odometer : route[route.length - 1].attributes.totalDistance
|
|
146
|
+
if (originalSpentFuel > 0) {
|
|
147
|
+
// A trip clipped at a report day boundary keeps only part of its route, so its
|
|
148
|
+
// share of the trip's total fuel must be prorated too, otherwise the full trip's
|
|
149
|
+
// fuel gets counted on both days it was split across.
|
|
150
|
+
const ratio = originalDistance > 0 ? distance / originalDistance : (originalDuration > 0 ? t.duration / originalDuration : 1)
|
|
151
|
+
t.spentFuel = originalSpentFuel * Math.min(Math.max(ratio, 0), 1)
|
|
152
|
+
}
|
|
143
153
|
}
|
|
144
154
|
|
|
145
155
|
function getUncompletedTrip (device, deviceRoute, deviceTrips) {
|