fleetmap-reports 1.0.957 → 1.0.959

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.957",
3
+ "version": "1.0.959",
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
+ })
@@ -61,4 +61,21 @@ describe('zones', function () {
61
61
  assert.equal(first.days[0].distanceOut, 0)
62
62
  assert.equal(first.days[2].distanceOut, 0)
63
63
  }, 4000000)
64
+
65
+ it('works with casais zones in columns 2', async () => {
66
+ const report = await getReports()
67
+ const userData = await report.getUserData()
68
+ userData.zonesByColumn = true
69
+ userData.devices = userData.devices.filter(d => d.id === 81201)
70
+ userData.geofences = userData.geofences.filter(g => g.name === 'baliza 1 - raio verde ' ||
71
+ g.name === 'baliza 2 - raio amarelo')
72
+ userData.onlyWithKmsOut = false
73
+ const result = await report.zoneReport(
74
+ new Date(Date.UTC(2023, 7, 7, 0, 0, 0, 0)),
75
+ new Date(Date.UTC(2023, 7, 7, 23, 59, 59, 0)),
76
+ userData)
77
+ const first = result[0].devices[0]
78
+ console.log(first)
79
+ assert.equal(first.days[0].distanceOut, 554.6037095121401)
80
+ }, 4000000)
64
81
  })
