Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(transport): make vehicle a useful logistical doctype for VRP solvers #37321

Closed
wants to merge 8 commits into from
1 change: 1 addition & 0 deletions erpnext/patches.txt
Expand Up @@ -260,6 +260,7 @@ erpnext.patches.v15_0.delete_saudi_doctypes
erpnext.patches.v14_0.show_loan_management_deprecation_warning
erpnext.patches.v14_0.clear_reconciliation_values_from_singles
execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
erpnext.patches.v15_0.rename_vehicle_to_transport

[post_model_sync]
execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
Expand Down
11 changes: 11 additions & 0 deletions erpnext/patches/v15_0/rename_vehicle_to_transport.py
@@ -0,0 +1,11 @@
import frappe
from frappe.model.utils.rename_field import rename_field


def execute():
rename_field("Vehicle", "license_plate", "identifier")
rename_field("Vehicle", "vehicle_value", "transport_value")
rename_field("Vehicle", "make", "manufacturer")
rename_field("Vehicle", "chassis_no", "serial_no")
frappe.rename_doc("DocType", "Vehicle", "Transport", force=True)
rename_field("Delivery Trip", "vehicle", "transport")
29 changes: 29 additions & 0 deletions erpnext/setup/demo_data/transport_logistic_feature.json
@@ -0,0 +1,29 @@
[
{
"description": "Transport can reach Zone A",
"docstatus": 0,
"doctype": "Transport Logistic Feature",
"modified": "2023-11-18 14:37:04.835369",
"name": "Zone A",
"taint": 0,
"title": "Zone A"
},
{
"description": "Transport can reach Zone B",
"docstatus": 0,
"doctype": "Transport Logistic Feature",
"modified": "2023-11-18 14:37:10.701509",
"name": "Zone B",
"taint": 0,
"title": "Zone B"
},
{
"description": "Transport has freezer capacity installed.",
"docstatus": 0,
"doctype": "Transport Logistic Feature",
"modified": "2023-11-18 14:36:42.553773",
"name": "Freezer",
"taint": 0,
"title": "Freezer"
}
]
Expand Up @@ -9,19 +9,18 @@
# test_records = frappe.get_test_records('Vehicle')


