perf: skip unnecessary item-wh reposts

Using basic idea that repost with older posting date will also take care
of subsequent posting dates...

When Item-WH reposts are queued:

1. If another repost with same item-wh but older posting date exists
    then skip current one.
2. If another repost with same item-wh but newer posting date exists
    then skip another one.
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
index 794c15e..cd7e63b 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
@@ -64,7 +64,7 @@
    "in_standard_filter": 1,
    "label": "Status",
    "no_copy": 1,
-   "options": "Queued\nIn Progress\nCompleted\nFailed",
+   "options": "Queued\nIn Progress\nCompleted\nSkipped\nFailed",
    "read_only": 1
   },
   {
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 64cea1d..c0cb2c5 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -2,10 +2,21 @@
 # For license information, please see license.txt
 
 
+import datetime
+
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, get_weekday, now, nowtime, today
+from frappe.utils import (
+	cint,
+	get_datetime,
+	get_link_to_form,
+	get_time,
+	get_weekday,
+	now,
+	nowtime,
+	today,
+)
 from frappe.utils.user import get_users_with_role
 from rq.timeouts import JobTimeoutException
 
@@ -19,7 +30,7 @@
 
 class RepostItemValuation(Document):
 	def validate(self):
-		self.set_status()
+		self.set_status(write=False)
 		self.reset_field_values()
 		self.set_company()
 
@@ -37,12 +48,17 @@
 		elif self.warehouse:
 			self.company = frappe.get_cached_value("Warehouse", self.warehouse, "company")
 
-	def set_status(self, status=None):
+	def set_status(self, status=None, write=True):
+		status = status or self.status
 		if not status:
-			status = 'Queued'
-		self.db_set('status', status)
+			self.status = 'Queued'
+		else:
+			self.status = status
+		if write:
+			self.db_set('status', self.status)
 
 	def on_submit(self):
+		self.deduplicate_similar_repost()
 		if not frappe.flags.in_test:
 			return
 
@@ -55,6 +71,35 @@
 		frappe.enqueue(repost, timeout=1800, queue='long',
 			job_name='repost_sle', now=True, doc=self)
 
+	def deduplicate_similar_repost(self):
+		""" Deduplicate similar reposts based on item-warehouse-posting combination."""
+		if self.based_on != "Item and Warehouse":
+			return
+
+		queued = frappe.db.get_value(
+				"Repost Item Valuation",
+				filters={
+					"docstatus": 1,
+					"status": "Queued",
+					"item_code": self.item_code,
+					"warehouse": self.warehouse,
+					"based_on": self.based_on,
+					"name": ("!=", self.name)
+				},
+				fieldname=["name", "posting_date", "posting_time"],
+				as_dict=True
+			)
+		if not queued:
+			return
+
+		posting_timestamp = datetime.datetime.combine(get_datetime(self.posting_date), get_time(self.posting_time))
+		queued_timestamp = datetime.datetime.combine(get_datetime(queued.posting_date), get_time(queued.posting_time))
+
+		if posting_timestamp > queued_timestamp:
+			self.set_status("Skipped")
+		else:
+			frappe.db.set_value("Repost Item Valuation", queued.name, "status", "Skipped")
+
 
 def on_doctype_update():
 	frappe.db.add_index("Repost Item Valuation", ["warehouse", "item_code"], "item_warehouse")
@@ -136,7 +181,8 @@
 
 	for row in riv_entries:
 		doc = frappe.get_doc('Repost Item Valuation', row.name)
-		repost(doc)
+		if doc.status in ('Queued', 'In Progress'):
+			repost(doc)
 
 	riv_entries = get_repost_item_valuation_entries()
 	if riv_entries: