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: