fleetmap-reports 1.0.956 → 1.0.958

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.956",
3
+ "version": "1.0.958",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -182,5 +182,15 @@ function Reports (config, axios, cookieJar) {
182
182
  this.stopReportToExcel = (userData, reportData) => {
183
183
  return require('./stop-report').exportStopReportToExcel(userData, reportData)
184
184
  }
185
+
186
+ this.performanceReport = (from, to, userData) => {
187
+ return require('./partnerReports/performance-report').createPerformanceReport(from, to, userData, this.traccar)
188
+ }
189
+ this.performanceReportToPDF = (userData, reportData) => {
190
+ return require('./partnerReports/performance-report').exportPerformanceReportToPDF(userData, reportData)
191
+ }
192
+ this.performanceReportToExcel = (userData, reportData) => {
193
+ return require('./partnerReports/performance-report').exportPerformanceReportToExcel(userData, reportData)
194
+ }
185
195
  }
186
196
  module.exports = Reports
@@ -2,7 +2,11 @@ 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
+ const { calculateDistance, getTranslations, convertMS } = require('../util/utils')
6
+ const { addTable } = require('../util/pdfDocument')
7
+ const jsPDF = require('jspdf')
8
+ const { getStyle } = require('../reportStyle')
9
+ const { getUserPartner } = require('fleetmap-partners')
6
10
 
7
11
  async function createPerformanceReport (from, to, userData, traccar) {
8
12
  const reportData = []
@@ -214,4 +218,134 @@ function calculateRPMSections (route, min, max) {
214
218
  return sections
215
219
  }
216
220
 
221
+ function exportPerformanceReportToPDF (userData, reportData) {
222
+ const translations = getTranslations(userData)
223
+
224
+ const headers = [
225
+ translations.report.vehicle,
226
+ 'Utilisation',
227
+ 'Conduite',
228
+ 'Ralenti',
229
+ 'Totale (L)',
230
+ 'Conduite (L)',
231
+ 'Ralenti (L)',
232
+ 'Conduite (Km)',
233
+ 'Économique',
234
+ 'Économique (L)',
235
+ 'Économique (Km)',
236
+ 'Cruise Control',
237
+ 'Cruise Control (L)',
238
+ 'Cruise Control (Km)',
239
+ 'Tour moteur élevé',
240
+ 'Accéleration brusque (Sum)',
241
+ 'Freinage brusque (Sum)',
242
+ 'Virages brusque'
243
+ ]
244
+
245
+ const data = []
246
+ reportData.forEach(d => {
247
+ const row = [
248
+ d.device,
249
+ convertMS((d.drivingTime + d.idleTime) * 1000),
250
+ convertMS(d.drivingTime * 1000),
251
+ convertMS(d.idleTime * 1000),
252
+ d.drivingConsumption + d.idleConsumption,
253
+ d.drivingConsumption,
254
+ d.idleConsumption,
255
+ d.drivingDistance.toFixed(2),
256
+ convertMS(d.economicTime * 1000),
257
+ d.economicConsumption.toFixed(1),
258
+ d.economicDistance.toFixed(2),
259
+ convertMS(d.cruiseControlTime * 1000),
260
+ d.cruiseControlConsumption.toFixed(1),
261
+ d.cruiseControlDistance.toFixed(2),
262
+ convertMS(d.highEngineRPM * 1000),
263
+ d.hardAcceleration,
264
+ d.hardBraking,
265
+ d.hardCornering
266
+ ]
267
+ data.push(row)
268
+ })
269
+
270
+ const doc = new jsPDF.jsPDF('l')
271
+ const style = getStyle(getUserPartner(userData.user))
272
+
273
+ const footValues = []
274
+
275
+ doc.setFontSize(11)
276
+ doc.text(new Date(userData.from).toLocaleString() + ' - ' + new Date(userData.to).toLocaleString(), 20, 33)
277
+
278
+ style.headerFontSize = 8
279
+ style.bodyFontSize = 7
280
+ const columnStyles = {}
281
+ for (let i = 1; i < 18; i++) {
282
+ columnStyles[i] = { halign: 'right' }
283
+ }
284
+ addTable(doc, headers, data, footValues, style, 40, columnStyles)
285
+ return doc
286
+ }
287
+
288
+ function exportPerformanceReportToExcel (userData, reportData) {
289
+ const translations = getTranslations(userData)
290
+
291
+ const settings = {
292
+ sheetName: 'Rapport de Performance', // The name of the sheet
293
+ fileName: 'RapportPerformance' // The name of the spreadsheet
294
+ }
295
+
296
+ const headers = [{ label: translations.report.vehicle, value: 'name' },
297
+ { label: 'Totale Utilisation', value: 'totalUse' },
298
+ { label: 'Conduite', value: 'drivingTime' },
299
+ { label: 'Ralenti', value: 'idleTime' },
300
+ { label: 'Totale (L)', value: 'totalConsumption' },
301
+ { label: 'Conduite (L)', value: 'drivingConsumption' },
302
+ { label: 'Ralenti (L)', value: 'idleConsumption' },
303
+ { label: 'Conduite (Km)', value: 'drivingDistance' },
304
+ { label: 'Économique', value: 'economicTime' },
305
+ { label: 'Économique (L)', value: 'economicConsumption' },
306
+ { label: 'Économique (Km)', value: 'economicDistance' },
307
+ { label: 'Cruise Control', value: 'cruiseControlTime' },
308
+ { label: 'Cruise Control (L)', value: 'cruiseControlConsumption' },
309
+ { label: 'Cruise Control (Km)', value: 'cruiseControlDistance' },
310
+ { label: 'Tour moteur élevé', value: 'highEngineRPM' },
311
+ { label: 'Accéleration brusque (Sum)', value: 'hardAcceleration' },
312
+ { label: 'Freinage brusque (Sum)', value: 'hardBraking' },
313
+ { label: 'Virages brusque', value: 'hardCornering' }]
314
+
315
+ let data = []
316
+ data = data.concat([{}])
317
+ /*data = data.concat(reportData.map(d => {
318
+ return {
319
+ name: d.device,
320
+ totalUse: convertMS((d.drivingTime + d.idleTime) * 1000),
321
+ drivingTime: convertMS(d.drivingTime * 1000),
322
+ idleTime: convertMS(d.idleTime * 1000),
323
+ totalConsumption: d.drivingConsumption + d.idleConsumption,
324
+ drivingConsumption: d.drivingConsumption,
325
+ idleConsumption: d.idleConsumption,
326
+ drivingDistance: d.drivingDistance,
327
+ economicTime: convertMS(d.economicTime * 1000),
328
+ economicConsumption: d.economicConsumption,
329
+ economicDistance: d.economicDistance,
330
+ cruiseControlTime: convertMS(d.cruiseControlTime * 1000),
331
+ cruiseControlConsumption: d.cruiseControlConsumption,
332
+ cruiseControlDistance: d.cruiseControlDistance,
333
+ highEngineRPM: d.highEngineRPM,
334
+ hardAcceleration: d.hardAcceleration,
335
+ hardBraking: d.hardBraking,
336
+ hardCornering: d.hardCornering
337
+ }
338
+ }))*/
339
+
340
+ console.log(data)
341
+
342
+ return {
343
+ headers,
344
+ data,
345
+ settings
346
+ }
347
+ }
348
+
217
349
  exports.createPerformanceReport = createPerformanceReport
350
+ exports.exportPerformanceReportToPDF = exportPerformanceReportToPDF
351
+ exports.exportPerformanceReportToExcel = exportPerformanceReportToExcel
@@ -0,0 +1,23 @@
1
+ const { getReports } = require('./index')
2
+ const assert = require('assert')
3
+ const { convertMS } = require('../util/utils')
4
+ const { createGPSJumpReport } = require('../partnerReports/gpsjump-report')
5
+
6
+ // eslint-disable-next-line no-undef
7
+ describe('gpsjump', function () {
8
+ // eslint-disable-next-line no-undef
9
+ it('gpsjump report', async () => {
10
+ const report = await getReports()
11
+ const userData = await report.getUserData()
12
+ userData.devices = userData.devices.filter(d => d.id === 22326)
13
+ const data = await createGPSJumpReport(
14
+ new Date(Date.UTC(2023, 6, 1, 0, 0, 0, 0)),
15
+ new Date(Date.UTC(2023, 6, 17, 23, 59, 59, 0)),
16
+ userData,
17
+ report.traccar)
18
+ console.log(data)
19
+ assert.equal(data[0].consumption, 19.799999999999997)
20
+ assert.equal(data[0].distance, 326.7657)
21
+ assert.equal(convertMS(data[1].time * 1000, false), '08:19')
22
+ }, 8000000)
23
+ })
@@ -22,13 +22,15 @@ function getNearestPOIs (long, lat, geofences) {
22
22
  .filter(g => g && g.area.startsWith('CIRCLE'))
23
23
  .map(g => {
24
24
  const str = g.area.substring('CIRCLE ('.length, g.area.indexOf(','))
25
+ const radius = g.area.substring(g.area.indexOf(',') + 1, g.area.indexOf(')'))
25
26
  const coord = str.trim().split(' ')
26
27
  return {
27
28
  p: g,
28
- distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), long, lat))
29
+ distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), long, lat)),
30
+ r: parseFloat(radius)
29
31
  }
30
32
  })
31
- return distance.filter(a => a.distance < 100).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
33
+ return distance.filter(a => a.distance < a.r).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
32
34
  }
33
35
  exports.getNearestPOIs = getNearestPOIs
34
36
 
@@ -270,6 +270,19 @@ function getAnyNextIn (outDate, alerts, deviceRoute) {
270
270
  }
271
271
  }
272
272
 
