Merge branch 'develop' into validate-paid-inv-msg
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 9c19791..61c48c7 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -5,7 +5,7 @@
 
 import frappe
 import unittest
-from frappe.utils import nowdate
+from frappe.utils import nowdate, now_datetime
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
 from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
@@ -13,27 +13,28 @@
 
 class TestBudget(unittest.TestCase):
 	def test_monthly_budget_crossed_ignore(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center")
 
 		budget = make_budget(budget_against="Cost Center")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
+			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
 
 		self.assertTrue(frappe.db.get_value("GL Entry",
 			{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
 
 		budget.cancel()
+		jv.cancel()
 
 	def test_monthly_budget_crossed_stop1(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center")
 
 		budget = make_budget(budget_against="Cost Center")
 
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28")
+			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
@@ -41,14 +42,14 @@
 		budget.cancel()
 
 	def test_exception_approver_role(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center")
 
 		budget = make_budget(budget_against="Cost Center")
 
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-03-02")
+			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
@@ -112,16 +113,17 @@
 
 		budget.load_from_db()
 		budget.cancel()
+		po.cancel()
 
 	def test_monthly_budget_crossed_stop2(self):
-		set_total_expense_zero("2013-02-28", "project")
+		set_total_expense_zero(nowdate(), "project")
 
 		budget = make_budget(budget_against="Project")
 
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-02-28")
+			"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
@@ -129,86 +131,76 @@
 		budget.cancel()
 
 	def test_yearly_budget_crossed_stop1(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center")
 
 		budget = make_budget(budget_against="Cost Center")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", posting_date="2013-03-28")
+			"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
 		budget.cancel()
 
 	def test_yearly_budget_crossed_stop2(self):
-		set_total_expense_zero("2013-02-28", "project")
+		set_total_expense_zero(nowdate(), "project")
 
 		budget = make_budget(budget_against="Project")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-03-28")
+			"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
 		budget.cancel()
 
 	def test_monthly_budget_on_cancellation1(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center")
 
 		budget = make_budget(budget_against="Cost Center")
 
-		jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
+		for i in range(now_datetime().month):
+			jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
+				"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
 
-		self.assertTrue(frappe.db.get_value("GL Entry",
-			{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
-
-		jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
-
-		self.assertTrue(frappe.db.get_value("GL Entry",
-			{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
+			self.assertTrue(frappe.db.get_value("GL Entry",
+				{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
 
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
-		self.assertRaises(BudgetError, jv1.cancel)
+		self.assertRaises(BudgetError, jv.cancel)
 
 		budget.load_from_db()
 		budget.cancel()
 
 	def test_monthly_budget_on_cancellation2(self):
-		set_total_expense_zero("2013-02-28", "project")
+		set_total_expense_zero(nowdate(), "project")
 
 		budget = make_budget(budget_against="Project")
 
-		jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
+		for i in range(now_datetime().month):
+			jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
+				"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
 
-		self.assertTrue(frappe.db.get_value("GL Entry",
-			{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
-
-		jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
-
-		self.assertTrue(frappe.db.get_value("GL Entry",
-			{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
+			self.assertTrue(frappe.db.get_value("GL Entry",
+				{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
 
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
-		self.assertRaises(BudgetError, jv1.cancel)
+		self.assertRaises(BudgetError, jv.cancel)
 
 		budget.load_from_db()
 		budget.cancel()
 
 	def test_monthly_budget_against_group_cost_center(self):
-		set_total_expense_zero("2013-02-28", "cost_center")
-		set_total_expense_zero("2013-02-28", "cost_center", "_Test Cost Center 2 - _TC")
+		set_total_expense_zero(nowdate(), "cost_center")
+		set_total_expense_zero(nowdate(), "cost_center", "_Test Cost Center 2 - _TC")
 
 		budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date="2013-02-28")
+			"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
@@ -231,7 +223,7 @@
 		frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
 
 		jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", 40000, cost_center, posting_date="2013-02-28")
+			"_Test Bank - _TC", 40000, cost_center, posting_date=nowdate())
 
 		self.assertRaises(BudgetError, jv.submit)
 
@@ -246,12 +238,14 @@
 	else:
 		budget_against = budget_against_CC or "_Test Cost Center - _TC"
 
+	fiscal_year = get_fiscal_year(nowdate())[0]
+
 	args = frappe._dict({
 		"account": "_Test Account Cost for Goods Sold - _TC",
 		"cost_center": "_Test Cost Center - _TC",
 		"monthly_end_date": posting_date,
 		"company": "_Test Company",
-		"fiscal_year": "_Test Fiscal Year 2013",
+		"fiscal_year": fiscal_year,
 		"budget_against_field": budget_against_field,
 	})
 
@@ -263,10 +257,10 @@
 	if existing_expense:
 		if budget_against_field == "cost_center":
 			make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
+			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
 		elif budget_against_field == "project":
 			make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date="2013-02-28")
+			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
 
 def make_budget(**args):
 	args = frappe._dict(args)
@@ -274,10 +268,13 @@
 	budget_against=args.budget_against
 	cost_center=args.cost_center
 
+	fiscal_year = get_fiscal_year(nowdate())[0]
+
 	if budget_against == "Project":
-		budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
+		project_name = "{0}%".format("_Test Project/" + fiscal_year)
+		budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", project_name)})
 	else:
-		cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/_Test Fiscal Year 2013")
+		cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
 		budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
 	for d in budget_list:
 		frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
@@ -290,8 +287,10 @@
 	else:
 		budget.cost_center =cost_center or "_Test Cost Center - _TC"
 
+	monthly_distribution = frappe.get_doc("Monthly Distribution", "_Test Distribution")
+	monthly_distribution.fiscal_year = fiscal_year
 
-	budget.fiscal_year = "_Test Fiscal Year 2013"
+	budget.fiscal_year = fiscal_year
 	budget.monthly_distribution = "_Test Distribution"
 	budget.company = "_Test Company"
 	budget.applicable_on_booking_actual_expenses = 1
@@ -300,7 +299,7 @@
 	budget.budget_against = budget_against
 	budget.append("accounts", {
 		"account": "_Test Account Cost for Goods Sold - _TC",
-		"budget_amount": 100000
+		"budget_amount": 200000
 	})
 
 	if args.applicable_on_material_request:
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js
index 96ec57d..9e2f6ee 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center.js
@@ -18,7 +18,7 @@
 	},
 	refresh: function(frm) {
 		if (!frm.is_new()) {
-			frm.add_custom_button(__('Update Cost Center Number'), function () {
+			frm.add_custom_button(__('Update Cost Center Name / Number'), function () {
 				frm.trigger("update_cost_center_number");
 			});
 		}
@@ -47,35 +47,45 @@
 	},
 	update_cost_center_number: function(frm) {
 		var d = new frappe.ui.Dialog({
-			title: __('Update Cost Center Number'),
+			title: __('Update Cost Center Name / Number'),
 			fields: [
 				{
-					"label": 'Cost Center Number',
+					"label": "Cost Center Name",
+					"fieldname": "cost_center_name",
+					"fieldtype": "Data",
+					"reqd": 1,
+					"default": frm.doc.cost_center_name
+				},
+				{
+					"label": "Cost Center Number",
 					"fieldname": "cost_center_number",
 					"fieldtype": "Data",
-					"reqd": 1
+					"reqd": 1,
+					"default": frm.doc.cost_center_number
 				}
 			],
 			primary_action: function() {
 				var data = d.get_values();
-				if(data.cost_center_number === frm.doc.cost_center_number) {
+				if(data.cost_center_name === frm.doc.cost_center_name && data.cost_center_number === frm.doc.cost_center_number) {
 					d.hide();
 					return;
 				}
+				frappe.dom.freeze();
 				frappe.call({
-					method: "erpnext.accounts.utils.update_number_field",
+					method: "erpnext.accounts.utils.update_cost_center",
 					args: {
-						doctype_name: frm.doc.doctype,
-						name: frm.doc.name,
-						field_name: d.fields[0].fieldname,
-						number_value: data.cost_center_number,
+						docname: frm.doc.name,
+						cost_center_name: data.cost_center_name,
+						cost_center_number: data.cost_center_number,
 						company: frm.doc.company
 					},
 					callback: function(r) {
+						frappe.dom.unfreeze();
 						if(!r.exc) {
 							if(r.message) {
 								frappe.set_route("Form", "Cost Center", r.message);
 							} else {
+								me.frm.set_value("cost_center_name", data.cost_center_name);
 								me.frm.set_value("cost_center_number", data.cost_center_number);
 							}
 							d.hide();
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index 99b89d1..5013c92 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -2,7 +2,6 @@
  "actions": [],
  "allow_copy": 1,
  "allow_import": 1,
- "allow_rename": 1,
  "creation": "2013-01-23 19:57:17",
  "description": "Track separate Income and Expense for product verticals or divisions.",
  "doctype": "DocType",
@@ -126,7 +125,7 @@
  "idx": 1,
  "is_tree": 1,
  "links": [],
- "modified": "2020-03-18 17:59:04.321637",
+ "modified": "2020-04-29 16:09:30.025214",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Cost Center",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index 2214811..0d75329 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -30,7 +30,8 @@
   "company",
   "finance_book",
   "to_rename",
-  "due_date"
+  "due_date",
+  "is_cancelled"
  ],
  "fields": [
   {
@@ -245,12 +246,18 @@
    "fieldname": "due_date",
    "fieldtype": "Date",
    "label": "Due Date"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_cancelled",
+   "fieldtype": "Check",
+   "label": "Is Cancelled"
   }
  ],
  "icon": "fa fa-list",
  "idx": 1,
  "in_create": 1,
- "modified": "2020-03-28 16:22:33.766994",
+ "modified": "2020-04-07 16:22:33.766994",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "GL Entry",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 14d0531..efab580 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -30,23 +30,20 @@
 		self.pl_must_have_cost_center()
 		self.validate_cost_center()
 
-		if not self.flags.from_repost:
-			self.check_pl_account()
-			self.validate_party()
-			self.validate_currency()
+		self.check_pl_account()
+		self.validate_party()
+		self.validate_currency()
 
-	def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
-		if not from_repost:
-			self.validate_account_details(adv_adj)
-			self.validate_dimensions_for_pl_and_bs()
-			check_freezing_date(self.posting_date, adv_adj)
+	def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
+		self.validate_account_details(adv_adj)
+		self.validate_dimensions_for_pl_and_bs()
 
 		validate_frozen_account(self.account, adv_adj)
 		validate_balance_type(self.account, adv_adj)
 
 		# Update outstanding amt on against voucher
 		if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
-			and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
+			and self.against_voucher and update_outstanding == 'Yes':
 				update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
 					self.against_voucher)
 
@@ -159,7 +156,6 @@
 		if self.party_type and self.party:
 			validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
 
-
 	def validate_and_set_fiscal_year(self):
 		if not self.fiscal_year:
 			self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
@@ -176,19 +172,6 @@
 				(balance_must_be=="Credit" and flt(balance) > 0):
 				frappe.throw(_("Balance for Account {0} must always be {1}").format(account, _(balance_must_be)))
 
-def check_freezing_date(posting_date, adv_adj=False):
-	"""
-		Nobody can do GL Entries where posting date is before freezing date
-		except authorized person
-	"""
-	if not adv_adj:
-		acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
-		if acc_frozen_upto:
-			frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
-			if getdate(posting_date) <= getdate(acc_frozen_upto) \
-					and not frozen_accounts_modifier in frappe.get_roles():
-				frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
-
 def update_outstanding_amt(account, party_type, party, against_voucher_type, against_voucher, on_cancel=False):
 	if party_type and party:
 		party_condition = " and party_type={0} and party={1}"\
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index eb3017a..d6ffdb6 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -57,6 +57,7 @@
 		from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
 		unlink_ref_doc_from_payment_entries(self)
 		unlink_ref_doc_from_salary_slip(self.name)
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 		self.make_gl_entries(1)
 		self.update_advance_paid()
 		self.update_expense_claim()
@@ -594,7 +595,7 @@
 		for d in self.accounts:
 			if d.reference_type=="Expense Claim" and d.reference_name:
 				doc = frappe.get_doc("Expense Claim", d.reference_name)
-				update_reimbursed_amount(doc)
+				update_reimbursed_amount(doc, jv=self.name)
 
 
 	def validate_expense_claim(self):
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 27596af..bcb22f0 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -76,6 +76,7 @@
 		self.set_status()
 
 	def on_cancel(self):
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 		self.setup_party_account_field()
 		self.make_gl_entries(cancel=1)
 		self.update_outstanding_amounts()
@@ -591,7 +592,7 @@
 			for d in self.get("references"):
 				if d.reference_doctype=="Expense Claim" and d.reference_name:
 					doc = frappe.get_doc("Expense Claim", d.reference_name)
-					update_reimbursed_amount(doc)
+					update_reimbursed_amount(doc, self.name)
 
 	def on_recurring(self, reference_doc, auto_repeat_doc):
 		self.reference_no = reference_doc.name
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 4c7d933..8bb741f 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -35,8 +35,6 @@
 
 		pe.cancel()
 
-		self.assertFalse(self.get_gle(pe.name))
-
 		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
 		self.assertEqual(so_advance_paid, 0)
 
@@ -124,7 +122,6 @@
 		self.assertEqual(outstanding_amount, 0)
 
 		pe.cancel()
-		self.assertFalse(self.get_gle(pe.name))
 
 		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
 		self.assertEqual(outstanding_amount, 100)
@@ -381,7 +378,6 @@
 		self.assertEqual(outstanding_amount, 0)
 
 		pe3.cancel()
-		self.assertFalse(self.get_gle(pe3.name))
 
 		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
 		self.assertEqual(outstanding_amount, -100)
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
index 03b8f93..87e02fe 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
@@ -5,7 +5,7 @@
 	onload: function(frm) {
 		if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
 	},
-	
+
 	setup: function(frm) {
 		frm.set_query("closing_account_head", function() {
 			return {
@@ -18,9 +18,9 @@
 			}
 		});
 	},
-	
+
 	refresh: function(frm) {
-		if(frm.doc.docstatus==1) {
+		if(frm.doc.docstatus > 0) {
 			frm.add_custom_button(__('Ledger'), function() {
 				frappe.route_options = {
 					"voucher_no": frm.doc.name,
@@ -33,5 +33,5 @@
 			}, "fa fa-table");
 		}
 	}
-	
+
 })
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index eb95e45..0bd9a90 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -17,8 +17,9 @@
 		self.make_gl_entries()
 
 	def on_cancel(self):
-		frappe.db.sql("""delete from `tabGL Entry`
-			where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name)
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+		from erpnext.accounts.general_ledger import make_reverse_gl_entries
+		make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name, cancel=True)
 
 	def validate_account_head(self):
 		closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 3cf4d59..4f6be59 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -382,11 +382,6 @@
 	cur_frm.refresh_fields();
 }
 
-cur_frm.cscript.update_stock = function(doc, dt, dn) {
-	hide_fields(doc, dt, dn);
-	this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
-}
-
 cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
 	return {
 		filters: [
@@ -528,5 +523,10 @@
 			erpnext.buying.get_default_bom(frm);
 		}
 		frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
+	},
+
+	update_stock: function(frm) {
+		hide_fields(frm.doc);
+		frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
 	}
 })
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index b1ae194..3aa24df 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -14,7 +14,7 @@
 from erpnext.accounts.utils import get_account_currency, get_fiscal_year
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
 from erpnext.stock import get_warehouse_account_map
-from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
+from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, make_reverse_gl_entries
 from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
 from erpnext.buying.utils import check_on_hold_or_closed_status
 from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
@@ -382,7 +382,7 @@
 		self.update_project()
 		update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
 
-	def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
+	def make_gl_entries(self, gl_entries=None):
 		if not self.grand_total:
 			return
 		if not gl_entries:
@@ -391,21 +391,17 @@
 		if gl_entries:
 			update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
 
-			make_gl_entries(gl_entries,  cancel=(self.docstatus == 2),
-				update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
+			if self.docstatus == 1:
+				make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
+			elif self.docstatus == 2:
+				make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 
 			if update_outstanding == "No":
 				update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
 					self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
 
-			if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) and self.auto_accounting_for_stock:
-				from erpnext.controllers.stock_controller import update_gl_entries_after
-				items, warehouses = self.get_items_and_warehouses()
-				update_gl_entries_after(self.posting_date, self.posting_time,
-					warehouses, items, company = self.company)
-
 		elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
-			delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
+			make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 
 	def get_gl_entries(self, warehouse_account=None):
 		self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
@@ -934,6 +930,7 @@
 		frappe.db.set(self, 'status', 'Cancelled')
 
 		unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 
 	def update_project(self):
 		project_list = []
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_records.json b/erpnext/accounts/doctype/purchase_invoice/test_records.json
index 171927c..7030faf 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_records.json
+++ b/erpnext/accounts/doctype/purchase_invoice/test_records.json
@@ -138,13 +138,12 @@
     "row_id": 7
    }
   ],
-  "posting_date": "2013-02-03",
   "supplier": "_Test Supplier",
   "supplier_name": "_Test Supplier"
  },
- 
- 
- 
+
+
+
  {
   "bill_no": "NA",
   "buying_price_list": "_Test Price List",
@@ -204,7 +203,6 @@
     "tax_amount": 150.0
    }
   ],
-  "posting_date": "2013-02-03",
   "supplier": "_Test Supplier",
   "supplier_name": "_Test Supplier"
  }
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 60e41f9..f248276 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -345,7 +345,7 @@
 
 	set_dynamic_labels: function() {
 		this._super();
-		this.hide_fields(this.frm.doc);
+		this.frm.events.hide_fields(this.frm)
 	},
 
 	items_on_form_rendered: function() {
@@ -404,7 +404,7 @@
 							if(r.message && r.message.print_format) {
 								me.frm.pos_print_format = r.message.print_format;
 							}
-							me.frm.script_manager.trigger("update_stock");
+							me.frm.trigger("update_stock");
 							if(me.frm.doc.taxes_and_charges) {
 								me.frm.script_manager.trigger("taxes_and_charges");
 							}
@@ -446,35 +446,6 @@
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
 
-// Hide Fields
-// ------------
-cur_frm.cscript.hide_fields = function(doc) {
-	var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
-		'advances', 'from_date', 'to_date'];
-
-	if(cint(doc.is_pos) == 1) {
-		hide_field(parent_fields);
-	} else {
-		for (var i in parent_fields) {
-			var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
-			if(!docfield.hidden) unhide_field(parent_fields[i]);
-		}
-	}
-
-	// India related fields
-	if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
-	else hide_field(['c_form_applicable', 'c_form_no']);
-
-	this.frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
-
-	cur_frm.refresh_fields();
-}
-
-cur_frm.cscript.update_stock = function(doc, dt, dn) {
-	cur_frm.cscript.hide_fields(doc, dt, dn);
-	this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
-}
-
 cur_frm.cscript['Make Delivery Note'] = function() {
 	frappe.model.open_mapped_doc({
 		method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_delivery_note",
@@ -719,6 +690,12 @@
 		frm.redemption_conversion_factor = null;
 	},
 
+	update_stock: function(frm, dt, dn) {
+		frm.events.hide_fields(frm);
+		frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock);
+		frm.trigger('reset_posting_time');
+	},
+
 	redeem_loyalty_points: function(frm) {
 		frm.events.get_loyalty_details(frm);
 	},
@@ -742,6 +719,29 @@
 		}
 	},
 
+	hide_fields: function(frm) {
+		let doc = frm.doc;
+		var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
+		'advances', 'from_date', 'to_date'];
+
+		if(cint(doc.is_pos) == 1) {
+			hide_field(parent_fields);
+		} else {
+			for (var i in parent_fields) {
+				var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
+				if(!docfield.hidden) unhide_field(parent_fields[i]);
+			}
+		}
+
+		// India related fields
+		if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
+		else hide_field(['c_form_applicable', 'c_form_no']);
+
+		frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
+
+		frm.refresh_fields();
+	},
+
 	get_loyalty_details: function(frm) {
 		if (frm.doc.customer && frm.doc.redeem_loyalty_points) {
 			frappe.call({
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 918fa14..db20589 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -149,9 +149,9 @@
   "edit_printing_settings",
   "letter_head",
   "group_same_items",
-  "language",
-  "column_break_84",
   "select_print_heading",
+  "column_break_84",
+  "language",
   "more_information",
   "inter_company_invoice_reference",
   "is_internal_customer",
@@ -1579,7 +1579,7 @@
  "idx": 181,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-17 12:38:41.435728",
+ "modified": "2020-04-29 13:37:09.355300",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 3c40112..3b0fade 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -7,7 +7,6 @@
 from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
 from frappe import _, msgprint, throw
 from erpnext.accounts.party import get_party_account, get_due_date
-from erpnext.controllers.stock_controller import update_gl_entries_after
 from frappe.model.mapper import get_mapped_doc
 from erpnext.accounts.doctype.sales_invoice.pos import update_multi_mode_option
 
@@ -282,6 +281,8 @@
 		if "Healthcare" in active_domains:
 			manage_invoice_submit_cancel(self, "on_cancel")
 
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+
 	def update_status_updater_args(self):
 		if cint(self.update_stock):
 			self.status_updater.append({
@@ -717,7 +718,9 @@
 			if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
 				throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
 
-	def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
+	def make_gl_entries(self, gl_entries=None):
+		from erpnext.accounts.general_ledger import make_reverse_gl_entries
+
 		auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
 		if not gl_entries:
 			gl_entries = self.get_gl_entries()
@@ -729,23 +732,19 @@
 			update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account or
 				cint(self.redeem_loyalty_points)) else "Yes"
 
-			make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
-				update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
+			if self.docstatus == 1:
+				make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
+			elif self.docstatus == 2:
+				make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 
 			if update_outstanding == "No":
 				from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
 				update_outstanding_amt(self.debit_to, "Customer", self.customer,
 					self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
 
-			if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) \
-				and cint(auto_accounting_for_stock):
-					items, warehouses = self.get_items_and_warehouses()
-					update_gl_entries_after(self.posting_date, self.posting_time,
-						warehouses, items, company = self.company)
 		elif self.docstatus == 2 and cint(self.update_stock) \
 			and cint(auto_accounting_for_stock):
-				from erpnext.accounts.general_ledger import delete_gl_entries
-				delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
+				make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 
 	def get_gl_entries(self, warehouse_account=None):
 		from erpnext.accounts.general_ledger import merge_similar_entries
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 88b54fe..dd727a4 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -364,7 +364,7 @@
 		gle = frappe.db.sql("""select * from `tabGL Entry`
 			where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
 
-		self.assertFalse(gle)
+		self.assertTrue(gle)
 
 	def test_tax_calculation_with_multiple_items(self):
 		si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
@@ -678,14 +678,15 @@
 		gle = frappe.db.sql("""select * from `tabGL Entry`
 			where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
 
-		self.assertFalse(gle)
+		self.assertTrue(gle)
 
 	def test_pos_gl_entry_with_perpetual_inventory(self):
 		make_pos_profile()
 
-		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
+		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
 
-		pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
+		pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
+			income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
 
 		pos.is_pos = 1
 		pos.update_stock = 1
@@ -766,9 +767,13 @@
 	def test_pos_change_amount(self):
 		make_pos_profile()
 
-		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
+		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
+			item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
 
-		pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
+		pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
+			debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
+			income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
+			cost_center = "Main - TCP1", do_not_save=True)
 
 		pos.is_pos = 1
 		pos.update_stock = 1
@@ -787,8 +792,15 @@
 		from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
 
 		pos_profile = make_pos_profile()
-		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
-		pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
+
+		pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
+			item_code= "_Test FG Item",
+			warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
+
+		pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
+			debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
+			income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
+			cost_center = "Main - TCP1", do_not_save=True)
 
 		pos.is_pos = 1
 		pos.update_stock = 1
@@ -891,11 +903,9 @@
 		gle = frappe.db.sql("""select * from `tabGL Entry`
 			where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
 
-		self.assertFalse(gle)
-
+		self.assertTrue(gle)
 
 		frappe.db.sql("delete from `tabPOS Profile`")
-		si.delete()
 
 	def test_pos_si_without_payment(self):
 		set_perpetual_inventory()
@@ -1012,9 +1022,6 @@
 
 		si.cancel()
 
-		self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
-			where reference_name=%s""", si.name))
-
 	def test_serialized(self):
 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -1230,7 +1237,7 @@
 		gle = frappe.db.sql("""select name from `tabGL Entry`
 			where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
 
-		self.assertFalse(gle)
+		self.assertTrue(gle)
 
 	def test_invalid_currency(self):
 		# Customer currency = USD
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 5ba455c..fb1a4f4 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe, erpnext
-from frappe.utils import flt, cstr, cint, comma_and
+from frappe.utils import flt, cstr, cint, comma_and, today, getdate, formatdate, now
 from frappe import _
 from erpnext.accounts.utils import get_stock_and_account_balance
 from frappe.model.meta import get_field_precision
@@ -15,17 +15,17 @@
 class StockAccountInvalidTransaction(frappe.ValidationError): pass
 class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
 
-def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
+def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
 	if gl_map:
 		if not cancel:
 			validate_accounting_period(gl_map)
 			gl_map = process_gl_map(gl_map, merge_entries)
 			if gl_map and len(gl_map) > 1:
-				save_entries(gl_map, adv_adj, update_outstanding, from_repost)
+				save_entries(gl_map, adv_adj, update_outstanding)
 			else:
 				frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
 		else:
-			delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
+			make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
 
 def validate_accounting_period(gl_map):
 	accounting_periods = frappe.db.sql(""" SELECT
@@ -119,33 +119,36 @@
 		if same_head:
 			return e
 
-def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
-	if not from_repost:
-		validate_cwip_accounts(gl_map)
+def save_entries(gl_map, adv_adj, update_outstanding):
+	validate_cwip_accounts(gl_map)
 
 	round_off_debit_credit(gl_map)
+
+	if gl_map:
+		check_freezing_date(gl_map[0]["posting_date"], adv_adj)
+
 	for entry in gl_map:
-		make_entry(entry, adv_adj, update_outstanding, from_repost)
+		make_entry(entry, adv_adj, update_outstanding)
 
 		# check against budget
-		if not from_repost:
-			validate_expense_against_budget(entry)
+		validate_expense_against_budget(entry)
 
-	if not from_repost:
-		validate_account_for_perpetual_inventory(gl_map)
+	validate_account_for_perpetual_inventory(gl_map)
 
 
-def make_entry(args, adv_adj, update_outstanding, from_repost=False):
+def make_entry(args, adv_adj, update_outstanding):
 	gle = frappe.new_doc("GL Entry")
 	gle.update(args)
 	gle.flags.ignore_permissions = 1
-	gle.flags.from_repost = from_repost
 	gle.validate()
 	gle.db_insert()
-	gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
+	gle.run_method("on_update_with_args", adv_adj, update_outstanding)
 	gle.flags.ignore_validate = True
 	gle.submit()
 
+	# check against budget
+	validate_expense_against_budget(args)
+
 def validate_account_for_perpetual_inventory(gl_map):
 	if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
 		account_list = [gl_entries.account for gl_entries in gl_map]
@@ -169,33 +172,33 @@
 						.format(account), StockAccountInvalidTransaction)
 
 			# This has been comment for a temporary, will add this code again on release of immutable ledger
-			# elif account_bal != stock_bal:
-			# 	precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
-			# 		currency=frappe.get_cached_value('Company',  gl_map[0].company,  "default_currency"))
+			elif account_bal != stock_bal:
+				precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
+					currency=frappe.get_cached_value('Company',  gl_map[0].company,  "default_currency"))
 
-			# 	diff = flt(stock_bal - account_bal, precision)
-			# 	error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
-			# 		stock_bal, account_bal, frappe.bold(account))
-			# 	error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
-			# 	stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
+				diff = flt(stock_bal - account_bal, precision)
+				error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
+					stock_bal, account_bal, frappe.bold(account))
+				error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
+				stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
 
-			# 	db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
-			# 	db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
+				db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
+				db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
 
-			# 	journal_entry_args = {
-			# 	'accounts':[
-			# 		{'account': account, db_or_cr_warehouse_account : abs(diff)},
-			# 		{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
-			# 	}
+				journal_entry_args = {
+				'accounts':[
+					{'account': account, db_or_cr_warehouse_account : abs(diff)},
+					{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
+				}
 
-			# 	frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
-			# 		raise_exception=StockValueAndAccountBalanceOutOfSync,
-			# 		title=_('Values Out Of Sync'),
-			# 		primary_action={
-			# 			'label': _('Make Journal Entry'),
-			# 			'client_action': 'erpnext.route_to_adjustment_jv',
-			# 			'args': journal_entry_args
-			# 		})
+				frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
+					raise_exception=StockValueAndAccountBalanceOutOfSync,
+					title=_('Values Out Of Sync'),
+					primary_action={
+						'label': _('Make Journal Entry'),
+						'client_action': 'erpnext.route_to_adjustment_jv',
+						'args': journal_entry_args
+					})
 
 def validate_cwip_accounts(gl_map):
 	cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
@@ -282,31 +285,64 @@
 
 	return round_off_account, round_off_cost_center
 
-def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
-		adv_adj=False, update_outstanding="Yes"):
-
-	from erpnext.accounts.doctype.gl_entry.gl_entry import validate_balance_type, \
-		check_freezing_date, update_outstanding_amt, validate_frozen_account
+def make_reverse_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
+	adv_adj=False, update_outstanding="Yes"):
+	"""
+		Get original gl entries of the voucher
+		and make reverse gl entries by swapping debit and credit
+	"""
 
 	if not gl_entries:
-		gl_entries = frappe.db.sql("""
-			select account, posting_date, party_type, party, cost_center, fiscal_year,voucher_type,
-			voucher_no, against_voucher_type, against_voucher, cost_center, company
-			from `tabGL Entry`
-			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
+		gl_entries = frappe.get_all("GL Entry",
+			fields = ["*"],
+			filters = {
+				"voucher_type": voucher_type,
+				"voucher_no": voucher_no
+			})
 
 	if gl_entries:
+		set_as_cancel(gl_entries[0]['voucher_type'], gl_entries[0]['voucher_no'])
 		check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
 
-	frappe.db.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
-		(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
+		for entry in gl_entries:
+			entry['name'] = None
+			debit = entry.get('debit', 0)
+			credit = entry.get('credit', 0)
 
-	for entry in gl_entries:
-		validate_frozen_account(entry["account"], adv_adj)
-		validate_balance_type(entry["account"], adv_adj)
-		if not adv_adj:
-			validate_expense_against_budget(entry)
+			debit_in_account_currency = entry.get('debit_in_account_currency', 0)
+			credit_in_account_currency = entry.get('credit_in_account_currency', 0)
 
-		if entry.get("against_voucher") and update_outstanding == 'Yes' and not adv_adj:
-			update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
-				entry.get("against_voucher"), on_cancel=True)
+			entry['debit'] = credit
+			entry['credit'] = debit
+			entry['debit_in_account_currency'] = credit_in_account_currency
+			entry['credit_in_account_currency'] = debit_in_account_currency
+
+			entry['remarks'] = "On cancellation of " + entry['voucher_no']
+			entry['is_cancelled'] = 1
+			entry['posting_date'] = today()
+
+			if entry['debit'] or entry['credit']:
+				make_entry(entry, adv_adj, "Yes")
+
+
+def check_freezing_date(posting_date, adv_adj=False):
+	"""
+		Nobody can do GL Entries where posting date is before freezing date
+		except authorized person
+	"""
+	if not adv_adj:
+		acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
+		if acc_frozen_upto:
+			frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
+			if getdate(posting_date) <= getdate(acc_frozen_upto) \
+					and not frozen_accounts_modifier in frappe.get_roles():
+				frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
+
+def set_as_cancel(voucher_type, voucher_no):
+	"""
+		Set is_cancelled=1 in all original gl entries for the voucher
+	"""
+	frappe.db.sql("""update `tabGL Entry` set is_cancelled = 1,
+		modified=%s, modified_by=%s
+		where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
+		(now(), frappe.session.user, voucher_type, voucher_no))
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index ac49d37..1188bea 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -154,8 +154,12 @@
 		{
 			"fieldname": "include_default_book_entries",
 			"label": __("Include Default Book Entries"),
-			"fieldtype": "Check",
-			"default": 1
+			"fieldtype": "Check"
+		},
+		{
+			"fieldname": "show_cancelled_entries",
+			"label": __("Show Cancelled Entries"),
+			"fieldtype": "Check"
 		}
 	]
 }
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index f776d93..7af5fa8 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -188,6 +188,9 @@
 		else:
 			conditions.append("finance_book in (%(finance_book)s)")
 
+	if not filters.get("show_cancelled_entries"):
+		conditions.append("is_cancelled = 0")
+
 	from frappe.desk.reportview import build_match_conditions
 	match_conditions = build_match_conditions("GL Entry")
 
diff --git a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
index 260f35f..1c45810 100644
--- a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
+++ b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
@@ -35,6 +35,12 @@
 		})
 		return columns, data
 
+	# to avoid error eg: gross_income[0] : list index out of range
+	if not gross_income:
+		gross_income = [{}]
+	if not gross_expense:
+		gross_expense = [{}]
+
 	data.append({
 		"account_name": "'" + _("Included in Gross Profit") + "'",
 		"account": "'" + _("Included in Gross Profit") + "'"
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 4789063..5165495 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -817,48 +817,37 @@
 		pass
 
 @frappe.whitelist()
-def update_number_field(doctype_name, name, field_name, number_value, company):
+def update_cost_center(docname, cost_center_name, cost_center_number, company):
 	'''
-		doctype_name = Name of the DocType
-		name = Docname being referred
-		field_name = Name of the field thats holding the 'number' attribute
-		number_value = Numeric value entered in field_name
-
-		Stores the number entered in the dialog to the DocType's field.
-
 		Renames the document by adding the number as a prefix to the current name and updates
 		all transaction where it was present.
 	'''
-	doc_title = frappe.db.get_value(doctype_name, name, frappe.scrub(doctype_name)+"_name")
+	validate_field_number("Cost Center", docname, cost_center_number, company, "cost_center_number")
 
-	validate_field_number(doctype_name, name, number_value, company, field_name)
+	if cost_center_number:
+		frappe.db.set_value("Cost Center", docname, "cost_center_number", cost_center_number.strip())
+	else:
+		frappe.db.set_value("Cost Center", docname, "cost_center_number", "")
 
-	frappe.db.set_value(doctype_name, name, field_name, number_value)
+	frappe.db.set_value("Cost Center", docname, "cost_center_name", cost_center_name.strip())
 
-	if doc_title[0].isdigit():
-		separator = " - " if " - " in doc_title else " "
-		doc_title = doc_title.split(separator, 1)[1]
-
-	frappe.db.set_value(doctype_name, name, frappe.scrub(doctype_name)+"_name", doc_title)
-
-	new_name = get_autoname_with_number(number_value, doc_title, name, company)
-
-	if name != new_name:
-		frappe.rename_doc(doctype_name, name, new_name)
+	new_name = get_autoname_with_number(cost_center_number, cost_center_name, docname, company)
+	if docname != new_name:
+		frappe.rename_doc("Cost Center", docname, new_name, force=1)
 		return new_name
 
-def validate_field_number(doctype_name, name, number_value, company, field_name):
+def validate_field_number(doctype_name, docname, number_value, company, field_name):
 	''' Validate if the number entered isn't already assigned to some other document. '''
 	if number_value:
+		filters = {field_name: number_value, "name": ["!=", docname]}
 		if company:
-			doctype_with_same_number = frappe.db.get_value(doctype_name,
-				{field_name: number_value, "company": company, "name": ["!=", name]})
-		else:
-			doctype_with_same_number = frappe.db.get_value(doctype_name,
-				{field_name: number_value, "name": ["!=", name]})
+			filters["company"] = company
+
+		doctype_with_same_number = frappe.db.get_value(doctype_name, filters)
+
 		if doctype_with_same_number:
-			frappe.throw(_("{0} Number {1} already used in account {2}")
-				.format(doctype_name, number_value, doctype_with_same_number))
+			frappe.throw(_("{0} Number {1} is already used in {2} {3}")
+				.format(doctype_name, number_value, doctype_name.lower(), doctype_with_same_number))
 
 def get_autoname_with_number(number_value, doc_title, name, company):
 	''' append title with prefix as number and suffix as company's abbreviation separated by '-' '''
@@ -897,4 +886,60 @@
 	return frappe.get_all("Account", filters = {
 		"account_type": "Stock",
 		"company": company
-	})
\ No newline at end of file
+	})
+
+def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
+		warehouse_account=None, company=None):
+	def _delete_gl_entries(voucher_type, voucher_no):
+		frappe.db.sql("""delete from `tabGL Entry`
+			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
+
+	if not warehouse_account:
+		warehouse_account = get_warehouse_account_map(company)
+
+	future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
+	gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
+
+	for voucher_type, voucher_no in future_stock_vouchers:
+		existing_gle = gle.get((voucher_type, voucher_no), [])
+		voucher_obj = frappe.get_doc(voucher_type, voucher_no)
+		expected_gle = voucher_obj.get_gl_entries(warehouse_account)
+		if expected_gle:
+			if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
+				_delete_gl_entries(voucher_type, voucher_no)
+				voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True)
+		else:
+			_delete_gl_entries(voucher_type, voucher_no)
+
+def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
+	future_stock_vouchers = []
+
+	values = []
+	condition = ""
+	if for_items:
+		condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
+		values += for_items
+
+	if for_warehouses:
+		condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
+		values += for_warehouses
+
+	for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
+		from `tabStock Ledger Entry` sle
+		where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
+		order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
+		tuple([posting_date, posting_time] + values), as_dict=True):
+			future_stock_vouchers.append([d.voucher_type, d.voucher_no])
+
+	return future_stock_vouchers
+
+def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
+	gl_entries = {}
+	if future_stock_vouchers:
+		for d in frappe.db.sql("""select * from `tabGL Entry`
+			where posting_date >= %s and voucher_no in (%s)""" %
+			('%s', ', '.join(['%s']*len(future_stock_vouchers))),
+			tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
+				gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
+
+	return gl_entries
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 759d42a..ecbfeb7 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -11,7 +11,7 @@
 from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
 from erpnext.assets.doctype.asset.depreciation \
 	import get_disposal_account_and_cost_center, get_depreciation_accounts
-from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries
+from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
 from erpnext.accounts.utils import get_account_currency
 from erpnext.controllers.accounts_controller import AccountsController
 
@@ -41,7 +41,8 @@
 		self.validate_cancellation()
 		self.delete_depreciation_entries()
 		self.set_status()
-		delete_gl_entries(voucher_type='Asset', voucher_no=self.name)
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+		make_reverse_gl_entries(voucher_type='Asset', voucher_no=self.name)
 		self.db_set('booked_fixed_asset', 0)
 
 	def validate_asset_and_reference(self):
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index a56440d..050b30d 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -66,9 +66,6 @@
 		pr.cancel()
 		self.assertEqual(asset.docstatus, 2)
 
-		self.assertFalse(frappe.db.get_value("GL Entry",
-			{"voucher_type": "Purchase Invoice", "voucher_no": pi.name}))
-
 	def test_is_fixed_asset_set(self):
 		asset = create_asset(is_existing_asset = 1)
 		doc = frappe.new_doc('Purchase Invoice')
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 9bf4df4..9a33fc1 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -11,7 +11,8 @@
 class AssetCategory(Document):
 	def validate(self):
 		self.validate_finance_books()
-		self.validate_accounts()
+		self.validate_account_types()
+		self.validate_account_currency()
 
 	def validate_finance_books(self):
 		for d in self.finance_books:
@@ -19,7 +20,26 @@
 				if cint(d.get(frappe.scrub(field)))<1:
 					frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
 	
-	def validate_accounts(self):
+	def validate_account_currency(self):
+		account_types = [
+			'fixed_asset_account', 'accumulated_depreciation_account', 'depreciation_expense_account', 'capital_work_in_progress_account'
+		]
+		invalid_accounts = []
+		for d in self.accounts:
+			company_currency = frappe.get_value('Company', d.get('company_name'), 'default_currency')
+			for type_of_account in account_types:
+				if d.get(type_of_account):
+					account_currency = frappe.get_value("Account", d.get(type_of_account), "account_currency")
+					if account_currency != company_currency:
+						invalid_accounts.append(frappe._dict({ 'type': type_of_account, 'idx': d.idx, 'account': d.get(type_of_account) }))
+	
+		for d in invalid_accounts:
+			frappe.throw(_("Row #{}: Currency of {} - {} doesn't matches company currency.")
+				.format(d.idx, frappe.bold(frappe.unscrub(d.type)), frappe.bold(d.account)),
+				title=_("Invalid Account"))
+
+	
+	def validate_account_types(self):
 		account_type_map = {
 			'fixed_asset_account': { 'account_type': 'Fixed Asset' },
 			'accumulated_depreciation_account': { 'account_type': 'Accumulated Depreciation' },
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 7b3b466..9855a11 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -172,6 +172,10 @@
 				},
 				{
 					"type": "doctype",
+					"name": "Income Tax Slab",
+				},
+				{
+					"type": "doctype",
 					"name": "Salary Component",
 				},
 				{
@@ -211,6 +215,10 @@
 				},
 				{
 					"type": "doctype",
+					"name": "Employee Other Income",
+				},
+				{
+					"type": "doctype",
 					"name": "Employee Benefit Application",
 					"dependencies": ["Employee"]
 				},
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 3e97f76..eecb143 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -664,23 +664,26 @@
 	def set_total_advance_paid(self):
 		if self.doctype == "Sales Order":
 			dr_or_cr = "credit_in_account_currency"
+			rev_dr_or_cr = "debit_in_account_currency"
 			party = self.customer
 		else:
 			dr_or_cr = "debit_in_account_currency"
+			rev_dr_or_cr = "credit_in_account_currency"
 			party = self.supplier
 
 		advance = frappe.db.sql("""
 			select
-				account_currency, sum({dr_or_cr}) as amount
+				account_currency, sum({dr_or_cr}) - sum({rev_dr_cr}) as amount
 			from
 				`tabGL Entry`
 			where
 				against_voucher_type = %s and against_voucher = %s and party=%s
 				and docstatus = 1
-		""".format(dr_or_cr=dr_or_cr), (self.doctype, self.name, party), as_dict=1)
+		""".format(dr_or_cr=dr_or_cr, rev_dr_cr=rev_dr_or_cr), (self.doctype, self.name, party), as_dict=1) #nosec
 
 		if advance:
 			advance = advance[0]
+
 			advance_paid = flt(advance.amount, self.precision("advance_paid"))
 			formatted_advance_paid = fmt_money(advance_paid, precision=self.precision("advance_paid"),
 											   currency=advance.account_currency)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 9d453af..86de808 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -7,7 +7,7 @@
 from frappe import _
 import frappe.defaults
 from erpnext.accounts.utils import get_fiscal_year
-from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
+from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries, process_gl_map
 from erpnext.controllers.accounts_controller import AccountsController
 from erpnext.stock.stock_ledger import get_valuation_rate
 from erpnext.stock import get_warehouse_account_map
@@ -23,9 +23,9 @@
 		self.validate_serialized_batch()
 		self.validate_customer_provided_item()
 
-	def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
+	def make_gl_entries(self, gl_entries=None):
 		if self.docstatus == 2:
-			delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
+			make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 
 		if cint(erpnext.is_perpetual_inventory_enabled(self.company)):
 			warehouse_account = get_warehouse_account_map(self.company)
@@ -33,16 +33,12 @@
 			if self.docstatus==1:
 				if not gl_entries:
 					gl_entries = self.get_gl_entries(warehouse_account)
-				make_gl_entries(gl_entries, from_repost=from_repost)
+				make_gl_entries(gl_entries)
 
-			if (repost_future_gle or self.flags.repost_future_gle):
-				items, warehouses = self.get_items_and_warehouses()
-				update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
-					warehouse_account, company=self.company)
 		elif self.doctype in ['Purchase Receipt', 'Purchase Invoice'] and self.docstatus == 1:
 			gl_entries = []
 			gl_entries = self.get_asset_gl_entry(gl_entries)
-			make_gl_entries(gl_entries, from_repost=from_repost)
+			make_gl_entries(gl_entries)
 
 	def validate_serialized_batch(self):
 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -274,21 +270,21 @@
 			"batch_no": cstr(d.get("batch_no")).strip(),
 			"serial_no": d.get("serial_no"),
 			"project": d.get("project") or self.get('project'),
-			"is_cancelled": self.docstatus==2 and "Yes" or "No"
+			"is_cancelled": 1 if self.docstatus==2 else 0
 		})
 
 		sl_dict.update(args)
 		return sl_dict
 
-	def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False,
+	def make_sl_entries(self, sl_entries, allow_negative_stock=False,
 			via_landed_cost_voucher=False):
 		from erpnext.stock.stock_ledger import make_sl_entries
-		make_sl_entries(sl_entries, is_amended, allow_negative_stock, via_landed_cost_voucher)
+		make_sl_entries(sl_entries, allow_negative_stock, via_landed_cost_voucher)
 
-	def make_gl_entries_on_cancel(self, repost_future_gle=True):
+	def make_gl_entries_on_cancel(self):
 		if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
 			and voucher_no=%s""", (self.doctype, self.name)):
-				self.make_gl_entries(repost_future_gle=repost_future_gle)
+				self.make_gl_entries()
 
 	def get_serialized_items(self):
 		serialized_items = []
@@ -391,29 +387,6 @@
 			if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
 				d.allow_zero_valuation_rate = 1
 
-def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
-		warehouse_account=None, company=None):
-	def _delete_gl_entries(voucher_type, voucher_no):
-		frappe.db.sql("""delete from `tabGL Entry`
-			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
-
-	if not warehouse_account:
-		warehouse_account = get_warehouse_account_map(company)
-
-	future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
-	gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
-
-	for voucher_type, voucher_no in future_stock_vouchers:
-		existing_gle = gle.get((voucher_type, voucher_no), [])
-		voucher_obj = frappe.get_doc(voucher_type, voucher_no)
-		expected_gle = voucher_obj.get_gl_entries(warehouse_account)
-		if expected_gle:
-			if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
-				_delete_gl_entries(voucher_type, voucher_no)
-				voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True)
-		else:
-			_delete_gl_entries(voucher_type, voucher_no)
-
 def compare_existing_and_expected_gle(existing_gle, expected_gle):
 	matched = True
 	for entry in expected_gle:
@@ -430,36 +403,3 @@
 			matched = False
 			break
 	return matched
-
-def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
-	future_stock_vouchers = []
-
-	values = []
-	condition = ""
-	if for_items:
-		condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
-		values += for_items
-
-	if for_warehouses:
-		condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
-		values += for_warehouses
-
-	for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
-		from `tabStock Ledger Entry` sle
-		where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
-		order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
-		tuple([posting_date, posting_time] + values), as_dict=True):
-			future_stock_vouchers.append([d.voucher_type, d.voucher_no])
-
-	return future_stock_vouchers
-
-def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
-	gl_entries = {}
-	if future_stock_vouchers:
-		for d in frappe.db.sql("""select * from `tabGL Entry`
-			where posting_date >= %s and voucher_no in (%s)""" %
-			('%s', ', '.join(['%s']*len(future_stock_vouchers))),
-			tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
-				gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
-
-	return gl_entries
diff --git a/erpnext/crm/utils.py b/erpnext/crm/utils.py
new file mode 100644
index 0000000..38bf79e
--- /dev/null
+++ b/erpnext/crm/utils.py
@@ -0,0 +1,24 @@
+import frappe
+
+
+def update_lead_phone_numbers(contact, method):
+	if contact.phone_nos:
+		contact_lead = contact.get_link_for("Lead")
+		if contact_lead:
+			phone = mobile_no = contact.phone_nos[0].phone
+
+			if len(contact.phone_nos) > 1:
+				# get the default phone number
+				primary_phones = [phone_doc.phone for phone_doc in contact.phone_nos if phone_doc.is_primary_phone]
+				if primary_phones:
+					phone = primary_phones[0]
+
+				# get the default mobile number
+				primary_mobile_nos = [phone_doc.phone for phone_doc in contact.phone_nos if phone_doc.is_primary_mobile_no]
+				if primary_mobile_nos:
+					mobile_no = primary_mobile_nos[0]
+
+			lead = frappe.get_doc("Lead", contact_lead)
+			lead.phone = phone
+			lead.mobile_no = mobile_no
+			lead.save()
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index f31003b..01f7b87 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -10,7 +10,7 @@
 from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
 from frappe.utils.csvutils import getlink
 from erpnext.controllers.accounts_controller import AccountsController
-from erpnext.accounts.general_ledger import delete_gl_entries
+from erpnext.accounts.general_ledger import make_reverse_gl_entries
 
 
 class Fees(AccountsController):
@@ -81,7 +81,8 @@
 			frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
 
 	def on_cancel(self):
-		delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+		make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name, cancel=True)
 		# frappe.db.set(self, 'status', 'Cancelled')
 
 
diff --git a/erpnext/education/doctype/video/__init__.py b/erpnext/education/doctype/video/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/education/doctype/video/__init__.py
+++ /dev/null
diff --git a/erpnext/education/doctype/video/test_video.js b/erpnext/education/doctype/video/test_video.js
deleted file mode 100644
index a82a221..0000000
--- a/erpnext/education/doctype/video/test_video.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Video", function (assert) {
-	let done = assert.async();
-
-	// number of asserts
-	assert.expect(1);
-
-	frappe.run_serially([
-		// insert a new Video
-		() => frappe.tests.make('Video', [
-			// values to be set
-			{key: 'value'}
-		]),
-		() => {
-			assert.equal(cur_frm.doc.key, 'value');
-		},
-		() => done()
-	]);
-
-});
diff --git a/erpnext/education/doctype/video/test_video.py b/erpnext/education/doctype/video/test_video.py
deleted file mode 100644
index ecb09a2..0000000
--- a/erpnext/education/doctype/video/test_video.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestVideo(unittest.TestCase):
-	pass
diff --git a/erpnext/education/doctype/video/video.js b/erpnext/education/doctype/video/video.js
deleted file mode 100644
index c35c19b..0000000
--- a/erpnext/education/doctype/video/video.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Video', {
-	refresh: function(frm) {
-
-	}
-});
diff --git a/erpnext/education/doctype/video/video.json b/erpnext/education/doctype/video/video.json
deleted file mode 100644
index e912eb3..0000000
--- a/erpnext/education/doctype/video/video.json
+++ /dev/null
@@ -1,112 +0,0 @@
-{
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:title",
- "creation": "2018-10-17 05:47:13.087395",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
-  "title",
-  "provider",
-  "url",
-  "column_break_4",
-  "publish_date",
-  "duration",
-  "section_break_7",
-  "description"
- ],
- "fields": [
-  {
-   "fieldname": "title",
-   "fieldtype": "Data",
-   "in_list_view": 1,
-   "label": "Title",
-   "reqd": 1,
-   "unique": 1
-  },
-  {
-   "fieldname": "description",
-   "fieldtype": "Text Editor",
-   "in_list_view": 1,
-   "label": "Description",
-   "reqd": 1
-  },
-  {
-   "fieldname": "duration",
-   "fieldtype": "Data",
-   "label": "Duration"
-  },
-  {
-   "fieldname": "url",
-   "fieldtype": "Data",
-   "in_list_view": 1,
-   "label": "URL",
-   "reqd": 1
-  },
-  {
-   "fieldname": "publish_date",
-   "fieldtype": "Date",
-   "label": "Publish Date"
-  },
-  {
-   "fieldname": "provider",
-   "fieldtype": "Select",
-   "in_list_view": 1,
-   "label": "Provider",
-   "options": "YouTube\nVimeo",
-   "reqd": 1
-  },
-  {
-   "fieldname": "column_break_4",
-   "fieldtype": "Column Break"
-  },
-  {
-   "fieldname": "section_break_7",
-   "fieldtype": "Section Break"
-  }
- ],
- "modified": "2019-06-12 12:36:48.753092",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Video",
- "owner": "Administrator",
- "permissions": [
-  {
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Academics User",
-   "share": 1,
-   "write": 1
-  },
-  {
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Instructor",
-   "share": 1,
-   "write": 1
-  },
-  {
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "LMS User",
-   "share": 1
-  }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/education/doctype/video/video.py b/erpnext/education/doctype/video/video.py
deleted file mode 100644
index b19f812..0000000
--- a/erpnext/education/doctype/video/video.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class Video(Document):
-
-
-	def get_video(self):
-		pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
index 5f36bdd..87c22cc 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
@@ -80,6 +80,7 @@
 							frappe.call({
 								method: 'complete_procedure',
 								doc: frm.doc,
+								freeze: true,
 								callback: function(r) {
 									if (r.message) {
 										frappe.show_alert({
@@ -87,8 +88,8 @@
 												['<a class="bold" href="#Form/Stock Entry/'+ r.message + '">' + r.message + '</a>']),
 											indicator: 'green'
 										});
-										frm.reload_doc();
 									}
+									frm.reload_doc();
 								}
 							});
 						}
@@ -111,9 +112,10 @@
 											frappe.call({
 												doc: frm.doc,
 												method: 'make_material_receipt',
+												freeze: true,
 												callback: function(r) {
 													if (!r.exc) {
-														cur_frm.reload_doc();
+														frm.reload_doc();
 														let doclist = frappe.model.sync(r.message);
 														frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
 													}
@@ -122,7 +124,7 @@
 										}
 									);
 								} else {
-									cur_frm.reload_doc();
+									frm.reload_doc();
 								}
 							}
 						}
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index db3afc8..b7d7a62 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -87,7 +87,8 @@
 			else:
 				frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found'))
 
-		frappe.db.set_value('Clinical Procedure', self.name, 'status', 'Completed')
+		self.db_set('status', 'Completed')
+
 		if self.consume_stock and self.items:
 			return stock_entry
 
@@ -245,9 +246,9 @@
 
 
 def insert_clinical_procedure_to_medical_record(doc):
-	subject = cstr(doc.procedure_template)
+	subject = frappe.bold(_("Clinical Procedure conducted: ")) + cstr(doc.procedure_template) + "<br>"
 	if doc.practitioner:
-		subject += ' ' + doc.practitioner
+		subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
 	if subject and doc.notes:
 		subject += '<br/>' + doc.notes
 
diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.js b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
index f450c9b..68db047 100644
--- a/erpnext/healthcare/doctype/exercise_type/exercise_type.js
+++ b/erpnext/healthcare/doctype/exercise_type/exercise_type.js
@@ -24,6 +24,8 @@
 
 		this.exercise_cards = $('<div class="exercise-cards"></div>').appendTo(this.wrapper);
 
+		this.row = $('<div class="exercise-row"></div>').appendTo(this.wrapper);
+
 		let me = this;
 
 		this.exercise_toolbar.find(".btn-add")
@@ -32,7 +34,7 @@
 				me.show_add_card_dialog(frm);
 			});
 
-		if (frm.doc.steps_table.length > 0) {
+		if (frm.doc.steps_table && frm.doc.steps_table.length > 0) {
 			this.make_cards(frm);
 			this.make_buttons(frm);
 		}
@@ -41,7 +43,6 @@
 	make_cards: function(frm) {
 		var me = this;
 		$(me.exercise_cards).empty();
-		this.row = $('<div class="exercise-row"></div>').appendTo(me.exercise_cards);
 
 		$.each(frm.doc.steps_table, function(i, step) {
 			$(repl(`
@@ -78,6 +79,7 @@
 				frm.doc.steps_table.pop(id);
 				frm.refresh_field('steps_table');
 				$('#col-'+id).remove();
+				frm.dirty();
 			}, 300);
 		});
 	},
@@ -106,7 +108,10 @@
 			],
 			primary_action: function() {
 				let data = d.get_values();
-				let i = frm.doc.steps_table.length;
+				let i = 0;
+				if (frm.doc.steps_table) {
+					i = frm.doc.steps_table.length;
+				}
 				$(repl(`
 					<div class="exercise-col col-sm-4" id="%(col_id)s">
 						<div class="card h-100 exercise-card" id="%(card_id)s">
@@ -165,9 +170,10 @@
 				frm.doc.steps_table[id].image = data.image;
 				frm.doc.steps_table[id].description = data.step_description;
 				refresh_field('steps_table');
+				frm.dirty();
 				new_dialog.hide();
 			},
-			primary_action_label: __("Save"),
+			primary_action_label: __("Edit"),
 		});
 
 		new_dialog.set_values({
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py
index 4e4015d..ea8ce25 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.py
@@ -288,23 +288,23 @@
 	table_row = False
 	subject = cstr(doc.lab_test_name)
 	if doc.practitioner:
-		subject += " "+ doc.practitioner
+		subject += frappe.bold(_("Healthcare Practitioner: "))+ doc.practitioner + "<br>"
 	if doc.normal_test_items:
 		item = doc.normal_test_items[0]
 		comment = ""
 		if item.lab_test_comment:
 			comment = str(item.lab_test_comment)
-		table_row = item.lab_test_name
+		table_row = frappe.bold(_("Lab Test Conducted: ")) + item.lab_test_name
 
 		if item.lab_test_event:
-			table_row += " " + item.lab_test_event
+			table_row += frappe.bold(_("Lab Test Event: ")) + item.lab_test_event
 
 		if item.result_value:
-			table_row += " " + item.result_value
+			table_row += " " + frappe.bold(_("Lab Test Result: ")) + item.result_value
 
 		if item.normal_range:
-			table_row += " normal_range("+item.normal_range+")"
-		table_row += " "+comment
+			table_row += " " + _("Normal Range:") + item.normal_range
+		table_row += " " + comment
 
 	elif doc.special_test_items:
 		item = doc.special_test_items[0]
@@ -316,12 +316,12 @@
 		item = doc.sensitivity_test_items[0]
 
 		if item.antibiotic and item.antibiotic_sensitivity:
-			table_row = item.antibiotic +" "+ item.antibiotic_sensitivity
+			table_row = item.antibiotic + " " + item.antibiotic_sensitivity
 
 	if table_row:
-		subject += "<br/>"+table_row
+		subject += "<br>" + table_row
 	if doc.lab_test_comment:
-		subject += "<br/>"+ cstr(doc.lab_test_comment)
+		subject += "<br>" + cstr(doc.lab_test_comment)
 
 	medical_record = frappe.new_doc("Patient Medical Record")
 	medical_record.patient = doc.patient
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index 767643b..1734c28 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -18,6 +18,9 @@
 	def after_insert(self):
 		insert_encounter_to_medical_record(self)
 
+	def on_submit(self):
+		update_encounter_medical_record(self)
+
 	def on_cancel(self):
 		if self.appointment:
 			frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open')
@@ -66,22 +69,26 @@
 	frappe.db.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name)
 
 def set_subject_field(encounter):
-	subject = encounter.practitioner + '\n'
+	subject = frappe.bold(_('Healthcare Practitioner: ')) + encounter.practitioner + '<br>'
 	if encounter.symptoms:
-		subject += _('Symptoms: ') + cstr(encounter.symptoms) + '\n'
+		subject += frappe.bold(_('Symptoms: ')) + '<br>'
+		for entry in encounter.symptoms:
+			subject += cstr(entry.complaint) + '<br>'
 	else:
-		subject +=  _('No Symptoms') + '\n'
+		subject += frappe.bold(_('No Symptoms')) + '<br>'
 
 	if encounter.diagnosis:
-		subject += _('Diagnosis: ') + cstr(encounter.diagnosis) + '\n'
+		subject += frappe.bold(_('Diagnosis: ')) + '<br>'
+		for entry in encounter.diagnosis:
+			subject += cstr(entry.diagnosis) + '<br>'
 	else:
-		subject += _('No Diagnosis') + '\n'
+		subject += frappe.bold(_('No Diagnosis')) + '<br>'
 
 	if encounter.drug_prescription:
-		subject += '\n' + _('Drug(s) Prescribed.')
+		subject += '<br>' + _('Drug(s) Prescribed.')
 	if encounter.lab_test_prescription:
-		subject += '\n' + _('Test(s) Prescribed.')
+		subject += '<br>' + _('Test(s) Prescribed.')
 	if encounter.procedure_prescription:
-		subject += '\n' + _('Procedure(s) Prescribed.')
+		subject += '<br>' + _('Procedure(s) Prescribed.')
 
 	return subject
diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json
index 3655e24..ed82355 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json
+++ b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json
@@ -57,7 +57,7 @@
   },
   {
    "fieldname": "subject",
-   "fieldtype": "Small Text",
+   "fieldtype": "Text Editor",
    "ignore_xss_filter": 1,
    "label": "Subject"
   },
@@ -125,7 +125,7 @@
  ],
  "in_create": 1,
  "links": [],
- "modified": "2020-03-23 19:26:59.308383",
+ "modified": "2020-04-29 12:26:57.679402",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Patient Medical Record",
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
index 201264f..c19be17 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
@@ -21,8 +21,14 @@
 				self.status = 'Completed'
 
 	def set_totals(self):
-		total_sessions = sum([int(d.no_of_sessions) for d in self.get('therapy_plan_details')])
-		total_sessions_completed = sum([int(d.sessions_completed) for d in self.get('therapy_plan_details')])
+		total_sessions = 0
+		total_sessions_completed = 0
+		for entry in self.therapy_plan_details:
+			if entry.no_of_sessions:
+				total_sessions += entry.no_of_sessions
+			if entry.sessions_completed:
+				total_sessions_completed += entry.sessions_completed
+
 		self.db_set('total_sessions', total_sessions)
 		self.db_set('total_sessions_completed', total_sessions_completed)
 
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
index bb67575..abe4def 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
@@ -13,23 +13,92 @@
 
 	refresh: function(frm) {
 		if (!frm.doc.__islocal) {
-			let target = 0;
-			let completed = 0;
-			$.each(frm.doc.exercises, function(_i, e) {
-				target += e.counts_target;
-				completed += e.counts_completed;
-			});
-			frm.dashboard.add_indicator(__('Counts Targetted: {0}', [target]), 'blue');
-			frm.dashboard.add_indicator(__('Counts Completed: {0}', [completed]), (completed < target) ? 'orange' : 'green');
+			frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue');
+			frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]),
+				(frm.doc.total_counts_completed < frm.doc.total_counts_targeted) ? 'orange' : 'green');
 		}
 
 		if (frm.doc.docstatus === 1) {
-			frm.add_custom_button(__('Patient Assessment'),function() {
+			frm.add_custom_button(__('Patient Assessment'), function() {
 				frappe.model.open_mapped_doc({
 					method: 'erpnext.healthcare.doctype.patient_assessment.patient_assessment.create_patient_assessment',
 					frm: frm,
 				})
 			}, 'Create');
+
+			frm.add_custom_button(__('Sales Invoice'), function() {
+				frappe.model.open_mapped_doc({
+					method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
+					frm: frm,
+				})
+			}, 'Create');
+		}
+	},
+
+	patient: function(frm) {
+		if (frm.doc.patient) {
+			frappe.call({
+				'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
+				args: {
+					patient: frm.doc.patient
+				},
+				callback: function (data) {
+					let age = '';
+					if (data.message.dob) {
+						age = calculate_age(data.message.dob);
+					} else if (data.message.age) {
+						age = data.message.age;
+						if (data.message.age_as_on) {
+							age = __('{0} as on {1}', [age, data.message.age_as_on]);
+						}
+					}
+					frm.set_value('patient_age', age);
+					frm.set_value('gender', data.message.sex);
+					frm.set_value('patient_name', data.message.patient_name);
+				}
+			});
+		} else {
+			frm.set_value('patient_age', '');
+			frm.set_value('gender', '');
+			frm.set_value('patient_name', '');
+		}
+	},
+
+	appointment: function(frm) {
+		if (frm.doc.appointment) {
+			frappe.call({
+				'method': 'frappe.client.get',
+				args: {
+					doctype: 'Patient Appointment',
+					name: frm.doc.appointment
+				},
+				callback: function(data) {
+					let values = {
+						'patient':data.message.patient,
+						'therapy_type': data.message.therapy_type,
+						'therapy_plan': data.message.therapy_plan,
+						'practitioner': data.message.practitioner,
+						'department': data.message.department,
+						'start_date': data.message.appointment_date,
+						'start_time': data.message.appointment_time,
+						'service_unit': data.message.service_unit,
+						'company': data.message.company
+					};
+					frm.set_value(values);
+				}
+			});
+		} else {
+			let values = {
+				'patient': '',
+				'therapy_type': '',
+				'therapy_plan': '',
+				'practitioner': '',
+				'department': '',
+				'start_date': '',
+				'start_time': '',
+				'service_unit': '',
+			};
+			frm.set_value(values);
 		}
 	},
 
@@ -44,6 +113,8 @@
 				callback: function(data) {
 					frm.set_value('duration', data.message.default_duration);
 					frm.set_value('rate', data.message.rate);
+					frm.set_value('service_unit', data.message.healthcare_service_unit);
+					frm.set_value('department', data.message.medical_department);
 					frm.doc.exercises = [];
 					$.each(data.message.exercises, function(_i, e) {
 						let exercise = frm.add_child('exercises');
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
index 5ff7196..00d74a0 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
@@ -9,9 +9,11 @@
   "naming_series",
   "appointment",
   "patient",
+  "patient_name",
   "patient_age",
   "gender",
   "column_break_5",
+  "company",
   "therapy_plan",
   "therapy_type",
   "practitioner",
@@ -20,7 +22,6 @@
   "duration",
   "rate",
   "location",
-  "company",
   "column_break_12",
   "service_unit",
   "start_date",
@@ -28,6 +29,10 @@
   "invoiced",
   "exercises_section",
   "exercises",
+  "section_break_23",
+  "total_counts_targeted",
+  "column_break_25",
+  "total_counts_completed",
   "amended_from"
  ],
  "fields": [
@@ -159,7 +164,8 @@
    "fieldname": "company",
    "fieldtype": "Link",
    "label": "Company",
-   "options": "Company"
+   "options": "Company",
+   "reqd": 1
   },
   {
    "default": "0",
@@ -173,11 +179,38 @@
    "fieldtype": "Data",
    "label": "Patient Age",
    "read_only": 1
+  },
+  {
+   "fieldname": "total_counts_targeted",
+   "fieldtype": "Int",
+   "label": "Total Counts Targeted",
+   "read_only": 1
+  },
+  {
+   "fieldname": "total_counts_completed",
+   "fieldtype": "Int",
+   "label": "Total Counts Completed",
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_23",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "column_break_25",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "patient.patient_name",
+   "fieldname": "patient_name",
+   "fieldtype": "Data",
+   "label": "Patient Name",
+   "read_only": 1
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-21 13:16:46.378798",
+ "modified": "2020-04-29 16:49:16.286006",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Therapy Session",
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
index 45d2ee6..9650183 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
@@ -6,10 +6,17 @@
 import frappe
 from frappe.model.document import Document
 from frappe.model.mapper import get_mapped_doc
+from frappe import _
+from frappe.utils import cstr, getdate
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
 
 class TherapySession(Document):
+	def validate(self):
+		self.set_total_counts()
+
 	def on_submit(self):
 		self.update_sessions_count_in_therapy_plan()
+		insert_session_medical_record(self)
 
 	def on_cancel(self):
 		self.update_sessions_count_in_therapy_plan(on_cancel=True)
@@ -24,6 +31,18 @@
 					entry.sessions_completed += 1
 		therapy_plan.save()
 
+	def set_total_counts(self):
+		target_total = 0
+		counts_completed = 0
+		for entry in self.exercises:
+			if entry.counts_target:
+				target_total += entry.counts_target
+			if entry.counts_completed:
+				counts_completed += entry.counts_completed
+
+		self.db_set('total_counts_targeted', target_total)
+		self.db_set('total_counts_completed', counts_completed)
+
 
 @frappe.whitelist()
 def create_therapy_session(source_name, target_doc=None):
@@ -52,4 +71,62 @@
 			}
 		}, target_doc, set_missing_values)
 
-	return doc
\ No newline at end of file
+	return doc
+
+
+@frappe.whitelist()
+def invoice_therapy_session(source_name, target_doc=None):
+	def set_missing_values(source, target):
+		target.customer = frappe.db.get_value('Patient', source.patient, 'customer')
+		target.due_date = getdate()
+		target.debit_to = get_receivable_account(source.company)
+		item = target.append('items', {})
+		item = get_therapy_item(source, item)
+		target.set_missing_values(for_validate=True)
+
+	doc = get_mapped_doc('Therapy Session', source_name, {
+			'Therapy Session': {
+				'doctype': 'Sales Invoice',
+				'field_map': [
+					['patient', 'patient'],
+					['referring_practitioner', 'practitioner'],
+					['company', 'company'],
+					['due_date', 'start_date']
+				]
+			}
+		}, target_doc, set_missing_values)
+
+	return doc
+
+
+def get_therapy_item(therapy, item):
+	item.item_code = frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item')
+	item.description = _('Therapy Session Charges: {0}').format(therapy.practitioner)
+	item.income_account = get_income_account(therapy.practitioner, therapy.company)
+	item.cost_center = frappe.get_cached_value('Company', therapy.company, 'cost_center')
+	item.rate = therapy.rate
+	item.amount = therapy.rate
+	item.qty = 1
+	item.reference_dt = 'Therapy Session'
+	item.reference_dn = therapy.name
+	return item
+
+
+def insert_session_medical_record(doc):
+	subject = frappe.bold(_('Therapy: ')) + cstr(doc.therapy_type) + '<br>'
+	if doc.therapy_plan:
+		subject += frappe.bold(_('Therapy Plan: ')) + cstr(doc.therapy_plan) + '<br>'
+	if doc.practitioner:
+		subject += frappe.bold(_('Healthcare Practitioner: ')) + doc.practitioner
+	subject += frappe.bold(_('Total Counts Targeted: ')) + cstr(doc.total_counts_targeted) + '<br>'
+	subject += frappe.bold(_('Total Counts Completed: ')) + cstr(doc.total_counts_completed) + '<br>'
+
+	medical_record = frappe.new_doc('Patient Medical Record')
+	medical_record.patient = doc.patient
+	medical_record.subject = subject
+	medical_record.status = 'Open'
+	medical_record.communication_date = doc.start_date
+	medical_record.reference_doctype = 'Therapy Session'
+	medical_record.reference_name = doc.name
+	medical_record.reference_owner = doc.owner
+	medical_record.save(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
index 959e850..b0e78e8 100644
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py
+++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
@@ -35,17 +35,17 @@
 
 def set_subject_field(doc):
 	subject = ''
-	if(doc.temperature):
-		subject += _('Temperature: ') + '\n'+ cstr(doc.temperature) + '. '
-	if(doc.pulse):
-		subject += _('Pulse: ') + '\n' + cstr(doc.pulse) + '. '
-	if(doc.respiratory_rate):
-		subject += _('Respiratory Rate: ') + '\n' + cstr(doc.respiratory_rate) + '. '
-	if(doc.bp):
-		subject += _('BP: ') + '\n' + cstr(doc.bp) + '. '
-	if(doc.bmi):
-		subject += _('BMI: ') + '\n' + cstr(doc.bmi) + '. '
-	if(doc.nutrition_note):
-		subject += _('Note: ') + '\n' + cstr(doc.nutrition_note) + '. '
+	if doc.temperature:
+		subject += frappe.bold(_('Temperature: ')) + cstr(doc.temperature) + '<br>'
+	if doc.pulse:
+		subject += frappe.bold(_('Pulse: ')) + cstr(doc.pulse) + '<br>'
+	if doc.respiratory_rate:
+		subject += frappe.bold(_('Respiratory Rate: ')) + cstr(doc.respiratory_rate) + '<br>'
+	if doc.bp:
+		subject += frappe.bold(_('BP: ')) + cstr(doc.bp) + '<br>'
+	if doc.bmi:
+		subject += frappe.bold(_('BMI: ')) + cstr(doc.bmi) + '<br>'
+	if doc.nutrition_note:
+		subject += frappe.bold(_('Note: ')) + cstr(doc.nutrition_note) + '<br>'
 
 	return subject
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index e6f6c8e..6b198e7 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -250,7 +250,8 @@
 	},
 	"Contact": {
 		"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
-		"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
+		"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information",
+		"validate": "erpnext.crm.utils.update_lead_phone_numbers"
 	},
 	"Lead": {
 		"after_insert": "erpnext.communication.doctype.call_log.call_log.set_caller_information"
@@ -537,4 +538,4 @@
 		{'doctype': 'Hotel Room Package', 'index': 3},
 		{'doctype': 'Hotel Room Type', 'index': 4}
 	]
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json
index 743aa23..22aa170 100644
--- a/erpnext/hr/desk_page/hr/hr.json
+++ b/erpnext/hr/desk_page/hr/hr.json
@@ -23,7 +23,7 @@
   {
    "hidden": 0,
    "label": "Payroll",
-   "links": "[\n    {\n        \"label\": \"Salary Structure\",\n        \"name\": \"Salary Structure\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Salary Structure\",\n            \"Employee\"\n        ],\n        \"label\": \"Salary Structure Assignment\",\n        \"name\": \"Salary Structure Assignment\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Payroll Entry\",\n        \"name\": \"Payroll Entry\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Salary Slip\",\n        \"name\": \"Salary Slip\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Payroll Period\",\n        \"name\": \"Payroll Period\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Salary Component\",\n        \"name\": \"Salary Component\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Additional Salary\",\n        \"name\": \"Additional Salary\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Retention Bonus\",\n        \"name\": \"Retention Bonus\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Incentive\",\n        \"name\": \"Employee Incentive\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Salary Slip\"\n        ],\n        \"doctype\": \"Salary Slip\",\n        \"is_query_report\": true,\n        \"label\": \"Salary Register\",\n        \"name\": \"Salary Register\",\n        \"type\": \"report\"\n    }\n]"
+   "links": "[\n    {\n        \"label\": \"Salary Structure\",\n        \"name\": \"Salary Structure\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Salary Structure\",\n            \"Employee\"\n        ],\n        \"label\": \"Salary Structure Assignment\",\n        \"name\": \"Salary Structure Assignment\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Payroll Entry\",\n        \"name\": \"Payroll Entry\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Salary Slip\",\n        \"name\": \"Salary Slip\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Payroll Period\",\n        \"name\": \"Payroll Period\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Income Tax Slab\",\n        \"name\": \"Income Tax Slab\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Salary Component\",\n        \"name\": \"Salary Component\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Additional Salary\",\n        \"name\": \"Additional Salary\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Retention Bonus\",\n        \"name\": \"Retention Bonus\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Incentive\",\n        \"name\": \"Employee Incentive\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Salary Slip\"\n        ],\n        \"doctype\": \"Salary Slip\",\n        \"is_query_report\": true,\n        \"label\": \"Salary Register\",\n        \"name\": \"Salary Register\",\n        \"type\": \"report\"\n    }\n]"
   },
   {
    "hidden": 0,
@@ -73,7 +73,7 @@
   {
    "hidden": 0,
    "label": "Employee Tax and Benefits",
-   "links": "[\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Declaration\",\n        \"name\": \"Employee Tax Exemption Declaration\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Proof Submission\",\n        \"name\": \"Employee Tax Exemption Proof Submission\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Benefit Application\",\n        \"name\": \"Employee Benefit Application\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Benefit Claim\",\n        \"name\": \"Employee Benefit Claim\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Category\",\n        \"name\": \"Employee Tax Exemption Category\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Sub Category\",\n        \"name\": \"Employee Tax Exemption Sub Category\",\n        \"type\": \"doctype\"\n    }\n]"
+   "links": "[\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Declaration\",\n        \"name\": \"Employee Tax Exemption Declaration\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Proof Submission\",\n        \"name\": \"Employee Tax Exemption Proof Submission\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\",\n            \"Payroll Period\"\n        ],\n        \"label\": \"Employee Other Income\",\n        \"name\": \"Employee Other Income\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Benefit Application\",\n        \"name\": \"Employee Benefit Application\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Benefit Claim\",\n        \"name\": \"Employee Benefit Claim\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Category\",\n        \"name\": \"Employee Tax Exemption Category\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"dependencies\": [\n            \"Employee\"\n        ],\n        \"label\": \"Employee Tax Exemption Sub Category\",\n        \"name\": \"Employee Tax Exemption Sub Category\",\n        \"type\": \"doctype\"\n    }\n]"
   }
  ],
  "category": "Modules",
@@ -88,7 +88,7 @@
  "idx": 0,
  "is_standard": 1,
  "label": "HR",
- "modified": "2020-04-01 11:28:50.860012",
+ "modified": "2020-04-29 20:29:22.114309",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR",
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index ad9d86b..ac1bfa1 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -76,6 +76,7 @@
 
 	def on_cancel(self):
 		self.update_task_and_project()
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 		if self.payable_account:
 			self.make_gl_entries(cancel=True)
 
@@ -260,10 +261,17 @@
 			if not expense.default_account or not validate:
 				expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"]
 
-def update_reimbursed_amount(doc):
-	amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) as amt
+def update_reimbursed_amount(doc, jv=None):
+
+	condition = ""
+
+	if jv:
+		condition += "and voucher_no = '{0}'".format(jv)
+
+	amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) - ifnull(sum(credit_in_account_currency), 0)as amt
 		from `tabGL Entry` where against_voucher_type = 'Expense Claim' and against_voucher = %s
-		and party = %s """, (doc.name, doc.employee) ,as_dict=1)[0].amt
+		and party = %s {condition}""".format(condition=condition), #nosec
+		(doc.name, doc.employee) ,as_dict=1)[0].amt
 
 	doc.total_amount_reimbursed = amt
 	frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt)
diff --git a/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
index 6d89b19..f74315f 100644
--- a/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
+++ b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
@@ -80,6 +80,7 @@
   },
   {
    "collapsible": 1,
+   "collapsible_depends_on": "other_taxes_and_charges",
    "fieldname": "taxes_and_charges_on_income_tax_section",
    "fieldtype": "Section Break",
    "label": "Taxes and Charges on Income Tax"
@@ -93,13 +94,15 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-24 12:28:36.805904",
+ "modified": "2020-04-29 15:08:21.436120",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Income Tax Slab",
  "owner": "Administrator",
  "permissions": [
   {
+   "amend": 1,
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -109,9 +112,11 @@
    "report": 1,
    "role": "System Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   },
   {
+   "amend": 1,
    "cancel": 1,
    "create": 1,
    "delete": 1,
@@ -126,6 +131,7 @@
    "write": 1
   },
   {
+   "amend": 1,
    "cancel": 1,
    "create": 1,
    "delete": 1,
@@ -138,20 +144,6 @@
    "share": 1,
    "submit": 1,
    "write": 1
-  },
-  {
-   "cancel": 1,
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Administrator",
-   "share": 1,
-   "submit": 1,
-   "write": 1
   }
  ],
  "sort_field": "modified",
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
index d25eb6d..da25d75 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
@@ -249,7 +249,7 @@
 
 let make_bank_entry = function (frm) {
 	var doc = frm.doc;
-	if (doc.company && doc.start_date && doc.end_date && doc.payment_account) {
+	if (doc.payment_account) {
 		return frappe.call({
 			doc: cur_frm.doc,
 			method: "make_payment_entry",
@@ -262,7 +262,8 @@
 			freeze_message: __("Creating Payment Entries......")
 		});
 	} else {
-		frappe.msgprint(__("Company, Payment Account, From Date and To Date is mandatory"));
+		frappe.msgprint(__("Payment Account is mandatory"));
+		frm.scroll_to_field('payment_account');
 	}
 };
 
diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json
index 5487e1d..97c46c8 100644
--- a/erpnext/hr/doctype/salary_component/salary_component.json
+++ b/erpnext/hr/doctype/salary_component/salary_component.json
@@ -227,7 +227,7 @@
   {
    "default": "0",
    "depends_on": "eval:doc.type == \"Deduction\" && !doc.variable_based_on_taxable_salary",
-   "description": "If checked, the full amount will be deducted from taxable income before calculating income tax. Otherwise, it can be exempted via Employee Tax Exemption Declaration.",
+   "description": "If checked, the full amount will be deducted from taxable income before calculating income tax without any declaration or proof submission.",
    "fieldname": "exempted_from_income_tax",
    "fieldtype": "Check",
    "label": "Exempted from Income Tax"
@@ -235,7 +235,7 @@
  ],
  "icon": "fa fa-flag",
  "links": [],
- "modified": "2020-04-24 14:50:28.994054",
+ "modified": "2020-04-28 15:46:45.252945",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Salary Component",
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 8a4da7e..db93f31 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -549,15 +549,16 @@
 		remaining_sub_periods = get_period_factor(self.employee,
 			self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
 		# get taxable_earnings, paid_taxes for previous period
-		previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date, self.start_date)
+		previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date,
+			self.start_date, tax_slab.allow_tax_exemption)
 		previous_total_paid_taxes = self.get_tax_paid_in_period(payroll_period.start_date, self.start_date, tax_component)
 
 		# get taxable_earnings for current period (all days)
-		current_taxable_earnings = self.get_taxable_earnings()
+		current_taxable_earnings = self.get_taxable_earnings(tax_slab.allow_tax_exemption)
 		future_structured_taxable_earnings = current_taxable_earnings.taxable_earnings * (math.ceil(remaining_sub_periods) - 1)
 
 		# get taxable_earnings, addition_earnings for current actual payment days
-		current_taxable_earnings_for_payment_days = self.get_taxable_earnings(based_on_payment_days=1)
+		current_taxable_earnings_for_payment_days = self.get_taxable_earnings(tax_slab.allow_tax_exemption, based_on_payment_days=1)
 		current_structured_taxable_earnings = current_taxable_earnings_for_payment_days.taxable_earnings
 		current_additional_earnings = current_taxable_earnings_for_payment_days.additional_income
 		current_additional_earnings_with_full_tax = current_taxable_earnings_for_payment_days.additional_income_with_full_tax
@@ -616,7 +617,7 @@
 		return income_tax_slab_doc
 
 
-	def get_taxable_earnings_for_prev_period(self, start_date, end_date):
+	def get_taxable_earnings_for_prev_period(self, start_date, end_date, allow_tax_exemption=False):
 		taxable_earnings = frappe.db.sql("""
 			select sum(sd.amount)
 			from
@@ -636,24 +637,26 @@
 			})
 		taxable_earnings = flt(taxable_earnings[0][0]) if taxable_earnings else 0
 
-		exempted_amount = frappe.db.sql("""
-			select sum(sd.amount)
-			from
-				`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
-			where
-				sd.parentfield='deductions'
-				and sd.exempted_from_income_tax=1
-				and is_flexible_benefit=0
-				and ss.docstatus=1
-				and ss.employee=%(employee)s
-				and ss.start_date between %(from_date)s and %(to_date)s
-				and ss.end_date between %(from_date)s and %(to_date)s
-			""", {
-				"employee": self.employee,
-				"from_date": start_date,
-				"to_date": end_date
-			})
-		exempted_amount = flt(exempted_amount[0][0]) if exempted_amount else 0
+		exempted_amount = 0
+		if allow_tax_exemption:
+			exempted_amount = frappe.db.sql("""
+				select sum(sd.amount)
+				from
+					`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
+				where
+					sd.parentfield='deductions'
+					and sd.exempted_from_income_tax=1
+					and is_flexible_benefit=0
+					and ss.docstatus=1
+					and ss.employee=%(employee)s
+					and ss.start_date between %(from_date)s and %(to_date)s
+					and ss.end_date between %(from_date)s and %(to_date)s
+				""", {
+					"employee": self.employee,
+					"from_date": start_date,
+					"to_date": end_date
+				})
+			exempted_amount = flt(exempted_amount[0][0]) if exempted_amount else 0
 
 		return taxable_earnings - exempted_amount
 
@@ -681,7 +684,7 @@
 
 		return total_tax_paid
 
-	def get_taxable_earnings(self, based_on_payment_days=0):
+	def get_taxable_earnings(self, allow_tax_exemption=False, based_on_payment_days=0):
 		joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
 			["date_of_joining", "relieving_date"])
 
@@ -715,12 +718,13 @@
 				else:
 					taxable_earnings += amount
 
-		for ded in self.deductions:
-			if ded.exempted_from_income_tax:
-				amount = ded.amount
-				if based_on_payment_days:
-					amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date)[0]
-				taxable_earnings -= flt(amount)
+		if allow_tax_exemption:
+			for ded in self.deductions:
+				if ded.exempted_from_income_tax:
+					amount = ded.amount
+					if based_on_payment_days:
+						amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date)[0]
+					taxable_earnings -= flt(amount)
 
 		return frappe._dict({
 			"taxable_earnings": taxable_earnings,
@@ -822,13 +826,13 @@
 		for slab in tax_slab.slabs:
 			if slab.condition and not self.eval_tax_slab_condition(slab.condition, data):
 				continue
-			if not slab.to_amount and annual_taxable_earning > slab.from_amount:
-				tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
+			if not slab.to_amount and annual_taxable_earning >= slab.from_amount:
+				tax_amount += (annual_taxable_earning - slab.from_amount + 1) * slab.percent_deduction *.01
 				continue
-			if annual_taxable_earning > slab.from_amount and annual_taxable_earning < slab.to_amount:
-				tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
-			elif annual_taxable_earning > slab.from_amount and annual_taxable_earning > slab.to_amount:
-				tax_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
+			if annual_taxable_earning >= slab.from_amount and annual_taxable_earning < slab.to_amount:
+				tax_amount += (annual_taxable_earning - slab.from_amount + 1) * slab.percent_deduction *.01
+			elif annual_taxable_earning >= slab.from_amount and annual_taxable_earning >= slab.to_amount:
+				tax_amount += (slab.to_amount - slab.from_amount + 1) * slab.percent_deduction * .01
 
 		# other taxes and charges on income tax
 		for d in tax_slab.other_taxes_and_charges:
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
index e5622b7..eab58ff 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
@@ -12,7 +12,8 @@
 	columns, data, chart = [], [], []
 	if filters.get('fiscal_year'):
 		company = erpnext.get_default_company()
-		period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'),"Monthly", company)
+		period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'),
+		'', '', 'Fiscal Year', 'Monthly', company=company)
 		columns=get_columns()
 		data=get_log_data(filters)
 		chart=get_chart_data(data,period_list)
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.json b/erpnext/loan_management/doctype/loan_security/loan_security.json
index e879b17..1d0bb30 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.json
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.json
@@ -1,18 +1,17 @@
 {
  "actions": [],
  "allow_rename": 1,
- "autoname": "field:loan_security_name",
  "creation": "2019-09-02 15:07:08.885593",
  "doctype": "DocType",
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
   "loan_security_name",
-  "unit_of_measure",
+  "haircut",
   "loan_security_code",
   "column_break_3",
   "loan_security_type",
-  "haircut",
+  "unit_of_measure",
   "disabled"
  ],
  "fields": [
@@ -66,7 +65,7 @@
   }
  ],
  "links": [],
- "modified": "2020-04-28 14:07:54.506896",
+ "modified": "2020-04-29 13:21:26.043492",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security",
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.py b/erpnext/loan_management/doctype/loan_security/loan_security.py
index 800ad12..8858c81 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.py
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.py
@@ -7,4 +7,5 @@
 from frappe.model.document import Document
 
 class LoanSecurity(Document):
-	pass
+	def autoname(self):
+		self.name = self.loan_security_name
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 26f580d..ca67d71 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -62,9 +62,9 @@
 
 	def test_production_plan_for_existing_ordered_qty(self):
 		sr1 = create_stock_reconciliation(item_code="Raw Material Item 1",
-			target="_Test Warehouse - _TC", qty=1, rate=100)
+			target="_Test Warehouse - _TC", qty=1, rate=110)
 		sr2 = create_stock_reconciliation(item_code="Raw Material Item 2",
-			target="_Test Warehouse - _TC", qty=1, rate=100)
+			target="_Test Warehouse - _TC", qty=1, rate=120)
 
 		pln = create_production_plan(item_code='Test Production Item 1', ignore_existing_ordered_qty=0)
 		self.assertTrue(len(pln.mr_items), 1)
@@ -86,9 +86,9 @@
 
 	def test_production_plan_without_multi_level_for_existing_ordered_qty(self):
 		sr1 = create_stock_reconciliation(item_code="Raw Material Item 1",
-			target="_Test Warehouse - _TC", qty=1, rate=100)
+			target="_Test Warehouse - _TC", qty=1, rate=130)
 		sr2 = create_stock_reconciliation(item_code="Subassembly Item 1",
-			target="_Test Warehouse - _TC", qty=1, rate=100)
+			target="_Test Warehouse - _TC", qty=1, rate=140)
 
 		pln = create_production_plan(item_code='Test Production Item 1',
 			use_multi_level_bom=0, ignore_existing_ordered_qty=0)
diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py
index a523a23..a81bf30 100644
--- a/erpnext/non_profit/doctype/membership/membership.py
+++ b/erpnext/non_profit/doctype/membership/membership.py
@@ -62,11 +62,9 @@
 					'subscription_id': subscription_id,
 					'email_id': email
 				}, order_by="creation desc")
-
 	return frappe.get_doc("Member", members[0]['name'])
 
-
-@frappe.whitelist()
+@frappe.whitelist(allow_guest=True)
 def trigger_razorpay_subscription(data):
 	if isinstance(data, six.string_types):
 		data = json.loads(data)
@@ -88,10 +86,13 @@
 
 	if data.event == "subscription.activated":
 		member.customer_id = payment.customer_id
-		member.subscription_start = datetime.fromtimestamp(subscription.start_at)
-		member.subscription_end = datetime.fromtimestamp(subscription.end_at)
-		member.subscription_activated = 1
-		member.save(ignore_permissions=True)
+
+	# Update these values anyway
+	member.subscription_start = datetime.fromtimestamp(subscription.start_at)
+	member.subscription_end = datetime.fromtimestamp(subscription.end_at)
+	member.subscription_activated = 1
+	member.save(ignore_permissions=True)
+
 	elif data.event == "subscription.charged":
 		membership = frappe.new_doc("Membership")
 		membership.update({
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index a216f53..275dd9f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -1,6 +1,7 @@
 execute:import unidecode # new requirement
 erpnext.patches.v8_0.move_perpetual_inventory_setting
 erpnext.patches.v8_9.set_print_zero_amount_taxes
+erpnext.patches.v12_0.update_is_cancelled_field
 erpnext.patches.v11_0.rename_production_order_to_work_order
 erpnext.patches.v11_0.refactor_naming_series
 erpnext.patches.v11_0.refactor_autoname_naming
@@ -261,7 +262,6 @@
 erpnext.patches.v6_21.fix_reorder_level
 erpnext.patches.v6_21.rename_material_request_fields
 erpnext.patches.v6_23.update_stopped_status_to_closed
-erpnext.patches.v6_24.repost_valuation_rate_for_serialized_items
 erpnext.patches.v6_24.set_recurring_id
 erpnext.patches.v6_20x.set_compact_print
 execute:frappe.delete_doc_if_exists("Web Form", "contact") #2016-03-10
@@ -315,7 +315,6 @@
 erpnext.patches.v7_0.rename_examination_to_assessment
 erpnext.patches.v7_0.set_portal_settings
 erpnext.patches.v7_0.update_change_amount_account
-erpnext.patches.v7_0.repost_future_gle_for_purchase_invoice
 erpnext.patches.v7_0.fix_duplicate_icons
 erpnext.patches.v7_0.repost_gle_for_pos_sales_return
 erpnext.patches.v7_1.update_total_billing_hours
@@ -674,4 +673,5 @@
 erpnext.patches.v12_0.update_end_date_and_status_in_email_campaign
 erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab #123
 erpnext.patches.v12_0.fix_quotation_expired_status
-erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
\ No newline at end of file
+erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
+erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
diff --git a/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py b/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py
index 68c06ef..e6546e3 100644
--- a/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py
+++ b/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py
@@ -24,9 +24,9 @@
 			doc = frappe.get_doc("Purchase Receipt", d.name)
 
 			doc.docstatus = 2
-			doc.make_gl_entries_on_cancel(repost_future_gle=False)
+			doc.make_gl_entries_on_cancel()
 
 
 			# update gl entries for submit state of PR
 			doc.docstatus = 1
-			doc.make_gl_entries(repost_future_gle=False)
+			doc.make_gl_entries()
diff --git a/erpnext/patches/v10_0/taxes_issue_with_pos.py b/erpnext/patches/v10_0/taxes_issue_with_pos.py
index 9b54297..2a3275a 100644
--- a/erpnext/patches/v10_0/taxes_issue_with_pos.py
+++ b/erpnext/patches/v10_0/taxes_issue_with_pos.py
@@ -19,7 +19,7 @@
 			doc.db_update()
 
 			delete_gle_for_voucher(doc.name)
-			doc.make_gl_entries(repost_future_gle=False)
+			doc.make_gl_entries()
 
 def delete_gle_for_voucher(voucher_no):
 	frappe.db.sql("""delete from `tabGL Entry` where voucher_no = %(voucher_no)s""",
diff --git a/erpnext/patches/v12_0/retain_permission_rules_for_video_doctype.py b/erpnext/patches/v12_0/retain_permission_rules_for_video_doctype.py
new file mode 100644
index 0000000..ca8a13b
--- /dev/null
+++ b/erpnext/patches/v12_0/retain_permission_rules_for_video_doctype.py
@@ -0,0 +1,21 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	# to retain the roles and permissions from Education Module
+	# after moving doctype to core
+	permissions = frappe.db.sql("""
+		SELECT
+			*
+		FROM
+			`tabDocPerm`
+		WHERE
+			parent='Video'
+	""", as_dict=True)
+
+	frappe.reload_doc('core', 'doctype', 'video')
+	doc = frappe.get_doc('DocType', 'Video')
+	doc.permissions = []
+	for perm in permissions:
+		doc.append('permissions', perm)
+	doc.save()
diff --git a/erpnext/patches/v12_0/set_total_batch_quantity.py b/erpnext/patches/v12_0/set_total_batch_quantity.py
index d373275..7296eaa 100644
--- a/erpnext/patches/v12_0/set_total_batch_quantity.py
+++ b/erpnext/patches/v12_0/set_total_batch_quantity.py
@@ -6,6 +6,6 @@
 
 	for batch in frappe.get_all("Batch", fields=["name", "batch_id"]):
 		batch_qty = frappe.db.get_value("Stock Ledger Entry",
-			{"docstatus": 1, "batch_no": batch.batch_id, "is_cancelled": "No"},
+			{"docstatus": 1, "batch_no": batch.batch_id, "is_cancelled": 0},
 			"sum(actual_qty)") or 0.0
 		frappe.db.set_value("Batch", batch.name, "batch_qty", batch_qty, update_modified=False)
diff --git a/erpnext/patches/v12_0/update_is_cancelled_field.py b/erpnext/patches/v12_0/update_is_cancelled_field.py
new file mode 100644
index 0000000..0b2e827
--- /dev/null
+++ b/erpnext/patches/v12_0/update_is_cancelled_field.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	try:
+		frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')")
+		frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')")
+
+		frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 1 where is_cancelled = 'Yes'")
+		frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 1 where is_cancelled = 'Yes'")
+
+		frappe.reload_doc("stock", "doctype", "stock_ledger_entry")
+		frappe.reload_doc("stock", "doctype", "serial_no")
+	except:
+		pass
\ No newline at end of file
diff --git a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
index 16932af..c6c94d4 100644
--- a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
+++ b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
@@ -8,7 +8,7 @@
 def execute():
 	from erpnext.stock.stock_balance import repost
 	repost(allow_zero_rate=True, only_actual=True)
-	
+
 	frappe.reload_doctype("Account")
 
 	warehouse_account = frappe.db.sql("""select name, master_name from tabAccount
@@ -43,7 +43,7 @@
 						where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
 
 					voucher = frappe.get_doc(voucher_type, voucher_no)
-					voucher.make_gl_entries(repost_future_gle=False)
+					voucher.make_gl_entries()
 					frappe.db.commit()
 				except Exception as e:
 					print(frappe.get_traceback())
diff --git a/erpnext/patches/v6_24/repost_valuation_rate_for_serialized_items.py b/erpnext/patches/v6_24/repost_valuation_rate_for_serialized_items.py
deleted file mode 100644
index 3b157a3..0000000
--- a/erpnext/patches/v6_24/repost_valuation_rate_for_serialized_items.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.utils import today
-from erpnext.accounts.utils import get_fiscal_year
-from erpnext.stock.stock_ledger import update_entries_after
-
-def execute():
-	try:
-		year_start_date = get_fiscal_year(today())[1]
-	except:
-		return
-	
-	if year_start_date:
-		items = frappe.db.sql("""select distinct item_code, warehouse from `tabStock Ledger Entry` 
-			where ifnull(serial_no, '') != '' and actual_qty > 0 and incoming_rate=0""", as_dict=1)
-		
-		for d in items:
-			try:
-				update_entries_after({
-					"item_code": d.item_code, 
-					"warehouse": d.warehouse,
-					"posting_date": year_start_date
-				}, allow_zero_rate=True)
-			except:
-				pass
\ No newline at end of file
diff --git a/erpnext/patches/v7_0/repost_future_gle_for_purchase_invoice.py b/erpnext/patches/v7_0/repost_future_gle_for_purchase_invoice.py
deleted file mode 100644
index 9e21fb6..0000000
--- a/erpnext/patches/v7_0/repost_future_gle_for_purchase_invoice.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.utils import cint
-from erpnext.stock import get_warehouse_account_map
-from erpnext.controllers.stock_controller import update_gl_entries_after
-
-def execute():
-	company_list = frappe.db.sql_list("""Select name from tabCompany where enable_perpetual_inventory = 1""")
-	frappe.reload_doc('accounts', 'doctype', 'sales_invoice')
-
-	frappe.reload_doctype("Purchase Invoice")
-	wh_account = get_warehouse_account_map()
-
-	for pi in frappe.get_all("Purchase Invoice", fields=["name", "company"], filters={"docstatus": 1, "update_stock": 1}):
-		if pi.company in company_list:
-			pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
-			items, warehouses = pi_doc.get_items_and_warehouses()
-			update_gl_entries_after(pi_doc.posting_date, pi_doc.posting_time,
-				warehouses, items, wh_account, company = pi.company)
-
-			frappe.db.commit()
\ No newline at end of file
diff --git a/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py b/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py
index 2d1a151..b864e59 100644
--- a/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py
+++ b/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py
@@ -8,13 +8,13 @@
 def execute():
 	frappe.reload_doctype("Purchase Invoice")
 
-	for pi in frappe.db.sql("""select name from `tabPurchase Invoice` 
-		where company in(select name from tabCompany where enable_perpetual_inventory = 1) and 
+	for pi in frappe.db.sql("""select name from `tabPurchase Invoice`
+		where company in(select name from tabCompany where enable_perpetual_inventory = 1) and
 		update_stock=1 and docstatus=1 order by posting_date asc""", as_dict=1):
-		
-			frappe.db.sql("""delete from `tabGL Entry` 
+
+			frappe.db.sql("""delete from `tabGL Entry`
 				where voucher_type = 'Purchase Invoice' and voucher_no = %s""", pi.name)
-				
+
 			pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
-			pi_doc.make_gl_entries(repost_future_gle=False)
+			pi_doc.make_gl_entries()
 			frappe.db.commit()
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 1c12c35..2ce49e7 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -50,7 +50,7 @@
 
 	show_stock_ledger: function() {
 		var me = this;
-		if(this.frm.doc.docstatus===1) {
+		if(this.frm.doc.docstatus > 0) {
 			cur_frm.add_custom_button(__("Stock Ledger"), function() {
 				frappe.route_options = {
 					voucher_no: me.frm.doc.name,
@@ -66,7 +66,7 @@
 
 	show_general_ledger: function() {
 		var me = this;
-		if(this.frm.doc.docstatus===1) {
+		if(this.frm.doc.docstatus > 0) {
 			cur_frm.add_custom_button(__('Accounting Ledger'), function() {
 				frappe.route_options = {
 					voucher_no: me.frm.doc.name,
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.json b/erpnext/regional/doctype/datev_settings/datev_settings.json
index 6860ed3..39486df 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.json
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.json
@@ -28,7 +28,8 @@
    "fieldtype": "Data",
    "in_list_view": 1,
    "label": "Client ID",
-   "reqd": 1
+   "reqd": 1,
+   "length": 5
   },
   {
    "fieldname": "consultant",
@@ -42,7 +43,8 @@
    "fieldtype": "Data",
    "in_list_view": 1,
    "label": "Consultant ID",
-   "reqd": 1
+   "reqd": 1,
+   "length": 7
   },
   {
    "fieldname": "column_break_2",
@@ -102,4 +104,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index d8e9a63..b8b0d40 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -335,7 +335,7 @@
 		self.assertEqual(so.get("items")[-1].qty, 7)
 		self.assertEqual(so.get("items")[-1].amount, 1400)
 		self.assertEqual(so.status, 'To Deliver and Bill')
-	
+
 	def test_remove_item_in_update_child_qty_rate(self):
 		so = make_sales_order(**{
 			"item_list": [{
@@ -373,7 +373,7 @@
 			"docname": so.get("items")[0].name
 		}])
 		update_child_qty_rate('Sales Order', trans_item, so.name)
-		
+
 		so.reload()
 		self.assertEqual(len(so.get("items")), 1)
 		self.assertEqual(so.status, 'To Deliver and Bill')
@@ -760,10 +760,9 @@
 		self.assertEqual(reserved_serial_no, dn.get("items")[0].serial_no)
 		item_line = dn.get("items")[0]
 		item_line.serial_no = item_serial_no.name
-		self.assertRaises(frappe.ValidationError, dn.submit)
 		item_line = dn.get("items")[0]
 		item_line.serial_no =  reserved_serial_no
-		self.assertTrue(dn.submit)
+		dn.submit()
 		dn.load_from_db()
 		dn.cancel()
 		si = make_sales_invoice(so.name)
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index 0cb606b..857b982 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -11,8 +11,8 @@
 
 def get_data_column(filters, partner_doctype):
 	data = []
-	period_list = get_period_list(filters.fiscal_year, filters.fiscal_year,
-		filters.period, company=filters.company)
+	period_list = get_period_list(filters.fiscal_year, filters.fiscal_year, '', '',
+		'Fiscal Year', filters.period, company=filters.company)
 
 	rows = get_data(filters, period_list, partner_doctype)
 	columns = get_columns(filters, period_list, partner_doctype)
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index e4986e3..3be6f44 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -32,7 +32,7 @@
 		{ 'doctype': 'Domain', 'domain': 'Agriculture'},
 		{ 'doctype': 'Domain', 'domain': 'Non Profit'},
 
-		# ensure at least an empty Address Template exists for this Country	
+		# ensure at least an empty Address Template exists for this Country
 		{'doctype':"Address Template", "country": country},
 
 		# item group
@@ -271,7 +271,7 @@
 
 	# Records for the Supplier Scorecard
 	from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
-	
+
 	make_default_records()
 	make_records(records)
 	set_up_address_templates(default_country=country)
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 73b36e3..7acdec7 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -23,22 +23,19 @@
 			if not args.get("posting_date"):
 				args["posting_date"] = nowdate()
 
-			# update valuation and qty after transaction for post dated entry
-			if args.get("is_cancelled") == "Yes" and via_landed_cost_voucher:
-				return
 			update_entries_after({
 				"item_code": self.item_code,
 				"warehouse": self.warehouse,
 				"posting_date": args.get("posting_date"),
 				"posting_time": args.get("posting_time"),
-				"voucher_no": args.get("voucher_no")
+				"voucher_no": args.get("voucher_no"),
+				"sle_id": args.sle_id
 			}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
 
 	def update_qty(self, args):
 		# update the stock values (for current quantities)
 		if args.get("voucher_type")=="Stock Reconciliation":
-			if args.get('is_cancelled') == 'No':
-				self.actual_qty = args.get("qty_after_transaction")
+			self.actual_qty = args.get("qty_after_transaction")
 		else:
 			self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty"))
 
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index f8608d8..68836b4 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -188,7 +188,7 @@
 			}
 		}
 
-		if (doc.docstatus==1) {
+		if (doc.docstatus > 0) {
 			this.show_stock_ledger();
 			if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
 				this.show_general_ledger();
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index dc96e7b..37f9097 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -222,6 +222,7 @@
 		self.cancel_packing_slips()
 
 		self.make_gl_entries_on_cancel()
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 
 	def check_credit_limit(self):
 		from erpnext.selling.doctype.customer.customer import check_credit_limit
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index d7a93fb..bf7007a 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -61,54 +61,55 @@
 
 		self.assertFalse(get_gl_entries("Delivery Note", dn.name))
 
-	def test_delivery_note_gl_entry(self):
-		company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
+	# def test_delivery_note_gl_entry(self):
+	# 	company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
 
-		set_valuation_method("_Test Item", "FIFO")
+	# 	set_valuation_method("_Test Item", "FIFO")
 
-		make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
+	# 	make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
 
-		stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
-		prev_bal = get_balance_on(stock_in_hand_account)
+	# 	stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
+	# 	prev_bal = get_balance_on(stock_in_hand_account)
 
-		dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1")
+	# 	dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1")
 
-		gl_entries = get_gl_entries("Delivery Note", dn.name)
-		self.assertTrue(gl_entries)
+	# 	gl_entries = get_gl_entries("Delivery Note", dn.name)
+	# 	self.assertTrue(gl_entries)
 
-		stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",
-			{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference"))
+	# 	stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",
+	# 		{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference"))
 
-		expected_values = {
-			stock_in_hand_account: [0.0, stock_value_difference],
-			"Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
-		}
-		for i, gle in enumerate(gl_entries):
-			self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
+	# 	expected_values = {
+	# 		stock_in_hand_account: [0.0, stock_value_difference],
+	# 		"Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
+	# 	}
+	# 	for i, gle in enumerate(gl_entries):
+	# 		self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
 
-		# check stock in hand balance
-		bal = get_balance_on(stock_in_hand_account)
-		self.assertEqual(bal, prev_bal - stock_value_difference)
+	# 	# check stock in hand balance
+	# 	bal = get_balance_on(stock_in_hand_account)
+	# 	self.assertEqual(bal, prev_bal - stock_value_difference)
 
-		# back dated incoming entry
-		make_stock_entry(posting_date=add_days(nowdate(), -2), target="Stores - TCP1",
-			qty=5, basic_rate=100)
+	# 	# back dated incoming entry
+	# 	make_stock_entry(posting_date=add_days(nowdate(), -2), target="Stores - TCP1",
+	# 		qty=5, basic_rate=100)
 
-		gl_entries = get_gl_entries("Delivery Note", dn.name)
-		self.assertTrue(gl_entries)
+	# 	gl_entries = get_gl_entries("Delivery Note", dn.name)
+	# 	self.assertTrue(gl_entries)
 
-		stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",
-			{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference"))
+	# 	stock_value_difference = abs(frappe.db.get_value("Stock Ledger Entry",
+	# 		{"voucher_type": "Delivery Note", "voucher_no": dn.name}, "stock_value_difference"))
 
-		expected_values = {
-			stock_in_hand_account: [0.0, stock_value_difference],
-			"Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
-		}
-		for i, gle in enumerate(gl_entries):
-			self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
+	# 	expected_values = {
+	# 		stock_in_hand_account: [0.0, stock_value_difference],
+	# 		"Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
+	# 	}
+	# 	for i, gle in enumerate(gl_entries):
+	# 		self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
 
-		dn.cancel()
-		self.assertFalse(get_gl_entries("Delivery Note", dn.name))
+	# 	dn.cancel()
+	# 	self.assertTrue(get_gl_entries("Delivery Note", dn.name))
+	# 	set_perpetual_inventory(0, company)
 
 	def test_delivery_note_gl_entry_packing_item(self):
 		company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
@@ -147,7 +148,6 @@
 		self.assertEqual(flt(bal, 2), flt(prev_bal - stock_value_diff, 2))
 
 		dn.cancel()
-		self.assertFalse(get_gl_entries("Delivery Note", dn.name))
 
 	def test_serialized(self):
 		se = make_serialized_item()
@@ -464,27 +464,19 @@
 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
 
 		dn1 = make_delivery_note(so.name)
-		dn1.set_posting_time = 1
-		dn1.posting_time = "10:00"
 		dn1.get("items")[0].qty = 2
 		dn1.submit()
 
+		dn2 = make_delivery_note(so.name)
+		dn2.get("items")[0].qty = 3
+		dn2.submit()
+
+		dn1.load_from_db()
 		self.assertEqual(dn1.get("items")[0].billed_amt, 200)
 		self.assertEqual(dn1.per_billed, 100)
 		self.assertEqual(dn1.status, "Completed")
 
-		dn2 = make_delivery_note(so.name)
-		dn2.set_posting_time = 1
-		dn2.posting_time = "08:00"
-		dn2.get("items")[0].qty = 4
-		dn2.submit()
-
-		dn1.load_from_db()
-		self.assertEqual(dn1.get("items")[0].billed_amt, 100)
-		self.assertEqual(dn1.per_billed, 50)
-		self.assertEqual(dn1.status, "To Bill")
-
-		self.assertEqual(dn2.get("items")[0].billed_amt, 400)
+		self.assertEqual(dn2.get("items")[0].billed_amt, 300)
 		self.assertEqual(dn2.per_billed, 100)
 		self.assertEqual(dn2.status, "Completed")
 
@@ -497,8 +489,6 @@
 		so = make_sales_order()
 
 		dn1 = make_delivery_note(so.name)
-		dn1.set_posting_time = 1
-		dn1.posting_time = "10:00"
 		dn1.get("items")[0].qty = 2
 		dn1.submit()
 
@@ -513,7 +503,6 @@
 		si2.submit()
 
 		dn2 = make_delivery_note(so.name)
-		dn2.posting_time = "08:00"
 		dn2.get("items")[0].qty = 5
 		dn2.submit()
 
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index 5ad0e13..bc3d326 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -137,7 +137,7 @@
 			# update stock & gl entries for cancelled state of PR
 			doc.docstatus = 2
 			doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
-			doc.make_gl_entries_on_cancel(repost_future_gle=False)
+			doc.make_gl_entries_on_cancel()
 
 			# update stock & gl entries for submit state of PR
 			doc.docstatus = 1
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 62d369c..3f2c5da 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -15,8 +15,9 @@
 	def test_landed_cost_voucher(self):
 		frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
 
-		pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True, get_taxes_and_charges = True)
-
+		pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+			warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1",
+			get_multiple_items = True, get_taxes_and_charges = True)
 
 		last_sle = frappe.db.get_value("Stock Ledger Entry", {
 				"voucher_type": pr.doctype,
@@ -26,7 +27,7 @@
 			},
 			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
 
-		submit_landed_cost_voucher("Purchase Receipt", pr.name)
+		submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
 
 		pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount")
 		self.assertEqual(pr_lc_value, 25.0)
@@ -67,8 +68,9 @@
 			}
 
 		for gle in gl_entries:
-			self.assertEqual(expected_values[gle.account][0], gle.debit)
-			self.assertEqual(expected_values[gle.account][1], gle.credit)
+			if not gle.get('is_cancelled'):
+				self.assertEqual(expected_values[gle.account][0], gle.debit)
+				self.assertEqual(expected_values[gle.account][1], gle.credit)
 
 
 	def test_landed_cost_voucher_against_purchase_invoice(self):
@@ -87,7 +89,7 @@
 			},
 			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
 
-		submit_landed_cost_voucher("Purchase Invoice", pi.name)
+		submit_landed_cost_voucher("Purchase Invoice", pi.name, pi.company)
 
 		pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name},
 			"landed_cost_voucher_amount")
@@ -118,8 +120,9 @@
 		}
 
 		for gle in gl_entries:
-			self.assertEqual(expected_values[gle.account][0], gle.debit)
-			self.assertEqual(expected_values[gle.account][1], gle.credit)
+			if not gle.get('is_cancelled'):
+				self.assertEqual(expected_values[gle.account][0], gle.debit)
+				self.assertEqual(expected_values[gle.account][1], gle.credit)
 
 
 	def test_landed_cost_voucher_for_serialized_item(self):
@@ -134,7 +137,7 @@
 
 		serial_no_rate = frappe.db.get_value("Serial No", "SN001", "purchase_rate")
 
-		submit_landed_cost_voucher("Purchase Receipt", pr.name)
+		submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company)
 
 		serial_no = frappe.db.get_value("Serial No", "SN001",
 			["warehouse", "purchase_rate"], as_dict=1)
@@ -157,13 +160,13 @@
 			})
 		pr.submit()
 
-		lcv = submit_landed_cost_voucher("Purchase Receipt", pr.name, 123.22)
+		lcv = submit_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, 123.22)
 
 		self.assertEqual(lcv.items[0].applicable_charges, 41.07)
 		self.assertEqual(lcv.items[2].applicable_charges, 41.08)
 
 	def test_multiple_landed_cost_voucher_against_pr(self):
-		pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", 
+		pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
 			supplier_warehouse = "Stores - TCP1", do_not_save=True)
 
 		pr.append("items", {
@@ -176,7 +179,7 @@
 
 		pr.submit()
 
-		lcv1 = make_landed_cost_voucher(receipt_document_type = 'Purchase Receipt', 
+		lcv1 = make_landed_cost_voucher(company = pr.company, receipt_document_type = 'Purchase Receipt',
 			receipt_document=pr.name, charges=100, do_not_save=True)
 
 		lcv1.insert()
@@ -187,7 +190,7 @@
 
 		lcv1.submit()
 
-		lcv2 = make_landed_cost_voucher(receipt_document_type = 'Purchase Receipt', 
+		lcv2 = make_landed_cost_voucher(company = pr.company, receipt_document_type = 'Purchase Receipt',
 			receipt_document=pr.name, charges=100, do_not_save=True)
 
 		lcv2.insert()
@@ -208,7 +211,7 @@
 	ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
 
 	lcv = frappe.new_doc('Landed Cost Voucher')
-	lcv.company = '_Test Company'
+	lcv.company = args.company or '_Test Company'
 	lcv.distribute_charges_based_on = 'Amount'
 
 	lcv.set('purchase_receipts', [{
@@ -233,11 +236,11 @@
 	return lcv
 
 
-def submit_landed_cost_voucher(receipt_document_type, receipt_document, charges=50):
+def submit_landed_cost_voucher(receipt_document_type, receipt_document, company, charges=50):
 	ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
 
 	lcv = frappe.new_doc("Landed Cost Voucher")
-	lcv.company = "_Test Company"
+	lcv.company = company
 	lcv.distribute_charges_based_on = 'Amount'
 
 	lcv.set("purchase_receipts", [{
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index f3020e0..e9568ee 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -92,7 +92,7 @@
 	refresh: function() {
 		var me = this;
 		this._super();
-		if(this.frm.doc.docstatus===1) {
+		if(this.frm.doc.docstatus > 0) {
 			this.show_stock_ledger();
 			//removed for temporary
 			this.show_general_ledger();
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index c2b3892..8dfe1d1 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -196,6 +196,7 @@
 		# because updating ordered qty in bin depends upon updated ordered qty in PO
 		self.update_stock_ledger()
 		self.make_gl_entries_on_cancel()
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 		self.delete_auto_created_batches()
 
 	def get_current_stock(self):
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 40d7cc2..3d42590 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -51,7 +51,7 @@
 		self.assertEqual(current_bin_stock_value, existing_bin_stock_value + 250)
 
 		self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
-	
+
 	def test_batched_serial_no_purchase(self):
 		item = frappe.db.exists("Item", {'item_name': 'Batched Serialized Item'})
 		if not item:
@@ -68,7 +68,7 @@
 		pr = make_purchase_receipt(item_code=item.name, qty=5, rate=500)
 
 		self.assertTrue(frappe.db.get_value('Batch', {'item': item.name, 'reference_name': pr.name}))
-		
+
 		pr.load_from_db()
 		batch_no = pr.items[0].batch_no
 		pr.cancel()
@@ -106,7 +106,7 @@
 			self.assertEqual(expected_values[gle.account][1], gle.credit)
 
 		pr.cancel()
-		self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
+		self.assertTrue(get_gl_entries("Purchase Receipt", pr.name))
 
 	def test_subcontracting(self):
 		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@@ -375,7 +375,7 @@
 
 		location = frappe.db.get_value('Asset', assets[0].name, 'location')
 		self.assertEquals(location, "Test Location")
-	
+
 	def test_purchase_return_with_submitted_asset(self):
 		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return
 
@@ -397,10 +397,10 @@
 
 		pr_return = make_purchase_return(pr.name)
 		self.assertRaises(frappe.exceptions.ValidationError, pr_return.submit)
-		
+
 		asset.load_from_db()
 		asset.cancel()
-		
+
 		pr_return.submit()
 
 	def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self):
@@ -505,10 +505,13 @@
 		self.assertEquals(pi2.items[1].qty, 1)
 
 	def test_stock_transfer_from_purchase_receipt(self):
-		set_perpetual_inventory(1)
-		pr = make_purchase_receipt(do_not_save=1)
+		pr1 = make_purchase_receipt(warehouse = 'Work In Progress - TCP1', company="_Test Company with perpetual inventory")
+
+		pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+			warehouse = "Stores - TCP1", do_not_save=1)
+
 		pr.supplier_warehouse = ''
-		pr.items[0].from_warehouse = '_Test Warehouse 2 - _TC'
+		pr.items[0].from_warehouse = 'Work In Progress - TCP1'
 
 		pr.submit()
 
@@ -518,31 +521,33 @@
 		self.assertFalse(gl_entries)
 
 		expected_sle = {
-			'_Test Warehouse 2 - _TC': -5,
-			'_Test Warehouse - _TC': 5
+			'Work In Progress - TCP1': -5,
+			'Stores - TCP1': 5
 		}
 
 		for sle in sl_entries:
 			self.assertEqual(expected_sle[sle.warehouse], sle.actual_qty)
 
-		set_perpetual_inventory(0)
-
 	def test_stock_transfer_from_purchase_receipt_with_valuation(self):
-		set_perpetual_inventory(1)
-		warehouse = frappe.get_doc('Warehouse', '_Test Warehouse 2 - _TC')
-		warehouse.account = '_Test Account Stock In Hand - _TC'
+		warehouse = frappe.get_doc('Warehouse', 'Work In Progress - TCP1')
+		warehouse.account = '_Test Account Stock In Hand - TCP1'
 		warehouse.save()
 
-		pr = make_purchase_receipt(do_not_save=1)
-		pr.items[0].from_warehouse = '_Test Warehouse 2 - _TC'
+		pr1 = make_purchase_receipt(warehouse = 'Work In Progress - TCP1',
+			company="_Test Company with perpetual inventory")
+
+		pr = make_purchase_receipt(company="_Test Company with perpetual inventory",
+			warehouse = "Stores - TCP1", do_not_save=1)
+
+		pr.items[0].from_warehouse = 'Work In Progress - TCP1'
 		pr.supplier_warehouse = ''
 
 
 		pr.append('taxes', {
 			'charge_type': 'On Net Total',
-			'account_head': '_Test Account Shipping Charges - _TC',
+			'account_head': '_Test Account Shipping Charges - TCP1',
 			'category': 'Valuation and Total',
-			'cost_center': 'Main - _TC',
+			'cost_center': 'Main - TCP1',
 			'description': 'Test',
 			'rate': 9
 		})
@@ -553,14 +558,14 @@
 		sl_entries = get_sl_entries('Purchase Receipt', pr.name)
 
 		expected_gle = [
-			['Stock In Hand - _TC', 272.5, 0.0],
-			['_Test Account Stock In Hand - _TC', 0.0, 250.0],
-			['_Test Account Shipping Charges - _TC', 0.0, 22.5]
+			['Stock In Hand - TCP1', 272.5, 0.0],
+			['_Test Account Stock In Hand - TCP1', 0.0, 250.0],
+			['_Test Account Shipping Charges - TCP1', 0.0, 22.5]
 		]
 
 		expected_sle = {
-			'_Test Warehouse 2 - _TC': -5,
-			'_Test Warehouse - _TC': 5
+			'Work In Progress - TCP1': -5,
+			'Stores - TCP1': 5
 		}
 
 		for sle in sl_entries:
@@ -573,8 +578,6 @@
 
 		warehouse.account = ''
 		warehouse.save()
-		set_perpetual_inventory(0)
-
 
 def get_sl_entries(voucher_type, voucher_no):
 	return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
@@ -582,7 +585,7 @@
 		order by posting_time desc""", (voucher_type, voucher_no), as_dict=1)
 
 def get_gl_entries(voucher_type, voucher_no):
-	return frappe.db.sql("""select account, debit, credit, cost_center
+	return frappe.db.sql("""select account, debit, credit, cost_center, is_cancelled
 		from `tabGL Entry` where voucher_type=%s and voucher_no=%s
 		order by account desc""", (voucher_type, voucher_no), as_dict=1)
 
diff --git a/erpnext/stock/doctype/purchase_receipt/test_records.json b/erpnext/stock/doctype/purchase_receipt/test_records.json
index e7ea9af..724e3d7 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_records.json
+++ b/erpnext/stock/doctype/purchase_receipt/test_records.json
@@ -83,5 +83,37 @@
    }
   ],
   "supplier": "_Test Supplier"
+ },
+
+ {
+  "buying_price_list": "_Test Price List",
+  "company": "_Test Company",
+  "conversion_rate": 1.0,
+  "currency": "INR",
+  "doctype": "Purchase Receipt",
+  "base_grand_total": 5000.0,
+  "is_subcontracted": "Yes",
+  "base_net_total": 5000.0,
+  "items": [
+   {
+    "base_amount": 5000.0,
+    "conversion_factor": 1.0,
+    "description": "_Test FG Item",
+    "doctype": "Purchase Receipt Item",
+    "item_code": "_Test FG Item",
+    "item_name": "_Test FG Item",
+    "parentfield": "items",
+    "qty": 10.0,
+    "rate": 500.0,
+    "received_qty": 10.0,
+    "rejected_qty": 0.0,
+    "stock_uom": "_Test UOM",
+    "uom": "_Test UOM",
+    "warehouse": "_Test Warehouse - _TC",
+	"cost_center": "Main - _TC"
+   }
+  ],
+  "supplier": "_Test Supplier",
+  "supplier_warehouse": "_Test Warehouse - _TC"
  }
 ]
\ No newline at end of file
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index b32c709..914eea3 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -130,13 +130,17 @@
 		sle_dict = self.get_stock_ledger_entries(serial_no)
 		if sle_dict:
 			if sle_dict.get("incoming", []):
-				entries["purchase_sle"] = sle_dict["incoming"][0]
+				sle_list = [sle for sle in sle_dict["incoming"] if sle.is_cancelled == 0]
+				if sle_list:
+					entries["purchase_sle"] = sle_list[0]
 
 			if len(sle_dict.get("incoming", [])) - len(sle_dict.get("outgoing", [])) > 0:
 				entries["last_sle"] = sle_dict["incoming"][0]
 			else:
 				entries["last_sle"] = sle_dict["outgoing"][0]
-				entries["delivery_sle"] = sle_dict["outgoing"][0]
+				sle_list = [sle for sle in sle_dict["outgoing"] if sle.is_cancelled == 0]
+				if sle_list:
+					entries["delivery_sle"] = sle_list[0]
 
 		return entries
 
@@ -147,11 +151,11 @@
 
 		for sle in frappe.db.sql("""
 			SELECT voucher_type, voucher_no,
-				posting_date, posting_time, incoming_rate, actual_qty, serial_no
+				posting_date, posting_time, incoming_rate, actual_qty, serial_no, is_cancelled
 			FROM
 				`tabStock Ledger Entry`
 			WHERE
-				item_code=%s AND company = %s AND ifnull(is_cancelled, 'No')='No'
+				item_code=%s AND company = %s
 				AND (serial_no = %s
 					OR serial_no like %s
 					OR serial_no like %s
@@ -171,7 +175,7 @@
 
 	def on_trash(self):
 		sl_entries = frappe.db.sql("""select serial_no from `tabStock Ledger Entry`
-			where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'""",
+			where serial_no like %s and item_code=%s""",
 			("%%%s%%" % self.name, self.item_code), as_dict=True)
 
 		# Find the exact match
@@ -221,7 +225,7 @@
 		if serial_nos:
 			frappe.throw(_("Item {0} is not setup for Serial Nos. Column must be blank").format(sle.item_code),
 				SerialNoNotRequiredError)
-	elif sle.is_cancelled == "No":
+	else:
 		if serial_nos:
 			if cint(sle.actual_qty) != flt(sle.actual_qty):
 				frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
@@ -239,6 +243,10 @@
 						"delivery_document_no", "delivery_document_type", "warehouse",
 						"purchase_document_no", "company"], as_dict=1)
 
+					if sr and cint(sle.actual_qty) < 0 and sr.warehouse != sle.warehouse:
+						frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}")
+							.format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse), SerialNoWarehouseError)
+
 					if sr.item_code!=sle.item_code:
 						if not allow_serial_nos_with_different_item(serial_no, sle):
 							frappe.throw(_("Serial No {0} does not belong to Item {1}").format(serial_no,
@@ -265,7 +273,7 @@
 								frappe.throw(_("Serial No {0} does not belong to Batch {1}").format(serial_no,
 									sle.batch_no), SerialNoBatchError)
 
-							if sle.is_cancelled=="No" and not sr.warehouse:
+							if not sr.warehouse:
 								frappe.throw(_("Serial No {0} does not belong to any Warehouse")
 									.format(serial_no), SerialNoWarehouseError)
 
@@ -311,12 +319,6 @@
 		elif cint(sle.actual_qty) < 0 or not item_det.serial_no_series:
 			frappe.throw(_("Serial Nos Required for Serialized Item {0}").format(sle.item_code),
 				SerialNoRequiredError)
-	elif serial_nos:
-		for serial_no in serial_nos:
-			sr = frappe.db.get_value("Serial No", serial_no, ["name", "warehouse"], as_dict=1)
-			if sr and cint(sle.actual_qty) < 0 and sr.warehouse != sle.warehouse:
-				frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}")
-					.format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse))
 
 def validate_material_transfer_entry(sle_doc):
 	sle_doc.update({
@@ -324,7 +326,7 @@
 		"skip_serial_no_validaiton": False
 	})
 
-	if (sle_doc.voucher_type == "Stock Entry" and sle_doc.is_cancelled == "No" and
+	if (sle_doc.voucher_type == "Stock Entry" and
 		frappe.get_cached_value("Stock Entry", sle_doc.voucher_no, "purpose") == "Material Transfer"):
 		if sle_doc.actual_qty < 0:
 			sle_doc.skip_update_serial_no = True
@@ -367,7 +369,7 @@
 		stock_entry = frappe.get_cached_doc("Stock Entry", sle.voucher_no)
 		if stock_entry.purpose in ("Repack", "Manufacture"):
 			for d in stock_entry.get("items"):
-				if d.serial_no and (d.s_warehouse if sle.is_cancelled=="No" else d.t_warehouse):
+				if d.serial_no and (d.s_warehouse or d.t_warehouse):
 					serial_nos = get_serial_nos(d.serial_no)
 					if sle_serial_no in serial_nos:
 						allow_serial_nos = True
@@ -376,7 +378,7 @@
 
 def update_serial_nos(sle, item_det):
 	if sle.skip_update_serial_no: return
-	if sle.is_cancelled == "No" and not sle.serial_no and cint(sle.actual_qty) > 0 \
+	if not sle.serial_no and cint(sle.actual_qty) > 0 \
 			and item_det.has_serial_no == 1 and item_det.serial_no_series:
 		serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty)
 		frappe.db.set(sle, "serial_no", serial_nos)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 95f9d46..f9aae7b 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -107,6 +107,9 @@
 
 		self.update_work_order()
 		self.update_stock_ledger()
+
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+
 		self.make_gl_entries_on_cancel()
 		self.update_cost_in_project()
 		self.update_transferred_qty()
@@ -651,7 +654,7 @@
 		if self.docstatus == 2:
 			sl_entries.reverse()
 
-		self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No')
+		self.make_sl_entries(sl_entries)
 
 	def get_gl_entries(self, warehouse_account):
 		gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
@@ -674,7 +677,7 @@
 					multiply_based_on = d.basic_amount if total_basic_amount else d.qty
 
 					item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
-						(t.amount * multiply_based_on) / divide_based_on
+						flt(t.amount * multiply_based_on) / divide_based_on
 
 		if item_account_wise_additional_cost:
 			for d in self.get("items"):
diff --git a/erpnext/stock/doctype/stock_entry/test_records.json b/erpnext/stock/doctype/stock_entry/test_records.json
index cfbdce4..dc21287 100644
--- a/erpnext/stock/doctype/stock_entry/test_records.json
+++ b/erpnext/stock/doctype/stock_entry/test_records.json
@@ -24,7 +24,6 @@
 	{
 		"company": "_Test Company",
 		"doctype": "Stock Entry",
-		"posting_date": "2013-01-25",
 		"purpose": "Material Issue",
 		"stock_entry_type": "Material Issue",
 		"items": [
@@ -47,7 +46,6 @@
 	{
 		"company": "_Test Company",
 		"doctype": "Stock Entry",
-		"posting_date": "2013-01-25",
 		"purpose": "Material Transfer",
 		"stock_entry_type": "Material Transfer",
 		"items": [
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 2afabe1..0fbc631 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -149,10 +149,10 @@
 
 		mr.cancel()
 
-		self.assertFalse(frappe.db.sql("""select * from `tabStock Ledger Entry`
+		self.assertTrue(frappe.db.sql("""select * from `tabStock Ledger Entry`
 			where voucher_type='Stock Entry' and voucher_no=%s""", mr.name))
 
-		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry`
+		self.assertTrue(frappe.db.sql("""select * from `tabGL Entry`
 			where voucher_type='Stock Entry' and voucher_no=%s""", mr.name))
 
 	def test_material_issue_gl_entry(self):
@@ -178,12 +178,6 @@
 		)
 		mi.cancel()
 
-		self.assertFalse(frappe.db.sql("""select name from `tabStock Ledger Entry`
-			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name))
-
-		self.assertFalse(frappe.db.sql("""select name from `tabGL Entry`
-			where voucher_type='Stock Entry' and voucher_no=%s""", mi.name))
-
 	def test_material_transfer_gl_entry(self):
 		company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
 
@@ -216,11 +210,6 @@
 			)
 
 		mtn.cancel()
-		self.assertFalse(frappe.db.sql("""select * from `tabStock Ledger Entry`
-			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name))
-
-		self.assertFalse(frappe.db.sql("""select * from `tabGL Entry`
-			where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name))
 
 	def test_repack_no_change_in_valuation(self):
 		company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
@@ -544,10 +533,10 @@
 		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto", '')
 
 		# test freeze_stocks_upto_days
-		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 7)
+		frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", -1)
 		se = frappe.copy_doc(test_records[0])
 		se.set_posting_time = 1
-		se.posting_date = add_days(nowdate(), -15)
+		se.posting_date = nowdate()
 		se.set_stock_entry_type()
 		se.insert()
 		self.assertRaises(StockFreezeError, se.submit)
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index c03eb79..fda17e0 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_copy": 1,
  "autoname": "MAT-SLE-.YYYY.-.#####",
  "creation": "2013-01-29 19:25:42",
@@ -255,11 +256,10 @@
    "width": "150px"
   },
   {
+   "default": "0",
    "fieldname": "is_cancelled",
-   "fieldtype": "Select",
-   "hidden": 1,
+   "fieldtype": "Check",
    "label": "Is Cancelled",
-   "options": "\nNo\nYes",
    "report_hide": 1
   },
   {
@@ -275,7 +275,8 @@
  "icon": "fa fa-list",
  "idx": 1,
  "in_create": 1,
- "modified": "2020-02-25 22:53:33.504681",
+ "links": [],
+ "modified": "2020-04-23 05:57:03.985520",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Ledger Entry",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index dab5a7b..101c6e0 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -46,7 +46,7 @@
 	def calculate_batch_qty(self):
 		if self.batch_no:
 			batch_qty = frappe.db.get_value("Stock Ledger Entry",
-				{"docstatus": 1, "batch_no": self.batch_no, "is_cancelled": "No"},
+				{"docstatus": 1, "batch_no": self.batch_no},
 				"sum(actual_qty)") or 0
 			frappe.db.set_value("Batch", self.batch_no, "batch_qty", batch_qty)
 
@@ -93,7 +93,7 @@
 				elif not frappe.db.get_value("Batch",{"item": self.item_code, "name": self.batch_no}):
 					frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, batch_item))
 
-			elif item_det.has_batch_no ==0 and self.batch_no and self.is_cancelled == "No":
+			elif item_det.has_batch_no ==0 and self.batch_no:
 				frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
 
 		if item_det.has_variants:
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index 1791978..dd284e4 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -227,7 +227,7 @@
 	},
 
 	refresh: function() {
-		if(this.frm.doc.docstatus==1) {
+		if(this.frm.doc.docstatus > 0) {
 			this.show_stock_ledger();
 			if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
 				this.show_general_ledger();
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 0a49c26..5e469c2 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -6,7 +6,6 @@
 import frappe.defaults
 from frappe import msgprint, _
 from frappe.utils import cstr, flt, cint
-from erpnext.stock.stock_ledger import update_entries_after
 from erpnext.controllers.stock_controller import StockController
 from erpnext.accounts.utils import get_company_default
 from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -43,7 +42,8 @@
 		update_serial_nos_after_submit(self, "items")
 
 	def on_cancel(self):
-		self.delete_and_repost_sle()
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
+		self.make_sle_on_cancel()
 		self.make_gl_entries_on_cancel()
 
 	def remove_items_with_no_change(self):
@@ -193,6 +193,7 @@
 				if row.serial_no or row.batch_no:
 					frappe.throw(_("Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.") \
 						.format(row.idx, frappe.bold(row.item_code)))
+
 				previous_sle = get_previous_sle({
 					"item_code": row.item_code,
 					"warehouse": row.warehouse,
@@ -319,7 +320,7 @@
 			"voucher_detail_no": row.name,
 			"company": self.company,
 			"stock_uom": frappe.db.get_value("Item", row.item_code, "stock_uom"),
-			"is_cancelled": "No" if self.docstatus != 2 else "Yes",
+			"is_cancelled": 1 if self.docstatus == 2 else 0,
 			"serial_no": '\n'.join(serial_nos) if serial_nos else '',
 			"batch_no": row.batch_no,
 			"valuation_rate": flt(row.valuation_rate, row.precision("valuation_rate"))
@@ -328,27 +329,35 @@
 		if not row.batch_no:
 			data.qty_after_transaction = flt(row.qty, row.precision("qty"))
 
+		if self.docstatus == 2 and not row.batch_no:
+			if row.current_qty:
+				data.actual_qty = -1 * row.current_qty
+				data.qty_after_transaction = flt(row.current_qty)
+				data.valuation_rate = flt(row.current_valuation_rate)
+				data.stock_value = data.qty_after_transaction * data.valuation_rate
+				data.stock_value_difference = -1 * flt(row.amount_difference)
+			else:
+				data.actual_qty = row.qty
+				data.qty_after_transaction = 0.0
+				data.valuation_rate = flt(row.valuation_rate)
+				data.stock_value_difference = -1 * flt(row.amount_difference)
+
 		return data
 
-	def delete_and_repost_sle(self):
-		"""	Delete Stock Ledger Entries related to this voucher
-			and repost future Stock Ledger Entries"""
-
-		existing_entries = frappe.db.sql("""select distinct item_code, warehouse
-			from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
-			(self.doctype, self.name), as_dict=1)
-
-		# delete entries
-		frappe.db.sql("""delete from `tabStock Ledger Entry`
-			where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
-
+	def make_sle_on_cancel(self):
 		sl_entries = []
 
 		has_serial_no = False
 		for row in self.items:
 			if row.serial_no or row.batch_no or row.current_serial_no:
 				has_serial_no = True
-				self.get_sle_for_serialized_items(row, sl_entries)
+				serial_nos = ''
+				if row.current_serial_no:
+					serial_nos = get_serial_nos(row.current_serial_no)
+
+				sl_entries.append(self.get_sle_for_items(row, serial_nos))
+			else:
+				sl_entries.append(self.get_sle_for_items(row))
 
 		if sl_entries:
 			if has_serial_no:
@@ -358,14 +367,6 @@
 			allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
 			self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
 
-		# repost future entries for selected item_code, warehouse
-		for entries in existing_entries:
-			update_entries_after({
-				"item_code": entries.item_code,
-				"warehouse": entries.warehouse,
-				"posting_date": self.posting_date,
-				"posting_time": self.posting_time
-			})
 
 	def merge_similar_item_serial_nos(self, sl_entries):
 		# If user has put the same item in multiple row with different serial no
@@ -434,12 +435,6 @@
 		else:
 			self._submit()
 
-	def cancel(self):
-		if len(self.items) > 100:
-			self.queue_action('cancel')
-		else:
-			self._cancel()
-
 @frappe.whitelist()
 def get_items(warehouse, posting_date, posting_time, company):
 	lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 51d027f..1571416 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -34,11 +34,11 @@
 		# [[qty, valuation_rate, posting_date,
 		#		posting_time, expected_stock_value, bin_qty, bin_valuation]]
 		input_data = [
-			[50, 1000, "2012-12-26", "12:00"],
-			[25, 900, "2012-12-26", "12:00"],
-			["", 1000, "2012-12-20", "12:05"],
-			[20, "", "2012-12-26", "12:05"],
-			[0, "", "2012-12-31", "12:10"]
+			[50, 1000],
+			[25, 900],
+			["", 1000],
+			[20, ""],
+			[0, ""]
 		]
 
 		for d in input_data:
@@ -47,13 +47,13 @@
 			last_sle = get_previous_sle({
 				"item_code": "_Test Item",
 				"warehouse": "Stores - TCP1",
-				"posting_date": d[2],
-				"posting_time": d[3]
+				"posting_date": nowdate(),
+				"posting_time": nowtime()
 			})
 
 			# submit stock reconciliation
 			stock_reco = create_stock_reconciliation(qty=d[0], rate=d[1],
-				posting_date=d[2], posting_time=d[3], warehouse="Stores - TCP1",
+				posting_date=nowdate(), posting_time=nowtime(), warehouse="Stores - TCP1",
 				company=company, expense_account = "Stock Adjustment - TCP1")
 
 			# check stock value
@@ -68,8 +68,8 @@
 				and valuation_rate == last_sle.get("valuation_rate"):
 					self.assertFalse(sle)
 			else:
-				self.assertEqual(sle[0].qty_after_transaction, qty_after_transaction)
-				self.assertEqual(sle[0].stock_value, qty_after_transaction * valuation_rate)
+				self.assertEqual(flt(sle[0].qty_after_transaction, 1), flt(qty_after_transaction, 1))
+				self.assertEqual(flt(sle[0].stock_value, 1), flt(qty_after_transaction * valuation_rate, 1))
 
 				# no gl entries
 				self.assertTrue(frappe.db.get_value("Stock Ledger Entry",
@@ -77,16 +77,10 @@
 
 				acc_bal, stock_bal, wh_list = get_stock_and_account_balance("Stock In Hand - TCP1",
 					stock_reco.posting_date, stock_reco.company)
-				self.assertEqual(acc_bal, stock_bal)
+				self.assertEqual(flt(acc_bal, 1), flt(stock_bal, 1))
 
 				stock_reco.cancel()
 
-				self.assertFalse(frappe.db.get_value("Stock Ledger Entry",
-					{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
-
-				self.assertFalse(frappe.db.get_value("GL Entry",
-					{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
-
 	def test_get_items(self):
 		create_warehouse("_Test Warehouse Group 1", {"is_group": 1})
 		create_warehouse("_Test Warehouse Ledger 1",
@@ -113,7 +107,6 @@
 		sr = create_stock_reconciliation(item_code=serial_item_code,
 			warehouse = serial_warehouse, qty=5, rate=200)
 
-		# print(sr.name)
 		serial_nos = get_serial_nos(sr.items[0].serial_no)
 		self.assertEqual(len(serial_nos), 5)
 
@@ -133,7 +126,6 @@
 		sr = create_stock_reconciliation(item_code=serial_item_code,
 			warehouse = serial_warehouse, qty=5, rate=300, serial_no = '\n'.join(serial_nos))
 
-		# print(sr.name)
 		serial_nos1 = get_serial_nos(sr.items[0].serial_no)
 		self.assertEqual(len(serial_nos1), 5)
 
@@ -155,10 +147,6 @@
 			stock_doc = frappe.get_doc("Stock Reconciliation", d)
 			stock_doc.cancel()
 
-		for d in serial_nos + serial_nos1:
-			if frappe.db.exists("Serial No", d):
-				frappe.delete_doc("Serial No", d)
-
 	def test_stock_reco_for_batch_item(self):
 		set_perpetual_inventory()
 
@@ -208,13 +196,13 @@
 def insert_existing_sle(warehouse):
 	from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 
-	make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
+	make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
 		target=warehouse, qty=10, basic_rate=700)
 
-	make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
+	make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
 		source=warehouse, qty=15)
 
-	make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
+	make_stock_entry(posting_date=nowdate(), posting_time=nowtime(), item_code="_Test Item",
 		target=warehouse, qty=15, basic_rate=1200)
 
 def create_batch_or_serial_no_items():
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js
index 9adfbf7..6f12c27 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.js
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.js
@@ -32,7 +32,7 @@
 			"options": "Warehouse",
 			"get_query": function() {
 				const company = frappe.query_report.get_filter_value('company');
-				return { 
+				return {
 					filters: { 'company': company }
 				}
 			}
@@ -82,6 +82,11 @@
 			"label": __("Include UOM"),
 			"fieldtype": "Link",
 			"options": "UOM"
+		},
+		{
+			"fieldname": "show_cancelled_entries",
+			"label": __("Show Cancelled Entries"),
+			"fieldtype": "Check"
 		}
 	],
 	"formatter": function (value, row, column, data, default_formatter) {
@@ -96,9 +101,3 @@
 		return value;
 	},
 }
-
-// $(function() {
-// 	$(wrapper).bind("show", function() {
-// 		frappe.query_report.load();
-// 	});
-// });
\ No newline at end of file
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 0190f09..abf959e 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -181,6 +181,9 @@
 	if filters.get("project"):
 		conditions.append("project=%(project)s")
 
+	if not filters.get("show_cancelled_entries"):
+		conditions.append("is_cancelled = 0")
+
 	return "and {}".format(" and ".join(conditions)) if conditions else ""
 
 
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 5697315..b5ae1b7 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -6,7 +6,6 @@
 from frappe.utils import flt, cstr, nowdate, nowtime
 from erpnext.stock.utils import update_bin
 from erpnext.stock.stock_ledger import update_entries_after
-from erpnext.controllers.stock_controller import update_gl_entries_after
 
 def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
 	"""
@@ -56,12 +55,13 @@
 
 		update_bin_qty(item_code, warehouse, qty_dict)
 
-def repost_actual_qty(item_code, warehouse, allow_zero_rate=False, allow_negative_stock=False):		update_entries_after({ "item_code": item_code, "warehouse": warehouse },
+def repost_actual_qty(item_code, warehouse, allow_zero_rate=False, allow_negative_stock=False):
+	update_entries_after({ "item_code": item_code, "warehouse": warehouse },
 		allow_zero_rate=allow_zero_rate, allow_negative_stock=allow_negative_stock)
 
 def get_balance_qty_from_sle(item_code, warehouse):
 	balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
-		where item_code=%s and warehouse=%s and is_cancelled='No'
+		where item_code=%s and warehouse=%s
 		order by posting_date desc, posting_time desc, creation desc
 		limit 1""", (item_code, warehouse))
 
@@ -191,7 +191,7 @@
 			print(d[0], d[1], d[2], serial_nos[0][0])
 
 		sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
-			where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
+			where item_code = %s and warehouse = %s
 			order by posting_date desc limit 1""", (d[0], d[1]))
 
 		sle_dict = {
@@ -208,7 +208,6 @@
 			'stock_uom'					: d[3],
 			'incoming_rate'				: sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
 			'company'					: sle and cstr(sle[0][1]) or 0,
-			'is_cancelled'			 	: 'No',
 			'batch_no'					: '',
 			'serial_no'					: ''
 		}
@@ -220,8 +219,7 @@
 
 		args = sle_dict.copy()
 		args.update({
-			"sle_id": sle_doc.name,
-			"is_amended": 'No'
+			"sle_id": sle_doc.name
 		})
 
 		update_bin(args)
@@ -246,15 +244,3 @@
 				sr.save()
 			except:
 				pass
-
-def repost_gle_for_stock_transactions(posting_date=None, posting_time=None, for_warehouses=None):
-	frappe.db.auto_commit_on_many_writes = 1
-
-	if not posting_date:
-		posting_date = "1900-01-01"
-	if not posting_time:
-		posting_time = "00:00"
-
-	update_gl_entries_after(posting_date, posting_time, for_warehouses=for_warehouses)
-
-	frappe.db.auto_commit_on_many_writes = 0
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 7567a1a..b4cb8ca 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -4,8 +4,8 @@
 
 import frappe, erpnext
 from frappe import _
-from frappe.utils import cint, flt, cstr, now
-from erpnext.stock.utils import get_valuation_method
+from frappe.utils import cint, flt, cstr, now, now_datetime
+from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
 import json
 
 from six import iteritems
@@ -16,36 +16,48 @@
 _exceptions = frappe.local('stockledger_exceptions')
 # _exceptions = []
 
-def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False, via_landed_cost_voucher=False):
+def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
 	if sl_entries:
 		from erpnext.stock.utils import update_bin
 
-		cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False
+		cancel = sl_entries[0].get("is_cancelled")
 		if cancel:
-			set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type'))
+			set_as_cancel(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
 
 		for sle in sl_entries:
 			sle_id = None
-			if sle.get('is_cancelled') == 'Yes':
-				sle['actual_qty'] = -flt(sle['actual_qty'])
+			if via_landed_cost_voucher or cancel:
+				sle['posting_date'] = now_datetime().strftime('%Y-%m-%d')
+				sle['posting_time'] = now_datetime().strftime('%H:%M:%S.%f')
+
+				if cancel:
+					sle['actual_qty'] = -flt(sle.get('actual_qty'), 0)
+
+					if sle['actual_qty'] < 0 and not sle.get('outgoing_rate'):
+						sle['outgoing_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
+							sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
+						sle['incoming_rate'] = 0.0
+
+					if sle['actual_qty'] > 0 and not sle.get('incoming_rate'):
+						sle['incoming_rate'] = get_incoming_outgoing_rate_for_cancel(sle.item_code,
+							sle.voucher_type, sle.voucher_no, sle.voucher_detail_no)
+						sle['outgoing_rate'] = 0.0
+
 
 			if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
 				sle_id = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
 
 			args = sle.copy()
 			args.update({
-				"sle_id": sle_id,
-				"is_amended": is_amended
+				"sle_id": sle_id
 			})
 			update_bin(args, allow_negative_stock, via_landed_cost_voucher)
 
-		if cancel:
-			delete_cancelled_entry(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
 
 def set_as_cancel(voucher_type, voucher_no):
-	frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
+	frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled=1,
 		modified=%s, modified_by=%s
-		where voucher_no=%s and voucher_type=%s""",
+		where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
 		(now(), frappe.session.user, voucher_type, voucher_no))
 
 def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
@@ -58,9 +70,6 @@
 	sle.submit()
 	return sle.name
 
-def delete_cancelled_entry(voucher_type, voucher_no):
-	frappe.db.sql("""delete from `tabStock Ledger Entry`
-		where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
 
 class update_entries_after(object):
 	"""
@@ -106,14 +115,17 @@
 		self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]")
 		self.valuation_method = get_valuation_method(self.item_code)
 		self.stock_value_difference = 0.0
-		self.build()
+		self.build(args.get('sle_id'))
 
-	def build(self):
-		# includes current entry!
-		entries_to_fix = self.get_sle_after_datetime()
-
-		for sle in entries_to_fix:
+	def build(self, sle_id):
+		if sle_id:
+			sle = get_sle_by_id(sle_id)
 			self.process_sle(sle)
+		else:
+			# includes current entry!
+			entries_to_fix = self.get_sle_after_datetime()
+			for sle in entries_to_fix:
+				self.process_sle(sle)
 
 		if self.exceptions:
 			self.raise_exceptions()
@@ -403,7 +415,10 @@
 
 	def get_sle_before_datetime(self):
 		"""get previous stock ledger entry before current time-bucket"""
-		return get_stock_ledger_entries(self.args, "<", "desc", "limit 1", for_update=False)
+		if self.args.get('sle_id'):
+			self.args['name'] = self.args.get('sle_id')
+
+		return get_stock_ledger_entries(self.args, "<=", "desc", "limit 1", for_update=False)
 
 	def get_sle_after_datetime(self):
 		"""get Stock Ledger Entries after a particular datetime, for reposting"""
@@ -470,9 +485,10 @@
 	if operator in (">", "<=") and previous_sle.get("name"):
 		conditions += " and name!=%(name)s"
 
-	return frappe.db.sql("""select *, timestamp(posting_date, posting_time) as "timestamp" from `tabStock Ledger Entry`
+	return frappe.db.sql("""
+		select *, timestamp(posting_date, posting_time) as "timestamp"
+		from `tabStock Ledger Entry`
 		where item_code = %%(item_code)s
-		and ifnull(is_cancelled, 'No')='No'
 		%(conditions)s
 		order by timestamp(posting_date, posting_time) %(order)s, creation %(order)s
 		%(limit)s %(for_update)s""" % {
@@ -482,6 +498,11 @@
 			"order": order
 		}, previous_sle, as_dict=1, debug=debug)
 
+def get_sle_by_id(sle_id):
+	return frappe.db.get_all('Stock Ledger Entry',
+		fields=['*', 'timestamp(posting_date, posting_time) as timestamp'],
+		filters={'name': sle_id})[0]
+
 def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
 	allow_zero_rate=False, currency=None, company=None, raise_error_if_no_rate=True):
 	# Get valuation rate from last sle for the same item and warehouse
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 7f32b8d..f21dc3f 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -364,4 +364,16 @@
 			else:
 				row[data.converted_col] = flt(value_before_conversion) / conversion_factor
 
-		result[row_idx] = row
\ No newline at end of file
+		result[row_idx] = row
+
+def get_incoming_outgoing_rate_for_cancel(item_code, voucher_type, voucher_no, voucher_detail_no):
+	outgoing_rate = frappe.db.sql("""SELECT abs(stock_value_difference / actual_qty)
+		FROM `tabStock Ledger Entry`
+		WHERE voucher_type = %s and voucher_no = %s
+			and item_code = %s and voucher_detail_no = %s
+			ORDER BY CREATION DESC limit 1""",
+		(voucher_type, voucher_no, item_code, voucher_detail_no))
+
+	outgoing_rate = outgoing_rate[0][0] if outgoing_rate else 0.0
+
+	return outgoing_rate
\ No newline at end of file
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 14674c0..ea96503 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -5,8 +5,9 @@
 import frappe
 import frappe.share
 from frappe import _
-from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_link_to_form
+from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_datetime, get_link_to_form
 from erpnext.controllers.status_updater import StatusUpdater
+from erpnext.accounts.utils import get_fiscal_year
 
 from six import string_types
 
@@ -28,6 +29,8 @@
 			except ValueError:
 				frappe.throw(_('Invalid Posting Time'))
 
+		self.validate_with_last_transaction_posting_time()
+
 	def add_calendar_event(self, opts, force=False):
 		if cstr(self.contact_by) != cstr(self._prev.contact_by) or \
 				cstr(self.contact_date) != cstr(self._prev.contact_date) or force or \
@@ -148,6 +151,30 @@
 
 		return ret
 
+	def validate_with_last_transaction_posting_time(self):
+
+		if self.doctype not in ["Sales Invoice", "Purchase Invoice", "Stock Entry", "Stock Reconciliation",
+			"Delivery Note", "Purchase Receipt", "Fees"]:
+				return
+
+		if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
+			if not (self.get("update_stock") or self.get("is_pos")):
+				return
+
+		fiscal_year = get_fiscal_year(self.get('posting_date'), as_dict=True).name
+
+		last_transaction_time = frappe.db.sql("""
+			select MAX(timestamp(posting_date, posting_time)) as posting_time
+			from `tabStock Ledger Entry`
+			where docstatus = 1 and fiscal_year = %s""", (fiscal_year))[0][0]
+
+		cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
+
+		if last_transaction_time and get_datetime(cur_doc_posting_datetime) < get_datetime(last_transaction_time):
+			frappe.throw(_("""Posting timestamp of current transaction
+				must be after last Stock transaction's timestamp which is {0}""").format(frappe.bold(last_transaction_time)),
+				title=_("Backdated Stock Entry"))
+
 def delete_events(ref_type, ref_name):
 	events = frappe.db.sql_list(""" SELECT
 			distinct `tabEvent`.name