fleetmap-reports 1.0.288 → 1.0.292

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.
@@ -1,158 +1,151 @@
1
- const automaticReports = require("./automaticReports");
2
- const messages = require('../lang');
3
- const jsPDF = require('jspdf');
4
- const {convertMS} = require("./util/utils");
5
- const autotable = require('jspdf-autotable');
6
- const {coordsDistance} = require("./util/utils");
7
- const reportStyle = require("./reportStyle")
8
- const drivers = require("./util/driver");
1
+ const automaticReports = require("./automaticReports")
2
+ const messages = require('../lang')
3
+ const jsPDF = require('jspdf')
4
+ const {convertMS, convertToLocaleString, convertToLocaleDateString, convertToLocaleTimeString} = require("./util/utils")
5
+ require('jspdf-autotable')
6
+ const drivers = require("./util/driver")
7
+ const {getUserPartner} = require("fleetmap-partners")
8
+ const {headerFromUser, addTable} = require("./util/pdfDocument")
9
+ const {getStyle} = require("./reportStyle")
10
+ const traccar = require("./util/traccar")
11
+ const trips = require("./util/trips");
12
+ const {isInsideTimetable, addNearestPOIs} = require("./util/trips");
13
+
9
14
 
10
15
  let traccarInstance
16
+ let userData
11
17
 
12
18
  const fileName = 'TripReport'
13
19
 
