fleetmap-reports 1.0.272 → 1.0.276

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.
@@ -0,0 +1,285 @@
1
+ const traccar = require("./util/traccar");
2
+ const messages = require("../lang");
3
+ const jsPDF = require("jspdf");
4
+ const {headerFromUser, AmiriRegular} = require("./util/pdfDocument");
5
+ const {convertToLocaleString, convertMS} = require("./util/utils");
6
+ const {getStyle} = require("./reportStyle");
7
+ const {getUserPartner} = require("fleetmap-partners");
8
+
9
+
10
+ let traccarInstance
11
+ let userData
12
+
13
+ const fileName = 'IdleReport'
14
+
15
+ async function createIdleReport(from, to, reportUserData, traccar) {
16
+ console.log('Create IdleReport')
17
+ userData = reportUserData
18
+ traccarInstance = traccar
19
+ const reportData = []
20
+
21
+ if (userData.byGroup) {
22
+ console.log("ByGroup")
23
+ const allData = await createTripReportByGroup(from, to)
24
+ reportData.push(...allData)
25
+ } else {
26
+ console.log("ByDevice")
27
+ const report = await createTripReportByDevice(from, to)
28
+ reportData.push(report)
29
+ }
30
+
31
+ return reportData
32
+ }
33
+
34
+ async function createTripReportByGroup(from, to) {
35
+ const reportData = []
36
+ for (const g of userData.groups) {
37
+ const devices = userData.devices.filter(d => d.groupId === g.id)
38
+ console.log(g.name + ' devices:' + devices.length)
39
+ if(devices.length > 0) {
40
+ const groupData = {
41
+ devices: [],
42
+ group: g,
43
+ from: from,
44
+ to: to
45
+ }
46
+
47
+ const response = await traccarInstance.reports.reportsRouteGet(from, to, null, [g.id])
48
+ const routes = response.data
49
+
50
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
51
+
52
+ if (routes.length > 0) {
53
+ console.log('Routes:' + routes.length)
54
+ groupData.devices = processDevices(from, to, devices, routes)
55
+
56
+ reportData.push(groupData)
57
+ }
58
+ }
59
+ }
60
+
61
+ const groupIds = userData.groups.map(g => g.id)
62
+ const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
63
+
64
+ const allData = await createTripReportByDevice(from, to, withoutGroupDevices)
65
+ reportData.push(allData)
66
+
67
+ return reportData
68
+ }
69
+
70
+ async function createTripReportByDevice(from, to) {
71
+ const devices = userData.devices
72
+ const allData = {
73
+ devices: [],
74
+ from: from,
75
+ to: to
76
+ }
77
+
78
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
79
+
80
+ const devicesToSlice = devices.slice()
81
+ const route = await traccar.getRoute(traccarInstance, from, to, devicesToSlice)
82
+
83
+ console.log('Route:' + route.length)
84
+
85
+ if (route.length > 0) {
86
+ allData.devices = processDevices(from, to, devices, route)
87
+ }
88
+
89
+ return allData
90
+ }
91
+
92
+ function processDevices(from, to, devices, routes) {
93
+ const devicesResult = []
94
+
95
+ devices.forEach(d => {
96
+ const route = routes.filter(p => p.deviceId === d.id)
97
+
98
+ const idleEvents = []
99
+ let inIdle = false
100
+ route.forEach(p => {
101
+ if(p.attributes.ignition && p.speed === 0){
102
+ if(!inIdle) {
103
+ const idleEvent = {
104
+ position: p,
105
+ idleTime: 0
106
+ }
107
+ idleEvents.push(idleEvent)
108
+ inIdle = true
109
+ }
110
+ } else if(inIdle) {
111
+ const currentIdleEvent = idleEvents[idleEvents.length-1]
112
+ currentIdleEvent.idleTime = new Date(p.fixTime) - new Date(currentIdleEvent.position.fixTime)
113
+ inIdle = false
114
+ }
115
+ })
116
+
117
+ if(idleEvents.length) {
118
+ const deviceData = {
119
+ device: d,
120
+ idleEvents: idleEvents
121
+ }
122
+ devicesResult.push(deviceData)
123
+ }
124
+ })
125
+
126
+ return devicesResult
127
+ }
128
+
129
+ async function exportIdleReportToPDF(userData, reportData) {
130
+ console.log('Export to PDF')
131
+
132
+ const lang = userData.user.attributes.lang
133
+ const timezone = userData.user.attributes.timezone
134
+ const translations = messages[lang] ? messages[lang] : messages['en-GB']
135
+
136
+ const idleData = userData.byDriver ? reportData.drivers : reportData.devices
137
+
138
+ const headers = [
139
+ translations.report.date,
140
+ translations.report.address,
141
+ translations.report.duration
142
+ ]
143
+
144
+ if (userData.byDriver) {
145
+ headers.push(translations.report.vehicle)
146
+ } else {
147
+ headers.push(translations.report.driver)
148
+ }
149
+
150
+ if (idleData) {
151
+ let first = true
152
+ const doc = new jsPDF.jsPDF('l');
153
+ await headerFromUser(doc, translations.report.titleIdleReport, userData.user)
154
+
155
+ idleData.forEach(d => {
156
+ try {
157
+ let data = []
158
+
159
+ const name = userData.byDriver ? d.driver.name : deviceName(d.device)
160
+ const group = userData.byDriver ? userData.groups.find(g => g.drivers.includes(d.id)) : userData.groups.find(g => d.device.groupId === g.id)
161
+
162
+ let space = 0
163
+ if(!first) {
164
+ doc.addPage()
165
+ } else {
166
+ first = false
167
+ space = 10
168
+ }
169
+ doc.setFontSize(13)
170
+ doc.text(name, 20, space+20 )
171
+ doc.setFontSize(11)
172
+ doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space+20 )
173
+ doc.text(convertToLocaleString(reportData.from, lang, timezone) + ' - ' + convertToLocaleString(reportData.to, lang, timezone), 20, space+25 )
174
+
175
+ d.idleEvents.map(a => {
176
+ const temp = [
177
+ getIdleEventDate(a, userData.user),
178
+ a.position.address,
179
+ convertMS(a.idleTime, true),
180
+ userData.byDriver ? a.deviceName : a.driver
181
+ ]
182
+
183
+ data.push(temp)
184
+ })
185
+
186
+ const footValues = [
187
+ 'Total:' + d.idleEvents.length,
188
+ '',
189
+ convertMS(d.idleEvents.reduce((a, b) => a + b.idleTime, 0), true)
190
+ ]
191
+
192
+ if(userData.roadSpeedLimits){
193
+ footValues.splice(2, 0, '')
194
+ }
195
+
196
+ doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
197
+ doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
198
+
199
+ const style = getStyle(getUserPartner(userData.user))
200
+ doc.autoTable({
201
+ head: [headers],
202
+ body: data,
203
+ foot: [footValues],
204
+ showFoot: 'lastPage',
205
+ headStyles: {
206
+ fillColor: style.pdfHeaderColor,
207
+ textColor: style.pdfHeaderTextColor,
208
+ fontSize: 10
209
+ },
210
+ bodyStyles: {
211
+ fillColor: style.pdfBodyColor,
212
+ textColor: style.pdfBodyTextColor,
213
+ fontSize: 8,
214
+ font: timezone === 'Asia/Qatar' ? "Amiri" : ''
215
+
216
+ },
217
+ footStyles: {
218
+ fillColor: style.pdfFooterColor,
219
+ textColor: style.pdfFooterTextColor,
220
+ fontSize: 9
221
+ },
222
+ startY: space+35 });
223
+ } catch (e) {
224
+ console.error(e, 'moving on...')
225
+ }
226
+ })
227
+
228
+ return doc
229
+ }
230
+ }
231
+
232
+ function exportIdleReportToExcel(userData, reportData) {
233
+ console.log('Export to Excel')
234
+
235
+ const lang = userData.user.attributes.lang
236
+ const translations = messages[lang] ? messages[lang] : messages['en-GB']
237
+
238
+ const idleData = userData.byDriver ? reportData.drivers : reportData.devices
239
+
240
+ const settings = {
241
+ sheetName: translations.report.titleIdleReport.substring(0, 31), // The name of the sheet
242
+ fileName: fileName, // The name of the spreadsheet
243
+ }
244
+ const headers = [
245
+ userData.byDriver ? {label: translations.report.driver, value:'driver'} : {label: translations.report.vehicle, value:'name'},
246
+ {label: translations.report.date, value:'fixTime'},
247
+ {label: translations.report.address, value:'address'},
248
+ {label: translations.report.duration, value:'duration'},
249
+ userData.byDriver ? {label: translations.report.vehicle, value:'name'} : {label: translations.report.driver, value:'driver'}
250
+ ]
251
+
252
+ let data = []
253
+ if (idleData) {
254
+ idleData.forEach(d => {
255
+ data = data.concat([{}])
256
+ data = data.concat(d.idleEvents.map(a => {
257
+ return {
258
+ driver: userData.byDriver ? d.driver.name : a.driver,
259
+ duration: convertMS(a.idleTime, true),
260
+ fixTime: getIdleEventDate(a, userData.user),
261
+ name: userData.byDriver ? a.deviceName : d.device.name,
262
+ address: a.position.address + (a.geofenceName ? ' - ' + a.geofenceName : '')
263
+ }
264
+ }))
265
+ })
266
+ console.log(data)
267
+ return {
268
+ headers,
269
+ data,
270
+ settings
271
+ }
272
+ }
273
+ }
274
+
275
+ function deviceName(device){
276
+ return device.name + (device.attributes.license_plate ? ', ' +device.attributes.license_plate : '') + (device.model ? ', ' + device.model : '')
277
+ }
278
+
279
+ function getIdleEventDate(row, user) {
280
+ return convertToLocaleString(row.position.fixTime, user.attributes.lang, user.attributes.timezone)
281
+ }
282
+
283
+ exports.createIdleReport = createIdleReport;
284
+ exports.exportIdleReportToPDF = exportIdleReportToPDF;
285
+ exports.exportIdleReportToExcel = exportIdleReportToExcel;
package/src/index.js CHANGED
@@ -124,6 +124,16 @@ function Reports(config, axios) {
124
124
  this.vistaWasteActivityReportToExcel = (userData, reportData) => {
125
125
  return require('./custom/vistawasteActivity-report').exportVistaWasteActivityReportToExcel(userData, reportData)
126
126
  }
127
+
128
+ this.idleReport = (from, to, userData) => {
129
+ return require('./idle-report').createIdleReport(from, to, userData, this.traccar)
130
+ }
131
+ this.idleReportToPDF = (userData, reportData) => {
132
+ return require('./idle-report').exportIdleReportToPDF(userData, reportData)
133
+ }
134
+ this.idleReportToExcel = (userData, reportData) => {
135
+ return require('./idle-report').exportIdleReportToExcel(userData, reportData)
136
+ }
127
137
  }
