Multiple delivery dates in Sales Order and make DN based on selected delivery dates (#9933)

* Multiple delivery dates in Sales Order and make DN based on selected delivery dates

* Test case and some other minor fixes

* Updated docs for multi delivery date

* removed the trailing whitespace

* removed the trailing whitespace

* removed trailing whitespace
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index b88623b..005abe6 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -289,7 +289,7 @@
 			credit_days_based_on, credit_days = \
 				frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])
 
-	if not (credit_days_based_on and credit_days):
+	if not credit_days_based_on:
 		credit_days_based_on, credit_days = \
 			frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
 
diff --git a/erpnext/controllers/tests/test_recurring_document.py b/erpnext/controllers/tests/test_recurring_document.py
index d47c5c7..e218fa6 100644
--- a/erpnext/controllers/tests/test_recurring_document.py
+++ b/erpnext/controllers/tests/test_recurring_document.py
@@ -27,7 +27,8 @@
 	base_doc.set(date_field, today)
 
 	if base_doc.doctype == "Sales Order":
-		base_doc.set("delivery_date", add_days(today, 15))
+		for d in base_doc.get("items"):
+			d.set("delivery_date", add_days(today, 15))
 
 	# monthly
 	doc1 = frappe.copy_doc(base_doc)
diff --git a/erpnext/demo/user/sales.py b/erpnext/demo/user/sales.py
index ddd36ef..666e201 100644
--- a/erpnext/demo/user/sales.py
+++ b/erpnext/demo/user/sales.py
@@ -118,7 +118,8 @@
 		from erpnext.selling.doctype.quotation.quotation import make_sales_order
 		so = frappe.get_doc(make_sales_order(q))
 		so.transaction_date = frappe.flags.current_date
-		so.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10)
+		for d in so.get("items"):
+			d.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10)
 		so.insert()
 		frappe.db.commit()
 		so.submit()
diff --git a/erpnext/docs/assets/img/selling/make-so.gif b/erpnext/docs/assets/img/selling/make-so.gif
index 5edd19b..0e568a8 100644
--- a/erpnext/docs/assets/img/selling/make-so.gif
+++ b/erpnext/docs/assets/img/selling/make-so.gif
Binary files differ
diff --git a/erpnext/docs/user/manual/en/selling/sales-order.md b/erpnext/docs/user/manual/en/selling/sales-order.md
index 99b9a85..b103038 100644
--- a/erpnext/docs/user/manual/en/selling/sales-order.md
+++ b/erpnext/docs/user/manual/en/selling/sales-order.md
@@ -31,7 +31,7 @@
 There are a few amongst other things that a Sales Order will ask you to
 update.
 
-  * Expected date of delivery.
+  * Enter delivery date agaist each item. If there are multiple items and if you enter delivery date in the first row, the date will be copied to other rows as well where it is blank.
   * Customer Purchase Order number: If your customer has sent you a Purchase Order, you can update its number for future reference (in billing).
 
 ### Packing List
@@ -89,9 +89,9 @@
 Once you “Submit” your Sales Order, you can now trigger different aspects of
 your organization:
 
-  * To begin purchase click on “Make Purchase Request”
-  * To make a shipment entry click on “Make Delivery Note”
-  * To bill, make “Make Sales Invoice”
+  * To begin purchase click on Make -> Purchase Request
+  * To make a shipment entry click on Make -> Delivery Note. You can also make Delivery Note for selected items based on delivery date.
+  * To bill, make Make -> Sales Invoice
   * To stop further process on this Sales Order, click on “Stop”
 
 ### Submission
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js
index 657819a..c61eec6 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.js
+++ b/erpnext/manufacturing/doctype/production_order/production_order.js
@@ -77,7 +77,6 @@
 		if (!frm.doc.status)
 			frm.doc.status = 'Draft';
 
