diff --git a/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle.json b/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle.json index 525472c..497cff1 100755 --- a/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle.json +++ b/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle.json @@ -19,6 +19,7 @@ { "fieldname": "tracker", "fieldtype": "Link", + "in_list_view": 1, "label": "Tracker", "options": "Tracker" }, @@ -58,7 +59,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2024-04-11 15:29:47.121435", + "modified": "2024-04-17 12:10:38.738798", "modified_by": "Administrator", "module": "Fleet Management", "name": "Fleet Vehicle", diff --git a/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle_dashboard.py b/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle_dashboard.py new file mode 100644 index 0000000..cccce3b --- /dev/null +++ b/fleet_management/fleet_management/doctype/fleet_vehicle/fleet_vehicle_dashboard.py @@ -0,0 +1,14 @@ +from frappe import _ + +def get_data(): + return { + 'heatmap': False, + 'heatmap_message': _('Based on routes (trips) of linked Vehicle.'), + 'fieldname': 'fleet_vehicle', + 'transactions': [ + { + 'label': _('Available Routes'), + 'items': ['Trip'] + } + ] + } diff --git a/fleet_management/fleet_management/doctype/traccar_settings/traccar_settings.json b/fleet_management/fleet_management/doctype/traccar_settings/traccar_settings.json index b2eb83d..1849f33 100755 --- a/fleet_management/fleet_management/doctype/traccar_settings/traccar_settings.json +++ b/fleet_management/fleet_management/doctype/traccar_settings/traccar_settings.json @@ -8,8 +8,7 @@ "engine": "InnoDB", "field_order": [ "traccar_server", - "traccar_username", - "traccar_password" + "traccar_token" ], "fields": [ { @@ -18,20 +17,17 @@ "label": "URL Server" }, { - "fieldname": "traccar_username", - "fieldtype": "Data", - "label": "Username" - }, - { - "fieldname": "traccar_password", + "fieldname": "traccar_token", "fieldtype": "Password", - "label": "Password" + "in_list_view": 1, + "label": "Token", + "reqd": 1 } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2024-04-11 16:50:20.436522", + "modified": "2024-04-16 11:46:08.967177", "modified_by": "Administrator", "module": "Fleet Management", "name": "Traccar Settings", diff --git a/fleet_management/fleet_management/doctype/tracker/tracker.json b/fleet_management/fleet_management/doctype/tracker/tracker.json index 7e021ca..8aba04f 100755 --- a/fleet_management/fleet_management/doctype/tracker/tracker.json +++ b/fleet_management/fleet_management/doctype/tracker/tracker.json @@ -18,8 +18,7 @@ "model", "contact", "category", - "disabled", - "button_trips" + "disabled" ], "fields": [ { @@ -86,16 +85,11 @@ "fieldname": "disabled", "fieldtype": "Data", "label": "Disabled" - }, - { - "fieldname": "button_trips", - "fieldtype": "Button", - "label": "View Trips" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2024-04-11 12:52:37.199851", + "modified": "2024-04-17 12:10:01.016561", "modified_by": "Administrator", "module": "Fleet Management", "name": "Tracker", diff --git a/fleet_management/fleet_management/doctype/trip/trip.json b/fleet_management/fleet_management/doctype/trip/trip.json index 61fbdeb..a9ec740 100755 --- a/fleet_management/fleet_management/doctype/trip/trip.json +++ b/fleet_management/fleet_management/doctype/trip/trip.json @@ -16,12 +16,18 @@ "average_speed", "max_speed", "spent_fuel", + "start_position_id", + "start_lat", + "start_lon", + "end_lat", + "end_lon", "start_address", "end_address", "duration", "driver_unique_id", "fleet_vehicle", - "tracker" + "tracker", + "unique_id" ], "fields": [ { @@ -105,11 +111,42 @@ "fieldtype": "Link", "label": "Tracker", "options": "Tracker" + }, + { + "fieldname": "unique_id", + "fieldtype": "Data", + "hidden": 1, + "label": "unique_id" + }, + { + "fieldname": "start_position_id", + "fieldtype": "Data", + "label": "Start Position ID" + }, + { + "fieldname": "start_lat", + "fieldtype": "Data", + "label": "Start Latitude" + }, + { + "fieldname": "start_lon", + "fieldtype": "Data", + "label": "Start Longitude" + }, + { + "fieldname": "end_lat", + "fieldtype": "Data", + "label": "End Latitude" + }, + { + "fieldname": "end_lon", + "fieldtype": "Data", + "label": "End Longitude" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2024-04-12 12:31:26.524755", + "modified": "2024-04-14 17:20:36.937514", "modified_by": "Administrator", "module": "Fleet Management", "name": "Trip", diff --git a/fleet_management/fleet_management/workspace/fleet_management/fleet_management.json b/fleet_management/fleet_management/workspace/fleet_management/fleet_management.json new file mode 100644 index 0000000..96796e1 --- /dev/null +++ b/fleet_management/fleet_management/workspace/fleet_management/fleet_management.json @@ -0,0 +1,63 @@ +{ + "charts": [], + "content": "[{\"id\":\"PROwwE8CMR\",\"type\":\"header\",\"data\":{\"text\":\"Fleet Management\",\"col\":12}},{\"id\":\"zW5zgDOYYt\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"Traccar Button\",\"col\":12}},{\"id\":\"jqsG9hjyOU\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Tracker Devices\",\"col\":4}},{\"id\":\"0ABxSuv34v\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trips\",\"col\":3}},{\"id\":\"0s-UKXtLZr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Traccar Server Settings\",\"col\":5}},{\"id\":\"dHKqoHT70w\",\"type\":\"quick_list\",\"data\":{\"quick_list_name\":\"Fleet Vehicle\",\"col\":11}}]", + "creation": "2024-04-14 17:22:37.053886", + "custom_blocks": [ + { + "custom_block_name": "Traccar Button", + "label": "Traccar Button" + } + ], + "docstatus": 0, + "doctype": "Workspace", + "for_user": "", + "hide_custom": 0, + "icon": "map", + "idx": 1, + "is_hidden": 0, + "label": "Fleet Management", + "links": [], + "modified": "2024-04-16 12:06:30.954320", + "modified_by": "Administrator", + "module": "Fleet Management", + "name": "Fleet Management", + "number_cards": [], + "owner": "Administrator", + "parent_page": "", + "public": 1, + "quick_lists": [ + { + "document_type": "Fleet Vehicle", + "label": "Fleet Vehicle", + "quick_list_filter": "[]" + } + ], + "roles": [], + "sequence_id": 4.1, + "shortcuts": [ + { + "color": "Grey", + "doc_view": "List", + "label": "Tracker Devices", + "link_to": "Tracker", + "stats_filter": "[]", + "type": "DocType" + }, + { + "color": "Grey", + "doc_view": "List", + "label": "Trips", + "link_to": "Trip", + "stats_filter": "[]", + "type": "DocType" + }, + { + "color": "Grey", + "doc_view": "List", + "label": "Traccar Server Settings", + "link_to": "Traccar Settings", + "type": "DocType" + } + ], + "title": "Fleet Management" +} \ No newline at end of file diff --git a/fleet_management/hooks.py b/fleet_management/hooks.py index 0ee443f..e57c27a 100755 --- a/fleet_management/hooks.py +++ b/fleet_management/hooks.py @@ -218,3 +218,13 @@ app_license = "GPLv3" # hooks.py +scheduler_events = { + #"all": [ + # "fleet_management.tasks.get_trips_for_device" + #], + "cron": { + "*/15 * * * *": [ + "fleet_management.tasks.get_trips_for_device" + ] + } +} diff --git a/fleet_management/tasks.py b/fleet_management/tasks.py new file mode 100755 index 0000000..1d50db6 --- /dev/null +++ b/fleet_management/tasks.py @@ -0,0 +1,107 @@ +from datetime import datetime, timedelta +from zoneinfo import ZoneInfo +from frappe.utils.password import get_decrypted_password +from frappe.utils import add_to_date, get_datetime +import frappe +import requests + +def traccar_auth(ts): + """authenticates on traccar server and returns cookies""" + response = requests.get( + f"{ts.traccar_server}/api/session", + params = { + 'token': get_decrypted_password('Traccar Settings', ts.name, 'traccar_token') + } + ) + + if response.status_code == 200: + return response.cookies + else: + frappe.throw(f"Authentication failed: {response.status_code}: {response.reason}
Dict ts: {ts.as_dict()}") + +def get_devices(): + ts = frappe.get_doc('Traccar Settings') + + try: + devices_response = requests.get( + f"{ts.traccar_server}/api/devices", + cookies=traccar_auth(ts) + ) + devices_response.raise_for_status() + + except requests.HTTPError as e: + frappe.throw(f"HTTP error occurred: {e}") + except Exception as e: + frappe.throw(f"Error fetching devices: {e}") + + return devices_response.json() + + +@frappe.whitelist() +def get_trips_for_device(): + ts = frappe.get_doc('Traccar Settings') + frappe.logger().info("Starting import Trips from Traccar server ...") + for dev in get_devices(): + try: + trips_response = requests.get( + f"{ts.traccar_server}/api/reports/trips", + cookies=traccar_auth(ts), + params={ + 'deviceId': dev['id'], + 'from': (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%dT23:00:00.000Z'), + 'to': datetime.now().strftime('%Y-%m-%dT22:59:59.999Z') + } + ) + trips_response.raise_for_status() + except requests.HTTPError as e: + frappe.throw(f"HTTP error occurred: {e}") + except Exception as e: + frappe.throw(f"Error fetching trips: {e}") + + #if len(trips_response.json()) > 0: + # for debug in trips_response.json(): + # print(f"Distance: {debug['distance']} | Average Speed: {debug['averageSpeed']}") + + for trip in trips_response.json(): + # Assuming 'device_id' and 'startTime' can uniquely identify a trip + unique_id = f"{trip['deviceId']}-{trip['startTime']}" + + # Check if the document already exists + existing_trip = frappe.db.exists('Trip', {'unique_id': unique_id}) + + if existing_trip: + trip_doc = frappe.get_doc('Trip', existing_trip) + else: + trip_doc = frappe.new_doc('Trip') + trip_doc.unique_id = unique_id # Atribui o identificador Ășnico + + # Atualiza ou define os campos + trip_doc.device_id = trip['deviceId'] + trip_doc.start = datetime.fromisoformat(trip['startTime']).replace( + tzinfo=ZoneInfo("UTC")).astimezone(ZoneInfo("Europe/Berlin") + ).strftime('%Y-%m-%d %H:%M:%S') + trip_doc.end = datetime.fromisoformat(trip['endTime']).replace( + tzinfo=ZoneInfo("UTC")).astimezone(ZoneInfo("Europe/Berlin") + ).strftime('%Y-%m-%d %H:%M:%S') + trip_doc.distance = trip['distance'] + trip_doc.average_speed = trip['averageSpeed'] + trip_doc.max_speed = trip['maxSpeed'] + trip_doc.spent_fuel = trip['spentFuel'] + trip_doc.start_position_id = trip['startPositionId'] + trip_doc.end_position_id = trip['endPositionId'] + trip_doc.start_lat = trip['startLat'] + trip_doc.start_lon = trip['startLon'] + trip_doc.end_lat = trip['endLat'] + trip_doc.end_lon = trip['endLon'] + trip_doc.start_address = trip['startAddress'] + trip_doc.end_address = trip['endAddress'] + trip_doc.duration = trip['duration'] + trip_doc.driver_unique_id = trip['driverUniqueId'] + trip_doc.tracker = frappe.get_value('Tracker', {'portal_id': trip['deviceId']}, 'portal_name') + trip_doc.fleet_vehicle = frappe.get_value('Fleet Vehicle', {'tracker': trip_doc.tracker}, 'name') + + trip_doc.save(ignore_permissions=True) + + frappe.db.commit() + + frappe.logger().info("End of task of import") diff --git a/fleet_management/traccar_api.py b/fleet_management/traccar_api.py index fe96f36..249eec2 100755 --- a/fleet_management/traccar_api.py +++ b/fleet_management/traccar_api.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from zoneinfo import ZoneInfo from frappe.utils.password import get_decrypted_password import frappe import requests @@ -6,11 +7,10 @@ import requests def traccar_auth(ts): """authenticates on traccar server and returns cookies""" - response = requests.post( + response = requests.get( f"{ts.traccar_server}/api/session", - data = { - 'email': ts.traccar_username, - 'password': get_decrypted_password('Traccar Settings', ts.name, 'traccar_password') + params = { + 'token': get_decrypted_password('Traccar Settings', ts.name, 'traccar_token') } ) @@ -123,11 +123,14 @@ def get_trips_for_device(device_id, start=None, end=None): def getroutes(name, start=None, end=None): ts = frappe.get_doc('Traccar Settings') device_id = frappe.get_value('Trip', {'name': name}, 'device_id') - startdate = datetime.strptime(start, "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S.000+00:00") - enddate = datetime.strptime(end, "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S.000+00:00") - - print(f"startdate: {startdate}") - print(f"enddate: {enddate}") + startdate = datetime.strptime(start, "%Y-%m-%d %H:%M:%S")\ + .replace(tzinfo=ZoneInfo("Europe/Berlin"))\ + .astimezone(ZoneInfo("UTC"))\ + .strftime("%Y-%m-%dT%H:%M:%S.000+00:00") + enddate = datetime.strptime(end, "%Y-%m-%d %H:%M:%S")\ + .replace(tzinfo=ZoneInfo("Europe/Berlin"))\ + .astimezone(ZoneInfo("UTC"))\ + .strftime("%Y-%m-%dT%H:%M:%S.000+00:00") # get route by filter from traccar server try: @@ -147,3 +150,9 @@ def getroutes(name, start=None, end=None): return route_response.json() +@frappe.whitelist() +def get_traccar_url(): + ts = frappe.get_doc('Traccar Settings') + + return(f"{ts.traccar_server}/?token=" + get_decrypted_password('Traccar Settings', ts.name, 'traccar_token')) +