Block negative stock in perpetual inventory

This commit is contained in:
Nabin Hait
2014-10-06 11:53:52 +05:30
parent bb19b91ef9
commit adeb976a1b
7 changed files with 63 additions and 29 deletions

View File

@@ -8,10 +8,10 @@ from frappe import msgprint, _
import frappe.defaults
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
class StockController(AccountsController):
def make_gl_entries(self, repost_future_gle=True):
def make_gl_entries(self, repost_future_gle=True, allow_negative_stock=False):
if self.docstatus == 2:
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
@@ -19,16 +19,19 @@ class StockController(AccountsController):
warehouse_account = get_warehouse_account()
if self.docstatus==1:
gl_entries = self.get_gl_entries(warehouse_account)
gl_entries = self.get_gl_entries(warehouse_account, allow_negative_stock)
make_gl_entries(gl_entries)
if repost_future_gle:
items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items, warehouse_account)
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
warehouse_account, allow_negative_stock)
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
default_cost_center=None):
from erpnext.accounts.general_ledger import process_gl_map
default_cost_center=None, allow_negative_stock=False):
block_negative_stock(allow_negative_stock)
if not warehouse_account:
warehouse_account = get_warehouse_account()
@@ -46,12 +49,17 @@ 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, sle.posting_date)
stock_value_difference = flt(sle.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": flt(sle.stock_value_difference, 2)
"debit": stock_value_difference
}))
# to target warehouse / expense account
@@ -60,7 +68,7 @@ class StockController(AccountsController):
"against": warehouse_account[sle.warehouse],
"cost_center": detail.cost_center,
"remarks": self.get("remarks") or "Accounting Entry for Stock",
"credit": flt(sle.stock_value_difference, 2)
"credit": stock_value_difference
}))
elif sle.warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(sle.warehouse)
@@ -214,7 +222,8 @@ class StockController(AccountsController):
return serialized_items
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, warehouse_account=None):
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None, allow_negative_stock=False):
def _delete_gl_entries(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
@@ -228,12 +237,12 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for
for voucher_type, voucher_no in future_stock_vouchers:
existing_gle = gle.get((voucher_type, voucher_no), [])
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
expected_gle = voucher_obj.get_gl_entries(warehouse_account, allow_negative_stock)
if expected_gle:
if not existing_gle or not compare_existing_and_expected_gle(existing_gle,
expected_gle):
_delete_gl_entries(voucher_type, voucher_no)
voucher_obj.make_gl_entries(repost_future_gle=False)
voucher_obj.make_gl_entries(repost_future_gle=False, allow_negative_stock=allow_negative_stock)
else:
_delete_gl_entries(voucher_type, voucher_no)
@@ -285,3 +294,22 @@ def get_warehouse_account():
warehouse_account = dict(frappe.db.sql("""select master_name, name from tabAccount
where account_type = 'Warehouse' and ifnull(master_name, '') != ''"""))
return warehouse_account
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, posting_date):
last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry`
where item_code = %s and warehouse = %s
and ifnull(qty_after_transaction, 0) > 0 and posting_date < %s
order by posting_date desc limit 1""", (item_code, warehouse, posting_date))
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")
return valuation_rate