@@ -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 === 'geofenceEnter' &&
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() &&
@@ -322,7 +336,7 @@ function calculateDistanceOut (zoneInOutDayData, dayRoute, fromByDay, toByDay, f
322
336
 
323
337
  function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
324
338
  const zoneInOutData = []
325
- const zoneInData = {}
339
+ let zoneInData = []
326
340
 
327
341
  alerts.forEach(a => {
328
342
  if (!a.position) {
@@ -331,7 +345,12 @@ 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 : ''
334
- zoneInData[a.geofenceId] = a
348
+ if (zoneInData.length === 0) {
349
+ const anyLastExist = getAnyLastExit(new Date(a.position.fixTime).getTime(), alerts, deviceRoute)
350
+ a.anyLastExit = anyLastExist || from
351
+ }
352
+
353
+ zoneInData.push(a)
335
354
  } else if (a.type === 'geofenceExit') {
336
355
  const geofence = userData.geofences.find(g => g.id === a.geofenceId)
337
356
  if (!geofence) {
@@ -346,34 +365,41 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
346
365
  const totalOutTime = nextIn - outDate
347
366
  const distanceOut = calculateDistance(routeAfterOut, device.attributes['report.ignoreOdometer'])
348
367
 
349
- const anyNextIn = getAnyNextIn(outDate, alerts, deviceRoute)
350
- const routeAfterOutAndBeforeAnyNextIn = deviceRoute.filter(p =>
351
- new Date(p.fixTime).getTime() >= outDate &&
352
- new Date(p.fixTime).getTime() <= anyNextIn
353
- )
354
- const distanceOutAny = Object.keys(zoneInData).length < 2 ? Math.round(calculateDistance(routeAfterOutAndBeforeAnyNextIn, device.attributes['report.ignoreOdometer'])) : 0
368
+ let anyNextIn
369
+ let distanceOutAny = 0
370
+ if (zoneInData.length < 2) {
371
+ anyNextIn = getAnyNextIn(outDate, alerts, deviceRoute)
372
+ const routeAfterOutAndBeforeAnyNextIn = deviceRoute.filter(p =>
373
+ new Date(p.fixTime).getTime() >= outDate &&
374
+ new Date(p.fixTime).getTime() <= anyNextIn
375
+ )
376
+ distanceOutAny = zoneInData.length < 2 ? Math.round(calculateDistance(routeAfterOutAndBeforeAnyNextIn, device.attributes['report.ignoreOdometer'])) : 0
377
+ }
355
378
 
356
- if (zoneInData[a.geofenceId]) {
357
- const totalInTime = new Date(a.position.fixTime).getTime() - new Date(zoneInData[a.geofenceId].position.fixTime).getTime()
358
- const inDate = new Date(zoneInData[a.geofenceId].position.fixTime).getTime()
379
+ const inData = zoneInData.find(z => z.geofenceId === a.geofenceId)
380
+ if (inData) {
381
+ const totalInTime = new Date(a.position.fixTime).getTime() - new Date(inData.position.fixTime).getTime()
382
+ const inDate = new Date(inData.position.fixTime).getTime()
359
383
  const routeIn = deviceRoute.filter(p =>
360
384
  new Date(p.fixTime).getTime() >= inDate &&
361
385
  new Date(p.fixTime).getTime() < outDate
362
386
  )
363
387
  zoneInOutData.push({
364
- inTime: zoneInData[a.geofenceId].position,
388
+ inTime: inData.position,
365
389
  outTime: a.position,
366
390
  totalInTime,
367
391
  totalOutTime,
368
392
  distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
369
393
  distanceOut,
370
394
  distanceOutAny,
395
+ anyNextIn,
396
+ anyLastExit: a.anyLastExit,
371
397
  geofenceName: geofence.name,
372
398
  geofenceId: geofence.id,
373
399
  stopped: routeIn.filter(p => !p.attributes.ignition).length > 0,
374
- driverName: zoneInData[a.geofenceId].position.driverName
400
+ driverName: inData.position.driverName
375
401
  })
376
- delete zoneInData[a.geofenceId]
402
+ zoneInData = zoneInData.filter(z => z.geofenceId === a.geofenceId)
377
403
  } else {
378
404
  const totalInTime = new Date(a.position.fixTime).getTime() - from.getTime()
379
405
  const routeIn = deviceRoute.filter(p =>
@@ -389,35 +415,36 @@ function analyseAlerts (alerts, deviceRoute, userData, from, to, device) {
389
415
  distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
390
416
  driverName: '',
391
417
  distanceOut,
392
- distanceOutAny
418
+ distanceOutAny,
419
+ anyNextIn,
420
+ anyLastExit: a.anyLastExit
393
421
  })
394
422
  }
395
423
  }
396
424
  })
397
425
 
398
- for (const i in zoneInData) {
399
- if (zoneInData[i]) {
400
- const geofence = userData.geofences.find(g => g.id === zoneInData[i].geofenceId)
401
- if (geofence) {
402
- const totalInTime = to.getTime() - new Date(zoneInData[i].position.fixTime).getTime()
403
- const routeIn = deviceRoute.filter(p =>
404
- new Date(p.fixTime).getTime() >= new Date(zoneInData[i].position.fixTime).getTime() &&
426
+ for (const inData of zoneInData) {
427
+ const geofence = userData.geofences.find(g => g.id === inData.geofenceId)
428
+ if (geofence) {
429
+ const totalInTime = to.getTime() - new Date(inData.position.fixTime).getTime()
430
+ const routeIn = deviceRoute.filter(p =>
431
+ new Date(p.fixTime).getTime() >= new Date(inData.position.fixTime).getTime() &&
405
432
  new Date(p.fixTime).getTime() < to.getTime()
406
- )
407
- zoneInOutData.push({
408
- inTime: zoneInData[i].position,
409
- totalInTime,
410
- distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
411
- geofenceName: geofence.name,
412
- geofenceId: geofence.id,
413
- driverName: zoneInData[i].position.driverName
414
- })
415
- }
433
+ )
434
+ zoneInOutData.push({
435
+ inTime: inData.position,
436
+ totalInTime,
437
+ distanceIn: calculateDistance(routeIn, device.attributes['report.ignoreOdometer']),
438
+ geofenceName: geofence.name,
439
+ geofenceId: geofence.id,
440
+ driverName: inData.position.driverName,
441
+ anyLastExit: inData.anyLastExit
442
+ })
416
443
  }
417
444
  }
418
445
 
419
446
  if (!zoneInOutData.length && userData.groupByDay) {
420
- const geofenceIn = alerts.find(a => a.type === 'geofenceIn')
447
+ const geofenceIn = alerts.find(a => a.type === 'geofenceEnter')
421
448
  zoneInOutData.push({
422
449
  distanceIn: geofenceIn ? calculateDistance(deviceRoute, device.attributes['report.ignoreOdometer']) : 0,
423
450
  distanceOut: !geofenceIn ? calculateDistance(deviceRoute, device.attributes['report.ignoreOdometer']) : 0,