fleetmap-reports 2.0.132 → 2.0.134

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.
Binary file
package/lang/frFR.json CHANGED
@@ -193,6 +193,7 @@
193
193
  "titleMachinesReport": "Rapport machine",
194
194
  "titleStopReport": "Arrêter le rapport",
195
195
  "titleDelayedStartReport": "Rapport de Departs Tardifs",
196
+ "titleDriverRankingReport": "Rapport d'conducteur",
196
197
  "from": "Dans",
197
198
  "to": "Le",
198
199
  "headerStartAddress": "lieu de départ",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetmap-reports",
3
- "version": "2.0.132",
3
+ "version": "2.0.134",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/kms-report.js CHANGED
@@ -9,7 +9,8 @@ const { getUserPartner } = require('fleetmap-partners')
9
9
  const traccar = require('./util/traccar')
10
10
  const { getDates, getTranslations, isClientSide, executeServerSide } = require('./util/utils')
11
11
  const driversUtil = require('./util/driver')
12
- const { isInsideTimetable, isPartialInsideTimetable, calculateTrip, getDataByDay, getKms,
12
+ const {
13
+ isInsideTimetable, isPartialInsideTimetable, calculateTrip, getDataByDay, getKms,
13
14
  getTripTotalKms
14
15
  } = require('./util/trips')
15
16
  const { devicesToProcess } = require('./util/device')
@@ -121,7 +122,7 @@ async function createKmsReportByDriver (from, to, userData, traccarInstance) {
121
122
  report.drivers = drivers
122
123
  })
