diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index cf57658342..fc912c9f1b 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -269,7 +269,7 @@ class BuyingController(StockController): # get raw materials rate if self.doctype == "Purchase Receipt": from erpnext.stock.utils import get_incoming_rate - item_rate = get_incoming_rate({ + rm.rate = get_incoming_rate({ "item_code": bom_item.item_code, "warehouse": self.supplier_warehouse, "posting_date": self.posting_date, @@ -277,10 +277,9 @@ class BuyingController(StockController): "qty": -1 * required_qty, "serial_no": rm.serial_no }) - if not item_rate: - from erpnext.controllers.stock_controller import get_valuation_rate - item_rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse) - rm.rate = item_rate or bom_item.rate + if not rm.rate: + from erpnext.stock.stock_ledger import get_valuation_rate + rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse) else: rm.rate = bom_item.rate diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index a72a3d09fb..d7c7a43568 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -49,17 +49,12 @@ class StockController(AccountsController): self.check_expense_account(detail) - stock_value_difference = flt(sle.stock_value_difference, 2) - if not stock_value_difference: - valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse) - stock_value_difference = flt(sle.actual_qty)*flt(valuation_rate) - gl_list.append(self.get_gl_dict({ "account": warehouse_account[sle.warehouse], "against": detail.expense_account, "cost_center": detail.cost_center, "remarks": self.get("remarks") or "Accounting Entry for Stock", - "debit": stock_value_difference + "debit": flt(sle.stock_value_difference, 2) })) # to target warehouse / expense account @@ -68,7 +63,7 @@ class StockController(AccountsController): "against": warehouse_account[sle.warehouse], "cost_center": detail.cost_center, "remarks": self.get("remarks") or "Accounting Entry for Stock", - "credit": stock_value_difference + "credit": flt(sle.stock_value_difference, 2) })) elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) @@ -300,26 +295,3 @@ def block_negative_stock(allow_negative_stock=False): if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) and not allow_negative_stock: if cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")): frappe.throw(_("Negative stock is not allowed in case of Perpetual Inventory, please disable it from Stock Settings")) - -def get_valuation_rate(item_code, warehouse): - last_valuation_rate = frappe.db.sql("""select valuation_rate - from `tabStock Ledger Entry` - where item_code = %s and warehouse = %s - and ifnull(valuation_rate, 0) > 0 - order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse)) - - if not last_valuation_rate: - last_valuation_rate = frappe.db.sql("""select valuation_rate - from `tabStock Ledger Entry` - where item_code = %s and ifnull(valuation_rate, 0) > 0 - order by posting_date desc, posting_time desc, name desc limit 1""", item_code) - - valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0 - - if not valuation_rate: - valuation_rate = frappe.db.get_value("Item Price", {"item_code": item_code, "buying": 1}, "price_list_rate") - - if not valuation_rate: - frappe.throw(_("Purchase rate for item: {0} not found, which is required to book accounting entry. Please mention item price against a buying price list.").format(item_code)) - - return valuation_rate diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index 95ace86b79..12ab0c98a1 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -12,9 +12,6 @@ from frappe.model.document import Document class StockSettings(Document): def validate(self): - if cint(self.allow_negative_stock) and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): - frappe.throw(_("Negative stock is not allowed in case of Perpetual Inventory")) - for key in ["item_naming_by", "item_group", "stock_uom", "allow_negative_stock"]: frappe.db.set_default(key, self.get(key, "")) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 7dc8d837bb..0fbf6a8652 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -6,7 +6,6 @@ import frappe from frappe import _ from frappe.utils import cint, flt, cstr, now from erpnext.stock.utils import get_valuation_method -from erpnext.controllers.stock_controller import get_valuation_rate import json # future reposting @@ -266,7 +265,7 @@ def get_moving_average_values(qty_after_transaction, sle, valuation_rate): if new_stock_qty: valuation_rate = new_stock_value / flt(new_stock_qty) - elif not valuation_rate: + elif not valuation_rate and qty_after_transaction <= 0: valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse) return abs(flt(valuation_rate)) @@ -275,9 +274,10 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue): incoming_rate = flt(sle.incoming_rate) actual_qty = flt(sle.actual_qty) - intialize_stock_queue(stock_queue, sle.item_code, sle.warehouse, actual_qty) - if actual_qty > 0: + if not stock_queue: + stock_queue.append([0, 0]) + if stock_queue[-1][0] > 0: stock_queue.append([actual_qty, incoming_rate]) else: @@ -289,12 +289,12 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue): else: qty_to_pop = abs(actual_qty) while qty_to_pop: - intialize_stock_queue(stock_queue, sle.item_code, sle.warehouse, actual_qty) + if not stock_queue: + stock_queue.append([0, get_valuation_rate(sle.item_code, sle.warehouse) + if qty_after_transaction <= 0 else 0]) batch = stock_queue[0] - # print qty_to_pop, batch - if qty_to_pop >= batch[0]: # consume current batch qty_to_pop = qty_to_pop - batch[0] @@ -318,11 +318,6 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue): return abs(valuation_rate) -def intialize_stock_queue(stock_queue, item_code, warehouse, actual_qty): - if not stock_queue: - estimated_val_rate = get_valuation_rate(item_code, warehouse) if actual_qty < 0 else 0 - stock_queue.append([0, estimated_val_rate]) - def _raise_exceptions(args, verbose=1): deficiency = min(e["diff"] for e in _exceptions) msg = _("Negative Stock Error ({6}) for Item {0} in Warehouse {1} on {2} {3} in {4} {5}").format(args["item_code"], @@ -353,3 +348,26 @@ def get_previous_sle(args, for_update=False): "timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"], "desc", "limit 1", for_update=for_update) return sle and sle[0] or {} + +def get_valuation_rate(item_code, warehouse): + last_valuation_rate = frappe.db.sql("""select valuation_rate + from `tabStock Ledger Entry` + where item_code = %s and warehouse = %s + and ifnull(valuation_rate, 0) > 0 + order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse)) + + if not last_valuation_rate: + last_valuation_rate = frappe.db.sql("""select valuation_rate + from `tabStock Ledger Entry` + where item_code = %s and ifnull(valuation_rate, 0) > 0 + order by posting_date desc, posting_time desc, name desc limit 1""", item_code) + + valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0 + + if not valuation_rate: + valuation_rate = frappe.db.get_value("Item Price", {"item_code": item_code, "buying": 1}, "price_list_rate") + + if not valuation_rate and cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")): + frappe.throw(_("Purchase rate for item: {0} not found, which is required to book accounting entry (expense). Please mention item price against a buying price list.").format(item_code)) + + return valuation_rate