Purchase Invoice - Due Date reverts to first time value on save #12340 (#12382)

* add handler for due_date:
if due_date is changed and payment terms template or payment schedule is set,
ask user to clear them.

* ui test cases

* cleanup
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
index 8fac32d..b470051 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js
@@ -1,7 +1,7 @@
 QUnit.module('Purchase Invoice');
 
 QUnit.test("test purchase invoice", function(assert) {
-	assert.expect(6);
+	assert.expect(9);
 	let done = assert.async();
 	frappe.run_serially([
 		() => {
@@ -39,6 +39,33 @@
 			assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
 
 		},
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
+		},
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
+		},
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(!cur_dialog, 'Message is not shown');
+		},
+		() => cur_frm.save(),
 		() => frappe.tests.click_button('Submit'),
 		() => frappe.tests.click_button('Yes'),
 		() => frappe.timeout(1),
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
index 0c92c37..1c052bd 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
@@ -1,7 +1,7 @@
 QUnit.module('Sales Invoice');
 
 QUnit.test("test sales Invoice", function(assert) {
-	assert.expect(6);
+	assert.expect(9);
 	let done = assert.async();
 	frappe.run_serially([
 		() => {
@@ -38,6 +38,33 @@
 			assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
 
 		},
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
+		},
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
+		},
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
+		() => {
+			let date = cur_frm.doc.due_date;
+			frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
+			frappe.timeout(0.5);
+			assert.ok(!cur_dialog, 'Message is not shown');
+		},
+		() => cur_frm.save(),
 		() => frappe.tests.click_button('Submit'),
 		() => frappe.tests.click_button('Yes'),
 		() => frappe.timeout(0.3),
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 503f152..b7ad866 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -228,7 +228,6 @@
 		erpnext.hide_company();
 		this.set_dynamic_labels();
 		this.setup_sms();
-
 	},
 
 	apply_default_taxes: function() {
@@ -535,6 +534,32 @@
 		}
 	},
 
+	due_date: function() {
+		// due_date is to be changed, payment terms template and/or payment schedule must
+		// be removed as due_date is automatically changed based on payment terms
+		if (this.frm.doc.due_date) {
+			if (this.frm.doc.payment_terms_template || this.frm.doc.payment_schedule.length) {
+				var message1 = "";
+				var message2 = "";
+				var final_message = "Please clear the ";
+
+				if (this.frm.doc.payment_terms_template) {
+					message1 = "selected Payment Terms Template";
+					final_message = final_message + message1;
+				}
+
+				if (this.frm.doc.payment_schedule.length) {
+					message2 = "Payment Schedule Table";
+					if (message1.length !== 0) message2 = " and " + message2;
+					final_message = final_message + message2;
+				}
+
+				frappe.msgprint(final_message);
+			}
+
+	    }
+	},
+
 	recalculate_terms: function() {
 		const doc = this.frm.doc;
 
@@ -542,7 +567,6 @@
 			this.payment_terms_template();
 		} else if (doc.payment_schedule) {
 			const me = this;
-
 			doc.payment_schedule.forEach(
 				function(term) {
 					if (term.payment_term) {