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 6148e16513..156f77f5ac 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json @@ -23,6 +23,7 @@ "error_section", "error_log", "items_to_be_repost", + "affected_transactions", "distinct_item_and_warehouse", "current_index" ], @@ -172,12 +173,20 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "affected_transactions", + "fieldtype": "Code", + "hidden": 1, + "label": "Affected Transactions", + "no_copy": 1, + "read_only": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-03-30 07:22:48.520266", + "modified": "2022-04-18 14:08:08.821602", "modified_by": "Administrator", "module": "Stock", "name": "Repost Item Valuation", 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 49aa0ff72f..eb0be460d8 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -8,8 +8,12 @@ from frappe.utils import cint, get_link_to_form, get_weekday, now, nowtime from frappe.utils.user import get_users_with_role import erpnext -from erpnext.accounts.utils import update_gl_entries_after -from erpnext.stock.stock_ledger import get_items_to_be_repost, repost_future_sle +from erpnext.accounts.utils import get_future_stock_vouchers, repost_gle_for_stock_vouchers +from erpnext.stock.stock_ledger import ( + get_affected_transactions, + get_items_to_be_repost, + repost_future_sle, +) class RepostItemValuation(Document): @@ -169,6 +173,7 @@ def repost_sl_entries(doc): ], allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher, + doc=doc, ) @@ -176,27 +181,46 @@ def repost_gl_entries(doc): if not cint(erpnext.is_perpetual_inventory_enabled(doc.company)): return + # directly modified transactions + directly_dependent_transactions = _get_directly_dependent_vouchers(doc) + repost_affected_transaction = get_affected_transactions(doc) + repost_gle_for_stock_vouchers( + directly_dependent_transactions + list(repost_affected_transaction), + doc.posting_date, + doc.company, + ) + + +def _get_directly_dependent_vouchers(doc): + """Get stock vouchers that are directly affected by reposting + i.e. any one item-warehouse is present in the stock transaction""" + + items = set() + warehouses = set() + if doc.based_on == "Transaction": ref_doc = frappe.get_doc(doc.voucher_type, doc.voucher_no) doc_items, doc_warehouses = ref_doc.get_items_and_warehouses() + items.update(doc_items) + warehouses.update(doc_warehouses) sles = get_items_to_be_repost(doc.voucher_type, doc.voucher_no) - sle_items = [sle.item_code for sle in sles] - sle_warehouse = [sle.warehouse for sle in sles] - - items = list(set(doc_items).union(set(sle_items))) - warehouses = list(set(doc_warehouses).union(set(sle_warehouse))) + sle_items = {sle.item_code for sle in sles} + sle_warehouses = {sle.warehouse for sle in sles} + items.update(sle_items) + warehouses.update(sle_warehouses) else: - items = [doc.item_code] - warehouses = [doc.warehouse] + items.add(doc.item_code) + warehouses.add(doc.warehouse) - update_gl_entries_after( - doc.posting_date, - doc.posting_time, - for_warehouses=warehouses, - for_items=items, + affected_vouchers = get_future_stock_vouchers( + posting_date=doc.posting_date, + posting_time=doc.posting_time, + for_warehouses=list(warehouses), + for_items=list(items), company=doc.company, ) + return affected_vouchers def notify_error_to_stock_managers(doc, traceback): diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index b7fd65bda8..f46332b726 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -3,7 +3,7 @@ import copy import json -from typing import Optional +from typing import Optional, Set, Tuple import frappe from frappe import _ @@ -214,6 +214,7 @@ def repost_future_sle( args = get_items_to_be_repost(voucher_type, voucher_no, doc) distinct_item_warehouses = get_distinct_item_warehouse(args, doc) + affected_transactions = get_affected_transactions(doc) i = get_current_index(doc) or 0 while i < len(args): @@ -231,6 +232,7 @@ def repost_future_sle( allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher, ) + affected_transactions.update(obj.affected_transactions) distinct_item_warehouses[ (args[i].get("item_code"), args[i].get("warehouse")) @@ -250,10 +252,14 @@ def repost_future_sle( i += 1 if doc and i % 2 == 0: - update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses) + update_args_in_repost_item_valuation( + doc, i, args, distinct_item_warehouses, affected_transactions + ) if doc and args: - update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses) + update_args_in_repost_item_valuation( + doc, i, args, distinct_item_warehouses, affected_transactions + ) def validate_item_warehouse(args): @@ -263,20 +269,24 @@ def validate_item_warehouse(args): frappe.throw(_(validation_msg)) -def update_args_in_repost_item_valuation(doc, index, args, distinct_item_warehouses): - frappe.db.set_value( - doc.doctype, - doc.name, +def update_args_in_repost_item_valuation( + doc, index, args, distinct_item_warehouses, affected_transactions +): + affected_transactions_list = [list(transaction) for transaction in affected_transactions] + + doc.db_set( { "items_to_be_repost": json.dumps(args, default=str), "distinct_item_and_warehouse": json.dumps( {str(k): v for k, v in distinct_item_warehouses.items()}, default=str ), "current_index": index, - }, + "affected_transactions": json.dumps(affected_transactions_list), + } ) - frappe.db.commit() + if not frappe.flags.in_test: + frappe.db.commit() frappe.publish_realtime( "item_reposting_progress", @@ -313,6 +323,14 @@ def get_distinct_item_warehouse(args=None, doc=None): return distinct_item_warehouses +def get_affected_transactions(doc) -> Set[Tuple[str, str]]: + if not doc.affected_transactions: + return set() + + transactions = frappe.parse_json(doc.affected_transactions) + return {tuple(transaction) for transaction in transactions} + + def get_current_index(doc=None): if doc and doc.current_index: return doc.current_index @@ -360,6 +378,7 @@ class update_entries_after(object): self.new_items_found = False self.distinct_item_warehouses = args.get("distinct_item_warehouses", frappe._dict()) + self.affected_transactions: Set[Tuple[str, str]] = set() self.data = frappe._dict() self.initialize_previous_data(self.args) @@ -518,6 +537,7 @@ class update_entries_after(object): # previous sle data for this warehouse self.wh_data = self.data[sle.warehouse] + self.affected_transactions.add((sle.voucher_type, sle.voucher_no)) if (sle.serial_no and not self.via_landed_cost_voucher) or not cint(self.allow_negative_stock): # validate negative stock for serialized items, fifo valuation