Merge branch 'develop' into fix-repayment-schedule
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 882a374..9ebcadd 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1410,7 +1410,7 @@
 			self.repost_future_sle_and_gle()
 
 		self.update_project()
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 
 		unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
 		self.ignore_linked_doctypes = (
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/__init__.py b/erpnext/accounts/doctype/repost_payment_ledger/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/__init__.py
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.js b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.js
new file mode 100644
index 0000000..6801408
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.js
@@ -0,0 +1,53 @@
+// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Repost Payment Ledger', {
+	setup: function(frm) {
+		frm.set_query("voucher_type", () => {
+			return {
+				filters: {
+					name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']]
+				}
+			};
+		});
+
+		frm.fields_dict['repost_vouchers'].grid.get_field('voucher_type').get_query = function(doc) {
+			return {
+				filters: {
+					name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']]
+				}
+			}
+		}
+
+		frm.fields_dict['repost_vouchers'].grid.get_field('voucher_no').get_query = function(doc) {
+			if (doc.company) {
+				return {
+					filters: {
+						company: doc.company,
+						docstatus: 1
+					}
+				}
+			}
+		}
+
+	},
+	refresh: function(frm) {
+
+		if (frm.doc.docstatus==1 && ['Queued', 'Failed'].find(x => x == frm.doc.repost_status)) {
+			frm.set_intro(__("Use 'Repost in background' button to trigger background job. Job can only be triggered when document is in Queued or Failed status."));
+			var btn_label = __("Repost in background")
+
+			frm.add_custom_button(btn_label, () => {
+				frappe.call({
+					method: 'erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.execute_repost_payment_ledger',
+					args: {
+						docname: frm.doc.name,
+					}
+				});
+				frappe.msgprint(__('Reposting in the background.'));
+			});
+		}
+
+	}
+});
+
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json
new file mode 100644
index 0000000..5175fd1
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json
@@ -0,0 +1,159 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2022-10-19 21:59:33.553852",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "filters_section",
+  "company",
+  "posting_date",
+  "column_break_4",
+  "voucher_type",
+  "add_manually",
+  "status_section",
+  "repost_status",
+  "repost_error_log",
+  "selected_vouchers_section",
+  "repost_vouchers",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "default": "Today",
+   "fieldname": "posting_date",
+   "fieldtype": "Date",
+   "label": "Posting Date",
+   "reqd": 1
+  },
+  {
+   "fieldname": "voucher_type",
+   "fieldtype": "Link",
+   "label": "Voucher Type",
+   "options": "DocType"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Repost Payment Ledger",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
+  {
+   "fieldname": "selected_vouchers_section",
+   "fieldtype": "Section Break",
+   "label": "Vouchers"
+  },
+  {
+   "fieldname": "filters_section",
+   "fieldtype": "Section Break",
+   "label": "Filters"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "repost_vouchers",
+   "fieldtype": "Table",
+   "label": "Selected Vouchers",
+   "options": "Repost Payment Ledger Items"
+  },
+  {
+   "fieldname": "repost_status",
+   "fieldtype": "Select",
+   "label": "Repost Status",
+   "options": "\nQueued\nFailed\nCompleted",
+   "read_only": 1
+  },
+  {
+   "fieldname": "status_section",
+   "fieldtype": "Section Break",
+   "label": "Status"
+  },
+  {
+   "default": "0",
+   "description": "Ignore Voucher Type filter and Select Vouchers Manually",
+   "fieldname": "add_manually",
+   "fieldtype": "Check",
+   "label": "Add Manually"
+  },
+  {
+   "depends_on": "eval:doc.repost_error_log",
+   "fieldname": "repost_error_log",
+   "fieldtype": "Long Text",
+   "label": "Repost Error Log"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2022-11-08 07:38:40.079038",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Repost Payment Ledger",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "email": 1,
+   "export": 1,
+   "permlevel": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
new file mode 100644
index 0000000..9f6828f
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import copy
+
+import frappe
+from frappe import _, qb
+from frappe.model.document import Document
+from frappe.query_builder.custom import ConstantColumn
+from frappe.utils.background_jobs import is_job_queued
+
+from erpnext.accounts.utils import _delete_pl_entries, create_payment_ledger_entry
+
+VOUCHER_TYPES = ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]
+
+
+def repost_ple_for_voucher(voucher_type, voucher_no, gle_map=None):
+	if voucher_type and voucher_no and gle_map:
+		_delete_pl_entries(voucher_type, voucher_no)
+		create_payment_ledger_entry(gle_map, cancel=0)
+
+
+@frappe.whitelist()
+def start_payment_ledger_repost(docname=None):
+	"""
+	Repost Payment Ledger Entries for Vouchers through Background Job
+	"""
+	if docname:
+		repost_doc = frappe.get_doc("Repost Payment Ledger", docname)
+		if repost_doc.docstatus == 1 and repost_doc.repost_status in ["Queued", "Failed"]:
+			try:
+				for entry in repost_doc.repost_vouchers:
+					doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
+
+					if doc.doctype in ["Payment Entry", "Journal Entry"]:
+						gle_map = doc.build_gl_map()
+					else:
+						gle_map = doc.get_gl_entries()
+
+					repost_ple_for_voucher(entry.voucher_type, entry.voucher_no, gle_map)
+
+				frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_error_log", "")
+				frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_status", "Completed")
+			except Exception as e:
+				frappe.db.rollback()
+
+				traceback = frappe.get_traceback()
+				if traceback:
+					message = "Traceback: <br>" + traceback
+					frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_error_log", message)
+
+				frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_status", "Failed")
+
+
+class RepostPaymentLedger(Document):
+	def __init__(self, *args, **kwargs):
+		super(RepostPaymentLedger, self).__init__(*args, **kwargs)
+		self.vouchers = []
+
+	def before_validate(self):
+		self.load_vouchers_based_on_filters()
+		self.set_status()
+
+	def load_vouchers_based_on_filters(self):
+		if not self.add_manually:
+			self.repost_vouchers.clear()
+			self.get_vouchers()
+			self.extend("repost_vouchers", copy.deepcopy(self.vouchers))
+
+	def get_vouchers(self):
+		self.vouchers.clear()
+
+		filter_on_voucher_types = [self.voucher_type] if self.voucher_type else VOUCHER_TYPES
+
+		for vtype in filter_on_voucher_types:
+			doc = qb.DocType(vtype)
+			doctype_name = ConstantColumn(vtype)
+			query = (
+				qb.from_(doc)
+				.select(doctype_name.as_("voucher_type"), doc.name.as_("voucher_no"))
+				.where(
+					(doc.docstatus == 1)
+					& (doc.company == self.company)
+					& (doc.posting_date.gte(self.posting_date))
+				)
+			)
+			entries = query.run(as_dict=True)
+			self.vouchers.extend(entries)
+
+	def set_status(self):
+		if self.docstatus == 0:
+			self.repost_status = "Queued"
+
+	def on_submit(self):
+		execute_repost_payment_ledger(self.name)
+		frappe.msgprint(_("Repost started in the background"))
+
+
+@frappe.whitelist()
+def execute_repost_payment_ledger(docname):
+	"""Repost Payment Ledger Entries by background job."""
+
+	job_name = "payment_ledger_repost_" + docname
+
+	if not is_job_queued(job_name):
+		frappe.enqueue(
+			method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost",
+			docname=docname,
+			is_async=True,
+			job_name=job_name,
+		)
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger_list.js b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger_list.js
new file mode 100644
index 0000000..e045184
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger_list.js
@@ -0,0 +1,12 @@
+frappe.listview_settings["Repost Payment Ledger"] = {
+	add_fields: ["repost_status"],
+	get_indicator: function(doc) {
+		var colors = {
+			'Queued': 'orange',
+			'Completed': 'green',
+			'Failed': 'red',
+		};
+		let status = doc.repost_status;
+		return [__(status), colors[status], 'status,=,'+status];
+	},
+};
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/test_repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/test_repost_payment_ledger.py
new file mode 100644
index 0000000..781726a
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger/test_repost_payment_ledger.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestRepostPaymentLedger(FrappeTestCase):
+	pass
diff --git a/erpnext/accounts/doctype/repost_payment_ledger_items/__init__.py b/erpnext/accounts/doctype/repost_payment_ledger_items/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger_items/__init__.py
diff --git a/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.json b/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.json
new file mode 100644
index 0000000..93005ee
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.json
@@ -0,0 +1,35 @@
+{
+ "actions": [],
+ "creation": "2022-10-20 10:44:18.796489",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "voucher_type",
+  "voucher_no"
+ ],
+ "fields": [
+  {
+   "fieldname": "voucher_type",
+   "fieldtype": "Link",
+   "label": "Voucher Type",
+   "options": "DocType"
+  },
+  {
+   "fieldname": "voucher_no",
+   "fieldtype": "Dynamic Link",
+   "label": "Voucher No",
+   "options": "voucher_type"
+  }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2022-10-28 14:47:11.838109",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Repost Payment Ledger Items",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.py b/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.py
new file mode 100644
index 0000000..fb19e84
--- /dev/null
+++ b/erpnext/accounts/doctype/repost_payment_ledger_items/repost_payment_ledger_items.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class RepostPaymentLedgerItems(Document):
+	pass
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 73ec051..7abf3f3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -64,6 +64,25 @@
 
 		this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
 
+		if (this.frm.doc.repost_required && this.frm.doc.docstatus===1) {
+			this.frm.set_intro(__("Accounting entries for this invoice needs to be reposted. Please click on 'Repost' button to update."));
+			this.frm.add_custom_button(__('Repost Accounting Entries'),
+				() => {
+					this.frm.call({
+						doc: this.frm.doc,
+						method: 'repost_accounting_entries',
+						freeze: true,
+						freeze_message: __('Reposting...'),
+						callback: (r) => {
+							if (!r.exc) {
+								frappe.msgprint(__('Accounting Entries are reposted'));
+								me.frm.refresh();
+							}
+						}
+					});
+				}).removeClass('btn-default').addClass('btn-warning');
+		}
+
 		if (this.frm.doc.is_return) {
 			this.frm.return_print_format = "Sales Invoice Return";
 		}
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 97e5f40..15d1d25 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -207,6 +207,7 @@
   "is_internal_customer",
   "is_discounted",
   "remarks",
+  "repost_required",
   "connections_tab"
  ],
  "fields": [
@@ -1035,6 +1036,7 @@
    "read_only": 1
   },
   {
+   "allow_on_submit": 1,
    "depends_on": "redeem_loyalty_points",
    "fieldname": "loyalty_redemption_account",
    "fieldtype": "Link",
@@ -1333,6 +1335,7 @@
    "options": "fa fa-money"
   },
   {
+   "allow_on_submit": 1,
    "depends_on": "is_pos",
    "fieldname": "cash_bank_account",
    "fieldtype": "Link",
@@ -1432,6 +1435,7 @@
    "print_hide": 1
   },
   {
+   "allow_on_submit": 1,
    "depends_on": "is_pos",
    "fieldname": "account_for_change_amount",
    "fieldtype": "Link",
@@ -1480,6 +1484,7 @@
    "hide_seconds": 1
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "write_off_account",
    "fieldtype": "Link",
    "hide_days": 1,
@@ -1703,6 +1708,7 @@
    "read_only": 1
   },
   {
+   "allow_on_submit": 1,
    "default": "No",
    "fieldname": "is_opening",
    "fieldtype": "Select",
@@ -1917,6 +1923,7 @@
    "read_only": 1
   },
   {
+   "allow_on_submit": 1,
    "depends_on": "eval:doc.is_internal_customer",
    "description": "Unrealized Profit / Loss account for intra-company transfers",
    "fieldname": "unrealized_profit_loss_account",
@@ -1959,6 +1966,7 @@
    "label": "Disable Rounded Total"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "additional_discount_account",
    "fieldtype": "Link",
    "label": "Discount Account",
@@ -2097,6 +2105,15 @@
    "hide_seconds": 1,
    "label": "Write Off",
    "width": "50%"
+  },
+  {
+   "default": "0",
+   "fieldname": "repost_required",
+   "fieldtype": "Check",
+   "hidden": 1,
+   "label": "Repost Required",
+   "no_copy": 1,
+   "read_only": 1
   }
  ],
  "icon": "fa fa-file-text",
