Merge pull request #26432 from nabinhait/reposting-optimization-v13-pre-release
refactor: Optimized code for reposting item valuation
This commit is contained in:
commit
1ef1daf383
@ -529,7 +529,7 @@ class StockEntry(StockController):
|
|||||||
scrap_items_cost = sum([flt(d.basic_amount) for d in self.get("items") if d.is_scrap_item])
|
scrap_items_cost = sum([flt(d.basic_amount) for d in self.get("items") if d.is_scrap_item])
|
||||||
|
|
||||||
# Get raw materials cost from BOM if multiple material consumption entries
|
# Get raw materials cost from BOM if multiple material consumption entries
|
||||||
if frappe.db.get_single_value("Manufacturing Settings", "material_consumption"):
|
if frappe.db.get_single_value("Manufacturing Settings", "material_consumption", cache=True):
|
||||||
bom_items = self.get_bom_raw_materials(finished_item_qty)
|
bom_items = self.get_bom_raw_materials(finished_item_qty)
|
||||||
outgoing_items_cost = sum([flt(row.qty)*flt(row.rate) for row in bom_items.values()])
|
outgoing_items_cost = sum([flt(row.qty)*flt(row.rate) for row in bom_items.values()])
|
||||||
|
|
||||||
|
@ -178,3 +178,4 @@ def on_doctype_update():
|
|||||||
|
|
||||||
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
|
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
|
||||||
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
|
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
|
||||||
|
frappe.db.add_index("Stock Ledger Entry", ["voucher_detail_no"])
|
||||||
|
@ -6,13 +6,14 @@ import frappe
|
|||||||
import erpnext
|
import erpnext
|
||||||
import copy
|
import copy
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, cstr, now, get_link_to_form
|
from frappe.utils import cint, flt, cstr, now, get_link_to_form, getdate
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
|
from erpnext.stock.utils import get_valuation_method, get_incoming_outgoing_rate_for_cancel
|
||||||
from erpnext.stock.utils import get_bin
|
from erpnext.stock.utils import get_bin
|
||||||
import json
|
import json
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
|
|
||||||
# future reposting
|
# future reposting
|
||||||
class NegativeStockError(frappe.ValidationError): pass
|
class NegativeStockError(frappe.ValidationError): pass
|
||||||
class SerialNoExistsInFutureTransaction(frappe.ValidationError):
|
class SerialNoExistsInFutureTransaction(frappe.ValidationError):
|
||||||
@ -130,7 +131,13 @@ def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negat
|
|||||||
if not args and voucher_type and voucher_no:
|
if not args and voucher_type and voucher_no:
|
||||||
args = get_args_for_voucher(voucher_type, voucher_no)
|
args = get_args_for_voucher(voucher_type, voucher_no)
|
||||||
|
|
||||||
distinct_item_warehouses = [(d.item_code, d.warehouse) for d in args]
|
distinct_item_warehouses = {}
|
||||||
|
for i, d in enumerate(args):
|
||||||
|
distinct_item_warehouses.setdefault((d.item_code, d.warehouse), frappe._dict({
|
||||||
|
"reposting_status": False,
|
||||||
|
"sle": d,
|
||||||
|
"args_idx": i
|
||||||
|
}))
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@ -139,13 +146,21 @@ def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negat
|
|||||||
"warehouse": args[i].warehouse,
|
"warehouse": args[i].warehouse,
|
||||||
"posting_date": args[i].posting_date,
|
"posting_date": args[i].posting_date,
|
||||||
"posting_time": args[i].posting_time,
|
"posting_time": args[i].posting_time,
|
||||||
"creation": args[i].get("creation")
|
"creation": args[i].get("creation"),
|
||||||
|
"distinct_item_warehouses": distinct_item_warehouses
|
||||||
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
|
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
|
||||||
|
|
||||||
for item_wh, new_sle in iteritems(obj.new_items):
|
distinct_item_warehouses[(args[i].item_code, args[i].warehouse)].reposting_status = True
|
||||||
if item_wh not in distinct_item_warehouses:
|
|
||||||
args.append(new_sle)
|
|
||||||
|
|
||||||
|
if obj.new_items_found:
|
||||||
|
for item_wh, data in iteritems(distinct_item_warehouses):
|
||||||
|
if ('args_idx' not in data and not data.reposting_status) or (data.sle_changed and data.reposting_status):
|
||||||
|
data.args_idx = len(args)
|
||||||
|
args.append(data.sle)
|
||||||
|
elif data.sle_changed and not data.reposting_status:
|
||||||
|
args[data.args_idx] = data.sle
|
||||||
|
|
||||||
|
data.sle_changed = False
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
def get_args_for_voucher(voucher_type, voucher_no):
|
def get_args_for_voucher(voucher_type, voucher_no):
|
||||||
@ -186,11 +201,12 @@ class update_entries_after(object):
|
|||||||
self.company = frappe.get_cached_value("Warehouse", self.args.warehouse, "company")
|
self.company = frappe.get_cached_value("Warehouse", self.args.warehouse, "company")
|
||||||
self.get_precision()
|
self.get_precision()
|
||||||
self.valuation_method = get_valuation_method(self.item_code)
|
self.valuation_method = get_valuation_method(self.item_code)
|
||||||
self.new_items = {}
|
|
||||||
|
self.new_items_found = False
|
||||||
|
self.distinct_item_warehouses = args.get("distinct_item_warehouses", frappe._dict())
|
||||||
|
|
||||||
self.data = frappe._dict()
|
self.data = frappe._dict()
|
||||||
self.initialize_previous_data(self.args)
|
self.initialize_previous_data(self.args)
|
||||||
|
|
||||||
self.build()
|
self.build()
|
||||||
|
|
||||||
def get_precision(self):
|
def get_precision(self):
|
||||||
@ -296,11 +312,29 @@ class update_entries_after(object):
|
|||||||
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
|
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
|
||||||
return entries_to_fix
|
return entries_to_fix
|
||||||
elif dependant_sle.item_code != self.item_code:
|
elif dependant_sle.item_code != self.item_code:
|
||||||
if (dependant_sle.item_code, dependant_sle.warehouse) not in self.new_items:
|
self.update_distinct_item_warehouses(dependant_sle)
|
||||||
self.new_items[(dependant_sle.item_code, dependant_sle.warehouse)] = dependant_sle
|
|
||||||
return entries_to_fix
|
return entries_to_fix
|
||||||
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse in self.data:
|
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse in self.data:
|
||||||
return entries_to_fix
|
return entries_to_fix
|
||||||
|
else:
|
||||||
|
return self.append_future_sle_for_dependant(dependant_sle, entries_to_fix)
|
||||||
|
|
||||||
|
def update_distinct_item_warehouses(self, dependant_sle):
|
||||||
|
key = (dependant_sle.item_code, dependant_sle.warehouse)
|
||||||
|
val = frappe._dict({
|
||||||
|
"sle": dependant_sle
|
||||||
|
})
|
||||||
|
if key not in self.distinct_item_warehouses:
|
||||||
|
self.distinct_item_warehouses[key] = val
|
||||||
|
self.new_items_found = True
|
||||||
|
else:
|
||||||
|
existing_sle_posting_date = self.distinct_item_warehouses[key].get("sle", {}).get("posting_date")
|
||||||
|
if getdate(dependant_sle.posting_date) < getdate(existing_sle_posting_date):
|
||||||
|
val.sle_changed = True
|
||||||
|
self.distinct_item_warehouses[key] = val
|
||||||
|
self.new_items_found = True
|
||||||
|
|
||||||
|
def append_future_sle_for_dependant(self, dependant_sle, entries_to_fix):
|
||||||
self.initialize_previous_data(dependant_sle)
|
self.initialize_previous_data(dependant_sle)
|
||||||
|
|
||||||
args = self.data[dependant_sle.warehouse].previous_sle \
|
args = self.data[dependant_sle.warehouse].previous_sle \
|
||||||
@ -393,6 +427,7 @@ class update_entries_after(object):
|
|||||||
rate = 0
|
rate = 0
|
||||||
# Material Transfer, Repack, Manufacturing
|
# Material Transfer, Repack, Manufacturing
|
||||||
if sle.voucher_type == "Stock Entry":
|
if sle.voucher_type == "Stock Entry":
|
||||||
|
self.recalculate_amounts_in_stock_entry(sle.voucher_no)
|
||||||
rate = frappe.db.get_value("Stock Entry Detail", sle.voucher_detail_no, "valuation_rate")
|
rate = frappe.db.get_value("Stock Entry Detail", sle.voucher_detail_no, "valuation_rate")
|
||||||
# Sales and Purchase Return
|
# Sales and Purchase Return
|
||||||
elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
|
elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
|
||||||
@ -442,7 +477,11 @@ class update_entries_after(object):
|
|||||||
frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
|
frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
|
||||||
|
|
||||||
# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
|
# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
|
||||||
stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no, for_update=True)
|
if not sle.dependant_sle_voucher_detail_no:
|
||||||
|
self.recalculate_amounts_in_stock_entry(sle.voucher_no)
|
||||||
|
|
||||||
|
def recalculate_amounts_in_stock_entry(self, voucher_no):
|
||||||
|
stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True)
|
||||||
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
|
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
|
||||||
stock_entry.db_update()
|
stock_entry.db_update()
|
||||||
for d in stock_entry.items:
|
for d in stock_entry.items:
|
||||||
|
Loading…
Reference in New Issue
Block a user