fleetmap-reports 1.0.439 → 1.0.440
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 +1 -1
- package/src/events-report.js +234 -232
package/package.json
CHANGED
package/src/events-report.js
CHANGED
|
@@ -1,273 +1,275 @@
|
|
|
1
|
-
const automaticReports = require(
|
|
1
|
+
const automaticReports = require('./automaticReports')
|
|
2
2
|
const jsPDF = require('jspdf')
|
|
3
3
|
require('jspdf-autotable')
|
|
4
|
-
const {getStyle} = require(
|
|
5
|
-
const {headerFromUser} = require(
|
|
6
|
-
const {getUserPartner} = require(
|
|
7
|
-
const {convertToLocaleString, getTranslations} = require(
|
|
8
|
-
const {devicesToProcess} = require(
|
|
4
|
+
const { getStyle } = require('./reportStyle')
|
|
5
|
+
const { headerFromUser } = require('./util/pdfDocument')
|
|
6
|
+
const { getUserPartner } = require('fleetmap-partners')
|
|
7
|
+
const { convertToLocaleString, getTranslations } = require('./util/utils')
|
|
8
|
+
const { devicesToProcess } = require('./util/device')
|
|
9
9
|
|
|
10
10
|
const fileName = 'EventReport'
|
|
11
11
|
|
|
12
|
-
async function createEventsReport(from, to, userData, traccar) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const data = await getReportData(from, to, devices, userData.eventTypes, traccar)
|
|
29
|
-
|
|
30
|
-
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
31
|
-
|
|
32
|
-
if (data.length > 0) {
|
|
33
|
-
groupData.devices = await processDevices(from, to, devices, userData.geofences, userData.drivers, data)
|
|
34
|
-
reportData.push(groupData)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
12
|
+
async function createEventsReport (from, to, userData, traccar) {
|
|
13
|
+
console.log('Create EventsReport')
|
|
14
|
+
const reportData = []
|
|
15
|
+
|
|
16
|
+
if (userData.byGroup) {
|
|
17
|
+
console.log('ByGroup')
|
|
18
|
+
for (const g of userData.groups) {
|
|
19
|
+
const devices = userData.devices.filter(d => d.groupId === g.id)
|
|
20
|
+
console.log(g.name + ' devices:' + devices.length)
|
|
21
|
+
if (devices.length > 0) {
|
|
22
|
+
const groupData = {
|
|
23
|
+
devices: [],
|
|
24
|
+
group: g,
|
|
25
|
+
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
37
26
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const devices = devicesToProcess(userData)
|
|
41
27
|
|
|
42
|
-
|
|
28
|
+
const data = await getReportData(from, to, devices, userData.eventTypes, traccar)
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
reportData.push({
|
|
46
|
-
devices: await processDevices(from, to, devices, userData.geofences, userData.drivers, data, traccar),
|
|
47
|
-
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return reportData
|
|
52
|
-
}
|
|
30
|
+
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
53
31
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const traccarTypes = new Set(types.map(t => t.startsWith('alarm') ? 'alarm' : t))
|
|
58
|
-
const traccarSubTypes = types.map(t => t.startsWith('alarm') ? t.replace('alarm_', '') : '').filter(Boolean)
|
|
59
|
-
for (const a of arrayOfArrays) {
|
|
60
|
-
const response = await traccar.reports.reportsEventsGet(from, to, a.map(d => d.id), null, traccarTypes)
|
|
61
|
-
if(types.length > 0) {
|
|
62
|
-
data = data.concat(response.data.filter(e => e.type === 'alarm' ? traccarSubTypes.includes(e.attributes.alarm) : true))
|
|
63
|
-
} else {
|
|
64
|
-
data = data.concat(response.data)
|
|
32
|
+
if (data.length > 0) {
|
|
33
|
+
groupData.devices = await processDevices(from, to, devices, userData.geofences, userData.drivers, data)
|
|
34
|
+
reportData.push(groupData)
|
|
65
35
|
}
|
|
36
|
+
}
|
|
66
37
|
}
|
|
67
|
-
|
|
68
|
-
return data
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function processDevices(from, to, devices, geofences, drivers, data, traccar) {
|
|
72
|
-
const devicesResult = []
|
|
38
|
+
}
|
|
73
39
|
|
|
74
|
-
|
|
75
|
-
const alerts = data.filter(t => t.deviceId === d.id)
|
|
40
|
+
const devices = devicesToProcess(userData)
|
|
76
41
|
|
|
77
|
-
|
|
78
|
-
const response = await traccar.reports.reportsRouteGet(from, to, [d.id])
|
|
79
|
-
const positions = response.data
|
|
42
|
+
const data = await getReportData(from, to, devices, userData.eventTypes, traccar)
|
|
80
43
|
|
|
81
|
-
|
|
82
|
-
|
|
44
|
+
if (data.length > 0) {
|
|
45
|
+
reportData.push({
|
|
46
|
+
devices: await processDevices(from, to, devices, userData.geofences, userData.drivers, data, traccar),
|
|
47
|
+
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
48
|
+
})
|
|
49
|
+
}
|
|
83
50
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (geofence) {
|
|
87
|
-
if(a.type === 'deviceOverspeed'){
|
|
88
|
-
a.geofenceName = geofence.name + ' (' + Math.round(a.attributes.speedLimit * 1.85200) + ' Km/h)'
|
|
89
|
-
} else {
|
|
90
|
-
a.geofenceName = geofence.name
|
|
91
|
-
}
|
|
51
|
+
return reportData
|
|
52
|
+
}
|
|
92
53
|
|
|
93
|
-
|
|
94
|
-
|
|
54
|
+
async function getReportData (from, to, devices, types, traccar) {
|
|
55
|
+
let data = []
|
|
56
|
+
const arrayOfArrays = automaticReports.sliceArray(devices)
|
|
57
|
+
const traccarTypes = new Set(types.map(t => t.startsWith('alarm') ? 'alarm' : t))
|
|
58
|
+
const traccarSubTypes = types.map(t => t.startsWith('alarm') ? t.replace('alarm_', '') : '').filter(Boolean)
|
|
59
|
+
for (const a of arrayOfArrays) {
|
|
60
|
+
const response = await traccar.reports.reportsEventsGet(from, to, a.map(d => d.id), null, traccarTypes)
|
|
61
|
+
if (types.length > 0) {
|
|
62
|
+
data = data.concat(response.data.filter(e => e.type === 'alarm' ? traccarSubTypes.includes(e.attributes.alarm) : true))
|
|
63
|
+
} else {
|
|
64
|
+
data = data.concat(response.data)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
console.log('Alerts:' + data.length)
|
|
68
|
+
return data
|
|
69
|
+
}
|
|
95
70
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
71
|
+
async function processDevices (from, to, devices, geofences, drivers, data, traccar) {
|
|
72
|
+
const devicesResult = []
|
|
73
|
+
let i = 0
|
|
74
|
+
for (const d of devices) {
|
|
75
|
+
console.log('LOADING_MESSAGE:' + d.name)
|
|
76
|
+
console.log(`PROGRESS_PERC:${++i / devices.length * 100}`)
|
|
77
|
+
const alerts = data.filter(t => t.deviceId === d.id)
|
|
78
|
+
|
|
79
|
+
if (alerts.length > 0) {
|
|
80
|
+
const response = await traccar.reports.reportsRouteGet(from, to, [d.id])
|
|
81
|
+
const positions = response.data
|
|
82
|
+
|
|
83
|
+
for (const a of alerts) {
|
|
84
|
+
a.position = positions.find(p => p.id === a.positionId)
|
|
85
|
+
|
|
86
|
+
if (a.geofenceId) {
|
|
87
|
+
const geofence = geofences.find(g => g.id === a.geofenceId)
|
|
88
|
+
if (geofence) {
|
|
89
|
+
if (a.type === 'deviceOverspeed') {
|
|
90
|
+
a.geofenceName = geofence.name + ' (' + Math.round(a.attributes.speedLimit * 1.85200) + ' Km/h)'
|
|
91
|
+
} else {
|
|
92
|
+
a.geofenceName = geofence.name
|
|
100
93
|
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
101
96
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
to: to,
|
|
106
|
-
alerts: alerts
|
|
107
|
-
})
|
|
97
|
+
if (a.position && a.position.attributes.driverUniqueId) {
|
|
98
|
+
const driver = drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
|
|
99
|
+
a.driver = driver && driver.name
|
|
108
100
|
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
devicesResult.push({
|
|
104
|
+
device: d,
|
|
105
|
+
from,
|
|
106
|
+
to,
|
|
107
|
+
alerts
|
|
108
|
+
})
|
|
109
109
|
}
|
|
110
|
+
}
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
return devicesResult
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
async function exportSpeedingReportToPDF(userData, reportData) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
115
|
+
async function exportSpeedingReportToPDF (userData, reportData) {
|
|
116
|
+
console.log('Export to PDF')
|
|
117
|
+
const lang = userData.user.attributes.lang || (navigator && navigator.language)
|
|
118
|
+
const translations = getTranslations(userData)
|
|
119
|
+
const timezone = userData.user.attributes.timezone
|
|
120
|
+
|
|
121
|
+
const headers = [
|
|
122
|
+
translations.report.eventType,
|
|
123
|
+
translations.report.date,
|
|
124
|
+
translations.report.address,
|
|
125
|
+
translations.report.info
|
|
126
|
+
]
|
|
127
|
+
if (reportData.devices) {
|
|
128
|
+
let first = true
|
|
129
|
+
// eslint-disable-next-line new-cap
|
|
130
|
+
const doc = new jsPDF.jsPDF('l')
|
|
131
|
+
await headerFromUser(doc, translations.report.titleEventsReport, userData.user)
|
|
132
|
+
|
|
133
|
+
reportData.devices.forEach(d => {
|
|
134
|
+
const data = []
|
|
135
|
+
const name = deviceName(d.device)
|
|
136
|
+
const group = deviceGroupName(translations, userData.groups, d.device)
|
|
137
|
+
|
|
138
|
+
let space = 0
|
|
139
|
+
if (!first) {
|
|
140
|
+
doc.addPage()
|
|
141
|
+
} else {
|
|
142
|
+
first = false
|
|
143
|
+
space = 10
|
|
144
|
+
}
|
|
145
|
+
doc.setFontSize(13)
|
|
146
|
+
doc.text(name, 20, space + 20)
|
|
147
|
+
doc.setFontSize(11)
|
|
148
|
+
doc.text(group, 200, space + 20)
|
|
149
|
+
doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space + 25)
|
|
150
|
+
|
|
151
|
+
doc.autoTable(['', '', '', '', ''], [
|
|
152
|
+
[translations.report.event_ignitionOn, translations.report.event_ignitionOff, translations.report.event_geofenceEnter,
|
|
153
|
+
translations.report.event_geofenceExit, translations.report.event_deviceOverspeed],
|
|
154
|
+
[d.alerts.filter(a => a.type === 'ignitionOn').length, d.alerts.filter(a => a.type === 'ignitionOff').length,
|
|
155
|
+
d.alerts.filter(a => a.type === 'geofenceEnter').length, d.alerts.filter(a => a.type === 'geofenceExit').length,
|
|
156
|
+
d.alerts.filter(a => a.type === 'deviceOverspeed').length],
|
|
157
|
+
[translations.report.event_driverChanged, translations.report.event_powerOn, translations.report.event_sos,
|
|
158
|
+
translations.report.event_deviceFuelDrop, translations.report.eve],
|
|
159
|
+
[d.alerts.filter(a => a.type === 'driverChanged').length, d.alerts.filter(a => a.type === 'powerOn').length,
|
|
160
|
+
d.alerts.filter(a => a.type === 'sos').length, d.alerts.filter(a => a.type === 'deviceFuelDrop').length,
|
|
161
|
+
d.alerts.filter(a => a.type === 'powerCut').length]
|
|
162
|
+
], { startY: space + 30, showHead: false, bodyStyles: { fillColor: [256, 256, 256], textColor: [30, 30, 30], halign: 'center', valign: 'middle' }, alternateRowStyles: { fillColor: [256, 256, 256], valign: 'bottom' } })
|
|
163
|
+
|
|
164
|
+
d.alerts.forEach(a => {
|
|
165
|
+
const temp = [
|
|
166
|
+
a.type === 'alarm' ? translations.report['event_' + a.attributes.alarm] : translations.report['event_' + a.type],
|
|
167
|
+
getAlertDate(userData.user, a),
|
|
168
|
+
a.geofenceName || (a.position ? a.position.address : ''),
|
|
169
|
+
getAlertInfo(userData.drivers, a)
|
|
170
|
+
]
|
|
171
|
+
data.push(temp)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const footValues = [
|
|
175
|
+
'Total:' + d.alerts.length,
|
|
176
|
+
'', '', ''
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
const style = getStyle(getUserPartner(userData.user))
|
|
180
|
+
doc.autoTable({
|
|
181
|
+
head: [headers],
|
|
182
|
+
body: data,
|
|
183
|
+
foot: [footValues],
|
|
184
|
+
showFoot: 'lastPage',
|
|
185
|
+
headStyles: {
|
|
186
|
+
fillColor: style.pdfHeaderColor,
|
|
187
|
+
textColor: style.pdfHeaderTextColor,
|
|
188
|
+
fontSize: 10
|
|
189
|
+
},
|
|
190
|
+
bodyStyles: {
|
|
191
|
+
fillColor: style.pdfBodyColor,
|
|
192
|
+
textColor: style.pdfBodyTextColor,
|
|
193
|
+
fontSize: 8
|
|
194
|
+
},
|
|
195
|
+
footStyles: {
|
|
196
|
+
fillColor: style.pdfFooterColor,
|
|
197
|
+
textColor: style.pdfFooterTextColor,
|
|
198
|
+
fontSize: 9
|
|
199
|
+
},
|
|
200
|
+
startY: space + 65
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
return doc
|
|
204
|
+
}
|
|
203
205
|
}
|
|
204
206
|
|
|
205
|
-
function exportSpeedingReportToExcel(userData, reportData) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
name: d.device.name,
|
|
227
|
-
eventType: a.type === 'alarm' ? translations.report['event_'+a.attributes.alarm] : translations.report['event_'+a.type],
|
|
228
|
-
fixTime: getAlertDate(userData.user, a),
|
|
229
|
-
address: a.geofenceName || (a.position ? a.position.address : ''),
|
|
230
|
-
info: getAlertInfo(userData.drivers, a)
|
|
231
|
-
}
|
|
232
|
-
}))
|
|
233
|
-
})
|
|
207
|
+
function exportSpeedingReportToExcel (userData, reportData) {
|
|
208
|
+
console.log('exportSpeedingReportToExcel')
|
|
209
|
+
|
|
210
|
+
const translations = getTranslations(userData)
|
|
211
|
+
|
|
212
|
+
const settings = {
|
|
213
|
+
sheetName: translations.report.titleEventsReport, // The name of the sheet
|
|
214
|
+
fileName // The name of the spreadsheet
|
|
215
|
+
}
|
|
216
|
+
const headers = [
|
|
217
|
+
{ label: translations.report.vehicle, value: 'name' },
|
|
218
|
+
{ label: translations.report.eventType, value: 'eventType' },
|
|
219
|
+
{ label: translations.report.date, value: 'fixTime' },
|
|
220
|
+
{ label: translations.report.address, value: 'address' },
|
|
221
|
+
{ label: translations.report.info, value: 'info' }
|
|
222
|
+
]
|
|
223
|
+
let data = []
|
|
224
|
+
if (reportData.devices) {
|
|
225
|
+
reportData.devices.forEach(d => {
|
|
226
|
+
data = data.concat(d.alerts.map(a => {
|
|
234
227
|
return {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
228
|
+
name: d.device.name,
|
|
229
|
+
eventType: a.type === 'alarm' ? translations.report['event_' + a.attributes.alarm] : translations.report['event_' + a.type],
|
|
230
|
+
fixTime: getAlertDate(userData.user, a),
|
|
231
|
+
address: a.geofenceName || (a.position ? a.position.address : ''),
|
|
232
|
+
info: getAlertInfo(userData.drivers, a)
|
|
238
233
|
}
|
|
234
|
+
}))
|
|
235
|
+
})
|
|
236
|
+
return {
|
|
237
|
+
headers,
|
|
238
|
+
data,
|
|
239
|
+
settings
|
|
239
240
|
}
|
|
241
|
+
}
|
|
240
242
|
}
|
|
241
243
|
|
|
242
|
-
function deviceGroupName(translation, groups, device){
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
function deviceGroupName (translation, groups, device) {
|
|
245
|
+
const group = groups.find(g => device.groupId === g.id)
|
|
246
|
+
if (group) {
|
|
247
|
+
return translation.report.group + ': ' + group.name
|
|
248
|
+
}
|
|
249
|
+
return ''
|
|
248
250
|
}
|
|
249
251
|
|
|
250
|
-
function deviceName(device){
|
|
251
|
-
|
|
252
|
+
function deviceName (device) {
|
|
253
|
+
return device.name + (device.attributes.license_plate ? ', ' + device.attributes.license_plate : '') + (device.model ? ', ' + device.model : '')
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
function getAlertInfo(drivers, alert) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
256
|
+
function getAlertInfo (drivers, alert) {
|
|
257
|
+
if (alert.type === 'deviceOverspeed') {
|
|
258
|
+
return Math.round(alert.attributes.speed * 1.85200) + ' Km/h'
|
|
259
|
+
}
|
|
260
|
+
if (alert.type === 'driverChanged') {
|
|
261
|
+
const driver = drivers.find(d => d.uniqueId === alert.attributes.driverUniqueId)
|
|
262
|
+
return driver ? driver.name : alert.attributes.driverUniqueId
|
|
263
|
+
}
|
|
264
|
+
return ''
|
|
263
265
|
}
|
|
264
266
|
|
|
265
|
-
function getAlertDate(user, alert) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
function getAlertDate (user, alert) {
|
|
268
|
+
if (alert.position) {
|
|
269
|
+
return convertToLocaleString(alert.position.fixTime, user.attributes.lang, user.attributes.timezone)
|
|
270
|
+
}
|
|
269
271
|
}
|
|
270
272
|
|
|
271
|
-
exports.createEventsReport = createEventsReport
|
|
273
|
+
exports.createEventsReport = createEventsReport
|
|
272
274
|
exports.exportSpeedingReportToPDF = exportSpeedingReportToPDF
|
|
273
275
|
exports.exportSpeedingReportToExcel = exportSpeedingReportToExcel
|