Allow zero rate while reposting
This commit is contained in:
parent
fb6e434315
commit
f1a07ff105
@ -7,7 +7,7 @@ import frappe.defaults
|
|||||||
from frappe.utils import cint, cstr, flt
|
from frappe.utils import cint, cstr, flt
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
from erpnext.accounts.party import get_party_account, get_due_date
|
from erpnext.accounts.party import get_party_account, get_due_date
|
||||||
from erpnext.controllers.stock_controller import update_gl_entries_after, block_negative_stock
|
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
from erpnext.controllers.selling_controller import SellingController
|
from erpnext.controllers.selling_controller import SellingController
|
||||||
@ -456,8 +456,8 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
self.make_sl_entries(sl_entries)
|
self.make_sl_entries(sl_entries)
|
||||||
|
|
||||||
def make_gl_entries(self, repost_future_gle=True, allow_negative_stock=False):
|
def make_gl_entries(self, repost_future_gle=True):
|
||||||
gl_entries = self.get_gl_entries(allow_negative_stock=allow_negative_stock)
|
gl_entries = self.get_gl_entries()
|
||||||
|
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
@ -476,7 +476,7 @@ class SalesInvoice(SellingController):
|
|||||||
items, warehouses = self.get_items_and_warehouses()
|
items, warehouses = self.get_items_and_warehouses()
|
||||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
|
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, allow_negative_stock=False):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
from erpnext.accounts.general_ledger import merge_similar_entries
|
from erpnext.accounts.general_ledger import merge_similar_entries
|
||||||
|
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
@ -485,7 +485,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
self.make_tax_gl_entries(gl_entries)
|
self.make_tax_gl_entries(gl_entries)
|
||||||
|
|
||||||
self.make_item_gl_entries(gl_entries, allow_negative_stock)
|
self.make_item_gl_entries(gl_entries)
|
||||||
|
|
||||||
# merge gl entries before adding pos entries
|
# merge gl entries before adding pos entries
|
||||||
gl_entries = merge_similar_entries(gl_entries)
|
gl_entries = merge_similar_entries(gl_entries)
|
||||||
@ -520,7 +520,7 @@ class SalesInvoice(SellingController):
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_item_gl_entries(self, gl_entries, allow_negative_stock=False):
|
def make_item_gl_entries(self, gl_entries):
|
||||||
# income account gl entries
|
# income account gl entries
|
||||||
for item in self.get("entries"):
|
for item in self.get("entries"):
|
||||||
if flt(item.base_amount):
|
if flt(item.base_amount):
|
||||||
@ -537,7 +537,7 @@ class SalesInvoice(SellingController):
|
|||||||
# expense account gl entries
|
# expense account gl entries
|
||||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
||||||
and cint(self.update_stock):
|
and cint(self.update_stock):
|
||||||
gl_entries += super(SalesInvoice, self).get_gl_entries(allow_negative_stock=allow_negative_stock)
|
gl_entries += super(SalesInvoice, self).get_gl_entries()
|
||||||
|
|
||||||
def make_pos_gl_entries(self, gl_entries):
|
def make_pos_gl_entries(self, gl_entries):
|
||||||
if cint(self.is_pos) and self.cash_bank_account and self.paid_amount:
|
if cint(self.is_pos) and self.cash_bank_account and self.paid_amount:
|
||||||
|
@ -11,7 +11,7 @@ from erpnext.controllers.accounts_controller import AccountsController
|
|||||||
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
||||||
|
|
||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def make_gl_entries(self, repost_future_gle=True, allow_negative_stock=False):
|
def make_gl_entries(self, repost_future_gle=True):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
@ -19,18 +19,16 @@ class StockController(AccountsController):
|
|||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account()
|
||||||
|
|
||||||
if self.docstatus==1:
|
if self.docstatus==1:
|
||||||
gl_entries = self.get_gl_entries(warehouse_account, allow_negative_stock=allow_negative_stock)
|
gl_entries = self.get_gl_entries(warehouse_account)
|
||||||
make_gl_entries(gl_entries)
|
make_gl_entries(gl_entries)
|
||||||
|
|
||||||
if repost_future_gle:
|
if repost_future_gle:
|
||||||
items, warehouses = self.get_items_and_warehouses()
|
items, warehouses = self.get_items_and_warehouses()
|
||||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
|
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
|
||||||
warehouse_account, allow_negative_stock)
|
warehouse_account)
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
||||||
default_cost_center=None, allow_negative_stock=False):
|
default_cost_center=None):
|
||||||
|
|
||||||
# block_negative_stock(allow_negative_stock)
|
|
||||||
|
|
||||||
if not warehouse_account:
|
if not warehouse_account:
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account()
|
||||||
@ -219,7 +217,7 @@ class StockController(AccountsController):
|
|||||||
return serialized_items
|
return serialized_items
|
||||||
|
|
||||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||||
warehouse_account=None, allow_negative_stock=False):
|
warehouse_account=None):
|
||||||
def _delete_gl_entries(voucher_type, voucher_no):
|
def _delete_gl_entries(voucher_type, voucher_no):
|
||||||
frappe.db.sql("""delete from `tabGL Entry`
|
frappe.db.sql("""delete from `tabGL Entry`
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
@ -233,12 +231,12 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for
|
|||||||
for voucher_type, voucher_no in future_stock_vouchers:
|
for voucher_type, voucher_no in future_stock_vouchers:
|
||||||
existing_gle = gle.get((voucher_type, voucher_no), [])
|
existing_gle = gle.get((voucher_type, voucher_no), [])
|
||||||
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
||||||
expected_gle = voucher_obj.get_gl_entries(warehouse_account, allow_negative_stock=allow_negative_stock)
|
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
||||||
if expected_gle:
|
if expected_gle:
|
||||||
if not existing_gle or not compare_existing_and_expected_gle(existing_gle,
|
if not existing_gle or not compare_existing_and_expected_gle(existing_gle,
|
||||||
expected_gle):
|
expected_gle):
|
||||||
_delete_gl_entries(voucher_type, voucher_no)
|
_delete_gl_entries(voucher_type, voucher_no)
|
||||||
voucher_obj.make_gl_entries(repost_future_gle=False, allow_negative_stock=allow_negative_stock)
|
voucher_obj.make_gl_entries(repost_future_gle=False)
|
||||||
else:
|
else:
|
||||||
_delete_gl_entries(voucher_type, voucher_no)
|
_delete_gl_entries(voucher_type, voucher_no)
|
||||||
|
|
||||||
@ -290,8 +288,3 @@ def get_warehouse_account():
|
|||||||
warehouse_account = dict(frappe.db.sql("""select master_name, name from tabAccount
|
warehouse_account = dict(frappe.db.sql("""select master_name, name from tabAccount
|
||||||
where account_type = 'Warehouse' and ifnull(master_name, '') != ''"""))
|
where account_type = 'Warehouse' and ifnull(master_name, '') != ''"""))
|
||||||
return warehouse_account
|
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"))
|
|
||||||
|
@ -7,7 +7,7 @@ from frappe.utils import flt
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
from erpnext.utilities.repost_stock import repost
|
from erpnext.utilities.repost_stock import repost
|
||||||
repost()
|
repost(allow_zero_rate=True)
|
||||||
|
|
||||||
warehouse_account = frappe.db.sql("""select name, master_name from tabAccount
|
warehouse_account = frappe.db.sql("""select name, master_name from tabAccount
|
||||||
where ifnull(account_type, '') = 'Warehouse'""")
|
where ifnull(account_type, '') = 'Warehouse'""")
|
||||||
@ -40,7 +40,7 @@ def execute():
|
|||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
voucher = frappe.get_doc(voucher_type, voucher_no)
|
voucher = frappe.get_doc(voucher_type, voucher_no)
|
||||||
voucher.make_gl_entries(repost_future_gle=False, allow_negative_stock=True)
|
voucher.make_gl_entries(repost_future_gle=False)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print frappe.get_traceback()
|
print frappe.get_traceback()
|
||||||
|
@ -283,11 +283,8 @@ class PurchaseReceipt(BuyingController):
|
|||||||
def get_rate(self,arg):
|
def get_rate(self,arg):
|
||||||
return frappe.get_doc('Purchase Common').get_rate(arg,self)
|
return frappe.get_doc('Purchase Common').get_rate(arg,self)
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, allow_negative_stock=False):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
from erpnext.accounts.general_ledger import process_gl_map
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
from erpnext.controllers.stock_controller import block_negative_stock
|
|
||||||
|
|
||||||
# block_negative_stock(allow_negative_stock)
|
|
||||||
|
|
||||||
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
|
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
|
||||||
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||||
|
@ -198,12 +198,12 @@ class StockReconciliation(StockController):
|
|||||||
"posting_time": self.posting_time
|
"posting_time": self.posting_time
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, allow_negative_stock=False):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
if not self.cost_center:
|
if not self.cost_center:
|
||||||
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
||||||
|
|
||||||
return super(StockReconciliation, self).get_gl_entries(warehouse_account,
|
return super(StockReconciliation, self).get_gl_entries(warehouse_account,
|
||||||
self.expense_account, self.cost_center, allow_negative_stock=allow_negative_stock)
|
self.expense_account, self.cost_center)
|
||||||
|
|
||||||
def validate_expense_account(self):
|
def validate_expense_account(self):
|
||||||
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
|
@ -58,7 +58,7 @@ def delete_cancelled_entry(voucher_type, voucher_no):
|
|||||||
frappe.db.sql("""delete from `tabStock Ledger Entry`
|
frappe.db.sql("""delete from `tabStock Ledger Entry`
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
def update_entries_after(args, verbose=1):
|
def update_entries_after(args, allow_zero_rate=False, verbose=1):
|
||||||
"""
|
"""
|
||||||
update valution rate and qty after transaction
|
update valution rate and qty after transaction
|
||||||
from the current time-bucket onwards
|
from the current time-bucket onwards
|
||||||
@ -106,9 +106,9 @@ def update_entries_after(args, verbose=1):
|
|||||||
stock_queue = [[qty_after_transaction, valuation_rate]]
|
stock_queue = [[qty_after_transaction, valuation_rate]]
|
||||||
else:
|
else:
|
||||||
if valuation_method == "Moving Average":
|
if valuation_method == "Moving Average":
|
||||||
valuation_rate = get_moving_average_values(qty_after_transaction, sle, valuation_rate)
|
valuation_rate = get_moving_average_values(qty_after_transaction, sle, valuation_rate, allow_zero_rate)
|
||||||
else:
|
else:
|
||||||
valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue)
|
valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue, allow_zero_rate)
|
||||||
|
|
||||||
|
|
||||||
qty_after_transaction += flt(sle.actual_qty)
|
qty_after_transaction += flt(sle.actual_qty)
|
||||||
@ -251,7 +251,7 @@ def get_serialized_values(qty_after_transaction, sle, valuation_rate):
|
|||||||
|
|
||||||
return valuation_rate
|
return valuation_rate
|
||||||
|
|
||||||
def get_moving_average_values(qty_after_transaction, sle, valuation_rate):
|
def get_moving_average_values(qty_after_transaction, sle, valuation_rate, allow_zero_rate):
|
||||||
incoming_rate = flt(sle.incoming_rate)
|
incoming_rate = flt(sle.incoming_rate)
|
||||||
actual_qty = flt(sle.actual_qty)
|
actual_qty = flt(sle.actual_qty)
|
||||||
|
|
||||||
@ -266,11 +266,11 @@ 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 and qty_after_transaction <= 0:
|
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, allow_zero_rate)
|
||||||
|
|
||||||
return abs(flt(valuation_rate))
|
return abs(flt(valuation_rate))
|
||||||
|
|
||||||
def get_fifo_values(qty_after_transaction, sle, stock_queue):
|
def get_fifo_values(qty_after_transaction, sle, stock_queue, allow_zero_rate):
|
||||||
incoming_rate = flt(sle.incoming_rate)
|
incoming_rate = flt(sle.incoming_rate)
|
||||||
actual_qty = flt(sle.actual_qty)
|
actual_qty = flt(sle.actual_qty)
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ def get_fifo_values(qty_after_transaction, sle, stock_queue):
|
|||||||
qty_to_pop = abs(actual_qty)
|
qty_to_pop = abs(actual_qty)
|
||||||
while qty_to_pop:
|
while qty_to_pop:
|
||||||
if not stock_queue:
|
if not stock_queue:
|
||||||
stock_queue.append([0, get_valuation_rate(sle.item_code, sle.warehouse)
|
stock_queue.append([0, get_valuation_rate(sle.item_code, sle.warehouse, allow_zero_rate)
|
||||||
if qty_after_transaction <= 0 else 0])
|
if qty_after_transaction <= 0 else 0])
|
||||||
|
|
||||||
batch = stock_queue[0]
|
batch = stock_queue[0]
|
||||||
@ -349,7 +349,7 @@ def get_previous_sle(args, for_update=False):
|
|||||||
"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):
|
def get_valuation_rate(item_code, warehouse, allow_zero_rate=False):
|
||||||
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where item_code = %s and warehouse = %s
|
where item_code = %s and warehouse = %s
|
||||||
@ -367,7 +367,7 @@ def get_valuation_rate(item_code, warehouse):
|
|||||||
if not valuation_rate:
|
if not valuation_rate:
|
||||||
valuation_rate = frappe.db.get_value("Item Price", {"item_code": item_code, "buying": 1}, "price_list_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")):
|
if not allow_zero_rate and 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))
|
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
|
return valuation_rate
|
||||||
|
@ -9,7 +9,7 @@ from erpnext.stock.utils import update_bin
|
|||||||
from erpnext.stock.stock_ledger import update_entries_after
|
from erpnext.stock.stock_ledger import update_entries_after
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
def repost(allow_negative_stock=False):
|
def repost(allow_negative_stock=False, allow_zero_rate=False):
|
||||||
"""
|
"""
|
||||||
Repost everything!
|
Repost everything!
|
||||||
"""
|
"""
|
||||||
@ -23,7 +23,7 @@ def repost(allow_negative_stock=False):
|
|||||||
union
|
union
|
||||||
select item_code, warehouse from `tabStock Ledger Entry`) a"""):
|
select item_code, warehouse from `tabStock Ledger Entry`) a"""):
|
||||||
try:
|
try:
|
||||||
repost_stock(d[0], d[1])
|
repost_stock(d[0], d[1], allow_zero_rate)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
except:
|
except:
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
@ -33,8 +33,8 @@ def repost(allow_negative_stock=False):
|
|||||||
frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
||||||
frappe.db.auto_commit_on_many_writes = 0
|
frappe.db.auto_commit_on_many_writes = 0
|
||||||
|
|
||||||
def repost_stock(item_code, warehouse):
|
def repost_stock(item_code, warehouse, allow_zero_rate=False):
|
||||||
repost_actual_qty(item_code, warehouse)
|
repost_actual_qty(item_code, warehouse, allow_zero_rate)
|
||||||
|
|
||||||
if item_code and warehouse:
|
if item_code and warehouse:
|
||||||
update_bin_qty(item_code, warehouse, {
|
update_bin_qty(item_code, warehouse, {
|
||||||
@ -44,9 +44,9 @@ def repost_stock(item_code, warehouse):
|
|||||||
"planned_qty": get_planned_qty(item_code, warehouse)
|
"planned_qty": get_planned_qty(item_code, warehouse)
|
||||||
})
|
})
|
||||||
|
|
||||||
def repost_actual_qty(item_code, warehouse):
|
def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
|
||||||
try:
|
try:
|
||||||
update_entries_after({ "item_code": item_code, "warehouse": warehouse })
|
update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user