mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 17:04:47 +00:00
Merge pull request #23564 from rohitwaghchaure/fixed-batch-wise-stock-reco
fix: negative stock error while submitting stock reco for batch item
This commit is contained in:
@@ -172,8 +172,9 @@ class StockReconciliation(StockController):
|
|||||||
row.serial_no = ''
|
row.serial_no = ''
|
||||||
|
|
||||||
# item managed batch-wise not allowed
|
# item managed batch-wise not allowed
|
||||||
if item.has_batch_no and not row.batch_no and not item.create_new_batch:
|
if item.has_batch_no and not row.batch_no and not frappe.flags.in_test:
|
||||||
raise frappe.ValidationError(_("Batch no is required for batched item {0}").format(item_code))
|
if not item.create_new_batch or self.purpose != 'Opening Stock':
|
||||||
|
raise frappe.ValidationError(_("Batch no is required for the batched item {0}").format(item_code))
|
||||||
|
|
||||||
# docstatus should be < 2
|
# docstatus should be < 2
|
||||||
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
||||||
@@ -191,10 +192,11 @@ class StockReconciliation(StockController):
|
|||||||
serialized_items = False
|
serialized_items = False
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
item = frappe.get_cached_doc("Item", row.item_code)
|
item = frappe.get_cached_doc("Item", row.item_code)
|
||||||
if not (item.has_serial_no or item.has_batch_no):
|
if not (item.has_serial_no):
|
||||||
if row.serial_no or row.batch_no:
|
if row.serial_no:
|
||||||
frappe.throw(_("Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.") \
|
frappe.throw(_("Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.") \
|
||||||
.format(row.idx, frappe.bold(row.item_code)))
|
.format(row.idx, frappe.bold(row.item_code)))
|
||||||
|
|
||||||
previous_sle = get_previous_sle({
|
previous_sle = get_previous_sle({
|
||||||
"item_code": row.item_code,
|
"item_code": row.item_code,
|
||||||
"warehouse": row.warehouse,
|
"warehouse": row.warehouse,
|
||||||
@@ -217,7 +219,12 @@ class StockReconciliation(StockController):
|
|||||||
or (not previous_sle and not row.qty)):
|
or (not previous_sle and not row.qty)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
sl_entries.append(self.get_sle_for_items(row))
|
sle_data = self.get_sle_for_items(row)
|
||||||
|
|
||||||
|
if row.batch_no:
|
||||||
|
sle_data.actual_qty = row.quantity_difference
|
||||||
|
|
||||||
|
sl_entries.append(sle_data)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
serialized_items = True
|
serialized_items = True
|
||||||
@@ -244,7 +251,7 @@ class StockReconciliation(StockController):
|
|||||||
serial_nos = get_serial_nos(row.serial_no) or []
|
serial_nos = get_serial_nos(row.serial_no) or []
|
||||||
|
|
||||||
# To issue existing serial nos
|
# To issue existing serial nos
|
||||||
if row.current_qty and (row.current_serial_no or row.batch_no):
|
if row.current_qty and (row.current_serial_no):
|
||||||
args = self.get_sle_for_items(row)
|
args = self.get_sle_for_items(row)
|
||||||
args.update({
|
args.update({
|
||||||
'actual_qty': -1 * row.current_qty,
|
'actual_qty': -1 * row.current_qty,
|
||||||
|
|||||||
@@ -361,6 +361,37 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
doc.cancel()
|
doc.cancel()
|
||||||
frappe.delete_doc(doc.doctype, doc.name)
|
frappe.delete_doc(doc.doctype, doc.name)
|
||||||
|
|
||||||
|
def test_allow_negative_for_batch(self):
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
item_code = "Stock-Reco-batch-Item-5"
|
||||||
|
warehouse = "_Test Warehouse for Stock Reco5 - _TC"
|
||||||
|
|
||||||
|
create_warehouse("_Test Warehouse for Stock Reco5", {"is_group": 0,
|
||||||
|
"parent_warehouse": "_Test Warehouse Group - _TC", "company": "_Test Company"})
|
||||||
|
|
||||||
|
batch_item_doc = create_item(item_code, is_stock_item=1)
|
||||||
|
if not batch_item_doc.has_batch_no:
|
||||||
|
frappe.db.set_value("Item", item_code, {
|
||||||
|
"has_batch_no": 1,
|
||||||
|
"create_new_batch": 1,
|
||||||
|
"batch_number_series": "Test-C.####"
|
||||||
|
})
|
||||||
|
|
||||||
|
ste1=make_stock_entry(posting_date="2020-10-07", posting_time="02:00", item_code=item_code,
|
||||||
|
target=warehouse, qty=2, basic_rate=100)
|
||||||
|
|
||||||
|
batch_no = ste1.items[0].batch_no
|
||||||
|
|
||||||
|
ste2=make_stock_entry(posting_date="2020-10-09", posting_time="02:00", item_code=item_code,
|
||||||
|
source=warehouse, qty=2, basic_rate=100, batch_no=batch_no)
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(item_code=item_code,
|
||||||
|
warehouse = warehouse, batch_no=batch_no, rate=200)
|
||||||
|
|
||||||
|
for doc in [sr, ste2, ste1]:
|
||||||
|
doc.cancel()
|
||||||
|
frappe.delete_doc(doc.doctype, doc.name)
|
||||||
|
|
||||||
def insert_existing_sle(warehouse):
|
def insert_existing_sle(warehouse):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
|
||||||
|
|||||||
@@ -162,10 +162,13 @@ class update_entries_after(object):
|
|||||||
|
|
||||||
self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
|
self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
|
||||||
else:
|
else:
|
||||||
if sle.voucher_type=="Stock Reconciliation" and not sle.batch_no:
|
if sle.voucher_type=="Stock Reconciliation":
|
||||||
# assert
|
if sle.batch_no:
|
||||||
|
self.qty_after_transaction += flt(sle.actual_qty)
|
||||||
|
else:
|
||||||
|
self.qty_after_transaction = sle.qty_after_transaction
|
||||||
|
|
||||||
self.valuation_rate = sle.valuation_rate
|
self.valuation_rate = sle.valuation_rate
|
||||||
self.qty_after_transaction = sle.qty_after_transaction
|
|
||||||
self.stock_queue = [[self.qty_after_transaction, self.valuation_rate]]
|
self.stock_queue = [[self.qty_after_transaction, self.valuation_rate]]
|
||||||
self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
|
self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user