aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/reports
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/reports')
-rw-r--r--src/main/java/org/traccar/reports/CsvExportProvider.java76
-rw-r--r--src/main/java/org/traccar/reports/Events.java133
-rw-r--r--src/main/java/org/traccar/reports/EventsReportProvider.java169
-rw-r--r--src/main/java/org/traccar/reports/GpxExportProvider.java76
-rw-r--r--src/main/java/org/traccar/reports/KmlExportProvider.java80
-rw-r--r--src/main/java/org/traccar/reports/ReportUtils.java368
-rw-r--r--src/main/java/org/traccar/reports/Route.java85
-rw-r--r--src/main/java/org/traccar/reports/RouteReportProvider.java102
-rw-r--r--src/main/java/org/traccar/reports/Stops.java102
-rw-r--r--src/main/java/org/traccar/reports/StopsReportProvider.java110
-rw-r--r--src/main/java/org/traccar/reports/SummaryReportProvider.java (renamed from src/main/java/org/traccar/reports/Summary.java)120
-rw-r--r--src/main/java/org/traccar/reports/Trips.java100
-rw-r--r--src/main/java/org/traccar/reports/TripsReportProvider.java110
-rw-r--r--src/main/java/org/traccar/reports/common/ReportUtils.java399
-rw-r--r--src/main/java/org/traccar/reports/common/TripsConfig.java (renamed from src/main/java/org/traccar/reports/model/TripsConfig.java)67
-rw-r--r--src/main/java/org/traccar/reports/model/BaseReportItem.java (renamed from src/main/java/org/traccar/reports/model/BaseReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/DeviceReportSection.java (renamed from src/main/java/org/traccar/reports/model/DeviceReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/StopReportItem.java (renamed from src/main/java/org/traccar/reports/model/StopReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/SummaryReportItem.java (renamed from src/main/java/org/traccar/reports/model/SummaryReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/TripReportItem.java (renamed from src/main/java/org/traccar/reports/model/TripReport.java)2
20 files changed, 1227 insertions, 880 deletions
diff --git a/src/main/java/org/traccar/reports/CsvExportProvider.java b/src/main/java/org/traccar/reports/CsvExportProvider.java
new file mode 100644
index 000000000..df55c470e
--- /dev/null
+++ b/src/main/java/org/traccar/reports/CsvExportProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.traccar.helper.DateUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+
+import javax.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class CsvExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public CsvExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ var attributes = positions.stream()
+ .flatMap((position -> position.getAttributes().keySet().stream()))
+ .collect(Collectors.toUnmodifiableSet());
+
+ var properties = new LinkedHashMap<String, Function<Position, Object>>();
+ properties.put("id", Position::getId);
+ properties.put("deviceId", Position::getDeviceId);
+ properties.put("protocol", Position::getProtocol);
+ properties.put("serverTime", position -> DateUtil.formatDate(position.getServerTime()));
+ properties.put("deviceTime", position -> DateUtil.formatDate(position.getDeviceTime()));
+ properties.put("fixTime", position -> DateUtil.formatDate(position.getFixTime()));
+ properties.put("valid", Position::getValid);
+ properties.put("latitude", Position::getLatitude);
+ properties.put("longitude", Position::getLongitude);
+ properties.put("altitude", Position::getAltitude);
+ properties.put("speed", Position::getSpeed);
+ properties.put("course", Position::getCourse);
+ properties.put("address", Position::getAddress);
+ properties.put("accuracy", Position::getAccuracy);
+ attributes.forEach(key -> properties.put(key, position -> position.getAttributes().get(key)));
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.println(String.join(",", properties.keySet()));
+ positions.forEach(position -> writer.println(properties.values().stream()
+ .map(f -> Objects.toString(f.apply(position), ""))
+ .collect(Collectors.joining(","))));
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/Events.java b/src/main/java/org/traccar/reports/Events.java
deleted file mode 100644
index 66d9e708d..000000000
--- a/src/main/java/org/traccar/reports/Events.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.reports.model.DeviceReport;
-
-public final class Events {
-
- private Events() {
- }
-
- public static Collection<Event> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Collection<String> types, Date from, Date to) throws SQLException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<Event> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
- boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
- for (Event event : events) {
- if (all || types.contains(event.getType())) {
- long geofenceId = event.getGeofenceId();
- long maintenanceId = event.getMaintenanceId();
- if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId))
- && (maintenanceId == 0
- || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) {
- result.add(event);
- }
- }
- }
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Collection<String> types, Date from, Date to) throws SQLException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesEvents = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- HashMap<Long, String> geofenceNames = new HashMap<>();
- HashMap<Long, String> maintenanceNames = new HashMap<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
- boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
- for (Iterator<Event> iterator = events.iterator(); iterator.hasNext();) {
- Event event = iterator.next();
- if (all || types.contains(event.getType())) {
- long geofenceId = event.getGeofenceId();
- long maintenanceId = event.getMaintenanceId();
- if (geofenceId != 0) {
- if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
- Geofence geofence = Context.getGeofenceManager().getById(geofenceId);
- if (geofence != null) {
- geofenceNames.put(geofenceId, geofence.getName());
- }
- } else {
- iterator.remove();
- }
- } else if (maintenanceId != 0) {
- if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) {
- Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
- if (maintenance != null) {
- maintenanceNames.put(maintenanceId, maintenance.getName());
- }
- } else {
- iterator.remove();
- }
- }
- } else {
- iterator.remove();
- }
- }
- DeviceReport deviceEvents = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceEvents.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceEvents.setGroupName(group.getName());
- }
- }
- deviceEvents.setObjects(events);
- devicesEvents.add(deviceEvents);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesEvents);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("geofenceNames", geofenceNames);
- jxlsContext.putVar("maintenanceNames", maintenanceNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-}
diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java
new file mode 100644
index 000000000..30f55ba80
--- /dev/null
+++ b/src/main/java/org/traccar/reports/EventsReportProvider.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class EventsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public EventsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ private List<Event> getEvents(long deviceId, Date from, Date to) throws StorageException {
+ return storage.getObjects(Event.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Between("eventTime", "from", from, "to", to)),
+ new Order("eventTime")));
+ }
+
+ public Collection<Event> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Collection<String> types, Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<Event> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<Event> events = getEvents(device.getId(), from, to);
+ boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
+ for (Event event : events) {
+ if (all || types.contains(event.getType())) {
+ long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
+ if ((geofenceId == 0 || reportUtils.getObject(userId, Geofence.class, geofenceId) != null)
+ && (maintenanceId == 0
+ || reportUtils.getObject(userId, Maintenance.class, maintenanceId) != null)) {
+ result.add(event);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void getExcel(
+ OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Collection<String> types, Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesEvents = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ HashMap<Long, String> geofenceNames = new HashMap<>();
+ HashMap<Long, String> maintenanceNames = new HashMap<>();
+ HashMap<Long, Position> positions = new HashMap<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<Event> events = getEvents(device.getId(), from, to);
+ boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
+ for (Iterator<Event> iterator = events.iterator(); iterator.hasNext();) {
+ Event event = iterator.next();
+ if (all || types.contains(event.getType())) {
+ long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
+ if (geofenceId != 0) {
+ Geofence geofence = reportUtils.getObject(userId, Geofence.class, geofenceId);
+ if (geofence != null) {
+ geofenceNames.put(geofenceId, geofence.getName());
+ } else {
+ iterator.remove();
+ }
+ } else if (maintenanceId != 0) {
+ Maintenance maintenance = reportUtils.getObject(userId, Maintenance.class, maintenanceId);
+ if (maintenance != null) {
+ maintenanceNames.put(maintenanceId, maintenance.getName());
+ } else {
+ iterator.remove();
+ }
+ }
+ } else {
+ iterator.remove();
+ }
+ }
+ for (Event event : events) {
+ long positionId = event.getPositionId();
+ if (positionId > 0) {
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", positionId)));
+ positions.put(positionId, position);
+ }
+ }
+ DeviceReportSection deviceEvents = new DeviceReportSection();
+ deviceEvents.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceEvents.setGroupName(group.getName());
+ }
+ }
+ deviceEvents.setObjects(events);
+ devicesEvents.add(deviceEvents);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "events.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesEvents);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("geofenceNames", geofenceNames);
+ context.putVar("maintenanceNames", maintenanceNames);
+ context.putVar("positions", positions);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/reports/GpxExportProvider.java b/src/main/java/org/traccar/reports/GpxExportProvider.java
new file mode 100644
index 000000000..ccbd97fc3
--- /dev/null
+++ b/src/main/java/org/traccar/reports/GpxExportProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.traccar.helper.DateUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Date;
+
+public class GpxExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public GpxExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ writer.print("<gpx version=\"1.0\">");
+ writer.print("<trk>");
+ writer.print("<name>");
+ writer.print(device.getName());
+ writer.print("</name>");
+ writer.print("<trkseg>");
+ positions.forEach(position -> {
+ writer.print("<trkpt lat=\"");
+ writer.print(position.getLatitude());
+ writer.print("\" lon=\"");
+ writer.print(position.getLongitude());
+ writer.print("\">");
+ writer.print("<ele>");
+ writer.print(position.getAltitude());
+ writer.print("</ele>");
+ writer.print("<time>");
+ writer.print(DateUtil.formatDate(position.getFixTime()));
+ writer.print("</time>");
+ writer.print("</trkpt>");
+ });
+ writer.print("</trkseg>");
+ writer.print("</trk>");
+ writer.print("</gpx>");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/KmlExportProvider.java b/src/main/java/org/traccar/reports/KmlExportProvider.java
new file mode 100644
index 000000000..24fcfb8ab
--- /dev/null
+++ b/src/main/java/org/traccar/reports/KmlExportProvider.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+public class KmlExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public KmlExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ writer.print("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
+ writer.print("<Document>");
+ writer.print("<name>");
+ writer.print(device.getName());
+ writer.print("</name>");
+ writer.print("<Placemark>");
+ writer.print("<name>");
+ writer.print(dateFormat.format(from));
+ writer.print(" - ");
+ writer.print(dateFormat.format(to));
+ writer.print("</name>");
+ writer.print("<LineString>");
+ writer.print("<extrude>1</extrude>");
+ writer.print("<tessellate>1</tessellate>");
+ writer.print("<altitudeMode>absolute</altitudeMode>");
+ writer.print("<coordinates>");
+ writer.print(positions.stream()
+ .map((p -> String.format("%f,%f,%f", p.getLongitude(), p.getLatitude(), p.getAltitude())))
+ .collect(Collectors.joining(" ")));
+ writer.print("</coordinates>");
+ writer.print("</LineString>");
+ writer.print("</Placemark>");
+ writer.print("</Document>");
+ writer.print("</kml>");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/ReportUtils.java b/src/main/java/org/traccar/reports/ReportUtils.java
deleted file mode 100644
index 58674beae..000000000
--- a/src/main/java/org/traccar/reports/ReportUtils.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.reports;
-
-import org.apache.velocity.tools.generic.DateTool;
-import org.apache.velocity.tools.generic.NumberTool;
-import org.jxls.area.Area;
-import org.jxls.builder.xls.XlsCommentAreaBuilder;
-import org.jxls.common.CellRef;
-import org.jxls.formula.StandardFormulaProcessor;
-import org.jxls.transform.Transformer;
-import org.jxls.transform.poi.PoiTransformer;
-import org.jxls.util.TransformerFactory;
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.handler.events.MotionEventHandler;
-import org.traccar.helper.UnitsConverter;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Driver;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-import org.traccar.reports.model.BaseReport;
-import org.traccar.reports.model.StopReport;
-import org.traccar.reports.model.TripReport;
-import org.traccar.reports.model.TripsConfig;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-public final class ReportUtils {
-
- private ReportUtils() {
- }
-
- public static void checkPeriodLimit(Date from, Date to) {
- long limit = Context.getConfig().getLong(Keys.REPORT_PERIOD_LIMIT) * 1000;
- if (limit > 0 && to.getTime() - from.getTime() > limit) {
- throw new IllegalArgumentException("Time period exceeds the limit");
- }
- }
-
- public static String getDistanceUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "distanceUnit", "km");
- }
-
- public static String getSpeedUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "speedUnit", "kn");
- }
-
- public static String getVolumeUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "volumeUnit", "ltr");
- }
-
- public static TimeZone getTimezone(long userId) {
- String timezone = (String) Context.getPermissionsManager().lookupAttribute(userId, "timezone", null);
- return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault();
- }
-
- public static Collection<Long> getDeviceList(Collection<Long> deviceIds, Collection<Long> groupIds) {
- Collection<Long> result = new ArrayList<>(deviceIds);
- for (long groupId : groupIds) {
- result.addAll(Context.getPermissionsManager().getGroupDevices(groupId));
- }
- return result;
- }
-
- public static double calculateDistance(Position firstPosition, Position lastPosition) {
- return calculateDistance(firstPosition, lastPosition, true);
- }
-
- public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) {
- double distance = 0.0;
- double firstOdometer = firstPosition.getDouble(Position.KEY_ODOMETER);
- double lastOdometer = lastPosition.getDouble(Position.KEY_ODOMETER);
-
- if (useOdometer && firstOdometer != 0.0 && lastOdometer != 0.0) {
- distance = lastOdometer - firstOdometer;
- } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)
- && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) {
- distance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE)
- - firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE);
- }
- return distance;
- }
-
- public static double calculateFuel(Position firstPosition, Position lastPosition) {
-
- if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null
- && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) {
-
- BigDecimal value = BigDecimal.valueOf(firstPosition.getDouble(Position.KEY_FUEL_LEVEL)
- - lastPosition.getDouble(Position.KEY_FUEL_LEVEL));
- return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue();
- }
- return 0;
- }
-
- public static String findDriver(Position firstPosition, Position lastPosition) {
- if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) {
- return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
- } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) {
- return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
- }
- return null;
- }
-
- public static String findDriverName(String driverUniqueId) {
- if (driverUniqueId != null && Context.getDriversManager() != null) {
- Driver driver = Context.getDriversManager().getDriverByUniqueId(driverUniqueId);
- if (driver != null) {
- return driver.getName();
- }
- }
- return null;
- }
-
- public static org.jxls.common.Context initializeContext(long userId) {
- org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext();
- jxlsContext.putVar("distanceUnit", getDistanceUnit(userId));
- jxlsContext.putVar("speedUnit", getSpeedUnit(userId));
- jxlsContext.putVar("volumeUnit", getVolumeUnit(userId));
- jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url"));
- jxlsContext.putVar("dateTool", new DateTool());
- jxlsContext.putVar("numberTool", new NumberTool());
- jxlsContext.putVar("timezone", getTimezone(userId));
- jxlsContext.putVar("locale", Locale.getDefault());
- jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]");
- return jxlsContext;
- }
-
- public static void processTemplateWithSheets(
- InputStream templateStream, OutputStream targetStream,
- org.jxls.common.Context jxlsContext) throws IOException {
-
- Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
- List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
- for (Area xlsArea : xlsAreas) {
- xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), jxlsContext);
- xlsArea.setFormulaProcessor(new StandardFormulaProcessor());
- xlsArea.processFormulas();
- }
- transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName());
- transformer.write();
- }
-
- private static TripReport calculateTrip(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
-
- Position startTrip = positions.get(startIndex);
- Position endTrip = positions.get(endIndex);
-
- double speedMax = 0;
- for (int i = startIndex; i <= endIndex; i++) {
- double speed = positions.get(i).getSpeed();
- if (speed > speedMax) {
- speedMax = speed;
- }
- }
-
- TripReport trip = new TripReport();
-
- long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime();
- long deviceId = startTrip.getDeviceId();
- trip.setDeviceId(deviceId);
- trip.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
-
- trip.setStartPositionId(startTrip.getId());
- trip.setStartLat(startTrip.getLatitude());
- trip.setStartLon(startTrip.getLongitude());
- trip.setStartTime(startTrip.getFixTime());
- String startAddress = startTrip.getAddress();
- if (startAddress == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- startAddress = Context.getGeocoder().getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null);
- }
- trip.setStartAddress(startAddress);
-
- trip.setEndPositionId(endTrip.getId());
- trip.setEndLat(endTrip.getLatitude());
- trip.setEndLon(endTrip.getLongitude());
- trip.setEndTime(endTrip.getFixTime());
- String endAddress = endTrip.getAddress();
- if (endAddress == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- endAddress = Context.getGeocoder().getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null);
- }
- trip.setEndAddress(endAddress);
-
- trip.setDistance(calculateDistance(startTrip, endTrip, !ignoreOdometer));
- trip.setDuration(tripDuration);
- if (tripDuration > 0) {
- trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration));
- }
- trip.setMaxSpeed(speedMax);
- trip.setSpentFuel(calculateFuel(startTrip, endTrip));
-
- trip.setDriverUniqueId(findDriver(startTrip, endTrip));
- trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
-
- if (!ignoreOdometer
- && startTrip.getDouble(Position.KEY_ODOMETER) != 0
- && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
- trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
- trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
- } else {
- trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
- trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- return trip;
- }
-
- private static StopReport calculateStop(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
-
- Position startStop = positions.get(startIndex);
- Position endStop = positions.get(endIndex);
-
- StopReport stop = new StopReport();
-
- long deviceId = startStop.getDeviceId();
- stop.setDeviceId(deviceId);
- stop.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
-
- stop.setPositionId(startStop.getId());
- stop.setLatitude(startStop.getLatitude());
- stop.setLongitude(startStop.getLongitude());
- stop.setStartTime(startStop.getFixTime());
- String address = startStop.getAddress();
- if (address == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- address = Context.getGeocoder().getAddress(stop.getLatitude(), stop.getLongitude(), null);
- }
- stop.setAddress(address);
-
- stop.setEndTime(endStop.getFixTime());
-
- long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime();
- stop.setDuration(stopDuration);
- stop.setSpentFuel(calculateFuel(startStop, endStop));
-
- if (startStop.getAttributes().containsKey(Position.KEY_HOURS)
- && endStop.getAttributes().containsKey(Position.KEY_HOURS)) {
- stop.setEngineHours(endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS));
- }
-
- if (!ignoreOdometer
- && startStop.getDouble(Position.KEY_ODOMETER) != 0
- && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
- stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
- stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
- } else {
- stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
- stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- return stop;
-
- }
-
- private static <T extends BaseReport> T calculateTripOrStop(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
-
- if (reportClass.equals(TripReport.class)) {
- return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer);
- } else {
- return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer);
- }
- }
-
- private static boolean isMoving(ArrayList<Position> positions, int index, TripsConfig tripsConfig) {
- if (tripsConfig.getMinimalNoDataDuration() > 0) {
- boolean beforeGap = index < positions.size() - 1
- && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime()
- >= tripsConfig.getMinimalNoDataDuration();
- boolean afterGap = index > 0
- && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime()
- >= tripsConfig.getMinimalNoDataDuration();
- if (beforeGap || afterGap) {
- return false;
- }
- }
- if (positions.get(index).getAttributes().containsKey(Position.KEY_MOTION)
- && positions.get(index).getAttributes().get(Position.KEY_MOTION) instanceof Boolean) {
- return positions.get(index).getBoolean(Position.KEY_MOTION);
- } else {
- return positions.get(index).getSpeed() > tripsConfig.getSpeedThreshold();
- }
- }
-
- public static <T extends BaseReport> Collection<T> detectTripsAndStops(
- IdentityManager identityManager, DeviceManager deviceManager,
- Collection<Position> positionCollection,
- TripsConfig tripsConfig, boolean ignoreOdometer, Class<T> reportClass) {
-
- Collection<T> result = new ArrayList<>();
-
- ArrayList<Position> positions = new ArrayList<>(positionCollection);
- if (!positions.isEmpty()) {
- boolean trips = reportClass.equals(TripReport.class);
- MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(isMoving(positions, 0, tripsConfig));
- int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1;
- int startNoEventIndex = -1;
- for (int i = 0; i < positions.size(); i++) {
- Map<Event, Position> event = motionHandler.updateMotionState(deviceState, positions.get(i),
- isMoving(positions, i, tripsConfig));
- if (startEventIndex == -1
- && (trips != deviceState.getMotionState() && deviceState.getMotionPosition() != null
- || trips == deviceState.getMotionState() && event != null)) {
- startEventIndex = i;
- startNoEventIndex = -1;
- } else if (trips != deviceState.getMotionState() && startEventIndex != -1
- && deviceState.getMotionPosition() == null && event == null) {
- startEventIndex = -1;
- }
- if (startNoEventIndex == -1
- && (trips == deviceState.getMotionState() && deviceState.getMotionPosition() != null
- || trips != deviceState.getMotionState() && event != null)) {
- startNoEventIndex = i;
- } else if (startNoEventIndex != -1 && deviceState.getMotionPosition() == null && event == null) {
- startNoEventIndex = -1;
- }
- if (startEventIndex != -1 && startNoEventIndex != -1 && event != null
- && trips != deviceState.getMotionState()) {
- result.add(calculateTripOrStop(positions, startEventIndex, startNoEventIndex,
- ignoreOdometer, reportClass));
- startEventIndex = -1;
- }
- }
- if (startEventIndex != -1 && (startNoEventIndex != -1 || !trips)) {
- result.add(calculateTripOrStop(positions, startEventIndex,
- startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1,
- ignoreOdometer, reportClass));
- }
- }
-
- return result;
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/Route.java b/src/main/java/org/traccar/reports/Route.java
deleted file mode 100644
index 6adb00aae..000000000
--- a/src/main/java/org/traccar/reports/Route.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.model.Position;
-import org.traccar.reports.model.DeviceReport;
-
-public final class Route {
-
- private Route() {
- }
-
- public static Collection<Position> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<Position> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(Context.getDataManager().getPositions(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesRoutes = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Position> positions = Context.getDataManager()
- .getPositions(deviceId, from, to);
- DeviceReport deviceRoutes = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceRoutes.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceRoutes.setGroupName(group.getName());
- }
- }
- deviceRoutes.setObjects(positions);
- devicesRoutes.add(deviceRoutes);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesRoutes);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-}
diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java
new file mode 100644
index 000000000..3ee651619
--- /dev/null
+++ b/src/main/java/org/traccar/reports/RouteReportProvider.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+public class RouteReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public RouteReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ public Collection<Position> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<Position> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(PositionUtil.getPositions(storage, device.getId(), from, to));
+ }
+ return result;
+ }
+
+ public void getExcel(OutputStream outputStream,
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesRoutes = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ DeviceReportSection deviceRoutes = new DeviceReportSection();
+ deviceRoutes.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceRoutes.setGroupName(group.getName());
+ }
+ }
+ deviceRoutes.setObjects(positions);
+ devicesRoutes.add(deviceRoutes);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "route.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesRoutes);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java
deleted file mode 100644
index 2036b0641..000000000
--- a/src/main/java/org/traccar/reports/Stops.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.traccar.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.reports.model.StopReport;
-
-public final class Stops {
-
- private Stops() {
- }
-
- private static Collection<StopReport> detectStops(long deviceId, Date from, Date to) throws SQLException {
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
-
- IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class);
- DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class);
-
- return ReportUtils.detectTripsAndStops(
- identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to),
- Context.getTripsConfig(), ignoreOdometer, StopReport.class);
- }
-
- public static Collection<StopReport> getObjects(
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<StopReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(detectStops(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(
- OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesStops = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<StopReport> stops = detectStops(deviceId, from, to);
- DeviceReport deviceStops = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceStops.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceStops.setGroupName(group.getName());
- }
- }
- deviceStops.setObjects(stops);
- devicesStops.add(deviceStops);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesStops);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java
new file mode 100644
index 000000000..ec3fd2215
--- /dev/null
+++ b/src/main/java/org/traccar/reports/StopsReportProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+public class StopsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public StopsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ private Collection<StopReportItem> detectStops(Device device, Date from, Date to) throws StorageException {
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, StopReportItem.class);
+ }
+
+ public Collection<StopReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<StopReportItem> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(detectStops(device, from, to));
+ }
+ return result;
+ }
+
+ public void getExcel(
+ OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesStops = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<StopReportItem> stops = detectStops(device, from, to);
+ DeviceReportSection deviceStops = new DeviceReportSection();
+ deviceStops.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceStops.setGroupName(group.getName());
+ }
+ }
+ deviceStops.setObjects(stops);
+ devicesStops.add(deviceStops);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "stops.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesStops);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java
index d576ac1e6..9415f3e81 100644
--- a/src/main/java/org/traccar/reports/Summary.java
+++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,31 +16,52 @@
*/
package org.traccar.reports;
+import org.jxls.util.JxlsHelper;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.SummaryReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+
+import javax.inject.Inject;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.sql.SQLException;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
-import org.jxls.util.JxlsHelper;
-import org.traccar.Context;
-import org.traccar.helper.UnitsConverter;
-import org.traccar.model.Position;
-import org.traccar.reports.model.SummaryReport;
+public class SummaryReportProvider {
-public final class Summary {
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final PermissionsService permissionsService;
+ private final Storage storage;
- private Summary() {
+ @Inject
+ public SummaryReportProvider(
+ Config config, ReportUtils reportUtils, PermissionsService permissionsService, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.permissionsService = permissionsService;
+ this.storage = storage;
}
- private static SummaryReport calculateSummaryResult(long deviceId, Collection<Position> positions) {
- SummaryReport result = new SummaryReport();
- result.setDeviceId(deviceId);
- result.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
+ private SummaryReportItem calculateSummaryResult(Device device, Collection<Position> positions) {
+ SummaryReportItem result = new SummaryReportItem();
+ result.setDeviceId(device.getId());
+ result.setDeviceName(device.getName());
if (positions != null && !positions.isEmpty()) {
Position firstPosition = null;
Position previousPosition = null;
@@ -53,14 +74,12 @@ public final class Summary {
result.setMaxSpeed(position.getSpeed());
}
}
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
- result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer));
- result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition));
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ result.setDistance(PositionUtil.calculateDistance(firstPosition, previousPosition, !ignoreOdometer));
+ result.setSpentFuel(reportUtils.calculateFuel(firstPosition, previousPosition));
long durationMilliseconds;
- if (firstPosition.getAttributes().containsKey(Position.KEY_HOURS)
- && previousPosition.getAttributes().containsKey(Position.KEY_HOURS)) {
+ if (firstPosition.hasAttribute(Position.KEY_HOURS) && previousPosition.hasAttribute(Position.KEY_HOURS)) {
durationMilliseconds =
previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS);
result.setEngineHours(durationMilliseconds);
@@ -90,62 +109,67 @@ public final class Summary {
return result;
}
- private static int getDay(long userId, Date date) {
- Calendar calendar = Calendar.getInstance(ReportUtils.getTimezone(userId));
+ private int getDay(long userId, Date date) throws StorageException {
+ Calendar calendar = Calendar.getInstance(UserUtil.getTimezone(
+ permissionsService.getServer(), permissionsService.getUser(userId)));
calendar.setTime(date);
return calendar.get(Calendar.DAY_OF_MONTH);
}
- private static Collection<SummaryReport> calculateSummaryResults(
- long userId, long deviceId, Date from, Date to, boolean daily) throws SQLException {
-
- ArrayList<Position> positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to));
+ private Collection<SummaryReportItem> calculateSummaryResults(
+ long userId, Device device, Date from, Date to, boolean daily) throws StorageException {
- ArrayList<SummaryReport> results = new ArrayList<>();
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ var results = new ArrayList<SummaryReportItem>();
if (daily && !positions.isEmpty()) {
int startIndex = 0;
int startDay = getDay(userId, positions.iterator().next().getFixTime());
for (int i = 0; i < positions.size(); i++) {
int currentDay = getDay(userId, positions.get(i).getFixTime());
if (currentDay != startDay) {
- results.add(calculateSummaryResult(deviceId, positions.subList(startIndex, i)));
+ results.add(calculateSummaryResult(device, positions.subList(startIndex, i)));
startIndex = i;
startDay = currentDay;
}
}
- results.add(calculateSummaryResult(deviceId, positions.subList(startIndex, positions.size())));
+ results.add(calculateSummaryResult(device, positions.subList(startIndex, positions.size())));
} else {
- results.add(calculateSummaryResult(deviceId, positions));
+ results.add(calculateSummaryResult(device, positions));
}
return results;
}
- public static Collection<SummaryReport> getObjects(long userId, Collection<Long> deviceIds,
- Collection<Long> groupIds, Date from, Date to, boolean daily) throws SQLException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<SummaryReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(calculateSummaryResults(userId, deviceId, from, to, daily));
+ public Collection<SummaryReportItem> getObjects(
+ long userId, Collection<Long> deviceIds,
+ Collection<Long> groupIds, Date from, Date to, boolean daily) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<SummaryReportItem> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<SummaryReportItem> deviceResults = calculateSummaryResults(userId, device, from, to, daily);
+ for (SummaryReportItem summaryReport : deviceResults) {
+ if (summaryReport.getStartTime() != null && summaryReport.getEndTime() != null) {
+ result.add(summaryReport);
+ }
+ }
}
return result;
}
- public static void getExcel(OutputStream outputStream,
+ public void getExcel(OutputStream outputStream,
long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to, boolean daily) throws SQLException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- Collection<SummaryReport> summaries = getObjects(userId, deviceIds, groupIds, from, to, daily);
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("summaries", summaries);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
+ Date from, Date to, boolean daily) throws StorageException, IOException {
+ Collection<SummaryReportItem> summaries = getObjects(userId, deviceIds, groupIds, from, to, daily);
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "summary.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("summaries", summaries);
+ context.putVar("from", from);
+ context.putVar("to", to);
JxlsHelper.getInstance().setUseFastFormulaProcessor(false)
- .processTemplate(inputStream, outputStream, jxlsContext);
+ .processTemplate(inputStream, outputStream, context);
}
}
}
diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java
deleted file mode 100644
index 7c0cd6921..000000000
--- a/src/main/java/org/traccar/reports/Trips.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.reports.model.TripReport;
-
-public final class Trips {
-
- private Trips() {
- }
-
- private static Collection<TripReport> detectTrips(long deviceId, Date from, Date to) throws SQLException {
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
-
- IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class);
- DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class);
-
- return ReportUtils.detectTripsAndStops(
- identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to),
- Context.getTripsConfig(), ignoreOdometer, TripReport.class);
- }
-
- public static Collection<TripReport> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<TripReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(detectTrips(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesTrips = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<TripReport> trips = detectTrips(deviceId, from, to);
- DeviceReport deviceTrips = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceTrips.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceTrips.setGroupName(group.getName());
- }
- }
- deviceTrips.setObjects(trips);
- devicesTrips.add(deviceTrips);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesTrips);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java
new file mode 100644
index 000000000..265811354
--- /dev/null
+++ b/src/main/java/org/traccar/reports/TripsReportProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+public class TripsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public TripsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ private Collection<TripReportItem> detectTrips(Device device, Date from, Date to) throws StorageException {
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, TripReportItem.class);
+ }
+
+ public Collection<TripReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<TripReportItem> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(detectTrips(device, from, to));
+ }
+ return result;
+ }
+
+ public void getExcel(OutputStream outputStream,
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesTrips = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<TripReportItem> trips = detectTrips(device, from, to);
+ DeviceReportSection deviceTrips = new DeviceReportSection();
+ deviceTrips.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceTrips.setGroupName(group.getName());
+ }
+ }
+ deviceTrips.setObjects(trips);
+ devicesTrips.add(deviceTrips);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "trips.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesTrips);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java
new file mode 100644
index 000000000..a7c420095
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ReportUtils.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports.common;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.tools.generic.DateTool;
+import org.apache.velocity.tools.generic.NumberTool;
+import org.jxls.area.Area;
+import org.jxls.builder.xls.XlsCommentAreaBuilder;
+import org.jxls.common.CellRef;
+import org.jxls.formula.StandardFormulaProcessor;
+import org.jxls.transform.Transformer;
+import org.jxls.transform.poi.PoiTransformer;
+import org.jxls.util.TransformerFactory;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.geocoder.Geocoder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Driver;
+import org.traccar.model.Group;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.reports.model.BaseReportItem;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Singleton
+public class ReportUtils {
+
+ private final Config config;
+ private final Storage storage;
+ private final PermissionsService permissionsService;
+ private final TripsConfig tripsConfig;
+ private final VelocityEngine velocityEngine;
+ private final Geocoder geocoder;
+
+ @Inject
+ public ReportUtils(
+ Config config, Storage storage, PermissionsService permissionsService,
+ TripsConfig tripsConfig, VelocityEngine velocityEngine, @Nullable Geocoder geocoder) {
+ this.config = config;
+ this.storage = storage;
+ this.permissionsService = permissionsService;
+ this.tripsConfig = tripsConfig;
+ this.velocityEngine = velocityEngine;
+ this.geocoder = geocoder;
+ }
+
+ public <T extends BaseModel> T getObject(
+ long userId, Class<T> clazz, long objectId) throws StorageException, SecurityException {
+ return storage.getObject(clazz, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("id", objectId),
+ new Condition.Permission(User.class, userId, clazz))));
+ }
+
+ public void checkPeriodLimit(Date from, Date to) {
+ long limit = config.getLong(Keys.REPORT_PERIOD_LIMIT) * 1000;
+ if (limit > 0 && to.getTime() - from.getTime() > limit) {
+ throw new IllegalArgumentException("Time period exceeds the limit");
+ }
+ }
+
+ public Collection<Device> getAccessibleDevices(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds) throws StorageException {
+
+ var devices = storage.getObjects(Device.class, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, userId, Device.class)));
+ var deviceById = devices.stream()
+ .collect(Collectors.toUnmodifiableMap(Device::getId, x -> x));
+ var devicesByGroup = devices.stream()
+ .filter(x -> x.getGroupId() > 0)
+ .collect(Collectors.groupingBy(Device::getGroupId));
+
+ var groups = storage.getObjects(Group.class, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, userId, Group.class)));
+ var groupsByGroup = groups.stream()
+ .filter(x -> x.getGroupId() > 0)
+ .collect(Collectors.groupingBy(Group::getGroupId));
+
+ var results = deviceIds.stream()
+ .map(deviceById::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+
+ var groupQueue = new LinkedList<>(groupIds);
+ while (!groupQueue.isEmpty()) {
+ long groupId = groupQueue.pop();
+ results.addAll(devicesByGroup.getOrDefault(groupId, Collections.emptyList()));
+ groupQueue.addAll(groupsByGroup.getOrDefault(groupId, Collections.emptyList())
+ .stream().map(Group::getId).collect(Collectors.toUnmodifiableList()));
+ }
+
+ return results;
+ }
+
+ public double calculateFuel(Position firstPosition, Position lastPosition) {
+
+ if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null
+ && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) {
+
+ BigDecimal value = BigDecimal.valueOf(firstPosition.getDouble(Position.KEY_FUEL_LEVEL)
+ - lastPosition.getDouble(Position.KEY_FUEL_LEVEL));
+ return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue();
+ }
+ return 0;
+ }
+
+ public String findDriver(Position firstPosition, Position lastPosition) {
+ if (firstPosition.hasAttribute(Position.KEY_DRIVER_UNIQUE_ID)) {
+ return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
+ } else if (lastPosition.hasAttribute(Position.KEY_DRIVER_UNIQUE_ID)) {
+ return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
+ }
+ return null;
+ }
+
+ public String findDriverName(String driverUniqueId) throws StorageException {
+ if (driverUniqueId != null) {
+ Driver driver = storage.getObject(Driver.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("uniqueId", driverUniqueId)));
+ if (driver != null) {
+ return driver.getName();
+ }
+ }
+ return null;
+ }
+
+ public org.jxls.common.Context initializeContext(long userId) throws StorageException {
+ var server = permissionsService.getServer();
+ var user = permissionsService.getUser(userId);
+ var context = PoiTransformer.createInitialContext();
+ context.putVar("distanceUnit", UserUtil.getDistanceUnit(server, user));
+ context.putVar("speedUnit", UserUtil.getSpeedUnit(server, user));
+ context.putVar("volumeUnit", UserUtil.getVolumeUnit(server, user));
+ context.putVar("webUrl", velocityEngine.getProperty("web.url"));
+ context.putVar("dateTool", new DateTool());
+ context.putVar("numberTool", new NumberTool());
+ context.putVar("timezone", UserUtil.getTimezone(server, user));
+ context.putVar("locale", Locale.getDefault());
+ context.putVar("bracketsRegex", "[\\{\\}\"]");
+ return context;
+ }
+
+ public void processTemplateWithSheets(
+ InputStream templateStream, OutputStream targetStream, org.jxls.common.Context context) throws IOException {
+
+ Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
+ List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
+ for (Area xlsArea : xlsAreas) {
+ xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), context);
+ xlsArea.setFormulaProcessor(new StandardFormulaProcessor());
+ xlsArea.processFormulas();
+ }
+ transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName());
+ transformer.write();
+ }
+
+ private TripReportItem calculateTrip(
+ Device device, ArrayList<Position> positions, int startIndex, int endIndex,
+ boolean ignoreOdometer) throws StorageException {
+
+ Position startTrip = positions.get(startIndex);
+ Position endTrip = positions.get(endIndex);
+
+ double speedMax = 0;
+ for (int i = startIndex; i <= endIndex; i++) {
+ double speed = positions.get(i).getSpeed();
+ if (speed > speedMax) {
+ speedMax = speed;
+ }
+ }
+
+ TripReportItem trip = new TripReportItem();
+
+ long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime();
+ long deviceId = startTrip.getDeviceId();
+ trip.setDeviceId(deviceId);
+ trip.setDeviceName(device.getName());
+
+ trip.setStartPositionId(startTrip.getId());
+ trip.setStartLat(startTrip.getLatitude());
+ trip.setStartLon(startTrip.getLongitude());
+ trip.setStartTime(startTrip.getFixTime());
+ String startAddress = startTrip.getAddress();
+ if (startAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ startAddress = geocoder.getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null);
+ }
+ trip.setStartAddress(startAddress);
+
+ trip.setEndPositionId(endTrip.getId());
+ trip.setEndLat(endTrip.getLatitude());
+ trip.setEndLon(endTrip.getLongitude());
+ trip.setEndTime(endTrip.getFixTime());
+ String endAddress = endTrip.getAddress();
+ if (endAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ endAddress = geocoder.getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null);
+ }
+ trip.setEndAddress(endAddress);
+
+ trip.setDistance(PositionUtil.calculateDistance(startTrip, endTrip, !ignoreOdometer));
+ trip.setDuration(tripDuration);
+ if (tripDuration > 0) {
+ trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration));
+ }
+ trip.setMaxSpeed(speedMax);
+ trip.setSpentFuel(calculateFuel(startTrip, endTrip));
+
+ trip.setDriverUniqueId(findDriver(startTrip, endTrip));
+ trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
+
+ if (!ignoreOdometer
+ && startTrip.getDouble(Position.KEY_ODOMETER) != 0
+ && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
+ } else {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
+ return trip;
+ }
+
+ private StopReportItem calculateStop(
+ Device device, ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
+ Position startStop = positions.get(startIndex);
+ Position endStop = positions.get(endIndex);
+
+ StopReportItem stop = new StopReportItem();
+
+ long deviceId = startStop.getDeviceId();
+ stop.setDeviceId(deviceId);
+ stop.setDeviceName(device.getName());
+
+ stop.setPositionId(startStop.getId());
+ stop.setLatitude(startStop.getLatitude());
+ stop.setLongitude(startStop.getLongitude());
+ stop.setStartTime(startStop.getFixTime());
+ String address = startStop.getAddress();
+ if (address == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ address = geocoder.getAddress(stop.getLatitude(), stop.getLongitude(), null);
+ }
+ stop.setAddress(address);
+
+ stop.setEndTime(endStop.getFixTime());
+
+ long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime();
+ stop.setDuration(stopDuration);
+ stop.setSpentFuel(calculateFuel(startStop, endStop));
+
+ if (startStop.hasAttribute(Position.KEY_HOURS) && endStop.hasAttribute(Position.KEY_HOURS)) {
+ stop.setEngineHours(endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS));
+ }
+
+ if (!ignoreOdometer
+ && startStop.getDouble(Position.KEY_ODOMETER) != 0
+ && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
+ } else {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
+ return stop;
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T extends BaseReportItem> T calculateTripOrStop(
+ Device device, ArrayList<Position> positions, int startIndex, int endIndex,
+ boolean ignoreOdometer, Class<T> reportClass) throws StorageException {
+
+ if (reportClass.equals(TripReportItem.class)) {
+ return (T) calculateTrip(device, positions, startIndex, endIndex, ignoreOdometer);
+ } else {
+ return (T) calculateStop(device, positions, startIndex, endIndex, ignoreOdometer);
+ }
+ }
+
+ private boolean isMoving(ArrayList<Position> positions, int index, TripsConfig tripsConfig) {
+ if (tripsConfig.getMinimalNoDataDuration() > 0) {
+ boolean beforeGap = index < positions.size() - 1
+ && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime()
+ >= tripsConfig.getMinimalNoDataDuration();
+ boolean afterGap = index > 0
+ && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime()
+ >= tripsConfig.getMinimalNoDataDuration();
+ if (beforeGap || afterGap) {
+ return false;
+ }
+ }
+ return positions.get(index).getBoolean(Position.KEY_MOTION);
+ }
+
+ public <T extends BaseReportItem> Collection<T> detectTripsAndStops(
+ Device device, Collection<Position> positionCollection, boolean ignoreOdometer,
+ Class<T> reportClass) throws StorageException {
+
+ Collection<T> result = new ArrayList<>();
+
+ ArrayList<Position> positions = new ArrayList<>(positionCollection);
+ if (!positions.isEmpty()) {
+ boolean trips = reportClass.equals(TripReportItem.class);
+
+ MotionState motionState = new MotionState();
+ boolean initialValue = isMoving(positions, 0, tripsConfig);
+ motionState.setMotionStreak(initialValue);
+ motionState.setMotionState(initialValue);
+
+ boolean detected = trips == motionState.getMotionState();
+ int startEventIndex = detected ? 0 : -1;
+ int startNoEventIndex = -1;
+ for (int i = 0; i < positions.size(); i++) {
+ boolean motion = isMoving(positions, i, tripsConfig);
+ if (motionState.getMotionState() != motion) {
+ if (motion == trips) {
+ startEventIndex = detected ? startEventIndex : i;
+ startNoEventIndex = -1;
+ } else {
+ startNoEventIndex = i;
+ }
+ }
+
+ MotionProcessor.updateState(motionState, positions.get(i), motion, tripsConfig);
+ if (motionState.getEvent() != null) {
+ if (motion == trips) {
+ detected = true;
+ startNoEventIndex = -1;
+ } else if (startEventIndex >= 0 && startNoEventIndex >= 0) {
+ result.add(calculateTripOrStop(
+ device, positions, startEventIndex, startNoEventIndex, ignoreOdometer, reportClass));
+ detected = false;
+ startEventIndex = -1;
+ startNoEventIndex = -1;
+ }
+ }
+ }
+ if (startEventIndex >= 0 && startEventIndex < positions.size() - 1) {
+ int endIndex = startNoEventIndex >= 0 ? startNoEventIndex : positions.size() - 1;
+ result.add(calculateTripOrStop(
+ device, positions, startEventIndex, endIndex, ignoreOdometer, reportClass));
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/model/TripsConfig.java b/src/main/java/org/traccar/reports/common/TripsConfig.java
index 0f0c615d3..52db97b74 100644
--- a/src/main/java/org/traccar/reports/model/TripsConfig.java
+++ b/src/main/java/org/traccar/reports/common/TripsConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,14 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.reports.model;
+package org.traccar.reports.common;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
public class TripsConfig {
- public TripsConfig() {
+ @Inject
+ public TripsConfig(Config config) {
+ this(
+ config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE),
+ config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION) * 1000,
+ config.getLong(Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000,
+ config.getLong(Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000,
+ config.getBoolean(Keys.REPORT_TRIP_USE_IGNITION),
+ config.getBoolean(Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS),
+ config.getDouble(Keys.EVENT_MOTION_SPEED_THRESHOLD));
}
- public TripsConfig(double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
+ public TripsConfig(
+ double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) {
this.minimalTripDistance = minimalTripDistance;
this.minimalTripDuration = minimalTripDuration;
@@ -32,74 +49,46 @@ public class TripsConfig {
this.speedThreshold = speedThreshold;
}
- private double minimalTripDistance;
+ private final double minimalTripDistance;
public double getMinimalTripDistance() {
return minimalTripDistance;
}
- public void setMinimalTripDistance(double minimalTripDistance) {
- this.minimalTripDistance = minimalTripDistance;
- }
-
- private long minimalTripDuration;
+ private final long minimalTripDuration;
public long getMinimalTripDuration() {
return minimalTripDuration;
}
- public void setMinimalTripDuration(long minimalTripDuration) {
- this.minimalTripDuration = minimalTripDuration;
- }
-
- private long minimalParkingDuration;
+ private final long minimalParkingDuration;
public long getMinimalParkingDuration() {
return minimalParkingDuration;
}
- public void setMinimalParkingDuration(long minimalParkingDuration) {
- this.minimalParkingDuration = minimalParkingDuration;
- }
-
- private long minimalNoDataDuration;
+ private final long minimalNoDataDuration;
public long getMinimalNoDataDuration() {
return minimalNoDataDuration;
}
- public void setMinimalNoDataDuration(long minimalNoDataDuration) {
- this.minimalNoDataDuration = minimalNoDataDuration;
- }
-
- private boolean useIgnition;
+ private final boolean useIgnition;
public boolean getUseIgnition() {
return useIgnition;
}
- public void setUseIgnition(boolean useIgnition) {
- this.useIgnition = useIgnition;
- }
-
- private boolean processInvalidPositions;
+ private final boolean processInvalidPositions;
public boolean getProcessInvalidPositions() {
return processInvalidPositions;
}
- public void setProcessInvalidPositions(boolean processInvalidPositions) {
- this.processInvalidPositions = processInvalidPositions;
- }
-
- private double speedThreshold;
+ private final double speedThreshold;
public double getSpeedThreshold() {
return speedThreshold;
}
- public void setSpeedThreshold(double speedThreshold) {
- this.speedThreshold = speedThreshold;
- }
-
}
diff --git a/src/main/java/org/traccar/reports/model/BaseReport.java b/src/main/java/org/traccar/reports/model/BaseReportItem.java
index 928c0557d..6e270dfe3 100644
--- a/src/main/java/org/traccar/reports/model/BaseReport.java
+++ b/src/main/java/org/traccar/reports/model/BaseReportItem.java
@@ -18,7 +18,7 @@ package org.traccar.reports.model;
import java.util.Date;
-public class BaseReport {
+public class BaseReportItem {
private long deviceId;
diff --git a/src/main/java/org/traccar/reports/model/DeviceReport.java b/src/main/java/org/traccar/reports/model/DeviceReportSection.java
index 932753d15..ffc4d774f 100644
--- a/src/main/java/org/traccar/reports/model/DeviceReport.java
+++ b/src/main/java/org/traccar/reports/model/DeviceReportSection.java
@@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-public class DeviceReport {
+public class DeviceReportSection {
private String deviceName;
diff --git a/src/main/java/org/traccar/reports/model/StopReport.java b/src/main/java/org/traccar/reports/model/StopReportItem.java
index e20f2c503..3c35bdc21 100644
--- a/src/main/java/org/traccar/reports/model/StopReport.java
+++ b/src/main/java/org/traccar/reports/model/StopReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class StopReport extends BaseReport {
+public class StopReportItem extends BaseReportItem {
private long positionId;
diff --git a/src/main/java/org/traccar/reports/model/SummaryReport.java b/src/main/java/org/traccar/reports/model/SummaryReportItem.java
index 886f8b9e2..44a15cf1d 100644
--- a/src/main/java/org/traccar/reports/model/SummaryReport.java
+++ b/src/main/java/org/traccar/reports/model/SummaryReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class SummaryReport extends BaseReport {
+public class SummaryReportItem extends BaseReportItem {
private long engineHours; // milliseconds
diff --git a/src/main/java/org/traccar/reports/model/TripReport.java b/src/main/java/org/traccar/reports/model/TripReportItem.java
index 151c34bd5..332a34cca 100644
--- a/src/main/java/org/traccar/reports/model/TripReport.java
+++ b/src/main/java/org/traccar/reports/model/TripReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class TripReport extends BaseReport {
+public class TripReportItem extends BaseReportItem {
private long startPositionId;