fleetmap-reports 1.0.288 → 1.0.289

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,150 @@
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) {
22
+ console.log('Create SpeedingReport')
18
23
  traccarInstance = traccar
19
- console.log('createSpeedingReport', from, to, userData, traccar, roadSpeedLimits)
24
+ userData = reportUserData
20
25
  const reportData = []
21
26
 
22
- if(userData.byDriver){
23
- const allData = await createSpeedingReportByDriver(from, to, userData, roadSpeedLimits)
27
+ if (userData.byDriver) {
28
+ console.log("ByDriver")
29
+ const allData = await createSpeedingReportByDriver(from, to)
24
30
  reportData.push(allData)
25
31
  }
26
- else if(userData.byGroup){
32
+ else if (userData.byGroup) {
27
33
  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
- }
34
+ const allData = await createSpeedingReportByGroup(from, to)
35
+ reportData.push(...allData)
36
+ } else {
37
+ console.log("ByDevice")
38
+ const allData = await createSpeedingReportByDevice(from, to, userData.devices)
39
+ reportData.push(allData)
40
+ }
37
41
 
38
- const data = await getReportData(from, to, devices)
42
+ return reportData
43
+ }
39
44
 
40
- devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
45
+ async function createSpeedingReportByGroup(from, to){
46
+ const reportData = []
47
+ for (const g of userData.groups) {
48
+ const devices = userData.devices.filter(d => d.groupId === g.id)
49
+ console.log(g.name + ' devices:' + devices.length)
50
+ if(devices.length > 0) {
51
+ const groupData = {
52
+ devices: [],
53
+ group: g,
54
+ xpert: devices.filter(d => d.attributes.xpert).length > 0
55
+ }
41
56
 
42
- if (data.length > 0) {
43
- groupData.devices = await processDevices(from, to, devices, userData.geofences, userData.drivers, data, roadSpeedLimits)
44
- reportData.push(groupData)
45
- }
57
+ const events = await traccar.getEvents(traccarInstance, from, to, devices, eventTypes)
58
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
59
+
60
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
61
+
62
+ if (events.length > 0) {
63
+ groupData.devices = await processDevices(from, to, devices, events, routes)
64
+ reportData.push(groupData)
46
65
  }
47
66
  }
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
67
  }
55
68
 
69
+ const groupIds = userData.groups.map(g => g.id)
70
+ const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
71
+
72
+ const withoutGroupData = await createSpeedingReportByDevice(from, to, withoutGroupDevices)
73
+ reportData.push(withoutGroupData)
74
+
56
75
  return reportData
57
76
  }
58
77
 
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
78
+ async function createSpeedingReportByDevice(from, to, devices) {
79
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
62
80
 
63
- withoutGroupDevices.sort((a, b) => (a.name > b.name) ? 1 : -1)
64
-
65
- const data = await getReportData(from, to, withoutGroupDevices)
81
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
82
+ const events = []
83
+ if(!userData.useVehicleSpeedLimit && userData.customSpeed){
84
+ events.push(...await getCustomSpeedLimitEvents(devices, routes))
85
+ } else {
86
+ events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
87
+ }
66
88
 
67
- const allData = { devices: [] }
89
+ if(userData.roadSpeedLimits){
90
+ events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
91
+ }
68
92
 
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
93
+ if(!events.length) {
94
+ //empty report
95
+ return { devices: [] }
72
96
  }
73
97
 
74
- return allData
98
+ return {
99
+ devices: await processDevices(from, to, devices, events, routes),
100
+ xpert: devices.filter(d => d && d.attributes && d.attributes.xpert).length > 0
101
+ }
75
102
  }
76
103
 
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)
104
+ async function createSpeedingReportByDriver(from, to) {
105
+ const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
106
+ console.log('Devices with driver',devices.length)
80
107
 
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)
108
+ if(!devices.length) {
109
+ //empty report
110
+ return { drivers: [] }
86
111
  }
87
112
 
