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.
@@ -109,21 +109,31 @@ function calculateRefuelingPositions(d, positions) {
109
109
  let refuelingActivated = false
110
110
  let currentValue = null
111
111
  let positionsChecked = 0
112
+ let lastRefuelingIndex = 0
112
113
  positions.forEach(function(element, index, array){
113
114
  if(!element.attributes.ignition && refuelingActivated && !currentValue){
114
- const before = (index > 5 ? array.slice(index-6, index-1) : array.slice(0, index-1)).filter(b => b.attributes.ignition && b.attributes.fuel)
115
+ //Ignition is off and Refueling is Active and there is no current value
116
+
117
+ //Get 5 position before the ignition off to calculate the current value of the fuel tank level
118
+ //lastRefuelingIndex is used to avoid re-analyzing positions prior to a refueling
119
+ const before = (index > 5 ? array.slice((index-6 < lastRefuelingIndex ? lastRefuelingIndex : index-6), index-1) : array.slice(0, index-1)).filter(b => b.attributes.ignition && b.attributes.fuel)
115
120
  currentValue = Math.round(before.reduce((a, b) => a + b.attributes.fuel, 0) / before.length )
121
+
116
122
  positionsChecked = 0
117
123
  }
118
124
 
119
125
  if(element.attributes.ignition && refuelingActivated && currentValue) {
126
+ //Ignition is on and Refueling is Active and there is a current value
127
+ //Calculate the value of the fuel tank level after turning the ignition back on
120
128
  const after = (array.length > index + 5 ? array.slice(index, index+1) : array.slice(index)).filter(b => b.attributes.ignition && b.attributes.fuel)
121
129
  const newValue = Math.round(after.reduce((a, b) => a + b.attributes.fuel, 0) / after.length )
122
130
 
123
131
  const diff = automaticReports.calculateFuelDiff(currentValue, newValue, d)
124
132
  if (diff > 20) {
133
+ //New refueling detected
125
134
  const value = Math.round(diff * d.attributes.fuel_tank_capacity / 100)
126
135
  refuelingPositions.push({position: element, diff: value})
136
+ lastRefuelingIndex = index
127
137
  positionsChecked = 6 // to reset values
128
138
  }
129
139
 
@@ -1,3 +1,27 @@
1
+ function getStyle(partnerData) {
2
+ const reportStyleData = {
3
+ pdfHeaderColor: [105, 105, 105],
4
+ pdfHeaderTextColor: [256, 256, 256],
5
+ pdfBodyColor: [256, 256, 256],
6
+ pdfBodyTextColor: [30, 30, 30],
7
+ pdfFooterColor: [210, 210, 210],
8
+ pdfFooterTextColor: [30, 30, 30],
9
+ imgHeight: 0,
10
+ imgWidth: 0,
11
+ }
12
+
13
+ if(partnerData && partnerData.reports){
14
+ reportStyleData.pdfHeaderColor = partnerData.reports.mainColor || [105, 105, 105]
15
+ reportStyleData.pdfFooterColor = partnerData.reports.mainColor || [210, 210, 210]
16
+ reportStyleData.pdfFooterTextColor = partnerData.reports.mainColor ? [256, 256, 256] : [30, 30, 30]
17
+ reportStyleData.imgHeight = partnerData.reports.logoHeight || 0
18
+ reportStyleData.imgWidth = partnerData.reports.logoWidth || 0
19
+ }
20
+
21
+ return reportStyleData
22
+ }
23
+
24
+ exports.getStyle = getStyle
1
25
 
2
26
  exports.pdfHeaderColor = [105, 105, 105]
3
27
  exports.pdfHeaderTextColor = [256, 256, 256]
@@ -6,3 +30,5 @@ exports.pdfBodyTextColor = [30, 30, 30]
6
30
  exports.pdfFooterColor = [210, 210, 210]
7
31
  exports.pdfFooterTextColor = [30, 30, 30]
8
32
 
33
+
34
+
@@ -1,119 +1,149 @@
1
- const automaticReports = require("./automaticReports")
2
1
  const messages = require('../lang')
3
2
  const jsPDF = require('jspdf')
4
- const {convertMS} = require("./util/utils")
3
+ const {convertMS, convertToLocaleString} = require("./util/utils")
4
+ const {headerFromUser, AmiriRegular} = require("./util/pdfDocument")
5
5
  require('jspdf-autotable')
6
6
  const { parse } = require('wkt')
7
7
  const turf = require('turf')
8
- const reportStyle = require("./reportStyle")
8
+ const {getStyle} = require("./reportStyle")
9
9
  const drivers = require("./util/driver")
10
10
  const {distance, point} = require('turf')
11
11
  const here = require('./here')
12
+ const {getUserPartner} = require("fleetmap-partners");
13
+ const traccar = require("./util/traccar");
12
14
 
13
15
  let traccarInstance
16
+ let userData
14
17
 
15
18
  const fileName = 'SpeedingReport'
19
+ const eventTypes = ['deviceOverspeed']
16
20
 
17
- async function createSpeedingReport(from, to, userData, traccar, roadSpeedLimits) {
21
+ async function createSpeedingReport(from, to, reportUserData, traccar) {
18
22
  traccarInstance = traccar
19
- console.log('createSpeedingReport', from, to, userData, traccar, roadSpeedLimits)
23
+ userData = reportUserData
20
24
  const reportData = []
21
25
 
22
- if(userData.byDriver){
23
- const allData = await createSpeedingReportByDriver(from, to, userData, roadSpeedLimits)
26
+ if (userData.byDriver) {
27
+ console.log("ByDriver")
28
+ const allData = await createSpeedingReportByDriver(from, to)
24
29
  reportData.push(allData)
25
30
  }
26
- else if(userData.byGroup){
31
+ else if (userData.byGroup) {
27
32
  console.log("ByGroup")
28
- for (const g of userData.groups) {
29
- const devices = userData.devices.filter(d => d.groupId === g.id)
30
- console.log(g.name + ' devices:' + devices.length)
31
- if(devices.length > 0) {
32
- const groupData = {
33
- devices: [],
34
- group: g,
35
- xpert: devices.filter(d => d.attributes.xpert).length > 0
36
- }
33
+ const allData = await createSpeedingReportByGroup(from, to)
34
+ reportData.push(...allData)
35
+ } else {
36
+ console.log("createSpeedingReportByDevice")
37
+ const allData = await createSpeedingReportByDevice(from, to, userData.devices)
38
+ reportData.push(allData)
39
+ }
37
40
 
38
- const data = await getReportData(from, to, devices)
41
+ return reportData
42
+ }
39
43
 
40
- devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
44
+ async function createSpeedingReportByGroup(from, to){
45
+ const reportData = []
46
+ for (const g of userData.groups) {
47
+ const devices = userData.devices.filter(d => d.groupId === g.id)
48
+ console.log(g.name + ' devices:' + devices.length)
49
+ if(devices.length > 0) {
50
+ const groupData = {
51
+ devices: [],
52
+ group: g,
53
+ xpert: devices.filter(d => d.attributes.xpert).length > 0
54
+ }
41
55
 
42
- if (data.length > 0) {
43
- groupData.devices = await processDevices(from, to, devices, userData.geofences, userData.drivers, data, roadSpeedLimits)
44
- reportData.push(groupData)
45
- }
56
+ const events = await traccar.getEvents(traccarInstance, from, to, devices, eventTypes)
57
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
58
+
59
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
60
+
61
+ if (events.length > 0) {
62
+ groupData.devices = await processDevices(from, to, devices, events, routes)
63
+ reportData.push(groupData)
46
64
  }
47
65
  }
48
-
49
- const withoutGroupData = await createSpeedingReportByDevice(from, to, userData)
50
- reportData.push(withoutGroupData)
51
- } else {
52
- const allData = await createSpeedingReportByDevice(from, to, userData, roadSpeedLimits)
53
- reportData.push(allData)
54
66
  }
55
67
 
68
+ const groupIds = userData.groups.map(g => g.id)
69
+ const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
70
+
71
+ const withoutGroupData = await createSpeedingReportByDevice(from, to, withoutGroupDevices)
72
+ reportData.push(withoutGroupData)
73
+
56
74
  return reportData
57
75
  }
58
76
 
59
- async function createSpeedingReportByDevice(from, to, userData, roadSpeedLimits) {
60
- const groupIds = userData.groups.map(g => g.id)
61
- const withoutGroupDevices = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
62
-
63
- withoutGroupDevices.sort((a, b) => (a.name > b.name) ? 1 : -1)
77
+ async function createSpeedingReportByDevice(from, to, devices) {
78
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
64
79
 
65
- const data = await getReportData(from, to, withoutGroupDevices)
80
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
81
+ const events = []
82
+ if(!userData.useVehicleSpeedLimit && userData.customSpeed){
83
+ events.push(...await getCustomSpeedLimitEvents(devices, routes))
84
+ } else {
85
+ events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
86
+ }
66
87
 
67
- const allData = { devices: [] }
88
+ if(userData.roadSpeedLimits){
89
+ events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
90
+ }
68
91
 
69
- if(data.length > 0 || roadSpeedLimits) {
70
- allData.devices = await processDevices(from, to, withoutGroupDevices, userData.geofences, userData.drivers, data, roadSpeedLimits)
71
- allData.xpert = withoutGroupDevices.filter(d => d && d.attributes && d.attributes.xpert).length > 0
92
+ if(!events.length) {
93
+ //empty report
94
+ return { devices: [] }
72
95
  }
73
96
 
74
- return allData
97
+ return {
98
+ devices: await processDevices(from, to, devices, events, routes),
99
+ xpert: devices.filter(d => d && d.attributes && d.attributes.xpert).length > 0
100
+ }
75
101
  }
76
102
 
77
- async function createSpeedingReportByDriver(from, to, userData) {
78
- const deviceIds = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
79
- console.log(deviceIds.length)
103
+ async function createSpeedingReportByDriver(from, to) {
104
+ const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
105
+ console.log('Devices with driver',devices.length)
80
106
 
81
- let eventsData = []
82
- if(deviceIds.length > 0) {
83
- console.log('getReportData', deviceIds.length)
84
- const devices = userData.devices.filter(d => deviceIds.includes(d.id))
85
- eventsData = await getReportData(from, to, devices)
107
+ if(!devices.length) {
108
+ //empty report
109
+ return { drivers: [] }
86
110
  }
87
111
 
88
- const allData = {
89
- drivers: []
112
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
113
+ const events = []
114
+ if(!userData.useVehicleSpeedLimit && userData.customSpeed){
115
+ events.push(...await getCustomSpeedLimitEvents(devices, routes))
116
+ } else {
117
+ events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
90
118
  }
91
119
 
92
- console.log(eventsData.length)
120
+ if(userData.roadSpeedLimits){
121
+ events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
122
+ }
93
123
 
94
- await getEventsPosition(from , to, userData.devices, userData.geofences, userData.drivers, eventsData)
124
+ if(!events.length) {
125
+ //empty report
126
+ return { drivers: [] }
127
+ }
95
128
 
96
- allData.drivers = await processDrivers(from, to, userData.drivers, eventsData)
97
- console.log(allData.drivers.length)
98
- return allData
129
+ return {drivers: await processDrivers(from, to, events, routes)}
99
130
  }
100
131
 
101
- async function processDrivers(from, to, drivers, data) {
102
- console.log(data)
132
+ async function processDrivers(from, to, events, routes) {
103
133
  const driversResult = []
104
- const alertsWithPosition = data.filter(a => a.position)
105
-
106
- drivers.forEach(d => {
107
- const alerts = alertsWithPosition.filter(e => e.position.attributes.driverUniqueId === d.uniqueId)
108
134
 
109
- if (alerts.length > 0) {
135
+ await findEventsPosition(from, to, userData.devices, events, routes)
110
136
 
137
+ userData.drivers.forEach(d => {
138
+ const driverEvents = events.filter(e => e.position && e.position.attributes.driverUniqueId === d.uniqueId)
139
+ if (driverEvents.length > 0) {
140
+ driverEvents.sort((a, b) => a.positionId - b.positionId)
111
141
  driversResult.push({
112
142
  driver: d,
113
143
  from: from,
114
144
  to: to,
115
- alerts: alerts,
116
- maxSpeed: alerts.reduce((a, b) => {
145
+ alerts: driverEvents,
146
+ maxSpeed: driverEvents.reduce((a, b) => {
117
147
  return a > b.attributes.maxSpeed ? a : b.attributes.maxSpeed
118
148
  }, 0),
119
149
  })
@@ -123,40 +153,20 @@ async function processDrivers(from, to, drivers, data) {
123
153
  return driversResult
124
154
  }
125
155
 
126
- async function getReportData(from, to, devices) {
127
- const types = ['deviceOverspeed']
128
- let data = []
129
- const arrayOfArrays = automaticReports.sliceArray(devices)
130
- for (const a of arrayOfArrays) {
131
- try {
132
- const devices = a.map(d => d.id)
133
- console.log('reportsEventsGet', from, to, devices, null, types)
134
- const response = await traccarInstance.reports.reportsEventsGet(from, to, devices, null, types)
135
- data = data.concat(response.data)
136
- } catch (e) {
137
- console.error(e)
138
- }
139
- }
140
- console.log('Alerts:', data.length)
141
- return data
142
- }
143
-
144
- async function processDevices(from, to, devices, geofences, drivers, data, roadSpeedLimits) {
156
+ async function processDevices(from, to, devices, events, routes) {
145
157
  const devicesResult = []
146
-
147
- await getEventsPosition(from , to, devices, geofences, drivers, data, roadSpeedLimits)
158
+ await findEventsPosition(from, to, devices, events, routes)
148
159
 
149
160
  for (const d of devices) {
150
- const alerts = data.filter(t => t.deviceId === d.id)
151
-
152
- if (alerts.length > 0) {
153
- const alertsWithPosition = alerts.filter(a => a.position).sort((a,b) => a.positionId - b.positionId)
161
+ const deviceEvents = events.filter(e => e.deviceId === d.id && e.position)
162
+ if (deviceEvents.length > 0) {
163
+ deviceEvents.sort((a, b) => a.positionId - b.positionId)
154
164
  devicesResult.push({
155
165
  device: d,
156
166
  from: from,
157
167
  to: to,
158
- alerts: alertsWithPosition,
159
- maxSpeed: alertsWithPosition.reduce((a, b) => {
168
+ alerts: deviceEvents,
169
+ maxSpeed: deviceEvents.reduce((a, b) => {
160
170
  return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
161
171
  }, 0),
162
172
  })
@@ -166,93 +176,137 @@ async function processDevices(from, to, devices, geofences, drivers, data, roadS
166
176
  return devicesResult
167
177
  }
168
178
 
169
- async function getEventsPosition(from, to, devices, geofences, drivers, data, roadSpeedLimits){
179
+ async function findEventsPosition(from, to, devices, events, routes){
170
180
  for (const d of devices) {
181
+ let deviceEvents = events.filter(e => e.deviceId === d.id && e.positionId)
182
+ if (deviceEvents.length > 0) {
183
+ deviceEvents.sort((a,b) => a.positionId-b.positionId )
184
+ const positions = routes.filter(p => p.deviceId === d.id)
171
185
 
172
- let alerts = data.filter(t => t.deviceId === d.id)
173
-
174
- if (alerts.length > 0 || roadSpeedLimits) {
175
- const response = await traccarInstance.reports.reportsRouteGet(from, to, [d.id])
176
- const positions = response.data
177
-
178
- if (roadSpeedLimits && positions.length) {
179
- try {
180
- await new Promise(res => setTimeout(res, 1000))
181
- const results = await here.routeMatch(positions)
182
- const hereAlerts = results.map(r => {
183
- const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
184
- return {
185
- ...r,
186
- roadSpeedLimit: r.speedLimit,
187
- deviceId: d.id,
188
- position,
189
- positionId: position && position.id,
190
- attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
191
- }
192
- })
193
- console.log('hereAlerts', hereAlerts)
194
- const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
195
- if (idx === 1) {
196
- return [cur]
197
- }
198
- if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
199
- return acc.concat(cur)
200
- }
201
- return acc
202
- })
203
- data.push(...reduced)
204
- alerts = data.filter(t => t.deviceId === d.id)
205
- } catch (e) {
206
- console.error(e)
207
- }
208
- }
209
-
210
- for (const a of alerts) {
186
+ for (const a of deviceEvents) {
211
187
  let pIndex = positions.findIndex(p => p.id === a.positionId)
212
188
  if (pIndex > 0) {
213
- a.position = positions[pIndex]
214
189
  let geofence = null
215
-
216
190
  if (a.geofenceId) {
217
- geofence = geofences.find(g => g.id === a.geofenceId)
191
+ geofence = userData.geofences.find(g => g.id === a.geofenceId)
218
192
  if (geofence) {
219
193
  a.geofenceName = geofence.name + ' (' + Math.round(a.attributes.speedLimit * 1.85200) + ' Km/h)'
220
194
  }
221
195
  }
222
196
 
223
- let endEventPosition = a.position
224
- let maxSpeed = a.position.speed
225
- let dist = 0
226
- while (pIndex + 1 < positions.length) {
227
- pIndex++
228
-
229
- dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
230
- point([positions[pIndex].longitude, positions[pIndex].latitude]))
231
- endEventPosition = positions[pIndex]
232
- if (endEventPosition.speed <= a.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
233
- a.eventTime = new Date(endEventPosition.fixTime) - new Date(a.position.fixTime)
234
- a.attributes.maxSpeed = maxSpeed
235
- a.distance = dist
236
- break
237
- } else {
238
- if (maxSpeed < endEventPosition.speed) {
239
- maxSpeed = endEventPosition.speed
240
- }
241
- }
242
- }
197
+ a.position = positions[pIndex]
198
+ pIndex = calculateEventData(positions, pIndex, a, d, geofence)
199
+ positions.slice(pIndex)
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ async function getCustomSpeedLimitEvents(devices, routes){
207
+ console.log('custom speed limit events')
208
+ const events = []
209
+ const maxSpeed = userData.customSpeed / 1.85200
243
210
 
244
- if (a.position.attributes.driverUniqueId) {
245
- const driver = drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
246
- a.driver = driver && driver.name
211
+ for (const d of devices) {
212
+ const positions = routes.filter(p => p.deviceId === d.id)
213
+ let eventIsActive = false
214
+
215
+ for (const position of positions) {
216
+ if(position.speed > maxSpeed && !eventIsActive){
217
+ const event = {
218
+ positionId: position && position.id,
219
+ deviceId: d.id,
220
+ attributes: {
221
+ speedLimit: maxSpeed,
222
+ speed: position.speed
247
223
  }
224
+ }
225
+ events.push(event)
226
+ eventIsActive = true
227
+ } else if (position.speed <= maxSpeed) {
228
+ eventIsActive = false
229
+ }
230
+ }
231
+ }
248
232
 
249
- a.deviceName = d.name
233
+ return events
234
+ }
250
235
 
251
- positions.slice(pIndex)
236
+ async function getHereEvents(devices, routes, threshold){
237
+ console.log('here speed limit events')
238
+ const events = []
239
+ for (const d of devices) {
240
+ const positions = routes.filter(p => p.deviceId === d.id)
241
+ if (!positions.length) {
242
+ console.log('no positions on device', d.name)
243
+ continue
244
+ }
245
+ try {
246
+ const results = await here.routeMatch(positions)
247
+ const hereAlerts = results.filter(r => r.currentSpeedKmh > (parseInt(r.speedLimit) + threshold)).map(r => {
248
+ const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
249
+ return {
250
+ ...r,
251
+ roadSpeedLimit: r.speedLimit,
252
+ deviceId: d.id,
253
+ position,
254
+ positionId: position && position.id,
255
+ attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
252
256
  }
257
+ })
258
+ if (!hereAlerts.length) {
259
+ console.log('empty array after filter on device', d.name)
260
+ continue
253
261
  }
262
+ const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
263
+ if (idx === 1) {
264
+ return [cur]
265
+ }
266
+ if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
267
+ return acc.concat(cur)
268
+ }
269
+ return acc
270
+ })
271
+ events.push(...reduced)
272
+ } catch (e) {
273
+ console.error(e)
254
274
  }
255
275
  }
276
+ return events
277
+ }
278
+
279
+ function calculateEventData(positions, pIndex, alert, device, geofence){
280
+ let endEventPosition = alert.position
281
+ let maxSpeed = alert.position.speed
282
+ let dist = 0
283
+ while (pIndex + 1 < positions.length) {
284
+ pIndex++
285
+
286
+ dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
287
+ point([positions[pIndex].longitude, positions[pIndex].latitude]))
288
+ endEventPosition = positions[pIndex]
289
+ if (endEventPosition.speed <= alert.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
290
+ alert.eventTime = new Date(endEventPosition.fixTime) - new Date(alert.position.fixTime)
291
+ alert.attributes.maxSpeed = maxSpeed
292
+ alert.distance = dist
293
+ break
294
+ } else {
295
+ if (maxSpeed < endEventPosition.speed) {
296
+ maxSpeed = endEventPosition.speed
297
+ }
298
+ }
299
+ }
300
+
301
+
302
+ if (alert.position.attributes.driverUniqueId) {
303
+ const driver = userData.drivers.find(d => d.uniqueId === alert.position.attributes.driverUniqueId)
304
+ alert.driver = driver && driver.name
305
+ }
306
+
307
+ alert.deviceName = device.name
308
+
309
+ return pIndex
256
310
  }
257
311
 
258
312
  function isOutsideGeofence(geofence, endEventPosition) {
@@ -261,10 +315,11 @@ function isOutsideGeofence(geofence, endEventPosition) {
261
315
  return turf.inside(point, v)
262
316
  }
263
317
 
264
- function exportSpeedingReportToPDF(userData, reportData) {
318
+ async function exportSpeedingReportToPDF(userData, reportData) {
265
319
  console.log('Export to PDF')
266
320
 
267
321
  const lang = userData.user.attributes.lang
322
+ const timezone = userData.user.attributes.timezone
268
323
  const translations = messages[lang] ? messages[lang] : messages['en-GB']
269
324
 
270
325
  const overspeedData = userData.byDriver ? reportData.drivers : reportData.devices
@@ -278,7 +333,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
278
333
  translations.report.duration,
279
334
  ]
280
335
 
281
- if(userData.useRoadSpeedLimits) {
336
+ if(userData.roadSpeedLimits) {
282
337
  headers.splice(2, 0, translations.report.roadSpeedLimit)
283
338
  }
284
339
 
@@ -291,8 +346,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
291
346
  if (overspeedData) {
292
347
  let first = true
293
348
  const doc = new jsPDF.jsPDF('l');
294
- doc.setFontSize(14)
295
- doc.text(translations.report.titleSpeedingReport, 15, 15 )
349
+ await headerFromUser(doc, translations.report.titleSpeedingReport, userData.user)
296
350
 
297
351
  overspeedData.forEach(d => {
298
352
  try {
@@ -308,13 +362,13 @@ function exportSpeedingReportToPDF(userData, reportData) {
308
362
  first = false
309
363
  space = 10
310
364
  }
311
- doc.setFontSize(12)
365
+ doc.setFontSize(13)
312
366
  doc.text(name, 20, space+20 )
313
- doc.setFontSize(10)
367
+ doc.setFontSize(11)
314
368
  doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space+20 )
315
- doc.text(new Date(d.from).toLocaleString() + ' - ' + new Date(d.to).toLocaleString(), 20, space+25 )
369
+ doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space+25 )
316
370
  if (d.alerts[0] && !userData.byDriver) {
317
- doc.text(translations.report.speedLimit + ": " + Math.round(d.alerts[0].attributes.speedLimit * 1.85200) + ' Km/h', 20, space + 30)
371
+ doc.text(translations.report.speedLimit + ": " + ((userData.useVehicleSpeedLimit || !userData.customSpeed) ? Math.round(d.alerts[0].attributes.speedLimit * 1.85200) : userData.customSpeed) + ' Km/h', 20, space + 30)
318
372
  }
319
373
  d.alerts.map(a => {
320
374
  const temp = [
@@ -327,7 +381,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
327
381
  userData.byDriver ? a.deviceName : a.driver
328
382
  ]
329
383
 
330
- if(userData.useRoadSpeedLimits){
384
+ if(userData.roadSpeedLimits){
331
385
  temp.splice(2, 0, a.roadSpeedLimit)
332
386
  }
333
387
 
@@ -343,26 +397,34 @@ function exportSpeedingReportToPDF(userData, reportData) {
343
397
  convertMS(d.alerts.reduce((a, b) => a + b.eventTime, 0), true)
344
398
  ]
345
399
 
346
- if(userData.useRoadSpeedLimits){
400
+ if(userData.roadSpeedLimits){
347
401
  footValues.splice(2, 0, '')
348
402
  }
349
403
 
404
+ doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
405
+ doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
406
+
407
+ const style = getStyle(getUserPartner(userData.user))
350
408
  doc.autoTable({
351
409
  head: [headers],
352
410
  body: data,
353
411
  foot: [footValues],
354
412
  showFoot: 'lastPage',
355
413
  headStyles: {
356
- fillColor: reportStyle.pdfHeaderColor,
357
- textColor: reportStyle.pdfHeaderTextColor
414
+ fillColor: style.pdfHeaderColor,
415
+ textColor: style.pdfHeaderTextColor,
416
+ fontSize: 10
358
417
  },
359
418
  bodyStyles: {
360
- fillColor: reportStyle.pdfBodyColor,
361
- textColor: reportStyle.pdfBodyTextColor
419
+ fillColor: style.pdfBodyColor,
420
+ textColor: style.pdfBodyTextColor,
421
+ fontSize: 8,
422
+ font: timezone === 'Asia/Qatar' ? "Amiri" : ''
362
423
  },
363
424
  footStyles: {
364
- fillColor: reportStyle.pdfFooterColor,
365
- textColor: reportStyle.pdfFooterTextColor
425
+ fillColor: style.pdfFooterColor,
426
+ textColor: style.pdfFooterTextColor,
427
+ fontSize: 9
366
428
  },
367
429
  startY: space+35 });
368
430
  } catch (e) {
@@ -398,7 +460,7 @@ function exportSpeedingReportToExcel(userData, reportData) {
398
460
  userData.byDriver ? {label: translations.report.vehicle, value:'name'} : {label: translations.report.driver, value:'driver'}
399
461
  ]
400
462
 
401
- if (userData.useRoadSpeedLimits){
463
+ if (userData.roadSpeedLimits){
402
464
  headers.splice(3, 0, {label: translations.report.roadSpeedLimit, value:'roadSpeedLimit'})
403
465
  }
404
466
 
@@ -434,10 +496,7 @@ function deviceName(device){
434
496
  }
435
497
 
436
498
  function getAlertDate(row, user) {
437
- return new Date(row.position.fixTime).toLocaleString(user.attributes.lang, {
438
- timeZone: user.attributes.timezone,
439
- hour12: false
440
- })
499
+ return convertToLocaleString(row.position.fixTime, user.attributes.lang, user.attributes.timezone)
441
500
  }
442
501
 
443
502
  function getMaxSpeed(data) {
@@ -0,0 +1,22 @@
1
+ const {SessionApi} = require("traccar-api");
2
+ const axios = require('axios')
3
+ const axiosCookieJarSupport = require('axios-cookiejar-support').default;
4
+ const tough = require('tough-cookie');
5
+ const Index = require('../index');
6
+ const cookieJar = new tough.CookieJar();
7
+ const traccarConfig = {
8
+ basePath: 'https://api.pinme.io/api',
9
+ baseOptions: {
10
+ withCredentials: true,
11
+ jar: cookieJar
12
+ }
13
+ }
14
+
15
+ axiosCookieJarSupport(axios)
16
+
17
+ exports.getReports = async() => {
18
+ await new SessionApi(traccarConfig, null, axios).sessionPost(process.env.email, process.env.password)
19
+ return new Index(traccarConfig, axios)
20
+ }
21
+
22
+