fleetmap-reports 2.0.356 → 2.0.358

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 (88) hide show
  1. package/.claude/worktrees/eager-stonebraker-c08ac7/.eslintrc.js +15 -0
  2. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/enGB.js +309 -0
  3. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/esCL.js +297 -0
  4. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/frFR.json +324 -0
  5. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/index.js +35 -0
  6. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptBR.js +301 -0
  7. package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptPT.js +310 -0
  8. package/.claude/worktrees/eager-stonebraker-c08ac7/package-lock.json +11944 -0
  9. package/.claude/worktrees/eager-stonebraker-c08ac7/package.json +45 -0
  10. package/.claude/worktrees/eager-stonebraker-c08ac7/src/activity-report.js +822 -0
  11. package/.claude/worktrees/eager-stonebraker-c08ac7/src/automaticReports.js +34 -0
  12. package/.claude/worktrees/eager-stonebraker-c08ac7/src/carbone/index.js +13 -0
  13. package/.claude/worktrees/eager-stonebraker-c08ac7/src/custom/vistawasteActivity-report.js +544 -0
  14. package/.claude/worktrees/eager-stonebraker-c08ac7/src/events-report.js +360 -0
  15. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-consumption-report.js +296 -0
  16. package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-drop-report.js +128 -0
  17. package/.claude/worktrees/eager-stonebraker-c08ac7/src/here.js +172 -0
  18. package/.claude/worktrees/eager-stonebraker-c08ac7/src/idle-report.js +403 -0
  19. package/.claude/worktrees/eager-stonebraker-c08ac7/src/index.js +244 -0
  20. package/.claude/worktrees/eager-stonebraker-c08ac7/src/kms-report.js +549 -0
  21. package/.claude/worktrees/eager-stonebraker-c08ac7/src/location-report.js +496 -0
  22. package/.claude/worktrees/eager-stonebraker-c08ac7/src/machines-report.js +278 -0
  23. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/afriquia.js +129 -0
  24. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/dailyuse-report.js +80 -0
  25. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/delayedstart-report.js +223 -0
  26. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/driverranking-report.js +328 -0
  27. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/gpsjump-report.js +61 -0
  28. package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/performance-report.js +359 -0
  29. package/.claude/worktrees/eager-stonebraker-c08ac7/src/refueling-report.js +345 -0
  30. package/.claude/worktrees/eager-stonebraker-c08ac7/src/reportStyle.js +34 -0
  31. package/.claude/worktrees/eager-stonebraker-c08ac7/src/sensor-report.js +447 -0
  32. package/.claude/worktrees/eager-stonebraker-c08ac7/src/speeding-report.js +663 -0
  33. package/.claude/worktrees/eager-stonebraker-c08ac7/src/stop-report.js +242 -0
  34. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ActivityReportTemplate.mjml +51 -0
  35. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EmptyReportTemplate.mjml +25 -0
  36. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EventsReportTemplate.mjml +75 -0
  37. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/FuelDropReportTemplate.mjml +60 -0
  38. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/IdleReportTemplate.mjml +54 -0
  39. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportGroupByDayTemplate.mjml +43 -0
  40. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportTemplate.mjml +44 -0
  41. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/LocationReportTemplate.mjml +37 -0
  42. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/RefuelingReportTemplate.mjml +60 -0
  43. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SensorReportTemplate.mjml +23 -0
  44. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SpeedingReportTemplate.mjml +80 -0
  45. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/TripReportTemplate.mjml +97 -0
  46. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ZoneReportTemplate.mjml +52 -0
  47. package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/report.mjml +96 -0
  48. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/activity.test.js +99 -0
  49. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/carbone.test.js +20 -0
  50. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/events.test.js +30 -0
  51. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/fuel.test.js +35 -0
  52. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/idle.test.js +16 -0
  53. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.js +24 -0
  54. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.test.js +203 -0
  55. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/kms.test.js +74 -0
  56. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/performance.test.js +36 -0
  57. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/positions.test.js +67 -0
  58. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/speeding.test.js +120 -0
  59. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/translations.test.js +21 -0
  60. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/trips.test.js +140 -0
  61. package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/zones.test.js +162 -0
  62. package/.claude/worktrees/eager-stonebraker-c08ac7/src/trip-report.js +641 -0
  63. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/device.js +13 -0
  64. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/driver.js +90 -0
  65. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/fuel.js +102 -0
  66. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/geofence.js +52 -0
  67. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/odoo.js +18 -0
  68. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/parallel.js +64 -0
  69. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/pdfDocument.js +140 -0
  70. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/route.js +78 -0
  71. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/timetable.js +30 -0
  72. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.js +213 -0
  73. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.worker.js +49 -0
  74. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/trips.js +270 -0
  75. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/utils.js +358 -0
  76. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/worker.js +14 -0
  77. package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/xpert.js +58 -0
  78. package/.claude/worktrees/eager-stonebraker-c08ac7/src/word/index.js +95 -0
  79. package/.claude/worktrees/eager-stonebraker-c08ac7/src/zone-report.js +904 -0
  80. package/lang/enGB.js +18 -0
  81. package/lang/esCL.js +18 -0
  82. package/lang/frFR.json +7 -1
  83. package/lang/ptBR.js +18 -0
  84. package/lang/ptPT.js +18 -0
  85. package/package.json +1 -1
  86. package/src/partnerReports/driverranking-report.js +152 -49
  87. package/src/speeding-report.js +11 -1
  88. package/src/util/pdfDocument.js +2 -1