-		frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
 		frm.add_fetch("sales_order", "project", "project");
 
 		if(frm.doc.__islocal) {
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 040a559..511f6de 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -50,8 +50,12 @@
 
 	def validate_sales_order(self):
 		if self.sales_order:
-			so = frappe.db.sql("""select name, delivery_date, project from `tabSales Order`
-				where name=%s and docstatus = 1""", self.sales_order, as_dict=1)
+			so = frappe.db.sql("""
+				select so.name, so_item.delivery_date, so.project 
+				from `tabSales Order` so, `tabSales Order Item` so_item
+				where so.name=%s and so.name=so_item.parent 
+					and so.docstatus = 1 and so_item.item_code=%s
+			""", (self.sales_order, self.production_item), as_dict=1)
 
 			if len(so):
 				if not self.expected_delivery_date:
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 5b45cb4..6119f3d 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -421,4 +421,5 @@
 erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
 erpnext.patches.v8_3.set_restrict_to_domain_for_module_def
 erpnext.patches.v8_1.update_expense_claim_status
-erpnext.patches.v8_3.update_company_total_sales
\ No newline at end of file
+erpnext.patches.v8_3.update_company_total_sales
+erpnext.patches.v8_1.set_delivery_date_in_so_item
\ No newline at end of file
diff --git a/erpnext/patches/v8_1/set_delivery_date_in_so_item.py b/erpnext/patches/v8_1/set_delivery_date_in_so_item.py
new file mode 100644
index 0000000..6840424
--- /dev/null
+++ b/erpnext/patches/v8_1/set_delivery_date_in_so_item.py
@@ -0,0 +1,13 @@
+import frappe
+
+def execute():
+	frappe.reload_doctype("Sales Order")
+	frappe.reload_doctype("Sales Order Item")
+
+	frappe.db.sql("""update `tabSales Order` set final_delivery_date = delivery_date where docstatus=1""")
+
+	frappe.db.sql("""
+		update `tabSales Order` so, `tabSales Order Item` so_item
+		set so_item.delivery_date = so.delivery_date
+		where so.name = so_item.parent
+	""")
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 640c026..7fb4074 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -27,7 +27,8 @@
 		self.assertEquals(sales_order.get("items")[0].prevdoc_docname, quotation.name)
 		self.assertEquals(sales_order.customer, "_Test Customer")
 
-		sales_order.delivery_date = "2014-01-01"
+		for d in sales_order.get("items"):
+			d.delivery_date = "2014-01-01"
 		sales_order.naming_series = "_T-Quotation-"
 		sales_order.transaction_date = "2013-05-12"
 		sales_order.insert()
@@ -51,9 +52,11 @@
 		quotation.submit()
 
 		sales_order = make_sales_order(quotation.name)
-		sales_order.delivery_date = "2016-01-02"
 		sales_order.naming_series = "_T-Quotation-"
 		sales_order.transaction_date = "2016-01-01"
+		for d in sales_order.get("items"):
+			d.delivery_date = "2016-01-02"
+
 		sales_order.insert()
 
 		self.assertEquals(quotation.get("items")[0].rate, rate_with_margin)
@@ -86,4 +89,4 @@
 				'rate': 100
 			}
 		]
-	}
\ No newline at end of file
+	}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 457b6aa..2e01a08 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -33,7 +33,13 @@
 			function(doc) { return (doc.stock_qty<=doc.delivered_qty) ? "green" : "orange" })
 
 		erpnext.queries.setup_warehouse_query(frm);
-	}
+	},
+});
+
+frappe.ui.form.on("Sales Order Item", {
+	delivery_date: function(frm, cdt, cdn) {
+		erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "delivery_date");
+	}	
 });
 
 erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
@@ -77,7 +83,7 @@
 				// delivery note
 				if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
 					this.frm.add_custom_button(__('Delivery'),
-						function() { me.make_delivery_note() }, __("Make"));
+						function() { me.make_delivery_note_based_on_delivery_note(); }, __("Make"));
 					this.frm.add_custom_button(__('Production Order'),
 						function() { me.make_production_order() }, __("Make"));
 
@@ -235,7 +241,7 @@
 	},
 
 	order_type: function() {
-		this.frm.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
+		this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
 	},
 
 	tc_name: function() {
@@ -249,10 +255,72 @@
 		})
 	},
 
