mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 05:39:12 +00:00
Guess valuation rate in case of negative stock
This commit is contained in:
@@ -269,7 +269,7 @@ class BuyingController(StockController):
|
|||||||
# get raw materials rate
|
# get raw materials rate
|
||||||
if self.doctype == "Purchase Receipt":
|
if self.doctype == "Purchase Receipt":
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
item_rate = get_incoming_rate({
|
rm.rate = get_incoming_rate({
|
||||||
"item_code": bom_item.item_code,
|
"item_code": bom_item.item_code,
|
||||||
"warehouse": self.supplier_warehouse,
|
"warehouse": self.supplier_warehouse,
|
||||||
"posting_date": self.posting_date,
|
"posting_date": self.posting_date,
|
||||||
@@ -277,10 +277,9 @@ class BuyingController(StockController):
|
|||||||
"qty": -1 * required_qty,
|
"qty": -1 * required_qty,
|
||||||
"serial_no": rm.serial_no
|
"serial_no": rm.serial_no
|
||||||
})
|
})
|
||||||
if not item_rate:
|
if not rm.rate:
|
||||||
from erpnext.controllers.stock_controller import get_valuation_rate
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
item_rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse)
|
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse)
|
||||||
rm.rate = item_rate or bom_item.rate
|
|
||||||
else:
|
else:
|
||||||
rm.rate = bom_item.rate
|
rm.rate = bom_item.rate
|
||||||
|
|
||||||
|
|||||||
@@ -49,17 +49,12 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
self.check_expense_account(detail)
|
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({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[sle.warehouse],
|
"account": warehouse_account[sle.warehouse],
|
||||||
"against": detail.expense_account,
|
"against": detail.expense_account,
|
||||||
"cost_center": detail.cost_center,
|
"cost_center": detail.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"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
|
# to target warehouse / expense account
|
||||||
@@ -68,7 +63,7 @@ class StockController(AccountsController):
|
|||||||
"against": warehouse_account[sle.warehouse],
|
"against": warehouse_account[sle.warehouse],
|
||||||
"cost_center": detail.cost_center,
|
"cost_center": detail.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"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:
|
elif sle.warehouse not in warehouse_with_no_account:
|
||||||
warehouse_with_no_account.append(sle.warehouse)
|
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.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")):
|
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"))
|
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
|
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ from frappe.model.document import Document
|
|||||||
class StockSettings(Document):
|
class StockSettings(Document):
|
||||||
|
|
||||||
def validate(self):
|
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"]:
|
for key in ["item_naming_by", "item_group", "stock_uom", "allow_negative_stock"]:
|
||||||
frappe.db.set_default(key, self.get(key, ""))
|
frappe.db.set_default(key, self.get(key, ""))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, cstr, now
|
from frappe.utils import cint, flt, cstr, now
|
||||||
from erpnext.stock.utils import get_valuation_method
|
from erpnext.stock.utils import get_valuation_method
|
||||||
from erpnext.controllers.stock_controller import get_valuation_rate
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
# future reposting
|
# future reposting
|
||||||
@@ -266,7 +265,7 @@ def get_moving_average_values(qty_after_transaction, sle, valuation_rate):
|
|||||||
|
|
||||||
if new_stock_qty:
|
if new_stock_qty:
|
||||||
valuation_rate = new_stock_value / flt(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)
|
valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse)
|
||||||
|
|
||||||
return abs(flt(valuation_rate))
|
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)
|
incoming_rate = flt(sle.incoming_rate)
|
||||||
actual_qty = flt(sle.actual_qty)
|
actual_qty = flt(sle.actual_qty)
|
||||||
|
|
||||||
intialize_stock_queue(stock_queue, sle.item_code, sle.warehouse, actual_qty)
|
|
||||||
|
|
||||||
if actual_qty > 0:
|
if actual_qty > 0:
|
||||||
|
if not stock_queue:
|
||||||
|
stock_queue.append([0, 0])
|
||||||
|
|
||||||
if stock_queue[-1][0] > 0:
|
if stock_queue[-1][0] > 0:
|
||||||
stock_queue.append([actual_qty, incoming_rate])
|
stock_queue.append([actual_qty, incoming_rate])
|
||||||
else:
|
else:
|
||||||
@@ -289,12 +289,12 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
|
|||||||
else:
|
else:
|
||||||
qty_to_pop = abs(actual_qty)
|
qty_to_pop = abs(actual_qty)
|
||||||
while qty_to_pop:
|
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]
|
batch = stock_queue[0]
|
||||||
|
|
||||||
# print qty_to_pop, batch
|
|
||||||
|
|
||||||
if qty_to_pop >= batch[0]:
|
if qty_to_pop >= batch[0]:
|
||||||
# consume current batch
|
# consume current batch
|
||||||
qty_to_pop = qty_to_pop - batch[0]
|
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)
|
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):
|
def _raise_exceptions(args, verbose=1):
|
||||||
deficiency = min(e["diff"] for e in _exceptions)
|
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"],
|
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)"],
|
"timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"],
|
||||||
"desc", "limit 1", for_update=for_update)
|
"desc", "limit 1", for_update=for_update)
|
||||||
return sle and sle[0] or {}
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user