fleetmap-reports 1.0.263 → 1.0.267
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/.idea/workspace.xml +54 -5
- package/package.json +1 -1
- package/src/activity-report.js +38 -17
- package/src/kms-report.js +75 -3
- package/src/speeding-report.js +191 -193
- package/src/trip-report.js +55 -94
- package/src/util/driver.js +2 -3
- package/src/util/traccar.js +3 -3
- package/src/util/trips.js +53 -0
package/.idea/workspace.xml
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<project version="4">
|
|
3
3
|
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="eb665c86-c893-4333-bd2a-721dc27980b9" name="Changes" comment="
|
|
4
|
+
<list default="true" id="eb665c86-c893-4333-bd2a-721dc27980b9" name="Changes" comment="check if weekDays parameter is set">
|
|
5
5
|
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
|
|
6
6
|
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
|
7
|
-
<change beforePath="$PROJECT_DIR$/src/activity-report.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/activity-report.js" afterDir="false" />
|
|
8
7
|
<change beforePath="$PROJECT_DIR$/src/index.test.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.test.js" afterDir="false" />
|
|
8
|
+
<change beforePath="$PROJECT_DIR$/src/trip-report.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/trip-report.js" afterDir="false" />
|
|
9
9
|
</list>
|
|
10
10
|
<option name="SHOW_DIALOG" value="false" />
|
|
11
11
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
@@ -219,7 +219,13 @@
|
|
|
219
219
|
<workItem from="1640866364417" duration="67000" />
|
|
220
220
|
<workItem from="1640866782794" duration="123000" />
|
|
221
221
|
<workItem from="1640866964393" duration="1022000" />
|
|
222
|
-
<workItem from="1640870147277" duration="
|
|
222
|
+
<workItem from="1640870147277" duration="8236000" />
|
|
223
|
+
<workItem from="1641321068227" duration="14805000" />
|
|
224
|
+
<workItem from="1641387675790" duration="32947000" />
|
|
225
|
+
<workItem from="1641509412324" duration="41000" />
|
|
226
|
+
<workItem from="1641510744190" duration="1404000" />
|
|
227
|
+
<workItem from="1641526151665" duration="1679000" />
|
|
228
|
+
<workItem from="1641640203903" duration="3434000" />
|
|
223
229
|
</task>
|
|
224
230
|
<task id="LOCAL-00001" summary="Fix getStyle">
|
|
225
231
|
<created>1636983717385</created>
|
|
@@ -361,12 +367,51 @@
|
|
|
361
367
|
<option name="project" value="LOCAL" />
|
|
362
368
|
<updated>1640872780968</updated>
|
|
363
369
|
</task>
|
|
364
|
-
<
|
|
370
|
+
<task id="LOCAL-00021" summary="activity report by driver grouped by day">
|
|
371
|
+
<created>1640878664617</created>
|
|
372
|
+
<option name="number" value="00021" />
|
|
373
|
+
<option name="presentableId" value="LOCAL-00021" />
|
|
374
|
+
<option name="project" value="LOCAL" />
|
|
375
|
+
<updated>1640878664617</updated>
|
|
376
|
+
</task>
|
|
377
|
+
<task id="LOCAL-00022" summary="fix kms-report by driver and fix activity report with time period">
|
|
378
|
+
<created>1641348028566</created>
|
|
379
|
+
<option name="number" value="00022" />
|
|
380
|
+
<option name="presentableId" value="LOCAL-00022" />
|
|
381
|
+
<option name="project" value="LOCAL" />
|
|
382
|
+
<updated>1641348028566</updated>
|
|
383
|
+
</task>
|
|
384
|
+
<task id="LOCAL-00023" summary="Refactor trip and speeding reports">
|
|
385
|
+
<created>1641511586537</created>
|
|
386
|
+
<option name="number" value="00023" />
|
|
387
|
+
<option name="presentableId" value="LOCAL-00023" />
|
|
388
|
+
<option name="project" value="LOCAL" />
|
|
389
|
+
<updated>1641511586537</updated>
|
|
390
|
+
</task>
|
|
391
|
+
<task id="LOCAL-00024" summary="check if weekDays parameter is set">
|
|
392
|
+
<created>1641527800168</created>
|
|
393
|
+
<option name="number" value="00024" />
|
|
394
|
+
<option name="presentableId" value="LOCAL-00024" />
|
|
395
|
+
<option name="project" value="LOCAL" />
|
|
396
|
+
<updated>1641527800170</updated>
|
|
397
|
+
</task>
|
|
398
|
+
<option name="localTasksCounter" value="25" />
|
|
365
399
|
<servers />
|
|
366
400
|
</component>
|
|
367
401
|
<component name="TypeScriptGeneratedFilesManager">
|
|
368
402
|
<option name="version" value="3" />
|
|
369
403
|
</component>
|
|
404
|
+
<component name="Vcs.Log.History.Properties">
|
|
405
|
+
<option name="COLUMN_ID_ORDER">
|
|
406
|
+
<list>
|
|
407
|
+
<option value="Default.Root" />
|
|
408
|
+
<option value="Default.Author" />
|
|
409
|
+
<option value="Default.Date" />
|
|
410
|
+
<option value="Default.Subject" />
|
|
411
|
+
<option value="Space.CommitStatus" />
|
|
412
|
+
</list>
|
|
413
|
+
</option>
|
|
414
|
+
</component>
|
|
370
415
|
<component name="Vcs.Log.Tabs.Properties">
|
|
371
416
|
<option name="TAB_STATES">
|
|
372
417
|
<map>
|
|
@@ -399,6 +444,10 @@
|
|
|
399
444
|
<MESSAGE value="timezone - check if it's running on client side" />
|
|
400
445
|
<MESSAGE value="calculate avg speed" />
|
|
401
446
|
<MESSAGE value="fix activity report by driver" />
|
|
402
|
-
<
|
|
447
|
+
<MESSAGE value="activity report by driver grouped by day" />
|
|
448
|
+
<MESSAGE value="fix kms-report by driver and fix activity report with time period" />
|
|
449
|
+
<MESSAGE value="Refactor trip and speeding reports" />
|
|
450
|
+
<MESSAGE value="check if weekDays parameter is set" />
|
|
451
|
+
<option name="LAST_COMMIT_MESSAGE" value="check if weekDays parameter is set" />
|
|
403
452
|
</component>
|
|
404
453
|
</project>
|
package/package.json
CHANGED
package/src/activity-report.js
CHANGED
|
@@ -87,11 +87,14 @@ async function createActivityReportByDevice(from, to){
|
|
|
87
87
|
//Get report data from traccar
|
|
88
88
|
devicesToProcess.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
89
89
|
|
|
90
|
+
// use the km report to calculate kms
|
|
91
|
+
const kmsReport = await createKmsReport(from, to, userData, traccarInstance)
|
|
92
|
+
|
|
90
93
|
let data = []
|
|
91
94
|
if(userData.groupByDay) {
|
|
92
95
|
const dates = getDates(from, to)
|
|
93
96
|
for(const date of dates){
|
|
94
|
-
if(userData.allWeek){
|
|
97
|
+
if(userData.allWeek || !userData.weekDays){
|
|
95
98
|
const fromByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
|
|
96
99
|
const toByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
|
|
97
100
|
|
|
@@ -110,9 +113,33 @@ async function createActivityReportByDevice(from, to){
|
|
|
110
113
|
const fromByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
|
|
111
114
|
const toByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
if(fromByDay.getTime() < toByDay.getTime()) {
|
|
117
|
+
const summary = await traccar.getSummary(traccarInstance, new Date(fromByDay.toUTCString()), new Date(toByDay.toUTCString()), devicesToProcess)
|
|
118
|
+
summary.forEach(s => s.date = date)
|
|
119
|
+
data = data.concat(summary)
|
|
120
|
+
} else {
|
|
121
|
+
const dayStart = new Date(new Date(date).toISOString().split('T')[0] + ' 00:00:00')
|
|
122
|
+
const dayEnd = new Date(new Date(date).toISOString().split('T')[0] + ' 23:59:59')
|
|
123
|
+
|
|
124
|
+
const summaryStart = await traccar.getSummary(traccarInstance, new Date(dayStart.toUTCString()), new Date(toByDay.toUTCString()), devicesToProcess)
|
|
125
|
+
const summaryEnd = await traccar.getSummary(traccarInstance, new Date(fromByDay.toUTCString()), new Date(dayEnd.toUTCString()), devicesToProcess)
|
|
126
|
+
|
|
127
|
+
const summary = []
|
|
128
|
+
summaryStart.forEach(s => {
|
|
129
|
+
const sEnd = summaryEnd.find(a => s.deviceId === a.deviceId)
|
|
130
|
+
summary.push({
|
|
131
|
+
date: date,
|
|
132
|
+
deviceId: s.deviceId,
|
|
133
|
+
averageSpeed: (s.averageSpeed + sEnd.averageSpeed) / 2,
|
|
134
|
+
distance: s.distance + sEnd.distance,
|
|
135
|
+
engineHours: s.engineHours + sEnd.engineHours,
|
|
136
|
+
maxSpeed: s.maxSpeed > sEnd.maxSpeed ? s.maxSpeed : sEnd.maxSpeed,
|
|
137
|
+
endOdometer: 0,
|
|
138
|
+
startOdometer: 0
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
data = data.concat(summary)
|
|
142
|
+
}
|
|
116
143
|
}else {
|
|
117
144
|
data = data.concat({date: date})
|
|
118
145
|
}
|
|
@@ -122,9 +149,6 @@ async function createActivityReportByDevice(from, to){
|
|
|
122
149
|
data = await traccar.getSummary(traccarInstance, from, to, devicesToProcess)
|
|
123
150
|
}
|
|
124
151
|
|
|
125
|
-
// use the km report to calculate kms
|
|
126
|
-
const kmsReport = await createKmsReport(from, to, userData, traccarInstance)
|
|
127
|
-
|
|
128
152
|
console.log('Summary:' + data.length)
|
|
129
153
|
|
|
130
154
|
//Process report data
|
|
@@ -136,11 +160,11 @@ async function createActivityReportByDevice(from, to){
|
|
|
136
160
|
}
|
|
137
161
|
|
|
138
162
|
async function createActivityReportByDriver(from, to){
|
|
139
|
-
const
|
|
140
|
-
|
|
163
|
+
const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
|
|
164
|
+
|
|
141
165
|
let tripsData = []
|
|
142
|
-
if(
|
|
143
|
-
tripsData = await traccar.getTrips(traccarInstance, from, to,
|
|
166
|
+
if(devices.length > 0) {
|
|
167
|
+
tripsData = await traccar.getTrips(traccarInstance, from, to, devices)
|
|
144
168
|
}
|
|
145
169
|
|
|
146
170
|
const allData = {
|
|
@@ -163,9 +187,6 @@ function processDevices(devices, data, kmsReport) {
|
|
|
163
187
|
if (summary) {
|
|
164
188
|
summary.forEach(s => {
|
|
165
189
|
const deviceKms = kmsReport[0].devices.filter(r => r.device.id === d.id)
|
|
166
|
-
|
|
167
|
-
console.log(deviceKms)
|
|
168
|
-
|
|
169
190
|
s.convertedSpentFuel = automaticReports.calculateSpentFuel(s.spentFuel, d)
|
|
170
191
|
s.distance = deviceKms.length ? (userData.groupByDay ? deviceKms[0].days.find(d => d.date.getTime() === s.date.getTime()).kms : deviceKms[0].summary.distance) : 0
|
|
171
192
|
})
|
|
@@ -193,7 +214,7 @@ function processDrivers(from, to, drivers, data) {
|
|
|
193
214
|
if(userData.groupByDay) {
|
|
194
215
|
const dates = getDates(from, to)
|
|
195
216
|
for(const date of dates){
|
|
196
|
-
if(userData.allWeek){
|
|
217
|
+
if(userData.allWeek || !userData.weekDays){
|
|
197
218
|
const fromByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
|
|
198
219
|
const toByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
|
|
199
220
|
|
|
@@ -388,7 +409,7 @@ function exportActivityReportToPDF_Vehicle_GroupByDay(doc, translations, reportD
|
|
|
388
409
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space + 20)
|
|
389
410
|
doc.text(new Date(reportData.from).toLocaleString() + ' - ' + new Date(reportData.to).toLocaleString(), 20, space + 25)
|
|
390
411
|
|
|
391
|
-
if (!userData.allWeek) {
|
|
412
|
+
if (!userData.allWeek && userData.weekDays) {
|
|
392
413
|
doc.text((userData.weekDays.monday ? ' ' + translations.report.monday + ',' : '')
|
|
393
414
|
+ (userData.weekDays.tuesday ? ' ' + translations.report.tuesday + ',' : '')
|
|
394
415
|
+ (userData.weekDays.wednesday ? ' ' + translations.report.wednesday + ',' : '')
|
|
@@ -515,7 +536,7 @@ function exportActivityReportToPDF_Driver_GroupByDay(doc, translations, reportDa
|
|
|
515
536
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space + 20)
|
|
516
537
|
doc.text(new Date(reportData.from).toLocaleString() + ' - ' + new Date(reportData.to).toLocaleString(), 20, space + 25)
|
|
517
538
|
|
|
518
|
-
if (!userData.allWeek) {
|
|
539
|
+
if (!userData.allWeek && userData.weekDays) {
|
|
519
540
|
doc.text((userData.weekDays.monday ? ' ' + translations.report.monday + ',' : '')
|
|
520
541
|
+ (userData.weekDays.tuesday ? ' ' + translations.report.tuesday + ',' : '')
|
|
521
542
|
+ (userData.weekDays.wednesday ? ' ' + translations.report.wednesday + ',' : '')
|
package/src/kms-report.js
CHANGED
|
@@ -7,6 +7,7 @@ const {getUserPartner} = require("fleetmap-partners");
|
|
|
7
7
|
const traccar = require("./util/traccar");
|
|
8
8
|
const {getDates} = require("./util/utils");
|
|
9
9
|
const trips = require("./util/trips");
|
|
10
|
+
const drivers = require("./util/driver");
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
let traccarInstance
|
|
@@ -26,7 +27,7 @@ async function createKmsReportByDevice(from, to) {
|
|
|
26
27
|
|
|
27
28
|
devicesToProcess.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
28
29
|
const route = userData.allWeek ? [] : await traccar.getRoute(traccarInstance, from, to, devicesToProcess)
|
|
29
|
-
const tripsData = await traccar.getTrips(traccarInstance, from, to, devicesToProcess
|
|
30
|
+
const tripsData = await traccar.getTrips(traccarInstance, from, to, devicesToProcess)
|
|
30
31
|
|
|
31
32
|
console.log('trips:' + tripsData.length)
|
|
32
33
|
|
|
@@ -39,13 +40,84 @@ async function createKmsReportByDevice(from, to) {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
async function createKmsReportByDriver(from, to) {
|
|
43
|
+
const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
|
|
44
|
+
console.log(devices.length)
|
|
42
45
|
|
|
46
|
+
if(!devices.length) {
|
|
47
|
+
//empty report
|
|
48
|
+
return { drivers: [] }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const tripsData = await traccar.getTrips(traccarInstance, from, to, devices)
|
|
52
|
+
return { drivers: processDrivers(from, to, userData.drivers, tripsData) }
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
async function createKmsReportByGroup(from, to) {
|
|
46
56
|
|
|
47
57
|
}
|
|
48
58
|
|
|
59
|
+
function processDrivers(from, to, drivers, data) {
|
|
60
|
+
console.log(data)
|
|
61
|
+
const driversResult = []
|
|
62
|
+
drivers.forEach(d => {
|
|
63
|
+
const trips = data.filter(t => t.driverUniqueId === d.uniqueId)
|
|
64
|
+
if (trips.length > 0) {
|
|
65
|
+
const driverData = {
|
|
66
|
+
driver: d
|
|
67
|
+
}
|
|
68
|
+
if(userData.groupByDay) {
|
|
69
|
+
driverData.days = []
|
|
70
|
+
const dates = getDates(from, to)
|
|
71
|
+
for(const date of dates){
|
|
72
|
+
if(userData.allWeek || !userData.weekDays){
|
|
73
|
+
const fromByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
|
|
74
|
+
const toByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
|
|
75
|
+
|
|
76
|
+
const tripsByDay = trips.filter(t => new Date(t.startTime) > fromByDay && new Date(t.endTime) < toByDay)
|
|
77
|
+
|
|
78
|
+
driverData.days.push({
|
|
79
|
+
date: date,
|
|
80
|
+
kms: tripsByDay.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
|
|
81
|
+
})
|
|
82
|
+
} else {
|
|
83
|
+
if((date.getDay() === 0 && userData.weekDays.sunday) ||
|
|
84
|
+
(date.getDay() === 1 && userData.weekDays.monday) ||
|
|
85
|
+
(date.getDay() === 2 && userData.weekDays.tuesday) ||
|
|
86
|
+
(date.getDay() === 3 && userData.weekDays.wednesday) ||
|
|
87
|
+
(date.getDay() === 4 && userData.weekDays.thursday) ||
|
|
88
|
+
(date.getDay() === 5 && userData.weekDays.friday) ||
|
|
89
|
+
(date.getDay() === 6 && userData.weekDays.saturday)) {
|
|
90
|
+
|
|
91
|
+
const fromByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
|
|
92
|
+
const toByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
|
|
93
|
+
|
|
94
|
+
const tripsByDay = trips.filter(t => new Date(t.startTime) > fromByDay && new Date(t.endTime) < toByDay)
|
|
95
|
+
|
|
96
|
+
driverData.days.push({
|
|
97
|
+
date: date,
|
|
98
|
+
kms: tripsByDay.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
|
|
99
|
+
})
|
|
100
|
+
}else {
|
|
101
|
+
driverData.days.push({
|
|
102
|
+
date: date,
|
|
103
|
+
kms: 0
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
driverData.summary = {
|
|
110
|
+
distance: trips.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
driversResult.push(driverData)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return driversResult
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
49
121
|
function processDevices(from, to, devices, route, trips) {
|
|
50
122
|
const devicesResult = []
|
|
51
123
|
|
|
@@ -81,7 +153,7 @@ function processDevices(from, to, devices, route, trips) {
|
|
|
81
153
|
kms: 0
|
|
82
154
|
}
|
|
83
155
|
|
|
84
|
-
if(userData.allWeek){
|
|
156
|
+
if(userData.allWeek || !userData.weekDays){
|
|
85
157
|
day.kms = dayTrips.reduce((a, b) => a + b.distance, 0) || 0
|
|
86
158
|
} else {
|
|
87
159
|
if((currentDate.getDay() === 0 && userData.weekDays.sunday) ||
|
|
@@ -230,7 +302,7 @@ async function exportKmsReportToPDF(userData, reportData) {
|
|
|
230
302
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space + 20)
|
|
231
303
|
doc.text(new Date(reportData.from).toLocaleString() + ' - ' + new Date(reportData.to).toLocaleString(), 20, space + 25)
|
|
232
304
|
|
|
233
|
-
if(!userData.allWeek) {
|
|
305
|
+
if(!userData.allWeek && userData.weekDays) {
|
|
234
306
|
doc.text((userData.weekDays.monday ? ' ' + translations.report.monday + ',' : '')
|
|
235
307
|
+ (userData.weekDays.tuesday ? ' ' + translations.report.tuesday + ',' : '')
|
|
236
308
|
+ (userData.weekDays.wednesday ? ' ' + translations.report.wednesday + ',' : '')
|
package/src/speeding-report.js
CHANGED
|
@@ -16,109 +16,135 @@ let traccarInstance
|
|
|
16
16
|
let userData
|
|
17
17
|
|
|
18
18
|
const fileName = 'SpeedingReport'
|
|
19
|
+
const eventTypes = ['deviceOverspeed']
|
|
19
20
|
|
|
20
21
|
async function createSpeedingReport(from, to, reportUserData, traccar) {
|
|
22
|
+
console.log('Create SpeedingReport')
|
|
21
23
|
traccarInstance = traccar
|
|
22
24
|
userData = reportUserData
|
|
23
|
-
console.log('createSpeedingReport', from, to, userData, traccar)
|
|
24
25
|
const reportData = []
|
|
25
26
|
|
|
26
|
-
if(userData.byDriver){
|
|
27
|
+
if (userData.byDriver) {
|
|
28
|
+
console.log("ByDriver")
|
|
27
29
|
const allData = await createSpeedingReportByDriver(from, to)
|
|
28
30
|
reportData.push(allData)
|
|
29
31
|
}
|
|
30
|
-
else if(userData.byGroup){
|
|
32
|
+
else if (userData.byGroup) {
|
|
31
33
|
console.log("ByGroup")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
40
|
-
}
|
|
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
|
+
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const routes = userData.useVehicleSpeedLimit ? [] : await traccar.getRoute(traccarInstance, from, to, devices)
|
|
42
|
+
return reportData
|
|
43
|
+
}
|
|
45
44
|
|
|
46
|
-
|
|
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
|
+
}
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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)
|
|
52
65
|
}
|
|
53
66
|
}
|
|
54
|
-
|
|
55
|
-
const withoutGroupData = await createSpeedingReportByDevice(from, to)
|
|
56
|
-
reportData.push(withoutGroupData)
|
|
57
|
-
} else {
|
|
58
|
-
const allData = await createSpeedingReportByDevice(from, to)
|
|
59
|
-
reportData.push(allData)
|
|
60
67
|
}
|
|
61
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
|
+
|
|
62
75
|
return reportData
|
|
63
76
|
}
|
|
64
77
|
|
|
65
|
-
async function createSpeedingReportByDevice(from, to) {
|
|
66
|
-
|
|
67
|
-
const withoutGroupDevices = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
|
|
68
|
-
|
|
69
|
-
withoutGroupDevices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
78
|
+
async function createSpeedingReportByDevice(from, to, devices) {
|
|
79
|
+
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
70
80
|
|
|
71
|
-
const
|
|
72
|
-
const events =
|
|
73
|
-
|
|
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
|
+
}
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
if(userData.roadSpeedLimits){
|
|
90
|
+
events.push(...await getHereEvents(devices, routes))
|
|
91
|
+
}
|
|
76
92
|
|
|
77
|
-
if(events.length
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
if(!events.length) {
|
|
94
|
+
//empty report
|
|
95
|
+
return { devices: [] }
|
|
80
96
|
}
|
|
81
97
|
|
|
82
|
-
return
|
|
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
|
+
}
|
|
83
102
|
}
|
|
84
103
|
|
|
85
104
|
async function createSpeedingReportByDriver(from, to) {
|
|
86
|
-
const
|
|
87
|
-
console.log('Devices with driver',
|
|
105
|
+
const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
|
|
106
|
+
console.log('Devices with driver',devices.length)
|
|
107
|
+
|
|
108
|
+
if(!devices.length) {
|
|
109
|
+
//empty report
|
|
110
|
+
return { drivers: [] }
|
|
111
|
+
}
|
|
88
112
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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))
|
|
93
119
|
}
|
|
94
120
|
|
|
95
|
-
|
|
96
|
-
|
|
121
|
+
if(userData.roadSpeedLimits){
|
|
122
|
+
events.push(...await getHereEvents(devices, routes))
|
|
97
123
|
}
|
|
98
|
-
console.log(eventsData.length)
|
|
99
124
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
if(!events.length) {
|
|
126
|
+
//empty report
|
|
127
|
+
return { drivers: [] }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {drivers: await processDrivers(from, to, events, routes)}
|
|
104
131
|
}
|
|
105
132
|
|
|
106
|
-
async function processDrivers(from, to,
|
|
107
|
-
console.log(data)
|
|
133
|
+
async function processDrivers(from, to, events, routes) {
|
|
108
134
|
const driversResult = []
|
|
109
|
-
const alertsWithPosition = data.filter(a => a.position)
|
|
110
|
-
|
|
111
|
-
userData.drivers.forEach(d => {
|
|
112
|
-
const alerts = alertsWithPosition.filter(e => e.position.attributes.driverUniqueId === d.uniqueId)
|
|
113
135
|
|
|
114
|
-
|
|
136
|
+
await findEventsPosition(from, to, userData.devices, events, routes)
|
|
115
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)
|
|
116
142
|
driversResult.push({
|
|
117
143
|
driver: d,
|
|
118
144
|
from: from,
|
|
119
145
|
to: to,
|
|
120
|
-
alerts:
|
|
121
|
-
maxSpeed:
|
|
146
|
+
alerts: driverEvents,
|
|
147
|
+
maxSpeed: driverEvents.reduce((a, b) => {
|
|
122
148
|
return a > b.attributes.maxSpeed ? a : b.attributes.maxSpeed
|
|
123
149
|
}, 0),
|
|
124
150
|
})
|
|
@@ -130,117 +156,38 @@ async function processDrivers(from, to, data) {
|
|
|
130
156
|
|
|
131
157
|
async function processDevices(from, to, devices, events, routes) {
|
|
132
158
|
const devicesResult = []
|
|
159
|
+
await findEventsPosition(from, to, devices, events, routes)
|
|
133
160
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
to: to,
|
|
148
|
-
alerts: alertsWithPosition,
|
|
149
|
-
maxSpeed: alertsWithPosition.reduce((a, b) => {
|
|
150
|
-
return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
|
|
151
|
-
}, 0),
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
for (const d of devices) {
|
|
157
|
-
const positions = routes.filter(t => t.deviceId === d.id)
|
|
158
|
-
const maxSpeed = userData.customSpeed / 1.85200
|
|
159
|
-
|
|
160
|
-
const alerts = []
|
|
161
|
-
for(let pIndex = 0; pIndex < positions.length ; pIndex++){
|
|
162
|
-
const position = positions[pIndex]
|
|
163
|
-
if(position.speed > maxSpeed){
|
|
164
|
-
const alert = {
|
|
165
|
-
position: position,
|
|
166
|
-
attributes: {
|
|
167
|
-
speedLimit: maxSpeed,
|
|
168
|
-
speed: position.speed
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
pIndex = calculateEventData(positions, pIndex, alert)
|
|
173
|
-
|
|
174
|
-
alerts.push(alert)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if(alerts.length > 0){
|
|
178
|
-
devicesResult.push({
|
|
179
|
-
device: d,
|
|
180
|
-
from: from,
|
|
181
|
-
to: to,
|
|
182
|
-
alerts: alerts,
|
|
183
|
-
maxSpeed: alerts.reduce((a, b) => {
|
|
184
|
-
return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
|
|
185
|
-
}, 0),
|
|
186
|
-
})
|
|
187
|
-
}
|
|
161
|
+
for (const d of devices) {
|
|
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)
|
|
165
|
+
devicesResult.push({
|
|
166
|
+
device: d,
|
|
167
|
+
from: from,
|
|
168
|
+
to: to,
|
|
169
|
+
alerts: deviceEvents,
|
|
170
|
+
maxSpeed: deviceEvents.reduce((a, b) => {
|
|
171
|
+
return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
|
|
172
|
+
}, 0),
|
|
173
|
+
})
|
|
188
174
|
}
|
|
189
175
|
}
|
|
190
176
|
|
|
191
177
|
return devicesResult
|
|
192
178
|
}
|
|
193
179
|
|
|
194
|
-
async function
|
|
195
|
-
|
|
196
|
-
const deviceIds = [...new Set(events.map(e => e.deviceId))]
|
|
197
|
-
const routeData = await traccar.getRoute(traccarInstance, from, to, deviceIds.map(id => { return { id: id } } ))
|
|
198
|
-
|
|
199
|
-
console.log(events)
|
|
200
|
-
|
|
180
|
+
async function findEventsPosition(from, to, devices, events, routes){
|
|
201
181
|
for (const d of devices) {
|
|
202
|
-
let
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const positions =
|
|
206
|
-
|
|
207
|
-
if (userData.roadSpeedLimits && positions.length) {
|
|
208
|
-
try {
|
|
209
|
-
const results = await here.routeMatch(positions)
|
|
210
|
-
const hereAlerts = results.map(r => {
|
|
211
|
-
const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
|
|
212
|
-
return {
|
|
213
|
-
...r,
|
|
214
|
-
roadSpeedLimit: r.speedLimit,
|
|
215
|
-
deviceId: d.id,
|
|
216
|
-
position,
|
|
217
|
-
positionId: position && position.id,
|
|
218
|
-
attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
|
|
219
|
-
}
|
|
220
|
-
})
|
|
221
|
-
console.log('hereAlerts', hereAlerts)
|
|
222
|
-
const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
|
|
223
|
-
if (idx === 1) {
|
|
224
|
-
return [cur]
|
|
225
|
-
}
|
|
226
|
-
if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
|
|
227
|
-
return acc.concat(cur)
|
|
228
|
-
}
|
|
229
|
-
return acc
|
|
230
|
-
})
|
|
231
|
-
events.push(...reduced)
|
|
232
|
-
alerts = events.filter(t => t.deviceId === d.id)
|
|
233
|
-
} catch (e) {
|
|
234
|
-
console.error(e)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
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)
|
|
237
186
|
|
|
238
|
-
for (const a of
|
|
187
|
+
for (const a of deviceEvents) {
|
|
239
188
|
let pIndex = positions.findIndex(p => p.id === a.positionId)
|
|
240
189
|
if (pIndex > 0) {
|
|
241
|
-
a.position = positions[pIndex]
|
|
242
190
|
let geofence = null
|
|
243
|
-
|
|
244
191
|
if (a.geofenceId) {
|
|
245
192
|
geofence = userData.geofences.find(g => g.id === a.geofenceId)
|
|
246
193
|
if (geofence) {
|
|
@@ -248,44 +195,87 @@ async function getEventsPosition(from, to, devices, events){
|
|
|
248
195
|
}
|
|
249
196
|
}
|
|
250
197
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
while (pIndex + 1 < positions.length) {
|
|
255
|
-
pIndex++
|
|
256
|
-
|
|
257
|
-
dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
|
|
258
|
-
point([positions[pIndex].longitude, positions[pIndex].latitude]))
|
|
259
|
-
endEventPosition = positions[pIndex]
|
|
260
|
-
if (endEventPosition.speed <= a.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
|
|
261
|
-
a.eventTime = new Date(endEventPosition.fixTime) - new Date(a.position.fixTime)
|
|
262
|
-
a.attributes.maxSpeed = maxSpeed
|
|
263
|
-
a.distance = dist
|
|
264
|
-
break
|
|
265
|
-
} else {
|
|
266
|
-
if (maxSpeed < endEventPosition.speed) {
|
|
267
|
-
maxSpeed = endEventPosition.speed
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
198
|
+
if(!a.position) {
|
|
199
|
+
a.position = positions[pIndex]
|
|
200
|
+
pIndex = calculateEventData(positions, pIndex, a, d, geofence)
|
|
271
201
|
|
|
272
|
-
|
|
273
|
-
const driver = userData.drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
|
|
274
|
-
a.driver = driver && driver.name
|
|
202
|
+
positions.slice(pIndex)
|
|
275
203
|
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
276
209
|
|
|
277
|
-
|
|
210
|
+
async function getCustomSpeedLimitEvents(devices, routes){
|
|
211
|
+
console.log('calculate custom speed limit events')
|
|
212
|
+
const events = []
|
|
213
|
+
const maxSpeed = userData.customSpeed / 1.85200
|
|
278
214
|
|
|
279
|
-
|
|
215
|
+
for (const d of devices) {
|
|
216
|
+
const positions = routes.filter(p => p.deviceId === d.id)
|
|
217
|
+
let eventIsActive = false
|
|
218
|
+
|
|
219
|
+
for (const position of positions) {
|
|
220
|
+
if(position.speed > maxSpeed && !eventIsActive){
|
|
221
|
+
const event = {
|
|
222
|
+
positionId: position && position.id,
|
|
223
|
+
deviceId: d.id,
|
|
224
|
+
attributes: {
|
|
225
|
+
speedLimit: maxSpeed,
|
|
226
|
+
speed: position.speed
|
|
227
|
+
}
|
|
280
228
|
}
|
|
229
|
+
events.push(event)
|
|
230
|
+
eventIsActive = true
|
|
231
|
+
} else if (position.speed <= maxSpeed) {
|
|
232
|
+
eventIsActive = false
|
|
281
233
|
}
|
|
282
234
|
}
|
|
283
235
|
}
|
|
236
|
+
|
|
237
|
+
return events
|
|
284
238
|
}
|
|
285
239
|
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
|
|
240
|
+
async function getHereEvents(devices, routes){
|
|
241
|
+
console.log('calculate custom speed limit events')
|
|
242
|
+
const events = []
|
|
243
|
+
for (const d of devices) {
|
|
244
|
+
const positions = routes.filter(p => p.deviceId === d.id)
|
|
245
|
+
try {
|
|
246
|
+
const results = await here.routeMatch(positions)
|
|
247
|
+
const hereAlerts = results.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}
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
console.log('hereAlerts', hereAlerts)
|
|
259
|
+
const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
|
|
260
|
+
if (idx === 1) {
|
|
261
|
+
return [cur]
|
|
262
|
+
}
|
|
263
|
+
if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
|
|
264
|
+
return acc.concat(cur)
|
|
265
|
+
}
|
|
266
|
+
return acc
|
|
267
|
+
})
|
|
268
|
+
events.push(...reduced)
|
|
269
|
+
} catch (e) {
|
|
270
|
+
//console.error(e)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return events
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function calculateEventData(positions, pIndex, alert, device, geofence){
|
|
277
|
+
let endEventPosition = alert.position
|
|
278
|
+
let maxSpeed = alert.position.speed
|
|
289
279
|
let dist = 0
|
|
290
280
|
while (pIndex + 1 < positions.length) {
|
|
291
281
|
pIndex++
|
|
@@ -293,10 +283,10 @@ function calculateEventData(positions, pIndex, a, geofence){
|
|
|
293
283
|
dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
|
|
294
284
|
point([positions[pIndex].longitude, positions[pIndex].latitude]))
|
|
295
285
|
endEventPosition = positions[pIndex]
|
|
296
|
-
if (endEventPosition.speed <=
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
286
|
+
if (endEventPosition.speed <= alert.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
|
|
287
|
+
alert.eventTime = new Date(endEventPosition.fixTime) - new Date(alert.position.fixTime)
|
|
288
|
+
alert.attributes.maxSpeed = maxSpeed
|
|
289
|
+
alert.distance = dist
|
|
300
290
|
break
|
|
301
291
|
} else {
|
|
302
292
|
if (maxSpeed < endEventPosition.speed) {
|
|
@@ -305,6 +295,14 @@ function calculateEventData(positions, pIndex, a, geofence){
|
|
|
305
295
|
}
|
|
306
296
|
}
|
|
307
297
|
|
|
298
|
+
|
|
299
|
+
if (alert.position.attributes.driverUniqueId) {
|
|
300
|
+
const driver = userData.drivers.find(d => d.uniqueId === alert.position.attributes.driverUniqueId)
|
|
301
|
+
alert.driver = driver && driver.name
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
alert.deviceName = device.name
|
|
305
|
+
|
|
308
306
|
return pIndex
|
|
309
307
|
}
|
|
310
308
|
|
|
@@ -367,7 +365,7 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
367
365
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space+20 )
|
|
368
366
|
doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space+25 )
|
|
369
367
|
if (d.alerts[0] && !userData.byDriver) {
|
|
370
|
-
doc.text(translations.report.speedLimit + ": " + (userData.useVehicleSpeedLimit ? Math.round(d.alerts[0].attributes.speedLimit * 1.85200) : userData.customSpeed) + ' Km/h', 20, space + 30)
|
|
368
|
+
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)
|
|
371
369
|
}
|
|
372
370
|
d.alerts.map(a => {
|
|
373
371
|
const temp = [
|
package/src/trip-report.js
CHANGED
|
@@ -3,13 +3,13 @@ const messages = require('../lang')
|
|
|
3
3
|
const jsPDF = require('jspdf')
|
|
4
4
|
const {convertMS, convertToLocaleString, convertToLocaleDateString, convertToLocaleTimeString} = require("./util/utils")
|
|
5
5
|
require('jspdf-autotable')
|
|
6
|
-
const {coordsDistance} = require("./util/utils")
|
|
7
6
|
const drivers = require("./util/driver")
|
|
8
7
|
const {getUserPartner} = require("fleetmap-partners")
|
|
9
8
|
const {headerFromUser, addTable} = require("./util/pdfDocument")
|
|
10
9
|
const {getStyle} = require("./reportStyle")
|
|
11
10
|
const traccar = require("./util/traccar")
|
|
12
11
|
const trips = require("./util/trips");
|
|
12
|
+
const {isInsideTimetable, addNearestPOIs} = require("./util/trips");
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
let traccarInstance
|
|
@@ -23,26 +23,26 @@ async function createTripReport(from, to, reportUserData, traccar) {
|
|
|
23
23
|
traccarInstance = traccar
|
|
24
24
|
const reportData = []
|
|
25
25
|
|
|
26
|
-
if(userData.byDriver){
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
if (userData.byDriver) {
|
|
27
|
+
console.log("ByDriver")
|
|
28
|
+
const report = await createTripReportByDriver(from, to)
|
|
29
|
+
reportData.push(report)
|
|
29
30
|
}
|
|
30
|
-
else if(userData.byGroup){
|
|
31
|
+
else if (userData.byGroup) {
|
|
31
32
|
console.log("ByGroup")
|
|
32
33
|
const allData = await createTripReportByGroup(from, to)
|
|
33
34
|
reportData.push(...allData)
|
|
35
|
+
} else {
|
|
36
|
+
console.log("ByDevice")
|
|
37
|
+
const report = await createTripReportByDevice(from, to)
|
|
38
|
+
reportData.push(report)
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
const groupIds = userData.groups.map(g => g.id)
|
|
37
|
-
const withoutGroupDevices = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
|
|
38
|
-
|
|
39
|
-
const allData = await createTripReportByDevice(from, to, withoutGroupDevices)
|
|
40
|
-
reportData.push(allData)
|
|
41
|
-
|
|
42
41
|
return reportData
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
async function createTripReportByDevice(from, to
|
|
44
|
+
async function createTripReportByDevice(from, to) {
|
|
45
|
+
const devices = userData.devices
|
|
46
46
|
const allData = {
|
|
47
47
|
devices: [],
|
|
48
48
|
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
@@ -51,7 +51,7 @@ async function createTripReportByDevice(from, to, devices) {
|
|
|
51
51
|
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
52
52
|
|
|
53
53
|
const devicesToSlice = devices.slice()
|
|
54
|
-
const data = await traccar.getTrips(traccarInstance, from, to, devicesToSlice
|
|
54
|
+
const data = await traccar.getTrips(traccarInstance, from, to, devicesToSlice)
|
|
55
55
|
const stopsData = await traccar.getStops(traccarInstance, from, to, devicesToSlice)
|
|
56
56
|
|
|
57
57
|
console.log('Trips:' + data.length)
|
|
@@ -77,90 +77,75 @@ async function createTripReportByGroup(from, to) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const response = await traccarInstance.reports.reportsTripsGet(from, to, null, [g.id])
|
|
80
|
-
const
|
|
80
|
+
const tripsData = response.data
|
|
81
81
|
|
|
82
82
|
const stopsResponse = await traccarInstance.reports.reportsStopsGet(from, to, null, [g.id])
|
|
83
83
|
const stopsData = stopsResponse.data
|
|
84
84
|
|
|
85
85
|
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
86
86
|
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
groupData.devices = processDevices(from, to, devices, data, stopsData, userData)
|
|
87
|
+
if (tripsData.length > 0) {
|
|
88
|
+
console.log('Trips:' + tripsData.length)
|
|
89
|
+
groupData.devices = processDevices(from, to, devices, tripsData, stopsData, userData)
|
|
91
90
|
|
|
92
91
|
reportData.push(groupData)
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
}
|
|
95
|
+
|
|
96
|
+
const groupIds = userData.groups.map(g => g.id)
|
|
97
|
+
const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
|
|
98
|
+
|
|
99
|
+
const allData = await createTripReportByDevice(from, to, withoutGroupDevices)
|
|
100
|
+
reportData.push(allData)
|
|
101
|
+
|
|
96
102
|
return reportData
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
async function createTripReportByDriver(from, to){
|
|
100
|
-
const
|
|
101
|
-
console.log(
|
|
102
|
-
|
|
103
|
-
let tripsData = []
|
|
104
|
-
if(deviceIds.length > 0) {
|
|
105
|
-
const response = await traccarInstance.reports.reportsTripsGet(from, to, deviceIds)
|
|
106
|
-
tripsData = response.data
|
|
107
|
-
}
|
|
106
|
+
const devices = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
|
|
107
|
+
console.log(devices.length)
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
if(!devices.length){
|
|
110
|
+
//Empty report
|
|
111
|
+
return { drivers:[] }
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
|
|
114
|
+
const tripsData = await traccar.getTrips(traccarInstance, from, to, devices)
|
|
114
115
|
|
|
115
|
-
return
|
|
116
|
+
return { drivers: processDrivers(from, to, userData.drivers, tripsData)}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
function processDevices(from, to, devices, data, stopsData) {
|
|
119
120
|
const devicesResult = []
|
|
120
121
|
|
|
121
122
|
devices.forEach(d => {
|
|
122
|
-
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)))
|
|
123
125
|
const stops = stopsData.filter(s => s.deviceId === d.id)
|
|
124
126
|
|
|
125
|
-
trips
|
|
126
|
-
|
|
127
|
+
addNearestPOIs(trips, userData)
|
|
128
|
+
|
|
129
|
+
trips.forEach(trip => {
|
|
127
130
|
if (automaticReports.deviceWithFuelInfo(d)) {
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
130
133
|
} else {
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
trip.fuelConsumption = '-'
|
|
135
|
+
trip.avgFuelConsumption = '-'
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), t.endLon, t.endLat))
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
const nearestPOIs = distance.filter(a => a.distance < 100).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
|
|
146
|
-
if (nearestPOIs.length > 0) {
|
|
147
|
-
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
|
|
148
145
|
}
|
|
149
146
|
})
|
|
150
147
|
|
|
151
148
|
if (trips.length > 0) {
|
|
152
|
-
trips.forEach(trip => {
|
|
153
|
-
const stop = getStop(new Date(trip.startTime), stops)
|
|
154
|
-
|
|
155
|
-
if (stop) {
|
|
156
|
-
trip.stopDuration = (new Date(stop.endTime) - new Date(stop.startTime))
|
|
157
|
-
trip.stopEngineHours = stop.engineHours
|
|
158
|
-
} else {
|
|
159
|
-
trip.stopDuration = 0
|
|
160
|
-
trip.stopEngineHours = 0
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
|
|
164
149
|
const deviceData = {
|
|
165
150
|
device: d,
|
|
166
151
|
from: from,
|
|
@@ -188,11 +173,12 @@ function processDrivers(from, to, drivers, data) {
|
|
|
188
173
|
console.log(data)
|
|
189
174
|
const driversResult = []
|
|
190
175
|
drivers.forEach(d => {
|
|
191
|
-
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)))
|
|
192
178
|
|
|
193
|
-
trips.
|
|
194
|
-
|
|
195
|
-
|
|
179
|
+
trips.sort((a,b)=>new Date(a.startTime).getTime()-new Date(b.startTime).getTime())
|
|
180
|
+
|
|
181
|
+
addNearestPOIs(trips, userData)
|
|
196
182
|
|
|
197
183
|
if (trips.length > 0) {
|
|
198
184
|
const driverData = {
|
|
@@ -201,14 +187,13 @@ function processDrivers(from, to, drivers, data) {
|
|
|
201
187
|
to: to,
|
|
202
188
|
totalDuration: trips.reduce((a, b) => a + b.duration, 0),
|
|
203
189
|
totalDistance: trips.reduce((a, b) => a + b.distance, 0),
|
|
204
|
-
maxSpeed: trips.reduce((a, b) => {
|
|
205
|
-
return a > b.maxSpeed ? a : b.maxSpeed
|
|
206
|
-
}, 0),
|
|
190
|
+
maxSpeed: trips.reduce((a, b) => { return a > b.maxSpeed ? a : b.maxSpeed }, 0),
|
|
207
191
|
trips: trips,
|
|
208
192
|
}
|
|
209
193
|
driversResult.push(driverData)
|
|
210
194
|
}
|
|
211
195
|
})
|
|
196
|
+
console.log(driversResult)
|
|
212
197
|
|
|
213
198
|
return driversResult
|
|
214
199
|
}
|
|
@@ -262,7 +247,7 @@ async function exportTripReportToPDF(userData, reportData) {
|
|
|
262
247
|
doc.setFontSize(11)
|
|
263
248
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 200, space+20 )
|
|
264
249
|
doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space+25 )
|
|
265
|
-
if(!userData.allWeek) {
|
|
250
|
+
if(!userData.allWeek && userData.weekDays) {
|
|
266
251
|
doc.text((userData.weekDays.monday ? ' ' + translations.report.monday + ',' : '')
|
|
267
252
|
+ (userData.weekDays.tuesday ? ' ' + translations.report.tuesday + ',' : '')
|
|
268
253
|
+ (userData.weekDays.wednesday ? ' ' + translations.report.wednesday + ',' : '')
|
|
@@ -453,30 +438,6 @@ function getStop(tripEndDate, stops){
|
|
|
453
438
|
return null
|
|
454
439
|
}
|
|
455
440
|
|
|
456
|
-
function isInsideTimetable(t, userData){
|
|
457
|
-
const tripStart = new Date(t.startTime)
|
|
458
|
-
const tripEnd = new Date(t.endTime)
|
|
459
|
-
|
|
460
|
-
if((tripStart.getDay() === 0 && userData.weekDays.sunday) ||
|
|
461
|
-
(tripStart.getDay() === 1 && userData.weekDays.monday) ||
|
|
462
|
-
(tripStart.getDay() === 2 && userData.weekDays.tuesday) ||
|
|
463
|
-
(tripStart.getDay() === 3 && userData.weekDays.wednesday) ||
|
|
464
|
-
(tripStart.getDay() === 4 && userData.weekDays.thursday) ||
|
|
465
|
-
(tripStart.getDay() === 5 && userData.weekDays.friday) ||
|
|
466
|
-
(tripStart.getDay() === 6 && userData.weekDays.saturday)) {
|
|
467
|
-
|
|
468
|
-
const startDate = new Date(new Date(tripStart).toISOString().split('T')[0] + ' '+userData.dayHours.startTime)
|
|
469
|
-
const endDate = new Date(new Date(tripStart).toISOString().split('T')[0] + ' '+userData.dayHours.endTime)
|
|
470
|
-
|
|
471
|
-
console.log(tripStart, startDate, endDate)
|
|
472
|
-
|
|
473
|
-
//Trips inside time period
|
|
474
|
-
return tripStart.getTime() > startDate.getTime() && tripEnd.getTime() < endDate.getTime()
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
return false
|
|
478
|
-
}
|
|
479
|
-
|
|
480
441
|
exports.createTripReport = createTripReport;
|
|
481
442
|
exports.exportTripReportToPDF = exportTripReportToPDF;
|
|
482
443
|
exports.exportTripReportToExcel = exportTripReportToExcel;
|
package/src/util/driver.js
CHANGED
|
@@ -9,10 +9,9 @@ async function devicesByDriver(traccarInstance, from, to, drivers, devices){
|
|
|
9
9
|
return e.attributes.driverUniqueId === d.uniqueId
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
deviceIds.push(events.map(e => e.deviceId))
|
|
12
|
+
deviceIds.push(...events.map(e => e.deviceId))
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
return [...new Set(deviceIds.flat())]
|
|
14
|
+
return devices.filter(d => deviceIds.includes(d.id))
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
exports.devicesByDriver = devicesByDriver
|
package/src/util/traccar.js
CHANGED
|
@@ -14,12 +14,12 @@ async function getRoute(traccar, from, to, devices){
|
|
|
14
14
|
return result.map(r => r.data).flat()
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async function getTrips(traccar, from, to,
|
|
18
|
-
const devicesToSlice =
|
|
17
|
+
async function getTrips(traccar, from, to, devices){
|
|
18
|
+
const devicesToSlice = devices.slice()
|
|
19
19
|
const arrayOfArrays = automaticReports.sliceArray(devicesToSlice)
|
|
20
20
|
let requests = []
|
|
21
21
|
for (const a of arrayOfArrays) {
|
|
22
|
-
const promise = traccar.reports.reportsTripsGet(from, to, a)
|
|
22
|
+
const promise = traccar.reports.reportsTripsGet(from, to, a.map(d => d.id))
|
|
23
23
|
requests = requests.concat(promise)
|
|
24
24
|
}
|
|
25
25
|
|
package/src/util/trips.js
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
const traccar = require("./traccar");
|
|
2
|
+
const {coordsDistance} = require("./utils");
|
|
2
3
|
|
|
3
4
|
const minDistance = 0
|
|
4
5
|
const minAvgSpeed = 0
|
|
5
6
|
|
|
7
|
+
function addNearestPOIs(trips, userData){
|
|
8
|
+
trips.forEach(t => {
|
|
9
|
+
t.totalKms = t.distance / 1000
|
|
10
|
+
|
|
11
|
+
const distance = userData.geofences
|
|
12
|
+
.filter(g => g && g.area.startsWith('CIRCLE'))
|
|
13
|
+
.map(g => {
|
|
14
|
+
const str = g.area.substring('CIRCLE ('.length, g.area.indexOf(','))
|
|
15
|
+
const coord = str.trim().split(' ')
|
|
16
|
+
return {
|
|
17
|
+
p: g,
|
|
18
|
+
distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), t.endLon, t.endLat))
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
const nearestPOIs = distance.filter(a => a.distance < 100).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
|
|
22
|
+
if (nearestPOIs.length > 0) {
|
|
23
|
+
t.endPOIName = nearestPOIs[0].p.name
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
async function checkTripsKms(traccarInstance, from, to, routeData, tripsData, devices) {
|
|
7
29
|
console.log('checkTripsKms')
|
|
8
30
|
const trips = tripsData.filter(t => t.distance === minDistance && t.averageSpeed > minAvgSpeed)
|
|
@@ -20,4 +42,35 @@ async function checkTripsKms(traccarInstance, from, to, routeData, tripsData, de
|
|
|
20
42
|
}
|
|
21
43
|
}
|
|
22
44
|
|
|
45
|
+
function isInsideTimetable(t, userData){
|
|
46
|
+
const tripStart = new Date(t.startTime)
|
|
47
|
+
const tripEnd = new Date(t.endTime)
|
|
48
|
+
|
|
49
|
+
if((tripStart.getDay() === 0 && userData.weekDays.sunday) ||
|
|
50
|
+
(tripStart.getDay() === 1 && userData.weekDays.monday) ||
|
|
51
|
+
(tripStart.getDay() === 2 && userData.weekDays.tuesday) ||
|
|
52
|
+
(tripStart.getDay() === 3 && userData.weekDays.wednesday) ||
|
|
53
|
+
(tripStart.getDay() === 4 && userData.weekDays.thursday) ||
|
|
54
|
+
(tripStart.getDay() === 5 && userData.weekDays.friday) ||
|
|
55
|
+
(tripStart.getDay() === 6 && userData.weekDays.saturday)) {
|
|
56
|
+
|
|
57
|
+
const startDate = new Date(new Date(tripStart).toISOString().split('T')[0] + ' '+userData.dayHours.startTime)
|
|
58
|
+
const endDate = new Date(new Date(tripStart).toISOString().split('T')[0] + ' '+userData.dayHours.endTime)
|
|
59
|
+
|
|
60
|
+
console.log(tripStart, startDate, endDate)
|
|
61
|
+
|
|
62
|
+
//Trips inside time period
|
|
63
|
+
if(startDate.getTime() < endDate.getTime()) {
|
|
64
|
+
return tripStart.getTime() > startDate.getTime() && tripEnd.getTime() < endDate.getTime()
|
|
65
|
+
} else {
|
|
66
|
+
return (tripStart.getTime() < endDate.getTime() && tripEnd.getTime() < endDate.getTime()) ||
|
|
67
|
+
(tripStart.getTime() > startDate.getTime())
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
|
|
23
74
|
exports.checkTripsKms = checkTripsKms
|
|
75
|
+
exports.isInsideTimetable = isInsideTimetable
|
|
76
|
+
exports.addNearestPOIs = addNearestPOIs
|