+	make_delivery_note_based_on_delivery_note: function() {
+		var me = this;
+		
+		var delivery_dates = [];
+		$.each(this.frm.doc.items || [], function(i, d) {
+			if(!delivery_dates.includes(d.delivery_date)) {
+				delivery_dates.push(d.delivery_date);
+			}
+		});
+		
+		var item_grid = this.frm.fields_dict["items"].grid;
+		if(!item_grid.get_selected().length && delivery_dates.length > 1) {
+			var dialog = new frappe.ui.Dialog({
+				title: __("Select Items based on Delivery Date"),
+				fields: [{fieldtype: "HTML", fieldname: "dates_html"}]
+			});
+			
+			var html = $(`
+				<div style="border: 1px solid #d1d8dd">
+					<div class="list-item list-item--head">
+						<div class="list-item__content list-item__content--flex-2">
+							${__('Delivery Date')}
+						</div>
+					</div>
+					${delivery_dates.map(date => `
+						<div class="list-item">
+							<div class="list-item__content list-item__content--flex-2">
+								<label>
+								<input type="checkbox" data-date="${date}" checked="checked"/>
+								${frappe.datetime.str_to_user(date)}
+								</label>
+							</div>
+						</div>
+					`).join("")}
+				</div>
+			`);
+
+			var wrapper = dialog.fields_dict.dates_html.$wrapper;
+			wrapper.html(html);
+
+			dialog.set_primary_action(__("Select"), function() {
+				var dates = wrapper.find('input[type=checkbox]:checked')
+					.map((i, el) => $(el).attr('data-date')).toArray();
+
+				if(!dates) return;
+				
+				$.each(dates, function(i, d) {
+					$.each(item_grid.grid_rows || [], function(j, row) {
+						if(row.doc.delivery_date == d) {
+							row.doc.__checked = 1;
+						}
+					});
+				})
+				me.make_delivery_note();
+				dialog.hide();
+			});
+			dialog.show();
+		} else {
+			this.make_delivery_note();
+		}
+	},
+
 	make_delivery_note: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
-			frm: this.frm
+			frm: me.frm
 		})
 	},
 
@@ -344,6 +412,11 @@
 		if(cint(frappe.boot.notification_settings.sales_order)) {
 			this.frm.email_doc(frappe.boot.notification_settings.sales_order_message);
 		}
+	},
+
+	items_add: function(doc, cdt, cdn) {
+		var row = frappe.get_doc(cdt, cdn);
+		this.frm.script_manager.copy_from_first_row("items", row, ["delivery_date"]);
 	}
 });
 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 7c995f2..45365ff 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -367,32 +367,29 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "depends_on": "eval:doc.order_type == 'Sales'", 
-   "fieldname": "delivery_date", 
+   "fieldname": "final_delivery_date", 
    "fieldtype": "Date", 
-   "hidden": 0, 
+   "hidden": 1, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_global_search": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "in_standard_filter": 0, 
-   "label": "Delivery Date", 
+   "label": "Final Delivery Date", 
    "length": 0, 
    "no_copy": 1, 
-   "oldfieldname": "delivery_date", 
-   "oldfieldtype": "Date", 
    "permlevel": 0, 
-   "print_hide": 0, 
+   "precision": "", 
+   "print_hide": 1, 
    "print_hide_if_no_value": 0, 
-   "read_only": 0, 
+   "read_only": 1, 
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
-   "unique": 0, 
-   "width": "160px"
+   "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
@@ -3632,7 +3629,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-06-19 13:06:31.736384", 
+ "modified": "2017-07-17 18:23:36.023797", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order", 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 4333fd8..ae63bb3 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -30,7 +30,6 @@
 
 		self.validate_order_type()
 		self.validate_delivery_date()
-		self.validate_mandatory()
 		self.validate_proj_cust()
 		self.validate_po()
 		self.validate_uom_is_integer("stock_uom", "stock_qty")
@@ -48,25 +47,20 @@
 		if not self.billing_status: self.billing_status = 'Not Billed'
 		if not self.delivery_status: self.delivery_status = 'Not Delivered'
 
-	def validate_mandatory(self):
-		# validate transaction date v/s delivery date
-		if self.delivery_date:
-			if getdate(self.transaction_date) > getdate(self.delivery_date):
-				frappe.msgprint(_("Expected Delivery Date is be before Sales Order Date"),
-					indicator='orange',
-					title=_('Warning'))
-
 	def validate_po(self):
 		# validate p.o date v/s delivery date
-		if self.po_date and self.delivery_date and getdate(self.po_date) > getdate(self.delivery_date):
-			frappe.throw(_("Expected Delivery Date cannot be before Purchase Order Date"))
+		if self.po_date:
+			for d in self.get("items"):
+				 if d.delivery_date and getdate(self.po_date) > getdate(d.delivery_date):
+					 frappe.throw(_("Row #{0}: Expected Delivery Date cannot be before Purchase Order Date")
+					 	.format(d.idx))
 
 		if self.po_no and self.customer:
 			so = frappe.db.sql("select name from `tabSales Order` \
 				where ifnull(po_no, '') = %s and name != %s and docstatus < 2\
 				and customer = %s", (self.po_no, self.name, self.customer))