128
138
  module.exports = Reports
129
139
 
package/src/index.test.js CHANGED
@@ -1,20 +1,60 @@
1
1
  const {getReports} = require("./tests");
2
2
 
3
- describe('speedingReport', function() {
3
+ describe('Reports', function() {
4
4
  this.timeout(500000)
5
5
  it('test speeding', async () => {
6
6
  const report = await getReports()
7
7
  const userData = await report.getUserData()
8
8
 
9
- await report.speedingReport(new Date(2021, 2, 30, 0, 0, 0, 0),
9
+ const reportData = await report.speedingReport(new Date(2021, 2, 30, 0, 0, 0, 0),
10
10
  new Date(2021, 2, 30, 23, 59, 59, 0),
11
11
  userData)
12
+
13
+ console.log(reportData)
14
+
15
+ })
16
+ it('test trip report', async () => {
17
+ const report = await getReports()
18
+ const userData = await report.getUserData()
19
+ userData.byGroup = true
20
+ const reportData = await report.tripReport(new Date(2021, 2, 30, 0, 0, 0, 0),
21
+ new Date(2021, 2, 30, 23, 59, 59, 0),
22
+ userData)
23
+
24
+ console.log(reportData)
25
+
26
+ })
27
+ it('test event report', async () => {
28
+ const report = await getReports()
29
+ const userData = await report.getUserData()
30
+ userData.eventTypes = []
31
+ const reportData = await report.eventsReport(new Date(2021, 10, 20, 0, 0, 0, 0),
32
+ new Date(2021, 10, 30, 23, 59, 59, 0),
33
+ userData)
34
+
35
+ console.log(reportData)
36
+
12
37
  })
13
38
  it('test kmsReport by day', async () => {
14
39
  const reports = await getReports()
15
40
  const userData = await reports.getUserData()
16
41
  userData.groupByDay = true
17
- await reports.kmsReport(new Date(2021, 9), new Date(2021, 10),
42
+ const reportData = await reports.kmsReport(new Date(2021, 10, 1), new Date(2021, 10, 3),
43
+ userData)
44
+
45
+ console.log(reportData)
46
+
47
+ await reports.kmsReportToPDF(userData, reportData[0])
48
+ })
49
+ it('test locationReport by day', async () => {
50
+ const reports = await getReports()
51
+ const userData = await reports.getUserData()
52
+ userData.groupByDay = true
53
+ const reportData = await reports.locations(new Date(2021, 10, 1), new Date(2021, 10, 3),
18
54
  userData)
55
+
56
+ console.log(reportData)
57
+
58
+ await reports.kmsReportToPDF(userData, reportData[0])
19
59
  })
20
60
  })
package/src/kms-report.js CHANGED
@@ -8,6 +8,7 @@ const traccar = require("./util/traccar");
8
8
  const {getDates} = require("./util/utils");
9
9
  const trips = require("./util/trips");
10
10
  const drivers = require("./util/driver");
11
+ const {isInsideTimetable} = require("./util/trips");
11
12
 
12
13
 
13
14
  let traccarInstance
@@ -15,6 +16,31 @@ let userData
15
16
 
16
17
  const fileName = 'KmsReport'
17
18
 
19
+ async function createKmsReport(from, to, reportUserData, traccar) {
20
+ console.log('Create KmsReport')
21
+
22
+ console.log(from, to)
23
+ traccarInstance = traccar
24
+ userData = reportUserData
25
+ const reportData = []
26
+ if(userData.byDriver){
27
+ console.log("ByDriver")
28
+ const allData = await createKmsReportByDriver(from, to)
29
+ reportData.push(allData)
30
+ }
31
+ else if(userData.byGroup){
32
+ console.log("ByGroup")
33
+ const allData = await createKmsReportByGroup(from, to)
34
+ reportData.push(...allData)
35
+ } else {
36
+ console.log("ByDevice")
37
+ const allData = await createKmsReportByDevice(from, to)
38
+ reportData.push(allData)
39
+ }
40
+
41
+ return reportData
42
+ }
43
+
18
44
  async function createKmsReportByDevice(from, to) {
19
45
  const groupIds = userData.groups.map(g => g.id)
20
46
  const devicesToProcess = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
@@ -53,7 +79,37 @@ async function createKmsReportByDriver(from, to) {
53
79
  }
54
80
 
55
81
  async function createKmsReportByGroup(from, to) {
82
+ const reportData = []
83
+ for (const g of userData.groups) {
84
+ const devices = userData.devices.filter(d => d.groupId === g.id)
85
+ console.log(g.name + ' devices:' + devices.length)
86
+ if(devices.length > 0) {
87
+ const groupData = {
88
+ devices: [],
89
+ group: g,
90
+ xpert: devices.filter(d => d.attributes.xpert).length > 0
91
+ }
92
+
93
+ const route = userData.allWeek ? [] : await traccar.getRoute(traccarInstance, from, to, devices)
94
+ const tripsData = await traccar.getTrips(traccarInstance, from, to, devices)
95
+
96
+ devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
97
+
98
+ console.log('trips:' + tripsData.length)
99
+
100
+ if (tripsData.length > 0) {
101
+ await trips.checkTripsKms(traccarInstance, from, to, route, tripsData, devices)
102
+ groupData.devices = processDevices(from, to, devices, route, tripsData)
103
+ }
104
+
105
+ reportData.push(groupData)
106
+ }
107
+ }
56
108
 
109
+ const withoutGroupData = await createKmsReportByDevice(from, to)
110
+ reportData.push(withoutGroupData)
111
+
112
+ return reportData
57
113
  }
58
114
 
59
115
  function processDrivers(from, to, drivers, data) {
@@ -69,41 +125,16 @@ function processDrivers(from, to, drivers, data) {
69
125
  driverData.days = []
70
126
  const dates = getDates(from, to)
71
127
  for(const date of dates){
72
- if(userData.allWeek || !userData.weekDays){
73
- const fromByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
74
- const toByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
128
+ const fromByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0)
129
+ const toByDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59)
75
130
 
76
- const tripsByDay = trips.filter(t => new Date(t.startTime) > fromByDay && new Date(t.endTime) < toByDay)
131
+ const tripsByDay = trips.filter(t => (new Date(t.startTime) > fromByDay && new Date(t.endTime) < toByDay)
132
+ && (userData.allWeek || !userData.weekDays || isInsideTimetable(t, userData)))
77
133
 
78
- driverData.days.push({
79
- date: date,
80
- kms: tripsByDay.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
81
- })
82
- } else {
83
- if((date.getDay() === 0 && userData.weekDays.sunday) ||
84
- (date.getDay() === 1 && userData.weekDays.monday) ||
85
- (date.getDay() === 2 && userData.weekDays.tuesday) ||
86
- (date.getDay() === 3 && userData.weekDays.wednesday) ||
87
- (date.getDay() === 4 && userData.weekDays.thursday) ||
88
- (date.getDay() === 5 && userData.weekDays.friday) ||
89
- (date.getDay() === 6 && userData.weekDays.saturday)) {
90
-
91
- const fromByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.startTime)
92
- const toByDay = new Date(new Date(date).toISOString().split('T')[0] + ' ' + userData.dayHours.endTime)
93
-
94
- const tripsByDay = trips.filter(t => new Date(t.startTime) > fromByDay && new Date(t.endTime) < toByDay)
95
-
96
- driverData.days.push({
97
- date: date,
98
- kms: tripsByDay.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
99
- })
100
- }else {
101
- driverData.days.push({
102
- date: date,
103
- kms: 0
104
- })
105
- }
106
- }
134
+ driverData.days.push({
135
+ date: date,
136
+ kms: tripsByDay.filter(t => t.distance > 0).reduce((a, b) => a + b.distance, 0)
137
+ })
107
138
  }
108
139
  } else {
109
140
  driverData.summary = {
@@ -227,30 +258,6 @@ function processDevices(from, to, devices, route, trips) {
227
258
  return devicesResult
228
259
  }
229
260
 
230
- async function createKmsReport(from, to, reportUserData, traccar) {
231
- console.log('Create KmsReport')
232
-
233
- console.log(from, to)
234
- traccarInstance = traccar
235
- userData = reportUserData
236
- const reportData = []
237
- if(userData.byDriver){
238
- const allData = await createKmsReportByDriver(from, to)
239
- reportData.push(allData)
240
- }
241
- else if(userData.byGroup){
242
- const allGroupsData = await createKmsReportByGroup(from, to)
243
- allGroupsData.forEach(data => reportData.push(data))
244
- const withoutGroupDevices = await createKmsReportByDevice(from, to)
245
- reportData.push(withoutGroupDevices)
246
- } else {
247
- const allData = await createKmsReportByDevice(from, to)
248
- reportData.push(allData)
249
- }
250
-
251
- return reportData
252
- }
253
-
254
261
  async function exportKmsReportToPDF(userData, reportData) {
255
262
  const lang = userData.user.attributes.lang || (navigator && navigator.language)
256
263
  const translations = messages[lang] ? messages[lang] : messages['en-GB']
@@ -1,7 +1,7 @@
1
1
  const messages = require('../lang')
2
2
  const jsPDF = require('jspdf')
3
3
  const {convertMS, convertToLocaleString} = require("./util/utils")
4
- const {headerFromUser} = require("./util/pdfDocument")
4
+ const {headerFromUser, AmiriRegular} = require("./util/pdfDocument")
5
5
  require('jspdf-autotable')
6
6
  const { parse } = require('wkt')
7
7
  const turf = require('turf')
@@ -241,7 +241,6 @@ async function getHereEvents(devices, routes, threshold){
241
241
  const positions = routes.filter(p => p.deviceId === d.id)
242
242
  try {
243
243
  const results = await here.routeMatch(positions)
244
- console.log('results', results)
245
244
  const hereAlerts = results.filter(r => r.currentSpeedKmh > (parseInt(r.speedLimit) + threshold)).map(r => {
246
245
  const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
247
246
  return {
@@ -253,7 +252,6 @@ async function getHereEvents(devices, routes, threshold){
253
252
  attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
254
253
  }
255
254
  })
256
- console.log('threshold', threshold, hereAlerts)
257
255
  const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
258
256
  if (idx === 1) {
259
257
  return [cur]
@@ -396,6 +394,9 @@ async function exportSpeedingReportToPDF(userData, reportData) {
396
394
  footValues.splice(2, 0, '')
397
395
  }
398
396
 
397
+ doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
398
+ doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
399
+
399
400
  const style = getStyle(getUserPartner(userData.user))
400
401
  doc.autoTable({
401
402
  head: [headers],
@@ -410,7 +411,8 @@ async function exportSpeedingReportToPDF(userData, reportData) {
410
411
  bodyStyles: {
411
412
  fillColor: style.pdfBodyColor,
412
413
  textColor: style.pdfBodyTextColor,
413
- fontSize: 8
414
+ fontSize: 8,
415
+ font: timezone === 'Asia/Qatar' ? "Amiri" : ''
414
416
  },
415
417
  footStyles: {
416
418
  fillColor: style.pdfFooterColor,