Update Delivery Trip status based on visited stops (#15723)
* feat(delivery_trip_status): Update Delivery Trip status based on visited stops
* feat(delivery_trip_status): Fix tests
* feat(delivery_trip_status): Fix allow on submit for status
* feat(delivery_trip_status): Change status mapping
* feat(delivery_trip_status): Fix patch
* Update update_delivery_trip_status.py
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
old mode 100644
new mode 100755
index 19857d2..1f231e6
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -576,3 +576,4 @@
erpnext.patches.v11_0.drop_column_max_days_allowed
erpnext.patches.v11_0.change_healthcare_desktop_icons
erpnext.patches.v10_0.update_user_image_in_employee
+erpnext.patches.v11_0.update_delivery_trip_status
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py
new file mode 100755
index 0000000..64b3063
--- /dev/null
+++ b/erpnext/patches/v11_0/update_delivery_trip_status.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('stock', 'doctype', 'delivery_trip')
+ frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
+
+ for trip in frappe.get_all("Delivery Trip"):
+ trip_doc = frappe.get_doc("Delivery Trip", trip.name)
+
+ status = {
+ 0: "Draft",
+ 1: "Scheduled",
+ 2: "Cancelled"
+ }[trip_doc.docstatus]
+
+ if trip_doc.docstatus == 1:
+ visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
+ if all(visited_stops):
+ status = "Completed"
+ elif any(visited_stops):
+ status = "In Transit"
+
+ frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
diff --git a/erpnext/stock/doctype/delivery_stop/delivery_stop.json b/erpnext/stock/doctype/delivery_stop/delivery_stop.json
index 7bce72d..5610a81 100644
--- a/erpnext/stock/doctype/delivery_stop/delivery_stop.json
+++ b/erpnext/stock/doctype/delivery_stop/delivery_stop.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -176,6 +177,39 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
+ "allow_on_submit": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:doc.docstatus==1",
+ "fieldname": "visited",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Visited",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -762,7 +796,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-10-11 22:32:27.450906",
+ "modified": "2018-10-16 05:23:25.661542",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Stop",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index a38c6d7..a9e2f88 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -3,6 +3,8 @@
frappe.ui.form.on('Delivery Trip', {
setup: function (frm) {
+ frm.set_indicator_formatter('customer', (stop) => (stop.visited) ? "green" : "orange");
+
frm.set_query("driver", function () {
return {
filters: {
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
index a9236e8..1d32ecd 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -540,7 +541,7 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -575,6 +576,70 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Draft\nScheduled\nIn Transit\nCompleted\nCancelled",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "cb_more_info",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -611,7 +676,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-10-11 22:32:04.355068",
+ "modified": "2018-10-22 08:25:42.323147",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Trip",
@@ -663,6 +728,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "driver_name",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index 431eb6c..01b4734 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -27,9 +27,14 @@
self.validate_stop_addresses()
def on_submit(self):
+ self.update_status()
self.update_delivery_notes()
+ def on_update_after_submit(self):
+ self.update_status()
+
def on_cancel(self):
+ self.update_status()
self.update_delivery_notes(delete=True)
def validate_stop_addresses(self):
@@ -37,6 +42,22 @@
if not stop.customer_address:
stop.customer_address = get_address_display(frappe.get_doc("Address", stop.address).as_dict())
+ def update_status(self):
+ status = {
+ 0: "Draft",
+ 1: "Scheduled",
+ 2: "Cancelled"
+ }[self.docstatus]
+
+ if self.docstatus == 1:
+ visited_stops = [stop.visited for stop in self.delivery_stops]
+ if all(visited_stops):
+ status = "Completed"
+ elif any(visited_stops):
+ status = "In Transit"
+
+ self.db_set("status", status)
+
def update_delivery_notes(self, delete=False):
"""
Update all connected Delivery Notes with Delivery Trip details
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js
new file mode 100644
index 0000000..1d198b7
--- /dev/null
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js
@@ -0,0 +1,12 @@
+frappe.listview_settings['Delivery Trip'] = {
+ add_fields: ["status"],
+ get_indicator: function (doc) {
+ if (in_list(["Cancelled", "Draft"], doc.status)) {
+ return [__(doc.status), "red", "status,=," + doc.status];
+ } else if (in_list(["In Transit", "Scheduled"], doc.status)) {
+ return [__(doc.status), "orange", "status,=," + doc.status];
+ } else if (doc.status === "Completed") {
+ return [__(doc.status), "green", "status,=," + doc.status];
+ }
+ }
+};
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
index b0a3d31..76b6fcd 100644
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
@@ -9,7 +9,7 @@
import frappe
from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers
from erpnext.tests.utils import create_test_contact_and_address
-from frappe.utils import add_days, now_datetime
+from frappe.utils import add_days, flt, now_datetime, nowdate
class TestDeliveryTrip(unittest.TestCase):
@@ -72,6 +72,33 @@
self.assertEqual(len(route_list[0]), 2) # [home_address, locked_stop]
self.assertEqual(len(route_list[1]), 3) # [locked_stop, second_stop, home_address]
+ def test_delivery_trip_status_draft(self):
+ self.assertEqual(self.delivery_trip.status, "Draft")
+
+ def test_delivery_trip_status_scheduled(self):
+ self.delivery_trip.submit()
+ self.assertEqual(self.delivery_trip.status, "Scheduled")
+
+ def test_delivery_trip_status_cancelled(self):
+ self.delivery_trip.submit()
+ self.delivery_trip.cancel()
+ self.assertEqual(self.delivery_trip.status, "Cancelled")
+
+ def test_delivery_trip_status_in_transit(self):
+ self.delivery_trip.submit()
+ self.delivery_trip.delivery_stops[0].visited = 1
+ self.delivery_trip.save()
+ self.assertEqual(self.delivery_trip.status, "In Transit")
+
+ def test_delivery_trip_status_completed(self):
+ self.delivery_trip.submit()
+
+ for stop in self.delivery_trip.delivery_stops:
+ stop.visited = 1
+
+ self.delivery_trip.save()
+ self.assertEqual(self.delivery_trip.status, "Completed")
+
def create_driver():
if not frappe.db.exists("Driver", "Newton Scmander"):
@@ -108,11 +135,11 @@
"make": "Maruti",
"model": "PCM",
"last_odometer": 5000,
- "acquisition_date": frappe.utils.nowdate(),
+ "acquisition_date": nowdate(),
"location": "Mumbai",
"chassis_no": "1234ABCD",
"uom": "Litre",
- "vehicle_value": frappe.utils.flt(500000)
+ "vehicle_value": flt(500000)
})
vehicle.insert()