fleetmap-reports 1.0.598 → 1.0.600
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/lang/enGB.js +1 -0
- package/lang/esCL.js +1 -0
- package/lang/frFR.js +1 -0
- package/lang/ptBR.js +1 -0
- package/lang/ptPT.js +1 -0
- package/package.json +1 -1
- package/src/index.js +10 -0
- package/src/stop-report.js +220 -0
- package/src/tests/index.test.js +0 -1
- package/src/trip-report.js +17 -10
- package/src/util/device.js +4 -0
- package/src/util/geofence.js +15 -0
- package/src/util/pdfDocument.js +6 -0
- package/src/util/trips.js +0 -22
package/lang/enGB.js
CHANGED
package/lang/esCL.js
CHANGED
|
@@ -179,6 +179,7 @@ module.exports = {
|
|
|
179
179
|
titleKmsReport: 'Informe de Kms',
|
|
180
180
|
titleIdleReport: 'Informe de Ralenti',
|
|
181
181
|
titleMachinesReport: 'Informe de Maquinas',
|
|
182
|
+
titleStopReport: 'Informe de Paragens',
|
|
182
183
|
from: 'De',
|
|
183
184
|
to: 'a',
|
|
184
185
|
headerStartAddress: 'Lugar de início',
|
package/lang/frFR.js
CHANGED
|
@@ -173,6 +173,7 @@ module.exports = {
|
|
|
173
173
|
titleKmsReport: 'Rapport de km',
|
|
174
174
|
titleIdleReport: 'Rapport ralenti',
|
|
175
175
|
titleMachinesReport: 'Rapport sur les machines',
|
|
176
|
+
titleStopReport: 'Rapport de Arrêté',
|
|
176
177
|
headerStartAddress: 'Adresse de départ',
|
|
177
178
|
headerDistance: 'Distance',
|
|
178
179
|
headerDrivingTime: 'Driving Time',
|
package/lang/ptBR.js
CHANGED
|
@@ -181,6 +181,7 @@ module.exports = {
|
|
|
181
181
|
titleKmsReport: 'Relatórios de Kms',
|
|
182
182
|
titleIdleReport: 'Relatórios de Ralenti',
|
|
183
183
|
titleMachinesReport: 'Relatório de Máquinas',
|
|
184
|
+
titleStopReport: 'Relatório de Paragens',
|
|
184
185
|
from: 'De',
|
|
185
186
|
to: 'a',
|
|
186
187
|
headerStartAddress: 'Local de início',
|
package/lang/ptPT.js
CHANGED
|
@@ -187,6 +187,7 @@ module.exports = {
|
|
|
187
187
|
titleKmsReport: 'Relatórios de Kms',
|
|
188
188
|
titleIdleReport: 'Relatórios de Ralenti',
|
|
189
189
|
titleMachinesReport: 'Relatório de Máquinas',
|
|
190
|
+
titleStopReport: 'Relatório de Paragens',
|
|
190
191
|
from: 'De',
|
|
191
192
|
to: 'a',
|
|
192
193
|
headerStartAddress: 'Local de início',
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -172,5 +172,15 @@ function Reports (config, axios, cookieJar) {
|
|
|
172
172
|
this.machinesReportToExcel = (userData, reportData) => {
|
|
173
173
|
return require('./machines-report').exportMachinesReportToExcel(userData, reportData)
|
|
174
174
|
}
|
|
175
|
+
|
|
176
|
+
this.stopReport = (from, to, userData) => {
|
|
177
|
+
return require('./stop-report').createStopReport(from, to, userData, this.traccar)
|
|
178
|
+
}
|
|
179
|
+
this.stopReportToPDF = (userData, reportData) => {
|
|
180
|
+
return require('./stop-report').exportStopReportToPDF(userData, reportData)
|
|
181
|
+
}
|
|
182
|
+
this.stopReportToExcel = (userData, reportData) => {
|
|
183
|
+
return require('./stop-report').exportStopReportToExcel(userData, reportData)
|
|
184
|
+
}
|
|
175
185
|
}
|
|
176
186
|
module.exports = Reports
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const { devicesToProcess, deviceName } = require('./util/device')
|
|
2
|
+
const automaticReports = require('./automaticReports')
|
|
3
|
+
const traccarHelper = require('./util/traccar')
|
|
4
|
+
const { getNearestPOIs, insideGeofence } = require('./util/geofence')
|
|
5
|
+
const { getTranslations, convertToLocaleString, convertMS, convertToLocaleDateString, convertToLocaleTimeString } = require('./util/utils')
|
|
6
|
+
const jsPDF = require('jspdf')
|
|
7
|
+
const { headerFromUser, addTable } = require('./util/pdfDocument')
|
|
8
|
+
const { getStyle } = require('./reportStyle')
|
|
9
|
+
const { getUserPartner } = require('fleetmap-partners')
|
|
10
|
+
|
|
11
|
+
const fileName = 'StopReport'
|
|
12
|
+
|
|
13
|
+
async function createStopReport (from, to, userData, traccar) {
|
|
14
|
+
console.log('Create StopReport')
|
|
15
|
+
const reportData = []
|
|
16
|
+
|
|
17
|
+
const report = await createStopReportByDevice(from, to, userData, traccar)
|
|
18
|
+
reportData.push(report)
|
|
19
|
+
|
|
20
|
+
return reportData
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function createStopReportByDevice (from, to, userData, traccar) {
|
|
24
|
+
const devices = devicesToProcess(userData)
|
|
25
|
+
|
|
26
|
+
const allData = {
|
|
27
|
+
devices: []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const sliced = automaticReports.sliceArray(devices, 5)
|
|
31
|
+
|
|
32
|
+
let deviceCount = 0
|
|
33
|
+
for (const slice of sliced) {
|
|
34
|
+
const allInOne = await traccarHelper.getAllInOne(traccar, from, to, slice, false, false, true, false, deviceCount, devices.length)
|
|
35
|
+
const stopsData = allInOne.stops
|
|
36
|
+
|
|
37
|
+
console.log('Stops:' + stopsData.length)
|
|
38
|
+
|
|
39
|
+
if (stopsData.length > 0) {
|
|
40
|
+
allData.devices.push(...processDevices(from, to, slice, {
|
|
41
|
+
stops: stopsData
|
|
42
|
+
}, userData))
|
|
43
|
+
}
|
|
44
|
+
deviceCount = deviceCount + slice.length
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return allData
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function processDevices (from, to, devices, data, userData) {
|
|
51
|
+
const devicesResult = []
|
|
52
|
+
|
|
53
|
+
devices.forEach(d => {
|
|
54
|
+
const deviceStops = data.stops.filter(t => t.deviceId === d.id)
|
|
55
|
+
|
|
56
|
+
deviceStops.forEach(stop => {
|
|
57
|
+
const nearestPOIs = getNearestPOIs(stop.longitude, stop.latitude, userData.geofences)
|
|
58
|
+
if (nearestPOIs.length > 0) {
|
|
59
|
+
stop.endPOIName = nearestPOIs[0].p.name
|
|
60
|
+
} else {
|
|
61
|
+
const geofence = userData.geofences.filter(g => g && g.area.startsWith('POLYGON')).some(g =>
|
|
62
|
+
insideGeofence({ latitude: stop.latitude, longitude: stop.longitude }, g)
|
|
63
|
+
)
|
|
64
|
+
if (geofence) {
|
|
65
|
+
stop.endPOIName = geofence.name
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
stop.stopDuration = ((new Date(stop.endTime) - new Date(stop.startTime)) - stop.engineHours)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
if (deviceStops.length > 0) {
|
|
73
|
+
const deviceData = {
|
|
74
|
+
device: d,
|
|
75
|
+
from,
|
|
76
|
+
to,
|
|
77
|
+
stops: deviceStops
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
devicesResult.push(deviceData)
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
return devicesResult
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function exportStopReportToPDF (userData, reportData) {
|
|
88
|
+
console.log('Export stop report to PDF')
|
|
89
|
+
|
|
90
|
+
const timezone = userData.user.attributes.timezone
|
|
91
|
+
const translations = getTranslations(userData)
|
|
92
|
+
const lang = userData.user.attributes.lang || (navigator && navigator.language)
|
|
93
|
+
const stopsData = userData.byDriver ? reportData.drivers : reportData.devices
|
|
94
|
+
|
|
95
|
+
const headers = [
|
|
96
|
+
translations.report.date,
|
|
97
|
+
translations.report.start,
|
|
98
|
+
translations.report.end,
|
|
99
|
+
translations.report.address,
|
|
100
|
+
translations.report.idleTime,
|
|
101
|
+
translations.report.event_ignitionOff
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
if (stopsData) {
|
|
105
|
+
// eslint-disable-next-line new-cap
|
|
106
|
+
const doc = new jsPDF.jsPDF('l')
|
|
107
|
+
await headerFromUser(doc, translations.report.titleTripReport, userData.user)
|
|
108
|
+
|
|
109
|
+
stopsData.forEach(function (d, index) {
|
|
110
|
+
const data = []
|
|
111
|
+
const name = deviceName(d.device)
|
|
112
|
+
const group = userData.groups.find(g => d.device.groupId === g.id)
|
|
113
|
+
|
|
114
|
+
const space = index === 0 ? 8 : 0
|
|
115
|
+
if (index) {
|
|
116
|
+
doc.addPage()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
doc.setFontSize(13)
|
|
120
|
+
doc.text(name, 20, space + 20)
|
|
121
|
+
doc.setFontSize(11)
|
|
122
|
+
doc.text(group ? translations.report.group + ': ' + group.name : '', 200, space + 20)
|
|
123
|
+
doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space + 25)
|
|
124
|
+
|
|
125
|
+
d.stops.forEach(a => {
|
|
126
|
+
data.push([
|
|
127
|
+
getStopDate(userData.user, a),
|
|
128
|
+
getStopStart(userData.user, a),
|
|
129
|
+
getStopEnd(userData.user, a),
|
|
130
|
+
a.endPOIName || a.address,
|
|
131
|
+
convertMS(a.engineHours, true),
|
|
132
|
+
convertMS(a.stopDuration, true)
|
|
133
|
+
])
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const footValues = [
|
|
137
|
+
'Total:' + d.stops.length,
|
|
138
|
+
'', '', '',
|
|
139
|
+
convertMS(d.stops.reduce((a, b) => a + b.engineHours, 0), true),
|
|
140
|
+
convertMS(d.stops.reduce((a, b) => a + b.stopDuration, 0), true)]
|
|
141
|
+
|
|
142
|
+
const style = getStyle(getUserPartner(userData.user))
|
|
143
|
+
addTable(doc,
|
|
144
|
+
headers, data, footValues, style,
|
|
145
|
+
space + 40,
|
|
146
|
+
{
|
|
147
|
+
4: { halign: 'right' },
|
|
148
|
+
5: { halign: 'right' }
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
return doc
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function exportStopReportToExcel (userData, reportData) {
|
|
156
|
+
console.log('Export stop report to Excel')
|
|
157
|
+
|
|
158
|
+
const translations = getTranslations(userData)
|
|
159
|
+
|
|
160
|
+
const settings = {
|
|
161
|
+
sheetName: translations.report.titleStopReport, // The name of the sheet
|
|
162
|
+
fileName // The name of the spreadsheet
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const headers = [
|
|
166
|
+
{ label: translations.report.date, value: 'date' },
|
|
167
|
+
{ label: translations.report.start, value: 'start' },
|
|
168
|
+
{ label: translations.report.end, value: 'end' },
|
|
169
|
+
{ label: translations.report.address, value: 'address' },
|
|
170
|
+
{ label: translations.report.idleTime, value: 'idleTime' },
|
|
171
|
+
{ label: translations.report.event_ignitionOff, value: 'stopTime' }
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
let data = []
|
|
175
|
+
if (reportData.devices) {
|
|
176
|
+
reportData.devices.forEach(d => {
|
|
177
|
+
data = data.concat([{}])
|
|
178
|
+
data = data.concat(d.stops.map(a => {
|
|
179
|
+
return {
|
|
180
|
+
name: a.deviceName,
|
|
181
|
+
date: getStopDate(userData.user, a),
|
|
182
|
+
start: getStopStart(userData.user, a),
|
|
183
|
+
end: getStopEnd(userData.user, a),
|
|
184
|
+
address: a.endPOIName || a.address,
|
|
185
|
+
idleTime: convertMS(a.engineHours, true),
|
|
186
|
+
stopTime: convertMS(a.stopDuration, true)
|
|
187
|
+
}
|
|
188
|
+
}))
|
|
189
|
+
// Totals
|
|
190
|
+
data = data.concat([{
|
|
191
|
+
name: d.stops.length,
|
|
192
|
+
idleTime: convertMS(d.stops.reduce((a, b) => a + b.engineHours, 0), true),
|
|
193
|
+
stopTime: convertMS(d.stops.reduce((a, b) => a + b.stopDuration, 0), true)
|
|
194
|
+
}])
|
|
195
|
+
data = data.concat([{}])
|
|
196
|
+
})
|
|
197
|
+
console.log(data)
|
|
198
|
+
return {
|
|
199
|
+
headers,
|
|
200
|
+
data,
|
|
201
|
+
settings
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function getStopDate (user, stop) {
|
|
207
|
+
return convertToLocaleDateString(stop.startTime, user.attributes.lang, user.attributes.timezone)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getStopStart (user, stop) {
|
|
211
|
+
return convertToLocaleTimeString(stop.startTime, user.attributes.lang, user.attributes.timezone)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getStopEnd (user, stop) {
|
|
215
|
+
return convertToLocaleTimeString(stop.endTime, user.attributes.lang, user.attributes.timezone)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
exports.createStopReport = createStopReport
|
|
219
|
+
exports.exportStopReportToPDF = exportStopReportToPDF
|
|
220
|
+
exports.exportStopReportToExcel = exportStopReportToExcel
|
package/src/tests/index.test.js
CHANGED
package/src/trip-report.js
CHANGED
|
@@ -7,10 +7,11 @@ const { headerFromUser, addTable } = require('./util/pdfDocument')
|
|
|
7
7
|
const { getStyle } = require('./reportStyle')
|
|
8
8
|
const traccarHelper = require('./util/traccar')
|
|
9
9
|
const trips = require('./util/trips')
|
|
10
|
-
const { isInsideTimetable,
|
|
11
|
-
const { devicesToProcess } = require('./util/device')
|
|
10
|
+
const { isInsideTimetable, isPartialInsideTimetable, calculateTrip, getTripIdleTime } = require('./util/trips')
|
|
11
|
+
const { devicesToProcess, deviceName } = require('./util/device')
|
|
12
12
|
const { getIdleEvents } = require('./util/route')
|
|
13
13
|
const { reportByDriver } = require('./util/driver')
|
|
14
|
+
const { getNearestPOIs } = require('./util/geofence')
|
|
14
15
|
|
|
15
16
|
const fileName = 'TripReport'
|
|
16
17
|
|
|
@@ -160,9 +161,14 @@ function processDevices (from, to, devices, data, userData, traccar) {
|
|
|
160
161
|
const trips = deviceTrips.filter(t => userData.allWeek || !userData.weekDays || isInsideTimetable(t, userData) || isPartialInsideTimetable(t, userData, deviceRoute))
|
|
161
162
|
const stops = data.stops.filter(s => s.deviceId === d.id)
|
|
162
163
|
|
|
163
|
-
addNearestPOIs(trips, userData)
|
|
164
|
-
|
|
165
164
|
trips.forEach(trip => {
|
|
165
|
+
trip.totalKms = trip.distance / 1000
|
|
166
|
+
|
|
167
|
+
const nearestPOIs = getNearestPOIs(trip.endLon, trip.endLat, userData.geofences)
|
|
168
|
+
if (nearestPOIs.length > 0) {
|
|
169
|
+
trip.endPOIName = nearestPOIs[0].p.name
|
|
170
|
+
}
|
|
171
|
+
|
|
166
172
|
if ((deviceRoute[0].protocol === 'teltonika' && deviceRoute[0].attributes.fuel) ||
|
|
167
173
|
automaticReports.deviceWithFuelInfo(d)) {
|
|
168
174
|
trip.fuelConsumption = trip.spentFuel
|
|
@@ -220,12 +226,17 @@ function processDrivers (from, to, userData, data) {
|
|
|
220
226
|
const idleEvents = getIdleEvents(data.route, d)
|
|
221
227
|
|
|
222
228
|
trips.forEach(function (trip, i) {
|
|
229
|
+
trip.totalKms = trip.distance / 1000
|
|
230
|
+
|
|
231
|
+
const nearestPOIs = getNearestPOIs(trip.endLon, trip.endLat, userData.geofences)
|
|
232
|
+
if (nearestPOIs.length > 0) {
|
|
233
|
+
trip.endPOIName = nearestPOIs[0].p.name
|
|
234
|
+
}
|
|
235
|
+
|
|
223
236
|
trip.stopEngineHours = getTripIdleTime(trip, idleEvents)
|
|
224
237
|
trip.stopDuration = i !== trips.length - 1 ? (new Date(trips[i + 1].startTime) - new Date(trip.endTime)) : 0
|
|
225
238
|
})
|
|
226
239
|
|
|
227
|
-
addNearestPOIs(trips, userData)
|
|
228
|
-
|
|
229
240
|
if (trips.length > 0) {
|
|
230
241
|
const driverData = {
|
|
231
242
|
driver: d,
|
|
@@ -461,10 +472,6 @@ function exportTripReportToExcel (userData, reportData) {
|
|
|
461
472
|
}
|
|
462
473
|
}
|
|
463
474
|
|
|
464
|
-
function deviceName (device) {
|
|
465
|
-
return device.name + (device.attributes.license_plate ? ', ' + device.attributes.license_plate : '') + (device.model ? ', ' + device.model : '')
|
|
466
|
-
}
|
|
467
|
-
|
|
468
475
|
function getTripDate (user, trip) {
|
|
469
476
|
return convertToLocaleDateString(trip.startTime, user.attributes.lang, user.attributes.timezone)
|
|
470
477
|
}
|
package/src/util/device.js
CHANGED
|
@@ -7,4 +7,8 @@ function devicesToProcess (userData) {
|
|
|
7
7
|
return devices
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
exports.deviceName = function deviceName (device) {
|
|
11
|
+
return device.name + (device.attributes.license_plate ? ', ' + device.attributes.license_plate : '') + (device.model ? ', ' + device.model : '')
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
exports.devicesToProcess = devicesToProcess
|
package/src/util/geofence.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const turf = require('@turf/helpers')
|
|
2
2
|
const inside = require('@turf/boolean-point-in-polygon')
|
|
3
|
+
const { coordsDistance } = require('./utils')
|
|
3
4
|
|
|
4
5
|
exports.insideGeofence = function insideGeofence (position, geofence) {
|
|
5
6
|
const coords = geofence.area.slice(9, geofence.area.length - 2).split(',')
|
|
@@ -11,3 +12,17 @@ exports.insideGeofence = function insideGeofence (position, geofence) {
|
|
|
11
12
|
|
|
12
13
|
return inside.default(pt, poly)
|
|
13
14
|
}
|
|
15
|
+
|
|
16
|
+
exports.getNearestPOIs = function getNearestPOIs (long, lat, geofences) {
|
|
17
|
+
const distance = geofences
|
|
18
|
+
.filter(g => g && g.area.startsWith('CIRCLE'))
|
|
19
|
+
.map(g => {
|
|
20
|
+
const str = g.area.substring('CIRCLE ('.length, g.area.indexOf(','))
|
|
21
|
+
const coord = str.trim().split(' ')
|
|
22
|
+
return {
|
|
23
|
+
p: g,
|
|
24
|
+
distance: Math.round(coordsDistance(parseFloat(coord[1]), parseFloat(coord[0]), long, lat))
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
return distance.filter(a => a.distance < 100).sort((a, b) => (a.distance > b.distance) ? 1 : -1)
|
|
28
|
+
}
|
package/src/util/pdfDocument.js
CHANGED
|
@@ -48,6 +48,12 @@ function addTable (doc, headers, data, footValues, style, startY, columnStyles =
|
|
|
48
48
|
|
|
49
49
|
},
|
|
50
50
|
didDrawCell: (data) => {
|
|
51
|
+
data.table.head.forEach((footRow) => {
|
|
52
|
+
const keys = Object.keys(columnStyles)
|
|
53
|
+
keys.forEach(a => {
|
|
54
|
+
footRow.cells[a].styles.halign = 'right'
|
|
55
|
+
})
|
|
56
|
+
})
|
|
51
57
|
data.table.foot.forEach((footRow) => {
|
|
52
58
|
const keys = Object.keys(columnStyles)
|
|
53
59
|
keys.forEach(a => {
|
package/src/util/trips.js
CHANGED
|
@@ -4,27 +4,6 @@ const { isInside } = require('./timetable')
|
|
|
4
4
|
const minDistance = 0
|
|
5
5
|
const minAvgSpeed = 0
|
|
6
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
|
-
|
|
28
7
|
function checkTripsKms (traccarInstance, from, to, devices, data) {
|
|
29
8
|
console.log('checkTripsKms')
|
|
30
9
|
const trips = data.trips.filter(t => t.distance === minDistance && t.averageSpeed > minAvgSpeed)
|
|
@@ -165,6 +144,5 @@ function getTripIdleTime (trip, idleEvents) {
|
|
|
165
144
|
exports.checkTripsKms = checkTripsKms
|
|
166
145
|
exports.isInsideTimetable = isInsideTimetable
|
|
167
146
|
exports.isPartialInsideTimetable = isPartialInsideTimetable
|
|
168
|
-
exports.addNearestPOIs = addNearestPOIs
|
|
169
147
|
exports.calculateTrip = calculateTrip
|
|
170
148
|
exports.getTripIdleTime = getTripIdleTime
|