class TestVehicle(unittest.TestCase):
def test_make_vehicle(self):
class TestTransport(unittest.TestCase):
def test_make_transport(self):
vehicle = frappe.get_doc(
{
"doctype": "Vehicle",
"license_plate": random_string(10).upper(),
"make": "Maruti",
"doctype": "Transport",
"idenifier": random_string(10).upper(),
"manufacturer": "Maruti",
"model": "PCM",
"last_odometer": 5000,
"acquisition_date": frappe.utils.nowdate(),
"location": "Mumbai",
"chassis_no": "1234ABCD",
"uom": "Litre",
"serial_no": "1234ABCD",
"vehicle_value": frappe.utils.flt(500000),
}
)
Expand Down
@@ -1,7 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Vehicle', {
frappe.ui.form.on('Transport', {
refresh: function(frm) {

}
Expand Down
263 changes: 263 additions & 0 deletions erpnext/setup/doctype/transport/transport.json
@@ -0,0 +1,263 @@
{
"actions": [],
"autoname": "field:identifier",
"creation": "2016-09-03 03:33:27.680331",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"identifier",
"transport_mode",
"propulsion",
"location",
"column_break_3",
"manufacturer",
"model",
"serial_no",
"fuel_type",
"column_break_8",
"acquisition_date",
"last_odometer",
"transport_value",
"driver",
"routing_problem_parameters_section",
"avg_speed",
"avg_cost",
"trip_setup_cost",
"column_break_kqde",
"logistic_features",
"volume_capacity",
"weight_capacity",
"insurance_details",
"insurance_company",
"policy_no",
"column_break_15",
"start_date",
"end_date"
],
"fields": [
{
"depends_on": "eval: doc.transport_mode !== \"Pipeline\"",
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"allow_in_quick_entry": 1,
"fieldname": "model",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Model"
},
{
"depends_on": "eval: [\"Engine\", \"Hybride\"].includes(doc.propulsion)",
"fieldname": "last_odometer",
"fieldtype": "Int",
"label": "Odometer Value (Last)",
"no_copy": 1,
"set_only_once": 1
},
{
"fieldname": "acquisition_date",
"fieldtype": "Date",
"label": "Acquisition Date"
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
},
{
"fieldname": "transport_value",
"fieldtype": "Currency",
"label": "Value",
"print_hide_if_no_value": 1
},
{
"collapsible": 1,
"fieldname": "insurance_details",
"fieldtype": "Section Break",
"label": "Insurance Details"
},
{
"fieldname": "insurance_company",
"fieldtype": "Data",
"label": "Insurance Company"
},
{
"fieldname": "policy_no",
"fieldtype": "Data",
"label": "Policy No"
},
{
"fieldname": "column_break_15",
"fieldtype": "Column Break"
},
{
"fieldname": "start_date",
"fieldtype": "Date",
"label": "Start Date"
},
{
"fieldname": "end_date",
"fieldtype": "Date",
"label": "End Date"
},
{
"depends_on": "eval: [\"Engine\", \"Hybride\"].includes(doc.propulsion)",
"fieldname": "fuel_type",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Fuel Type",
"options": "\nGasoline\nDiesel\nNatural Gas\nElectric\nHeavy Fuel\nKerosene\nOther"
},
{
"description": "e.g. license plate for motor vehicles",
"fieldname": "identifier",
"fieldtype": "Data",
"label": "Identifier",
"no_copy": 1,
"reqd": 1,
"unique": 1
},
{
"default": "Road",
"documentation_url": "https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Glossary:Transport_mode",
"fieldname": "transport_mode",
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Mode",
"options": "Road\nRail\nMaritime\nInland Waterways\nAir\nPipeline",
"reqd": 1
},
{
"allow_in_quick_entry": 1,
"default": "Engine",
"depends_on": "eval: doc.transport_mode !== \"Pipeline\"",
"fieldname": "propulsion",
"fieldtype": "Select",
"label": "Propulsion",
"options": "\nEngine\nElectric\nHuman\nAnimal\nHybrid"
},
{
"fieldname": "manufacturer",
"fieldtype": "Data",
"label": "Manufacturer"
},
{
"description": "e.g. chassis number",
"fieldname": "serial_no",
"fieldtype": "Data",
"label": "Serial"
},
{
"description": "meter / second",
"fieldname": "avg_speed",
"fieldtype": "Float",
"label": "Average Speed",
"non_negative": 1
},
{
"description": "cost unit / km",
"fieldname": "avg_cost",
"fieldtype": "Float",
"label": "Average Cost"
},
{
"fieldname": "column_break_kqde",
"fieldtype": "Column Break"
},
{
"description": "cost unit",
"fieldname": "trip_setup_cost",
"fieldtype": "Float",
"label": "Trip Setup Cost"
},
{
"description": "to be used as positive/negative constraints in a VRP solver",
"fieldname": "logistic_features",
"fieldtype": "Table MultiSelect",
"label": "Features",
"options": "Transport Features"
},
{
"description": "liter",
"fieldname": "volume_capacity",
"fieldtype": "Float",
"label": "Volume Capacity"
},
{
"description": "kg",
"fieldname": "weight_capacity",
"fieldtype": "Float",
"label": "Weight Capacity"
},
{
"fieldname": "routing_problem_parameters_section",
"fieldtype": "Section Break",
"label": "Routing Problem Parameters"
},
{
"allow_in_quick_entry": 1,
"depends_on": "eval: doc.transport_mode !== \"Pipeline\";",
"fieldname": "location",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Location",
"options": "Address"
},
{
"fieldname": "driver",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Driver",
"options": "Driver"
}
],
"links": [],
"modified": "2023-11-18 15:34:43.240533",
"modified_by": "Administrator",
"module": "Setup",
"name": "Transport",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Fleet Manager",
"share": 1,
"write": 1
},
{
"print": 1,
"read": 1,
"report": 1,
"role": "Delivery User"
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Delivery Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"search_fields": "identifier,location,model",
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "identifier",
"track_changes": 1
}
Expand Up @@ -8,7 +8,7 @@
from frappe.utils import getdate


class Vehicle(Document):
class Transport(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.

Expand All @@ -20,27 +20,25 @@ class Vehicle(Document):
acquisition_date: DF.Date | None
amended_from: DF.Link | None
carbon_check_date: DF.Date | None
chassis_no: DF.Data | None
serial_no: DF.Data | None
color: DF.Data | None
doors: DF.Int
employee: DF.Link | None
end_date: DF.Date | None
fuel_type: DF.Literal["Petrol", "Diesel", "Natural Gas", "Electric"]
insurance_company: DF.Data | None
last_odometer: DF.Int
license_plate: DF.Data
identifier: DF.Data
location: DF.Data | None
make: DF.Data
manufacturer: DF.Data
model: DF.Data
policy_no: DF.Data | None
start_date: DF.Date | None
uom: DF.Link
vehicle_value: DF.Currency
transport_value: DF.Currency
wheels: DF.Int
# end: auto-generated types

def validate(self):
if getdate(self.start_date) > getdate(self.end_date):
frappe.throw(_("Insurance Start date should be less than Insurance End date"))
if getdate(self.carbon_check_date) > getdate():
frappe.throw(_("Last carbon check date cannot be a future date"))
Expand Up @@ -5,6 +5,6 @@
def get_data():
return {
"fieldname": "license_plate",
"non_standard_fieldnames": {"Delivery Trip": "vehicle"},
"transactions": [{"items": ["Vehicle Log"]}, {"items": ["Delivery Trip"]}],
"non_standard_fieldnames": {"Delivery Trip": "transport"},
"transactions": [{"items": ["Transport Log"]}, {"items": ["Delivery Trip"]}],
}