273
+ function getAnyLastExit (inDate, alerts, deviceRoute) {
274
+ const next = alerts
275
+ .filter(a => a.type === 'geofenceExit')
276
+ .find(a => new Date(a.position.fixTime).getTime() < inDate)
277
+
278
+ if (next && !alerts.filter(a => a.type === 'geofenceExit' &&
279
+ new Date(a.position.fixTime).getTime() < inDate &&
280
+ new Date(a.position.fixTime).getTime() > new Date(next.position.fixTime).getTime()).length) {
281
+ return (next && next.position && new Date(next.position.fixTime).getTime()) ||
282
+ new Date(deviceRoute.slice(-1)[0].fixTime).getTime()
283
+ }
284
+ }
285
+
273
286
  function calculateDistanceIn (zoneInOutDayData, deviceRoute, dayRoute, fromByDay, toByDay, to, device) {
274
287
  let distanceIn = zoneInOutDayData.length && dayRoute.length ? zoneInOutDayData.reduce((a, b) => a + (b.distanceIn || 0), 0) : 0
275
288
 
@@ -297,7 +310,7 @@ function calculateDistanceOut (zoneInOutDayData, dayRoute, fromByDay, toByDay, f
297
310
  const dataInsideDay = zoneInOutDayData.filter(z => z.outTime && new Date(z.outTime.fixTime) < toByDay)
298
311
  let distanceOut = dataInsideDay.reduce((a, b) => a + (b[field] || 0), 0)
299
312
 
300
- if (zoneInOutDayData[0].inTime && new Date(zoneInOutDayData[0].inTime.fixTime) > fromByDay) {
313
+ if (zoneInOutDayData[0].inTime && new Date(zoneInOutDayData[0].inTime.fixTime) > fromByDay && (field !== 'distanceOutAny' || zoneInOutDayData[0].anyLastExit)) {
301
314
  // Add distanceOut before the first entry
302
315
  const routeOut = dayRoute.filter(p =>
303
316
  new Date(p.fixTime).getTime() < new Date(zoneInOutDayData[0].inTime.fixTime).getTime() &&
@@ -306,7 +319,8 @@ function calculateDistanceOut (zoneInOutDayData, dayRoute, fromByDay, toByDay, f
306
319
  distanceOut = distanceOut + calculateDistance(routeOut, device.attributes['report.ignoreOdometer'])
307
320
  }
308
321
 
309
- if (zoneInOutDayData[zoneInOutDayData.length - 1].outTime && new Date(zoneInOutDayData[zoneInOutDayData.length - 1].outTime.fixTime) < toByDay) {
322
+ if (zoneInOutDayData[zoneInOutDayData.length - 1].outTime && new Date(zoneInOutDayData[zoneInOutDayData.length - 1].outTime.fixTime) < toByDay && (field !== 'distanceOutAny' || zoneInOutDayData[zoneInOutDayData.length - 1].anyNextIn)) {
323
+ // Add distanceOut after last exit
310
324
  distanceOut = distanceOut - zoneInOutDayData[zoneInOutDayData.length - 1][field]
311
325
  const routeOut = dayRoute.filter(p =>
312
326
  new Date(p.fixTime) >= new Date(zoneInOutDayData[zoneInOutDayData.length - 1].outTime.fixTime).getTime() &&
@@ -331,6 +345,10 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
331
345
  if (a.type === 'geofenceEnter') {
332
346
  const driver = userData.drivers.find(d => a.position.attributes && d.uniqueId === a.position.attributes.driverUniqueId)
333
347
  a.position.driverName = driver ? driver.name : ''
348
+ if (Object.keys(zoneInData).length === 0) {
349
+ a.anyLastExit = getAnyLastExit(new Date(a.position.fixTime).getTime(), alerts, deviceRoute)
350
+ }
351
+
334
352
  zoneInData[a.geofenceId] = a
335
353
  } else if (a.type === 'geofenceExit') {
336
354
  const geofence = userData.geofences.find(g => g.id === a.geofenceId)
@@ -368,6 +386,8 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
368
386
  distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
369
387
  distanceOut,
370
388
  distanceOutAny,
389
+ anyNextIn,
390
+ anyLastExit: a.anyLastExit,
371
391
  geofenceName: geofence.name,
372
392
  geofenceId: geofence.id,
373
393
  stopped: routeIn.filter(p => !p.attributes.ignition).length > 0,
@@ -389,7 +409,9 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
389
409
  distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
390
410
  driverName: '',
391
411
  distanceOut,
392
- distanceOutAny
412
+ distanceOutAny,
413
+ anyNextIn,
414
+ anyLastExit: a.anyLastExit
393
415
  })
394
416
  }
395
417
  }
@@ -417,7 +439,7 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
417
439
  }
418
440
 
419
441
  if (!zoneInOutData.length && userData.groupByDay) {
420
- const geofenceIn = alerts.find(a => a.type === 'geofenceIn')
442
+ const geofenceIn = alerts.find(a => a.type === 'geofenceEnter')
421
443
  zoneInOutData.push({
422
444
  distanceIn: geofenceIn ? calculateDistance(deviceRoute, device.attributes['report.ignoreOdometer']) : 0,
423
445
  distanceOut: !geofenceIn ? calculateDistance(deviceRoute, device.attributes['report.ignoreOdometer']) : 0,