From 67495fadfbdd12a110de47472381df5e78b1abd0 Mon Sep 17 00:00:00 2001 From: MariamMabele Date: Fri, 18 Sep 2026 08:46:56 +0300 Subject: [PATCH 1/3] feat(fleet-ms): add fleet analytics reports and remade workspace layout --- vsd_fleet_ms/patches.txt | 1 + .../workspace}/__init__.py | 0 .../workspace/rename_fleet_ms_workspace.py | 32 + .../vsd_fleet_ms/number_card/__init__.py | 0 .../available_truck/available_truck.json | 22 + .../cargo_registrations.json | 22 + .../completed_trips/completed_trips.json | 22 + .../fuel_requests/fuel_requests.json | 22 + .../number_card/manifest/manifest.json | 22 + .../ongoing_trips/ongoing_trips.json | 22 + .../overdue_sales_invoices.json | 23 + .../requested_payments_in_trip.json | 22 + .../number_card/total_trips/total_trips.json | 22 + .../total_trucks/total_trucks.json | 22 + .../truck_on_trip/truck_on_trip.json | 22 + .../unpaid_sales_invoices.json | 22 + .../report/completed_trips_report/__init__.py | 0 .../completed_trips_report.js | 26 + .../completed_trips_report.json | 30 + .../completed_trips_report.py | 58 ++ .../report/driver_activity_report/__init__.py | 0 .../driver_activity_report.js | 14 + .../driver_activity_report.json | 30 + .../driver_activity_report.py | 57 ++ .../report/fixed_expenses_report/__init__.py | 0 .../fixed_expenses_report.js | 26 + .../fixed_expenses_report.json | 30 + .../fixed_expenses_report.py | 60 ++ .../report/fleet_availability/__init__.py | 0 .../fleet_availability/fleet_availability.js | 7 + .../fleet_availability.json | 30 + .../fleet_availability/fleet_availability.py | 30 + .../fuel_consumption_report/__init__.py | 0 .../fuel_consumption_report.js | 26 + .../fuel_consumption_report.json | 30 + .../fuel_consumption_report.py | 64 ++ .../fuel_expense_by_trip.js | 9 - .../report/ongoing_trips_report/__init__.py | 0 .../ongoing_trips_report.js | 24 + .../ongoing_trips_report.json | 30 + .../ongoing_trips_report.py | 58 ++ .../overdue_invoices_report/__init__.py | 0 .../overdue_invoices_report.js | 14 + .../overdue_invoices_report.json | 30 + .../overdue_invoices_report.py | 60 ++ .../pending_fuel_requests_report/__init__.py | 0 .../pending_fuel_requests_report.js | 30 + .../pending_fuel_requests_report.json | 30 + .../pending_fuel_requests_report.py | 104 +++ .../__init__.py | 0 .../pending_requested_payments_report.js | 36 + .../pending_requested_payments_report.json | 30 + .../pending_requested_payments_report.py | 87 +++ .../report/trip_fuel_cost/__init__.py | 0 .../report/trip_fuel_cost/trip_fuel_cost.js | 26 + .../trip_fuel_cost.json} | 8 +- .../trip_fuel_cost.py} | 82 +-- .../__init__.py | 0 .../trip_profit_and_loss_statement.js | 26 + .../trip_profit_and_loss_statement.json | 30 + .../trip_profit_and_loss_statement.py | 131 ++++ .../report/trip_revenue_report/__init__.py | 0 .../trip_revenue_report.js | 20 + .../trip_revenue_report.json | 30 + .../trip_revenue_report.py | 64 ++ .../report/trip_turnaround_time/__init__.py | 0 .../trip_turnaround_time.js | 26 + .../trip_turnaround_time.json | 30 + .../trip_turnaround_time.py | 60 ++ .../report/unpaid_invoices_report/__init__.py | 0 .../unpaid_invoices_report.js | 14 + .../unpaid_invoices_report.json | 30 + .../unpaid_invoices_report.py | 56 ++ .../report/vehicle_utilization/__init__.py | 0 .../vehicle_utilization.js | 14 + .../vehicle_utilization.json | 30 + .../vehicle_utilization.py | 57 ++ .../fleet_management/fleet_management.json | 644 ++++++++++++++++++ .../workspace/fleet_ms/fleet_ms.json | 319 --------- 79 files changed, 2684 insertions(+), 371 deletions(-) rename vsd_fleet_ms/{vsd_fleet_ms/report/fuel_expense_by_trip => patches/workspace}/__init__.py (100%) create mode 100644 vsd_fleet_ms/patches/workspace/rename_fleet_ms_workspace.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/available_truck/available_truck.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/cargo_registrations/cargo_registrations.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/completed_trips/completed_trips.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/fuel_requests/fuel_requests.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/manifest/manifest.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/ongoing_trips/ongoing_trips.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/overdue_sales_invoices/overdue_sales_invoices.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/requested_payments_in_trip/requested_payments_in_trip.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/total_trips/total_trips.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/total_trucks/total_trucks.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/truck_on_trip/truck_on_trip.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/number_card/unpaid_sales_invoices/unpaid_sales_invoices.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.js rename vsd_fleet_ms/vsd_fleet_ms/report/{fuel_expense_by_trip/fuel_expense_by_trip.json => trip_fuel_cost/trip_fuel_cost.json} (79%) rename vsd_fleet_ms/vsd_fleet_ms/report/{fuel_expense_by_trip/fuel_expense_by_trip.py => trip_fuel_cost/trip_fuel_cost.py} (50%) create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.js create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.json create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_ms/fleet_ms.json diff --git a/vsd_fleet_ms/patches.txt b/vsd_fleet_ms/patches.txt index e8fc603..b281a55 100644 --- a/vsd_fleet_ms/patches.txt +++ b/vsd_fleet_ms/patches.txt @@ -1,4 +1,5 @@ [pre_model_sync] +vsd_fleet_ms.patches.workspace.rename_fleet_ms_workspace [post_model_sync] vsd_fleet_ms.patches.custom_fields.add_cargo_id_custom_field_on_sales_invoice_item diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/__init__.py b/vsd_fleet_ms/patches/workspace/__init__.py similarity index 100% rename from vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/__init__.py rename to vsd_fleet_ms/patches/workspace/__init__.py diff --git a/vsd_fleet_ms/patches/workspace/rename_fleet_ms_workspace.py b/vsd_fleet_ms/patches/workspace/rename_fleet_ms_workspace.py new file mode 100644 index 0000000..3b673fb --- /dev/null +++ b/vsd_fleet_ms/patches/workspace/rename_fleet_ms_workspace.py @@ -0,0 +1,32 @@ +import glob +import os + +import frappe +from frappe.modules.import_file import import_file_by_path + + +def execute(): + """Bring any site's Fleet MS workspace in line with the new Fleet Management layout. + + Runs in pre_model_sync so the rename happens before the standard fixture sync + tries to import the "Fleet Management" workspace file - otherwise a site that + still has the old "Fleet MS" doc would end up with both, side by side. + """ + if frappe.db.exists("Workspace", "Fleet MS") and not frappe.db.exists("Workspace", "Fleet Management"): + frappe.rename_doc("Workspace", "Fleet MS", "Fleet Management", ignore_permissions=True) + frappe.db.set_value("Workspace", "Fleet Management", "label", "Fleet Management") + + frappe.flags.in_migrate = True + for old_report in ("Fuel Expense By Trip", "Truck Status Report"): + if frappe.db.exists("Report", old_report): + frappe.delete_doc("Report", old_report, force=True, ignore_permissions=True) + + # Number Card fixtures for this app are not picked up by the generic module sync + # (frappe.model.sync only scans a fixed doctype list that excludes "number_card" + # for non-core apps), so import them explicitly here - before the workspace + # fixture syncs and tries to link to them. + app_path = frappe.get_app_path("vsd_fleet_ms", "vsd_fleet_ms") + for path in sorted(glob.glob(os.path.join(app_path, "number_card", "*", "*.json"))): + import_file_by_path(path, force=True) + + frappe.db.commit() diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/number_card/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/available_truck/available_truck.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/available_truck/available_truck.json new file mode 100644 index 0000000..92e47ec --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/available_truck/available_truck.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e6f6ea", + "color": "#2e9e4f", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Truck", + "filters_json": "[[\"Truck\", \"status\", \"=\", \"Idle\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Available Truck", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Available Truck", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/cargo_registrations/cargo_registrations.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/cargo_registrations/cargo_registrations.json new file mode 100644 index 0000000..6b03291 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/cargo_registrations/cargo_registrations.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e0f7f7", + "color": "#16a3a3", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Cargo Registration", + "filters_json": "[]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Cargo Registrations", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Cargo Registrations", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/completed_trips/completed_trips.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/completed_trips/completed_trips.json new file mode 100644 index 0000000..ba2f2be --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/completed_trips/completed_trips.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e6f6ea", + "color": "#2e9e4f", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Trips", + "filters_json": "[[\"Trips\", \"trip_status\", \"=\", \"Completed\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Completed Trips", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Completed Trips", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/fuel_requests/fuel_requests.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/fuel_requests/fuel_requests.json new file mode 100644 index 0000000..2009497 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/fuel_requests/fuel_requests.json @@ -0,0 +1,22 @@ +{ + "background_color": "#fdf1df", + "color": "#e0891e", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Fuel Requests", + "filters_json": "[[\"Fuel Requests\", \"status\", \"!=\", \"Fully Processed\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Fuel Requests", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Fuel Requests", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/manifest/manifest.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/manifest/manifest.json new file mode 100644 index 0000000..7e1ee36 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/manifest/manifest.json @@ -0,0 +1,22 @@ +{ + "background_color": "#f1e9fb", + "color": "#8258d1", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Manifest", + "filters_json": "[]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Manifest", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Manifest", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/ongoing_trips/ongoing_trips.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/ongoing_trips/ongoing_trips.json new file mode 100644 index 0000000..430e178 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/ongoing_trips/ongoing_trips.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e5f0fd", + "color": "#2f6fed", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Trips", + "filters_json": "[[\"Trips\", \"trip_status\", \"=\", \"Pending\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Ongoing Trips", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Ongoing Trips", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/overdue_sales_invoices/overdue_sales_invoices.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/overdue_sales_invoices/overdue_sales_invoices.json new file mode 100644 index 0000000..20891a9 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/overdue_sales_invoices/overdue_sales_invoices.json @@ -0,0 +1,23 @@ +{ + "background_color": "#fbe7ea", + "color": "#c0293f", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Sales Invoice", + "dynamic_filters_json": "[[\"Sales Invoice\", \"due_date\", \"<\", \"frappe.datetime.get_today()\"]]", + "filters_json": "[[\"Sales Invoice\", \"docstatus\", \"=\", \"1\", false], [\"Sales Invoice\", \"outstanding_amount\", \">\", \"0\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Overdue Sales Invoices", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Overdue Sales Invoices", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/requested_payments_in_trip/requested_payments_in_trip.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/requested_payments_in_trip/requested_payments_in_trip.json new file mode 100644 index 0000000..e868117 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/requested_payments_in_trip/requested_payments_in_trip.json @@ -0,0 +1,22 @@ +{ + "background_color": "#fbe7ea", + "color": "#c0293f", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Requested Payment", + "filters_json": "[[\"Requested Payment\", \"payment_status\", \"!=\", \"Paid\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Requested Payments In Trip", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Requested Payments In Trip", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trips/total_trips.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trips/total_trips.json new file mode 100644 index 0000000..222236c --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trips/total_trips.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e6e9f5", + "color": "#3f51b5", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Trips", + "filters_json": "[]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Total Trips", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Total Trips", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trucks/total_trucks.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trucks/total_trucks.json new file mode 100644 index 0000000..91a0689 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/total_trucks/total_trucks.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e6e9f5", + "color": "#3f51b5", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Truck", + "filters_json": "[]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Total Trucks", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Total Trucks", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/truck_on_trip/truck_on_trip.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/truck_on_trip/truck_on_trip.json new file mode 100644 index 0000000..2a0b273 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/truck_on_trip/truck_on_trip.json @@ -0,0 +1,22 @@ +{ + "background_color": "#e5f0fd", + "color": "#2f6fed", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Truck", + "filters_json": "[[\"Truck\", \"status\", \"=\", \"On Trip\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Truck On Trip", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Truck On Trip", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/number_card/unpaid_sales_invoices/unpaid_sales_invoices.json b/vsd_fleet_ms/vsd_fleet_ms/number_card/unpaid_sales_invoices/unpaid_sales_invoices.json new file mode 100644 index 0000000..2705e50 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/number_card/unpaid_sales_invoices/unpaid_sales_invoices.json @@ -0,0 +1,22 @@ +{ + "background_color": "#fdf1df", + "color": "#c0293f", + "creation": "2026-09-17 09:00:00.000000", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Sales Invoice", + "filters_json": "[[\"Sales Invoice\", \"docstatus\", \"=\", \"1\", false], [\"Sales Invoice\", \"outstanding_amount\", \">\", \"0\", false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Unpaid Sales Invoices", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Unpaid Sales Invoices", + "owner": "Administrator", + "show_percentage_stats": 0, + "stats_time_interval": "Weekly", + "type": "Document Type" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.js new file mode 100644 index 0000000..bca6f95 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Completed Trips Report"] = { + "filters": [ + { + "fieldname": "truck_number", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.json new file mode 100644 index 0000000..0f5f480 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Completed Trips Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Completed Trips Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py new file mode 100644 index 0000000..e677776 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py @@ -0,0 +1,58 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 130}, + {"fieldname": "date", "label": _("Trip Date"), "fieldtype": "Date", "width": 100}, + {"fieldname": "trip_completed_date", "label": _("Completed Date"), "fieldtype": "Date", "width": 120}, + {"fieldname": "truck_number", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 110}, + {"fieldname": "truck_licence_plate", "label": _("Plate Number"), "fieldtype": "Data", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "route", "label": _("Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT name, date, trip_completed_date, truck_number, truck_licence_plate, driver_name, route + FROM `tabTrips` + WHERE trip_status = 'Completed' {conditions} + ORDER BY trip_completed_date DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("truck_number"): + conditions += " AND truck_number = %(truck_number)s" + values["truck_number"] = filters.get("truck_number") + + if filters.get("from_date"): + conditions += " AND trip_completed_date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND trip_completed_date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.js new file mode 100644 index 0000000..9507d8f --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.js @@ -0,0 +1,14 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Driver Activity Report"] = { + "filters": [ + { + "fieldname": "status", + "label": __("Status"), + "fieldtype": "Select", + "options": "\nActive\nSuspended\nLeft" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.json new file mode 100644 index 0000000..2c3543f --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Driver Activity Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Truck Driver", + "report_name": "Driver Activity Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py new file mode 100644 index 0000000..473a1a9 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py @@ -0,0 +1,57 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "driver", "label": _("Driver"), "fieldtype": "Link", "options": "Truck Driver", "width": 130}, + {"fieldname": "full_name", "label": _("Full Name"), "fieldtype": "Data", "width": 150}, + {"fieldname": "status", "label": _("Status"), "fieldtype": "Select", "width": 100}, + {"fieldname": "current_truck", "label": _("Current Truck"), "fieldtype": "Link", "options": "Truck", "width": 120}, + {"fieldname": "total_trips", "label": _("Total Trips"), "fieldtype": "Int", "width": 100}, + {"fieldname": "completed_trips", "label": _("Completed Trips"), "fieldtype": "Int", "width": 130}, + {"fieldname": "pending_trips", "label": _("Pending Trips"), "fieldtype": "Int", "width": 110}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + d.name AS driver, + d.full_name, + d.status, + (SELECT tr.name FROM `tabTruck` tr WHERE tr.trans_ms_driver = d.name LIMIT 1) AS current_truck, + (SELECT COUNT(*) FROM `tabTrips` WHERE assigned_driver = d.name) AS total_trips, + (SELECT COUNT(*) FROM `tabTrips` WHERE assigned_driver = d.name AND trip_status = 'Completed') AS completed_trips, + (SELECT COUNT(*) FROM `tabTrips` WHERE assigned_driver = d.name AND trip_status = 'Pending') AS pending_trips + FROM `tabTruck Driver` d + WHERE 1 = 1 {conditions} + ORDER BY total_trips DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("status"): + conditions += " AND d.status = %(status)s" + values["status"] = filters.get("status") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.js new file mode 100644 index 0000000..6663990 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Fixed Expenses Report"] = { + "filters": [ + { + "fieldname": "expense_type", + "label": __("Expense"), + "fieldtype": "Link", + "options": "Fixed Expenses" + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.json new file mode 100644 index 0000000..4a21c51 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-18 12:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Fixed Expenses Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Fixed Expenses", + "report_name": "Fixed Expenses Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py new file mode 100644 index 0000000..cae1e77 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py @@ -0,0 +1,60 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "expense_type", "label": _("Expense"), "fieldtype": "Link", "options": "Fixed Expenses", "width": 200}, + {"fieldname": "request_count", "label": _("Number of Requests"), "fieldtype": "Int", "width": 140}, + {"fieldname": "total_tzs", "label": _("Total (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + {"fieldname": "total_usd", "label": _("Total (USD)"), "fieldtype": "Currency", "options": "USD", "width": 130}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + expense_type, + COUNT(*) AS request_count, + SUM(CASE WHEN request_currency = 'TZS' THEN request_amount ELSE 0 END) AS total_tzs, + SUM(CASE WHEN request_currency = 'USD' THEN request_amount ELSE 0 END) AS total_usd + FROM `tabRequested Fund Details` + WHERE expense_type IS NOT NULL AND expense_type != '' {conditions} + GROUP BY expense_type + ORDER BY total_tzs DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("expense_type"): + conditions += " AND expense_type = %(expense_type)s" + values["expense_type"] = filters.get("expense_type") + + if filters.get("from_date"): + conditions += " AND requested_date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND requested_date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.js b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.js new file mode 100644 index 0000000..0ea653a --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.js @@ -0,0 +1,7 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Fleet Availability"] = { + "filters": [] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.json b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.json new file mode 100644 index 0000000..9ec0d6d --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Fleet Availability", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Truck", + "report_name": "Fleet Availability", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.py b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.py new file mode 100644 index 0000000..7472f3c --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fleet_availability/fleet_availability.py @@ -0,0 +1,30 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + columns = get_columns() + data = get_data() + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "status", "label": _("Status"), "fieldtype": "Select", "width": 150}, + {"fieldname": "truck_count", "label": _("Number of Trucks"), "fieldtype": "Int", "width": 150}, + ] + + +def get_data(): + return frappe.db.sql( + """ + SELECT status, COUNT(*) AS truck_count + FROM `tabTruck` + GROUP BY status + ORDER BY truck_count DESC + """, + as_dict=1, + ) diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.js new file mode 100644 index 0000000..b46bef7 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Fuel Consumption Report"] = { + "filters": [ + { + "fieldname": "truck_number", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.json new file mode 100644 index 0000000..b00f761 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Fuel Consumption Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Fuel Consumption Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py new file mode 100644 index 0000000..778fd0e --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py @@ -0,0 +1,64 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "truck_number", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 120}, + {"fieldname": "trip_count", "label": _("Trips"), "fieldtype": "Int", "width": 90}, + {"fieldname": "total_quantity", "label": _("Total Fuel (Ltr)"), "fieldtype": "Float", "width": 130}, + {"fieldname": "total_cost_tzs", "label": _("Total Cost (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 140}, + {"fieldname": "total_cost_usd", "label": _("Total Cost (USD)"), "fieldtype": "Currency", "options": "USD", "width": 140}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + t.truck_number, + COUNT(DISTINCT t.name) AS trip_count, + SUM(f.quantity) AS total_quantity, + SUM(CASE WHEN f.currency = 'TZS' THEN f.total_cost ELSE 0 END) AS total_cost_tzs, + SUM(CASE WHEN f.currency = 'USD' THEN f.total_cost ELSE 0 END) AS total_cost_usd + FROM `tabTrips` t + INNER JOIN `tabFuel Requests Table` f + ON f.parent = t.name AND f.parentfield = 'fuel_request_history' + WHERE t.truck_number IS NOT NULL AND t.truck_number != '' {conditions} + GROUP BY t.truck_number + ORDER BY total_quantity DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("truck_number"): + conditions += " AND t.truck_number = %(truck_number)s" + values["truck_number"] = filters.get("truck_number") + + if filters.get("from_date"): + conditions += " AND t.date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND t.date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.js b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.js deleted file mode 100644 index af490a4..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.js +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024, VV SYSTEMS DEVELOPER LTD and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Fuel Expense By Trip"] = { - "filters": [ - - ] -}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.js new file mode 100644 index 0000000..4cfb759 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.js @@ -0,0 +1,24 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Ongoing Trips Report"] = { + "filters": [ + { + "fieldname": "truck_number", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date" + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.json new file mode 100644 index 0000000..82191b3 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Ongoing Trips Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Ongoing Trips Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py new file mode 100644 index 0000000..234ad71 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py @@ -0,0 +1,58 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 130}, + {"fieldname": "date", "label": _("Trip Date"), "fieldtype": "Date", "width": 100}, + {"fieldname": "truck_number", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 110}, + {"fieldname": "truck_licence_plate", "label": _("Plate Number"), "fieldtype": "Data", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "route", "label": _("Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "transporter_type", "label": _("Transporter"), "fieldtype": "Data", "width": 110}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT name, date, truck_number, truck_licence_plate, driver_name, route, transporter_type + FROM `tabTrips` + WHERE trip_status = 'Pending' {conditions} + ORDER BY date DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("truck_number"): + conditions += " AND truck_number = %(truck_number)s" + values["truck_number"] = filters.get("truck_number") + + if filters.get("from_date"): + conditions += " AND date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js new file mode 100644 index 0000000..a2eddc5 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js @@ -0,0 +1,14 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Overdue Invoices Report"] = { + "filters": [ + { + "fieldname": "customer", + "label": __("Customer"), + "fieldtype": "Link", + "options": "Customer" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json new file mode 100644 index 0000000..e5682d5 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Overdue Invoices Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Invoice", + "report_name": "Overdue Invoices Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py new file mode 100644 index 0000000..f6dded8 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py @@ -0,0 +1,60 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ +from frappe.utils import nowdate + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Sales Invoice"), "fieldtype": "Link", "options": "Sales Invoice", "width": 130}, + {"fieldname": "trip", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 120}, + {"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 160}, + {"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "due_date", "label": _("Due Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "days_overdue", "label": _("Days Overdue"), "fieldtype": "Int", "width": 110}, + {"fieldname": "grand_total", "label": _("Grand Total"), "fieldtype": "Currency", "options": "currency", "width": 130}, + {"fieldname": "outstanding_amount", "label": _("Outstanding Amount"), "fieldtype": "Currency", "options": "currency", "width": 150}, + {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 90}, + ] + + +def get_data(filters): + # Only invoices booked against a fleet trip (Trip -> Cargo Registration -> Cargo Detail -> Sales Invoice) + conditions, values = get_conditions(filters) + values["today"] = nowdate() + + return frappe.db.sql( + f""" + SELECT DISTINCT + si.name, cr.trip, si.customer, si.posting_date, si.due_date, + DATEDIFF(%(today)s, si.due_date) AS days_overdue, + si.grand_total, si.outstanding_amount, si.currency + FROM `tabSales Invoice` si + INNER JOIN `tabCargo Detail` cd ON cd.invoice = si.name + INNER JOIN `tabCargo Registration` cr ON cr.name = cd.parent AND cr.trip IS NOT NULL AND cr.trip != '' + WHERE si.docstatus = 1 AND si.outstanding_amount > 0 AND si.due_date < %(today)s {conditions} + ORDER BY days_overdue DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("customer"): + conditions += " AND si.customer = %(customer)s" + values["customer"] = filters.get("customer") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.js new file mode 100644 index 0000000..c961330 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.js @@ -0,0 +1,30 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Pending Fuel Requests Report"] = { + "filters": [ + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date" + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date" + }, + { + "fieldname": "truck", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "status", + "label": __("Status"), + "fieldtype": "Select", + "options": "\nWaiting Approval\nPartially Processed" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.json new file mode 100644 index 0000000..213c835 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Pending Fuel Requests Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Fuel Requests", + "report_name": "Pending Fuel Requests Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py new file mode 100644 index 0000000..d40c51c --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py @@ -0,0 +1,104 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Fuel Request"), "fieldtype": "Link", "options": "Fuel Requests", "width": 150}, + {"fieldname": "transaction_date", "label": _("Transaction Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "truck", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "main_route", "label": _("Main Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "return_route", "label": _("Return Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "status", "label": _("Status"), "fieldtype": "Data", "width": 130}, + {"fieldname": "requested_quantity", "label": _("Requested Quantity (Ltr)"), "fieldtype": "Float", "width": 160}, + {"fieldname": "requested_cost_tzs", "label": _("Requested Cost (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 150}, + {"fieldname": "requested_cost_usd", "label": _("Requested Cost (USD)"), "fieldtype": "Currency", "options": "USD", "width": 150}, + {"fieldname": "reference_doctype", "label": _("Reference Doctype"), "fieldtype": "Link", "options": "DocType", "width": 130}, + {"fieldname": "reference_docname", "label": _("Reference"), "fieldtype": "Dynamic Link", "options": "reference_doctype", "width": 150}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + fr.name AS name, + COALESCE(fr.transaction_date, t.date) AS transaction_date, + COALESCE(fr.truck, t.truck_number) AS truck, + COALESCE(fr.driver_name, t.driver_name) AS driver_name, + COALESCE(fr.main_route, t.route) AS main_route, + fr.return_route, + fr.status, + fr.reference_doctype, + fr.reference_docname, + COALESCE(( + SELECT SUM(quantity) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Fuel Requests' AND parentfield = 'requested_fuel' AND parent = fr.name + ), 0) + COALESCE(( + SELECT SUM(quantity) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = t.name + ), 0) AS requested_quantity, + COALESCE(( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Fuel Requests' AND parentfield = 'requested_fuel' AND parent = fr.name AND currency = 'TZS' + ), 0) + COALESCE(( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = t.name AND currency = 'TZS' + ), 0) AS requested_cost_tzs, + COALESCE(( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Fuel Requests' AND parentfield = 'requested_fuel' AND parent = fr.name AND currency = 'USD' + ), 0) + COALESCE(( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = t.name AND currency = 'USD' + ), 0) AS requested_cost_usd + FROM `tabFuel Requests` fr + LEFT JOIN `tabTrips` t ON fr.reference_doctype = 'Trips' AND fr.reference_docname = t.name + WHERE fr.status != 'Fully Processed' {conditions} + ORDER BY transaction_date DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("status"): + conditions += " AND fr.status = %(status)s" + values["status"] = filters.get("status") + + if filters.get("truck"): + conditions += " AND fr.truck = %(truck)s" + values["truck"] = filters.get("truck") + + if filters.get("from_date"): + conditions += " AND (COALESCE(fr.transaction_date, t.date) >= %(from_date)s OR COALESCE(fr.transaction_date, t.date) IS NULL)" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND (COALESCE(fr.transaction_date, t.date) <= %(to_date)s OR COALESCE(fr.transaction_date, t.date) IS NULL)" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js new file mode 100644 index 0000000..96fd5fb --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js @@ -0,0 +1,36 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Pending Requested Payments Report"] = { + "filters": [ + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date" + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date" + }, + { + "fieldname": "truck_no", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "approval_status", + "label": __("Approval Status"), + "fieldtype": "Select", + "options": "\nWaiting Approval\nProcessed" + }, + { + "fieldname": "payment_status", + "label": __("Payment Status"), + "fieldtype": "Select", + "options": "\nWaiting Approval\nWaiting Payment\nPaid" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.json new file mode 100644 index 0000000..715680f --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Pending Requested Payments Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Requested Payment", + "report_name": "Pending Requested Payments Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py new file mode 100644 index 0000000..b684115 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py @@ -0,0 +1,87 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "reference", "label": _("Requested Payment"), "fieldtype": "Link", "options": "Requested Payment", "width": 160}, + {"fieldname": "request_date", "label": _("Request Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "truck_no", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "trip_route", "label": _("Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "manifest", "label": _("Manifest"), "fieldtype": "Link", "options": "Manifest", "width": 130}, + {"fieldname": "approval_status", "label": _("Approval Status"), "fieldtype": "Data", "width": 130}, + {"fieldname": "payment_status", "label": _("Payment Status"), "fieldtype": "Data", "width": 130}, + {"fieldname": "requested_usd", "label": _("Requested (USD)"), "fieldtype": "Currency", "options": "USD", "width": 130}, + {"fieldname": "requested_tzs", "label": _("Requested (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + rp.name AS reference, + rp.request_date, + rp.truck_no, + rp.driver_name, + rp.trip_route, + rp.manifest, + rp.approval_status, + rp.payment_status, + ( + SELECT SUM(request_amount) + FROM `tabRequested Fund Details` + WHERE parenttype = rp.reference_doctype AND parent = rp.reference_docname AND request_currency = 'USD' + ) AS requested_usd, + ( + SELECT SUM(request_amount) + FROM `tabRequested Fund Details` + WHERE parenttype = rp.reference_doctype AND parent = rp.reference_docname AND request_currency = 'TZS' + ) AS requested_tzs + FROM `tabRequested Payment` rp + WHERE rp.payment_status != 'Paid' {conditions} + ORDER BY rp.request_date DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("approval_status"): + conditions += " AND rp.approval_status = %(approval_status)s" + values["approval_status"] = filters.get("approval_status") + + if filters.get("payment_status"): + conditions += " AND rp.payment_status = %(payment_status)s" + values["payment_status"] = filters.get("payment_status") + + if filters.get("truck_no"): + conditions += " AND rp.truck_no = %(truck_no)s" + values["truck_no"] = filters.get("truck_no") + + if filters.get("from_date"): + conditions += " AND rp.request_date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND rp.request_date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.js b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.js new file mode 100644 index 0000000..3575121 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Trip Fuel Cost"] = { + "filters": [ + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + }, + { + "fieldname": "truck_number", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json similarity index 79% rename from vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.json rename to vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json index 9521bde..2ede687 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.json +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json @@ -9,14 +9,14 @@ "filters": [], "idx": 0, "is_standard": "Yes", - "modified": "2024-05-06 09:52:06.596618", + "modified": "2026-09-17 09:00:00.000000", "modified_by": "Administrator", "module": "VSD Fleet MS", - "name": "Fuel Expense By Trip", + "name": "Trip Fuel Cost", "owner": "Administrator", "prepared_report": 0, "ref_doctype": "Trips", - "report_name": "Fuel Expense By Trip", + "report_name": "Trip Fuel Cost", "report_type": "Script Report", "roles": [ { @@ -26,4 +26,4 @@ "role": "All" } ] -} \ No newline at end of file +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py similarity index 50% rename from vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.py rename to vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py index e1c834e..1ec6fea 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_expense_by_trip/fuel_expense_by_trip.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, VV SYSTEMS DEVELOPER LTD and contributors +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors # For license information, please see license.txt import frappe @@ -6,13 +6,13 @@ def execute(filters=None): - columns, data = [], [] + filters = filters or {} columns = get_columns() data = get_data(filters) return columns, data, None + def get_columns(): - # Define the columns to be displayed in the report return [ {"fieldname": "vehicle_trip", "fieldtype": "Link", "label": "Vehicle Trip", "options": "Trips"}, {"fieldname": "date", "fieldtype": "Date", "label": "Trip Date"}, @@ -20,52 +20,56 @@ def get_columns(): {"fieldname": "truck_number", "fieldtype": "Data", "label": "Truck Number"}, {"fieldname": "transporter_type", "fieldtype": "Data", "label": "Transporter Type"}, {"fieldname": "trip_status", "fieldtype": "Data", "label": "Trip Status"}, - {"fieldname": "truck_licence_plate", "fieldtype": "Data", "label": "Truck Licence Plate"}, - {"fieldname": "route", "fieldtype": "Link", "label": "Route","options":"Trip Routes"}, + {"fieldname": "route", "fieldtype": "Link", "label": "Route", "options": "Trip Routes"}, {"fieldname": "item_name", "fieldtype": "Data", "label": "Item Name"}, {"fieldname": "uom", "fieldtype": "Data", "label": "UOM"}, {"fieldname": "quantity", "fieldtype": "Float", "label": "Quantity"}, {"fieldname": "cost_per_litre", "fieldtype": "Float", "label": "Cost Per Litre"}, - {"fieldname": "currency", "fieldtype": "Link", "label": "Currency","options":"Currency"}, - {"fieldname": "total_cost", "fieldtype": "Currency", "label": "Total Cost","options":""}, + {"fieldname": "currency", "fieldtype": "Link", "label": "Currency", "options": "Currency"}, + {"fieldname": "total_cost", "fieldtype": "Currency", "label": "Total Cost", "options": "currency"}, {"fieldname": "disbursement_type", "fieldtype": "Data", "label": "Disbursement Type"}, {"fieldname": "supplier", "fieldtype": "Link", "label": "Supplier", "options": "Supplier"}, {"fieldname": "status", "fieldtype": "Data", "label": "Status"}, {"fieldname": "approved_by", "fieldtype": "Data", "label": "Approved By"}, {"fieldname": "approved_date", "fieldtype": "Date", "label": "Approved Date"}, - {"fieldname": "round_trip", "fieldtype": "Check", "label": "Round Trip"}, - {"fieldname": "trip_complited", "fieldtype": "Check", "label": "Trip Completed"} - ] + def get_data(filters): - data = [] - vehicle_trips = frappe.db.sql("SELECT * FROM tabTrips T INNER JOIN `tabFuel Requests Table` FL ON FL.parent = T.name",as_dict=True) - for trip in vehicle_trips: - data.append({ - "round_trip": trip.round_trip, - "driver_name": trip.driver_name, - "trip_complited": trip.trip_complited, - "truck_number": trip.truck_number, - "transporter_type": trip.transporter_type, - "trip_status": trip.trip_status, - "truck_number": trip.truck_number, - "truck_licence_plate": trip.truck_licence_plate, - "route": trip.route, - "vehicle_trip": trip.parent, - "item_code": trip.item_code, - "item_name": trip.item_name, - "uom": trip.uom, - "quantity": trip.quantity, - "cost_per_litre": trip.cost_per_litre, - "currency": trip.currency, - "total_cost": trip.total_cost, - "disbursement_type": trip.disbursement_type, - "supplier": trip.supplier, - "status": trip.status, - "approved_by": trip.approved_by, - "date": trip.date, - "approved_date": trip.approved_date + conditions, values = get_conditions(filters) + + rows = frappe.db.sql( + f""" + SELECT + T.name AS vehicle_trip, T.date, T.driver_name, T.truck_number, T.transporter_type, + T.trip_status, T.route, + FL.item_name, FL.uom, FL.quantity, FL.cost_per_litre, FL.currency, FL.total_cost, + FL.disbursement_type, FL.supplier, FL.status, FL.approved_by, FL.approved_date + FROM `tabTrips` T + INNER JOIN `tabFuel Requests Table` FL ON FL.parent = T.name AND FL.parentfield = 'fuel_request_history' + WHERE 1 = 1 {conditions} + ORDER BY T.date DESC + """, + values, + as_dict=True, + ) + return rows + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("truck_number"): + conditions += " AND T.truck_number = %(truck_number)s" + values["truck_number"] = filters.get("truck_number") + + if filters.get("from_date"): + conditions += " AND T.date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND T.date <= %(to_date)s" + values["to_date"] = filters.get("to_date") - }) - return data \ No newline at end of file + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.js b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.js new file mode 100644 index 0000000..2215f82 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Trip Profit and Loss Statement"] = { + "filters": [ + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + }, + { + "fieldname": "status", + "label": __("Trip Status"), + "fieldtype": "Select", + "options": "\nPending\nCompleted\nBreakdown" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.json new file mode 100644 index 0000000..ab4457b --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Trip Profit and Loss Statement", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Trip Profit and Loss Statement", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py new file mode 100644 index 0000000..93b0b58 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py @@ -0,0 +1,131 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + + if filters.get("from_date") and filters.get("to_date") and filters.get("from_date") > filters.get("to_date"): + frappe.throw(_("From Date must be before To Date {0}").format(filters.get("to_date"))) + + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "reference", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 130}, + {"fieldname": "posting_date", "label": _("Trip Date"), "fieldtype": "Date", "width": 100}, + {"fieldname": "transporter_name", "label": _("Transporter"), "fieldtype": "Data", "width": 160}, + {"fieldname": "vehicle_plate_number", "label": _("Vehicle"), "fieldtype": "Data", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "route", "label": _("Route"), "fieldtype": "Data", "width": 150}, + {"fieldname": "status", "label": _("Status"), "fieldtype": "Data", "width": 110}, + {"fieldname": "revenue_usd", "label": _("Revenue (USD)"), "fieldtype": "Currency", "options": "USD", "width": 120}, + {"fieldname": "expenses_usd", "label": _("Expenses (USD)"), "fieldtype": "Currency", "options": "USD", "width": 120}, + {"fieldname": "profit_usd", "label": _("Profit (USD)"), "fieldtype": "Currency", "options": "USD", "width": 120}, + {"fieldname": "revenue_tzs", "label": _("Revenue (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + {"fieldname": "expenses_tzs", "label": _("Expenses (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + {"fieldname": "profit_tzs", "label": _("Profit (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + rows = frappe.db.sql( + f""" + SELECT + `tabTrips`.name AS reference, + `tabTrips`.date AS posting_date, + `tabTrips`.trip_status AS status, + IF(`tabTrips`.transporter_type = 'In House', '', `tabTrips`.sub_contractor_name) AS transporter_name, + IF(`tabTrips`.transporter_type = 'In House', `tabTrips`.truck_licence_plate, `tabTrips`.sub_contactor_truck_license_plate_no) AS vehicle_plate_number, + IF(`tabTrips`.transporter_type = 'In House', `tabTrips`.driver_name, `tabTrips`.sub_contactor_driver_name) AS driver_name, + `tabTrips`.route AS route, + ( + SELECT SUM(cd.rate) + FROM `tabCargo Detail` cd + INNER JOIN `tabCargo Registration` cr ON cd.parent = cr.name + WHERE cr.trip = `tabTrips`.name AND cd.currency = 'USD' + ) AS revenue_usd, + ( + SELECT SUM(cd.rate) + FROM `tabCargo Detail` cd + INNER JOIN `tabCargo Registration` cr ON cd.parent = cr.name + WHERE cr.trip = `tabTrips`.name AND cd.currency = 'TZS' + ) AS revenue_tzs, + ( + SELECT SUM(request_amount) + FROM `tabRequested Fund Details` + WHERE parenttype = 'Trips' AND parent = `tabTrips`.name AND request_currency = 'USD' AND request_status = 'Approved' + ) AS fund_expenses_usd, + ( + SELECT SUM(request_amount) + FROM `tabRequested Fund Details` + WHERE parenttype = 'Trips' AND parent = `tabTrips`.name AND request_currency = 'TZS' AND request_status = 'Approved' + ) AS fund_expenses_tzs, + ( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = `tabTrips`.name AND currency = 'USD' + ) AS fuel_expenses_usd, + ( + SELECT SUM(total_cost) + FROM `tabFuel Requests Table` + WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = `tabTrips`.name AND currency = 'TZS' + ) AS fuel_expenses_tzs + FROM `tabTrips` + WHERE 1 = 1 {conditions} + """, + values, + as_dict=1, + ) + + data = [] + for row in rows: + revenue_usd = row.revenue_usd or 0 + revenue_tzs = row.revenue_tzs or 0 + expenses_usd = (row.fund_expenses_usd or 0) + (row.fuel_expenses_usd or 0) + expenses_tzs = (row.fund_expenses_tzs or 0) + (row.fuel_expenses_tzs or 0) + + data.append({ + "reference": row.reference, + "posting_date": row.posting_date, + "transporter_name": row.transporter_name, + "vehicle_plate_number": row.vehicle_plate_number, + "driver_name": row.driver_name, + "route": row.route, + "status": row.status, + "revenue_usd": revenue_usd, + "expenses_usd": expenses_usd, + "profit_usd": revenue_usd - expenses_usd, + "revenue_tzs": revenue_tzs, + "expenses_tzs": expenses_tzs, + "profit_tzs": revenue_tzs - expenses_tzs, + }) + + return data + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("status"): + conditions += " AND `tabTrips`.trip_status = %(status)s" + values["status"] = filters.get("status") + + if filters.get("from_date"): + conditions += " AND `tabTrips`.date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND `tabTrips`.date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.js new file mode 100644 index 0000000..d233232 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.js @@ -0,0 +1,20 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Trip Revenue Report"] = { + "filters": [ + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.json new file mode 100644 index 0000000..efcc64a --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Trip Revenue Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Trip Revenue Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py new file mode 100644 index 0000000..29e9639 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py @@ -0,0 +1,64 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "reference", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 130}, + {"fieldname": "date", "label": _("Trip Date"), "fieldtype": "Date", "width": 100}, + {"fieldname": "route", "label": _("Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "invoice_count", "label": _("Invoices"), "fieldtype": "Int", "width": 90}, + {"fieldname": "revenue_usd", "label": _("Revenue (USD)"), "fieldtype": "Currency", "options": "USD", "width": 130}, + {"fieldname": "revenue_tzs", "label": _("Revenue (TZS)"), "fieldtype": "Currency", "options": "TZS", "width": 130}, + ] + + +def get_data(filters): + # Revenue is booked through Cargo Registration: Trip -> Cargo Registration -> Cargo Detail -> Sales Invoice + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + t.name AS reference, + t.date, + t.route, + COUNT(DISTINCT si.name) AS invoice_count, + SUM(CASE WHEN si.currency = 'USD' THEN si.grand_total ELSE 0 END) AS revenue_usd, + SUM(CASE WHEN si.currency = 'TZS' THEN si.grand_total ELSE 0 END) AS revenue_tzs + FROM `tabTrips` t + INNER JOIN `tabCargo Registration` cr ON cr.trip = t.name + INNER JOIN `tabCargo Detail` cd ON cd.parent = cr.name AND cd.invoice IS NOT NULL AND cd.invoice != '' + INNER JOIN `tabSales Invoice` si ON si.name = cd.invoice AND si.docstatus = 1 + WHERE 1 = 1 {conditions} + GROUP BY t.name + ORDER BY t.date DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("from_date"): + conditions += " AND t.date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND t.date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.js b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.js new file mode 100644 index 0000000..8d9b677 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.js @@ -0,0 +1,26 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Trip Turnaround Time"] = { + "filters": [ + { + "fieldname": "truck_number", + "label": __("Truck"), + "fieldtype": "Link", + "options": "Truck" + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.month_start() + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.json new file mode 100644 index 0000000..92ceee4 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Trip Turnaround Time", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Trips", + "report_name": "Trip Turnaround Time", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py new file mode 100644 index 0000000..1b8020a --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py @@ -0,0 +1,60 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 130}, + {"fieldname": "truck_number", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 110}, + {"fieldname": "driver_name", "label": _("Driver"), "fieldtype": "Data", "width": 150}, + {"fieldname": "route", "label": _("Route"), "fieldtype": "Link", "options": "Trip Routes", "width": 150}, + {"fieldname": "date", "label": _("Start Date"), "fieldtype": "Date", "width": 100}, + {"fieldname": "trip_completed_date", "label": _("Completed Date"), "fieldtype": "Date", "width": 120}, + {"fieldname": "days_taken", "label": _("Days Taken"), "fieldtype": "Int", "width": 100}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + name, truck_number, driver_name, route, date, trip_completed_date, + DATEDIFF(trip_completed_date, date) AS days_taken + FROM `tabTrips` + WHERE trip_status = 'Completed' AND date IS NOT NULL AND trip_completed_date IS NOT NULL {conditions} + ORDER BY days_taken DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("truck_number"): + conditions += " AND truck_number = %(truck_number)s" + values["truck_number"] = filters.get("truck_number") + + if filters.get("from_date"): + conditions += " AND date >= %(from_date)s" + values["from_date"] = filters.get("from_date") + + if filters.get("to_date"): + conditions += " AND date <= %(to_date)s" + values["to_date"] = filters.get("to_date") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js new file mode 100644 index 0000000..f185ac5 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js @@ -0,0 +1,14 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Unpaid Invoices Report"] = { + "filters": [ + { + "fieldname": "customer", + "label": __("Customer"), + "fieldtype": "Link", + "options": "Customer" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json new file mode 100644 index 0000000..fbedb4b --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Unpaid Invoices Report", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Invoice", + "report_name": "Unpaid Invoices Report", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py new file mode 100644 index 0000000..5a464d6 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py @@ -0,0 +1,56 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Sales Invoice"), "fieldtype": "Link", "options": "Sales Invoice", "width": 130}, + {"fieldname": "trip", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 120}, + {"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 160}, + {"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "due_date", "label": _("Due Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "grand_total", "label": _("Grand Total"), "fieldtype": "Currency", "options": "currency", "width": 130}, + {"fieldname": "outstanding_amount", "label": _("Outstanding Amount"), "fieldtype": "Currency", "options": "currency", "width": 150}, + {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 90}, + ] + + +def get_data(filters): + # Only invoices booked against a fleet trip (Trip -> Cargo Registration -> Cargo Detail -> Sales Invoice) + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT DISTINCT + si.name, cr.trip, si.customer, si.posting_date, si.due_date, + si.grand_total, si.outstanding_amount, si.currency + FROM `tabSales Invoice` si + INNER JOIN `tabCargo Detail` cd ON cd.invoice = si.name + INNER JOIN `tabCargo Registration` cr ON cr.name = cd.parent AND cr.trip IS NOT NULL AND cr.trip != '' + WHERE si.docstatus = 1 AND si.outstanding_amount > 0 {conditions} + ORDER BY si.due_date ASC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("customer"): + conditions += " AND si.customer = %(customer)s" + values["customer"] = filters.get("customer") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.js b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.js new file mode 100644 index 0000000..465c35c --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.js @@ -0,0 +1,14 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Vehicle Utilization"] = { + "filters": [ + { + "fieldname": "status", + "label": __("Status"), + "fieldtype": "Select", + "options": "\nIdle\nUnder Maintenance\nOn Trip\nDisabled" + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.json b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.json new file mode 100644 index 0000000..f39a712 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.json @@ -0,0 +1,30 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2026-09-17 09:00:00.000000", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "json": "{}", + "modified": "2026-09-17 09:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Vehicle Utilization", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Truck", + "report_name": "Vehicle Utilization", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "All" + } + ] +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py new file mode 100644 index 0000000..2f3d9ac --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py @@ -0,0 +1,57 @@ +# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +def execute(filters=None): + filters = filters or {} + columns = get_columns() + data = get_data(filters) + return columns, data, None, None + + +def get_columns(): + return [ + {"fieldname": "truck", "label": _("Truck"), "fieldtype": "Link", "options": "Truck", "width": 120}, + {"fieldname": "truck_number", "label": _("Truck Number"), "fieldtype": "Data", "width": 110}, + {"fieldname": "status", "label": _("Current Status"), "fieldtype": "Select", "width": 120}, + {"fieldname": "total_trips", "label": _("Total Trips"), "fieldtype": "Int", "width": 100}, + {"fieldname": "completed_trips", "label": _("Completed Trips"), "fieldtype": "Int", "width": 130}, + {"fieldname": "breakdown_trips", "label": _("Breakdown Trips"), "fieldtype": "Int", "width": 130}, + {"fieldname": "last_trip_date", "label": _("Last Trip Date"), "fieldtype": "Date", "width": 120}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + + return frappe.db.sql( + f""" + SELECT + t.name AS truck, + t.truck_number, + t.status, + (SELECT COUNT(*) FROM `tabTrips` WHERE truck_number = t.name) AS total_trips, + (SELECT COUNT(*) FROM `tabTrips` WHERE truck_number = t.name AND trip_status = 'Completed') AS completed_trips, + (SELECT COUNT(*) FROM `tabTrips` WHERE truck_number = t.name AND trip_status = 'Breakdown') AS breakdown_trips, + (SELECT MAX(date) FROM `tabTrips` WHERE truck_number = t.name) AS last_trip_date + FROM `tabTruck` t + WHERE 1 = 1 {conditions} + ORDER BY total_trips DESC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("status"): + conditions += " AND t.status = %(status)s" + values["status"] = filters.get("status") + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json b/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json new file mode 100644 index 0000000..3c815eb --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json @@ -0,0 +1,644 @@ +{ + "charts": [], + "content": "[{\"id\":\"fleet_head_1\",\"type\":\"header\",\"data\":{\"text\":\"Overview\",\"col\":12}},{\"id\":\"fleet_nc_1\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Trucks\",\"col\":3}},{\"id\":\"fleet_nc_2\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Available Truck\",\"col\":3}},{\"id\":\"fleet_nc_3\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Truck On Trip\",\"col\":3}},{\"id\":\"fleet_nc_4\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Trips\",\"col\":3}},{\"id\":\"fleet_head_2\",\"type\":\"header\",\"data\":{\"text\":\"Trip Operations\",\"col\":12}},{\"id\":\"fleet_nc_5\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Ongoing Trips\",\"col\":3}},{\"id\":\"fleet_nc_6\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Completed Trips\",\"col\":3}},{\"id\":\"fleet_nc_7\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Cargo Registrations\",\"col\":3}},{\"id\":\"fleet_nc_8\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Manifest\",\"col\":3}},{\"id\":\"fleet_head_3\",\"type\":\"header\",\"data\":{\"text\":\"Attention Required\",\"col\":12}},{\"id\":\"fleet_nc_9\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Fuel Requests\",\"col\":3}},{\"id\":\"fleet_nc_10\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Requested Payments In Trip\",\"col\":3}},{\"id\":\"fleet_nc_11\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Unpaid Sales Invoices\",\"col\":3}},{\"id\":\"fleet_nc_12\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Overdue Sales Invoices\",\"col\":3}},{\"id\":\"fleet_space_1\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"fleet_head_4\",\"type\":\"header\",\"data\":{\"text\":\"Fleet Management\",\"col\":12}},{\"id\":\"fleet_card_1\",\"type\":\"card\",\"data\":{\"card_name\":\"Fleet & Drivers\",\"col\":3}},{\"id\":\"fleet_card_2\",\"type\":\"card\",\"data\":{\"card_name\":\"Trip Operations\",\"col\":3}},{\"id\":\"fleet_card_3\",\"type\":\"card\",\"data\":{\"card_name\":\"Locations & Routes\",\"col\":3}},{\"id\":\"fleet_card_4\",\"type\":\"card\",\"data\":{\"card_name\":\"Fuel & Expenses\",\"col\":3}},{\"id\":\"fleet_card_5\",\"type\":\"card\",\"data\":{\"card_name\":\"Compliance & Logs\",\"col\":3}},{\"id\":\"fleet_space_2\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"fleet_head_5\",\"type\":\"header\",\"data\":{\"text\":\"Finance & Operations\",\"col\":12}},{\"id\":\"fleet_card_6\",\"type\":\"card\",\"data\":{\"card_name\":\"Finance & Billing\",\"col\":4}},{\"id\":\"fleet_card_7\",\"type\":\"card\",\"data\":{\"card_name\":\"Procurement & Stock\",\"col\":4}},{\"id\":\"fleet_card_8\",\"type\":\"card\",\"data\":{\"card_name\":\"Configuration\",\"col\":4}},{\"id\":\"fleet_space_4\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"fleet_head_8\",\"type\":\"header\",\"data\":{\"text\":\"Reports & Analytics\",\"col\":12}},{\"id\":\"fleet_card_13\",\"type\":\"card\",\"data\":{\"card_name\":\"Fleet Operations\",\"col\":3}},{\"id\":\"fleet_card_14\",\"type\":\"card\",\"data\":{\"card_name\":\"Trip Performance\",\"col\":3}},{\"id\":\"fleet_card_15\",\"type\":\"card\",\"data\":{\"card_name\":\"Fuel & Cost Analysis\",\"col\":3}},{\"id\":\"fleet_card_16\",\"type\":\"card\",\"data\":{\"card_name\":\"Finance & Billing Reports\",\"col\":3}}]", + "creation": "2023-05-04 18:08:12.460715", + "custom_blocks": [], + "docstatus": 0, + "doctype": "Workspace", + "for_user": "", + "hide_custom": 0, + "icon": "map", + "idx": 0, + "is_hidden": 0, + "label": "Fleet Management", + "links": [ + { + "hidden": 0, + "is_query_report": 0, + "label": "Fleet & Drivers", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Truck", + "link_count": 0, + "link_to": "Truck", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Truck Type", + "link_count": 0, + "link_to": "Truck Type", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trailers", + "link_count": 0, + "link_to": "Trailers", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Truck Driver", + "link_count": 0, + "link_to": "Truck Driver", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Operations", + "link_count": 5, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Cargo Registration", + "link_count": 0, + "link_to": "Cargo Registration", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Bulk Cargo", + "link_count": 0, + "link_to": "Bulk Cargo", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trips", + "link_count": 0, + "link_to": "Trips", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Round Trip", + "link_count": 0, + "link_to": "Round Trip", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Manifest", + "link_count": 0, + "link_to": "Manifest", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Locations & Routes", + "link_count": 5, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Routes", + "link_count": 0, + "link_to": "Trip Routes", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Locations", + "link_count": 0, + "link_to": "Trip Locations", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Locations Type", + "link_count": 0, + "link_to": "Trip Locations Type", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Transport Location", + "link_count": 0, + "link_to": "Transport Location", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Cargo Types", + "link_count": 0, + "link_to": "Cargo Types", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel & Expenses", + "link_count": 3, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel Requests", + "link_count": 0, + "link_to": "Fuel Requests", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel UOM", + "link_count": 0, + "link_to": "Fuel UOM", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fixed Expenses", + "link_count": 0, + "link_to": "Fixed Expenses", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Compliance & Logs", + "link_count": 3, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Truck and Trailer Inspection", + "link_count": 0, + "link_to": "Truck and Trailer Inspection", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Truck Log", + "link_count": 0, + "link_to": "Truck Log", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Breakdown", + "link_count": 0, + "link_to": "Trip Breakdown", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Finance & Billing", + "link_count": 5, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Quotation", + "link_count": 0, + "link_to": "Quotation", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Sales Order", + "link_count": 0, + "link_to": "Sales Order", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Sales Invoice", + "link_count": 0, + "link_to": "Sales Invoice", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Journal Entry", + "link_count": 0, + "link_to": "Journal Entry", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Requested Payment", + "link_count": 0, + "link_to": "Requested Payment", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Procurement & Stock", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Purchase Order", + "link_count": 0, + "link_to": "Purchase Order", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Purchase Receipt", + "link_count": 0, + "link_to": "Purchase Receipt", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Purchase Invoice", + "link_count": 0, + "link_to": "Purchase Invoice", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Stock Entry", + "link_count": 0, + "link_to": "Stock Entry", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Configuration", + "link_count": 3, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Transport Settings", + "link_count": 0, + "link_to": "Transport Settings", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Approval Workflows", + "link_count": 0, + "link_to": "Workflow", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Accounting Dimension", + "link_count": 0, + "link_to": "Transport Accounting Dimension", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fleet Operations", + "link_count": 3, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Vehicle Utilization", + "link_count": 0, + "link_to": "Vehicle Utilization", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Driver Assignment/Activity", + "link_count": 0, + "link_to": "Driver Activity Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fleet Availability", + "link_count": 0, + "link_to": "Fleet Availability", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Performance", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Summary", + "link_count": 0, + "link_to": "Trip Summary", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Ongoing Trips", + "link_count": 0, + "link_to": "Ongoing Trips Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Completed Trips", + "link_count": 0, + "link_to": "Completed Trips Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Turnaround / Duration", + "link_count": 0, + "link_to": "Trip Turnaround Time", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel & Cost Analysis", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel Consumption", + "link_count": 0, + "link_to": "Fuel Consumption Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fuel Requests", + "link_count": 0, + "link_to": "Pending Fuel Requests Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Fuel Cost", + "link_count": 0, + "link_to": "Trip Fuel Cost", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Fixed Expenses", + "link_count": 0, + "link_to": "Fixed Expenses Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Finance & Billing Reports", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Trip Revenue", + "link_count": 0, + "link_to": "Trip Revenue Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Requested Payments", + "link_count": 0, + "link_to": "Pending Requested Payments Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Unpaid Invoices", + "link_count": 0, + "link_to": "Unpaid Invoices Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Overdue Invoices", + "link_count": 0, + "link_to": "Overdue Invoices Report", + "link_type": "Report", + "onboard": 0, + "type": "Link" + } + ], + "modified": "2026-09-18 11:00:00.000000", + "modified_by": "Administrator", + "module": "VSD Fleet MS", + "name": "Fleet Management", + "number_cards": [ + { + "label": "Total Trucks", + "number_card_name": "Total Trucks" + }, + { + "label": "Available Truck", + "number_card_name": "Available Truck" + }, + { + "label": "Truck On Trip", + "number_card_name": "Truck On Trip" + }, + { + "label": "Total Trips", + "number_card_name": "Total Trips" + }, + { + "label": "Ongoing Trips", + "number_card_name": "Ongoing Trips" + }, + { + "label": "Completed Trips", + "number_card_name": "Completed Trips" + }, + { + "label": "Cargo Registrations", + "number_card_name": "Cargo Registrations" + }, + { + "label": "Manifest", + "number_card_name": "Manifest" + }, + { + "label": "Fuel Requests", + "number_card_name": "Fuel Requests" + }, + { + "label": "Requested Payments In Trip", + "number_card_name": "Requested Payments In Trip" + }, + { + "label": "Unpaid Sales Invoices", + "number_card_name": "Unpaid Sales Invoices" + }, + { + "label": "Overdue Sales Invoices", + "number_card_name": "Overdue Sales Invoices" + } + ], + "owner": "Administrator", + "parent_page": "", + "public": 1, + "quick_lists": [], + "roles": [], + "sequence_id": 1.0, + "shortcuts": [], + "title": "Fleet Management" +} diff --git a/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_ms/fleet_ms.json b/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_ms/fleet_ms.json deleted file mode 100644 index d92d28f..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_ms/fleet_ms.json +++ /dev/null @@ -1,319 +0,0 @@ -{ - "charts": [], - "content": "[{\"id\":\"jXwnsJvil0\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Active Trucks\",\"col\":4}},{\"id\":\"G8EkHN13E6\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Idle Trucks\",\"col\":3}},{\"id\":\"WQoT9AN7J1\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Completed Trips\",\"col\":4}},{\"id\":\"ClfVgiJBsi\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Active Trips\",\"col\":3}},{\"id\":\"q2QOU-UHg3\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Requested Payments\",\"col\":3}},{\"id\":\"zmWWdyEBaN\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Drivers\",\"col\":3}},{\"id\":\"x0AUY7DppD\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Fuel Requested\",\"col\":3}},{\"id\":\"D_r2tq24Wk\",\"type\":\"header\",\"data\":{\"text\":\"VSD Fleet\",\"col\":12}},{\"id\":\"eEKQ_vxz6K\",\"type\":\"card\",\"data\":{\"card_name\":\"Masters\",\"col\":4}},{\"id\":\"_FHA1FtdB9\",\"type\":\"card\",\"data\":{\"card_name\":\"Trips\",\"col\":4}},{\"id\":\"tiOnXE60vg\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"id\":\"fgOY4518ML\",\"type\":\"card\",\"data\":{\"card_name\":\"Transactions\",\"col\":4}},{\"id\":\"RRWILp0x3t\",\"type\":\"card\",\"data\":{\"card_name\":\"Transport Records\",\"col\":4}},{\"id\":\"Fvhi34VUqU\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]", - "creation": "2023-05-04 18:08:12.460715", - "custom_blocks": [], - "docstatus": 0, - "doctype": "Workspace", - "for_user": "", - "hide_custom": 0, - "icon": "map", - "idx": 0, - "is_hidden": 0, - "label": "Fleet MS", - "links": [ - { - "hidden": 0, - "is_query_report": 0, - "label": "Masters", - "link_count": 4, - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Truck", - "link_count": 0, - "link_to": "Truck", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trailer", - "link_count": 0, - "link_to": "Trailers", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Driver", - "link_count": 0, - "link_to": "Truck Driver", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Fuel UOM", - "link_count": 0, - "link_to": "Fuel UOM", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Settings", - "link_count": 1, - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Transport Setting", - "link_count": 0, - "link_to": "Transport Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trips", - "link_count": 5, - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trip Location", - "link_count": 0, - "link_to": "Trip Locations", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trip Location Type", - "link_count": 0, - "link_to": "Trip Locations Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Cargo Type", - "link_count": 0, - "link_to": "Cargo Types", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trip Fixed Expense", - "link_count": 0, - "link_to": "Fixed Expenses", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Truck & Trailer Inspection", - "link_count": 0, - "link_to": "Truck and Trailer Inspection", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Transport Records", - "link_count": 2, - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Manifest", - "link_count": 0, - "link_to": "Manifest", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Truck Log", - "link_count": 0, - "link_to": "Truck Log", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Reports", - "link_count": 2, - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trip Report and Expenses", - "link_count": 0, - "link_to": "Trip Report and Expenses", - "link_type": "Report", - "onboard": 0, - "report_ref_doctype": "Trips", - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 1, - "label": "Fuel Expense By Trip", - "link_count": 0, - "link_to": "Fuel Expense By Trip", - "link_type": "Report", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Transactions", - "link_count": 7, - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Cargo Registration", - "link_count": 0, - "link_to": "Cargo Registration", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Vehicle Trips", - "link_count": 0, - "link_to": "Trips", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Fuel Requests", - "link_count": 0, - "link_to": "Fuel Requests", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Requested Payment", - "link_count": 0, - "link_to": "Requested Payment", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Round Trip Details", - "link_count": 0, - "link_to": "Round Trip", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Trip Breakdown", - "link_count": 0, - "link_to": "Trip Breakdown", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Fixed Expenses", - "link_count": 0, - "link_to": "Fixed Expenses", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - } - ], - "modified": "2025-09-03 10:49:31.306934", - "modified_by": "Administrator", - "module": "VSD Fleet MS", - "name": "Fleet MS", - "number_cards": [ - { - "label": "Active Trucks", - "number_card_name": "Active Trucks" - }, - { - "label": "Completed Trips", - "number_card_name": "Completed Trips" - }, - { - "label": "Idle Trucks", - "number_card_name": "Idle Trucks" - }, - { - "label": "Active Trips", - "number_card_name": "Trucks with Pending Trips" - }, - { - "label": "Total Requested Payments", - "number_card_name": "Total Requested Payments" - }, - { - "label": "Drivers", - "number_card_name": "Active Drivers" - }, - { - "label": "Total Fuel Requested", - "number_card_name": "Total Fuel Requested" - } - ], - "owner": "arnold@vvsdtz.com", - "parent_page": "", - "public": 1, - "quick_lists": [], - "roles": [], - "sequence_id": 1.0, - "shortcuts": [], - "title": "Fleet MS" -} \ No newline at end of file From 2c65ccb58dbe38bc74940d00b114df035ddf9981 Mon Sep 17 00:00:00 2001 From: MariamMabele Date: Fri, 18 Sep 2026 11:31:37 +0300 Subject: [PATCH 2/3] fix: resolve fleet report linter checks --- .github/workflows/linter.yml | 3 +- vsd_fleet_ms/patches.txt | 3 +- vsd_fleet_ms/patches/reports/__init__.py | 1 + .../reports/remove_legacy_invoice_reports.py | 7 ++ .../sync_fleet_management_workspace.py | 7 ++ .../completed_trips_report.py | 4 +- .../driver_activity_report.py | 4 +- .../fixed_expenses_report.py | 4 +- .../fuel_consumption_report.py | 4 +- .../ongoing_trips_report.py | 4 +- .../overdue_invoices_report/__init__.py | 0 .../overdue_invoices_report.js | 14 --- .../overdue_invoices_report.json | 30 ------- .../overdue_invoices_report.py | 60 ------------- .../pending_fuel_requests_report.py | 4 +- .../pending_requested_payments_report.js | 6 +- .../pending_requested_payments_report.py | 4 +- .../report/trip_fuel_cost/trip_fuel_cost.py | 4 +- .../report/trip_invoices_report/__init__.py | 1 + .../trip_invoices_report.js | 45 ++++++++++ .../trip_invoices_report.json} | 8 +- .../trip_invoices_report.py | 86 +++++++++++++++++++ .../trip_profit_and_loss_statement.py | 4 +- .../trip_revenue_report.py | 4 +- .../trip_turnaround_time.py | 4 +- .../report/unpaid_invoices_report/__init__.py | 0 .../unpaid_invoices_report.js | 14 --- .../unpaid_invoices_report.py | 56 ------------ .../vehicle_utilization.py | 4 +- .../fleet_management/fleet_management.json | 16 +--- 30 files changed, 185 insertions(+), 220 deletions(-) create mode 100644 vsd_fleet_ms/patches/reports/__init__.py create mode 100644 vsd_fleet_ms/patches/reports/remove_legacy_invoice_reports.py create mode 100644 vsd_fleet_ms/patches/workspace/sync_fleet_management_workspace.py delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/__init__.py create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.js rename vsd_fleet_ms/vsd_fleet_ms/report/{unpaid_invoices_report/unpaid_invoices_report.json => trip_invoices_report/trip_invoices_report.json} (73%) create mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.py delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js delete mode 100644 vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 7a89735..7cdc563 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -66,5 +66,4 @@ jobs: - name: Install and run pip-audit run: | pip install pip-audit - cd ${GITHUB_WORKSPACE} - pip-audit --desc on . + pip-audit -r requirements.txt --desc on diff --git a/vsd_fleet_ms/patches.txt b/vsd_fleet_ms/patches.txt index b281a55..e3aba9d 100644 --- a/vsd_fleet_ms/patches.txt +++ b/vsd_fleet_ms/patches.txt @@ -6,4 +6,5 @@ vsd_fleet_ms.patches.custom_fields.add_cargo_id_custom_field_on_sales_invoice_it vsd_fleet_ms.patches.custom_fields.add_bill_uom_field_in_cargo_detail vsd_fleet_ms.patches.custom_fields.add_allow_bill_on_weight vsd_fleet_ms.patches.property_setters.create_property_setter_cargo_details - +vsd_fleet_ms.patches.reports.remove_legacy_invoice_reports +vsd_fleet_ms.patches.workspace.sync_fleet_management_workspace diff --git a/vsd_fleet_ms/patches/reports/__init__.py b/vsd_fleet_ms/patches/reports/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/vsd_fleet_ms/patches/reports/__init__.py @@ -0,0 +1 @@ + diff --git a/vsd_fleet_ms/patches/reports/remove_legacy_invoice_reports.py b/vsd_fleet_ms/patches/reports/remove_legacy_invoice_reports.py new file mode 100644 index 0000000..1da5bc3 --- /dev/null +++ b/vsd_fleet_ms/patches/reports/remove_legacy_invoice_reports.py @@ -0,0 +1,7 @@ +import frappe + + +def execute(): + for report in ("Unpaid Invoices Report", "Overdue Invoices Report"): + if frappe.db.exists("Report", report): + frappe.delete_doc("Report", report, force=True, ignore_permissions=True) diff --git a/vsd_fleet_ms/patches/workspace/sync_fleet_management_workspace.py b/vsd_fleet_ms/patches/workspace/sync_fleet_management_workspace.py new file mode 100644 index 0000000..f9b599f --- /dev/null +++ b/vsd_fleet_ms/patches/workspace/sync_fleet_management_workspace.py @@ -0,0 +1,7 @@ +import frappe +from frappe.modules.import_file import import_file_by_path + + +def execute(): + path = frappe.get_app_path("vsd_fleet_ms", "vsd_fleet_ms", "workspace", "fleet_management", "fleet_management.json") + import_file_by_path(path, force=True) diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py index e677776..1770f20 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/completed_trips_report/completed_trips_report.py @@ -28,10 +28,10 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT name, date, trip_completed_date, truck_number, truck_licence_plate, driver_name, route FROM `tabTrips` - WHERE trip_status = 'Completed' {conditions} + WHERE trip_status = 'Completed' """ + conditions + """ ORDER BY trip_completed_date DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py index 473a1a9..99caef2 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/driver_activity_report/driver_activity_report.py @@ -28,7 +28,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT d.name AS driver, d.full_name, @@ -38,7 +38,7 @@ def get_data(filters): (SELECT COUNT(*) FROM `tabTrips` WHERE assigned_driver = d.name AND trip_status = 'Completed') AS completed_trips, (SELECT COUNT(*) FROM `tabTrips` WHERE assigned_driver = d.name AND trip_status = 'Pending') AS pending_trips FROM `tabTruck Driver` d - WHERE 1 = 1 {conditions} + WHERE 1 = 1 """ + conditions + """ ORDER BY total_trips DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py index cae1e77..d33f5db 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fixed_expenses_report/fixed_expenses_report.py @@ -25,14 +25,14 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT expense_type, COUNT(*) AS request_count, SUM(CASE WHEN request_currency = 'TZS' THEN request_amount ELSE 0 END) AS total_tzs, SUM(CASE WHEN request_currency = 'USD' THEN request_amount ELSE 0 END) AS total_usd FROM `tabRequested Fund Details` - WHERE expense_type IS NOT NULL AND expense_type != '' {conditions} + WHERE expense_type IS NOT NULL AND expense_type != '' """ + conditions + """ GROUP BY expense_type ORDER BY total_tzs DESC """, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py index 778fd0e..cfb8b10 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/fuel_consumption_report/fuel_consumption_report.py @@ -26,7 +26,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT t.truck_number, COUNT(DISTINCT t.name) AS trip_count, @@ -36,7 +36,7 @@ def get_data(filters): FROM `tabTrips` t INNER JOIN `tabFuel Requests Table` f ON f.parent = t.name AND f.parentfield = 'fuel_request_history' - WHERE t.truck_number IS NOT NULL AND t.truck_number != '' {conditions} + WHERE t.truck_number IS NOT NULL AND t.truck_number != '' """ + conditions + """ GROUP BY t.truck_number ORDER BY total_quantity DESC """, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py index 234ad71..6ffbcf0 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/ongoing_trips_report/ongoing_trips_report.py @@ -28,10 +28,10 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT name, date, truck_number, truck_licence_plate, driver_name, route, transporter_type FROM `tabTrips` - WHERE trip_status = 'Pending' {conditions} + WHERE trip_status = 'Pending' """ + conditions + """ ORDER BY date DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js deleted file mode 100644 index a2eddc5..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Overdue Invoices Report"] = { - "filters": [ - { - "fieldname": "customer", - "label": __("Customer"), - "fieldtype": "Link", - "options": "Customer" - } - ] -}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json deleted file mode 100644 index e5682d5..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "add_total_row": 1, - "columns": [], - "creation": "2026-09-17 09:00:00.000000", - "disable_prepared_report": 0, - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "filters": [], - "idx": 0, - "is_standard": "Yes", - "json": "{}", - "modified": "2026-09-17 09:00:00.000000", - "modified_by": "Administrator", - "module": "VSD Fleet MS", - "name": "Overdue Invoices Report", - "owner": "Administrator", - "prepared_report": 0, - "ref_doctype": "Sales Invoice", - "report_name": "Overdue Invoices Report", - "report_type": "Script Report", - "roles": [ - { - "role": "System Manager" - }, - { - "role": "All" - } - ] -} diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py deleted file mode 100644 index f6dded8..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/overdue_invoices_report/overdue_invoices_report.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors -# For license information, please see license.txt - -import frappe -from frappe import _ -from frappe.utils import nowdate - - -def execute(filters=None): - filters = filters or {} - columns = get_columns() - data = get_data(filters) - return columns, data, None, None - - -def get_columns(): - return [ - {"fieldname": "name", "label": _("Sales Invoice"), "fieldtype": "Link", "options": "Sales Invoice", "width": 130}, - {"fieldname": "trip", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 120}, - {"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 160}, - {"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110}, - {"fieldname": "due_date", "label": _("Due Date"), "fieldtype": "Date", "width": 110}, - {"fieldname": "days_overdue", "label": _("Days Overdue"), "fieldtype": "Int", "width": 110}, - {"fieldname": "grand_total", "label": _("Grand Total"), "fieldtype": "Currency", "options": "currency", "width": 130}, - {"fieldname": "outstanding_amount", "label": _("Outstanding Amount"), "fieldtype": "Currency", "options": "currency", "width": 150}, - {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 90}, - ] - - -def get_data(filters): - # Only invoices booked against a fleet trip (Trip -> Cargo Registration -> Cargo Detail -> Sales Invoice) - conditions, values = get_conditions(filters) - values["today"] = nowdate() - - return frappe.db.sql( - f""" - SELECT DISTINCT - si.name, cr.trip, si.customer, si.posting_date, si.due_date, - DATEDIFF(%(today)s, si.due_date) AS days_overdue, - si.grand_total, si.outstanding_amount, si.currency - FROM `tabSales Invoice` si - INNER JOIN `tabCargo Detail` cd ON cd.invoice = si.name - INNER JOIN `tabCargo Registration` cr ON cr.name = cd.parent AND cr.trip IS NOT NULL AND cr.trip != '' - WHERE si.docstatus = 1 AND si.outstanding_amount > 0 AND si.due_date < %(today)s {conditions} - ORDER BY days_overdue DESC - """, - values, - as_dict=1, - ) - - -def get_conditions(filters): - conditions = "" - values = {} - - if filters.get("customer"): - conditions += " AND si.customer = %(customer)s" - values["customer"] = filters.get("customer") - - return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py index d40c51c..7a4495f 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_fuel_requests_report/pending_fuel_requests_report.py @@ -33,7 +33,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT fr.name AS name, COALESCE(fr.transaction_date, t.date) AS transaction_date, @@ -73,7 +73,7 @@ def get_data(filters): ), 0) AS requested_cost_usd FROM `tabFuel Requests` fr LEFT JOIN `tabTrips` t ON fr.reference_doctype = 'Trips' AND fr.reference_docname = t.name - WHERE fr.status != 'Fully Processed' {conditions} + WHERE fr.status != 'Fully Processed' """ + conditions + """ ORDER BY transaction_date DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js index 96fd5fb..6fc45cc 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.js @@ -7,12 +7,14 @@ frappe.query_reports["Pending Requested Payments Report"] = { { "fieldname": "from_date", "label": __("From Date"), - "fieldtype": "Date" + "fieldtype": "Date", + "default": frappe.datetime.month_start() }, { "fieldname": "to_date", "label": __("To Date"), - "fieldtype": "Date" + "fieldtype": "Date", + "default": frappe.datetime.now_date() }, { "fieldname": "truck_no", diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py index b684115..d2450c9 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/pending_requested_payments_report/pending_requested_payments_report.py @@ -31,7 +31,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT rp.name AS reference, rp.request_date, @@ -52,7 +52,7 @@ def get_data(filters): WHERE parenttype = rp.reference_doctype AND parent = rp.reference_docname AND request_currency = 'TZS' ) AS requested_tzs FROM `tabRequested Payment` rp - WHERE rp.payment_status != 'Paid' {conditions} + WHERE rp.payment_status != 'Paid' """ + conditions + """ ORDER BY rp.request_date DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py index 1ec6fea..ca142d9 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py @@ -39,7 +39,7 @@ def get_data(filters): conditions, values = get_conditions(filters) rows = frappe.db.sql( - f""" + """ SELECT T.name AS vehicle_trip, T.date, T.driver_name, T.truck_number, T.transporter_type, T.trip_status, T.route, @@ -47,7 +47,7 @@ def get_data(filters): FL.disbursement_type, FL.supplier, FL.status, FL.approved_by, FL.approved_date FROM `tabTrips` T INNER JOIN `tabFuel Requests Table` FL ON FL.parent = T.name AND FL.parentfield = 'fuel_request_history' - WHERE 1 = 1 {conditions} + WHERE 1 = 1 """ + conditions + """ ORDER BY T.date DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/__init__.py @@ -0,0 +1 @@ + diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.js new file mode 100644 index 0000000..eb60055 --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.js @@ -0,0 +1,45 @@ +// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Trip Invoices Report"] = { + filters: [ + { + fieldname: "invoice_status", + label: __("Invoice Status"), + fieldtype: "Select", + options: "All\nPending\nOverdue\nPaid", + default: "All" + }, + { + fieldname: "customer", + label: __("Customer"), + fieldtype: "Link", + options: "Customer" + }, + { + fieldname: "trip", + label: __("Trip"), + fieldtype: "Link", + options: "Trips" + }, + { + fieldname: "cargo_registration", + label: __("Cargo Registration"), + fieldtype: "Link", + options: "Cargo Registration" + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + default: frappe.datetime.month_start() + }, + { + fieldname: "to_date", + label: __("To Date"), + fieldtype: "Date", + default: frappe.datetime.now_date() + } + ] +}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json similarity index 73% rename from vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json rename to vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json index fbedb4b..cf4c02f 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.json +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json @@ -1,7 +1,7 @@ { "add_total_row": 1, "columns": [], - "creation": "2026-09-17 09:00:00.000000", + "creation": "2026-09-18 12:00:00.000000", "disable_prepared_report": 0, "disabled": 0, "docstatus": 0, @@ -10,14 +10,14 @@ "idx": 0, "is_standard": "Yes", "json": "{}", - "modified": "2026-09-17 09:00:00.000000", + "modified": "2026-09-18 12:00:00.000000", "modified_by": "Administrator", "module": "VSD Fleet MS", - "name": "Unpaid Invoices Report", + "name": "Trip Invoices Report", "owner": "Administrator", "prepared_report": 0, "ref_doctype": "Sales Invoice", - "report_name": "Unpaid Invoices Report", + "report_name": "Trip Invoices Report", "report_type": "Script Report", "roles": [ { diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.py new file mode 100644 index 0000000..ea93d1a --- /dev/null +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.py @@ -0,0 +1,86 @@ +import frappe +from frappe import _ +from frappe.utils import nowdate + + +def execute(filters=None): + filters = filters or {} + return get_columns(), get_data(filters) + + +def get_columns(): + return [ + {"fieldname": "name", "label": _("Sales Invoice"), "fieldtype": "Link", "options": "Sales Invoice", "width": 130}, + {"fieldname": "invoice_status", "label": _("Status"), "fieldtype": "Data", "width": 100}, + {"fieldname": "trip", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 120}, + {"fieldname": "cargo_registration", "label": _("Cargo Registration"), "fieldtype": "Link", "options": "Cargo Registration", "width": 150}, + {"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 160}, + {"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "due_date", "label": _("Due Date"), "fieldtype": "Date", "width": 110}, + {"fieldname": "days_overdue", "label": _("Days Overdue"), "fieldtype": "Int", "width": 110}, + {"fieldname": "grand_total", "label": _("Grand Total"), "fieldtype": "Currency", "options": "currency", "width": 130}, + {"fieldname": "outstanding_amount", "label": _("Outstanding Amount"), "fieldtype": "Currency", "options": "currency", "width": 150}, + {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 90}, + ] + + +def get_data(filters): + conditions, values = get_conditions(filters) + values["today"] = nowdate() + + return frappe.db.sql( + """ + SELECT DISTINCT + si.name, + CASE + WHEN si.outstanding_amount = 0 THEN 'Paid' + WHEN si.due_date < %(today)s THEN 'Overdue' + ELSE 'Pending' + END AS invoice_status, + cr.trip, + cr.name AS cargo_registration, + si.customer, si.posting_date, si.due_date, + GREATEST(DATEDIFF(%(today)s, si.due_date), 0) AS days_overdue, + si.grand_total, si.outstanding_amount, si.currency + FROM `tabSales Invoice` si + INNER JOIN `tabCargo Detail` cd ON cd.invoice = si.name + INNER JOIN `tabCargo Registration` cr ON cr.name = cd.parent + WHERE si.docstatus = 1 + """ + + conditions + + """ + ORDER BY si.due_date ASC + """, + values, + as_dict=1, + ) + + +def get_conditions(filters): + conditions = "" + values = {} + + if filters.get("invoice_status") == "Pending": + conditions += " AND si.outstanding_amount > 0 AND si.due_date >= %(today)s" + elif filters.get("invoice_status") == "Overdue": + conditions += " AND si.outstanding_amount > 0 AND si.due_date < %(today)s" + elif filters.get("invoice_status") == "Paid": + conditions += " AND si.outstanding_amount = 0" + + for field, condition in ( + ("customer", " AND si.customer = %(customer)s"), + ("trip", " AND cr.trip = %(trip)s"), + ("cargo_registration", " AND cr.name = %(cargo_registration)s"), + ): + if filters.get(field): + conditions += condition + values[field] = filters[field] + + if filters.get("from_date"): + conditions += " AND si.posting_date >= %(from_date)s" + values["from_date"] = filters["from_date"] + if filters.get("to_date"): + conditions += " AND si.posting_date <= %(to_date)s" + values["to_date"] = filters["to_date"] + + return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py index 93b0b58..2e94079 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_profit_and_loss_statement/trip_profit_and_loss_statement.py @@ -38,7 +38,7 @@ def get_data(filters): conditions, values = get_conditions(filters) rows = frappe.db.sql( - f""" + """ SELECT `tabTrips`.name AS reference, `tabTrips`.date AS posting_date, @@ -80,7 +80,7 @@ def get_data(filters): WHERE parenttype = 'Trips' AND parentfield = 'fuel_request_history' AND parent = `tabTrips`.name AND currency = 'TZS' ) AS fuel_expenses_tzs FROM `tabTrips` - WHERE 1 = 1 {conditions} + WHERE 1 = 1 """ + conditions + """ """, values, as_dict=1, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py index 29e9639..a9ba215 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_revenue_report/trip_revenue_report.py @@ -28,7 +28,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT t.name AS reference, t.date, @@ -40,7 +40,7 @@ def get_data(filters): INNER JOIN `tabCargo Registration` cr ON cr.trip = t.name INNER JOIN `tabCargo Detail` cd ON cd.parent = cr.name AND cd.invoice IS NOT NULL AND cd.invoice != '' INNER JOIN `tabSales Invoice` si ON si.name = cd.invoice AND si.docstatus = 1 - WHERE 1 = 1 {conditions} + WHERE 1 = 1 """ + conditions + """ GROUP BY t.name ORDER BY t.date DESC """, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py index 1b8020a..d5d0c74 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_turnaround_time/trip_turnaround_time.py @@ -28,12 +28,12 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT name, truck_number, driver_name, route, date, trip_completed_date, DATEDIFF(trip_completed_date, date) AS days_taken FROM `tabTrips` - WHERE trip_status = 'Completed' AND date IS NOT NULL AND trip_completed_date IS NOT NULL {conditions} + WHERE trip_status = 'Completed' AND date IS NOT NULL AND trip_completed_date IS NOT NULL """ + conditions + """ ORDER BY days_taken DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js deleted file mode 100644 index f185ac5..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Unpaid Invoices Report"] = { - "filters": [ - { - "fieldname": "customer", - "label": __("Customer"), - "fieldtype": "Link", - "options": "Customer" - } - ] -}; diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py b/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py deleted file mode 100644 index 5a464d6..0000000 --- a/vsd_fleet_ms/vsd_fleet_ms/report/unpaid_invoices_report/unpaid_invoices_report.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2026, VV SYSTEMS DEVELOPER LTD and contributors -# For license information, please see license.txt - -import frappe -from frappe import _ - - -def execute(filters=None): - filters = filters or {} - columns = get_columns() - data = get_data(filters) - return columns, data, None, None - - -def get_columns(): - return [ - {"fieldname": "name", "label": _("Sales Invoice"), "fieldtype": "Link", "options": "Sales Invoice", "width": 130}, - {"fieldname": "trip", "label": _("Trip"), "fieldtype": "Link", "options": "Trips", "width": 120}, - {"fieldname": "customer", "label": _("Customer"), "fieldtype": "Link", "options": "Customer", "width": 160}, - {"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110}, - {"fieldname": "due_date", "label": _("Due Date"), "fieldtype": "Date", "width": 110}, - {"fieldname": "grand_total", "label": _("Grand Total"), "fieldtype": "Currency", "options": "currency", "width": 130}, - {"fieldname": "outstanding_amount", "label": _("Outstanding Amount"), "fieldtype": "Currency", "options": "currency", "width": 150}, - {"fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 90}, - ] - - -def get_data(filters): - # Only invoices booked against a fleet trip (Trip -> Cargo Registration -> Cargo Detail -> Sales Invoice) - conditions, values = get_conditions(filters) - - return frappe.db.sql( - f""" - SELECT DISTINCT - si.name, cr.trip, si.customer, si.posting_date, si.due_date, - si.grand_total, si.outstanding_amount, si.currency - FROM `tabSales Invoice` si - INNER JOIN `tabCargo Detail` cd ON cd.invoice = si.name - INNER JOIN `tabCargo Registration` cr ON cr.name = cd.parent AND cr.trip IS NOT NULL AND cr.trip != '' - WHERE si.docstatus = 1 AND si.outstanding_amount > 0 {conditions} - ORDER BY si.due_date ASC - """, - values, - as_dict=1, - ) - - -def get_conditions(filters): - conditions = "" - values = {} - - if filters.get("customer"): - conditions += " AND si.customer = %(customer)s" - values["customer"] = filters.get("customer") - - return conditions, values diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py index 2f3d9ac..a622d42 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/vehicle_utilization/vehicle_utilization.py @@ -28,7 +28,7 @@ def get_data(filters): conditions, values = get_conditions(filters) return frappe.db.sql( - f""" + """ SELECT t.name AS truck, t.truck_number, @@ -38,7 +38,7 @@ def get_data(filters): (SELECT COUNT(*) FROM `tabTrips` WHERE truck_number = t.name AND trip_status = 'Breakdown') AS breakdown_trips, (SELECT MAX(date) FROM `tabTrips` WHERE truck_number = t.name) AS last_trip_date FROM `tabTruck` t - WHERE 1 = 1 {conditions} + WHERE 1 = 1 """ + conditions + """ ORDER BY total_trips DESC """, values, diff --git a/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json b/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json index 3c815eb..a4736e6 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json +++ b/vsd_fleet_ms/vsd_fleet_ms/workspace/fleet_management/fleet_management.json @@ -16,7 +16,7 @@ "hidden": 0, "is_query_report": 0, "label": "Fleet & Drivers", - "link_count": 4, + "link_count": 3, "onboard": 0, "type": "Card Break" }, @@ -561,19 +561,9 @@ { "hidden": 0, "is_query_report": 0, - "label": "Unpaid Invoices", - "link_count": 0, - "link_to": "Unpaid Invoices Report", - "link_type": "Report", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Overdue Invoices", + "label": "Trip Invoices", "link_count": 0, - "link_to": "Overdue Invoices Report", + "link_to": "Trip Invoices Report", "link_type": "Report", "onboard": 0, "type": "Link" From aeec46f12e641eef954261c53b3482f8e82d80f3 Mon Sep 17 00:00:00 2001 From: MariamMabele Date: Fri, 18 Sep 2026 12:06:41 +0300 Subject: [PATCH 3/3] fix: resolve fleet report semgrep findings --- .../report/trip_fuel_cost/trip_fuel_cost.json | 5 ++- .../report/trip_fuel_cost/trip_fuel_cost.py | 36 +++++++++---------- .../trip_invoices_report.json | 5 ++- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json index 2ede687..f203053 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.json @@ -23,7 +23,10 @@ "role": "System Manager" }, { - "role": "All" + "role": "Fleet Manager" + }, + { + "role": "Accounts User" } ] } diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py index ca142d9..11d34f2 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_fuel_cost/trip_fuel_cost.py @@ -14,24 +14,24 @@ def execute(filters=None): def get_columns(): return [ - {"fieldname": "vehicle_trip", "fieldtype": "Link", "label": "Vehicle Trip", "options": "Trips"}, - {"fieldname": "date", "fieldtype": "Date", "label": "Trip Date"}, - {"fieldname": "driver_name", "fieldtype": "Data", "label": "Driver Name"}, - {"fieldname": "truck_number", "fieldtype": "Data", "label": "Truck Number"}, - {"fieldname": "transporter_type", "fieldtype": "Data", "label": "Transporter Type"}, - {"fieldname": "trip_status", "fieldtype": "Data", "label": "Trip Status"}, - {"fieldname": "route", "fieldtype": "Link", "label": "Route", "options": "Trip Routes"}, - {"fieldname": "item_name", "fieldtype": "Data", "label": "Item Name"}, - {"fieldname": "uom", "fieldtype": "Data", "label": "UOM"}, - {"fieldname": "quantity", "fieldtype": "Float", "label": "Quantity"}, - {"fieldname": "cost_per_litre", "fieldtype": "Float", "label": "Cost Per Litre"}, - {"fieldname": "currency", "fieldtype": "Link", "label": "Currency", "options": "Currency"}, - {"fieldname": "total_cost", "fieldtype": "Currency", "label": "Total Cost", "options": "currency"}, - {"fieldname": "disbursement_type", "fieldtype": "Data", "label": "Disbursement Type"}, - {"fieldname": "supplier", "fieldtype": "Link", "label": "Supplier", "options": "Supplier"}, - {"fieldname": "status", "fieldtype": "Data", "label": "Status"}, - {"fieldname": "approved_by", "fieldtype": "Data", "label": "Approved By"}, - {"fieldname": "approved_date", "fieldtype": "Date", "label": "Approved Date"}, + {"fieldname": "vehicle_trip", "fieldtype": "Link", "label": _("Vehicle Trip"), "options": "Trips"}, + {"fieldname": "date", "fieldtype": "Date", "label": _("Trip Date")}, + {"fieldname": "driver_name", "fieldtype": "Data", "label": _("Driver Name")}, + {"fieldname": "truck_number", "fieldtype": "Data", "label": _("Truck Number")}, + {"fieldname": "transporter_type", "fieldtype": "Data", "label": _("Transporter Type")}, + {"fieldname": "trip_status", "fieldtype": "Data", "label": _("Trip Status")}, + {"fieldname": "route", "fieldtype": "Link", "label": _("Route"), "options": "Trip Routes"}, + {"fieldname": "item_name", "fieldtype": "Data", "label": _("Item Name")}, + {"fieldname": "uom", "fieldtype": "Data", "label": _("UOM")}, + {"fieldname": "quantity", "fieldtype": "Float", "label": _("Quantity")}, + {"fieldname": "cost_per_litre", "fieldtype": "Float", "label": _("Cost Per Litre")}, + {"fieldname": "currency", "fieldtype": "Link", "label": _("Currency"), "options": "Currency"}, + {"fieldname": "total_cost", "fieldtype": "Currency", "label": _("Total Cost"), "options": "currency"}, + {"fieldname": "disbursement_type", "fieldtype": "Data", "label": _("Disbursement Type")}, + {"fieldname": "supplier", "fieldtype": "Link", "label": _("Supplier"), "options": "Supplier"}, + {"fieldname": "status", "fieldtype": "Data", "label": _("Status")}, + {"fieldname": "approved_by", "fieldtype": "Data", "label": _("Approved By")}, + {"fieldname": "approved_date", "fieldtype": "Date", "label": _("Approved Date")}, ] diff --git a/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json index cf4c02f..a87d18e 100644 --- a/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json +++ b/vsd_fleet_ms/vsd_fleet_ms/report/trip_invoices_report/trip_invoices_report.json @@ -24,7 +24,10 @@ "role": "System Manager" }, { - "role": "All" + "role": "Fleet Manager" + }, + { + "role": "Accounts User" } ] }