@@ -2109,7 +2126,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2022-10-11 13:07:36.488095",
+ "modified": "2022-11-07 16:02:07.972258",
  "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 0c03c55..911440f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -11,6 +11,9 @@
 
 import erpnext
 from erpnext.accounts.deferred_revenue import validate_service_stop_date
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
+	get_accounting_dimensions,
+)
 from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
 	get_loyalty_program_details_with_points,
 	validate_loyalty_points,
@@ -100,13 +103,11 @@
 		self.validate_debit_to_acc()
 		self.clear_unallocated_advances("Sales Invoice Advance", "advances")
 		self.add_remarks()
-		self.validate_write_off_account()
-		self.validate_account_for_change_amount()
 		self.validate_fixed_asset()
 		self.set_income_account_for_fixed_assets()
 		self.validate_item_cost_centers()
-		self.validate_income_account()
 		self.check_conversion_rate()
+		self.validate_accounts()
 
 		validate_inter_company_party(
 			self.doctype, self.customer, self.company, self.inter_company_invoice_reference
@@ -170,6 +171,11 @@
 
 		self.reset_default_field_value("set_warehouse", "items", "warehouse")
 
+	def validate_accounts(self):
+		self.validate_write_off_account()
+		self.validate_account_for_change_amount()
+		self.validate_income_account()
+
 	def validate_fixed_asset(self):
 		for d in self.get("items"):
 			if d.is_fixed_asset and d.meta.get_field("asset") and d.asset:
@@ -367,7 +373,8 @@
 		if self.update_stock == 1:
 			self.repost_future_sle_and_gle()
 
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
+		self.db_set("repost_required", 0)
 
 		if (
 			frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction"
@@ -514,6 +521,92 @@
 	def on_update(self):
 		self.set_paid_amount()
 
+	def on_update_after_submit(self):
+		if hasattr(self, "repost_required"):
+			needs_repost = 0
+
+			# Check if any field affecting accounting entry is altered
+			doc_before_update = self.get_doc_before_save()
+			accounting_dimensions = get_accounting_dimensions() + ["cost_center", "project"]
+
+			# Check if opening entry check updated
+			if doc_before_update.get("is_opening") != self.is_opening:
+				needs_repost = 1
+
+			if not needs_repost:
+				# Parent Level Accounts excluding party account
+				for field in (
+					"additional_discount_account",
+					"cash_bank_account",
+					"account_for_change_amount",
+					"write_off_account",
+					"loyalty_redemption_account",
+					"unrealized_profit_loss_account",
+				):
+					if doc_before_update.get(field) != self.get(field):
+						needs_repost = 1
+						break
+
+				# Check for parent accounting dimensions
+				for dimension in accounting_dimensions:
+					if doc_before_update.get(dimension) != self.get(dimension):
+						needs_repost = 1
+						break
+
+				# Check for child tables
+				if self.check_if_child_table_updated(
+					"items",
+					doc_before_update,
+					("income_account", "expense_account", "discount_account"),
+					accounting_dimensions,
+				):
+					needs_repost = 1
+
+				if self.check_if_child_table_updated(
+					"taxes", doc_before_update, ("account_head",), accounting_dimensions
+				):
+					needs_repost = 1
+
+			self.validate_accounts()
+
+			# validate if deferred revenue is enabled for any item
+			# Don't allow to update the invoice if deferred revenue is enabled
+			for item in self.get("items"):
+				if item.enable_deferred_revenue:
+					frappe.throw(
+						_(
+							"Deferred Revenue is enabled for item {0}. You cannot update the invoice after submission."
+						).format(item.item_code)
+					)
+
+			self.db_set("repost_required", needs_repost)
+
+	def check_if_child_table_updated(
+		self, child_table, doc_before_update, fields_to_check, accounting_dimensions
+	):
+		# Check if any field affecting accounting entry is altered
+		for index, item in enumerate(self.get(child_table)):
+			for field in fields_to_check:
+				if doc_before_update.get(child_table)[index].get(field) != item.get(field):
+					return True
+
+			for dimension in accounting_dimensions:
+				if doc_before_update.get(child_table)[index].get(dimension) != item.get(dimension):
+					return True
+
+		return False
+
+	@frappe.whitelist()
+	def repost_accounting_entries(self):
+		if self.repost_required:
+			self.docstatus = 2
+			self.make_gl_entries_on_cancel()
+			self.docstatus = 1
+			self.make_gl_entries()
+			self.db_set("repost_required", 0)
+		else:
+			frappe.throw(_("No updates pending for reposting"))
+
 	def set_paid_amount(self):
 		paid_amount = 0.0
 		base_paid_amount = 0.0
@@ -2306,7 +2399,7 @@
 	lp_details = get_loyalty_programs(customer)
 
 	if len(lp_details) == 1:
-		frappe.db.set(customer, "loyalty_program", lp_details[0])
+		customer.db_set("loyalty_program", lp_details[0])
 		return lp_details
 	else:
 		return lp_details
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index cb0d1a7..855380e 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2729,6 +2729,31 @@
 
 		check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
 
+		# Update Invoice post submit and then check GL Entries again
+
+		si.load_from_db()
+		si.items[0].income_account = "Service - _TC"
+		si.additional_discount_account = "_Test Account Sales - _TC"
+		si.taxes[0].account_head = "TDS Payable - _TC"
+		si.save()
+
+		si.load_from_db()
+		self.assertTrue(si.repost_required)
+
+		si.repost_accounting_entries()
+
+		expected_gle = [
+			["_Test Account Sales - _TC", 22.0, 0.0, nowdate()],
+			["Debtors - _TC", 88, 0.0, nowdate()],
+			["Service - _TC", 0.0, 100.0, nowdate()],
+			["TDS Payable - _TC", 0.0, 10.0, nowdate()],
+		]
+
+		check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
+
+		si.load_from_db()
+		self.assertFalse(si.repost_required)
+
 	def test_asset_depreciation_on_sale_with_pro_rata(self):
 		"""
 		Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale.
@@ -3286,6 +3311,7 @@
 		"""select account, debit, credit, posting_date
 		from `tabGL Entry`
 		where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
+		and is_cancelled = 0
 		order by posting_date asc, account asc""",
 		(voucher_no, posting_date),
 		as_dict=1,
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 77055f9..62c3ced 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -438,6 +438,7 @@
    "label": "Accounting Details"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "income_account",
    "fieldtype": "Link",
    "label": "Income Account",
@@ -450,6 +451,7 @@
    "width": "120px"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "expense_account",
    "fieldtype": "Link",
    "label": "Expense Account",
@@ -469,6 +471,7 @@
    "print_hide": 1
   },
   {
+   "allow_on_submit": 1,
    "default": ":Company",
    "fieldname": "cost_center",
    "fieldtype": "Link",
@@ -800,6 +803,7 @@
    "options": "Finance Book"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "project",
    "fieldtype": "Link",
    "label": "Project",
@@ -822,7 +826,6 @@
    "label": "Incoming Rate (Costing)",
    "no_copy": 1,
    "options": "Company:company:default_currency",
-   "precision": "6",
    "print_hide": 1
   },
   {
@@ -835,6 +838,7 @@
    "read_only": 1
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "discount_account",
    "fieldtype": "Link",
    "label": "Discount Account",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
index 3a871bf..e236577 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
@@ -51,6 +51,7 @@
    "oldfieldtype": "Data"
   },
   {
+   "allow_on_submit": 1,
    "columns": 2,
    "fieldname": "account_head",
    "fieldtype": "Link",
@@ -63,6 +64,7 @@
    "search_index": 1
   },
   {
+   "allow_on_submit": 1,
    "default": ":Company",
    "fieldname": "cost_center",
    "fieldtype": "Link",
@@ -216,12 +218,13 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-08-05 20:04:01.726867",
+ "modified": "2022-10-17 13:08:17.776528",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Taxes and Charges",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index d7bf991..103c154 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -1146,10 +1146,10 @@
 				if not existing_gle or not compare_existing_and_expected_gle(
 					existing_gle, expected_gle, precision
 				):
-					_delete_gl_entries(voucher_type, voucher_no)
+					_delete_accounting_ledger_entries(voucher_type, voucher_no)
 					voucher_obj.make_gl_entries(gl_entries=expected_gle, from_repost=True)
 			else:
-				_delete_gl_entries(voucher_type, voucher_no)
+				_delete_accounting_ledger_entries(voucher_type, voucher_no)
 
 		if not frappe.flags.in_test:
 			frappe.db.commit()
@@ -1161,18 +1161,28 @@
 			)
 
 
-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),
-	)
+def _delete_pl_entries(voucher_type, voucher_no):
 	ple = qb.DocType("Payment Ledger Entry")
 	qb.from_(ple).delete().where(
 		(ple.voucher_type == voucher_type) & (ple.voucher_no == voucher_no)
 	).run()
 
 
+def _delete_gl_entries(voucher_type, voucher_no):
+	gle = qb.DocType("GL Entry")
+	qb.from_(gle).delete().where(
+		(gle.voucher_type == voucher_type) & (gle.voucher_no == voucher_no)
+	).run()
+
+
+def _delete_accounting_ledger_entries(voucher_type, voucher_no):
+	"""
+	Remove entries from both General and Payment Ledger for specified Voucher
+	"""
+	_delete_gl_entries(voucher_type, voucher_no)
+	_delete_pl_entries(voucher_type, voucher_no)
+
+
 def sort_stock_vouchers_by_posting_date(
 	stock_vouchers: List[Tuple[str, str]]
 ) -> List[Tuple[str, str]]:
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index c224b61..4c10b48 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -361,7 +361,7 @@
 		self.update_reserved_qty_for_subcontract()
 		self.check_on_hold_or_closed_status()
 
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 
 		self.update_prevdoc_status()
 
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index ee28eb6..a560bda 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -31,7 +31,7 @@
 
 		if self.docstatus < 1:
 			# after amend and save, status still shows as cancelled, until submit
-			frappe.db.set(self, "status", "Draft")
+			self.db_set("status", "Draft")
 
 	def validate_duplicate_supplier(self):
 		supplier_list = [d.supplier for d in self.suppliers]
@@ -73,14 +73,14 @@
 			)
 
 	def on_submit(self):
-		frappe.db.set(self, "status", "Submitted")
+		self.db_set("status", "Submitted")
 		for supplier in self.suppliers:
 			supplier.email_sent = 0
 			supplier.quote_status = "Pending"
 		self.send_to_supplier()
 
 	def on_cancel(self):
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 
 	@frappe.whitelist()
 	def get_supplier_email_preview(self, supplier):
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 43152e8..bebff1c 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -145,7 +145,7 @@
 
 	def after_rename(self, olddn, newdn, merge=False):
 		if frappe.defaults.get_global_default("supp_master_name") == "Supplier Name":
-			frappe.db.set(self, "supplier_name", newdn)
+			self.db_set("supplier_name", newdn)
 
 
 @frappe.whitelist()
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index c19c1df..2dd748b 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -30,11 +30,11 @@
 		self.validate_valid_till()
 
 	def on_submit(self):
-		frappe.db.set(self, "status", "Submitted")
+		self.db_set("status", "Submitted")
 		self.update_rfq_supplier_status(1)
 
 	def on_cancel(self):
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 		self.update_rfq_supplier_status(0)
 
 	def on_trash(self):
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 08eb472..f4b6e91 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -60,7 +60,7 @@
 			if not self.get(field) and frappe.db.field_exists(self.opportunity_from, field):
 				try:
 					value = frappe.db.get_value(self.opportunity_from, self.party_name, field)
-					frappe.db.set(self, field, value)
+					self.db_set(field, value)
 				except Exception:
 					continue
 
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 3dc6b0f..95e2d69 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -119,7 +119,7 @@
 				event.add_participant(self.doctype, self.name)
 				event.insert(ignore_permissions=1)
 
-		frappe.db.set(self, "status", "Submitted")
+		self.db_set("status", "Submitted")
 
 	def create_schedule_list(self, start_date, end_date, no_of_visit, sales_person):
 		schedule_list = []
@@ -245,7 +245,7 @@
 			self.generate_schedule()
 
 	def on_update(self):
-		frappe.db.set(self, "status", "Draft")
+		self.db_set("status", "Draft")
 
 	def update_amc_date(self, serial_nos, amc_expiry_date=None):
 		for serial_no in serial_nos:
@@ -344,7 +344,7 @@
 			if d.serial_no:
 				serial_nos = get_valid_serial_nos(d.serial_no)
 				self.update_amc_date(serial_nos)
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 		delete_events(self.doctype, self.name)
 
 	def on_trash(self):
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index 66f4426..0d319bf 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -125,12 +125,12 @@
 
 	def on_submit(self):
 		self.update_customer_issue(1)
-		frappe.db.set(self, "status", "Submitted")
+		self.db_set("status", "Submitted")
 		self.update_status_and_actual_date()
 
 	def on_cancel(self):
 		self.check_if_last_visit()
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 		self.update_status_and_actual_date(cancel=True)
 
 	def on_update(self):
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 580838e..ca4f63d 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -206,8 +206,8 @@
 		self.manage_default_bom()
 
 	def on_cancel(self):
-		frappe.db.set(self, "is_active", 0)
-		frappe.db.set(self, "is_default", 0)
+		self.db_set("is_active", 0)
+		self.db_set("is_default", 0)
 
 		# check if used in any other bom
 		self.validate_bom_links()
@@ -449,10 +449,10 @@
 			not frappe.db.exists(dict(doctype="BOM", docstatus=1, item=self.item, is_default=1))
 			and self.is_active
 		):
-			frappe.db.set(self, "is_default", 1)
+			self.db_set("is_default", 1)
 			frappe.db.set_value("Item", self.item, "default_bom", self.name)
 		else:
-			frappe.db.set(self, "is_default", 0)
+			self.db_set("is_default", 0)
 			item = frappe.get_doc("Item", self.item)
 			if item.default_bom == self.name:
 				frappe.db.set_value("Item", self.item, "default_bom", None)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 1e6d982..0735133 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -373,7 +373,7 @@
 
 	def on_cancel(self):
 		self.validate_cancel()
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 
 		if self.production_plan and frappe.db.exists(
 			"Production Plan Item Reference", {"parent": self.production_plan}
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py
index 76795e3..3c25622 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation.py
@@ -100,9 +100,7 @@
 
 def check_if_within_operating_hours(workstation, operation, from_datetime, to_datetime):
 	if from_datetime and to_datetime:
-		if not cint(
-			frappe.db.get_value("Manufacturing Settings", None, "allow_production_on_holidays")
-		):
+		if not frappe.db.get_single_value("Manufacturing Settings", "allow_production_on_holidays"):
 			check_workstation_for_holiday(workstation, from_datetime, to_datetime)
 
 		if not cint(frappe.db.get_value("Manufacturing Settings", None, "allow_overtime")):
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index e1486de..a376bf4 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -92,18 +92,26 @@
 			frm.fields_dict["time_logs"].grid.toggle_enable("billing_hours", false);
 			frm.fields_dict["time_logs"].grid.toggle_enable("is_billable", false);
 		}
+
+		let filters = {
+			"status": "Open"
+		};
+
+		if (frm.doc.customer) {
+			filters["customer"] = frm.doc.customer;
+		}
+
+		frm.set_query('parent_project', function(doc) {
+			return {
+				filters: filters
+			};
+		});
+
 		frm.trigger('setup_filters');
 		frm.trigger('set_dynamic_field_label');
 	},
 
 	customer: function(frm) {
-		frm.set_query('parent_project', function(doc) {
-			return {
-				filters: {
-					"customer": doc.customer
-				}
-			};
-		});
 		frm.set_query('project', 'time_logs', function(doc) {
 			return {
 				filters: {
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index c1fe72b..a07f75d 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -143,6 +143,12 @@
 
 cur_frm.cscript.account_head = function(doc, cdt, cdn) {
 	var d = locals[cdt][cdn];
+
+	if (doc.docstatus == 1) {
+		// Should not trigger any changes on change post submit
+		return;
+	}
+
 	if(!d.charge_type && d.account_head){
 		frappe.msgprint(__("Please select Charge Type first"));
 		frappe.model.set_value(cdt, cdn, "account_head", "");
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 6605685..d0eb377 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -294,7 +294,7 @@
 
 	def after_rename(self, olddn, newdn, merge=False):
 		if frappe.defaults.get_global_default("cust_master_name") == "Customer Name":
-			frappe.db.set(self, "customer_name", newdn)
+			self.db_set("customer_name", newdn)
 
 	def set_loyalty_program(self):
 		if self.loyalty_program:
diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py
index dd0b1e8..0ef4754 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.py
+++ b/erpnext/selling/doctype/installation_note/installation_note.py
@@ -87,13 +87,13 @@
 			frappe.throw(_("Please pull items from Delivery Note"))
 
 	def on_update(self):
-		frappe.db.set(self, "status", "Draft")
+		self.db_set("status", "Draft")
 
 	def on_submit(self):
 		self.validate_serial_no()
 		self.update_prevdoc_status()
-		frappe.db.set(self, "status", "Submitted")
+		self.db_set("status", "Submitted")
 
 	def on_cancel(self):
 		self.update_prevdoc_status()
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 96092b1..60d98fb 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -119,10 +119,10 @@
 		if not (self.is_fully_ordered() or self.is_partially_ordered()):
 			get_lost_reasons = frappe.get_list("Quotation Lost Reason", fields=["name"])
 			lost_reasons_lst = [reason.get("name") for reason in get_lost_reasons]
-			frappe.db.set(self, "status", "Lost")
+			self.db_set("status", "Lost")
 
 			if detailed_reason:
-				frappe.db.set(self, "order_lost_reason", detailed_reason)
+				self.db_set("order_lost_reason", detailed_reason)
 
 			for reason in lost_reasons_list:
 				if reason.get("lost_reason") in lost_reasons_lst:
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 1f3419f..5fadfcb 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -246,7 +246,7 @@
 		self.update_project()
 		self.update_prevdoc_status("cancel")
 
-		frappe.db.set(self, "status", "Cancelled")
+		self.db_set("status", "Cancelled")
 
 		self.update_blanket_order()
 
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 490504a..875f63d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -207,15 +207,14 @@
 		frappe.local.flags.ignore_root_company_validation = True
 		create_charts(self.name, self.chart_of_accounts, self.existing_company)
 
-		frappe.db.set(
-			self,
+		self.db_set(
 			"default_receivable_account",
 			frappe.db.get_value(
 				"Account", {"company": self.name, "account_type": "Receivable", "is_group": 0}
 			),
 		)
-		frappe.db.set(
-			self,
+
+		self.db_set(
 			"default_payable_account",
 			frappe.db.get_value(
 				"Account", {"company": self.name, "account_type": "Payable", "is_group": 0}
@@ -491,12 +490,12 @@
 				cc_doc.flags.ignore_mandatory = True
 			cc_doc.insert()
 
-		frappe.db.set(self, "cost_center", _("Main") + " - " + self.abbr)
-		frappe.db.set(self, "round_off_cost_center", _("Main") + " - " + self.abbr)
-		frappe.db.set(self, "depreciation_cost_center", _("Main") + " - " + self.abbr)
+		self.db_set("cost_center", _("Main") + " - " + self.abbr)
+		self.db_set("round_off_cost_center", _("Main") + " - " + self.abbr)
+		self.db_set("depreciation_cost_center", _("Main") + " - " + self.abbr)
 
 	def after_rename(self, olddn, newdn, merge=False):
-		frappe.db.set(self, "company_name", newdn)
+		self.db_set("company_name", newdn)
 
 		frappe.db.sql(
 			"""update `tabDefaultValue` set defvalue=%s
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 2614a7f..817248e 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -120,7 +120,6 @@
 			self.title = _("{0} Request for {1}").format(self.material_request_type, items)[:100]
 
 	def on_submit(self):
-		# frappe.db.set(self, 'status', 'Submitted')
 		self.update_requested_qty()
 		self.update_requested_qty_in_production_plan()
 		if self.material_request_type == "Purchase":
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index f02462c..f0a9499 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -216,7 +216,7 @@
 		po.load_from_db()
 		mr.update_status("Stopped")
 		self.assertRaises(frappe.InvalidStatusError, po.submit)
-		frappe.db.set(po, "docstatus", 1)
+		po.db_set("docstatus", 1)
 		self.assertRaises(frappe.InvalidStatusError, po.cancel)
 
 		# resubmit and check for per complete
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_list.js b/erpnext/stock/doctype/stock_entry/stock_entry_list.js
index 4eb0da1..af29d49 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_list.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_list.js
@@ -3,7 +3,6 @@
 		"`tabStock Entry`.`purpose`", "`tabStock Entry`.`work_order`", "`tabStock Entry`.`bom_no`",
 		"`tabStock Entry`.`is_return`"],
 	get_indicator: function (doc) {
-		debugger
 		if(doc.is_return===1 && doc.purpose === "Material Transfer for Manufacture") {
 			return [__("Material Returned from WIP"), "orange",
 				"is_return,=,1|purpose,=,Material Transfer for Manufacture|docstatus,<,2"];
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index aff76eb..b6bef8c 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -57,6 +57,18 @@
 				filters: { 'company': frm.doc.company }
 			};
 		});
