fleetmap-reports 1.0.375 → 1.0.378

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/lang/enGB.js CHANGED
@@ -178,6 +178,7 @@ module.exports = {
178
178
  titleSpeedingReport: 'Overspeed Report',
179
179
  titleZoneReport: 'Zone Report',
180
180
  titleRefuelReport: 'Refueling Report',
181
+ titleFuelConsumptionReport: 'Fuel Consumption Report',
181
182
  titleFuelDropReport: 'Fuel Drop Report',
182
183
  titleEventsReport: 'Events Report',
183
184
  titleActivityReport: 'Activity Report',
package/lang/esCL.js CHANGED
@@ -172,6 +172,7 @@ module.exports = {
172
172
  titleSpeedingReport: 'Informe de Excesos de Velocidad',
173
173
  titleZoneReport: 'Informe de Zonas',
174
174
  titleRefuelingReport: 'Informe de Cargas',
175
+ titleFuelConsumptionReport: 'Informe de Consumos',
175
176
  titleFuelDropReport: 'Fuel Drop Report',
176
177
  titleEventsReport: 'Informe de Eventos',
177
178
  titleActivityReport: 'Activity Report',
package/lang/ptBR.js CHANGED
@@ -168,6 +168,7 @@ module.exports = {
168
168
  titleSpeedingReport: 'Relatório de Excessos de Velocidade',
169
169
  titleZoneReport: 'Relatório de Zonas',
170
170
  titleRefuelingReport: 'Relatório de Abastecimentos',
171
+ titleFuelConsumptionReport: 'Relatório de Consumos',
171
172
  titleFuelDropReport: 'Relatório de Perdas de Combustível',
172
173
  titleEventsReport: 'Relatório de Eventos',
173
174
  titleActivityReport: 'Relatório de Actividade',
package/lang/ptPT.js CHANGED
@@ -174,6 +174,7 @@ module.exports = {
174
174
  titleSpeedingReport: 'Relatório de Excessos de Velocidade',
175
175
  titleZoneReport: 'Relatório de Zonas',
176
176
  titleRefuelingReport: 'Relatório de Abastecimentos',
177
+ titleFuelConsumptionReport: 'Relatório de Consumos',
177
178
  titleFuelDropReport: 'Relatório de Perdas de Combustível',
178
179
  titleEventsReport: 'Relatório de Eventos',
179
180
  titleActivityReport: 'Relatório de Actividade',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetmap-reports",
3
- "version": "1.0.375",
3
+ "version": "1.0.378",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -15,7 +15,7 @@
15
15
  "docx": "^7.3.0",
16
16
  "eslint": "^8.8.0",
17
17
  "file-saver": "^2.0.5",
18
- "fleetmap-partners": "^1.0.42",
18
+ "fleetmap-partners": "^1.0.76",
19
19
  "json-as-xlsx": "^1.2.1",
20
20
  "jspdf": "^2.3.1",
21
21
  "jspdf-autotable": "^3.5.14",
@@ -1,5 +1,9 @@
1
- const automaticReports = require("./automaticReports");
2
- const refuelingReport = require("./refueling-report");
1
+ const automaticReports = require("./automaticReports")
2
+ const refuelingReport = require("./refueling-report")
3
+ const traccarHelper = require("./util/traccar")
4
+ const odoo = require("./util/odoo")
5
+
6
+
3
7
 
4
8
  async function createFuelConsumptionReport(from, to, userData, traccar) {
5
9
  console.log('Create FuelConsumption Report')
@@ -13,66 +17,61 @@ async function createFuelConsumptionReport(from, to, userData, traccar) {
13
17
  }
14
18
 
15
19
  userData.devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
16
- const devicesToSlice = userData.devices.filter(d => automaticReports.deviceWithFuelInfo(d)).slice()
17
- console.log('Devices:'+devicesToSlice.length)
18
-
19
- const arrayOfArrays = automaticReports.sliceArray(devicesToSlice)
20
- let data = []
21
- for (const a of arrayOfArrays) {
22
- const response = await traccar.reports.reportsTripsGet(from, to, a.map(d => d.id))
23
- data = data.concat(response.data)
20
+
21
+ const allInOne = await traccarHelper.getAllInOne(traccar, from, to, userData.devices, true, true, false, false)
22
+ const tripsData = allInOne.trips
23
+ const routeData = allInOne.route
24
+
25
+ const fuelServicesData = []
26
+ if(userData.withOdooServices) {
27
+ fuelServicesData.push(...(await odoo.getOdooFuelServices(traccar, from, to)))
24
28
  }
25
- console.log('Trips:'+data.length)
26
29
 
27
- if(data.length === 0) {
30
+ if(tripsData.length === 0) {
28
31
  return reportData
29
32
  }
30
33
 
31
34
  allData.totalDevices = 0
32
35
 
33
36
  for (const d of userData.devices) {
34
- const trips = data.filter(t => t.deviceId===d.id)
37
+ const trips = tripsData.filter(t => t.deviceId===d.id)
38
+ const route = routeData.filter(r => r.deviceId===d.id)
39
+ const deviceFuelServices = fuelServicesData.filter(f => d.attributes.odooId === f.vehicle_id[0])
35
40
 
36
41
  if(trips.length > 0) {
37
- const response = await traccar.reports.reportsRouteGet(from, to, [d.id])
38
- const positions = response.data
39
-
40
- const refuelingPositions = refuelingReport.calculateRefuelingPositions(d, positions)
41
-
42
- const groupedRefuelings = refuelingPositions.reduce(
43
- (entryMap, e) => entryMap.set(e.position.fixTime.substring(0, 10), [...entryMap.get(e.position.fixTime.substring(0, 10))||[], e]),
42
+ const refuelingPositions = await refuelingReport.calculateRefuelingPositions(userData, d, {route: route, trips: trips, fuelServices: deviceFuelServices})
43
+ const groupedRefuelingsByDay = refuelingPositions.reduce(
44
+ (entryMap, e) => entryMap.set(e.date.substring(0, 10), [...entryMap.get(e.date.substring(0, 10))||[], e]),
44
45
  new Map()
45
46
  )
46
47
 
47
48
  trips.forEach(t => t.startDate = t.startTime.substring(0, 10))
48
- const groupedTrips = trips.reduce(
49
+ const groupedTripsByDay = trips.reduce(
49
50
  (entryMap, e) => entryMap.set(e.startDate, [...entryMap.get(e.startDate)||[], e]),
50
51
  new Map()
51
52
  )
52
53
 
53
54
  const days = []
54
- const keys = Array.from(groupedTrips.keys())
55
+ const keys = Array.from(groupedTripsByDay.keys())
56
+ const odooAvgConsumption = userData.withOdooServices ? calculateAvgConsumption(refuelingPositions, trips) : 0
55
57
 
56
- keys.forEach(key => {
57
- const dayTrips = groupedTrips.get(key)
58
- const dayRefueling = groupedRefuelings.get(key)
58
+ keys.forEach(day => {
59
+ const dayTrips = groupedTripsByDay.get(day)
60
+ const dayRefueling = groupedRefuelingsByDay.get(day)
59
61
  const distance = dayTrips.reduce((a, b) => a + b.distance, 0)
60
- let spentFuel = d.attributes.xpert ?
61
- automaticReports.calculateXpertSpentFuel(key, positions)
62
- :
63
- automaticReports.calculateSpentFuel(dayTrips.reduce((a, b) => a + b.spentFuel, 0), d)
62
+ const spentFuel = calculateConsumption(userData, d, day, odooAvgConsumption, { trips: dayTrips, route: route })
64
63
 
65
- const day = {
66
- date: key,
64
+ const dataRow = {
65
+ date: day,
67
66
  distance: distance,
68
67
  spentFuel: spentFuel,
69
- avgConsumption: distance > 0 && spentFuel > 0 ? Math.round(spentFuel * 100 / (distance / 1000)) : 0,
68
+ avgConsumption: userData.withOdooServices ? odooAvgConsumption : distance > 0 && spentFuel > 0 ? Math.round(spentFuel * 100 / (distance / 1000)) : 0,
70
69
  endOdometer: dayTrips.slice(-1)[0].endOdometer,
71
70
  duration: dayTrips.reduce((a, b) => a + b.duration, 0),
72
71
  refueling: (dayRefueling && dayRefueling.length > 0) ? dayRefueling.reduce((a, b) => a + b.diff, 0) : 0,
73
72
  }
74
73
 
75
- days.push(day)
74
+ days.push(dataRow)
76
75
  })
77
76
 
78
77
  if (days.length > 0) {
@@ -90,4 +89,20 @@ async function createFuelConsumptionReport(from, to, userData, traccar) {
90
89
  return reportData
91
90
  }
92
91
 
93
- exports.createFuelConsumptionReport = createFuelConsumptionReport;
92
+ function calculateAvgConsumption(refuelingPositions, trips) {
93
+ const odooTotalfuel = refuelingPositions.reduce((a, b) => a + b.diff, 0)
94
+ const totalKms = trips.reduce((a, b) => a + b.distance, 0)
95
+ return Math.round(odooTotalfuel * 100 / (totalKms / 1000))
96
+ }
97
+
98
+ function calculateConsumption(userData, d, day, avgConsumption, data) {
99
+ if (d.attributes.xpert) {
100
+ return automaticReports.calculateXpertSpentFuel(day, data.route)
101
+ }
102
+ if (userData.withOdooServices) {
103
+ return Math.round((avgConsumption * (data.trips.reduce((a, b) => a + b.distance, 0)/1000)) / 100)
104
+ }
105
+ return automaticReports.calculateSpentFuel(data.trips.reduce((a, b) => a + b.spentFuel, 0), d)
106
+ }
107
+
108
+ exports.createFuelConsumptionReport = createFuelConsumptionReport
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- function Reports(config, axios) {
1
+ function Reports(config, axios, cookieJar) {
2
2
  const {ReportsApi, PositionsApi, SessionApi, DevicesApi, GroupsApi, DriversApi, GeofencesApi} = require('traccar-api')
3
3
  this.traccar = {
4
4
  reports: new ReportsApi(config, null, axios),
@@ -8,7 +8,8 @@ function Reports(config, axios) {
8
8
  groups: new GroupsApi(config, null, axios),
9
9
  drivers: new DriversApi(config, null, axios),
10
10
  geofences: new GeofencesApi(config, null, axios),
11
- axios: axios || require('axios').create({...config.baseOptions, baseURL: config.basePath})
11
+ axios: axios || require('axios').create({...config.baseOptions, baseURL: config.basePath}),
12
+ cookieJar
12
13
  }
13
14
  this.getUserData = async () => {
14
15
  return {
package/src/index.test.js CHANGED
@@ -295,4 +295,33 @@ describe('Test_Reports', function() {
295
295
  assert.equal(device.refuelings.length, 4)
296
296
 
297
297
  }, 30000)
298
+ it('FuelConsumption Report', async () => {
299
+ const report = await getReports()
300
+ const userData = await report.getUserData()
301
+ userData.devices = userData.devices.filter(d => d.id === 22326)
302
+ const data = await report.fuelConsumptionReport(new Date(2022, 0, 1, 0, 0, 0, 0),
303
+ new Date(2022, 0, 10, 23, 59, 59, 0),
304
+ userData)
305
+
306
+ assert.equal(data.length, 1)
307
+ const device = data[0].devices.find(d => d.device.id===22326)
308
+ console.log(device.days)
309
+ assert.equal(device.days.length, 8)
310
+ assert.equal(device.days[0].spentFuel, 2)
311
+
312
+ }, 30000)
313
+ it('FuelConsumption Odoo Report', async () => {
314
+ const report = await getReports()
315
+ const userData = await report.getUserData()
316
+ userData.withOdooServices = true
317
+ userData.devices = userData.devices.filter(d => d.id === 25508)
318
+ const data = await report.fuelConsumptionReport(new Date(2022, 1, 1, 0, 0, 0, 0),
319
+ new Date(2022, 1, 28, 23, 59, 59, 0),
320
+ userData)
321
+
322
+ assert.equal(data.length, 1)
323
+ const device = data[0].devices.find(d => d.device.id===25508)
324
+ assert.equal(device.days.length, 25)
325
+
326
+ }, 30000)
298
327
  })
@@ -1,5 +1,5 @@
1
- const helpers = require("turf");
2
- const automaticReports = require("./automaticReports");
1
+ const helpers = require("turf")
2
+ const automaticReports = require("./automaticReports")
3
3
 
4
4
  const positionsToCheck = 15
5
5
 
@@ -40,7 +40,7 @@ async function createRefuelingReport(from, to, userData, traccar) {
40
40
  const positions = data.filter(t => t.deviceId===d.id)
41
41
 
42
42
  if(positions.length > 0) {
43
- const refuelingPositions = this.calculateRefuelingPositions(d, positions)
43
+ const refuelingPositions = await this.calculateRefuelingPositions(userData, d, {route: positions})
44
44
 
45
45
  if (userData.drivers.length > 0) {
46
46
  refuelingPositions.forEach(p => {
@@ -106,53 +106,69 @@ function coordsDistance(lon1, lat1, lon2, lat2) {
106
106
  return (helpers.distance(from, to) * 1000)
107
107
  }
108
108
 
109
- function calculateRefuelingPositions(d, positions) {
109
+ async function calculateRefuelingPositions(userData, d, data) {
110
110
  const refuelingPositions = []
111
- let refuelingActivated = false
112
- let currentValue = null
113
- let positionsChecked = 0
114
- let lastRefuelingIndex = 0
115
- positions.forEach(function(element, index, array){
116
- if(!element.attributes.ignition && refuelingActivated && !currentValue){
117
- //Ignition is off and Refueling is Active and there is no current value
118
-
119
- //Get 5 position before the ignition off to calculate the current value of the fuel tank level
120
- //lastRefuelingIndex is used to avoid re-analyzing positions prior to a refueling
121
- const before = (index > 5 ? array.slice((index-6 < lastRefuelingIndex ? lastRefuelingIndex : index-6), index-1) : array.slice(0, index-1)).filter(b => b.attributes.ignition && b.attributes.fuel)
122
- currentValue = Math.round(before.reduce((a, b) => a + b.attributes.fuel, 0) / before.length )
123
-
124
- positionsChecked = 0
125
- }
126
111
 
127
- if(element.attributes.ignition && refuelingActivated && currentValue) {
128
- //Ignition is on and Refueling is Active and there is a current value
129
- //Calculate the value of the fuel tank level after turning the ignition back on
130
- const after = (array.length > index + 5 ? array.slice(index, index+1) : array.slice(index)).filter(b => b.attributes.ignition && b.attributes.fuel)
131
- const newValue = Math.round(after.reduce((a, b) => a + b.attributes.fuel, 0) / after.length )
132
-
133
- const diff = automaticReports.calculateFuelDiff(currentValue, newValue, d)
134
- if (diff > 20) {
135
- //New refueling detected
136
- const value = Math.round(diff * d.attributes.fuel_tank_capacity / 100)
137
- refuelingPositions.push({position: element, diff: value})
138
- lastRefuelingIndex = index
139
- positionsChecked = positionsToCheck+1 // to reset values
112
+ if(userData.withOdooServices && d.attributes.odooId) {
113
+ console.log(data.fuelServices)
114
+ data.fuelServices.forEach(s => {
115
+ const serviceDate = new Date(s.date)
116
+ serviceDate.setHours(23, 59, 59, 59)
117
+
118
+ const routeBeforeService = data.route.filter(r => new Date(r.fixTime).getTime() < serviceDate.getTime())
119
+
120
+ const quantity = s.notes.split(':')[1].replace(',', '.') || 0
121
+
122
+ if (routeBeforeService.length) {
123
+ refuelingPositions.push({date: s.date, diff: Number.parseFloat(quantity), cost: s.amount})
140
124
  }
125
+ })
126
+ } else {
127
+ let refuelingActivated = false
128
+ let currentValue = null
129
+ let positionsChecked = 0
130
+ let lastRefuelingIndex = 0
131
+ data.route.forEach(function (element, index, array) {
132
+ if (!element.attributes.ignition && refuelingActivated && !currentValue) {
133
+ //Ignition is off and Refueling is Active and there is no current value
134
+
135
+ //Get 5 position before the ignition off to calculate the current value of the fuel tank level
136
+ //lastRefuelingIndex is used to avoid re-analyzing positions prior to a refueling
137
+ const before = (index > 5 ? array.slice((index - 6 < lastRefuelingIndex ? lastRefuelingIndex : index - 6), index - 1) : array.slice(0, index - 1)).filter(b => b.attributes.ignition && b.attributes.fuel)
138
+ currentValue = Math.round(before.reduce((a, b) => a + b.attributes.fuel, 0) / before.length)
141
139
 
142
- if(positionsChecked > positionsToCheck) {
143
- refuelingActivated = false
144
- currentValue = null
145
140
  positionsChecked = 0
146
- } else {
147
- positionsChecked++
148
141
  }
149
- }
150
142
 
151
- if(element.attributes.ignition && !refuelingActivated) {
152
- refuelingActivated = true
153
- }
154
- })
143
+ if (element.attributes.ignition && refuelingActivated && currentValue) {
144
+ //Ignition is on and Refueling is Active and there is a current value
145
+ //Calculate the value of the fuel tank level after turning the ignition back on
146
+ const after = (array.length > index + 5 ? array.slice(index, index + 1) : array.slice(index)).filter(b => b.attributes.ignition && b.attributes.fuel)
147
+ const newValue = Math.round(after.reduce((a, b) => a + b.attributes.fuel, 0) / after.length)
148
+
149
+ const diff = automaticReports.calculateFuelDiff(currentValue, newValue, d)
150
+ if (diff > 20) {
151
+ //New refueling detected
152
+ const value = Math.round(diff * d.attributes.fuel_tank_capacity / 100)
153
+ refuelingPositions.push({position: element, date: element.fixTime, diff: value})
154
+ lastRefuelingIndex = index
155
+ positionsChecked = positionsToCheck + 1 // to reset values
156
+ }
157
+
158
+ if (positionsChecked > positionsToCheck) {
159
+ refuelingActivated = false
160
+ currentValue = null
161
+ positionsChecked = 0
162
+ } else {
163
+ positionsChecked++
164
+ }
165
+ }
155
166
 
167
+ if (element.attributes.ignition && !refuelingActivated) {
168
+ refuelingActivated = true
169
+ }
170
+ })
171
+ }
156
172
  return refuelingPositions
157
173
  }
158
174
 
@@ -16,7 +16,7 @@ axiosCookieJarSupport(axios)
16
16
 
17
17
  const getReports = async() => {
18
18
  await new SessionApi(traccarConfig, null, axios).sessionPost(process.env.email, process.env.password)
19
- return new Index(traccarConfig, axios)
19
+ return new Index(traccarConfig, axios, cookieJar)
20
20
  }
21
21
 
22
22
  exports.getReports = getReports
@@ -0,0 +1,14 @@
1
+
2
+ async function getOdooFuelServices(traccar, from, to) {
3
+ const url = `/odoo/reports/refuelingServices?startDate=${from.toDateString()}&endDate=${to.toDateString()}`
4
+
5
+ const {data} = await traccar.axios.get(url,{
6
+ jar: traccar.cookieJar,
7
+ withCredentials: true })
8
+
9
+ console.log(data)
10
+
11
+ return data
12
+ }
13
+
14
+ exports.getOdooFuelServices = getOdooFuelServices