@@ -0,0 +1,242 @@
1
+ const { devicesToProcess, deviceName } = require('./util/device')
2
+ const automaticReports = require('./automaticReports')
3
+ const traccarHelper = require('./util/traccar')
4
+ const { getNearestPOIs, insideGeofence, loadGroupsData } = require('./util/geofence')
5
+ const {
6
+ getTranslations, convertToLocaleString, convertMS,
7
+ getLanguage
8
+ } = require('./util/utils')
9
+ const jsPDF = require('jspdf')
10
+ const { headerFromUser, addTable } = require('./util/pdfDocument')
11
+ const { getStyle } = require('./reportStyle')
12
+ const { getUserPartner } = require('fleetmap-partners')
13
+ const { calculateStopDuration } = require('./util/trips')
14
+
15
+ const fileName = 'StopReport'
16
+
17
+ async function createStopReport (from, to, userData, traccar) {
18
+ console.log('Create StopReport')
19
+ const reportData = []
20
+
21
+ const report = await createStopReportByDevice(from, to, userData, traccar)
22
+ reportData.push(report)
23
+
24
+ return reportData
25
+ }
26
+
27
+ async function createStopReportByDevice (from, to, userData, traccar) {
28
+ const devices = devicesToProcess(userData)
29
+
30
+ const allData = {
31
+ devices: []
32
+ }
33
+
34
+ await loadGroupsData(userData, traccar)
35
+
36
+ const sliced = automaticReports.sliceArray(devices, 5)
37
+
38
+ let deviceCount = 0
39
+ for (const slice of sliced) {
40
+ const allInOne = await traccarHelper.getAllInOne(traccar, from, to, slice, true, false, true, false, deviceCount, devices.length)
41
+ console.log('Stops:' + allInOne.stops.length)
42
+
43
+ if (allInOne.stops.length > 0) {
44
+ allData.devices.push(...processDevices(from, to, slice, allInOne, userData))
45
+ }
46
+ deviceCount = deviceCount + slice.length
47
+ }
48
+
49
+ return allData
50
+ }
51
+
52
+ function processDevices (from, to, devices, data, userData) {
53
+ const devicesResult = []
54
+
55
+ devices.forEach(d => {
56
+ const deviceStops = data.stops.filter(t => t.deviceId === d.id)
57
+ const route = data.route.filter(t => t.deviceId === d.id)
58
+
59
+ deviceStops.forEach(stop => {
60
+ stop.stopDuration = calculateStopDuration(stop)
61
+ })
62
+
63
+ if (deviceStops.length && route.length && !route[0].attributes.ignition) {
64
+ deviceStops[0].startTime = undefined
65
+ }
66
+
67
+ const filteredStops = deviceStops.filter(s => s.stopDuration > (userData.minimumStopMinutes ? userData.minimumStopMinutes * 60 * 1000 : 0))
68
+
69
+ filteredStops.forEach(stop => {
70
+ const routeInsideGeofence = route.filter(p =>
71
+ new Date(p.fixTime).getTime() >= new Date(stop.startTime).getTime() &&
72
+ new Date(p.fixTime).getTime() <= new Date(stop.endTime).getTime())
73
+
74
+ const nearestPOIs = getNearestPOIs(stop.longitude, stop.latitude, userData.geofences)
75
+ if (nearestPOIs.length > 0) {
76
+ stop.endPOIName = nearestPOIs[0].p.name
77
+ }
78
+
79
+ routeInsideGeofence.every(p => {
80
+ const geofence = userData.geofences.filter(g => g && g.area.startsWith('POLYGON')).find(g =>
81
+ insideGeofence({ latitude: p.latitude, longitude: p.longitude }, g)
82
+ )
83
+ if (geofence) {
84
+ const group = userData.groups.find(g => g.geofenceIds && g.geofenceIds.includes(geofence.id))
85
+ stop.geofenceName = geofence.name
86
+ stop.geofenceGroup = (group && group.name) || ''
87
+ return false
88
+ }
89
+ return true
90
+ })
91
+ })
92
+
93
+ if (filteredStops.length > 0) {
94
+ const deviceData = {
95
+ device: d,
96
+ from,
97
+ to,
98
+ stops: filteredStops
99
+ }
100
+
101
+ devicesResult.push(deviceData)
102
+ }
103
+ })
104
+
105
+ return devicesResult
106
+ }
107
+
108
+ async function exportStopReportToPDF (userData, reportData) {
109
+ console.log('Export stop report to PDF')
110
+
111
+ const timezone = userData.user.attributes.timezone
112
+ const translations = getTranslations(userData)
113
+ const lang = getLanguage(userData)
114
+ const stopsData = userData.byDriver ? reportData.drivers : reportData.devices
115
+
116
+ const headers = [
117
+ translations.report.start,
118
+ translations.report.end,
119
+ translations.report.address,
120
+ translations.report.idleTime,
121
+ translations.report.event_ignitionOff,
122
+ translations.report.zone
123
+ ]
124
+
125
+ if (stopsData) {
126
+ // eslint-disable-next-line new-cap
127
+ const doc = new jsPDF.jsPDF('l')
128
+ await headerFromUser(doc, translations.report.titleTripReport, userData.user)
129
+
130
+ stopsData.forEach(function (d, index) {
131
+ const data = []
132
+ const name = deviceName(d.device)
133
+ const group = userData.groups.find(g => d.device.groupId === g.id)
134
+
135
+ const space = index === 0 ? 8 : 0
136
+ if (index) {
137
+ doc.addPage()
138
+ }
139
+
140
+ doc.setFontSize(13)
141
+ doc.text(name, 20, space + 20)
142
+ doc.setFontSize(11)
143
+ doc.text(group ? translations.report.group + ': ' + group.name : '', 200, space + 20)
144
+ doc.text(convertToLocaleString(d.from, lang, timezone) + ' - ' + convertToLocaleString(d.to, lang, timezone), 20, space + 25)
145
+ doc.text(translations.report.minimumMinutes + ': ' + userData.minimumStopMinutes + ' ' + translations.report.minutes, 20, space + 35)
146
+
147
+ d.stops.forEach(a => {
148
+ data.push([
149
+ getStopStart(userData.user, a),
150
+ getStopEnd(userData.user, a),
151
+ a.endPOIName || a.address,
152
+ convertMS(a.engineHours, true),
153
+ convertMS(a.stopDuration, true),
154
+ (a.geofenceName || '') + (a.geofenceGroup ? ' (' + a.geofenceGroup + ')' : '')
155
+ ])
156
+ })
157
+
158
+ const footValues = [
159
+ 'Total:' + d.stops.length,
160
+ '', '', '',
161
+ convertMS(d.stops.reduce((a, b) => a + b.engineHours, 0), true),
162
+ convertMS(d.stops.reduce((a, b) => a + b.stopDuration, 0), true)]
163
+
164
+ const style = getStyle(getUserPartner(userData.user))
165
+ addTable(doc,
166
+ headers, data, footValues, style,
167
+ space + 45,
168
+ {
169
+ 4: { halign: 'right' },
170
+ 5: { halign: 'right' }
171
+ })
172
+ })
173
+ return doc
174
+ }
175
+ }
176
+
177
+ function exportStopReportToExcel (userData, reportData) {
178
+ console.log('Export stop report to Excel')
179
+
180
+ const translations = getTranslations(userData)
181
+
182
+ const settings = {
183
+ sheetName: translations.report.titleStopReport, // The name of the sheet
184
+ fileName // The name of the spreadsheet
185
+ }
186
+
187
+ const headers = [
188
+ { label: translations.report.vehicle, value: 'name' },
189
+ { label: translations.report.start, value: 'start' },
190
+ { label: translations.report.end, value: 'end' },
191
+ { label: translations.report.address, value: 'address' },
192
+ { label: translations.report.idleTime, value: 'idleTime' },
193
+ { label: translations.report.event_ignitionOff, value: 'stopTime' },
194
+ { label: translations.report.zone, value: 'zone' }
195
+ ]
196
+
197
+ let data = []
198
+ if (reportData.devices) {
199
+ reportData.devices.forEach(d => {
200
+ data = data.concat([{}])
201
+ data = data.concat(d.stops.map(a => {
202
+ return {
203
+ name: a.deviceName,
204
+ start: getStopStart(userData.user, a),
205
+ end: getStopEnd(userData.user, a),
206
+ address: a.endPOIName || a.address,
207
+ idleTime: convertMS(a.engineHours, true),
208
+ stopTime: convertMS(a.stopDuration, true),
209
+ zone: (a.geofenceName || '') + (a.geofenceGroup ? ' (' + a.geofenceGroup + ')' : '')
210
+ }
211
+ }))
212
+ // Totals
213
+ data = data.concat([{
214
+ name: d.stops.length,
215
+ idleTime: convertMS(d.stops.reduce((a, b) => a + b.engineHours, 0), true),
216
+ stopTime: convertMS(d.stops.reduce((a, b) => a + b.stopDuration, 0), true)
217
+ }])
218
+ data = data.concat([{}])
219
+ })
220
+ console.log(data)
221
+ return {
222
+ headers,
223
+ data,
224
+ settings
225
+ }
226
+ }
227
+ }
228
+
229
+ function getStopStart (user, stop) {
230
+ return stop.startTime ? convertToLocaleString(stop.startTime, user.attributes.lang, user.attributes.timezone) : ''
231
+ }
232
+
233
+ function getStopEnd (user, stop) {
234
+ return stop.endTime ? convertToLocaleString(stop.endTime, user.attributes.lang, user.attributes.timezone) : ''
235
+ }
236
+
237
+ exports.createStopReport = createStopReport
238
+ exports.exportStopReportToPDF = exportStopReportToPDF
239
+ exports.exportStopReportToExcel = exportStopReportToExcel
240
+ exports.create = createStopReport
241
+ exports.exportToPDF = exportStopReportToPDF
242
+ exports.exportToExcel = exportStopReportToExcel
@@ -0,0 +1,51 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding="10px 5px 0px 5px" >
4
+ <mj-column width="60%" style="float: left" text-align="left">
5
+ <mj-text>
6
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleActivityReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section>
14
+ <mj-section padding="0px">
15
+ <mj-table>
16
+ <tr style="font-size:11px">
17
+ <th colspan="3" style="text-align: left">
18
+ <span style="font-weight: bold;font-size:12px">{{ translations.from }} {{reportData.from.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone })}} {{ translations.to }} {{reportData.to.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone })}}</span>
19
+ </th>
20
+ </tr>
21
+ </mj-table>
22
+ </mj-section>
23
+ <mj-section>
24
+ <mj-table>
25
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
26
+ <th>{{ translations.vehicle }}</th>
27
+ <th>{{ translations.group }}</th>
28
+ <th>{{ translations.distance }}</th>
29
+ <th>{{ translations.startOdometer }}</th>
30
+ <th>{{ translations.endOdometer }}</th>
31
+ <th>{{ translations.avgSpeed }}</th>
32
+ <th>{{ translations.maxSpeed }}</th>
33
+ <th>{{ translations.engineHours }}</th>
34
+ <th>{{ translations.spentFuel }}</th>
35
+ </tr>
36
+ <tr style="font-size:9px" v-for="device in reportData.devices" v-bind:key="device.deviceId">
37
+ <th>{{device.device.name}}</th>
38
+ <th>{{device.device.groupName}}</th>
39
+ <th>{{(device.summary[0].distance/1000).toFixed(0)}}</th>
40
+ <th>{{(device.summary[0].startOdometer/1000).toFixed(0)}}</th>
41
+ <th>{{(device.summary[0].endOdometer/1000).toFixed(0)}}</th>
42
+ <th>{{Math.round(device.summary[0].averageSpeed * 1.85200)}}</th>
43
+ <th>{{Math.round(device.summary[0].maxSpeed * 1.85200)}}</th>
44
+ <th>{{convertMS(device.summary[0].engineHours)}}</th>
45
+ <th>{{device.summary[0].convertedSpentFuel >= 0 ? device.summary[0].convertedSpentFuel : 0}}</th>
46
+ </tr>
47
+ </mj-table>
48
+ </mj-section>
49
+ </mj-section>
50
+ </mj-body>
51
+ </mjml>
@@ -0,0 +1,25 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding-bottom="10px" padding-top="20px">
4
+ <mj-column width="60%">
5
+ <mj-text>
6
+ <span style="font-size:25px">{{ translations['title'+reportData.reportType] }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section>
14
+ <mj-text>
15
+ <span style="font-weight: bold;font-size:11px">
16
+ {{ translations.from }} {{ device.from.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}
17
+ {{ translations.to }} {{ device.to.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
18
+ </mj-text>
19
+ <mj-text>
20
+ <span style="font-size:25px">Relatório sem dados</span>
21
+ </mj-text>
22
+ </mj-section>
23
+
24
+ </mj-body>
25
+ </mjml>
@@ -0,0 +1,75 @@
1
+ <mjml>
2
+ <mj-head>
3
+ </mj-head>
4
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
5
+ <mj-section padding="10px 5px 0px 5px" >
6
+ <mj-column width="60%" style="float: left" text-align="left">
7
+ <mj-text>
8
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleEventsReport }}</span>
9
+ </mj-text>
10
+ </mj-column>
11
+ <mj-column width="40%">
12
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
13
+ </mj-column>
14
+ </mj-section>
15
+ <mj-section v-for="(device, index) in reportData.devices" v-bind:key="device.deviceId" padding="0px">
16
+ <mj-column>
17
+ <mj-wrapper border="1px solid #000000" padding="20px 10px">
18
+ <mj-table>
19
+ <tr>
20
+ <th colspan="4" style="text-align: left">
21
+ <span style="font-weight: bold;font-size:13px">{{device.device.name}}{{device.device.attributes.license_plate ? ', ' +device.device.attributes.license_plate : ''}}{{device.device.model ? ', ' + device.device.model : ''}}</span>
22
+ <span style="float:right; font-size:11px">{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
23
+ <span style="font-size:11px">{{ translations.from }} {{ device.from.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone }) }} {{ translations.to }} {{ device.to.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
24
+ </th>
25
+ </tr>
26
+ <tr style="font-size:10px">
27
+ <th><span style="font-weight: bold;">{{ translations.event_ignitionOn }}</span></th>
28
+ <th><span style="font-weight: bold;">{{ translations.event_ignitionOff }}</span></th>
29
+ <th><span style="font-weight: bold;">{{ translations.event_geofenceEnter }}</span></th>
30
+ <th><span style="font-weight: bold;">{{ translations.event_geofenceExit}}</span></th>
31
+ <th><span style="font-weight: bold;">{{ translations.event_deviceOverspeed}}</span></th>
32
+ </tr>
33
+ <tr style="font-size:10px">
34
+ <th>{{ device.alerts.filter(a => a.type === 'ignitionOn').length }}</th>
35
+ <th>{{ device.alerts.filter(a => a.type === 'ignitionOff').length }}</th>
36
+ <th>{{ device.alerts.filter(a => a.type === 'geofenceEnter').length }}</th>
37
+ <th>{{ device.alerts.filter(a => a.type === 'geofenceExit').length }}</th>
38
+ <th>{{ device.alerts.filter(a => a.type === 'deviceOverspeed').length }}</th>
39
+ </tr>
40
+ <tr style="font-size:10px">
41
+ <th><span style="font-weight: bold;">{{ translations.event_driverChanged }}</span></th>
42
+ <th><span style="font-weight: bold;">{{ translations.event_powerOn }}</span></th>
43
+ <th><span style="font-weight: bold;">{{ translations.event_sos }}</span></th>
44
+ <th><span style="font-weight: bold;">{{ translations.event_deviceFuelDrop}}</span></th>
45
+ </tr>
46
+ <tr style="font-size:10px">
47
+ <th>{{ device.alerts.filter(a => a.type === 'driverChanged').length }}</th>
48
+ <th>{{ device.alerts.filter(a => a.type === 'alarm' && a.attributes.alarm === 'powerOn').length }}</th>
49
+ <th>{{ device.alerts.filter(a => a.type === 'alarm' && a.attributes.alarm === 'sos').length }}</th>
50
+ <th>{{ device.alerts.filter(a => a.type === 'deviceFuelDrop').length }}</th>
51
+ </tr>
52
+ </mj-table>
53
+ <mj-table>
54
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
55
+ <th rowspan="2">{{ translations.eventType }}</th>
56
+ <th rowspan="2">{{ translations.date }}</th>
57
+ <th rowspan="2">{{ translations.address }}</th>
58
+ <th rowspan="2">{{ translations.info }}</th>
59
+ </tr>
60
+ <mj-section v-for="(alert, index) in device.alerts" v-bind:key="alert.deviceId">
61
+ <tr :style="index%2 ? 'text-align: center;background-color:#E3E3E3' : 'text-align: center;background-color:#FFFFFF'" >
62
+ <td style="font-size:10px">{{ alert.type === 'alarm' ? translations['event_'+alert.attributes.alarm] : translations['event_'+alert.type] }}</td>
63
+ <td style="font-size:10px">{{alert.position ?
64
+ new Date(alert.position.fixTime).toLocaleTimeString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false }) :
65
+ new Date(alert.serverTime).toLocaleTimeString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</td>
66
+ <td style="font-size:10px">{{alert.geofenceName ? alert.geofenceName : (alert.position ? alert.position.address : '')}}</td>
67
+ <td style="font-size:10px">{{getAlertInfo(alert)}}</td>
68
+ </tr>
69
+ </mj-section>
70
+ </mj-table>
71
+ </mj-wrapper>
72
+ </mj-column>
73
+ </mj-section>
74
+ </mj-body>
75
+ </mjml>
@@ -0,0 +1,60 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding-bottom="10px" padding-top="20px">
4
+ <mj-column width="100%">
5
+ <mj-text>
6
+ <span style="font-size:25px">{{ translations.titleFuelDropReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ </mj-section>
10
+ <mj-section>
11
+ <mj-section padding-bottom="15px">
12
+ <mj-table>
13
+ <tr style="font-size:12px">
14
+ <th colspan="3" style="text-align: left">
15
+ <span style="font-weight: bold;font-size:12px">{{ translations.from }} {{ reportData.from.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }} {{ translations.to }} {{ reportData.to.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
16
+ </th>
17
+ </tr>
18
+ <tr style="font-size:12px">
19
+ <th><span style="font-weight: bold;">{{ translations.vehicles }}</span></th>
20
+ <th><span style="font-weight: bold;">{{ translations.totalFuelDrops }}</span></th>
21
+ <th><span style="font-weight: bold;">{{ translations.totalFuelDropLiters }} (L)</span></th>
22
+ </tr>
23
+ <tr style="font-size:10px">
24
+ <th>{{reportData.totalDevices}}</th>
25
+ <th>{{reportData.totalFuelDrops}}</th>
26
+ <th>{{reportData.totalFuelDropLiters}}</th>
27
+ </tr>
28
+ </mj-table>
29
+ </mj-section>
30
+ <mj-section>
31
+ <mj-table>
32
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
33
+ <th>{{ translations.date }}</th>
34
+ <th>{{ translations.address }}</th>
35
+ <th>{{ translations.totalFuelDropLiters }} (L)</th>
36
+ <th>{{ translations.driver }}</th>
37
+ </tr>
38
+ <mj-section v-for="(device, index) in reportData.devices" v-bind:key="device.deviceId" >
39
+ <tr>
40
+ <th colspan="4"><span style="float:left;font-weight: bold;font-size:11px">{{device.device.name}}</span><span style="float:right; font-size:11px">Depósito:{{device.device.attributes.fuel_tank_capacity}}L</span></th>
41
+ </tr>
42
+ <tr style="font-size:9px" v-for="(alert, index) in device.alerts" v-bind:key="device.deviceId">
43
+ <th>{{alert.position.fixTime.substring(0, 10)}} {{alert.position.fixTime.substring(11, 19)}}</th>
44
+ <th>{{alert.position.geofenceName ? alert.position.geofenceName : alert.position.address}}</th>
45
+ <th>{{alert.fuelDropLiters}}</th>
46
+ <th>{{alert.position.driverName ? alert.position.driverName : ''}}</th>
47
+ </tr>
48
+ </mj-section>
49
+ </mj-table>
50
+ </mj-section>
51
+ </mj-section>
52
+ <mj-section>
53
+ <mj-column width="100%">
54
+ <mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
55
+ {{ translations.unsubscribeFuelDropReport.replace('%url%', url) }}
56
+ </mj-text>
57
+ </mj-column>
58
+ </mj-section>
59
+ </mj-body>
60
+ </mjml>
@@ -0,0 +1,54 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding="10px 5px 0px 5px" >
4
+ <mj-column width="60%" style="float: left" text-align="left">
5
+ <mj-text>
6
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleIdleReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section v-for="(device, index) in reportData.devices" v-bind:key="device.deviceId" >
14
+ <mj-column>
15
+ <mj-wrapper border="1px solid #000000" padding="20px 10px">
16
+ <mj-table>
17
+ <tr style="font-size:12px">
18
+ <th colspan="4" style="text-align: left">
19
+ <span style="font-weight: bold;font-size:12px">
20
+ {{device.device.name}}{{device.device.attributes.license_plate ? ', ' +device.device.attributes.license_plate : ''}}{{device.device.model ? ', ' + device.device.model : ''}}</span>
21
+ <span style="float:right; font-weight: bold;font-size:11px">
22
+ {{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
23
+ <span style="font-weight: bold;font-size:11px">
24
+ {{ translations.from }} {{ reportData.from.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}
25
+ {{ translations.to }} {{ reportData.to.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
26
+ </th>
27
+ </tr>
28
+ </mj-table>
29
+ <mj-table>
30
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
31
+ <th>{{ translations.date }}</th>
32
+ <th>{{ translations.address }}</th>
33
+ <th>{{ translations.duration }}</th>
34
+ <th>{{ translations.driver }}</th>
35
+ </tr>
36
+ <tr style="font-size:9px" v-for="(idleEvent) in device.idleEvents" v-bind:key="idleEvent.deviceId">
37
+ <th>{{new Date(idleEvent.position.fixTime).toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</th>
38
+ <th><a target=_blank :href="`${url}/#/map?vehicleName=${device.device.name}&date=${new Date(idleEvent.position.fixTime).toISOString()}`">{{idleEvent.position.address}}</a></th>
39
+ <th>{{convertMS(idleEvent.idleTime, true)}}</th>
40
+ <th>{{idleEvent.driver}}</th>
41
+ </tr>
42
+ </mj-table>
43
+ </mj-wrapper>
44
+ </mj-column>
45
+ </mj-section>
46
+ <mj-section>
47
+ <mj-column width="100%">
48
+ <mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
49
+ {{ translations.unsubscribeIdleReport.replace('%url%', url) }}
50
+ </mj-text>
51
+ </mj-column>
52
+ </mj-section>
53
+ </mj-body>
54
+ </mjml>
@@ -0,0 +1,43 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding="10px 5px 0px 5px" >
4
+ <mj-column width="60%" style="float: left" text-align="left">
5
+ <mj-text>
6
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleKmsReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section v-for="(device, index) in reportData.devices" v-bind:key="device.deviceId" >
14
+ <mj-table>
15
+ <tr style="font-size:12px">
16
+ <th colspan="4" style="text-align: left">
17
+ <span style="font-weight: bold;font-size:12px">{{device.device.name}}{{device.device.attributes.license_plate ? ', ' +device.device.attributes.license_plate : ''}}{{device.device.model ? ', ' + device.device.model : ''}}</span>
18
+ <span style="float:right; font-weight: bold;font-size:11px">{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
19
+ <span style="font-weight: bold;font-size:11px">{{ translations.from }} {{ reportData.from.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone }) }} {{ translations.to }} {{ reportData.to.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
20
+ </th>
21
+ </tr>
22
+ </mj-table>
23
+ <mj-section>
24
+ <mj-table>
25
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
26
+ <th>{{ translations.date }}</th>
27
+ <th>{{ translations.distance }} (Kms)</th>
28
+ </tr>
29
+ <mj-section v-for="(day, index) in device.days" v-bind:key="index">
30
+ <tr :style="index%2 ? 'text-align: center;background-color:#E3E3E3' : 'text-align: center;background-color:#FFFFFF'" >
31
+ <td style="font-size:10px">{{ day.date.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false }) }} - {{ weekDays[day.date.getDay()] }}</td>
32
+ <td style="font-size:10px">{{ (day.kms/1000).toFixed(0) }}</td>
33
+ </tr>
34
+ </mj-section>
35
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
36
+ <td></td>
37
+ <td>{{ (device.days.reduce((a, b) => a + b.kms, 0) / 1000).toFixed(0) }}</td>
38
+ </tr>
39
+ </mj-table>
40
+ </mj-section>
41
+ </mj-section>
42
+ </mj-body>
43
+ </mjml>
@@ -0,0 +1,44 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding="10px 5px 0px 5px" >
4
+ <mj-column width="60%" style="float: left" text-align="left">
5
+ <mj-text>
6
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleKmsReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section>
14
+ <mj-section padding-bottom="15px">
15
+ <mj-table>
16
+ <tr style="font-size:11px">
17
+ <th colspan="3" style="text-align: left">
18
+ <span style="font-weight: bold;font-size:12px">
19
+ {{ translations.from }}
20
+ {{ reportData.from && reportData.from.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone })}}
21
+ {{ translations.to }}
22
+ {{ reportData.to && reportData.to.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone })}}
23
+ </span>
24
+ </th>
25
+ </tr>
26
+ </mj-table>
27
+ </mj-section>
28
+ <mj-section>
29
+ <mj-table>
30
+ <tr :style="'font-size:10px;background-color:'+color+';color:white'">
31
+ <th>{{ translations.vehicle }}</th>
32
+ <th>{{ translations.group }}</th>
33
+ <th>{{ translations.distance }} (Kms)</th>
34
+ </tr>
35
+ <tr style="font-size:9px" v-for="device in reportData.devices" v-bind:key="device.deviceId">
36
+ <th>{{device.device.name}}</th>
37
+ <th>{{device.device.groupName}}</th>
38
+ <th>{{(device.summary.distance/1000).toFixed(0)}}</th>
39
+ </tr>
40
+ </mj-table>
41
+ </mj-section>
42
+ </mj-section>
43
+ </mj-body>
44
+ </mjml>
@@ -0,0 +1,37 @@
1
+ <mjml>
2
+ <mj-body background-color="#fff" font-size="13px" padding-right="0px" padding-left="0px">
3
+ <mj-section padding="10px 5px 0px 5px" >
4
+ <mj-column width="60%" style="float: left" text-align="left">
5
+ <mj-text>
6
+ <span style="font-size:18px;font-weight: bold">{{ translations.titleLocationReport }}</span>
7
+ </mj-text>
8
+ </mj-column>
9
+ <mj-column width="40%">
10
+ <mj-image width="120px" :src="url + '/' + logo"></mj-image>
11
+ </mj-column>
12
+ </mj-section>
13
+ <mj-section v-for="(device, index) in reportData.devices" v-bind:key="device.deviceId" >
14
+ <mj-wrapper border="1px solid #000000" padding="20px 10px">
15
+ <mj-column width="100%">
16
+ <mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
17
+ <span style="font-weight: bold;font-size:12px">{{device.device.name}}{{device.device.attributes.license_plate ? ', ' +device.device.attributes.license_plate : ''}}{{device.device.model ? ', ' + device.device.model : ''}}</span>
18
+ <span style="float:right; font-weight: bold;font-size:11px">{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
19
+ <span style="font-weight: bold;font-size:11px">
20
+ {{ translations.from }}
21
+ {{ device.from && device.from instanceof Date && device.from.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}
22
+ {{ translations.to }}
23
+ {{ device.to && device.to instanceof Date && device.to.toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}
24
+ </span>
25
+ </mj-text>
26
+ </mj-column>
27
+ </mj-wrapper>
28
+ </mj-section>
29
+ <mj-section>
30
+ <mj-column width="100%">
31
+ <mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
32
+ {{ translations.unsubscribeLocationsReport && translations.unsubscribeLocationsReport.replace('%url%', url) }}
33
+ </mj-text>
34
+ </mj-column>
35
+ </mj-section>
36
+ </mj-body>
37
+ </mjml>