fleetmap-reports 2.0.61 → 2.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +0 -21
- package/src/partnerReports/dailyuse-report.js +1 -73
- package/src/speeding-report.js +5 -6
- package/src/templates/ActivityReportTemplate.mjml +51 -0
- package/src/templates/EmptyReportTemplate.mjml +25 -0
- package/src/templates/EventsReportTemplate.mjml +75 -0
- package/src/templates/FuelDropReportTemplate.mjml +60 -0
- package/src/templates/IdleReportTemplate.mjml +54 -0
- package/src/templates/KmsReportGroupByDayTemplate.mjml +43 -0
- package/src/templates/KmsReportTemplate.mjml +44 -0
- package/src/templates/LocationReportTemplate.mjml +37 -0
- package/src/templates/RefuelingReportTemplate.mjml +60 -0
- package/src/templates/SpeedingReportTemplate.mjml +78 -0
- package/src/templates/TripReportTemplate.mjml +97 -0
- package/src/templates/ZoneReportTemplate.mjml +52 -0
- package/src/templates/report.mjml +96 -0
- package/src/tests/kms.test.js +0 -19
- package/src/tests/zones.test.js +0 -17
- package/src/util/utils.js +1 -9
- package/RapportPerformance.xlsx +0 -0
- package/src/partnerReports/delayedstart-report.js +0 -69
- package/src/partnerReports/passenger-report.js +0 -46
- package/src/tests/dailyuse.test.js +0 -19
- package/src/tests/gpsjump.test.js +0 -23
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -18,7 +18,6 @@ function Reports (config, axios) {
|
|
|
18
18
|
drivers: await this.traccar.drivers.driversGet().then(d => d.data),
|
|
19
19
|
geofences: await this.traccar.geofences.geofencesGet().then(d => d.data),
|
|
20
20
|
byGroup: false,
|
|
21
|
-
allWeek: true,
|
|
22
21
|
dayHours: { startTime: '00:00', endTime: '23:59' }
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -183,25 +182,5 @@ function Reports (config, axios) {
|
|
|
183
182
|
this.stopReportToExcel = (userData, reportData) => {
|
|
184
183
|
return require('./stop-report').exportStopReportToExcel(userData, reportData)
|
|
185
184
|
}
|
|
186
|
-
|
|
187
|
-
this.performanceReport = (from, to, userData) => {
|
|
188
|
-
return require('./partnerReports/performance-report').createPerformanceReport(from, to, userData, this.traccar)
|
|
189
|
-
}
|
|
190
|
-
this.performanceReportToPDF = (userData, reportData) => {
|
|
191
|
-
return require('./partnerReports/performance-report').exportPerformanceReportToPDF(userData, reportData)
|
|
192
|
-
}
|
|
193
|
-
this.performanceReportToExcel = (userData, reportData) => {
|
|
194
|
-
return require('./partnerReports/performance-report').exportPerformanceReportToExcel(userData, reportData)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
this.dailyUseReport = (from, to, userData) => {
|
|
198
|
-
return require('./partnerReports/dailyuse-report').createDailyUseReport(from, to, userData, this.traccar)
|
|
199
|
-
}
|
|
200
|
-
this.dailyUseReportToPDF = (userData, reportData) => {
|
|
201
|
-
return require('./partnerReports/dailyuse-report').exportDailyUseReportToPDF(userData, reportData)
|
|
202
|
-
}
|
|
203
|
-
this.dailyUseReportToExcel = (userData, reportData) => {
|
|
204
|
-
return require('./partnerReports/dailyuse-report').exportDailyUseReportToExcel(userData, reportData)
|
|
205
|
-
}
|
|
206
185
|
}
|
|
207
186
|
module.exports = Reports
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
const traccarHelper = require('../util/traccar')
|
|
2
2
|
const { isInsideTimetable } = require('../util/trips')
|
|
3
|
-
const { convertFromUTCDate
|
|
3
|
+
const { convertFromUTCDate } = require('../util/utils')
|
|
4
4
|
const automaticReports = require('../automaticReports')
|
|
5
|
-
const jsPDF = require('jspdf')
|
|
6
|
-
const { getStyle } = require('../reportStyle')
|
|
7
|
-
const { getUserPartner } = require('fleetmap-partners')
|
|
8
|
-
const { addTable, headerFromUser } = require('../util/pdfDocument')
|
|
9
5
|
|
|
10
6
|
async function createDailyUseReport (from, to, userData, traccar) {
|
|
11
7
|
const reportData = []
|
|
@@ -81,72 +77,4 @@ function processDeviceData (allInOne, d, userData) {
|
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
|
|
84
|
-
async function exportDailyUseReportToPDF (userData, reportData) {
|
|
85
|
-
const translations = getTranslations(userData)
|
|
86
|
-
const timezone = userData.user.attributes.timezone
|
|
87
|
-
const lang = userData.user.attributes.lang || (isClientSide() && navigator.language)
|
|
88
|
-
|
|
89
|
-
const headers = [
|
|
90
|
-
translations.report.vehicle,
|
|
91
|
-
'Immatriculation',
|
|
92
|
-
'Groupe',
|
|
93
|
-
'Matin départ',
|
|
94
|
-
'Matin arrêt',
|
|
95
|
-
'Matin temps',
|
|
96
|
-
'Déjeuner',
|
|
97
|
-
'Après-midi départ',
|
|
98
|
-
'Après-midi arrêt',
|
|
99
|
-
'Après-midi temps',
|
|
100
|
-
'Total temps',
|
|
101
|
-
'Total conduit',
|
|
102
|
-
'Total arrêts',
|
|
103
|
-
'Total kms'
|
|
104
|
-
]
|
|
105
|
-
|
|
106
|
-
const data = []
|
|
107
|
-
reportData.forEach(d => {
|
|
108
|
-
const row = [
|
|
109
|
-
d.device,
|
|
110
|
-
d.licensePlate,
|
|
111
|
-
d.group,
|
|
112
|
-
convertToLocaleTimeString(d.morningStart, lang, timezone, userData.user),
|
|
113
|
-
convertToLocaleTimeString(d.morningEnd, lang, timezone, userData.user),
|
|
114
|
-
convertMS(d.morningTime),
|
|
115
|
-
convertMS(d.lunch),
|
|
116
|
-
convertToLocaleTimeString(d.afternoonStart, lang, timezone, userData.user),
|
|
117
|
-
convertToLocaleTimeString(d.afternoonEnd, lang, timezone, userData.user),
|
|
118
|
-
convertMS(d.afternoonTime),
|
|
119
|
-
convertMS(d.totalTime),
|
|
120
|
-
convertMS(d.totalDrivingTime),
|
|
121
|
-
d.totalStops,
|
|
122
|
-
(d.totalDistance / 100).toFixed(1)
|
|
123
|
-
]
|
|
124
|
-
data.push(row)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
const doc = new jsPDF.jsPDF('l')
|
|
128
|
-
await headerFromUser(doc, 'Rapport de Performance', userData.user)
|
|
129
|
-
const style = getStyle(getUserPartner(userData.user))
|
|
130
|
-
|
|
131
|
-
const footValues = []
|
|
132
|
-
|
|
133
|
-
doc.setFontSize(11)
|
|
134
|
-
doc.text(new Date(userData.from).toLocaleString() + ' - ' + new Date(userData.to).toLocaleString(), 20, 33)
|
|
135
|
-
|
|
136
|
-
style.headerFontSize = 8
|
|
137
|
-
style.bodyFontSize = 7
|
|
138
|
-
const columnStyles = {}
|
|
139
|
-
for (let i = 3; i < 14; i++) {
|
|
140
|
-
columnStyles[i] = { halign: 'right' }
|
|
141
|
-
}
|
|
142
|
-
addTable(doc, headers, data, footValues, style, 40, columnStyles)
|
|
143
|
-
return doc
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function exportDailyUseReportToExcel (userData, reportData) {
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
80
|
exports.createDailyUseReport = createDailyUseReport
|
|
151
|
-
exports.exportDailyUseReportToPDF = exportDailyUseReportToPDF
|
|
152
|
-
exports.exportDailyUseReportToExcel = exportDailyUseReportToExcel
|
package/src/speeding-report.js
CHANGED
|
@@ -307,9 +307,9 @@ async function getRoadSpeedLimits (devices, routes, threshold, minimumMinutes =
|
|
|
307
307
|
const position = routes.find(p => getCountry(p))
|
|
308
308
|
const country = position && getCountry(position)
|
|
309
309
|
const config = {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
Chile: getOSMSpeedingEvents,
|
|
311
|
+
Morocco: getOSMSpeedingEvents,
|
|
312
|
+
Brazil: getOSMSpeedingEvents
|
|
313
313
|
}
|
|
314
314
|
const method = config[country] || getHereEvents
|
|
315
315
|
return method(devices, routes, threshold, minimumMinutes, country && country.code)
|
|
@@ -322,10 +322,9 @@ let countError = 0
|
|
|
322
322
|
let lastSuccessDuration
|
|
323
323
|
async function invokeValhalla (route, i, chunk, country, threshold, results, retry = 3) {
|
|
324
324
|
const slice = route.slice(i, i + chunk)
|
|
325
|
-
const position = slice.find(p => getCountry(p))
|
|
326
325
|
let url
|
|
327
326
|
try {
|
|
328
|
-
url =
|
|
327
|
+
url = 'http://valhalla.pinme.io:8002/trace_attributes'
|
|
329
328
|
const now = new Date()
|
|
330
329
|
const {
|
|
331
330
|
// eslint-disable-next-line camelcase
|
|
@@ -379,7 +378,7 @@ async function invokeValhalla (route, i, chunk, country, threshold, results, ret
|
|
|
379
378
|
return invokeValhalla(route, i, chunk, country, threshold, results, retry)
|
|
380
379
|
} else {
|
|
381
380
|
console.error(e.message, (e.response && e.response.data) || url, 'deviceId',
|
|
382
|
-
slice[0] && slice[0].deviceId, slice[0] && slice[0].address, slice[0] && slice[0].fixTime, country, 'chunk', chunk)
|
|
381
|
+
slice[0] && slice[0].deviceId, slice[0] && slice[0].address, slice[0] && slice[0].fixTime, country, 'chunk', chunk, 'success', countSuccess, 'error', countError, lastSuccessDuration)
|
|
383
382
|
}
|
|
384
383
|
}
|
|
385
384
|
}
|
|
@@ -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>
|
|
@@ -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.titleRefuelingReport }}</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}} {{ translations.to }} {{reportData.to}}</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.refueling }}</span></th>
|
|
21
|
+
<th><span style="font-weight: bold;">{{ translations.totalRefueled }} (L)</span></th>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr style="font-size:10px">
|
|
24
|
+
<th>{{reportData.totalDevices}}</th>
|
|
25
|
+
<th>{{reportData.totalRefueling}}</th>
|
|
26
|
+
<th>{{reportData.totalRefuelingLiters}}</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.totalRefueled }} (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="(refueling, index) in device.refuelings" v-bind:key="device.deviceId">
|
|
43
|
+
<th>{{refueling.position.fixTime.substring(0, 10)}} {{refueling.position.fixTime.substring(11, 19)}}</th>
|
|
44
|
+
<th>{{refueling.position.geofenceName ? refueling.position.geofenceName : refueling.position.address}}</th>
|
|
45
|
+
<th>{{refueling.diff}}</th>
|
|
46
|
+
<th>{{refueling.position.driverName ? refueling.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.unsubscribeRefuelingReport.replace('%url%', url) }}
|
|
56
|
+
</mj-text>
|
|
57
|
+
</mj-column>
|
|
58
|
+
</mj-section>
|
|
59
|
+
</mj-body>
|
|
60
|
+
</mjml>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<mjml>
|
|
2
|
+
<mj-body background-color="#fff">
|
|
3
|
+
<mj-section>
|
|
4
|
+
<mj-column>
|
|
5
|
+
<!--suppress UnknownAttribute -->
|
|
6
|
+
<mj-image :src="url + '/' + logo" width="256px"/>
|
|
7
|
+
<mj-text>
|
|
8
|
+
<span style="font-size:18px;font-weight: bold">{{ translations.titleSpeedingReport }}</span>
|
|
9
|
+
</mj-text>
|
|
10
|
+
</mj-column>
|
|
11
|
+
</mj-section>
|
|
12
|
+
<!--suppress UnknownAttribute -->
|
|
13
|
+
<mj-section v-for="device in reportData.devices" :key="device.deviceId" >
|
|
14
|
+
<mj-column>
|
|
15
|
+
<mj-wrapper border="1px solid #000000" padding="20px 10px">
|
|
16
|
+
<!--suppress InvalidParentTag -->
|
|
17
|
+
<mj-table>
|
|
18
|
+
<tr style="font-size:12px">
|
|
19
|
+
<th colspan="4" style="text-align: left">
|
|
20
|
+
<span style="font-weight: bold;font-size:12px">
|
|
21
|
+
{{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-weight: bold;font-size:11px">
|
|
23
|
+
{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
|
|
24
|
+
<span style="font-weight: bold;font-size:11px">
|
|
25
|
+
{{ translations.from }} {{ device.from.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}
|
|
26
|
+
{{ translations.to }} {{ device.to.toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone }) }}</span>
|
|
27
|
+
</th>
|
|
28
|
+
</tr>
|
|
29
|
+
<tr style="font-size:11px">
|
|
30
|
+
<th v-if="!userData.roadSpeedLimits"><span style="font-weight: bold;">{{ translations.speedLimit }}</span></th>
|
|
31
|
+
<th><span style="font-weight: bold;">{{ translations.headerMaxSpeed }}</span></th>
|
|
32
|
+
<th><span style="font-weight: bold;">{{ translations.totalAlerts }}</span></th>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr style="font-size:10px">
|
|
35
|
+
<th v-if="!userData.roadSpeedLimits">{{ Math.round(device.alerts[0].attributes.speedLimit * 1.85200)}} Km\h</th>
|
|
36
|
+
<th>{{ Math.round(device.maxSpeed * 1.85200)}} Km\h</th>
|
|
37
|
+
<th>{{ device.alerts.length }}</th>
|
|
38
|
+
</tr>
|
|
39
|
+
</mj-table>
|
|
40
|
+
<!--suppress InvalidParentTag -->
|
|
41
|
+
<mj-table>
|
|
42
|
+
<tr :style="'font-size:10px;background-color:'+color+';color:white'">
|
|
43
|
+
<th style="min-width: 50px">{{ translations.date }}</th>
|
|
44
|
+
<th style="min-width: 200px">{{ translations.address }}</th>
|
|
45
|
+
<th style="min-width: 60px" v-if="userData.roadSpeedLimits">{{ translations.roadSpeedLimit }}</th>
|
|
46
|
+
<th style="min-width: 90px">{{ translations.alertSpeed }}<br/>(Km/h)</th>
|
|
47
|
+
<th style="min-width: 90px">{{ translations.maxSpeed }}<br/>(Km/h)</th>
|
|
48
|
+
<th style="min-width: 90px">{{ translations.duration }}</th>
|
|
49
|
+
<th style="min-width: 60px" v-if="device.alerts.find(a => a.driver)">{{ translations.driver }}</th>
|
|
50
|
+
<th style="min-width: 50px" v-if="userData.roadSpeedLimits">Info</th>
|
|
51
|
+
</tr>
|
|
52
|
+
<tr style="font-size:9px" v-for="(alert) in device.alerts" :key="alert.deviceId">
|
|
53
|
+
<td>{{new Date(alert.position.fixTime).toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</td>
|
|
54
|
+
<td><a target=_blank :href="`${url}/#/map?vehicleName=${userData.byDriver?alert.deviceName:device.device.name}&date=${new Date(alert.position.fixTime).toISOString()}`">{{alert.geofenceName ? alert.geofenceName : alert.position.address}}</a></td>
|
|
55
|
+
<td v-if="userData.roadSpeedLimits">{{ alert.roadSpeedLimit }}</td>
|
|
56
|
+
<td>{{Math.round(alert.attributes.speed * 1.85200)}}</td>
|
|
57
|
+
<td>{{Math.round(alert.attributes.maxSpeed * 1.85200)}}</td>
|
|
58
|
+
<td>{{convertMS(alert.eventTime, true)}}</td>
|
|
59
|
+
<td v-if="alert.driver">{{alert.driver}}</td>
|
|
60
|
+
<td v-if="userData.roadSpeedLimits">
|
|
61
|
+
<a :href="`https://openstreetmap.org/way/${alert.position.way_id}`" target="_blank">
|
|
62
|
+
{{alert.position.way_id}}
|
|
63
|
+
</a>
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
</mj-table>
|
|
67
|
+
</mj-wrapper>
|
|
68
|
+
</mj-column>
|
|
69
|
+
</mj-section>
|
|
70
|
+
<mj-section>
|
|
71
|
+
<mj-column width="100%">
|
|
72
|
+
<mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
|
|
73
|
+
{{ translations.unsubscribeSpeedingReport.replace('%url%', url) }}
|
|
74
|
+
</mj-text>
|
|
75
|
+
</mj-column>
|
|
76
|
+
</mj-section>
|
|
77
|
+
</mj-body>
|
|
78
|
+
</mjml>
|
|
@@ -0,0 +1,97 @@
|
|
|
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.titleTripReport }}</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" >
|
|
16
|
+
<mj-column>
|
|
17
|
+
<mj-wrapper border="1px solid #000000" padding="20px 10px">
|
|
18
|
+
<mj-table>
|
|
19
|
+
<tr style="font-size:12px">
|
|
20
|
+
<th colspan="4" style="text-align: left">
|
|
21
|
+
<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>
|
|
22
|
+
<span style="float:right; font-weight: bold;font-size:11px">{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
|
|
23
|
+
<span style="font-weight: bold;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:11px">
|
|
27
|
+
<th><span style="font-weight: bold;">{{ translations.headerStartAddress }}</span></th>
|
|
28
|
+
<th><span style="font-weight: bold;">{{ translations.headerDistance }}</span></th>
|
|
29
|
+
<th><span style="font-weight: bold;">{{ translations.headerDrivingTime }}</span></th>
|
|
30
|
+
<th><span style="font-weight: bold;">{{ translations.headerMaxSpeed}}</span></th>
|
|
31
|
+
</tr>
|
|
32
|
+
<tr style="font-size:10px">
|
|
33
|
+
<th>{{device.trips[0].startAddress}}</th>
|
|
34
|
+
<th>{{(device.totalDistance/1000).toFixed(2)}} Kms</th>
|
|
35
|
+
<th>{{convertMS(device.totalDuration)}}</th>
|
|
36
|
+
<th>{{Math.round(device.maxSpeed * 1.85200)}} Km\h</th>
|
|
37
|
+
</tr>
|
|
38
|
+
<tr v-if="device.device.attributes.xpert === true" style="font-size:11px">
|
|
39
|
+
<th colspan="2"><span style="font-weight: bold;">Consumo Total</span></th>
|
|
40
|
+
<th colspan="2"><span style="font-weight: bold;">Consumo Médio</span></th>
|
|
41
|
+
</tr>
|
|
42
|
+
<tr v-if="device.device.attributes.xpert" style="font-size:10px">
|
|
43
|
+
<th colspan="2">{{device.totalFuelConsumption}} L</th>
|
|
44
|
+
<th colspan="2">{{device.avgFuelConsumption}} L/100</th>
|
|
45
|
+
</tr>
|
|
46
|
+
</mj-table>
|
|
47
|
+
<mj-table>
|
|
48
|
+
<tr :style="'font-size:10px;background-color:'+color+';color:white'">
|
|
49
|
+
<th rowspan="2">{{ translations.date }}</th>
|
|
50
|
+
<th rowspan="2">{{ translations.start }}</th>
|
|
51
|
+
<th rowspan="2">{{ translations.end }}</th>
|
|
52
|
+
<th rowspan="2">{{ translations.tripTime }}</th>
|
|
53
|
+
<th rowspan="2">{{ translations.idleTime }}</th>
|
|
54
|
+
<th rowspan="2">{{ translations.stopTime }}</th>
|
|
55
|
+
<th rowspan="2">{{ translations.distance }}<br/>(Kms)</th>
|
|
56
|
+
<th colspan="2">Velocidade</th>
|
|
57
|
+
<th colspan="2" v-if="reportData.xpert === true"> Consumo</th>
|
|
58
|
+
<th rowspan="2">{{ translations.driver }}</th>
|
|
59
|
+
</tr>
|
|
60
|
+
<tr :style="'font-size:10px;background-color:'+color+';color:white'">
|
|
61
|
+
<th>Méd(Km/h)</th>
|
|
62
|
+
<th>Max(Km/h)</th>
|
|
63
|
+
<th v-if="reportData.xpert === true">(L)</th>
|
|
64
|
+
<th v-if="reportData.xpert === true">(L/100)</th>
|
|
65
|
+
</tr>
|
|
66
|
+
<mj-section v-for="(trip, index) in device.trips" v-bind:key="trip.deviceId">
|
|
67
|
+
<tr :style="index%2 ? 'text-align: center;background-color:#E3E3E3' : 'text-align: center;background-color:#FFFFFF'" >
|
|
68
|
+
<td style="font-size:10px">{{new Date(trip.startTime).toLocaleDateString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</td>
|
|
69
|
+
<td style="font-size:10px">{{new Date(trip.startTime).toLocaleTimeString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</td>
|
|
70
|
+
<td style="font-size:10px">{{new Date(trip.endTime).toLocaleTimeString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false })}}</td>
|
|
71
|
+
<td style="font-size:10px">{{convertMS(trip.duration)}}</td>
|
|
72
|
+
<td style="font-size:10px">{{convertMS(trip.stopEngineHours)}}</td>
|
|
73
|
+
<td style="font-size:10px">{{convertMS(trip.stopDuration)}}</td>
|
|
74
|
+
<td style="font-size:10px">{{trip.totalKms.toFixed(2)}}</td>
|
|
75
|
+
<td style="font-size:10px">{{Math.round(trip.averageSpeed * 1.85200)}}</td>
|
|
76
|
+
<td style="font-size:10px">{{Math.round(trip.maxSpeed * 1.85200)}}</td>
|
|
77
|
+
<td style="font-size:10px" v-if="reportData.xpert === true">{{ trip.fuelConsumption }}</td>
|
|
78
|
+
<td style="font-size:10px" v-if="reportData.xpert === true">{{ trip.avgFuelConsumption}}</td>
|
|
79
|
+
<td style="font-size:9px">{{trip.driverName}}</td>
|
|
80
|
+
</tr>
|
|
81
|
+
<tr :style="index%2 ? 'vertical-align: top;background-color:#E3E3E3' : 'vertical-align: top;background-color:#FFFFFF'" >
|
|
82
|
+
<td style="font-size:9px;padding-left: 5px" :colspan="reportData.xpert === true ? 12 : 10">{{ translations.endAddress }}: {{trip.endPOIName || trip.endAddress}}</td>
|
|
83
|
+
</tr>
|
|
84
|
+
</mj-section>
|
|
85
|
+
</mj-table>
|
|
86
|
+
</mj-wrapper>
|
|
87
|
+
</mj-column>
|
|
88
|
+
</mj-section>
|
|
89
|
+
<mj-section>
|
|
90
|
+
<mj-column width="100%">
|
|
91
|
+
<mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
|
|
92
|
+
{{ translations.unsubscribeTripReport.replace('%url%', url) }}
|
|
93
|
+
</mj-text>
|
|
94
|
+
</mj-column>
|
|
95
|
+
</mj-section>
|
|
96
|
+
</mj-body>
|
|
97
|
+
</mjml>
|
|
@@ -0,0 +1,52 @@
|
|
|
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.titleZoneReport }}</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">{{device.device.name}}{{device.device.attributes.license_plate ? ', ' +device.device.attributes.license_plate : ''}}{{device.device.model > 0 ? ', ' + device.device.model : ''}}</span>
|
|
20
|
+
<span style="float:right; font-weight: bold;font-size:11px">{{ device.device.groupName ? translations.group + ': ' + device.device.groupName : ''}}</span><br/>
|
|
21
|
+
<span style="font-weight: bold;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>
|
|
22
|
+
</th>
|
|
23
|
+
</tr>
|
|
24
|
+
</mj-table>
|
|
25
|
+
<mj-table>
|
|
26
|
+
<tr :style="'font-size:10px;background-color:'+color+';color:white'">
|
|
27
|
+
<th>{{ translations.enter }}</th>
|
|
28
|
+
<th>{{ translations.exit }}</th>
|
|
29
|
+
<th>{{ translations.duration }}</th>
|
|
30
|
+
<th>{{ translations.geofence }}</th>
|
|
31
|
+
<th>{{ translations.driver }}</th>
|
|
32
|
+
</tr>
|
|
33
|
+
<tr style="font-size:9px" v-for="(geofence, index) in device.geofences" v-bind:key="device.deviceId">
|
|
34
|
+
<th>{{geofence.inTime ? new Date(geofence.inTime.fixTime).toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false }) : ''}}</th>
|
|
35
|
+
<th>{{geofence.outTime ? new Date(geofence.outTime.fixTime).toLocaleString(user.attributes.lang, { timeZone: user.attributes.timezone, hour12:false }) : ''}}</th>
|
|
36
|
+
<th>{{geofence.totalTime ? convertMS(geofence.totalTime * 1000, true) : '-'}}</th>
|
|
37
|
+
<th>{{geofence.geofenceName}}</th>
|
|
38
|
+
<th>{{geofence.driverName}}</th>
|
|
39
|
+
</tr>
|
|
40
|
+
</mj-table>
|
|
41
|
+
</mj-wrapper>
|
|
42
|
+
</mj-column>
|
|
43
|
+
</mj-section>
|
|
44
|
+
<mj-section>
|
|
45
|
+
<mj-column width="100%">
|
|
46
|
+
<mj-text align="left" font-family="Ubuntu, Helvetica, Arial, sans-serif">
|
|
47
|
+
{{ translations.unsubscribeZoneReport.replace('%url%', url) }}
|
|
48
|
+
</mj-text>
|
|
49
|
+
</mj-column>
|
|
50
|
+
</mj-section>
|
|
51
|
+
</mj-body>
|
|
52
|
+
</mjml>
|
|
@@ -0,0 +1,96 @@
|
|
|
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="50%">
|
|
5
|
+
<mj-text>
|
|
6
|
+
<span style="font-size:25px">{{strings.report_title}}</span>
|
|
7
|
+
</mj-text>
|
|
8
|
+
</mj-column>
|
|
9
|
+
<mj-column width="50%">
|
|
10
|
+
<mj-image :src="'https://wuizy.co.ao'+header.logo_url" alt="" align="right" border="none" width="200px"></mj-image>
|
|
11
|
+
</mj-column>
|
|
12
|
+
</mj-section>
|
|
13
|
+
<mj-section v-for="(vehicleTrips, index) in trips" v-bind:key="vehicleTrips[0].device_id">
|
|
14
|
+
<mj-section>
|
|
15
|
+
<mj-column width="50%">
|
|
16
|
+
<mj-text align="left" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif">
|
|
17
|
+
{{vehicleTrips[0].device_name}}, {{vehicleTrips[0].device_licenseplate}}, {{vehicleTrips[0].device_model}}
|
|
18
|
+
</mj-text>
|
|
19
|
+
</mj-column>
|
|
20
|
+
<mj-column width="50%">
|
|
21
|
+
<mj-text align="right" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif" >
|
|
22
|
+
{{strings.from}} {{header.date_from}} {{strings.to}} {{header.date_to}}
|
|
23
|
+
</mj-text>
|
|
24
|
+
</mj-column>
|
|
25
|
+
</mj-section>
|
|
26
|
+
<mj-section>
|
|
27
|
+
<mj-column width="25%">
|
|
28
|
+
<mj-text align="left" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif">
|
|
29
|
+
{{strings.start_place}}</br>
|
|
30
|
+
{{vehicleTrips[0].trip_start_address}}
|
|
31
|
+
</mj-text>
|
|
32
|
+
</mj-column>
|
|
33
|
+
<mj-column width="25%">
|
|
34
|
+
<mj-text align="left" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif" >
|
|
35
|
+
{{strings.total_distance}}</br>
|
|
36
|
+
{{vehicleTrips[vehicleTrips.length-1].trip_incremental_distance}} km
|
|
37
|
+
</mj-text>
|
|
38
|
+
</mj-column>
|
|
39
|
+
<mj-column width="25%">
|
|
40
|
+
<mj-text align="left" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif" >
|
|
41
|
+
{{strings.total_driving_time}}</br>
|
|
42
|
+
{{vehicleTrips[vehicleTrips.length-1].trip_incremental_driving_time}}
|
|
43
|
+
</mj-text>
|
|
44
|
+
</mj-column>
|
|
45
|
+
<mj-column width="25%">
|
|
46
|
+
<mj-text align="left" font-size="12px" font-family="Ubuntu, Helvetica, Arial, sans-serif" >
|
|
47
|
+
{{strings.total_max_speed}}</br>
|
|
48
|
+
{{vehicleTrips[vehicleTrips.length-1].trip_incremental_max_speed}} km/h
|
|
49
|
+
</mj-text>
|
|
50
|
+
</mj-column>
|
|
51
|
+
</mj-section>
|
|
52
|
+
<mj-section padding-bottom="15px">
|
|
53
|
+
<mj-table>
|
|
54
|
+
<tr style="font-size:10px">
|
|
55
|
+
<th>{{strings.date}}</th>
|
|
56
|
+
<th>{{strings.start}}</th>
|
|
57
|
+
<th>{{strings.end}}</th>
|
|
58
|
+
<th>{{strings.destination}}</th>
|
|
59
|
+
<th>{{strings.duration}}</th>
|
|
60
|
+
<th>{{strings.driving}}</th>
|
|
61
|
+
<th>{{strings.idle}}</th>
|
|
62
|
+
<th>{{strings.stop}}</th>
|
|
63
|
+
<th>{{strings.distance}}</th>
|
|
64
|
+
<th>{{strings.speed_avg}}</th>
|
|
65
|
+
<th>{{strings.speed_max}}</th>
|
|
66
|
+
<th>{{strings.speed_time}}</th>
|
|
67
|
+
<th>{{strings.driver}}</th>
|
|
68
|
+
</tr>
|
|
69
|
+
<tr style="font-size:9px" v-for="(trip,index) in vehicleTrips" :key="index">
|
|
70
|
+
<th>{{trip.trip_start_fixtime.substring(0, 10)}}</th>
|
|
71
|
+
<th>{{trip.trip_start_fixtime.substring(11)}}</th>
|
|
72
|
+
<th>{{trip.trip_end_fixtime.substring(11)}}</th>
|
|
73
|
+
<th>{{trip.trip_end_address}}</th>
|
|
74
|
+
<th>{{trip.trip_duration}}</th>
|
|
75
|
+
<th>{{trip.trip_driving_time}}</th>
|
|
76
|
+
<th>{{trip.trip_idle_time}}</th>
|
|
77
|
+
<th>{{trip.trip_stop_time}}</th>
|
|
78
|
+
<th>{{trip.trip_distance}}</th>
|
|
79
|
+
<th>{{trip.trip_avg_speed}}</th>
|
|
80
|
+
<th>{{trip.trip_max_speed}}</th>
|
|
81
|
+
<th>{{trip.trip_speeding_time}}</th>
|
|
82
|
+
<th>{{trip.trip_driver_uniqueid}}</th>
|
|
83
|
+
</tr>
|
|
84
|
+
</mj-table>
|
|
85
|
+
</mj-section>
|
|
86
|
+
</mj-section>
|
|
87
|
+
<mj-section background-color="#356cc7" padding-bottom="5px" padding-top="0">
|
|
88
|
+
<mj-column width="100%">
|
|
89
|
+
<mj-divider border-color="#ffffff" border-width="2px" border-style="solid" padding-left="20px" padding-right="20px" padding-bottom="0px" padding-top="0"></mj-divider>
|
|
90
|
+
<mj-text align="center" color="#FFF" font-size="15px" font-family="Helvetica" padding-left="25px" padding-right="25px" padding-bottom="20px" padding-top="20px">Best,
|
|
91
|
+
<br/>
|
|
92
|
+
<span style="font-size:15px">The Company Team</span></mj-text>
|
|
93
|
+
</mj-column>
|
|
94
|
+
</mj-section>
|
|
95
|
+
</mj-body>
|
|
96
|
+
</mjml>
|
package/src/tests/kms.test.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-undef */
|
|
2
2
|
const { getReports } = require('./index')
|
|
3
3
|
const assert = require('assert')
|
|
4
|
-
const {convertFromUTC, convertFromLocal} = require("../util/utils");
|
|
5
4
|
|
|
6
5
|
describe('Kms_Reports', function () {
|
|
7
6
|
// eslint-disable-next-line no-undef
|
|
@@ -53,22 +52,4 @@ describe('Kms_Reports', function () {
|
|
|
53
52
|
assert.equal(device.days.length, 30) // Total Kms
|
|
54
53
|
assert.equal(device.days[29].kms, 136174.93281451002) // Total Kms
|
|
55
54
|
}, 30000)
|
|
56
|
-
it('KmsReport by driver', async () => {
|
|
57
|
-
const reports = await getReports(process.env.USER_CTM_MOVIFLOTTE, process.env.PASS_CTM_MOVIFLOTTE)
|
|
58
|
-
const userData = await reports.getUserData()
|
|
59
|
-
userData.byDriver = true
|
|
60
|
-
console.log(userData.drivers)
|
|
61
|
-
const data = await reports.kmsReport(new Date(2024, 0, 1, 0, 0, 0), new Date(2024, 0, 31, 23, 59, 59),
|
|
62
|
-
userData)
|
|
63
|
-
assert.equal(data.length, 1)
|
|
64
|
-
}, 3000000)
|
|
65
|
-
it('KmsReport by timezone marrocos', async () => {
|
|
66
|
-
const reports = await getReports(process.env.email, process.env.password)
|
|
67
|
-
const userData = await reports.getUserData()
|
|
68
|
-
userData.groupByDay = true
|
|
69
|
-
const data = await reports.kmsReport(convertFromLocal(new Date(2024, 3, 5, 0, 0, 0), userData.user.attributes.timezone), convertFromLocal(new Date(2024, 3, 5, 23, 59, 59), userData.user.attributes.timezone),
|
|
70
|
-
userData)
|
|
71
|
-
const device = data[0].devices.find(d => d.device.id === 292563)
|
|
72
|
-
assert.equal(device, 1)
|
|
73
|
-
}, 3000000)
|
|
74
55
|
})
|
package/src/tests/zones.test.js
CHANGED
|
@@ -159,21 +159,4 @@ describe('zones', function () {
|
|
|
159
159
|
console.log(first)
|
|
160
160
|
assert.equal(first.days[6].distanceOut, 867.0554430738234)
|
|
161
161
|
}, 4000000)
|
|
162
|
-
|
|
163
|
-
it('works with casais zones in columns 7', async () => {
|
|
164
|
-
const report = await getReports()
|
|
165
|
-
const userData = await report.getUserData()
|
|
166
|
-
userData.zonesByColumn = true
|
|
167
|
-
userData.devices = userData.devices.filter(d => d.id === 81166)
|
|
168
|
-
userData.geofences = userData.geofences.filter(g => g.name === 'baliza 1 - raio verde ' ||
|
|
169
|
-
g.name === 'baliza 2 - raio amarelo')
|
|
170
|
-
userData.onlyWithKmsOut = false
|
|
171
|
-
const result = await report.zoneReport(
|
|
172
|
-
new Date(Date.UTC(2023, 9, 9, 0, 0, 0, 0)),
|
|
173
|
-
new Date(Date.UTC(2023, 9, 31, 23, 59, 59, 0)),
|
|
174
|
-
userData)
|
|
175
|
-
const first = result[0].devices[0]
|
|
176
|
-
console.log(first)
|
|
177
|
-
assert.equal(first.days[17].distanceOut, 720.7985320478997)
|
|
178
|
-
}, 4000000)
|
|
179
162
|
})
|
package/src/util/utils.js
CHANGED
|
@@ -318,16 +318,8 @@ exports.convertFromUTCDate = (value, user) => {
|
|
|
318
318
|
return convertFromUTC(value, user.attributes.timezone || getUserPartner(user).timezone)
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
const crg = require('country-reverse-geocoding').country_reverse_geocoding()
|
|
322
321
|
|
|
323
|
-
exports.getCountry =
|
|
324
|
-
const country = crg.get_country(position.latitude, position.longitude)
|
|
325
|
-
if (!country) {
|
|
326
|
-
const country = position && position.attributes.address && position.attributes.address.split(',').slice(-1)[0].trim()
|
|
327
|
-
return { Brazil: 'BRA' }[country]
|
|
328
|
-
}
|
|
329
|
-
return country && country.code
|
|
330
|
-
}
|
|
322
|
+
exports.getCountry = position => position && position.attributes.address && position.attributes.address.split(',').slice(-1)[0].trim()
|
|
331
323
|
|
|
332
324
|
exports.processServerSide = (userData) => {
|
|
333
325
|
const devices = devicesToProcess(userData)
|
package/RapportPerformance.xlsx
DELETED
|
Binary file
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const automaticReports = require('../automaticReports')
|
|
2
|
-
const traccarHelper = require('../util/traccar')
|
|
3
|
-
const { getDates, getTranslations } = require('../util/utils')
|
|
4
|
-
const { getUserPartner } = require('fleetmap-partners')
|
|
5
|
-
const { getDataByDay } = require('../util/trips')
|
|
6
|
-
|
|
7
|
-
async function createDelayedStartReport (from, to, userData, traccar) {
|
|
8
|
-
const reportData = []
|
|
9
|
-
|
|
10
|
-
const devices = userData.devices
|
|
11
|
-
|
|
12
|
-
const sliced = automaticReports.sliceArray(devices, 5)
|
|
13
|
-
let deviceCount = 0
|
|
14
|
-
for (const slice of sliced) {
|
|
15
|
-
const allInOne = await traccarHelper.getAllInOne(traccar, from, to, slice, false, true, true, false, deviceCount, devices.length)
|
|
16
|
-
|
|
17
|
-
for (const d of slice) {
|
|
18
|
-
const deviceData = await processDeviceData(from, to, allInOne, d, userData, traccar)
|
|
19
|
-
reportData.push(deviceData)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
deviceCount = deviceCount + slice.length
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return reportData
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function processDeviceData (from, to, allInOne, d, userData, traccar) {
|
|
29
|
-
const group = userData.groups.find(g => g.id === d.groupId)
|
|
30
|
-
const trips = allInOne.trips.filter(t => t.deviceId === d.id)
|
|
31
|
-
const translations = getTranslations(userData)
|
|
32
|
-
|
|
33
|
-
const weekDays = [
|
|
34
|
-
translations.report.sunday,
|
|
35
|
-
translations.report.monday,
|
|
36
|
-
translations.report.tuesday,
|
|
37
|
-
translations.report.wednesday,
|
|
38
|
-
translations.report.thursday,
|
|
39
|
-
translations.report.friday,
|
|
40
|
-
translations.report.saturday
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
const dates = getDates(from, to, userData.user.attributes.timezone || getUserPartner(userData.user).timezone)
|
|
44
|
-
|
|
45
|
-
const deviceData = {
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for (const date of dates) {
|
|
50
|
-
const { tripsByDay } = await getDataByDay(d, date, { trips }, userData, traccar)
|
|
51
|
-
|
|
52
|
-
if (tripsByDay.length > 0) {
|
|
53
|
-
const startTime = tripsByDay[0].startTime
|
|
54
|
-
const stopTime = tripsByDay[tripsByDay.length].endTime
|
|
55
|
-
|
|
56
|
-
const deviceDayData = {
|
|
57
|
-
device: d.name,
|
|
58
|
-
licensePlate: d.attributes.license_plate,
|
|
59
|
-
group: group ? group.name : '',
|
|
60
|
-
driver: '',
|
|
61
|
-
weekDay: weekDays[new Date(date).getDay()],
|
|
62
|
-
startDate: '',
|
|
63
|
-
startTime: '',
|
|
64
|
-
delayDescription: '',
|
|
65
|
-
stopTime: ''
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
async function createPassengerReport (from, to, userData, traccar) {
|
|
2
|
-
//const allDevices = await traccar.axios.get('/devices').then(d => d.data)
|
|
3
|
-
const devices = userData.devices
|
|
4
|
-
const drivers = await traccar.axios.get('/drivers').then(d => d.data)
|
|
5
|
-
const groups = await traccar.axios.get('/groups').then(d => d.data)
|
|
6
|
-
await Promise.all(groups.map(async g => {
|
|
7
|
-
const driversByGroup = await traccar.axios.get(`/drivers?groupId=${g.id}`).then(d => d.data)
|
|
8
|
-
driversByGroup.forEach(d => {
|
|
9
|
-
const _driver = drivers.find(a => a.id === d.id)
|
|
10
|
-
if (_driver) {
|
|
11
|
-
_driver.groupName = g.name
|
|
12
|
-
}
|
|
13
|
-
})
|
|
14
|
-
}))
|
|
15
|
-
const eventsUrl = `/reports/events?${devices.map(d => 'deviceId=' + d.id).join('&')
|
|
16
|
-
}&from=${from.toISOString()
|
|
17
|
-
}&to=${to.toISOString()
|
|
18
|
-
}`
|
|
19
|
-
const positionsUrl = `/reports/route?${devices.map(d => 'deviceId=' + d.id).join('&')
|
|
20
|
-
}&from=${from.toISOString()
|
|
21
|
-
}&to=${to.toISOString()
|
|
22
|
-
}`
|
|
23
|
-
const events = await traccar.axios.get(eventsUrl).then(d => d.data)
|
|
24
|
-
const positions = await traccar.axios.get(positionsUrl).then(d => d.data)
|
|
25
|
-
events.forEach(e => {
|
|
26
|
-
delete e.attributes
|
|
27
|
-
const driver = getDriver(e, positions, drivers)
|
|
28
|
-
const position = positions.find(p => p.id === e.positionId)
|
|
29
|
-
e.deviceName = devices.find(d => d.id === e.deviceId).name
|
|
30
|
-
e.groupName = driver.groupName || ''
|
|
31
|
-
e.fixtime = position && new Date(position.fixTime)
|
|
32
|
-
e.notes = driver && driver.attributes.notes
|
|
33
|
-
e.driverName = (driver && driver.name) || (position && position.attributes.driverUniqueId)
|
|
34
|
-
})
|
|
35
|
-
return events
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getDriver (event, positions, drivers) {
|
|
39
|
-
const p = positions.find(p => p.id === event.positionId)
|
|
40
|
-
if (!p) { return '' }
|
|
41
|
-
const d = drivers.find(d => d.uniqueId === p.attributes.driverUniqueId)
|
|
42
|
-
if (!d) { return '' }
|
|
43
|
-
return d
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
exports.createPassengerReport = createPassengerReport
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const { getReports } = require('./index')
|
|
2
|
-
const assert = require('assert')
|
|
3
|
-
const { createDailyUseReport } = require('../partnerReports/dailyuse-report')
|
|
4
|
-
|
|
5
|
-
describe('dailyuse', function () {
|
|
6
|
-
// eslint-disable-next-line no-undef
|
|
7
|
-
it('dailyuse report', async () => {
|
|
8
|
-
const report = await getReports()
|
|
9
|
-
const userData = await report.getUserData()
|
|
10
|
-
|
|
11
|
-
const data = await createDailyUseReport(
|
|
12
|
-
new Date(Date.UTC(2023, 10, 1, 0, 0, 0, 0)),
|
|
13
|
-
new Date(Date.UTC(2023, 10, 6, 23, 59, 59, 0)),
|
|
14
|
-
userData,
|
|
15
|
-
report.traccar)
|
|
16
|
-
console.log(data)
|
|
17
|
-
assert.equal(data[0].consumption, 19.799999999999997)
|
|
18
|
-
}, 8000000)
|
|
19
|
-
})
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { getReports } = require('./index')
|
|
2
|
-
const assert = require('assert')
|
|
3
|
-
const { convertMS } = require('../util/utils')
|
|
4
|
-
const { createGPSJumpReport } = require('../partnerReports/gpsjump-report')
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line no-undef
|
|
7
|
-
describe('gpsjump', function () {
|
|
8
|
-
// eslint-disable-next-line no-undef
|
|
9
|
-
it('gpsjump report', async () => {
|
|
10
|
-
const report = await getReports()
|
|
11
|
-
const userData = await report.getUserData()
|
|
12
|
-
userData.devices = userData.devices.filter(d => d.id === 22326)
|
|
13
|
-
const data = await createGPSJumpReport(
|
|
14
|
-
new Date(Date.UTC(2023, 6, 1, 0, 0, 0, 0)),
|
|
15
|
-
new Date(Date.UTC(2023, 6, 17, 23, 59, 59, 0)),
|
|
16
|
-
userData,
|
|
17
|
-
report.traccar)
|
|
18
|
-
console.log(data)
|
|
19
|
-
assert.equal(data[0].consumption, 19.799999999999997)
|
|
20
|
-
assert.equal(data[0].distance, 326.7657)
|
|
21
|
-
assert.equal(convertMS(data[1].time * 1000, false), '08:19')
|
|
22
|
-
}, 8000000)
|
|
23
|
-
})
|