14
- async function createTripReport(from, to, userData, traccar) {
20
+ async function createTripReport(from, to, reportUserData, traccar) {
15
21
  console.log('Create TripReport')
16
-
22
+ userData = reportUserData
17
23
  traccarInstance = traccar
18
24
  const reportData = []
19
25
 
20
- if(userData.byDriver){
21
- const allData = await createTripReportByDriver(from, to, userData)
22
- reportData.push(allData)
26
+ if (userData.byDriver) {
27
+ console.log("ByDriver")
28
+ const report = await createTripReportByDriver(from, to)
29
+ reportData.push(report)
23
30
  }
24
- else if(userData.byGroup){
31
+ else if (userData.byGroup) {
25
32
  console.log("ByGroup")
26
- for (const g of userData.groups) {
27
- const devices = userData.devices.filter(d => d.groupId === g.id)
28
- console.log(g.name + ' devices:' + devices.length)
29
- if(devices.length > 0) {
30
- const groupData = {
31
- devices: [],
32
- group: g,
33
- xpert: devices.filter(d => d.attributes.xpert).length > 0
34
- }
33
+ const allData = await createTripReportByGroup(from, to)
34
+ reportData.push(...allData)
35
+ } else {
36
+ console.log("ByDevice")
37
+ const report = await createTripReportByDevice(from, to)
38
+ reportData.push(report)
39
+ }
35
40
 
36
- const response = await traccarInstance.reports.reportsTripsGet(from, to, null, [g.id])
37
- const data = response.data
41
+ return reportData
42
+ }
38
43
 
39
- const stopsResponse = await traccarInstance.reports.reportsStopsGet(from, to, null, [g.id])
40
- const stopsData = stopsResponse.data
44
+ async function createTripReportByDevice(from, to) {
45
+ const devices = userData.devices
46
+ const allData = {
47
+ devices: [],
48
+ xpert: devices.filter(d => d.attributes.xpert).length > 0
49
+ }
41
50
 
42
- devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
51
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
43
52
 
44
- if (data.length > 0) {
53
+ const devicesToSlice = devices.slice()
54
+ const data = await traccar.getTrips(traccarInstance, from, to, devicesToSlice)
55
+ const stopsData = await traccar.getStops(traccarInstance, from, to, devicesToSlice)
45
56
 
46
- console.log('Trips:' + data.length)
47
- groupData.devices = processDevices(from, to, devices, data, stopsData)
57
+ console.log('Trips:' + data.length)
48
58
 
49
- reportData.push(groupData)
50
- }
51
- }
52
- }
59
+ if (data.length > 0) {
60
+ await trips.checkTripsKms(traccarInstance, from, to,[], data, devices)
61
+ allData.devices = processDevices(from, to, devices, data, stopsData)
53
62
  }
54
63
 
55
- const groupIds = userData.groups.map(g => g.id)
56
- const withoutGroupDevices = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
64
+ return allData
65
+ }
57
66
 
58
- const allData = {
59
- devices: [],
60
- xpert: withoutGroupDevices.filter(d => d.attributes.xpert).length > 0
61
- }
67
+ async function createTripReportByGroup(from, to) {
68
+ const reportData = []
69
+ for (const g of userData.groups) {
70
+ const devices = userData.devices.filter(d => d.groupId === g.id)
71
+ console.log(g.name + ' devices:' + devices.length)
72
+ if(devices.length > 0) {
73
+ const groupData = {
74
+ devices: [],
75
+ group: g,
76
+ xpert: devices.filter(d => d.attributes.xpert).length > 0
77
+ }
62
78
 
63
- withoutGroupDevices.sort((a, b) => (a.name > b.name) ? 1 : -1)
64
- const devicesToSlice = withoutGroupDevices.slice()
79
+ const response = await traccarInstance.reports.reportsTripsGet(from, to, null, [g.id])
80
+ const tripsData = response.data
65
81
 
66
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice)
67
- let data = []
68
- let stopsData = []
69
- for (const a of arrayOfArrays) {
70
- const response = await traccarInstance.reports.reportsTripsGet(from, to, a.map(d => d.id))
71
- data = data.concat(response.data)
82
+ const stopsResponse = await traccarInstance.reports.reportsStopsGet(from, to, null, [g.id])
83
+ const stopsData = stopsResponse.data
72
84
 
73
- const stopsResponse = await traccarInstance.reports.reportsStopsGet(from, to, a.map(d => d.id))
74
- stopsData = stopsResponse.data
75
- }
85
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
76
86
 
77
- console.log('Trips:' + data.length)
87
+ if (tripsData.length > 0) {
88
+ console.log('Trips:' + tripsData.length)
89
+ groupData.devices = processDevices(from, to, devices, tripsData, stopsData, userData)
78
90
 
79
- if (data.length === 0) {
80
- return reportData
91
+ reportData.push(groupData)
92
+ }
93
+ }
81
94
  }
82
95
 
83
- allData.devices = processDevices(from, to, withoutGroupDevices, data, stopsData, userData)
96
+ const groupIds = userData.groups.map(g => g.id)
97
+ const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
84
98
 
99
+ const allData = await createTripReportByDevice(from, to, withoutGroupDevices)
85
100
  reportData.push(allData)
86
101
 
87
102
  return reportData
88
103
  }
89
104
 
90
- async function createTripReportByDriver(from, to, userData){
91
-
92
- const deviceIds = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
93
- console.log(deviceIds.length)
94
-
95
- let tripsData = []
96
- if(deviceIds.length > 0) {
97
- const response = await traccarInstance.reports.reportsTripsGet(from, to, deviceIds)
98
- tripsData = response.data
99
- }
105
+ async function createTripReportByDriver(from, to){
106
+ const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
107
+ console.log(devices.length)
100
108
 
101
- const allData = {
102
- drivers: []
109
+ if(!devices.length){
110
+ //Empty report
111
+ return { drivers:[] }
103
112
  }
104
113
 
105
- allData.drivers = processDrivers(from, to, userData.drivers, tripsData)
114
+ const tripsData = await traccar.getTrips(traccarInstance, from, to, devices)
106
115
 
107
- return allData
116
+ return { drivers: processDrivers(from, to, userData.drivers, tripsData)}
108
117
  }
109
118
 
110
- function processDevices(from, to, devices, data, stopsData, userData) {
119
+ function processDevices(from, to, devices, data, stopsData) {
111
120
  const devicesResult = []
112
121
 
113
122
  devices.forEach(d => {
114
- const trips = data.filter(t => t.deviceId === d.id)
123
+ const trips = data.filter(t => t.deviceId === d.id
124
+ && (userData.allWeek || !userData.weekDays || isInsideTimetable(t, userData)))
115
125
  const stops = stopsData.filter(s => s.deviceId === d.id)
116
126
 
117
- trips.forEach(t => {
118
- t.totalKms = t.distance / 1000
127
+ addNearestPOIs(trips, userData)
128
+
129
+ trips.forEach(trip => {
119
130
  if (automaticReports.deviceWithFuelInfo(d)) {
120
- t.fuelConsumption = Math.round((t.spentFuel * d.attributes.fuel_tank_capacity) / 100)
121
- t.avgFuelConsumption = t.totalKms > 0 ? Math.round(t.fuelConsumption * 100 / t.totalKms) : 0
131
+ trip.fuelConsumption = Math.round((trip.spentFuel * d.attributes.fuel_tank_capacity) / 100)
132
+ trip.avgFuelConsumption = trip.totalKms > 0 ? Math.round(trip.fuelConsumption * 100 / trip.totalKms) : 0
122
133
  } else {
123
- t.fuelConsumption = '-'
124
- t.avgFuelConsumption = '-'
134
+ trip.fuelConsumption = '-'
135
+ trip.avgFuelConsumption = '-'
125
136
  }
126
137
 
127
- const distance = userData.geofences
128
- .filter(g => g && g.area.startsWith('CIRCLE'))
129
- .map(g => {
130
- const str = g.area.substring('CIRCLE ('.length, g.area.indexOf(','))
131
- const coord = str.trim().split(' ')
132
- return {
133
- p: g,
134
- distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), t.endLon, t.endLat))
135
- }
136
- })
137
- const nearestPOIs = distance.filter(a => a.distance < 100).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
138
- if (nearestPOIs.length > 0) {
139
- t.endPOIName = nearestPOIs[0].p.name
138
+ const stop = getStop(new Date(trip.startTime), stops)
139
+ if (stop) {
140
+ trip.stopDuration = (new Date(stop.endTime) - new Date(stop.startTime))
141
+ trip.stopEngineHours = stop.engineHours
142
+ } else {
143
+ trip.stopDuration = 0
144
+ trip.stopEngineHours = 0
140
145
  }
141
146
  })
142
147
 
143
148
  if (trips.length > 0) {
144
- trips.forEach(function(trip, index) {
145
- const stop = stops.length+1 > index ? stops[index+1] : null
146
-
147
- if (stop) {
148
- trip.stopDuration = (new Date(stop.endTime) - new Date(stop.startTime))
149
- trip.stopEngineHours = stop.engineHours
150
- } else {
151
- trip.stopDuration = 0
152
- trip.stopEngineHours = 0
153
- }
154
- })
155
-
156
149
  const deviceData = {
157
150
  device: d,
158
151
  from: from,
@@ -180,11 +173,12 @@ function processDrivers(from, to, drivers, data) {
180
173
  console.log(data)
181
174
  const driversResult = []
182
175
  drivers.forEach(d => {
183
- const trips = data.filter(t => t.driverUniqueId === d.uniqueId)
176
+ const trips = data.filter(t => t.driverUniqueId === d.uniqueId
177
+ && (userData.allWeek || !userData.weekDays || isInsideTimetable(t, userData)))
184
178
 
185
- trips.forEach(t => {
186
- t.totalKms = t.distance / 1000
187
- })
179
+ trips.sort((a,b)=>new Date(a.startTime).getTime()-new Date(b.startTime).getTime())
180
+
181
+ addNearestPOIs(trips, userData)
188
182
 
189
183
  if (trips.length > 0) {
190
184
  const driverData = {
@@ -193,22 +187,22 @@ function processDrivers(from, to, drivers, data) {
193
187
  to: to,
194
188
  totalDuration: trips.reduce((a, b) => a + b.duration, 0),
195
189
  totalDistance: trips.reduce((a, b) => a + b.distance, 0),
196
- maxSpeed: trips.reduce((a, b) => {
197
- return a > b.maxSpeed ? a : b.maxSpeed
198
- }, 0),
190
+ maxSpeed: trips.reduce((a, b) => { return a > b.maxSpeed ? a : b.maxSpeed }, 0),
199
191
  trips: trips,
200
192
  }
201
193
  driversResult.push(driverData)
202
194
  }
203
195
  })
196
+ console.log(driversResult)
204
197
 
205
198
  return driversResult
206
199
  }
207
200
 
208
- function exportTripReportToPDF(userData, reportData) {
201
+ async function exportTripReportToPDF(userData, reportData) {
209
202
  console.log('Export to PDF')
210
203
 
211
204
  const lang = userData.user.attributes.lang
205
+ const timezone = userData.user.attributes.timezone
212
206
  const translations = messages[lang] ? messages[lang] : messages['en-GB']
213
207
  const tripsData = userData.byDriver ? reportData.drivers : reportData.devices
214
208
 
@@ -235,29 +229,38 @@ function exportTripReportToPDF(userData, reportData) {
235
229
  }
236
230
 
237
231
  if (tripsData) {
238
- let first = true
239
232
  const doc = new jsPDF.jsPDF('l');
240
- doc.setFontSize(14)
241
- doc.text(translations.report.titleTripReport, 15, 15 )
233
+ await headerFromUser(doc, translations.report.titleTripReport, userData.user)
242
234
 
243
- for(const d of tripsData){
244
- let data = []
235
+ tripsData.forEach(function (d, index) {
236
+ const data = []
245
237
  const name = userData.byDriver ? d.driver.name : deviceName(d.device)
246
238
  const group = userData.byDriver ? userData.groups.find(g => g.drivers.includes(d.id)) : userData.groups.find(g => d.device.groupId === g.id)
247
239
 
248
- let space = 0
249
- if(!first) {
240
+ let space = index === 0 ? 8 : 0
241
+ if(index){
250
242
  doc.addPage()
251
- } else {
252
- first = false
253
- space = 10
254
243
  }
255
- doc.setFontSize(12)
244
+
245
+ doc.setFontSize(13)
256
246
  doc.text(name, 20, space+20 )
257
- doc.setFontSize(10)
247
+ doc.setFontSize(11)
258
248
  doc.text(group ? translations.report.group + ': ' + group.name : '', 200, space+20 )
259
- doc.text(new Date(d.from).toLocaleString() + ' - ' + new Date(d.to).toLocaleString(), 20, space+25 )
260
- doc.text(translations.report.headerStartAddress + ': ' + d.trips[0].startAddress, 20, space+30 )
249
+ doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space+25 )
250
+ if(!userData.allWeek && userData.weekDays) {
251
+ doc.text((userData.weekDays.monday ? ' ' + translations.report.monday + ',' : '')
252
+ + (userData.weekDays.tuesday ? ' ' + translations.report.tuesday + ',' : '')
253
+ + (userData.weekDays.wednesday ? ' ' + translations.report.wednesday + ',' : '')
254
+ + (userData.weekDays.thursday ? ' ' + translations.report.thursday + ',' : '')
255
+ + (userData.weekDays.friday ? ' ' + translations.report.friday + ',' : '')
256
+ + (userData.weekDays.saturday ? ' ' + translations.report.saturday + ',' : '')
257
+ + (userData.weekDays.sunday ? ' ' + translations.report.sunday + ',' : '')
258
+ + ' das '
259
+ + userData.dayHours.startTime + ' - ' + userData.dayHours.endTime, 20, space + 30)
260
+ doc.text(translations.report.headerStartAddress + ': ' + d.trips[0].startAddress, 20, space+40 )
261
+ } else {
262
+ doc.text(translations.report.headerStartAddress + ': ' + d.trips[0].startAddress, 20, space+35 )
263
+ }
261
264
 
262
265
  d.trips.map(a => {
263
266
  const temp = [
@@ -288,7 +291,6 @@ function exportTripReportToPDF(userData, reportData) {
288
291
  'Total:' + d.trips.length,
289
292
  '','','',
290
293
  convertMS(d.trips.reduce((a, b) => a + b.duration, 0)),
291
-
292
294
  ]
293
295
 
294
296
  if(userData.byDriver) {
@@ -303,25 +305,9 @@ function exportTripReportToPDF(userData, reportData) {
303
305
  getMaxSpeed(d.trips))
304
306
  }
305
307
 
306
- doc.autoTable({
307
- head: [headers],
308
- body: data,
309
- foot: [footValues],
310
- showFoot: 'lastPage',
311
- headStyles: {
312
- fillColor: reportStyle.pdfHeaderColor,
313
- textColor: reportStyle.pdfHeaderTextColor
314
- },
315
- bodyStyles: {
316
- fillColor: reportStyle.pdfBodyColor,
317
- textColor: reportStyle.pdfBodyTextColor
318
- },
319
- footStyles: {
320
- fillColor: reportStyle.pdfFooterColor,
321
- textColor: reportStyle.pdfFooterTextColor
322
- },
323
- startY: space+40 })
324
- }
308
+ const style = getStyle(getUserPartner(userData.user))
309
+ addTable(doc, headers, data, footValues, style, space + (userData.allWeek ? 40 : 45))
310
+ })
325
311
  return doc
326
312
  }
327
313
  }
@@ -398,23 +384,17 @@ function deviceName(device){
398
384
  }
399
385
 
400
386
  function getTripDate(user, trip){
401
- return new Date(trip.startTime).toLocaleDateString(user.attributes.lang, {
402
- timeZone: user.attributes.timezone,
403
- hour12: false
404
- })
387
+ return convertToLocaleDateString(trip.startTime, user.attributes.lang, user.attributes.timezone)
405
388
  }
389
+
406
390
  function getTripStart(user, trip){
407
- return new Date(trip.startTime).toLocaleTimeString(user.attributes.lang, {
408
- timeZone: user.attributes.timezone,
409
- hour12: false
410
- })
391
+ return convertToLocaleTimeString(trip.startTime, user.attributes.lang, user.attributes.timezone)
411
392
  }
393
+
412
394
  function getTripEnd(user, trip){
413
- return new Date(trip.endTime).toLocaleTimeString(user.attributes.lang, {
414
- timeZone: user.attributes.timezone,
415
- hour12: false
416
- })
395
+ return convertToLocaleTimeString(trip.endTime, user.attributes.lang, user.attributes.timezone)
417
396
  }
397
+
418
398
  function getDriverName(drivers, driverUniqueId) {
419
399
  if(driverUniqueId) {
420
400
  const driver = drivers.find(d => d.uniqueId === driverUniqueId)
@@ -423,18 +403,22 @@ function getDriverName(drivers, driverUniqueId) {
423
403
 
424
404
  return ''
425
405
  }
406
+
426
407
  function getSumTotalKms(user, data) {
427
408
  const values = data.map(item => {
428
409
  return item.totalKms ? parseFloat(item.totalKms) : 0
429
410
  })
430
411
  return Intl.NumberFormat(user.attributes.lang, {maximumFractionDigits: 2}).format(values.reduce((a, b) => a + b, 0))
431
412
  }
413
+
432
414
  function getSumAvgSpeed(data) {
433
415
  const values = data.map(item => {
434
- return Math.round(item.averageSpeed * 1.85200)
416
+ return Math.round(item.averageSpeed * 1.85200) * item.totalKms
435
417
  })
436
- return Math.round((values.reduce((a, b) => a + b, 0)) / data.length)
418
+ const totalKms = data.reduce((a, b) => a + b.totalKms, 0)
419
+ return totalKms > 0 ? Math.round((values.reduce((a, b) => a + b, 0)) / totalKms) : 0
437
420
  }
421
+
438
422
  function getMaxSpeed(data) {
439
423
  const values = data.map(item => {
440
424
  return item.maxSpeed
@@ -445,6 +429,15 @@ function getMaxSpeed(data) {
445
429
  return Math.round(max * 1.85200)
446
430
  }
447
431
 
432
+ function getStop(tripEndDate, stops){
433
+ const stopList = stops.filter(s => new Date(s.startTime).getTime() >= tripEndDate.getTime())
434
+ if(stopList.length){
435
+ return stopList[0]
436
+ }
437
+
438
+ return null
439
+ }
440
+
448
441
  exports.createTripReport = createTripReport;
449
442
  exports.exportTripReportToPDF = exportTripReportToPDF;
450
443
  exports.exportTripReportToExcel = exportTripReportToExcel;
@@ -1,25 +1,17 @@
1
- const automaticReports = require("../automaticReports")
1
+ const traccar = require("./traccar");
2
2
 
3
3
  //get devices used by each driver between two dates
4
- async function devicesByDriver(traccar, from, to, drivers, devices){
5
- let eventsData = []
6
- let tripsData = []
7
- const arrayOfArrays = automaticReports.sliceArray(devices)
8
- for (const a of arrayOfArrays) {
9
- const response = await traccar.reports.reportsEventsGet(from, to, a.map(d => d.id), null, ['driverChanged'])
10
- eventsData = eventsData.concat(response.data)
11
- }
12
-
4
+ async function devicesByDriver(traccarInstance, from, to, drivers, devices){
5
+ const eventsData = await traccar.getEvents(traccarInstance, from, to , devices, ['driverChanged'])
13
6
  const deviceIds = []
14
7
  for(const d of drivers) {
15
8
  const events = eventsData.filter(e => {
16
9
  return e.attributes.driverUniqueId === d.uniqueId
17
10
  })
18
11
 
19
- deviceIds.push(events.map(e => e.deviceId))
12
+ deviceIds.push(...events.map(e => e.deviceId))
20
13
  }
21
-
22
- return [...new Set(deviceIds.flat())]
14
+ return devices.filter(d => deviceIds.includes(d.id))
23
15
  }
24
16
 
25
17
  exports.devicesByDriver = devicesByDriver