123
124
  } else {
124
- const results = await reportByDriver(userData.devices, traccarInstance, from, to, userData, processDrivers, { route: !userData.allWeek, trips: true, stops: false, summary: false })
125
+ const results = await reportByDriver(userData.devices, traccarInstance, from, to, userData, processDrivers, { route: !userData.allWeek || userData.byDriver, trips: true, stops: true, summary: false })
125
126
 
126
127
  results.drivers.forEach(result => {
127
128
  const driver = report.drivers.find(d => d.driver.id === result.driver.id)
@@ -204,7 +205,13 @@ async function processDrivers (from, to, userData, data) {
204
205
  }
205
206
  } else {
206
207
  driverData.summary = {
207
- distance: trips.reduce((a, b) => a + getTripTotalKms(b, getStop(b.endTime, data.stops), data.route), 0)
208
+ distance: trips.reduce((a, b) =>
209
+ a + getTripTotalKms(
210
+ b,
211
+ getStop(new Date(b.endTime), data.stops.filter(s => s.deviceId === b.deviceId)),
212
+ data.route.filter(r => r.deviceId === b.deviceId)
213
+ ), 0
214
+ ) * 1000
208
215
  }
209
216
  }
210
217
  driversResult.push(driverData)
@@ -1,7 +1,11 @@
1
1
  const traccarHelper = require('../util/traccar')
2
2
  const { isInsideTimetable } = require('../util/trips')
3
- const { convertFromUTCDate } = require('../util/utils')
3
+ const { convertFromUTCDate, getTranslations, convertMS, convertToLocaleTimeString, isClientSide } = 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')
5
9
 
6
10
  async function createDailyUseReport (from, to, userData, traccar) {
7
11
  const reportData = []
@@ -77,4 +81,72 @@ function processDeviceData (allInOne, d, userData) {
77
81
  }
78
82
  }
79
83
 
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
+
80
150
  exports.createDailyUseReport = createDailyUseReport
151
+ exports.exportDailyUseReportToPDF = exportDailyUseReportToPDF
152
+ exports.exportDailyUseReportToExcel = exportDailyUseReportToExcel
@@ -1,6 +1,12 @@
1
1
  const traccarHelper = require('../util/traccar')
2
2
  const { getDriverData } = require('../util/driver')
3
3
  const { getCanDriverStyleMessages, parseCanDriverStyleMessage } = require('../util/xpert')
4
+ const { calculateRPMSections } = require('./performance-report')
5
+ const { getTranslations, isClientSide, convertToLocaleString } = require('../util/utils')
6
+ const jsPDF = require('jspdf')
7
+ const { headerFromUser, addTable } = require('../util/pdfDocument')
8
+ const { getStyle } = require('../reportStyle')
9
+ const { getUserPartner } = require('fleetmap-partners')
4
10
 
5
11
  async function create (from, to, userData, traccar) {
6
12
  const reportData = []
@@ -8,35 +14,160 @@ async function create (from, to, userData, traccar) {
8
14
  const drivers = userData.drivers
9
15
  const devices = userData.devices
10
16
 
11
- const allInOne = await traccarHelper.getAllInOne(traccar, from, to, devices, true, true, false, false)
17
+ let deviceCount = 0
18
+ const driversData = new Map()
19
+ for (const device of devices) {
20
+ const allInOne = await traccarHelper.getAllInOne(traccar, from, to, [device], true, true, false, false, deviceCount, devices.length)
12
21
 
13
- for (const d of drivers) {
14
- const { trips, route } = await getDriverData(d, allInOne, userData)
15
- const xpertMessages = route.map(p => p.attributes.rawXpert).filter(a => a)
16
- const canDriverStyle = getCanDriverStyleMessages(xpertMessages).map(m => parseCanDriverStyleMessage(m.xpertString || m)).sort((a, b) => a.date.localeCompare(b.date))
22
+ for (const d of drivers) {
23
+ const { trips, route } = await getDriverData(d, allInOne, userData)
17
24
 
18
- const highEngineRPM = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalTimeWithHighRpmAndTorque - canDriverStyle[0].totalTimeWithHighRpmAndTorque : 0
19
- const hardBraking = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalNumberOfHarshBrakes - canDriverStyle[0].totalNumberOfHarshBrakes : 0
20
- const hardAcceleration = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalNumberOfHarshAccelerations - canDriverStyle[0].totalNumberOfHarshAccelerations : 0
25
+ let driverData = driversData.get(d.id)
26
+ if (!driverData) {
27
+ driverData = {
28
+ name: d.name,
29
+ distance: 0,
30
+ highEngineRPM: 0,
31
+ hardBraking: 0,
32
+ hardAcceleration: 0,
33
+ hardCornering: 0
34
+ }
35
+ driversData.set(d.id, driverData)
36
+ }
21
37
 
22
- reportData.drivers.push({
23
- name: d.name,
24
- distance: trips.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0),
25
- highEngineRPM,
26
- hardBraking,
27
- hardAcceleration
28
- })
38
+ let highEngineRPM = 0
39
+ let hardBraking = 0
40
+ let hardAcceleration = 0
41
+ let hardCornering = 0
42
+ if (route.find(p => p.attributes.rawXpert)) {
43
+ const xpertMessages = route.map(p => p.attributes.rawXpert).filter(a => a)
44
+ const canDriverStyle = getCanDriverStyleMessages(xpertMessages).map(m => parseCanDriverStyleMessage(m.xpertString || m)).sort((a, b) => a.date.localeCompare(b.date))
45
+ highEngineRPM = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalTimeWithHighRpmAndTorque - canDriverStyle[0].totalTimeWithHighRpmAndTorque : 0
46
+ hardBraking = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalNumberOfHarshBrakes - canDriverStyle[0].totalNumberOfHarshBrakes : 0
47
+ hardAcceleration = canDriverStyle.length > 1 ? canDriverStyle[canDriverStyle.length - 1].totalNumberOfHarshAccelerations - canDriverStyle[0].totalNumberOfHarshAccelerations : 0
48
+ } else {
49
+ const highEngineRPMSections = calculateRPMSections(route, d.attributes.highRPM || 1300)
50
+ highEngineRPM = highEngineRPMSections.map(a => a.length > 1
51
+ ? a.map((p, index) => index === 0 ? 0 : new Date(p.fixTime).getTime() - new Date(a[index - 1].fixTime).getTime()).reduce((a, b) => a + b, 0)
52
+ : 0).reduce((a, b) => a + b, 0)
53
+
54
+ hardBraking = route.filter(p => p.attributes.alarm === 'hardBraking').length
55
+ hardAcceleration = route.filter(p => p.attributes.alarm === 'hardAcceleration').length
56
+ hardCornering = route.filter(p => p.attributes.alarm === 'hardCornering').length
57
+ }
58
+
59
+ driverData.distance = driverData.distance + trips.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
60
+ driverData.highEngineRPM = driverData.highEngineRPM + highEngineRPM
61
+ driverData.hardBraking = driverData.hardBraking + hardBraking
62
+ driverData.hardAcceleration = driverData.hardAcceleration + hardAcceleration
63
+ driverData.hardCornering = driverData.hardCornering + hardCornering
64
+ }
65
+
66
+ deviceCount++
29
67
  }
30
68
 
69
+ const allDriversData = (Array.from(driversData.values())).filter(d => d.distance > 0)
70
+ allDriversData.forEach(d => {
71
+ d.score = (d.highEngineRPM + d.hardBraking + d.hardAcceleration + d.hardCornering) / (d.distance / 1000)
72
+ })
73
+ allDriversData.sort((a, b) => (a.score > b.score) ? 1 : -1)
74
+
75
+ reportData.push(...allDriversData)
76
+
31
77
  return reportData
32
78
  }
33
79
 
80
+ const fileName = 'DriverRankingReport'
34
81
  async function exportToExcel (userData, reportData) {
82
+ console.log('Export to Excel')
83
+
84
+ const translations = getTranslations(userData)
85
+
86
+ const reportDataRows = reportData
87
+
88
+ const settings = {
89
+ sheetName: translations.report.titleDriverRankingReport, // The name of the sheet
90
+ fileName // The name of the spreadsheet
91
+ }
92
+
93
+ const headers = [
94
+ { label: translations.report.driver, value: 'name' },
95
+ { label: translations.report.distance, value: 'distance' },
96
+ { label: translations.report.highEngineRPM, value: 'highEngineRPM' },
97
+ { label: translations.report.hardBraking, value: 'hardBraking' },
98
+ { label: translations.report.hardAcceleration, value: 'hardAcceleration' },
99
+ { label: translations.report.hardCornering, value: 'hardCornering' },
100
+ { label: translations.report.score, value: 'score' }
101
+ ]
35
102
 
103
+ let data = []
104
+ if (reportDataRows) {
105
+ reportDataRows.forEach(row => {
106
+ data = data.concat({
107
+ name: row.name,
108
+ distance: row.distance,
109
+ highEngineRPM: row.highEngineRPM,
110
+ hardBraking: row.hardBraking,
111
+ hardAcceleration: row.hardAcceleration,
112
+ hardCornering: row.hardCornering,
113
+ score: row.score
114
+ })
115
+ })
116
+ console.log(data)
117
+ return {
118
+ headers,
119
+ data,
120
+ settings
121
+ }
122
+ }
36
123
  }
37
124
 
38
125
  async function exportToPDF (userData, reportData) {
126
+ console.log('exportDelayedStartReportToPDF')
127
+
128
+ const timezone = userData.user.attributes.timezone
129
+ const translations = getTranslations(userData)
130
+ const lang = userData.user.attributes.lang || (isClientSide() && navigator.language)
131
+ const reportDataRows = reportData.devices
132
+
133
+ const headers = [
134
+ translations.report.driver,
135
+ translations.report.distance,
136
+ translations.report.highEngineRPM,
137
+ translations.report.hardBraking,
138
+ translations.report.hardAcceleration,
139
+ translations.report.hardCornering,
140
+ translations.report.score
141
+ ]
142
+
143
+ if (reportDataRows) {
144
+ // eslint-disable-next-line new-cap
145
+ const doc = new jsPDF.jsPDF('l')
146
+ await headerFromUser(doc, translations.report.titleDriverRankingReport, userData.user)
39
147
 
148
+ doc.setFontSize(13)
149
+ doc.text(convertToLocaleString(reportData.from, lang, timezone, userData.user) + ' - ' + convertToLocaleString(reportData.to, lang, timezone, userData.user), 20, 25)
150
+
151
+ const data = []
152
+ reportDataRows.forEach(function (row) {
153
+ const temp = [
154
+ row.name,
155
+ row.distance,
156
+ row.highEngineRPM,
157
+ row.hardBraking,
158
+ row.hardAcceleration,
159
+ row.hardCornering,
160
+ row.score
161
+ ]
162
+ data.push(temp)
163
+ })
164
+ const footValues = []
165
+
166
+ const style = getStyle(getUserPartner(userData.user))
167
+
168
+ addTable(doc, headers, data, footValues, style, 40)
169
+ return doc
170
+ }
40
171
  }
41
172
 
42
173
  exports.create = create
@@ -0,0 +1,46 @@
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
@@ -352,6 +352,7 @@ function exportPerformanceReportToExcel (userData, reportData) {
352
352
  }
353
353
  }
354
354
 
355
+ exports.calculateRPMSections = calculateRPMSections
355
356
  exports.createPerformanceReport = createPerformanceReport
356
357
  exports.createPerformanceReportSingle = createPerformanceReportSingle
357
358
  exports.exportPerformanceReportToPDF = exportPerformanceReportToPDF
@@ -0,0 +1,19 @@
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
+ })
@@ -0,0 +1,23 @@
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
+ })
@@ -65,10 +65,11 @@ describe('Kms_Reports', function () {
65
65
  it('KmsReport by timezone marrocos', async () => {
66
66
  const reports = await getReports(process.env.email, process.env.password)
67
67
  const userData = await reports.getUserData()
68
+ userData.groupByDay = true
68
69
  userData.devices = userData.devices.filter(d => d.id === 93497)
69
70
  const data = await reports.kmsReport(convertFromLocal(new Date(2024, 2, 18, 0, 0, 0), userData.user.attributes.timezone), convertFromLocal(new Date(2024, 2, 18, 23, 59, 59), userData.user.attributes.timezone),
70
71
  userData)
71
72
  const device = data[0].devices.find(d => d.device.id === 93497)
72
- assert.equal(device, 1)
73
+ assert.equal(device.days.length, 1)
73
74
  }, 3000000)
74
75
  })
@@ -159,4 +159,21 @@ 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)
162
179
  })
@@ -79,7 +79,7 @@ async function getDriverData (d, data, userData) {
79
79
  return {
80
80
  route,
81
81
  trips: filteredTrips,
82
- events,
82
+ events
83
83
  }
84
84
  }
85
85