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.
- package/.claude/worktrees/eager-stonebraker-c08ac7/.eslintrc.js +15 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/enGB.js +309 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/esCL.js +297 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/frFR.json +324 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/index.js +35 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptBR.js +301 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/lang/ptPT.js +310 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/package-lock.json +11944 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/package.json +45 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/activity-report.js +822 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/automaticReports.js +34 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/carbone/index.js +13 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/custom/vistawasteActivity-report.js +544 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/events-report.js +360 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-consumption-report.js +296 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/fuel-drop-report.js +128 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/here.js +172 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/idle-report.js +403 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/index.js +244 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/kms-report.js +549 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/location-report.js +496 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/machines-report.js +278 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/afriquia.js +129 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/dailyuse-report.js +80 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/delayedstart-report.js +223 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/driverranking-report.js +328 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/gpsjump-report.js +61 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/partnerReports/performance-report.js +359 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/refueling-report.js +345 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/reportStyle.js +34 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/sensor-report.js +447 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/speeding-report.js +663 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/stop-report.js +242 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ActivityReportTemplate.mjml +51 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EmptyReportTemplate.mjml +25 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/EventsReportTemplate.mjml +75 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/FuelDropReportTemplate.mjml +60 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/IdleReportTemplate.mjml +54 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportGroupByDayTemplate.mjml +43 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/KmsReportTemplate.mjml +44 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/LocationReportTemplate.mjml +37 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/RefuelingReportTemplate.mjml +60 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SensorReportTemplate.mjml +23 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/SpeedingReportTemplate.mjml +80 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/TripReportTemplate.mjml +97 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/ZoneReportTemplate.mjml +52 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/templates/report.mjml +96 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/activity.test.js +99 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/carbone.test.js +20 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/events.test.js +30 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/fuel.test.js +35 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/idle.test.js +16 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.js +24 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/index.test.js +203 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/kms.test.js +74 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/performance.test.js +36 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/positions.test.js +67 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/speeding.test.js +120 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/translations.test.js +21 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/trips.test.js +140 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/tests/zones.test.js +162 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/trip-report.js +641 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/device.js +13 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/driver.js +90 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/fuel.js +102 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/geofence.js +52 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/odoo.js +18 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/parallel.js +64 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/pdfDocument.js +140 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/route.js +78 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/timetable.js +30 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.js +213 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/traccar.worker.js +49 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/trips.js +270 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/utils.js +358 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/worker.js +14 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/util/xpert.js +58 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/word/index.js +95 -0
- package/.claude/worktrees/eager-stonebraker-c08ac7/src/zone-report.js +904 -0
- package/lang/enGB.js +18 -0
- package/lang/esCL.js +18 -0
- package/lang/frFR.json +7 -1
- package/lang/ptBR.js +18 -0
- package/lang/ptPT.js +18 -0
- package/package.json +1 -1
- package/src/partnerReports/driverranking-report.js +152 -49
- package/src/speeding-report.js +11 -1
- package/src/util/pdfDocument.js +2 -1
package/lang/enGB.js
CHANGED
|
@@ -193,7 +193,25 @@ module.exports = {
|
|
|
193
193
|
titleIdleReport: 'Idle Report',
|
|
194
194
|
titleMachinesReport: 'Machines Report',
|
|
195
195
|
titleStopReport: 'Stop Report',
|
|
196
|
+
titleDriverRankingReport: 'Driver Ranking Report',
|
|
196
197
|
titleSensorReport: 'Sensor Report',
|
|
198
|
+
rank: 'Rank',
|
|
199
|
+
grade: 'Grade',
|
|
200
|
+
safetyScore: 'Safety',
|
|
201
|
+
efficiencyScore: 'Efficiency',
|
|
202
|
+
complianceScore: 'Compliance',
|
|
203
|
+
score: 'Overall Score',
|
|
204
|
+
avgFuelConsumption: 'Avg. L/100km',
|
|
205
|
+
highEngineRPM: 'High RPM',
|
|
206
|
+
hardBraking: 'Hard Braking',
|
|
207
|
+
hardAcceleration: 'Hard Acceleration',
|
|
208
|
+
hardCornering: 'Hard Cornering',
|
|
209
|
+
overspeedAlarm: 'Speeding',
|
|
210
|
+
geofenceAlarm: 'Seatbelt',
|
|
211
|
+
continuesDrivingAlarm: 'Continuous Driving',
|
|
212
|
+
reverseAlarm: 'Reverse Gear',
|
|
213
|
+
otherAlarm: 'Other',
|
|
214
|
+
detailedMetrics: 'Detailed metrics',
|
|
197
215
|
from: 'From',
|
|
198
216
|
to: 'to',
|
|
199
217
|
headerStartAddress: 'Start address',
|
package/lang/esCL.js
CHANGED
|
@@ -183,7 +183,25 @@ module.exports = {
|
|
|
183
183
|
titleIdleReport: 'Informe de Ralenti',
|
|
184
184
|
titleMachinesReport: 'Informe de Maquinas',
|
|
185
185
|
titleStopReport: 'Informe de Paradas',
|
|
186
|
+
titleDriverRankingReport: 'Informe de Ranking de Conductores',
|
|
186
187
|
titleSensorReport: 'Informe de Sensores',
|
|
188
|
+
rank: 'Posición',
|
|
189
|
+
grade: 'Calificación',
|
|
190
|
+
safetyScore: 'Seguridad',
|
|
191
|
+
efficiencyScore: 'Eficiencia',
|
|
192
|
+
complianceScore: 'Cumplimiento',
|
|
193
|
+
score: 'Puntuación General',
|
|
194
|
+
avgFuelConsumption: 'Consumo Prom. L/100km',
|
|
195
|
+
highEngineRPM: 'RPM Alto',
|
|
196
|
+
hardBraking: 'Frenado Brusco',
|
|
197
|
+
hardAcceleration: 'Aceleración Brusca',
|
|
198
|
+
hardCornering: 'Giro Brusco',
|
|
199
|
+
overspeedAlarm: 'Exceso de Velocidad',
|
|
200
|
+
geofenceAlarm: 'Cinturón de Seguridad',
|
|
201
|
+
continuesDrivingAlarm: 'Conducción Continua',
|
|
202
|
+
reverseAlarm: 'Marcha Atrás',
|
|
203
|
+
otherAlarm: 'Otros',
|
|
204
|
+
detailedMetrics: 'Métricas detalladas',
|
|
187
205
|
from: 'De',
|
|
188
206
|
to: 'a',
|
|
189
207
|
headerStartAddress: 'Lugar de início',
|
package/lang/frFR.json
CHANGED
|
@@ -297,7 +297,13 @@
|
|
|
297
297
|
"geofenceAlarm": "Ceinture",
|
|
298
298
|
"continuesDrivingAlarm": "Cond. Continue",
|
|
299
299
|
"reverseAlarm": "Marche Arriere",
|
|
300
|
-
"otherAlarm": "Other"
|
|
300
|
+
"otherAlarm": "Other",
|
|
301
|
+
"rank": "Rang",
|
|
302
|
+
"grade": "Note",
|
|
303
|
+
"safetyScore": "Sécurité",
|
|
304
|
+
"efficiencyScore": "Efficacité",
|
|
305
|
+
"complianceScore": "Conformité",
|
|
306
|
+
"detailedMetrics": "Métriques détaillées"
|
|
301
307
|
},
|
|
302
308
|
"layout": {
|
|
303
309
|
"deviceOnline": "Appareil en ligne",
|
package/lang/ptBR.js
CHANGED
|
@@ -185,7 +185,25 @@ module.exports = {
|
|
|
185
185
|
titleIdleReport: 'Relatórios de Ralenti',
|
|
186
186
|
titleMachinesReport: 'Relatório de Máquinas',
|
|
187
187
|
titleStopReport: 'Relatório de Paragens',
|
|
188
|
+
titleDriverRankingReport: 'Relatório de Ranking de Motoristas',
|
|
188
189
|
titleSensorReport: 'Relatório de Sensores',
|
|
190
|
+
rank: 'Posição',
|
|
191
|
+
grade: 'Nota',
|
|
192
|
+
safetyScore: 'Segurança',
|
|
193
|
+
efficiencyScore: 'Eficiência',
|
|
194
|
+
complianceScore: 'Conformidade',
|
|
195
|
+
score: 'Pontuação Geral',
|
|
196
|
+
avgFuelConsumption: 'Consumo Médio L/100km',
|
|
197
|
+
highEngineRPM: 'RPM Alta',
|
|
198
|
+
hardBraking: 'Frenagem Brusca',
|
|
199
|
+
hardAcceleration: 'Aceleração Brusca',
|
|
200
|
+
hardCornering: 'Curva Brusca',
|
|
201
|
+
overspeedAlarm: 'Excesso de Velocidade',
|
|
202
|
+
geofenceAlarm: 'Cinto de Segurança',
|
|
203
|
+
continuesDrivingAlarm: 'Condução Contínua',
|
|
204
|
+
reverseAlarm: 'Marcha à Ré',
|
|
205
|
+
otherAlarm: 'Outros',
|
|
206
|
+
detailedMetrics: 'Métricas detalhadas',
|
|
189
207
|
from: 'De',
|
|
190
208
|
to: 'a',
|
|
191
209
|
headerStartAddress: 'Local de início',
|
package/lang/ptPT.js
CHANGED
|
@@ -191,7 +191,25 @@ module.exports = {
|
|
|
191
191
|
titleIdleReport: 'Relatórios de Ralenti',
|
|
192
192
|
titleMachinesReport: 'Relatório de Máquinas',
|
|
193
193
|
titleStopReport: 'Relatório de Paragens',
|
|
194
|
+
titleDriverRankingReport: 'Relatório de Ranking de Condutores',
|
|
194
195
|
titleSensorReport: 'Relatório de Sensores',
|
|
196
|
+
rank: 'Posição',
|
|
197
|
+
grade: 'Nota',
|
|
198
|
+
safetyScore: 'Segurança',
|
|
199
|
+
efficiencyScore: 'Eficiência',
|
|
200
|
+
complianceScore: 'Conformidade',
|
|
201
|
+
score: 'Pontuação Geral',
|
|
202
|
+
avgFuelConsumption: 'Consumo Médio L/100km',
|
|
203
|
+
highEngineRPM: 'RPM Alto',
|
|
204
|
+
hardBraking: 'Travagem Brusca',
|
|
205
|
+
hardAcceleration: 'Aceleração Brusca',
|
|
206
|
+
hardCornering: 'Curva Brusca',
|
|
207
|
+
overspeedAlarm: 'Excesso de Velocidade',
|
|
208
|
+
geofenceAlarm: 'Cinto de Segurança',
|
|
209
|
+
continuesDrivingAlarm: 'Condução Contínua',
|
|
210
|
+
reverseAlarm: 'Marcha-atrás',
|
|
211
|
+
otherAlarm: 'Outros',
|
|
212
|
+
detailedMetrics: 'Métricas detalhadas',
|
|
195
213
|
from: 'De',
|
|
196
214
|
to: 'a',
|
|
197
215
|
headerStartAddress: 'Local de início',
|
package/package.json
CHANGED
|
@@ -24,6 +24,39 @@ const continuesDrivingCoefficient = 0.1
|
|
|
24
24
|
const reverseCoefficient = 0.1
|
|
25
25
|
const otherCoefficient = 0.1
|
|
26
26
|
|
|
27
|
+
const grades = [
|
|
28
|
+
{ min: 90, grade: 'A' },
|
|
29
|
+
{ min: 75, grade: 'B' },
|
|
30
|
+
{ min: 60, grade: 'C' },
|
|
31
|
+
{ min: 40, grade: 'D' },
|
|
32
|
+
{ min: -Infinity, grade: 'F' }
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
// Converts a "the lower the better" metric into a 0-100 score (100 = met target, 0 = twice the target or worse)
|
|
36
|
+
function goodnessScore (actual, target) {
|
|
37
|
+
if (!target || target <= 0) {
|
|
38
|
+
return 100
|
|
39
|
+
}
|
|
40
|
+
return Math.max(0, Math.min(100, 100 * (1 - (actual / target))))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Same as goodnessScore, but for metrics where deviating from the target in either direction is bad (e.g. distance)
|
|
44
|
+
function deviationScore (actual, target) {
|
|
45
|
+
if (!target || target <= 0) {
|
|
46
|
+
return 100
|
|
47
|
+
}
|
|
48
|
+
return Math.max(0, Math.min(100, 100 * (1 - (Math.abs(actual - target) / target))))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function weightedAverage (metrics) {
|
|
52
|
+
const totalWeight = metrics.reduce((sum, m) => sum + m.weight, 0)
|
|
53
|
+
return metrics.reduce((sum, m) => sum + (m.value * m.weight), 0) / totalWeight
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function toGrade (score) {
|
|
57
|
+
return grades.find(g => score >= g.min).grade
|
|
58
|
+
}
|
|
59
|
+
|
|
27
60
|
async function create (from, to, userData, traccar) {
|
|
28
61
|
const reportData = {
|
|
29
62
|
drivers: []
|
|
@@ -67,28 +100,37 @@ async function create (from, to, userData, traccar) {
|
|
|
67
100
|
await processDevice(driversData, device, userData, { route, trips }, deviceAlarmEvents, deviceOverspeedEvents)
|
|
68
101
|
deviceCount++
|
|
69
102
|
}
|
|
103
|
+
|
|
104
|
+
console.log('LOADING_MESSAGE:' + slice[0].name)
|
|
105
|
+
console.log(`PROGRESS_PERC:${deviceCount / devices.length * 100}`)
|
|
70
106
|
}
|
|
71
107
|
|
|
72
108
|
const allDriversData = (Array.from(driversData.values())).filter(d => d.distance > 0)
|
|
73
109
|
allDriversData.forEach(d => {
|
|
74
|
-
const distanceScore = (Math.abs(d.distance - userData.distanceTarget) / userData.distanceTarget) * distanceCoefficient
|
|
75
|
-
const rpmScore = ((d.highEngineRPM / 60000) / userData.rpmTarget) * rpmCoefficient
|
|
76
|
-
const hardBrakingScore = (d.hardBraking / userData.hardBrakingTarget) * hardBrakingCoefficient
|
|
77
|
-
const hardAccelerationScore = (d.hardAcceleration / userData.hardAccelerationTarget) * hardAccelerationCoefficient
|
|
78
|
-
const hardCorneringScore = (d.hardCornering / userData.hardCorneringTarget) * hardCorneringCoefficient
|
|
79
|
-
const overspeedScore = (d.overspeed / userData.overspeedTarget) * overspeedCoefficient
|
|
80
|
-
const consumptionScore = (getCanAvgConsumption(d.distance, d.spentFuel).byKms / userData.fuelConsumptionTarget) * consumptionCoefficient
|
|
81
|
-
const geofenceAlarmScore = (d.geofenceAlarm / userData.geofenceTarget) * geofenceCoefficient
|
|
82
|
-
const continuesDrivingAlarmScore = (d.continuesDrivingAlarm / userData.continuesDrivingTarget) * continuesDrivingCoefficient
|
|
83
|
-
const reverseAlarmScore = (d.reverseAlarm / userData.reverseTarget) * reverseCoefficient
|
|
84
|
-
const otherAlarmScore = (d.otherAlarm / userData.otherTarget) * otherCoefficient
|
|
85
|
-
|
|
86
110
|
d.avgFuelConsumption = getCanAvgConsumption(d.distance, d.spentFuel).byKms
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
111
|
+
|
|
112
|
+
d.safetyScore = weightedAverage([
|
|
113
|
+
{ value: goodnessScore(d.hardBraking, userData.hardBrakingTarget), weight: hardBrakingCoefficient },
|
|
114
|
+
{ value: goodnessScore(d.hardAcceleration, userData.hardAccelerationTarget), weight: hardAccelerationCoefficient },
|
|
115
|
+
{ value: goodnessScore(d.hardCornering, userData.hardCorneringTarget), weight: hardCorneringCoefficient },
|
|
116
|
+
{ value: goodnessScore(d.overspeed, userData.overspeedTarget), weight: overspeedCoefficient },
|
|
117
|
+
{ value: goodnessScore(d.reverseAlarm, userData.reverseTarget), weight: reverseCoefficient }
|
|
118
|
+
])
|
|
119
|
+
d.efficiencyScore = weightedAverage([
|
|
120
|
+
{ value: deviationScore(d.distance, userData.distanceTarget), weight: distanceCoefficient },
|
|
121
|
+
{ value: goodnessScore(d.avgFuelConsumption, userData.fuelConsumptionTarget), weight: consumptionCoefficient },
|
|
122
|
+
{ value: goodnessScore(d.highEngineRPM / 60000, userData.rpmTarget), weight: rpmCoefficient }
|
|
123
|
+
])
|
|
124
|
+
d.complianceScore = weightedAverage([
|
|
125
|
+
{ value: goodnessScore(d.geofenceAlarm, userData.geofenceTarget), weight: geofenceCoefficient },
|
|
126
|
+
{ value: goodnessScore(d.continuesDrivingAlarm, userData.continuesDrivingTarget), weight: continuesDrivingCoefficient },
|
|
127
|
+
{ value: goodnessScore(d.otherAlarm, userData.otherTarget), weight: otherCoefficient }
|
|
128
|
+
])
|
|
129
|
+
d.overallScore = (d.safetyScore + d.efficiencyScore + d.complianceScore) / 3
|
|
130
|
+
d.grade = toGrade(d.overallScore)
|
|
90
131
|
})
|
|
91
|
-
allDriversData.sort((a, b) =>
|
|
132
|
+
allDriversData.sort((a, b) => b.overallScore - a.overallScore)
|
|
133
|
+
allDriversData.forEach((d, index) => { d.rank = index + 1 })
|
|
92
134
|
|
|
93
135
|
reportData.drivers.push(...allDriversData)
|
|
94
136
|
|
|
@@ -204,7 +246,13 @@ async function exportToExcel (userData, reportData) {
|
|
|
204
246
|
}
|
|
205
247
|
|
|
206
248
|
const headers = [
|
|
249
|
+
{ label: translations.report.rank, value: 'rank' },
|
|
207
250
|
{ label: translations.report.driver, value: 'name' },
|
|
251
|
+
{ label: translations.report.grade, value: 'grade' },
|
|
252
|
+
{ label: translations.report.score, value: 'overallScore' },
|
|
253
|
+
{ label: translations.report.safetyScore, value: 'safetyScore' },
|
|
254
|
+
{ label: translations.report.efficiencyScore, value: 'efficiencyScore' },
|
|
255
|
+
{ label: translations.report.complianceScore, value: 'complianceScore' },
|
|
208
256
|
{ label: translations.report.distance, value: 'distance' },
|
|
209
257
|
{ label: translations.report.avgFuelConsumption, value: 'avgFuelConsumption' },
|
|
210
258
|
{ label: translations.report.highEngineRPM, value: 'highEngineRPM' },
|
|
@@ -215,16 +263,21 @@ async function exportToExcel (userData, reportData) {
|
|
|
215
263
|
{ label: translations.report.geofenceAlarm, value: 'geofenceAlarm' },
|
|
216
264
|
{ label: translations.report.continuesDrivingAlarm, value: 'continuesDrivingAlarm' },
|
|
217
265
|
{ label: translations.report.reverseAlarm, value: 'reverseAlarm' },
|
|
218
|
-
{ label: translations.report.otherAlarm, value: 'otherAlarm' }
|
|
219
|
-
{ label: translations.report.score, value: 'score' }
|
|
266
|
+
{ label: translations.report.otherAlarm, value: 'otherAlarm' }
|
|
220
267
|
]
|
|
221
268
|
|
|
222
269
|
let data = []
|
|
223
270
|
if (reportDataRows) {
|
|
224
271
|
reportDataRows.forEach(row => {
|
|
225
272
|
data = data.concat({
|
|
273
|
+
rank: row.rank,
|
|
226
274
|
name: row.name,
|
|
227
|
-
|
|
275
|
+
grade: row.grade,
|
|
276
|
+
overallScore: Math.round(row.overallScore),
|
|
277
|
+
safetyScore: Math.round(row.safetyScore),
|
|
278
|
+
efficiencyScore: Math.round(row.efficiencyScore),
|
|
279
|
+
complianceScore: Math.round(row.complianceScore),
|
|
280
|
+
distance: Number((row.distance / 1000).toFixed(1)),
|
|
228
281
|
avgFuelConsumption: Number(row.avgFuelConsumption.toFixed(2)),
|
|
229
282
|
highEngineRPM: convertMS(row.highEngineRPM, false),
|
|
230
283
|
hardBraking: row.hardBraking,
|
|
@@ -234,11 +287,9 @@ async function exportToExcel (userData, reportData) {
|
|
|
234
287
|
geofenceAlarm: row.geofenceAlarm,
|
|
235
288
|
continuesDrivingAlarm: row.continuesDrivingAlarm,
|
|
236
289
|
reverseAlarm: row.reverseAlarm,
|
|
237
|
-
otherAlarm: row.otherAlarm
|
|
238
|
-
score: Number(row.score.toFixed(2))
|
|
290
|
+
otherAlarm: row.otherAlarm
|
|
239
291
|
})
|
|
240
292
|
})
|
|
241
|
-
console.log(data)
|
|
242
293
|
return {
|
|
243
294
|
headers,
|
|
244
295
|
data,
|
|
@@ -247,15 +298,33 @@ async function exportToExcel (userData, reportData) {
|
|
|
247
298
|
}
|
|
248
299
|
}
|
|
249
300
|
|
|
301
|
+
const gradeColors = {
|
|
302
|
+
A: { fill: [200, 236, 204], text: [30, 110, 40] },
|
|
303
|
+
B: { fill: [223, 240, 196], text: [66, 110, 30] },
|
|
304
|
+
C: { fill: [255, 236, 179], text: [153, 101, 0] },
|
|
305
|
+
D: { fill: [255, 205, 178], text: [166, 74, 0] },
|
|
306
|
+
F: { fill: [255, 205, 210], text: [153, 0, 20] }
|
|
307
|
+
}
|
|
308
|
+
|
|
250
309
|
async function exportToPDF (userData, reportData) {
|
|
251
|
-
console.log('
|
|
310
|
+
console.log('exportDriverRankingReportToPDF')
|
|
252
311
|
|
|
253
312
|
const timezone = userData.user.attributes.timezone
|
|
254
313
|
const translations = getTranslations(userData)
|
|
255
314
|
const lang = userData.user.attributes.lang || (isClientSide() && navigator.language)
|
|
256
315
|
const reportDataRows = reportData.drivers
|
|
257
316
|
|
|
258
|
-
const
|
|
317
|
+
const scoreboardHeaders = [
|
|
318
|
+
translations.report.rank,
|
|
319
|
+
translations.report.driver,
|
|
320
|
+
translations.report.grade,
|
|
321
|
+
translations.report.score,
|
|
322
|
+
translations.report.safetyScore,
|
|
323
|
+
translations.report.efficiencyScore,
|
|
324
|
+
translations.report.complianceScore
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
const detailHeaders = [
|
|
259
328
|
translations.report.driver,
|
|
260
329
|
translations.report.distance,
|
|
261
330
|
translations.report.avgFuelConsumption,
|
|
@@ -267,8 +336,7 @@ async function exportToPDF (userData, reportData) {
|
|
|
267
336
|
translations.report.geofenceAlarm,
|
|
268
337
|
translations.report.continuesDrivingAlarm,
|
|
269
338
|
translations.report.reverseAlarm,
|
|
270
|
-
translations.report.otherAlarm
|
|
271
|
-
translations.report.score
|
|
339
|
+
translations.report.otherAlarm
|
|
272
340
|
]
|
|
273
341
|
|
|
274
342
|
if (reportDataRows) {
|
|
@@ -279,30 +347,66 @@ async function exportToPDF (userData, reportData) {
|
|
|
279
347
|
doc.setFontSize(13)
|
|
280
348
|
doc.text(convertToLocaleString(reportData.from, lang, timezone, userData.user) + ' - ' + convertToLocaleString(reportData.to, lang, timezone, userData.user), 20, 25)
|
|
281
349
|
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
row.hardCornering,
|
|
292
|
-
row.overspeed,
|
|
293
|
-
row.geofenceAlarm,
|
|
294
|
-
row.continuesDrivingAlarm,
|
|
295
|
-
row.reverseAlarm,
|
|
296
|
-
row.otherAlarm,
|
|
297
|
-
row.score.toFixed(2)
|
|
298
|
-
]
|
|
299
|
-
data.push(temp)
|
|
300
|
-
})
|
|
301
|
-
const footValues = []
|
|
350
|
+
const scoreboardData = reportDataRows.map(row => [
|
|
351
|
+
row.rank,
|
|
352
|
+
row.name,
|
|
353
|
+
row.grade,
|
|
354
|
+
Math.round(row.overallScore),
|
|
355
|
+
Math.round(row.safetyScore),
|
|
356
|
+
Math.round(row.efficiencyScore),
|
|
357
|
+
Math.round(row.complianceScore)
|
|
358
|
+
])
|
|
302
359
|
|
|
303
360
|
const style = getStyle(getUserPartner(userData.user))
|
|
304
361
|
|
|
305
|
-
addTable(doc,
|
|
362
|
+
addTable(doc, scoreboardHeaders, scoreboardData, [], style, 40, {
|
|
363
|
+
0: { halign: 'center' },
|
|
364
|
+
2: { halign: 'center' },
|
|
365
|
+
3: { halign: 'right' },
|
|
366
|
+
4: { halign: 'right' },
|
|
367
|
+
5: { halign: 'right' },
|
|
368
|
+
6: { halign: 'right' }
|
|
369
|
+
}, (cellData) => {
|
|
370
|
+
if (cellData.section !== 'body') {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
const row = reportDataRows[cellData.row.index]
|
|
374
|
+
if (!row) {
|
|
375
|
+
return
|
|
376
|
+
}
|
|
377
|
+
if (cellData.column.index === 0) {
|
|
378
|
+
cellData.cell.styles.fontStyle = row.rank <= 3 ? 'bold' : 'normal'
|
|
379
|
+
}
|
|
380
|
+
if (cellData.column.index === 2 || cellData.column.index === 3) {
|
|
381
|
+
const colors = gradeColors[row.grade]
|
|
382
|
+
cellData.cell.styles.fillColor = colors.fill
|
|
383
|
+
cellData.cell.styles.textColor = colors.text
|
|
384
|
+
cellData.cell.styles.fontStyle = 'bold'
|
|
385
|
+
}
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
const detailData = reportDataRows.map(row => [
|
|
389
|
+
row.name,
|
|
390
|
+
(row.distance / 1000).toFixed(1),
|
|
391
|
+
row.avgFuelConsumption.toFixed(2),
|
|
392
|
+
convertMS(row.highEngineRPM, false),
|
|
393
|
+
row.hardBraking,
|
|
394
|
+
row.hardAcceleration,
|
|
395
|
+
row.hardCornering,
|
|
396
|
+
row.overspeed,
|
|
397
|
+
row.geofenceAlarm,
|
|
398
|
+
row.continuesDrivingAlarm,
|
|
399
|
+
row.reverseAlarm,
|
|
400
|
+
row.otherAlarm
|
|
401
|
+
])
|
|
402
|
+
|
|
403
|
+
const detailStartY = doc.lastAutoTable.finalY + 12
|
|
404
|
+
doc.setFontSize(10)
|
|
405
|
+
doc.setFont('helvetica', 'bold')
|
|
406
|
+
doc.text(translations.report.detailedMetrics, 15, detailStartY - 4)
|
|
407
|
+
doc.setFont('helvetica', 'normal')
|
|
408
|
+
|
|
409
|
+
addTable(doc, detailHeaders, detailData, [], { ...style, bodyFontSize: 7, headerFontSize: 8 }, detailStartY, {
|
|
306
410
|
1: { halign: 'right' },
|
|
307
411
|
2: { halign: 'right' },
|
|
308
412
|
3: { halign: 'right' },
|
|
@@ -313,8 +417,7 @@ async function exportToPDF (userData, reportData) {
|
|
|
313
417
|
8: { halign: 'right' },
|
|
314
418
|
9: { halign: 'right' },
|
|
315
419
|
10: { halign: 'right' },
|
|
316
|
-
11: { halign: 'right' }
|
|
317
|
-
12: { halign: 'right' }
|
|
420
|
+
11: { halign: 'right' }
|
|
318
421
|
})
|
|
319
422
|
return doc
|
|
320
423
|
}
|
package/src/speeding-report.js
CHANGED
|
@@ -132,7 +132,17 @@ async function getEvents (traccarInstance, from, to, devices, userData, deviceCo
|
|
|
132
132
|
if (processServerSide() && !userData.useVehicleSpeedLimit) {
|
|
133
133
|
const cookie = await axios.get('/pinmeapi/cookie/get', { withCredentials: true }).then(d => d.data)
|
|
134
134
|
const url = `https://${getServerHost()}/pinmeapi/reports/speeding-report/getEvents`
|
|
135
|
-
|
|
135
|
+
const maxAttempts = 3
|
|
136
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
137
|
+
try {
|
|
138
|
+
return await axios.post(url, { from, to, devices, userData, deviceCount, totalDevices, sliceSize, cookie }, { withCredentials: true, timeout: 60000 }).then(d => d.data)
|
|
139
|
+
} catch (e) {
|
|
140
|
+
console.log(`getEvents failed for devices [${devices.map(d => d.name).join(', ')}] (attempt ${attempt}/${maxAttempts}): ${e.message}`)
|
|
141
|
+
if (attempt === maxAttempts) {
|
|
142
|
+
return []
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
136
146
|
} else {
|
|
137
147
|
const geofencesFeatures = userData.geofences.filter(g => g.area && g.area.startsWith('POLYGON') &&
|
|
138
148
|
g.attributes.speedLimit).map(g => convertToFeature(g))
|
package/src/util/pdfDocument.js
CHANGED
|
@@ -61,7 +61,7 @@ async function headerFromUser (doc, title, user, orientation = 'l') {
|
|
|
61
61
|
return header(doc, title, partner && partner.host, getStyle(partner), orientation)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
function addTable (doc, headers, data, footValues, style, startY, columnStyles = {}) {
|
|
64
|
+
function addTable (doc, headers, data, footValues, style, startY, columnStyles = {}, didParseCell) {
|
|
65
65
|
doc.autoTable({
|
|
66
66
|
head: [headers],
|
|
67
67
|
body: data,
|
|
@@ -97,6 +97,7 @@ function addTable (doc, headers, data, footValues, style, startY, columnStyles =
|
|
|
97
97
|
})
|
|
98
98
|
})
|
|
99
99
|
},
|
|
100
|
+
...(didParseCell ? { didParseCell } : {}),
|
|
100
101
|
columnStyles,
|
|
101
102
|
startY
|
|
102
103
|
})
|