From 7beffe47ea9b8c6954248932c150f01749067e45 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 2 Oct 2021 22:56:46 +0530 Subject: [PATCH 1/8] fix: Add indexes in stock queries --- erpnext/controllers/stock_controller.py | 2 +- .../stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 1 + erpnext/stock/stock_ledger.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 78a6e52e4d7f..4697205d72df 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -591,7 +591,7 @@ def future_sle_exists(args, sl_entries=None): data = frappe.db.sql(""" select item_code, warehouse, count(name) as total_row - from `tabStock Ledger Entry` + from `tabStock Ledger Entry` force index (item_warehouse) where ({}) and timestamp(posting_date, posting_time) 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 caa1d42b6620..e7b61b0639f4 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -182,3 +182,4 @@ def on_doctype_update(): 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", ["voucher_detail_no"]) + frappe.db.add_index("Stock Ledger Entry", ["item_code", "warehouse"], "item_warehouse") diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 1b5b792f9463..ae7b5388e909 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -918,7 +918,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, company = erpnext.get_default_company() last_valuation_rate = frappe.db.sql("""select valuation_rate - from `tabStock Ledger Entry` + from `tabStock Ledger Entry` force index (item_warehouse) where item_code = %s AND warehouse = %s @@ -929,7 +929,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, if not last_valuation_rate: # Get valuation rate from last sle for the item against any warehouse last_valuation_rate = frappe.db.sql("""select valuation_rate - from `tabStock Ledger Entry` + from `tabStock Ledger Entry` force index (item_code) where item_code = %s AND valuation_rate > 0 From 1adc634bca1f436374507ad8873a4d6288cbceae Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 3 Oct 2021 18:46:39 +0530 Subject: [PATCH 2/8] fix: Optimization on Bin updation --- erpnext/stock/doctype/bin/bin.py | 108 ++++++++++++++++++------------- erpnext/stock/stock_ledger.py | 9 ++- erpnext/stock/utils.py | 21 +++++- 3 files changed, 85 insertions(+), 53 deletions(-) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 5fbc2d8dee1f..d4ef00a6e53c 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -14,51 +14,6 @@ def before_save(self): self.stock_uom = frappe.get_cached_value('Item', self.item_code, 'stock_uom') self.set_projected_qty() - def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False): - '''Called from erpnext.stock.utils.update_bin''' - self.update_qty(args) - - if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation": - from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle - - if not args.get("posting_date"): - args["posting_date"] = nowdate() - - if args.get("is_cancelled") and via_landed_cost_voucher: - return - - # Reposts only current voucher SL Entries - # Updates valuation rate, stock value, stock queue for current transaction - update_entries_after({ - "item_code": self.item_code, - "warehouse": self.warehouse, - "posting_date": args.get("posting_date"), - "posting_time": args.get("posting_time"), - "voucher_type": args.get("voucher_type"), - "voucher_no": args.get("voucher_no"), - "sle_id": args.name, - "creation": args.creation - }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher) - - # update qty in future ale and Validate negative qty - update_qty_in_future_sle(args, allow_negative_stock) - - - def update_qty(self, args): - # update the stock values (for current quantities) - if args.get("voucher_type")=="Stock Reconciliation": - self.actual_qty = args.get("qty_after_transaction") - else: - self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty")) - - self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty")) - self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty")) - self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty")) - self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty")) - - self.set_projected_qty() - self.db_update() - def set_projected_qty(self): self.projected_qty = (flt(self.actual_qty) + flt(self.ordered_qty) + flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) @@ -143,3 +98,66 @@ def update_reserved_qty_for_sub_contracting(self): def on_doctype_update(): frappe.db.add_index("Bin", ["item_code", "warehouse"]) + + +def update_stock(bin, args, allow_negative_stock=False, via_landed_cost_voucher=False): + '''Called from erpnext.stock.utils.update_bin''' + # self.update_qty(args) + + if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation": + from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle + + if not args.get("posting_date"): + args["posting_date"] = nowdate() + + if args.get("is_cancelled") and via_landed_cost_voucher: + return + + # Reposts only current voucher SL Entries + # Updates valuation rate, stock value, stock queue for current transaction + update_entries_after({ + "item_code": args.get('item_code'), + "warehouse": args.get('warehouse'), + "posting_date": args.get("posting_date"), + "posting_time": args.get("posting_time"), + "voucher_type": args.get("voucher_type"), + "voucher_no": args.get("voucher_no"), + "sle_id": args.get('name'), + "creation": args.get('creation') + }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher) + + # update qty in future sle and Validate negative qty + update_qty_in_future_sle(args, allow_negative_stock) + +def update_qty(bin_name, args): + bin_details = frappe.db.get_value('Bin', bin_name, ['actual_qty', 'ordered_qty', + 'reserved_qty', 'indented_qty', 'planned_qty', 'reserved_qty_for_production', + 'reserved_qty_for_sub_contract'], as_dict=1) + + # update the stock values (for current quantities) + if args.get("voucher_type")=="Stock Reconciliation": + actual_qty = args.get('qty_after_transaction') + # self.actual_qty = args.get("qty_after_transaction") + else: + actual_qty = bin_details.actual_qty + args.get('qty_after_transaction') + # self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty")) + + ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty")) + reserved_qty = flt(bin_details.reserved_qty) + flt(args.get("reserved_qty")) + indented_qty = flt(bin_details.indented_qty) + flt(args.get("indented_qty")) + planned_qty = flt(bin_details.planned_qty) + flt(args.get("planned_qty")) + + + # compute projected qty + projected_qty = (flt(actual_qty) + flt(ordered_qty) + + flt(indented_qty) + flt(planned_qty) - flt(reserved_qty) + - flt(bin_details.reserved_qty_for_production) - flt(bin_details.reserved_qty_for_sub_contract)) + + frappe.db.set_value('Bin', bin_name, { + 'actual_qty': actual_qty, + 'ordered_qty': ordered_qty, + 'reserved_qty': reserved_qty, + 'indented_qty': indented_qty, + 'planned_qty': planned_qty, + 'projected_qty': projected_qty + }) \ No newline at end of file diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index ae7b5388e909..e9d5b6ae0912 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -13,8 +13,8 @@ import erpnext from erpnext.stock.utils import ( - get_bin, get_incoming_outgoing_rate_for_cancel, + get_or_make_bin, get_valuation_method, ) @@ -805,14 +805,13 @@ def raise_exceptions(self): def update_bin(self): # update bin for each warehouse for warehouse, data in iteritems(self.data): - bin_doc = get_bin(self.item_code, warehouse) - bin_doc.update({ + bin_record = get_or_make_bin(self.item_code, warehouse) + + frappe.db.set_value('Bin', bin_record, { "valuation_rate": data.valuation_rate, "actual_qty": data.qty_after_transaction, "stock_value": data.stock_value }) - bin_doc.flags.via_stock_ledger_entry = True - bin_doc.save(ignore_permissions=True) def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False): diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index aeb06e987f8a..ece4edbf8879 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -180,12 +180,27 @@ def get_bin(item_code, warehouse): bin_obj.flags.ignore_permissions = True return bin_obj +def get_or_make_bin(item_code, warehouse): + bin_record = frappe.db.get_value('Bin', {'item_code': item_code, 'warehouse': warehouse}) + + if not bin_record: + bin_obj = frappe.get_doc({ + "doctype": "Bin", + "item_code": item_code, + "warehouse": warehouse, + }) + bin_obj.flags.ignore_permissions = 1 + bin_obj.insert() + bin_record = bin_obj.name + + return bin_record + def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False): + from erpnext.stock.doctype.bin.bin import update_stock is_stock_item = frappe.get_cached_value('Item', args.get("item_code"), 'is_stock_item') if is_stock_item: - bin = get_bin(args.get("item_code"), args.get("warehouse")) - bin.update_stock(args, allow_negative_stock, via_landed_cost_voucher) - return bin + bin_record = get_or_make_bin(args.get("item_code"), args.get("warehouse")) + update_stock(bin_record, args, allow_negative_stock, via_landed_cost_voucher) else: frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code"))) From d111edb528103cb419a1064ead7c87fed2d29c96 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 8 Oct 2021 18:48:48 +0530 Subject: [PATCH 3/8] fix: Remove unwanted comments --- erpnext/stock/doctype/bin/bin.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index d4ef00a6e53c..e7b08fbe8eb1 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -55,6 +55,7 @@ def update_reserved_qty_for_production(self): self.db_set('projected_qty', self.projected_qty) def update_reserved_qty_for_sub_contracting(self): + print("Inininiinin") #reserved qty reserved_qty_for_sub_contract = frappe.db.sql(''' select ifnull(sum(itemsup.required_qty),0) @@ -100,9 +101,9 @@ def on_doctype_update(): frappe.db.add_index("Bin", ["item_code", "warehouse"]) -def update_stock(bin, args, allow_negative_stock=False, via_landed_cost_voucher=False): +def update_stock(bin_name, args, allow_negative_stock=False, via_landed_cost_voucher=False): '''Called from erpnext.stock.utils.update_bin''' - # self.update_qty(args) + update_qty(bin_name, args) if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation": from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle @@ -137,10 +138,8 @@ def update_qty(bin_name, args): # update the stock values (for current quantities) if args.get("voucher_type")=="Stock Reconciliation": actual_qty = args.get('qty_after_transaction') - # self.actual_qty = args.get("qty_after_transaction") else: actual_qty = bin_details.actual_qty + args.get('qty_after_transaction') - # self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty")) ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty")) reserved_qty = flt(bin_details.reserved_qty) + flt(args.get("reserved_qty")) From 1b7aa5b48b889c1f09a5d1753b1aab7b1dd6a111 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 8 Oct 2021 18:53:18 +0530 Subject: [PATCH 4/8] fix: Remove print statements --- erpnext/stock/doctype/bin/bin.py | 1 - .../stock/doctype/stock_ledger_entry/stock_ledger_entry.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index e7b08fbe8eb1..6e97c7da0d56 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -55,7 +55,6 @@ def update_reserved_qty_for_production(self): self.db_set('projected_qty', self.projected_qty) def update_reserved_qty_for_sub_contracting(self): - print("Inininiinin") #reserved qty reserved_qty_for_sub_contract = frappe.db.sql(''' select ifnull(sum(itemsup.required_qty),0) diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json index 40ae340bfea3..2651407d16f0 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json @@ -317,7 +317,7 @@ "in_create": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-10-08 12:42:51.857631", + "modified": "2021-10-08 13:42:51.857631", "modified_by": "Administrator", "module": "Stock", "name": "Stock Ledger Entry", From 51b12fd891a01d43dc4161da7601427fd5b73bf1 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 10 Oct 2021 21:25:22 +0530 Subject: [PATCH 5/8] fix: Incorrect actual qty updation --- erpnext/stock/doctype/bin/bin.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 6e97c7da0d56..4be0415564d9 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -129,16 +129,19 @@ def update_stock(bin_name, args, allow_negative_stock=False, via_landed_cost_vou # update qty in future sle and Validate negative qty update_qty_in_future_sle(args, allow_negative_stock) +def get_bin_details(bin_name): + return frappe.db.get_value('Bin', bin_name, ['actual_qty', 'ordered_qty', + 'reserved_qty', 'indented_qty', 'planned_qty', 'reserved_qty_for_production', + 'reserved_qty_for_sub_contract'], as_dict=1) + def update_qty(bin_name, args): - bin_details = frappe.db.get_value('Bin', bin_name, ['actual_qty', 'ordered_qty', - 'reserved_qty', 'indented_qty', 'planned_qty', 'reserved_qty_for_production', - 'reserved_qty_for_sub_contract'], as_dict=1) + bin_details = get_bin_details(bin_name) # update the stock values (for current quantities) if args.get("voucher_type")=="Stock Reconciliation": actual_qty = args.get('qty_after_transaction') else: - actual_qty = bin_details.actual_qty + args.get('qty_after_transaction') + actual_qty = bin_details.actual_qty + flt(args.get("actual_qty")) ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty")) reserved_qty = flt(bin_details.reserved_qty) + flt(args.get("reserved_qty")) From 6fef5abe1e91c263921e66aa12dcb96dc6a9e8a7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 11 Oct 2021 12:42:31 +0530 Subject: [PATCH 6/8] chore: remove duplicate index --- erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 1 - 1 file changed, 1 deletion(-) 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 e7b61b0639f4..90b5f2da5e64 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -181,5 +181,4 @@ def on_doctype_update(): 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", ["voucher_detail_no"]) frappe.db.add_index("Stock Ledger Entry", ["item_code", "warehouse"], "item_warehouse") From db8b76acecea31f705c9053ff6f2edbbe57d64ec Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:57:40 +0530 Subject: [PATCH 7/8] fix: Add return type Co-authored-by: Ankush Menat --- erpnext/stock/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index ece4edbf8879..c4a0497b7447 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -180,7 +180,7 @@ def get_bin(item_code, warehouse): bin_obj.flags.ignore_permissions = True return bin_obj -def get_or_make_bin(item_code, warehouse): +def get_or_make_bin(item_code, warehouse) -> str: bin_record = frappe.db.get_value('Bin', {'item_code': item_code, 'warehouse': warehouse}) if not bin_record: From 3563d8e62a72047aed375e80f239c5046b8fbef0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 11 Oct 2021 16:22:50 +0530 Subject: [PATCH 8/8] fix: Use warehouse as the first index column Co-authored-by: Ankush Menat --- erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 90b5f2da5e64..2cf71accf832 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -181,4 +181,4 @@ def on_doctype_update(): 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", ["item_code", "warehouse"], "item_warehouse") + frappe.db.add_index("Stock Ledger Entry", ["warehouse", "item_code"], "item_warehouse")