88
- const allData = {
89
- drivers: []
113
+ const routes = await traccar.getRoute(traccarInstance, from, to, devices)
114
+ const events = []
115
+ if(!userData.useVehicleSpeedLimit && userData.customSpeed){
116
+ events.push(...await getCustomSpeedLimitEvents(devices, routes))
117
+ } else {
118
+ events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
90
119
  }
91
120
 
92
- console.log(eventsData.length)
121
+ if(userData.roadSpeedLimits){
122
+ events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
123
+ }
93
124
 
94
- await getEventsPosition(from , to, userData.devices, userData.geofences, userData.drivers, eventsData)
125
+ if(!events.length) {
126
+ //empty report
127
+ return { drivers: [] }
128
+ }
95
129
 
96
- allData.drivers = await processDrivers(from, to, userData.drivers, eventsData)
97
- console.log(allData.drivers.length)
98
- return allData
130
+ return {drivers: await processDrivers(from, to, events, routes)}
99
131
  }
100
132
 
101
- async function processDrivers(from, to, drivers, data) {
102
- console.log(data)
133
+ async function processDrivers(from, to, events, routes) {
103
134
  const driversResult = []
104
- const alertsWithPosition = data.filter(a => a.position)
105
135
 
106
- drivers.forEach(d => {
107
- const alerts = alertsWithPosition.filter(e => e.position.attributes.driverUniqueId === d.uniqueId)
108
-
109
- if (alerts.length > 0) {
136
+ await findEventsPosition(from, to, userData.devices, events, routes)
110
137
 
138
+ userData.drivers.forEach(d => {
139
+ const driverEvents = events.filter(e => e.position && e.position.attributes.driverUniqueId === d.uniqueId)
140
+ if (driverEvents.length > 0) {
141
+ driverEvents.sort((a, b) => a.positionId - b.positionId)
111
142
  driversResult.push({
112
143
  driver: d,
113
144
  from: from,
114
145
  to: to,
115
- alerts: alerts,
116
- maxSpeed: alerts.reduce((a, b) => {
146
+ alerts: driverEvents,
147
+ maxSpeed: driverEvents.reduce((a, b) => {
117
148
  return a > b.attributes.maxSpeed ? a : b.attributes.maxSpeed
118
149
  }, 0),
119
150
  })
@@ -123,40 +154,20 @@ async function processDrivers(from, to, drivers, data) {
123
154
  return driversResult
124
155
  }
125
156
 
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) {
157
+ async function processDevices(from, to, devices, events, routes) {
145
158
  const devicesResult = []
146
-
147
- await getEventsPosition(from , to, devices, geofences, drivers, data, roadSpeedLimits)
159
+ await findEventsPosition(from, to, devices, events, routes)
148
160
 
149
161
  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)
162
+ const deviceEvents = events.filter(e => e.deviceId === d.id && e.position)
163
+ if (deviceEvents.length > 0) {
164
+ deviceEvents.sort((a, b) => a.positionId - b.positionId)
154
165
  devicesResult.push({
155
166
  device: d,
156
167
  from: from,
157
168
  to: to,
158
- alerts: alertsWithPosition,
159
- maxSpeed: alertsWithPosition.reduce((a, b) => {
169
+ alerts: deviceEvents,
170
+ maxSpeed: deviceEvents.reduce((a, b) => {
160
171
  return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
161
172
  }, 0),
162
173
  })
@@ -166,93 +177,129 @@ async function processDevices(from, to, devices, geofences, drivers, data, roadS
166
177
  return devicesResult
167
178
  }
168
179
 
169
- async function getEventsPosition(from, to, devices, geofences, drivers, data, roadSpeedLimits){
180
+ async function findEventsPosition(from, to, devices, events, routes){
170
181
  for (const d of devices) {
182
+ let deviceEvents = events.filter(e => e.deviceId === d.id && e.positionId)
183
+ if (deviceEvents.length > 0) {
184
+ deviceEvents.sort((a,b) => a.positionId-b.positionId )
185
+ const positions = routes.filter(p => p.deviceId === d.id)
171
186
 
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) {
187
+ for (const a of deviceEvents) {
211
188
  let pIndex = positions.findIndex(p => p.id === a.positionId)
212
189
  if (pIndex > 0) {
213
- a.position = positions[pIndex]
214
190
  let geofence = null
215
-
216
191
  if (a.geofenceId) {
217
- geofence = geofences.find(g => g.id === a.geofenceId)
192
+ geofence = userData.geofences.find(g => g.id === a.geofenceId)
218
193
  if (geofence) {
219
194
  a.geofenceName = geofence.name + ' (' + Math.round(a.attributes.speedLimit * 1.85200) + ' Km/h)'
220
195
  }
221
196
  }
222
197
 
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
- }
198
+ a.position = positions[pIndex]
199
+ pIndex = calculateEventData(positions, pIndex, a, d, geofence)
200
+ positions.slice(pIndex)
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ async function getCustomSpeedLimitEvents(devices, routes){
208
+ console.log('custom speed limit events')
209
+ const events = []
210
+ const maxSpeed = userData.customSpeed / 1.85200
243
211
 
244
- if (a.position.attributes.driverUniqueId) {
245
- const driver = drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
246
- a.driver = driver && driver.name
212
+ for (const d of devices) {
213
+ const positions = routes.filter(p => p.deviceId === d.id)
214
+ let eventIsActive = false
215
+
216
+ for (const position of positions) {
217
+ if(position.speed > maxSpeed && !eventIsActive){
218
+ const event = {
219
+ positionId: position && position.id,
220
+ deviceId: d.id,
221
+ attributes: {
222
+ speedLimit: maxSpeed,
223
+ speed: position.speed
247
224
  }
225
+ }
226
+ events.push(event)
227
+ eventIsActive = true
228
+ } else if (position.speed <= maxSpeed) {
229
+ eventIsActive = false
230
+ }
231
+ }
232
+ }
248
233
 
249
- a.deviceName = d.name
234
+ return events
235
+ }
250
236
 
251
- positions.slice(pIndex)
237
+ async function getHereEvents(devices, routes, threshold){
238
+ console.log('here speed limit events')
239
+ const events = []
240
+ for (const d of devices) {
241
+ const positions = routes.filter(p => p.deviceId === d.id)
242
+ try {
243
+ const results = await here.routeMatch(positions)
244
+ const hereAlerts = results.filter(r => r.currentSpeedKmh > (parseInt(r.speedLimit) + threshold)).map(r => {
245
+ const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
246
+ return {
247
+ ...r,
248
+ roadSpeedLimit: r.speedLimit,
249
+ deviceId: d.id,
250
+ position,
251
+ positionId: position && position.id,
252
+ attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
253
+ }
254
+ })
255
+ const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
256
+ if (idx === 1) {
257
+ return [cur]
252
258
  }
259
+ if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
260
+ return acc.concat(cur)
261
+ }
262
+ return acc
263
+ })
264
+ events.push(...reduced)
265
+ } catch (e) {
266
+ console.error(e)
267
+ }
268
+ }
269
+ return events
270
+ }
271
+
272
+ function calculateEventData(positions, pIndex, alert, device, geofence){
273
+ let endEventPosition = alert.position
274
+ let maxSpeed = alert.position.speed
275
+ let dist = 0
276
+ while (pIndex + 1 < positions.length) {
277
+ pIndex++
278
+
279
+ dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
280
+ point([positions[pIndex].longitude, positions[pIndex].latitude]))
281
+ endEventPosition = positions[pIndex]
282
+ if (endEventPosition.speed <= alert.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
283
+ alert.eventTime = new Date(endEventPosition.fixTime) - new Date(alert.position.fixTime)
284
+ alert.attributes.maxSpeed = maxSpeed
285
+ alert.distance = dist
286
+ break
287
+ } else {
288
+ if (maxSpeed < endEventPosition.speed) {
289
+ maxSpeed = endEventPosition.speed
253
290
  }
254
291
  }
255
292
  }
293
+
294
+
295
+ if (alert.position.attributes.driverUniqueId) {
296
+ const driver = userData.drivers.find(d => d.uniqueId === alert.position.attributes.driverUniqueId)
297
+ alert.driver = driver && driver.name
298
+ }
299
+
300
+ alert.deviceName = device.name
301
+
302
+ return pIndex
256
303
  }
257
304
 
258
305
  function isOutsideGeofence(geofence, endEventPosition) {
@@ -261,10 +308,11 @@ function isOutsideGeofence(geofence, endEventPosition) {
261
308
  return turf.inside(point, v)
262
309
  }
263
310
 
264
- function exportSpeedingReportToPDF(userData, reportData) {
311
+ async function exportSpeedingReportToPDF(userData, reportData) {
265
312
  console.log('Export to PDF')
266
313
 
267
314
  const lang = userData.user.attributes.lang
315
+ const timezone = userData.user.attributes.timezone
268
316
  const translations = messages[lang] ? messages[lang] : messages['en-GB']
269
317
 
270
318
  const overspeedData = userData.byDriver ? reportData.drivers : reportData.devices
@@ -278,7 +326,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
278
326
  translations.report.duration,
279
327
  ]
280
328
 
281
- if(userData.useRoadSpeedLimits) {
329
+ if(userData.roadSpeedLimits) {
282
330
  headers.splice(2, 0, translations.report.roadSpeedLimit)
283
331
  }
284
332
 
@@ -291,8 +339,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
291
339
  if (overspeedData) {
292
340
  let first = true
293
341
  const doc = new jsPDF.jsPDF('l');
294
- doc.setFontSize(14)
295
- doc.text(translations.report.titleSpeedingReport, 15, 15 )
342
+ await headerFromUser(doc, translations.report.titleSpeedingReport, userData.user)
296
343
 
297
344
  overspeedData.forEach(d => {
298
345
  try {
@@ -308,13 +355,13 @@ function exportSpeedingReportToPDF(userData, reportData) {
308
355
  first = false
309
356
  space = 10
310
357
  }
311
- doc.setFontSize(12)
358
+ doc.setFontSize(13)
312
359
  doc.text(name, 20, space+20 )
313
- doc.setFontSize(10)
360
+ doc.setFontSize(11)
314
361
  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 )
362
+ doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space+25 )
316
363
  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)
364
+ 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
365
  }
319
366
  d.alerts.map(a => {
320
367
  const temp = [
@@ -327,7 +374,7 @@ function exportSpeedingReportToPDF(userData, reportData) {
327
374
  userData.byDriver ? a.deviceName : a.driver
328
375
  ]
329
376
 
330
- if(userData.useRoadSpeedLimits){
377
+ if(userData.roadSpeedLimits){
331
378
  temp.splice(2, 0, a.roadSpeedLimit)
332
379
  }
333
380
 
@@ -343,26 +390,34 @@ function exportSpeedingReportToPDF(userData, reportData) {
343
390
  convertMS(d.alerts.reduce((a, b) => a + b.eventTime, 0), true)
344
391
  ]
345
392
 
346
- if(userData.useRoadSpeedLimits){
393
+ if(userData.roadSpeedLimits){
347
394
  footValues.splice(2, 0, '')
348
395
  }
349
396
 
397
+ doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
398
+ doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
399
+
400
+ const style = getStyle(getUserPartner(userData.user))
350
401
  doc.autoTable({
351
402
  head: [headers],
352
403
  body: data,
353
404
  foot: [footValues],
354
405
  showFoot: 'lastPage',
355
406
  headStyles: {
356
- fillColor: reportStyle.pdfHeaderColor,
357
- textColor: reportStyle.pdfHeaderTextColor
407
+ fillColor: style.pdfHeaderColor,
408
+ textColor: style.pdfHeaderTextColor,
409
+ fontSize: 10
358
410
  },
359
411
  bodyStyles: {
360
- fillColor: reportStyle.pdfBodyColor,
361
- textColor: reportStyle.pdfBodyTextColor
412
+ fillColor: style.pdfBodyColor,
413
+ textColor: style.pdfBodyTextColor,
414
+ fontSize: 8,
415
+ font: timezone === 'Asia/Qatar' ? "Amiri" : ''
362
416
  },
363
417
  footStyles: {
364
- fillColor: reportStyle.pdfFooterColor,
365
- textColor: reportStyle.pdfFooterTextColor
418
+ fillColor: style.pdfFooterColor,
419
+ textColor: style.pdfFooterTextColor,
420
+ fontSize: 9
366
421
  },
367
422
  startY: space+35 });
368
423
  } catch (e) {
@@ -398,7 +453,7 @@ function exportSpeedingReportToExcel(userData, reportData) {
398
453
  userData.byDriver ? {label: translations.report.vehicle, value:'name'} : {label: translations.report.driver, value:'driver'}
399
454
  ]
400
455
 
401
- if (userData.useRoadSpeedLimits){
456
+ if (userData.roadSpeedLimits){
402
457
  headers.splice(3, 0, {label: translations.report.roadSpeedLimit, value:'roadSpeedLimit'})
403
458
  }
404
459
 
@@ -434,10 +489,7 @@ function deviceName(device){
434
489
  }
435
490
 
436
491
  function getAlertDate(row, user) {
437
- return new Date(row.position.fixTime).toLocaleString(user.attributes.lang, {
438
- timeZone: user.attributes.timezone,
439
- hour12: false
440
- })
492
+ return convertToLocaleString(row.position.fixTime, user.attributes.lang, user.attributes.timezone)
441
493
  }
442
494
 
443
495
  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
+