fleetmap-reports 2.0.358 → 2.0.360

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.
Files changed (82) hide show
  1. package/package.json +1 -1
  2. package/src/partnerReports/driverranking-report.js +39 -7
  3. package/src/util/utils.js +3 -0
  4. package/.claude/worktrees/eager-stonebraker-c08ac7/.eslintrc.js +0 -15
  5. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/enGB.js +0 -309
  6. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/esCL.js +0 -297
  7. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/frFR.json +0 -324
  8. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/index.js +0 -35
  9. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptBR.js +0 -301
  10. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptPT.js +0 -310
  11. package/.claude/worktrees/eager-stonebraker-c08ac7/package-lock.json +0 -11944
  12. package/.claude/worktrees/eager-stonebraker-c08ac7/package.json +0 -45
  13. package/.claude/worktrees/eager-stonebraker-c08ac7/src/activity-report.js +0 -822
  14. package/.claude/worktrees/eager-stonebraker-c08ac7/src/automaticReports.js +0 -34
  15. package/.claude/worktrees/eager-stonebraker-c08ac7/src/carbone/index.js +0 -13
  16. package/.claude/worktrees/eager-stonebraker-c08ac7/src/custom/vistawasteActivity-report.js +0 -544
  17. package/.claude/worktrees/eager-stonebraker-c08ac7/src/events-report.js +0 -360
  18. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-consumption-report.js +0 -296
  19. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-drop-report.js +0 -128
  20. package/.claude/worktrees/eager-stonebraker-c08ac7/src/here.js +0 -172
  21. package/.claude/worktrees/eager-stonebraker-c08ac7/src/idle-report.js +0 -403
  22. package/.claude/worktrees/eager-stonebraker-c08ac7/src/index.js +0 -244
  23. package/.claude/worktrees/eager-stonebraker-c08ac7/src/kms-report.js +0 -549
  24. package/.claude/worktrees/eager-stonebraker-c08ac7/src/location-report.js +0 -496
  25. package/.claude/worktrees/eager-stonebraker-c08ac7/src/machines-report.js +0 -278
  26. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/afriquia.js +0 -129
  27. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/dailyuse-report.js +0 -80
  28. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/delayedstart-report.js +0 -223
  29. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/driverranking-report.js +0 -328
  30. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/gpsjump-report.js +0 -61
  31. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/performance-report.js +0 -359
  32. package/.claude/worktrees/eager-stonebraker-c08ac7/src/refueling-report.js +0 -345
  33. package/.claude/worktrees/eager-stonebraker-c08ac7/src/reportStyle.js +0 -34
  34. package/.claude/worktrees/eager-stonebraker-c08ac7/src/sensor-report.js +0 -447
  35. package/.claude/worktrees/eager-stonebraker-c08ac7/src/speeding-report.js +0 -663
  36. package/.claude/worktrees/eager-stonebraker-c08ac7/src/stop-report.js +0 -242
  37. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ActivityReportTemplate.mjml +0 -51
  38. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EmptyReportTemplate.mjml +0 -25
  39. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EventsReportTemplate.mjml +0 -75
  40. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/FuelDropReportTemplate.mjml +0 -60
  41. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/IdleReportTemplate.mjml +0 -54
  42. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportGroupByDayTemplate.mjml +0 -43
  43. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportTemplate.mjml +0 -44
  44. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/LocationReportTemplate.mjml +0 -37
  45. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/RefuelingReportTemplate.mjml +0 -60
  46. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SensorReportTemplate.mjml +0 -23
  47. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SpeedingReportTemplate.mjml +0 -80
  48. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/TripReportTemplate.mjml +0 -97
  49. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ZoneReportTemplate.mjml +0 -52
  50. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/report.mjml +0 -96
  51. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/activity.test.js +0 -99
  52. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/carbone.test.js +0 -20
  53. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/events.test.js +0 -30
  54. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/fuel.test.js +0 -35
  55. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/idle.test.js +0 -16
  56. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.js +0 -24
  57. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.test.js +0 -203
  58. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/kms.test.js +0 -74
  59. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/performance.test.js +0 -36
  60. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/positions.test.js +0 -67
  61. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/speeding.test.js +0 -120
  62. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/translations.test.js +0 -21
  63. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/trips.test.js +0 -140
  64. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/zones.test.js +0 -162
  65. package/.claude/worktrees/eager-stonebraker-c08ac7/src/trip-report.js +0 -641
  66. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/device.js +0 -13
  67. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/driver.js +0 -90
  68. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/fuel.js +0 -102
  69. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/geofence.js +0 -52
  70. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/odoo.js +0 -18
  71. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/parallel.js +0 -64
  72. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/pdfDocument.js +0 -140
  73. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/route.js +0 -78
  74. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/timetable.js +0 -30
  75. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.js +0 -213
  76. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.worker.js +0 -49
  77. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/trips.js +0 -270
  78. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/utils.js +0 -358
  79. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/worker.js +0 -14
  80. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/xpert.js +0 -58
  81. package/.claude/worktrees/eager-stonebraker-c08ac7/src/word/index.js +0 -95
  82. package/.claude/worktrees/eager-stonebraker-c08ac7/src/zone-report.js +0 -904
