fleetmap-reports 2.0.358 → 2.0.359

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 (81) hide show
  1. package/package.json +1 -1
  2. package/src/partnerReports/driverranking-report.js +39 -7
  3. package/.claude/worktrees/eager-stonebraker-c08ac7/.eslintrc.js +0 -15
  4. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/enGB.js +0 -309
  5. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/esCL.js +0 -297
  6. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/frFR.json +0 -324
  7. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/index.js +0 -35
  8. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptBR.js +0 -301
  9. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptPT.js +0 -310
  10. package/.claude/worktrees/eager-stonebraker-c08ac7/package-lock.json +0 -11944
  11. package/.claude/worktrees/eager-stonebraker-c08ac7/package.json +0 -45
  12. package/.claude/worktrees/eager-stonebraker-c08ac7/src/activity-report.js +0 -822
  13. package/.claude/worktrees/eager-stonebraker-c08ac7/src/automaticReports.js +0 -34
  14. package/.claude/worktrees/eager-stonebraker-c08ac7/src/carbone/index.js +0 -13
  15. package/.claude/worktrees/eager-stonebraker-c08ac7/src/custom/vistawasteActivity-report.js +0 -544
  16. package/.claude/worktrees/eager-stonebraker-c08ac7/src/events-report.js +0 -360
  17. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-consumption-report.js +0 -296
  18. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-drop-report.js +0 -128
  19. package/.claude/worktrees/eager-stonebraker-c08ac7/src/here.js +0 -172
  20. package/.claude/worktrees/eager-stonebraker-c08ac7/src/idle-report.js +0 -403
  21. package/.claude/worktrees/eager-stonebraker-c08ac7/src/index.js +0 -244
  22. package/.claude/worktrees/eager-stonebraker-c08ac7/src/kms-report.js +0 -549
  23. package/.claude/worktrees/eager-stonebraker-c08ac7/src/location-report.js +0 -496
  24. package/.claude/worktrees/eager-stonebraker-c08ac7/src/machines-report.js +0 -278
  25. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/afriquia.js +0 -129
  26. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/dailyuse-report.js +0 -80
  27. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/delayedstart-report.js +0 -223
  28. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/driverranking-report.js +0 -328
  29. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/gpsjump-report.js +0 -61
  30. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/performance-report.js +0 -359
  31. package/.claude/worktrees/eager-stonebraker-c08ac7/src/refueling-report.js +0 -345
  32. package/.claude/worktrees/eager-stonebraker-c08ac7/src/reportStyle.js +0 -34
  33. package/.claude/worktrees/eager-stonebraker-c08ac7/src/sensor-report.js +0 -447
  34. package/.claude/worktrees/eager-stonebraker-c08ac7/src/speeding-report.js +0 -663
  35. package/.claude/worktrees/eager-stonebraker-c08ac7/src/stop-report.js +0 -242
  36. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ActivityReportTemplate.mjml +0 -51
  37. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EmptyReportTemplate.mjml +0 -25
  38. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EventsReportTemplate.mjml +0 -75
  39. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/FuelDropReportTemplate.mjml +0 -60
  40. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/IdleReportTemplate.mjml +0 -54
  41. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportGroupByDayTemplate.mjml +0 -43
  42. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportTemplate.mjml +0 -44
  43. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/LocationReportTemplate.mjml +0 -37
  44. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/RefuelingReportTemplate.mjml +0 -60
  45. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SensorReportTemplate.mjml +0 -23
  46. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SpeedingReportTemplate.mjml +0 -80
  47. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/TripReportTemplate.mjml +0 -97
  48. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ZoneReportTemplate.mjml +0 -52
  49. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/report.mjml +0 -96
  50. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/activity.test.js +0 -99
  51. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/carbone.test.js +0 -20
  52. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/events.test.js +0 -30
  53. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/fuel.test.js +0 -35
  54. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/idle.test.js +0 -16
  55. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.js +0 -24
  56. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.test.js +0 -203
  57. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/kms.test.js +0 -74
  58. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/performance.test.js +0 -36
  59. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/positions.test.js +0 -67
  60. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/speeding.test.js +0 -120
  61. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/translations.test.js +0 -21
  62. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/trips.test.js +0 -140
  63. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/zones.test.js +0 -162
  64. package/.claude/worktrees/eager-stonebraker-c08ac7/src/trip-report.js +0 -641
  65. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/device.js +0 -13
  66. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/driver.js +0 -90
  67. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/fuel.js +0 -102
  68. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/geofence.js +0 -52
  69. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/odoo.js +0 -18
  70. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/parallel.js +0 -64
  71. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/pdfDocument.js +0 -140
  72. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/route.js +0 -78
  73. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/timetable.js +0 -30
  74. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.js +0 -213
  75. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.worker.js +0 -49
  76. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/trips.js +0 -270
  77. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/utils.js +0 -358
  78. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/worker.js +0 -14
  79. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/xpert.js +0 -58
  80. package/.claude/worktrees/eager-stonebraker-c08ac7/src/word/index.js +0 -95
  81. 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