fix: Check for backdated validation only for transaction company (#23639)

* fix: Check SLE only for transaction company

* fix: Add tests

* fix: Move backdated entry validation from transaction base to stock ledger entry

* chore: Add tests

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 74a06d8..12c8906 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -6,7 +6,7 @@
 import json
 import frappe, erpnext
 import frappe.defaults
-from frappe.utils import cint, flt, cstr, today, random_string
+from frappe.utils import cint, flt, cstr, today, random_string, add_days
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
 from erpnext.stock.doctype.item.test_item import create_item
 from erpnext import set_perpetual_inventory
@@ -665,6 +665,59 @@
 		warehouse.account = ''
 		warehouse.save()
 
+	def test_backdated_purchase_receipt(self):
+		# make purchase receipt for default company
+		make_purchase_receipt(company="_Test Company 4", warehouse="Stores - _TC4")
+
+		# try to make another backdated PR
+		posting_date = add_days(today(), -1)
+		pr = make_purchase_receipt(company="_Test Company 4", warehouse="Stores - _TC4",
+			do_not_submit=True)
+
+		pr.set_posting_time = 1
+		pr.posting_date = posting_date
+		pr.save()
+
+		self.assertRaises(frappe.ValidationError, pr.submit)
+
+		# make purchase receipt for other company backdated
+		pr = make_purchase_receipt(company="_Test Company 5", warehouse="Stores - _TC5",
+			do_not_submit=True)
+
+		pr.set_posting_time = 1
+		pr.posting_date = posting_date
+		pr.submit()
+
+		# Allowed to submit for other company's PR
+		self.assertEqual(pr.docstatus, 1)
+
+	def test_backdated_purchase_receipt_for_same_company_different_warehouse(self):
+			# make purchase receipt for default company
+		make_purchase_receipt(company="_Test Company 4", warehouse="Stores - _TC4")
+
+		# try to make another backdated PR
+		posting_date = add_days(today(), -1)
+		pr = make_purchase_receipt(company="_Test Company 4", warehouse="Stores - _TC4",
+			do_not_submit=True)
+
+		pr.set_posting_time = 1
+		pr.posting_date = posting_date
+		pr.save()
+
+		self.assertRaises(frappe.ValidationError, pr.submit)
+
+		# make purchase receipt for other company backdated
+		pr = make_purchase_receipt(company="_Test Company 4", warehouse="Finished Goods - _TC4",
+			do_not_submit=True)
+
+		pr.set_posting_time = 1
+		pr.posting_date = posting_date
+		pr.submit()
+
+		# Allowed to submit for other company's PR
+		self.assertEqual(pr.docstatus, 1)
+
+
 def get_sl_entries(voucher_type, voucher_no):
 	return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
 		from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
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 101c6e0..bb356f6 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -5,7 +5,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import flt, getdate, add_days, formatdate
+from frappe.utils import flt, getdate, add_days, formatdate, get_datetime, date_diff
 from frappe.model.document import Document
 from datetime import date
 from erpnext.controllers.item_variant import ItemTemplateCannotHaveStock
@@ -33,6 +33,8 @@
 		self.scrub_posting_time()
 		self.validate_and_set_fiscal_year()
 		self.block_transactions_against_group_warehouse()
+		self.validate_with_last_transaction_posting_time()
+		self.validate_future_posting()
 
 	def on_submit(self):
 		self.check_stock_frozen_date()
@@ -139,6 +141,30 @@
 		from erpnext.stock.utils import is_group_warehouse
 		is_group_warehouse(self.warehouse)
 
+	def validate_with_last_transaction_posting_time(self):
+		last_transaction_time = frappe.db.sql("""
+			select MAX(timestamp(posting_date, posting_time)) as posting_time
+			from `tabStock Ledger Entry`
+			where docstatus = 1 and item_code = %s
+			and warehouse = %s""", (self.item_code, self.warehouse))[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):
+			msg = _("Last Stock Transaction for item {0} under warehouse {1} was on {2}.").format(frappe.bold(self.item_code),
+				frappe.bold(self.warehouse), frappe.bold(last_transaction_time))
+
+			msg += "<br><br>" + _("Stock Transactions for Item {0} under warehouse {1} cannot be posted before this time.").format(
+				frappe.bold(self.item_code), frappe.bold(self.warehouse))
+
+			msg += "<br><br>" + _("Please remove this item and try to submit again or update the posting time.")
+			frappe.throw(msg, title=_("Backdated Stock Entry"))
+
+	def validate_future_posting(self):
+		if date_diff(self.posting_date, getdate()) > 0:
+			msg = _("Posting future stock transactions are not allowed due to Immutable Ledger")
+			frappe.throw(msg, title=_("Future Posting Not Allowed"))
+
 def on_doctype_update():
 	if not frappe.db.has_index('tabStock Ledger Entry', 'posting_sort_index'):
 		frappe.db.commit()
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 298e111..c8ae733 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -29,28 +29,6 @@
 			except ValueError:
 				frappe.throw(_('Invalid Posting Time'))
 
-		self.validate_future_posting()
-		self.validate_with_last_transaction_posting_time()
-	
-	def is_stock_transaction(self):
-		if self.doctype not in ["Sales Invoice", "Purchase Invoice", "Stock Entry", "Stock Reconciliation",
-			"Delivery Note", "Purchase Receipt", "Fees"]:
-				return False
-
-		if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
-			if not (self.get("update_stock") or self.get("is_pos")):
-				return False
-
-		return True
-	
-	def validate_future_posting(self):
-		if not self.is_stock_transaction():
-			return
-
-		if getattr(self, 'set_posting_time', None) and date_diff(self.posting_date, nowdate()) > 0:
-			msg = _("Posting future transactions are not allowed due to Immutable Ledger")
-			frappe.throw(msg, title=_("Future Posting Not Allowed"))
-
 	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 \
@@ -180,25 +158,6 @@
 
 		return ret
 
-	def validate_with_last_transaction_posting_time(self):
-
-		if not self.is_stock_transaction():
-			return
-
-		for item in self.get('items'):
-			last_transaction_time = frappe.db.sql("""
-				select MAX(timestamp(posting_date, posting_time)) as posting_time
-				from `tabStock Ledger Entry`
-				where docstatus = 1 and item_code = %s """, (item.item_code))[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):
-				msg = _("Last Stock Transaction for item {0} was on {1}.").format(frappe.bold(item.item_code), frappe.bold(last_transaction_time))
-				msg += "<br><br>" + _("Stock Transactions for Item {0} cannot be posted before this time.").format(frappe.bold(item.item_code))
-				msg += "<br><br>" + _("Please remove this item and try to submit again or update the posting time.")
-				frappe.throw(msg, title=_("Backdated Stock Entry"))
-
 def delete_events(ref_type, ref_name):
 	events = frappe.db.sql_list(""" SELECT
 			distinct `tabEvent`.name