@@ -1,78 +0,0 @@
1
- function getIdleEvents (route, driver, speedThreshold = 3) {
2
- const idleEvents = []
3
-
4
- const routeByDevice = route.reduce(function (a, x) {
5
- (a[x.deviceId] = a[x.deviceId] || []).push(x)
6
- return a
7
- }, {})
8
-
9
- Object.keys(routeByDevice).forEach(function (key) {
10
- let inIdle = false
11
- let last = null
12
- routeByDevice[key].forEach(p => {
13
- if (p.attributes.ignition && p.speed < speedThreshold && (!driver || p.attributes.driverUniqueId === driver.uniqueId)) {
14
- if (!inIdle) {
15
- const idleEvent = {
16
- position: p,
17
- idleTime: 0
18
- }
19
- idleEvents.push(idleEvent)
20
- inIdle = true
21
- }
22
-
23
- if (!idleEvents[idleEvents.length - 1].position.attributes.driverUniqueId) {
24
- idleEvents[idleEvents.length - 1].position.attributes.driverUniqueId = p.attributes.driverUniqueId
25
- }
26
-
27
- last = p
28
- } else if (inIdle) {
29
- const currentIdleEvent = idleEvents[idleEvents.length - 1]
30
- currentIdleEvent.idleTime = new Date(last.fixTime) - new Date(currentIdleEvent.position.fixTime)
31
- currentIdleEvent.lastPosition = last
32
- inIdle = false
33
- }
34
- })
35
- })
36
-
37
- return idleEvents
38
- }
39
-
40
- function filterPositions (positions) {
41
- return positions.filter(filterPosition)
42
- }
43
-
44
- function cleanPosition (p) {
45
- return {
46
- id: p.id,
47
- fixTime: p.fixTime,
48
- address: p.address,
49
- latitude: p.latitude,
50
- longitude: p.longitude,
51
- deviceId: p.deviceId,
52
- speed: p.speed,
53
- valid: p.valid,
54
- attributes: {
55
- ignition: p.attributes.ignition,
56
- driverUniqueId: p.attributes.driverUniqueId
57
- }
58
- }
59
- }
60
-
61
- exports.cleanPositions = (positions) => {
62
- return positions.map(cleanPosition)
63
- }
64
-
65
- function filterPosition (p) {
66
- if (p.valid === false) {
67
- return p.attributes.ignition || p.attributes.motion
68
- }
69
- if (p.protocol === 'osmand') {
70
- return !(p.attributes.event >= 200 || p.attributes.event === 30)
71
- }
72
- return true
73
- }
74
-
75
- exports.getIdleEvents = getIdleEvents
76
- exports.filterPositions = filterPositions
77
- exports.filterPosition = filterPosition
78
- exports.cleanPosition = cleanPosition
@@ -1,30 +0,0 @@
1
- const { weekDaySelected, convertFromUTC, isClientSide, convertFromLocal } = require('./utils')
2
-
3
- function isInside (_tripStart, _tripEnd, userData) {
4
- const tripStart = new Date(_tripStart)
5
- const tripEnd = new Date(_tripEnd)
6
-
7
- if (weekDaySelected(tripStart, userData.weekDays)) {
8
- const timeWindowStartLocal = new Date(convertFromUTC(_tripStart, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
9
- const timeWindowEndLocal = new Date(convertFromUTC(_tripEnd, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
10
-
11
- const timeWindowStartUTC = isClientSide() ? timeWindowStartLocal : convertFromLocal(timeWindowStartLocal, userData.user.attributes.timezone)
12
- const timeWindowEndUTC = isClientSide() ? timeWindowEndLocal : convertFromLocal(timeWindowEndLocal, userData.user.attributes.timezone)
13
-
14
- if (timeWindowStartUTC.getTime() > timeWindowEndUTC.getTime()) {
15
- const startDatePreviousDay = new Date(timeWindowStartUTC)
16
- startDatePreviousDay.setDate(timeWindowStartUTC.getDate() - 1)
17
- const endDateNextDay = new Date(timeWindowEndUTC)
18
- endDateNextDay.setDate(timeWindowEndUTC.getDate() + 1)
19
-
20
- return (tripStart.getTime() > startDatePreviousDay.getTime() && tripEnd.getTime() < timeWindowEndUTC.getTime()) ||
21
- (tripStart.getTime() > timeWindowStartUTC.getTime() && tripEnd.getTime() < endDateNextDay.getTime())
22
- }
23
- // Trips inside time period
24
- return tripStart.getTime() > timeWindowStartUTC.getTime() && tripEnd.getTime() < timeWindowEndUTC.getTime()
25
- }
26
-
27
- return false
28
- }
29
-
30
- exports.isInside = isInside
@@ -1,213 +0,0 @@
1
- const automaticReports = require('../automaticReports')
2
- const { convertFromUTC, isClientSide, convertFromLocal } = require('./utils')
3
- const path = require('path')
4
- const { cleanPositions, filterPosition } = require('./route')
5
- const Piscina = require('piscina')
6
- const piscina = new Piscina()
7
-
8
- async function getRoute (traccar, from, to, devices) {
9
- const devicesToSlice = devices.slice()
10
-
11
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice, 50)
12
- let requests = []
13
- for (const a of arrayOfArrays) {
14
- const promise = traccar.reports.reportsRouteGet(from, to, a.map(d => d.id))
15
- requests = requests.concat(promise)
16
- }
17
-
18
- const result = await Promise.all(requests)
19
- return result.map(r => r.data).flat()
20
- }
21
-
22
- async function getTrips (traccar, from, to, devices) {
23
- const devicesToSlice = devices.slice()
24
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice, 50)
25
- let requests = []
26
- for (const a of arrayOfArrays) {
27
- const promise = traccar.reports.reportsTripsGet(from, to, a.map(d => d.id))
28
- requests = requests.concat(promise)
29
- }
30
-
31
- const result = await Promise.all(requests)
32
- return result.map(r => r.data).flat()
33
- }
34
-
35
- async function getStops (traccar, from, to, devices) {
36
- const devicesToSlice = devices.slice()
37
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice, 50)
38
- let requests = []
39
- for (const a of arrayOfArrays) {
40
- const promise = traccar.reports.reportsStopsGet(from, to, a.map(d => d.id))
41
- requests = requests.concat(promise)
42
- }
43
-
44
- const result = await Promise.all(requests)
45
- return result.map(r => r.data).flat()
46
- }
47
-
48
- async function getEvents (traccar, from, to, devices, events) {
49
- const devicesToSlice = devices.slice()
50
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice, 50)
51
- let requests = []
52
- for (const a of arrayOfArrays) {
53
- const promise = traccar.reports.reportsEventsGet(from, to, a.map(d => d.id), null, events)
54
- requests = requests.concat(promise)
55
- }
56
- const result = await Promise.all(requests)
57
- return result.map(r => r.data).flat()
58
- }
59
-
60
- async function getSummary (traccar, from, to, devices) {
61
- const devicesToSlice = devices.slice()
62
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice, 50)
63
- let requests = []
64
- for (const a of arrayOfArrays) {
65
- const promise = getAllInOne(traccar, from, to, a, false, false, false, true, 0, a.length, a.length, a.length, undefined, true)
66
- requests = requests.concat(promise)
67
- }
68
-
69
- const result = await Promise.all(requests)
70
- return result.map(r => r.summary).flat()
71
- }
72
-
73
- async function getItems (traccar, u, _chunk, counter, devicesPerRequest, ignorePercentage,
74
- totalDevices, currentDeviceCount, routeOnly, filter) {
75
- try {
76
- const x = routeOnly && !isClientSide()
77
- ? await streamJson(traccar, u.replace('allinone', 'route').replace('type=route', ''), filter)
78
- : await traccar.axios.get(u, {
79
- withCredentials: true,
80
- timeout: 900000
81
- }).then(r => {
82
- if (filter && r.data.route) {
83
- r.data.route = cleanPositions(r.data.route.filter(filterPosition))
84
- }
85
- return r.data
86
- })
87
-
88
- console.log('LOADING_MESSAGE:' + _chunk[0].name)
89
- if (counter) {
90
- counter.count += devicesPerRequest
91
- ignorePercentage || console.log(`PROGRESS_PERC:${Math.round(counter.count / totalDevices * 100)}`)
92
- } else {
93
- currentDeviceCount += devicesPerRequest
94
- ignorePercentage || console.log(`PROGRESS_PERC:${Math.round(currentDeviceCount / totalDevices * 100)}`)
95
- }
96
- console.log('done devices', _chunk.map(d => d.id), 'position count', x.route && x.route.length)
97
- return x
98
- } catch (e) {
99
- console.error(e)
100
- return {}
101
- }
102
- }
103
-
104
- function getCookie (traccar) {
105
- return (traccar.axios.defaults.headers && traccar.axios.defaults.headers.cookie) ||
106
- (traccar.axios.defaults.headers && traccar.axios.defaults.headers.common && traccar.axios.defaults.headers.common.cookie) ||
107
- (require('axios').defaults.headers && require('axios').defaults.headers.common && require('axios').defaults.headers.common.cookie)
108
- }
109
-
110
- function streamJson (traccar, u, filter) {
111
- const cookie = getCookie(traccar)
112
- return piscina.run({
113
- url: traccar.axios.defaults.baseURL + u,
114
- cookie,
115
- filter
116
- },
117
- {
118
- filename: path.resolve(__dirname, './traccar.worker.js')
119
- })
120
- }
121
-
122
- async function getAllInOne (
123
- traccar,
124
- from,
125
- to,
126
- devices,
127
- getRoutes,
128
- getTrips,
129
- getStops,
130
- getSummary,
131
- currentDeviceCount = 0,
132
- totalDevices = devices.length,
133
- sliceSize = 5,
134
- devicesPerRequest = 1,
135
- counter = undefined,
136
- ignorePercentage = false,
137
- filter) {
138
- let url = `/reports/allinone?from=${from.toISOString()}&to=${to.toISOString()}`
139
- if (getRoutes) url += '&type=route'
140
- if (getTrips) url += '&type=trips'
141
- if (getStops) url += '&type=stops'
142
- if (getSummary) url += '&type=summary'
143
-
144
- const sliced = automaticReports.sliceArray(devices, sliceSize)
145
- const result = []
146
- for (const chunk of sliced) {
147
- const requests = []
148
- for (const _chunk of automaticReports.sliceArray(chunk, devicesPerRequest)) {
149
- const u = url + '&' + _chunk.map(d => `deviceId=${d.id}`).join('&')
150
- console.log(u)
151
- requests.push(
152
- getItems(traccar, u, _chunk, counter, devicesPerRequest, ignorePercentage, totalDevices, currentDeviceCount,
153
- !getTrips && !getStops && !getSummary, filter)
154
- )
155
- }
156
- const now = new Date()
157
- console.log('parallel', requests.length)
158
- try {
159
- result.push(...(await Promise.all(requests)))
160
- } catch (e) {
161
- console.error('parallel', e.message, e.config)
162
- }
163
- console.log('took', new Date() - now, 'ms')
164
- }
165
- return {
166
- route: result.filter(t => t.route).map(r => r.route).flat(),
167
- trips: result.filter(t => t.trips).map(r => r.trips).flat(),
168
- stops: result.filter(t => t.stops).map(r => r.stops).flat(),
169
- summary: result.filter(t => t.summary).map(r => r.summary).flat()
170
- }
171
- }
172
-
173
- async function getSummaryByDay (dates, userData, traccarInstance, allDevices, ignorePercentage = false, from, to) {
174
- const days = []
175
- let counter = 0
176
- for (const [index, date] of dates.entries()) {
177
- let startDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
178
- if (index === 0) {
179
- const _startDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + (isClientSide() ? from.toTimeString().slice(0, 8) : convertFromUTC(from, userData.user.attributes.timezone).toTimeString().slice(0, 8)))
180
- startDateLocal = startDateLocal.getTime() > _startDateLocal.getTime() ? startDateLocal : _startDateLocal
181
- }
182
-
183
- let endDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
184
- if (index === dates.length - 1) {
185
- const _endDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + (isClientSide() ? to.toTimeString().slice(0, 8) : convertFromUTC(to, userData.user.attributes.timezone).toTimeString().slice(0, 8)))
186
- endDateLocal = endDateLocal.getTime() < _endDateLocal.getTime() ? endDateLocal : _endDateLocal
187
- }
188
-
189
- const startDate = isClientSide() ? startDateLocal : convertFromLocal(startDateLocal, userData.user.attributes.timezone)
190
- const endDate = isClientSide() ? endDateLocal : convertFromLocal(endDateLocal, userData.user.attributes.timezone)
191
-
192
- const summary = await getSummary(traccarInstance, startDate, endDate, allDevices)
193
-
194
- counter = counter + 1
195
- if (!ignorePercentage) {
196
- console.log(`PROGRESS_PERC:${counter / dates.length * 100}`)
197
- }
198
- days.push({
199
- date,
200
- summary
201
- })
202
- }
203
-
204
- return days
205
- }
206
-
207
- exports.getRoute = getRoute
208
- exports.getTrips = getTrips
209
- exports.getStops = getStops
210
- exports.getEvents = getEvents
211
- exports.getSummary = getSummary
212
- exports.getSummaryByDay = getSummaryByDay
213
- exports.getAllInOne = getAllInOne
@@ -1,49 +0,0 @@
1
- const { chain } = require('stream-chain')
2
- const { parser } = require('stream-json')
3
- const { streamArray } = require('stream-json/streamers/StreamArray')
4
- const { Readable } = require('stream')
5
- const { cleanPosition, filterPosition } = require('./route')
6
-
7
- function fetchRetry (url, options, retry = 3) {
8
- return fetch(url, options).catch(async e => {
9
- if (retry) {
10
- console.warn(url, e.message, 'retrying', retry)
11
- return fetchRetry(url, options, retry - 1)
12
- }
13
- throw e
14
- })
15
- }
16
-
17
- module.exports = async ({ url, cookie, filter }) => {
18
- const now = new Date()
19
- const response = await fetchRetry(url, { headers: { cookie } })
20
- .catch(e => {
21
- console.error(e)
22
- throw new Error(`${e.message} traccar-worker ${cookie} ${url}`)
23
- })
24
- if (!response.ok) {
25
- throw new Error(`${cookie} ${url} Fetch failed: ${response.status} ${response.statusText}`)
26
- }
27
- console.log(url, 'took', new Date() - now, 'ms', 'streaming...')
28
- const nodeStream = Readable.fromWeb(response.body)
29
-
30
- const result = { route: [] }
31
- return new Promise((resolve, reject) => {
32
- const pipeline = chain([
33
- nodeStream,
34
- parser(),
35
- streamArray() // Stream each item in the array
36
- ])
37
- pipeline.on('data', ({ value }) => {
38
- if (filter) {
39
- if (filterPosition(value)) {
40
- result.route.push(cleanPosition(value))
41
- }
42
- } else {
43
- result.route.push(value)
44
- }
45
- })
46
- pipeline.on('end', () => resolve(result))
47
- pipeline.on('error', reject)
48
- })
49
- }
@@ -1,270 +0,0 @@
1
- const { coordsDistance, convertFromUTC, weekDaySelected, convertFromLocal, isClientSide, calculateDistance } = require('./utils')
2
- const { isInside } = require('./timetable')
3
- const traccarHelper = require('./traccar')
4
-
5
- async function calculatePartialTrip (device, startDate, endDate, route, t, traccarInstance) {
6
- let isPartialInside = false
7
- const tripStart = new Date(t.startTime)
8
- const tripEnd = new Date(t.endTime)
9
-
10
- if (startDate.getTime() > endDate.getTime()) {
11
- if (tripStart.getTime() < endDate.getTime() &&
12
- tripEnd.getTime() > endDate.getTime()) {
13
- // Trip starts inside time period and ends outside time period
14
- if (!route && device) {
15
- const allInOneData = await traccarHelper.getAllInOne(traccarInstance, startDate, endDate, [device], true, false, false, false, undefined, undefined, 5, 1, undefined, true)
16
- route = allInOneData.route
17
- }
18
- const routeInside = route.filter(p => new Date(p.fixTime).getTime() < new Date(endDate.toUTCString()).getTime() && new Date(p.fixTime).getTime() > new Date(t.startTime).getTime() && t.deviceId === p.deviceId)
19
- updateTrip(device, t, routeInside)
20
- t.endTime = endDate.toISOString().replace('Z', '+0000')
21
- t.endTimeIsOut = true
22
- isPartialInside = true
23
- }
24
-
25
- if (tripStart.getTime() < startDate.getTime() &&
26
- new Date(t.endTime).getTime() > startDate.getTime()) {
27
- // Trip starts outside time period and ends inside time period
28
- if (!route && device) {
29
- const allInOneData = await traccarHelper.getAllInOne(traccarInstance, startDate, endDate, [device], true, false, false, false, undefined, undefined, 5, 1, undefined, true)
30
- route = allInOneData.route
31
- }
32
- const routeInside = route.filter(p => new Date(p.fixTime).getTime() > startDate.getTime() && new Date(p.fixTime).getTime() < new Date(t.endTime).getTime() && t.deviceId === p.deviceId)
33
- updateTrip(device, t, routeInside)
34
- t.startTime = startDate.toISOString().replace('Z', '+0000')
35
- t.startTimeIsOut = true
36
- isPartialInside = true
37
- }
38
- } else {
39
- if (tripStart.getTime() < startDate.getTime() &&
40
- tripEnd.getTime() > startDate.getTime()) {
41
- // Trip starts outside time period and ends inside time period
42
- if (!route && device) {
43
- const allInOneData = await traccarHelper.getAllInOne(traccarInstance, startDate, endDate, [device], true, false, false, false, undefined, undefined, 5, 1, undefined, true)
44
- route = allInOneData.route
45
- }
46
- const routeInside = route.filter(p => new Date(p.fixTime).getTime() > new Date(startDate.toUTCString()).getTime() && new Date(p.fixTime).getTime() < new Date(t.endTime).getTime() && t.deviceId === p.deviceId)
47
- updateTrip(device, t, routeInside)
48
- t.startTime = startDate.toISOString().replace('Z', '+0000')
49
- t.startTimeIsOut = true
50
- isPartialInside = true
51
- }
52
-
53
- if (tripStart.getTime() < endDate.getTime() &&
54
- tripEnd.getTime() > endDate.getTime()) {
55
- // Trip starts inside time period and ends outside time period
56
- if (!route && device) {
57
- const allInOneData = await traccarHelper.getAllInOne(traccarInstance, startDate, endDate, [device], true, false, false, false, undefined, undefined, 5, 1, undefined, true)
58
- route = allInOneData.route
59
- }
60
- const routeInside = route.filter(p => new Date(p.fixTime).getTime() < endDate.getTime() && new Date(p.fixTime).getTime() > new Date(t.startTime).getTime() && t.deviceId === p.deviceId)
61
- updateTrip(device, t, routeInside)
62
- t.endTime = endDate.toISOString().replace('Z', '+0000')
63
- t.endTimeIsOut = true
64
- isPartialInside = true
65
- }
66
- }
67
- return isPartialInside
68
- }
69
-
70
- function isPartialInsideTimetable (device, t, userData, route) {
71
- if (weekDaySelected(new Date(t.startTime), userData.weekDays)) {
72
- const startDateLocal = new Date(convertFromUTC(t.startTime, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
73
- const endDateLocal = new Date(convertFromUTC(t.startTime, userData.user.attributes.timezone).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
74
-
75
- const startDate = isClientSide() ? startDateLocal : convertFromLocal(startDateLocal, userData.user.attributes.timezone)
76
- const endDate = isClientSide() ? endDateLocal : convertFromLocal(endDateLocal, userData.user.attributes.timezone)
77
-
78
- return calculatePartialTrip(device, startDate, endDate, route, t)
79
- }
80
-
81
- return false
82
- }
83
-
84
- async function getDataByDay (device, date, data, userData, traccarInstance) {
85
- const startDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' 00:00:00')
86
- const endDateLocal = new Date(convertFromUTC(date, userData.user.attributes.timezone).toISOString().split('T')[0] + ' 23:59:59')
87
- const startDate = isClientSide() ? startDateLocal : convertFromLocal(startDateLocal, userData.user.attributes.timezone)
88
- const endDate = isClientSide() ? endDateLocal : convertFromLocal(endDateLocal, userData.user.attributes.timezone)
89
-
90
- const tripsByDay = []
91
- if (data.trips) {
92
- const filteredTrips = data.trips.filter(t => new Date(t.endTime) > startDate && new Date(t.startTime) < endDate)
93
- tripsByDay.push(...filteredTrips.map(t => { return { ...t } }))
94
-
95
- for (const t of tripsByDay) {
96
- await calculatePartialTrip(device, startDate, endDate, data.route, t, traccarInstance)
97
- }
98
- }
99
-
100
- const stopsByDay = []
101
- if (data.stops) {
102
- const filteredStops = data.stops.filter(t => new Date(t.endTime) > startDate && new Date(t.startTime) < endDate)
103
- stopsByDay.push(...filteredStops.map(t => { return { ...t } }))
104
- }
105
-
106
- const routeByDay = data.route ? data.route.filter(p => (new Date(p.fixTime) > startDate && new Date(p.fixTime) < endDate)) : []
107
-
108
- const refuelingPositionsByDay = data.refuelingPositions ? data.refuelingPositions.filter(p => (new Date(p.date) > startDate && new Date(p.date) < endDate)) : []
109
-
110
- const zoneInOutDayData = data.zoneInOutData
111
- ? data.zoneInOutData.filter(z => (!z.inTime || (new Date(z.inTime.fixTime) < endDate)) &&
112
- (!z.outTime || (new Date(z.outTime.fixTime) > startDate)))
113
- : []
114
-
115
- return { tripsByDay, stopsByDay, routeByDay, refuelingPositionsByDay, zoneInOutDayData }
116
- }
117
-
118
- function isValidAvgSpeed (kms, startTime, endTime) {
119
- const totalTime = new Date(endTime).getTime() - new Date(startTime).getTime()
120
- const avgSpeed = (kms / 1000) / (totalTime / (1000 * 60 * 60))
121
- return avgSpeed < 200
122
- }
123
-
124
- function getKms (trips) {
125
- const odometerKms = trips.length > 0 ? trips[trips.length - 1].endOdometer - trips[0].startOdometer : 0
126
- return odometerKms > 0 && isValidAvgSpeed(odometerKms, trips[0].startTime, trips[trips.length - 1].endTime) ? odometerKms : trips.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
127
- }
128
-
129
- function isInsideTimetable (t, userData) {
130
- return isInside(t.startTime, t.endTime, userData)
131
- }
132
-
133
- function updateTrip (device, t, route) {
134
- route = route.filter(p => p && p.attributes.ignition)
135
- if (!route.length) { return }
136
- const distance = calculateDistance(route, device ? device.attributes['report.ignoreOdometer'] : true) * 1000
137
- t.distance = distance
138
- t.duration = new Date(route[route.length - 1].fixTime).getTime() - new Date(route[0].fixTime).getTime()
139
- t.maxSpeed = route.reduce((a, b) => Math.max(a, b.speed), 0)
140
- t.averageSpeed = distance > 0 ? ((route.reduce((a, b) => a + b.speed, 0)) / route.length) : 0
141
- t.startOdometer = device && !device.attributes['report.ignoreOdometer'] && route[0].attributes.odometer ? route[0].attributes.odometer : route[0].attributes.totalDistance
142
- t.endOdometer = device && !device.attributes['report.ignoreOdometer'] && route[route.length - 1].attributes.odometer ? route[route.length - 1].attributes.odometer : route[route.length - 1].attributes.totalDistance
143
- }
144
-
145
- function getUncompletedTrip (device, deviceRoute, deviceTrips) {
146
- if (deviceRoute.length && deviceTrips.length && deviceRoute[deviceRoute.length - 1].attributes.ignition) {
147
- const uncompletedTripRoute = deviceRoute.filter(p => p.attributes.ignition && new Date(p.fixTime).getTime() > new Date(deviceTrips[deviceTrips.length - 1].endTime).getTime())
148
- if (uncompletedTripRoute.length) {
149
- return calculateTrip(device, uncompletedTripRoute)
150
- }
151
- }
152
- }
153
-
154
- function calculateTrip (device, route) {
155
- console.log('route', route.length)
156
- const startPos = route[0]
157
- const endPos = route[route.length - 1]
158
-
159
- return {
160
- deviceId: device.id,
161
- deviceName: device.name,
162
- model: device.model,
163
- distance: calculateDistance(route, device.attributes['report.ignoreOdometer']) * 1000,
164
- averageSpeed: Math.round((route.map(p => p.speed).reduce((a, b) => a + b, 0)) / route.length),
165
- maxSpeed: route.map(p => p.speed).reduce(function (a, b) { return Math.max(a, b) }),
166
- spentFuel: 0,
167
- startOdometer: startPos.attributes.odometer || startPos.attributes.totalDistance,
168
- endOdometer: endPos.attributes.odometer || endPos.attributes.totalDistance,
169
- startPositionId: startPos.id,
170
- endPositionId: endPos.id,
171
- startLat: startPos.latitude,
172
- startLon: startPos.longitude,
173
- startTime: startPos.fixTime,
174
- startAddress: startPos.address,
175
- endLat: endPos.latitude,
176
- endLon: endPos.longitude,
177
- endTime: endPos.fixTime,
178
- endAddress: endPos.address,
179
- endTimeIsOut: true,
180
- duration: new Date(endPos.fixTime).getTime() - new Date(startPos.fixTime).getTime(),
181
- driverUniqueId: null,
182
- driverName: null
183
- }
184
- }
185
-
186
- function getTripIdleTime (trip, idleEvents) {
187
- const tripStartDate = new Date(trip.startTime)
188
- const tripEndDate = new Date(trip.endTime)
189
- const idleEventsInsideTrip = idleEvents.filter(i => tripStartDate < new Date(i.position.fixTime) && tripEndDate > new Date(i.position.fixTime))
190
- return idleEventsInsideTrip.reduce((a, b) => a + b.idleTime, 0)
191
- }
192
-
193
- function calculateStopDuration (stop) {
194
- const totalStopTime = new Date(stop.endTime) - new Date(stop.startTime)
195
- if (totalStopTime < stop.idleTime) return 0
196
- return totalStopTime - (stop.idleTime > 0 ? stop.idleTime : 0)
197
- }
198
-
199
- const maxDistanceDiff = 10000
200
-
201
- function shouldRecalculate (trip, route) {
202
- if (route && route.length) {
203
- if (!trip.distance) {
204
- return true
205
- }
206
- if (route[0].protocol === 'osmand' && route[0].attributes.odometer) {
207
- const positions = route.filter(p => p.deviceId === trip.deviceId &&
208
- new Date(p.fixTime).getTime() >= new Date(trip.startTime).getTime() &&
209
- new Date(p.fixTime).getTime() <= new Date(trip.endTime).getTime())
210
- if (positions.length) {
211
- const totalDistance = positions[positions.length - 1].attributes.totalDistance - positions[0].attributes.totalDistance
212
- return trip.distance < (totalDistance - maxDistanceDiff)
213
- }
214
- }
215
- }
216
- return false
217
- }
218
-
219
- function getTripTotalKms (trip, stop, route) {
220
- // we need to add stop kms to ensure that the total kms for the day, calculated with the odometer difference, will be equal to the sum of kms of all trips
221
- const stopKms = stop &&
222
- !route.find(p => p.attributes.putAccumulators
223
- || p.protocol === 'startek') //fix ticket 2263
224
- && (stop.endOdometer - stop.startOdometer)
225
- let distance = trip.distance + (stop && stopKms > 0 ? stopKms : 0)
226
- if (shouldRecalculate(trip, route)) {
227
- distance = 0
228
- const positions = route.filter(p => p.deviceId === trip.deviceId &&
229
- new Date(p.fixTime).getTime() >= new Date(trip.startTime).getTime() &&
230
- new Date(p.fixTime).getTime() <= new Date(trip.endTime).getTime())
231
-
232
- let current = null
233
- for (const p of positions) {
234
- if (current) {
235
- distance += coordsDistance(parseFloat(current.longitude), parseFloat(current.latitude),
236
- parseFloat(p.longitude), parseFloat(p.latitude))
237
- }
238
- current = p
239
- }
240
- }
241
- return distance / 1000
242
- }
243
-
244
- function calculateMultiDayTrips (trips, route, tripsByDay, fromByDay, toByDay, devices) {
245
- const startsOutside = trips.filter(t => (new Date(t.startTime) < fromByDay && new Date(t.endTime) > fromByDay))
246
- if (startsOutside.length > 0) {
247
- tripsByDay.push(calculateTrip(devices.find(d => d.id === startsOutside[0].deviceId),
248
- route.filter(p => new Date(p.fixTime) >= fromByDay &&
249
- new Date(p.fixTime) <= new Date(startsOutside[0].endTime))))
250
- }
251
-
252
- const endsOutside = trips.filter(t => (new Date(t.startTime) < toByDay && new Date(t.endTime) > toByDay))
253
- if (endsOutside.length > 0) {
254
- tripsByDay.push(calculateTrip(devices.find(d => d.id === endsOutside[0].deviceId),
255
- route.filter(p => new Date(p.fixTime) >= new Date(endsOutside[0].startTime) &&
256
- new Date(p.fixTime) <= toByDay)))
257
- }
258
- }
259
-
260
- exports.isInsideTimetable = isInsideTimetable
261
- exports.isPartialInsideTimetable = isPartialInsideTimetable
262
- exports.getDataByDay = getDataByDay
263
- exports.getKms = getKms
264
- exports.calculatePartialTrip = calculatePartialTrip
265
- exports.calculateTrip = calculateTrip
266
- exports.getTripIdleTime = getTripIdleTime
267
- exports.calculateStopDuration = calculateStopDuration
268
- exports.getUncompletedTrip = getUncompletedTrip
269
- exports.getTripTotalKms = getTripTotalKms
270
- exports.calculateMultiDayTrips = calculateMultiDayTrips