-			if so and so[0][0] and not \
-				cint(frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders")):
+			if so and so[0][0] and not cint(frappe.db.get_single_value("Selling Settings",
+				"allow_against_multiple_purchase_orders")):
 				frappe.msgprint(_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(so[0][0], self.po_no))
 
 	def validate_for_items(self):
@@ -78,7 +72,7 @@
 			d.transaction_date = self.transaction_date
 
 			tot_avail_qty = frappe.db.sql("select projected_qty from `tabBin` \
-				where item_code = %s and warehouse = %s", (d.item_code,d.warehouse))
+				where item_code = %s and warehouse = %s", (d.item_code, d.warehouse))
 			d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
 
 		# check for same entry multiple times
@@ -97,16 +91,30 @@
 	def validate_sales_mntc_quotation(self):
 		for d in self.get('items'):
 			if d.prevdoc_docname:
-				res = frappe.db.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.order_type))
+				res = frappe.db.sql("select name from `tabQuotation` where name=%s and order_type = %s",
+					(d.prevdoc_docname, self.order_type))
 				if not res:
-					frappe.msgprint(_("Quotation {0} not of type {1}").format(d.prevdoc_docname, self.order_type))
+					frappe.msgprint(_("Quotation {0} not of type {1}")
+						.format(d.prevdoc_docname, self.order_type))
 
 	def validate_order_type(self):
 		super(SalesOrder, self).validate_order_type()
 
 	def validate_delivery_date(self):
-		if self.order_type == 'Sales' and not self.delivery_date:
-			frappe.throw(_("Please enter 'Expected Delivery Date'"))
+		self.final_delivery_date = None
+		if self.order_type == 'Sales':
+			for d in self.get("items"):
+				if not d.delivery_date:
+					frappe.throw(_("Row #{0}: Please enter Delivery Date against item {1}")
+						.format(d.idx, d.item_code))
+
+				if getdate(self.transaction_date) > getdate(d.delivery_date):
+					frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"),
+						indicator='orange', title=_('Warning'))
+
+				if not self.final_delivery_date or \
+					(d.delivery_date and getdate(d.delivery_date) > getdate(self.final_delivery_date)):
+						self.final_delivery_date = d.delivery_date
 
 		self.validate_sales_mntc_quotation()
 
@@ -122,7 +130,7 @@
 		super(SalesOrder, self).validate_warehouse()
 
 		for d in self.get("items"):
-			if (frappe.db.get_value("Item", d.item_code, "is_stock_item")==1 or
+			if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 or
 				(self.has_product_bundle(d.item_code) and self.product_bundle_has_stock_item(d.item_code))) \
 				and not d.warehouse and not cint(d.delivered_by_supplier):
 				frappe.throw(_("Delivery warehouse required for stock item {0}").format(d.item_code),
@@ -336,11 +344,14 @@
 
 		return items
 
-
 	def on_recurring(self, reference_doc):
 		mcount = month_map[reference_doc.recurring_type]
-		self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount,
-						cint(reference_doc.repeat_on_day_of_month)))
+		for d in self.get("items"):
+			reference_delivery_date = frappe.db.get_value("Sales Order Item",
+				{"parent": reference_doc.name, "item_code": d.item_code, "idx": d.idx}, "delivery_date")
+
+			d.set("delivery_date",
+				get_next_date(reference_delivery_date, mcount, cint(reference_doc.repeat_on_day_of_month)))
 
 def get_list_context(context=None):
 	from erpnext.controllers.website_list_for_contact import get_list_context
@@ -423,7 +434,6 @@
 			},
 			"field_map":{
 				"name" : "sales_order",
-				"delivery_date" : "expected_end_date",
 				"base_grand_total" : "estimated_costing",
 			}
 		},
@@ -614,12 +624,17 @@
 	from frappe.desk.calendar import get_event_conditions
 	conditions = get_event_conditions("Sales Order", filters)
 
