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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetmap-reports",
3
- "version": "1.0.777",
3
+ "version": "1.0.779",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -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 = automaticReports.calculateSpentFuel(summaryCurrentDay.spentFuel, d)
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 = automaticReports.calculateSpentFuel(s.spentFuel, d)
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
@@ -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, false, false)
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 (tripsData.length === 0) {
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 = tripsData.filter(t => t.deviceId === d.id)
42
- const route = routeData.filter(r => r.deviceId === d.id)
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(userData, d, day, odooAvgConsumption, { trips: dayTrips, route: groupedRouteByDay.get(day) })
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 hardBreaking = deviceRoute.filter(p => p.attributes.io253 === 2).length
137
- const hardAcceleration = deviceRoute.filter(p => p.attributes.io253 === 1).length
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: 0,
144
- highEngineRPM: 0,
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: 0,
167
+ economicConsumption,
151
168
  drivingDistance,
152
169
  cruiseControlDistance: 0,
153
- economicDistance: 0
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, 5, 10, 0, 0, 0, 0)),
14
- new Date(Date.UTC(2023, 5, 20, 23, 59, 59, 0)),
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
- assert.equal(data[0].consumption, 21.8)
18
- assert.equal(data[0].distance, 381.29861000000005)
19
- assert.equal(convertMS(data[1].time * 1000, false), '10:30')
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
@@ -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.spentFuel + (stop ? stop.spentFuel : 0)
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