fleetmap-reports 1.0.777 → 1.0.779
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/activity-report.js +3 -2
- package/src/automaticReports.js +0 -16
- package/src/fuelconsumption-report.js +13 -24
- package/src/partnerReports/performance-report.js +43 -6
- package/src/tests/activity.test.js +14 -0
- package/src/tests/performance.test.js +6 -5
- package/src/trip-report.js +2 -1
- package/src/util/fuel.js +43 -0
package/package.json
CHANGED
package/src/activity-report.js
CHANGED
|
@@ -13,6 +13,7 @@ const { isInsideTimetable, isPartialInsideTimetable, calculateTrip } = require('
|
|
|
13
13
|
const tripHelper = require('./util/trips')
|
|
14
14
|
const { devicesToProcess } = require('./util/device')
|
|
15
15
|
const { getDriverData } = require('./util/driver')
|
|
16
|
+
const { calculateConsumption } = require('./util/fuel')
|
|
16
17
|
|
|
17
18
|
const fileName = 'ActivityReport'
|
|
18
19
|
|
|
@@ -204,7 +205,7 @@ function processDevices (from, to, devices, data, userData) {
|
|
|
204
205
|
if (summaryCurrentDay) {
|
|
205
206
|
summaryCurrentDay.engineHours = tripsByDay.reduce((a, b) => a + b.duration, 0)
|
|
206
207
|
summaryCurrentDay.distance = distance
|
|
207
|
-
summaryCurrentDay.convertedSpentFuel =
|
|
208
|
+
summaryCurrentDay.convertedSpentFuel = calculateConsumption(d, { route: deviceRoute, summary: summaryCurrentDay })
|
|
208
209
|
summaryCurrentDay.startTime = tripsByDay.length && tripsByDay[0].startTime
|
|
209
210
|
summaryCurrentDay.startAddress = tripsByDay.length && tripsByDay[0].startAddress
|
|
210
211
|
summaryCurrentDay.endTime = tripsByDay.length && tripsByDay[tripsByDay.length - 1].endTime
|
|
@@ -240,7 +241,7 @@ function processDevices (from, to, devices, data, userData) {
|
|
|
240
241
|
summary.forEach(s => {
|
|
241
242
|
s.engineHours = deviceTrips.reduce((a, b) => a + b.duration, 0)
|
|
242
243
|
s.distance = deviceTrips.reduce((a, b) => a + b.distance, 0)
|
|
243
|
-
s.convertedSpentFuel =
|
|
244
|
+
s.convertedSpentFuel = calculateConsumption(d, { route: deviceRoute, summary: s })
|
|
244
245
|
s.startTime = deviceTrips.length && deviceTrips[0].startTime
|
|
245
246
|
s.startAddress = deviceTrips.length && deviceTrips[0].startAddress
|
|
246
247
|
s.endTime = deviceTrips.length && deviceTrips[deviceTrips.length - 1].endTime
|
package/src/automaticReports.js
CHANGED
|
@@ -21,10 +21,6 @@ function deviceWithFuelInfo (device) {
|
|
|
21
21
|
(device.attributes.fuel_low_threshold >= 0 && device.attributes.fuel_high_threshold >= 0 && device.attributes.fuel_tank_capacity)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function fuelSignalInverter (device) {
|
|
25
|
-
return device.attributes.fuel_low_threshold <= device.attributes.fuel_high_threshold ? 1 : -1
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
function calculateXpertDistance (date, positions) {
|
|
29
25
|
const begin = moment(date, 'YYYY-MM-DD').startOf('day')
|
|
30
26
|
const end = moment(date, 'YYYY-MM-DD').endOf('day')
|
|
@@ -33,19 +29,7 @@ function calculateXpertDistance (date, positions) {
|
|
|
33
29
|
return datePositions.reduce((a, b) => a + b.attributes.distance, 0)
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
function calculateSpentFuel (value, device) {
|
|
37
|
-
if (!value || device.attributes.xpert) { return value }
|
|
38
|
-
|
|
39
|
-
if (device.attributes.fuel_low_threshold && device.attributes.fuel_high_threshold) {
|
|
40
|
-
const valueSignalCheck = value * fuelSignalInverter(device)
|
|
41
|
-
const valuePercentage = (valueSignalCheck * 100) / Math.abs(device.attributes.fuel_low_threshold - device.attributes.fuel_high_threshold)
|
|
42
|
-
return Math.round((valuePercentage * device.attributes.fuel_tank_capacity) / 100)
|
|
43
|
-
}
|
|
44
|
-
return value
|
|
45
|
-
}
|
|
46
|
-
|
|
47
32
|
exports.sliceArray = sliceArray
|
|
48
33
|
exports.deviceWithFuelInfo = deviceWithFuelInfo
|
|
49
|
-
exports.calculateSpentFuel = calculateSpentFuel
|
|
50
34
|
exports.calculateXpertDistance = calculateXpertDistance
|
|
51
35
|
exports.maxParallelRequests = maxParallelRequests
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const automaticReports = require('./automaticReports')
|
|
2
1
|
const refuelingReport = require('./refueling-report')
|
|
3
2
|
const traccarHelper = require('./util/traccar')
|
|
4
3
|
const odoo = require('./util/odoo')
|
|
@@ -8,6 +7,7 @@ const { getStyle } = require('./reportStyle')
|
|
|
8
7
|
const { getUserPartner } = require('fleetmap-partners')
|
|
9
8
|
const { addTable, headerFromUser } = require('./util/pdfDocument')
|
|
10
9
|
const jsPDF = require('jspdf')
|
|
10
|
+
const { useOdooFuelData, calculateConsumption } = require('./util/fuel')
|
|
11
11
|
|
|
12
12
|
async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
13
13
|
console.log('Create FuelConsumption Report')
|
|
@@ -22,24 +22,23 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
22
22
|
|
|
23
23
|
const devices = devicesToProcess(userData)
|
|
24
24
|
|
|
25
|
-
const allInOne = await traccarHelper.getAllInOne(traccar, from, to, devices, true, true,
|
|
26
|
-
const tripsData = allInOne.trips
|
|
27
|
-
const routeData = allInOne.route
|
|
25
|
+
const allInOne = await traccarHelper.getAllInOne(traccar, from, to, devices, true, true, true, false)
|
|
28
26
|
|
|
29
27
|
const fuelServicesData = []
|
|
30
28
|
if (devices.some(d => d.attributes.odooId)) {
|
|
31
29
|
fuelServicesData.push(...(await odoo.getOdooFuelServices(traccar, from, to)))
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
if (
|
|
32
|
+
if (allInOne.trips.length === 0) {
|
|
35
33
|
return reportData
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
allData.totalDevices = 0
|
|
39
37
|
|
|
40
38
|
for (const d of devices) {
|
|
41
|
-
const trips =
|
|
42
|
-
const route =
|
|
39
|
+
const trips = allInOne.trips.filter(t => t.deviceId === d.id)
|
|
40
|
+
const route = allInOne.route.filter(r => r.deviceId === d.id)
|
|
41
|
+
const stops = allInOne.stops.filter(s => s.deviceId === d.id)
|
|
43
42
|
const deviceFuelServices = fuelServicesData.filter(f => Number.parseInt(d.attributes.odooId) === f.vehicle_id[0])
|
|
44
43
|
|
|
45
44
|
if (trips.length > 0) {
|
|
@@ -55,6 +54,12 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
55
54
|
new Map()
|
|
56
55
|
)
|
|
57
56
|
|
|
57
|
+
stops.forEach(s => { s.startDate = s.startTime.substring(0, 10) })
|
|
58
|
+
const groupedStopsByDay = stops.reduce(
|
|
59
|
+
(entryMap, e) => entryMap.set(e.startDate, [...entryMap.get(e.startDate) || [], e]),
|
|
60
|
+
new Map()
|
|
61
|
+
)
|
|
62
|
+
|
|
58
63
|
route.forEach(p => { p.startDate = p.fixTime.substring(0, 10) })
|
|
59
64
|
const groupedRouteByDay = route.reduce(
|
|
60
65
|
(entryMap, e) => entryMap.set(e.startDate, [...entryMap.get(e.startDate) || [], e]),
|
|
@@ -69,7 +74,7 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
69
74
|
const dayTrips = groupedTripsByDay.get(day)
|
|
70
75
|
const dayRefueling = groupedRefuelingsByDay.get(day)
|
|
71
76
|
const distance = dayTrips.reduce((a, b) => a + b.distance, 0)
|
|
72
|
-
const spentFuel = calculateConsumption(
|
|
77
|
+
const spentFuel = calculateConsumption(d, { trips: dayTrips, stops: groupedStopsByDay.get(day), route: groupedRouteByDay.get(day) }, odooAvgConsumption)
|
|
73
78
|
|
|
74
79
|
const dataRow = {
|
|
75
80
|
date: day,
|
|
@@ -126,18 +131,6 @@ function calculateAvgConsumption (fuel, distance) {
|
|
|
126
131
|
return { byKms: fuel * 100 / (distance / 1000), byLiters: (distance / 1000) / fuel }
|
|
127
132
|
}
|
|
128
133
|
|
|
129
|
-
function calculateConsumption (userData, d, day, avgConsumption, data) {
|
|
130
|
-
if (useOdooFuelData(d, data.route)) {
|
|
131
|
-
return (avgConsumption.byKms * (data.trips.reduce((a, b) => a + b.distance, 0) / 1000) / 100)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (data.route.length > 1 && data.route[0].attributes.fuelUsed) {
|
|
135
|
-
return data.route[data.route.length - 1].attributes.fuelUsed - data.route[0].attributes.fuelUsed
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return automaticReports.calculateSpentFuel(data.trips.reduce((a, b) => a + b.spentFuel, 0), d)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
134
|
function exportFuelConsumptionReportToExcel (userData, reportData) {
|
|
142
135
|
const translations = getTranslations(userData)
|
|
143
136
|
const lang = getLanguage(userData)
|
|
@@ -268,10 +261,6 @@ function deviceName (device) {
|
|
|
268
261
|
return device.name + (device.attributes.license_plate ? ', ' + device.attributes.license_plate : '') + (device.model ? ', ' + device.model : '')
|
|
269
262
|
}
|
|
270
263
|
|
|
271
|
-
function useOdooFuelData (d, route) {
|
|
272
|
-
return route.length && !route[0].attributes.fuel && d.attributes.odooId
|
|
273
|
-
}
|
|
274
|
-
|
|
275
264
|
function getTotalKms (user, data) {
|
|
276
265
|
const totalKms = data.reduce((a, b) => a + b.distance, 0)
|
|
277
266
|
return formatNumber(totalKms / 1000, user.attributes.lang)
|
|
@@ -2,6 +2,7 @@ const automaticReports = require('../automaticReports')
|
|
|
2
2
|
const traccarHelper = require('../util/traccar')
|
|
3
3
|
const { getUncompletedTrip } = require('../util/trips')
|
|
4
4
|
const { getEndTripMessages, getCanDriverStyleMessages, parseEndTripMessage, parseCanDriverStyleMessage } = require('../util/xpert')
|
|
5
|
+
const { calculateDistance } = require('../util/utils')
|
|
5
6
|
|
|
6
7
|
async function createPerformanceReport (from, to, userData, traccar) {
|
|
7
8
|
const reportData = []
|
|
@@ -133,24 +134,40 @@ function getDeviceData (allInOne, d) {
|
|
|
133
134
|
const idleTime = deviceTrips.reduce((a, b) => a + b.idleTime, 0) + deviceStops.reduce((a, b) => a + b.engineHours, 0)
|
|
134
135
|
const idleConsumption = deviceSummary && deviceSummary.spentFuel > drivingConsumption ? deviceSummary.spentFuel - drivingConsumption : 0
|
|
135
136
|
|
|
136
|
-
const
|
|
137
|
-
const
|
|
137
|
+
const highEngineRPMSections = calculateRPMSections(deviceRoute, d.attributes.highRPM || 1300)
|
|
138
|
+
const highEngineRPM = highEngineRPMSections.map(a => a.length > 1
|
|
139
|
+
? a.map((p, index) => index === 0 ? 0 : new Date(p.fixTime).getTime() - new Date(a[index - 1].fixTime).getTime()).reduce((a, b) => a + b, 0)
|
|
140
|
+
: 0).reduce((a, b) => a + b, 0)
|
|
141
|
+
|
|
142
|
+
const economicRPMSections = calculateRPMSections(deviceRoute, d.attributes.minEconomicRPM || 1000, d.attributes.maxEconomicRPM || 1250)
|
|
143
|
+
const economicTime = economicRPMSections.map(a => a.length > 1
|
|
144
|
+
? a.map((p, index) => index === 0 ? 0 : new Date(p.fixTime).getTime() - new Date(a[index - 1].fixTime).getTime()).reduce((a, b) => a + b, 0)
|
|
145
|
+
: 0).reduce((a, b) => a + b, 0)
|
|
146
|
+
const economicDistance = economicRPMSections.map(a => a.length > 1
|
|
147
|
+
? calculateDistance(a)
|
|
148
|
+
: 0).reduce((a, b) => a + b, 0)
|
|
149
|
+
const economicConsumption = economicRPMSections.map(a => a.length > 1
|
|
150
|
+
? a[a.length - 1].attributes.fuelUsed - a[0].attributes.fuelUsed
|
|
151
|
+
: 0).reduce((a, b) => a + (b || 0), 0)
|
|
152
|
+
|
|
153
|
+
const hardBreaking = deviceRoute.filter(p => p.attributes.alarm === 'hardBreaking').length
|
|
154
|
+
const hardAcceleration = deviceRoute.filter(p => p.attributes.alarm === 'hardAcceleration').length
|
|
138
155
|
|
|
139
156
|
return {
|
|
140
157
|
drivingTime: drivingTime / 1000,
|
|
141
158
|
idleTime: idleTime / 1000,
|
|
142
159
|
cruiseControlTime: 0,
|
|
143
|
-
economicTime:
|
|
144
|
-
highEngineRPM:
|
|
160
|
+
economicTime: economicTime / 1000,
|
|
161
|
+
highEngineRPM: highEngineRPM / 1000,
|
|
145
162
|
hardBreaking,
|
|
146
163
|
hardAcceleration,
|
|
147
164
|
drivingConsumption,
|
|
148
165
|
idleConsumption,
|
|
149
166
|
cruiseControlConsumption: 0,
|
|
150
|
-
economicConsumption
|
|
167
|
+
economicConsumption,
|
|
151
168
|
drivingDistance,
|
|
152
169
|
cruiseControlDistance: 0,
|
|
153
|
-
economicDistance
|
|
170
|
+
economicDistance
|
|
154
171
|
}
|
|
155
172
|
}
|
|
156
173
|
}
|
|
@@ -170,4 +187,24 @@ function getRowData (index, device, description, time, consumption, distance, in
|
|
|
170
187
|
}
|
|
171
188
|
}
|
|
172
189
|
|
|
190
|
+
function calculateRPMSections (route, min, max) {
|
|
191
|
+
const sections = []
|
|
192
|
+
let newSection = true
|
|
193
|
+
route.forEach(p => {
|
|
194
|
+
const rpm = p.attributes.rpm
|
|
195
|
+
if ((!min || rpm > min) && (!max || rpm < max)) {
|
|
196
|
+
if (newSection) {
|
|
197
|
+
sections.push([p])
|
|
198
|
+
} else {
|
|
199
|
+
sections[sections.length - 1].push(p)
|
|
200
|
+
}
|
|
201
|
+
newSection = false
|
|
202
|
+
} else {
|
|
203
|
+
newSection = true
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
return sections
|
|
208
|
+
}
|
|
209
|
+
|
|
173
210
|
exports.createPerformanceReport = createPerformanceReport
|
|
@@ -58,4 +58,18 @@ describe('activity report', function () {
|
|
|
58
58
|
console.log(device)
|
|
59
59
|
assert.equal(device.summary[0].convertedSpentFuel, 168.6)
|
|
60
60
|
}, 800000)
|
|
61
|
+
// eslint-disable-next-line no-undef
|
|
62
|
+
it('Activity check fuel consumption group by day', async () => {
|
|
63
|
+
const report = await getReports()
|
|
64
|
+
const userData = await report.getUserData()
|
|
65
|
+
userData.groupByDay = true
|
|
66
|
+
userData.devices = userData.devices.filter(d => d.id === 69114)
|
|
67
|
+
const data = await report.activityReport(new Date(2023, 5, 11, 0, 0, 0, 0),
|
|
68
|
+
new Date(2023, 6, 11, 23, 59, 59, 0),
|
|
69
|
+
userData)
|
|
70
|
+
assert.equal(data.length, 1)
|
|
71
|
+
const device = data[0].devices.find(d => d.device.id === 69114)
|
|
72
|
+
console.log(device)
|
|
73
|
+
assert.equal(device.summary.reduce((a, b) => a + b.convertedSpentFuel, 0), 168.79999999999995)
|
|
74
|
+
}, 800000)
|
|
61
75
|
})
|
|
@@ -10,13 +10,14 @@ describe('performance', function () {
|
|
|
10
10
|
const userData = await report.getUserData()
|
|
11
11
|
userData.devices = userData.devices.filter(d => d.id === 22326)
|
|
12
12
|
const data = await createPerformanceReport(
|
|
13
|
-
new Date(Date.UTC(2023,
|
|
14
|
-
new Date(Date.UTC(2023,
|
|
13
|
+
new Date(Date.UTC(2023, 6, 1, 0, 0, 0, 0)),
|
|
14
|
+
new Date(Date.UTC(2023, 6, 17, 23, 59, 59, 0)),
|
|
15
15
|
userData,
|
|
16
16
|
report.traccar)
|
|
17
|
-
|
|
18
|
-
assert.equal(data[0].
|
|
19
|
-
assert.equal(
|
|
17
|
+
console.log(data)
|
|
18
|
+
assert.equal(data[0].consumption, 19.799999999999997)
|
|
19
|
+
assert.equal(data[0].distance, 326.7657)
|
|
20
|
+
assert.equal(convertMS(data[1].time * 1000, false), '08:19')
|
|
20
21
|
}, 8000000)
|
|
21
22
|
|
|
22
23
|
// eslint-disable-next-line no-undef
|
package/src/trip-report.js
CHANGED
|
@@ -19,6 +19,7 @@ const { getIdleEvents } = require('./util/route')
|
|
|
19
19
|
const { reportByDriver, getDriverName, getDriverData } = require('./util/driver')
|
|
20
20
|
const { getNearestPOIs } = require('./util/geofence')
|
|
21
21
|
const { parallel } = require('./util/parallel')
|
|
22
|
+
const { calculateConsumption } = require('./util/fuel')
|
|
22
23
|
|
|
23
24
|
const fileName = 'TripReport'
|
|
24
25
|
|
|
@@ -171,7 +172,7 @@ function processDevices (from, to, devices, data, userData, traccar) {
|
|
|
171
172
|
|
|
172
173
|
if ((deviceRoute[0].protocol === 'teltonika' && deviceRoute.some(r => r.attributes.fuel)) ||
|
|
173
174
|
automaticReports.deviceWithFuelInfo(d)) {
|
|
174
|
-
trip.fuelConsumption = trip
|
|
175
|
+
trip.fuelConsumption = calculateConsumption(d, { trips: [trip], stops: (stop ? [stop] : []), route: deviceRoute })
|
|
175
176
|
trip.avgFuelConsumption = trip.totalKms > 0 ? trip.fuelConsumption * 100 / trip.totalKms : 0
|
|
176
177
|
}
|
|
177
178
|
|
package/src/util/fuel.js
CHANGED
|
@@ -22,5 +22,48 @@ function getRefuelingLiters (d, position, diff) {
|
|
|
22
22
|
return Math.round(diff * d.attributes.fuel_tank_capacity / 100)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function calculateConsumption (d, data, avgConsumption) {
|
|
26
|
+
if (useOdooFuelData(d, data.route)) {
|
|
27
|
+
return (avgConsumption.byKms * (data.trips.reduce((a, b) => a + b.distance, 0) / 1000) / 100)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const withFuelUsed = data.route && data.route.find(p => p.attributes.fuelUsed)
|
|
31
|
+
|
|
32
|
+
if (data.summary) {
|
|
33
|
+
return calculateSpentFuel(data.summary.spentFuel, d, withFuelUsed)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (data.trips && data.stops) {
|
|
37
|
+
const spentFuel = data.trips.reduce((a, b) => a + b.spentFuel, 0) + data.stops.reduce((a, b) => a + b.spentFuel, 0)
|
|
38
|
+
return calculateSpentFuel(spentFuel, d, withFuelUsed)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (data.route && data.route.length > 1 && data.route[0].attributes.fuelUsed) {
|
|
42
|
+
return data.route[data.route.length - 1].attributes.fuelUsed - data.route[0].attributes.fuelUsed
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function calculateSpentFuel (value, device, withFuelUsed) {
|
|
47
|
+
if (!value) { return value }
|
|
48
|
+
|
|
49
|
+
if (device.attributes.xpert) {
|
|
50
|
+
return withFuelUsed ? value : (value * device.attributes.fuel_tank_capacity) / 100
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (device.attributes.fuel_low_threshold && device.attributes.fuel_high_threshold) {
|
|
54
|
+
const valueSignalCheck = value * fuelSignalInverter(device)
|
|
55
|
+
const valuePercentage = (valueSignalCheck * 100) / Math.abs(device.attributes.fuel_low_threshold - device.attributes.fuel_high_threshold)
|
|
56
|
+
return Math.round((valuePercentage * device.attributes.fuel_tank_capacity) / 100)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return value
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function useOdooFuelData (d, route) {
|
|
63
|
+
return route && route.length && !route[0].attributes.fuel && d.attributes.odooId
|
|
64
|
+
}
|
|
65
|
+
|
|
25
66
|
exports.calculateFuelDiff = calculateFuelDiff
|
|
26
67
|
exports.getRefuelingLiters = getRefuelingLiters
|
|
68
|
+
exports.calculateConsumption = calculateConsumption
|
|
69
|
+
exports.useOdooFuelData = useOdooFuelData
|