+
+		frappe.db.get_single_value('Buying Settings', 'backflush_raw_materials_of_subcontract_based_on').then(val => {
+			if (val == 'Material Transferred for Subcontract') {
+				frm.fields_dict['supplied_items'].grid.grid_rows.forEach((grid_row) => {
+					grid_row.docfields.forEach((df) => {
+						if (df.fieldname == 'consumed_qty') {
+							df.read_only = 0;
+						}
+					});
+				});
+			}
+		});
 	},
 
 	refresh: (frm) => {
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
index a9e5193..deb8342 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
@@ -4,6 +4,9 @@
 def get_data():
 	return {
 		"fieldname": "subcontracting_receipt_no",
+		"non_standard_fieldnames": {
+			"Subcontracting Receipt": "return_against",
+		},
 		"internal_links": {
 			"Subcontracting Order": ["items", "subcontracting_order"],
 			"Project": ["items", "project"],
@@ -11,5 +14,6 @@
 		},
 		"transactions": [
 			{"label": _("Reference"), "items": ["Subcontracting Order", "Quality Inspection", "Project"]},
+			{"label": _("Returns"), "items": ["Subcontracting Receipt"]},
 		],
 	}
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
index ddbb806..d21bc22 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
@@ -1,207 +1,208 @@
 {
-    "actions": [],
-    "creation": "2022-04-18 10:45:16.538479",
-    "doctype": "DocType",
-    "editable_grid": 1,
-    "engine": "InnoDB",
-    "field_order": [
-        "main_item_code",
-        "rm_item_code",
-        "item_name",
-        "bom_detail_no",
-        "col_break1",
-        "description",
-        "stock_uom",
-        "conversion_factor",
-        "reference_name",
-        "secbreak_1",
-        "rate",
-        "col_break2",
-        "amount",
-        "secbreak_2",
-        "available_qty_for_consumption",
-        "required_qty",
-        "col_break3",
-        "consumed_qty",
-        "current_stock",
-        "secbreak_3",
-        "batch_no",
-        "col_break4",
-        "serial_no",
-        "subcontracting_order"
-    ],
-    "fields": [
-        {
-            "fieldname": "main_item_code",
-            "fieldtype": "Link",
-            "in_list_view": 1,
-            "label": "Item Code",
-            "options": "Item",
-            "read_only": 1
-        },
-        {
-            "fieldname": "rm_item_code",
-            "fieldtype": "Link",
-            "in_list_view": 1,
-            "label": "Raw Material Item Code",
-            "options": "Item",
-            "read_only": 1
-        },
-        {
-            "fieldname": "description",
-            "fieldtype": "Text Editor",
-            "in_global_search": 1,
-            "label": "Description",
-            "print_width": "300px",
-            "read_only": 1,
-            "width": "300px"
-        },
-        {
-            "fieldname": "batch_no",
-            "fieldtype": "Link",
-            "label": "Batch No",
-            "no_copy": 1,
-            "options": "Batch"
-        },
-        {
-            "fieldname": "serial_no",
-            "fieldtype": "Text",
-            "label": "Serial No",
-            "no_copy": 1
-        },
-        {
-            "fieldname": "col_break1",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "required_qty",
-            "fieldtype": "Float",
-            "label": "Required Qty",
-            "print_hide": 1,
-            "read_only": 1
-        },
-        {
-            "columns": 2,
-            "fieldname": "consumed_qty",
-            "fieldtype": "Float",
-            "in_list_view": 1,
-            "label": "Consumed Qty",
-            "reqd": 1
-        },
-        {
-            "fieldname": "stock_uom",
-            "fieldtype": "Link",
-            "label": "Stock Uom",
-            "options": "UOM",
-            "read_only": 1
-        },
-        {
-            "fieldname": "rate",
-            "fieldtype": "Currency",
-            "label": "Rate",
-            "options": "Company:company:default_currency",
-            "read_only": 1
-        },
-        {
-            "fieldname": "amount",
-            "fieldtype": "Currency",
-            "label": "Amount",
-            "options": "Company:company:default_currency",
-            "read_only": 1
-        },
-        {
-            "default": "1",
-            "fieldname": "conversion_factor",
-            "fieldtype": "Float",
-            "hidden": 1,
-            "label": "Conversion Factor",
-            "read_only": 1
-        },
-        {
-            "fieldname": "current_stock",
-            "fieldtype": "Float",
-            "in_list_view": 1,
-            "label": "Current Stock",
-            "read_only": 1
-        },
-        {
-            "fieldname": "reference_name",
-            "fieldtype": "Data",
-            "hidden": 1,
-            "in_list_view": 1,
-            "label": "Reference Name",
-            "read_only": 1
-        },
-        {
-            "fieldname": "bom_detail_no",
-            "fieldtype": "Data",
-            "hidden": 1,
-            "in_list_view": 1,
-            "label": "BOM Detail No",
-            "read_only": 1
-        },
-        {
-            "fieldname": "secbreak_1",
-            "fieldtype": "Section Break"
-        },
-        {
-            "fieldname": "col_break2",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "secbreak_2",
-            "fieldtype": "Section Break"
-        },
-        {
-            "fieldname": "col_break3",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "secbreak_3",
-            "fieldtype": "Section Break"
-        },
-        {
-            "fieldname": "col_break4",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "item_name",
-            "fieldtype": "Data",
-            "label": "Item Name",
-            "read_only": 1
-        },
-        {
-            "fieldname": "subcontracting_order",
-            "fieldtype": "Link",
-            "hidden": 1,
-            "label": "Subcontracting Order",
-            "no_copy": 1,
-            "options": "Subcontracting Order",
-            "print_hide": 1,
-            "read_only": 1
-        },
-        {
-            "default": "0",
-            "fieldname": "available_qty_for_consumption",
-            "fieldtype": "Float",
-            "in_list_view": 1,
-            "label": "Available Qty For Consumption",
-            "print_hide": 1,
-            "read_only": 1
-        }
-    ],
-    "idx": 1,
-    "istable": 1,
-    "links": [],
-    "modified": "2022-09-02 22:28:53.392381",
-    "modified_by": "Administrator",
-    "module": "Subcontracting",
-    "name": "Subcontracting Receipt Supplied Item",
-    "naming_rule": "Autoincrement",
-    "owner": "Administrator",
-    "permissions": [],
-    "sort_field": "modified",
-    "sort_order": "DESC",
-    "states": [],
-    "track_changes": 1
+ "actions": [],
+ "creation": "2022-04-18 10:45:16.538479",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "main_item_code",
+  "rm_item_code",
+  "item_name",
+  "bom_detail_no",
+  "col_break1",
+  "description",
+  "stock_uom",
+  "conversion_factor",
+  "reference_name",
+  "secbreak_1",
+  "rate",
+  "col_break2",
+  "amount",
+  "secbreak_2",
+  "available_qty_for_consumption",
+  "required_qty",
+  "col_break3",
+  "consumed_qty",
+  "current_stock",
+  "secbreak_3",
+  "batch_no",
+  "col_break4",
+  "serial_no",
+  "subcontracting_order"
+ ],
+ "fields": [
+  {
+   "fieldname": "main_item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Code",
+   "options": "Item",
+   "read_only": 1
+  },
+  {
+   "fieldname": "rm_item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Raw Material Item Code",
+   "options": "Item",
+   "read_only": 1
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Text Editor",
+   "in_global_search": 1,
+   "label": "Description",
+   "print_width": "300px",
+   "read_only": 1,
+   "width": "300px"
+  },
+  {
+   "fieldname": "batch_no",
+   "fieldtype": "Link",
+   "label": "Batch No",
+   "no_copy": 1,
+   "options": "Batch"
+  },
+  {
+   "fieldname": "serial_no",
+   "fieldtype": "Text",
+   "label": "Serial No",
+   "no_copy": 1
+  },
+  {
+   "fieldname": "col_break1",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "required_qty",
+   "fieldtype": "Float",
+   "label": "Required Qty",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "columns": 2,
+   "fieldname": "consumed_qty",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Consumed Qty",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "Stock Uom",
+   "options": "UOM",
+   "read_only": 1
+  },
+  {
+   "fieldname": "rate",
+   "fieldtype": "Currency",
+   "label": "Rate",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "label": "Amount",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "default": "1",
+   "fieldname": "conversion_factor",
+   "fieldtype": "Float",
+   "hidden": 1,
+   "label": "Conversion Factor",
+   "read_only": 1
+  },
+  {
+   "fieldname": "current_stock",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Current Stock",
+   "read_only": 1
+  },
+  {
+   "fieldname": "reference_name",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "in_list_view": 1,
+   "label": "Reference Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "bom_detail_no",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "in_list_view": 1,
+   "label": "BOM Detail No",
+   "read_only": 1
+  },
+  {
+   "fieldname": "secbreak_1",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "col_break2",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "secbreak_2",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "col_break3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "secbreak_3",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "col_break4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "label": "Item Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "subcontracting_order",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Subcontracting Order",
+   "no_copy": 1,
+   "options": "Subcontracting Order",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "available_qty_for_consumption",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Available Qty For Consumption",
+   "print_hide": 1,
+   "read_only": 1
+  }
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2022-11-07 17:17:21.670761",
+ "modified_by": "Administrator",
+ "module": "Subcontracting",
+ "name": "Subcontracting Receipt Supplied Item",
+ "naming_rule": "Autoincrement",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.py b/erpnext/support/doctype/warranty_claim/warranty_claim.py
index 5e2ea06..c86356f 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.py
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.py
@@ -35,7 +35,7 @@
 			lst1 = ",".join(x[0] for x in lst)
 			frappe.throw(_("Cancel Material Visit {0} before cancelling this Warranty Claim").format(lst1))
 		else:
-			frappe.db.set(self, "status", "Cancelled")
+			self.db_set("status", "Cancelled")
 
 	def on_update(self):
 		pass