-	data = frappe.db.sql("""select name, customer_name, status, delivery_status, billing_status, delivery_date
-		from `tabSales Order`
-		where (ifnull(delivery_date, '0000-00-00')!= '0000-00-00') \
-				and (delivery_date between %(start)s and %(end)s)
-				and docstatus < 2
-				{conditions}
+	data = frappe.db.sql("""
+		select
+			so.name, so.customer_name, so.status,
+			so.delivery_status, so.billing_status, so_item.delivery_date
+		from
+			`tabSales Order` so, `tabSales Order Item` so_item
+		where so.name = so_item.parent
+			and (ifnull(so_item.delivery_date, '0000-00-00')!= '0000-00-00') \
+			and (so_item.delivery_date between %(start)s and %(end)s)
+			and so.docstatus < 2
+			{conditions}
 		""".format(conditions=conditions), {
 			"start": start,
 			"end": end
@@ -659,7 +674,7 @@
 		target.run_method("calculate_taxes_and_totals")
 
 	def update_item(source, target, source_parent):
-		target.schedule_date = source_parent.delivery_date
+		target.schedule_date = source.delivery_date
 		target.qty = flt(source.qty) - flt(source.ordered_qty)
 		target.stock_qty = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.conversion_factor)
 
diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js
index d1ac6d9..0ee9cf3 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_list.js
+++ b/erpnext/selling/doctype/sales_order/sales_order_list.js
@@ -1,14 +1,14 @@
 frappe.listview_settings['Sales Order'] = {
-	add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date", "per_delivered", "per_billed",
-		"status", "order_type"],
+	add_fields: ["base_grand_total", "customer_name", "currency", "final_delivery_date",
+		"per_delivered", "per_billed", "status", "order_type", "name"],
 	get_indicator: function(doc) {
 		if(doc.status==="Closed"){
 			return [__("Closed"), "green", "status,=,Closed"];
 
 		} else if (doc.order_type !== "Maintenance"
-			&& flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) {
+			&& flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.final_delivery_date) < 0) {
 			// to bill & overdue
-			return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"];
+			return [__("Overdue"), "red", "per_delivered,<,100|final_delivery_date,<,Today|status,!=,Closed"];
 
 		} else if (doc.order_type !== "Maintenance"
 			&& flt(doc.per_delivered, 2) < 100 && doc.status!=="Closed") {
diff --git a/erpnext/selling/doctype/sales_order/test_records.json b/erpnext/selling/doctype/sales_order/test_records.json
index 12e953a..6cbd6c2 100644
--- a/erpnext/selling/doctype/sales_order/test_records.json
+++ b/erpnext/selling/doctype/sales_order/test_records.json
@@ -7,7 +7,6 @@
   "customer": "_Test Customer", 
   "customer_group": "_Test Customer Group", 
   "customer_name": "_Test Customer", 
-  "delivery_date": "2013-02-23", 
   "doctype": "Sales Order", 
   "base_grand_total": 1000.0, 
   "grand_total": 1000.0, 
@@ -23,6 +22,7 @@
     "doctype": "Sales Order Item", 
     "item_code": "_Test Item Home Desktop 100", 
     "item_name": "CPU", 
+    "delivery_date": "2013-02-23", 
     "parentfield": "items", 
     "qty": 10.0, 
     "rate": 100.0, 
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 0417e5e..8c07118 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -512,7 +512,6 @@
 
 	so.company = args.company or "_Test Company"
 	so.customer = args.customer or "_Test Customer"
-	so.delivery_date = add_days(so.transaction_date, 10)
 	so.currency = args.currency or "INR"
 	if args.selling_price_list:
 		so.selling_price_list = args.selling_price_list
@@ -533,6 +532,9 @@
 			"rate": args.rate or 100
 		})
 
+	for d in so.get("items"):
+		d.delivery_date = add_days(so.transaction_date, 10)
+
 	if not args.do_not_save:
 		so.insert()
 		if not args.do_not_submit:
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 2aae911..f14f50d 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -18,7 +18,7 @@
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
-   "columns": 4, 
+   "columns": 3, 
    "fieldname": "item_code", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -205,6 +205,36 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 2, 
+   "fieldname": "delivery_date", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Delivery Date", 
+   "length": 0, 
+   "no_copy": 1, 
+   "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, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
    "columns": 0, 
    "fieldname": "column_break_7", 
    "fieldtype": "Column Break", 
@@ -324,7 +354,7 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "columns": 2, 
+   "columns": 1, 
    "fieldname": "qty", 
    "fieldtype": "Float", 
    "hidden": 0, 
@@ -1933,7 +1963,7 @@
  "istable": 1, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-05-10 17:14:48.277982", 
+ "modified": "2017-07-18 18:26:36.870342", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order Item",