mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-23 08:38:30 +00:00
fix: incorrect stock posting for current qty
(cherry picked from commit d4fe313de2)
This commit is contained in:
committed by
Mergify
parent
8591a151de
commit
05d5c48d29
@@ -823,11 +823,9 @@ class StockReconciliation(StockController):
|
|||||||
else:
|
else:
|
||||||
self._cancel()
|
self._cancel()
|
||||||
|
|
||||||
def recalculate_current_qty(self, voucher_detail_no, sle_creation, add_new_sle=False):
|
def recalculate_current_qty(self, voucher_detail_no):
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
|
|
||||||
sl_entries = []
|
|
||||||
|
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
if voucher_detail_no != row.name:
|
if voucher_detail_no != row.name:
|
||||||
continue
|
continue
|
||||||
@@ -881,32 +879,6 @@ class StockReconciliation(StockController):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
|
||||||
add_new_sle
|
|
||||||
and not frappe.db.get_value(
|
|
||||||
"Stock Ledger Entry",
|
|
||||||
{"voucher_detail_no": row.name, "actual_qty": ("<", 0), "is_cancelled": 0},
|
|
||||||
"name",
|
|
||||||
)
|
|
||||||
and (not row.current_serial_and_batch_bundle)
|
|
||||||
):
|
|
||||||
self.set_current_serial_and_batch_bundle(voucher_detail_no, save=True)
|
|
||||||
row.reload()
|
|
||||||
|
|
||||||
if row.current_qty > 0 and row.current_serial_and_batch_bundle:
|
|
||||||
new_sle = self.get_sle_for_items(row)
|
|
||||||
new_sle.actual_qty = row.current_qty * -1
|
|
||||||
new_sle.valuation_rate = row.current_valuation_rate
|
|
||||||
new_sle.creation_time = add_to_date(sle_creation, seconds=-1)
|
|
||||||
new_sle.serial_and_batch_bundle = row.current_serial_and_batch_bundle
|
|
||||||
new_sle.qty_after_transaction = 0.0
|
|
||||||
sl_entries.append(new_sle)
|
|
||||||
|
|
||||||
if sl_entries:
|
|
||||||
self.make_sl_entries(sl_entries, allow_negative_stock=self.has_negative_stock_allowed())
|
|
||||||
if not frappe.db.exists("Repost Item Valuation", {"voucher_no": self.name, "status": "Queued"}):
|
|
||||||
self.repost_future_sle_and_gle(force=True)
|
|
||||||
|
|
||||||
def has_negative_stock_allowed(self):
|
def has_negative_stock_allowed(self):
|
||||||
allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
|
allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
|
||||||
if allow_negative_stock:
|
if allow_negative_stock:
|
||||||
|
|||||||
@@ -756,66 +756,6 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
|||||||
|
|
||||||
self.assertEqual(flt(sle[0].actual_qty), flt(-100.0))
|
self.assertEqual(flt(sle[0].actual_qty), flt(-100.0))
|
||||||
|
|
||||||
def test_backdated_stock_reco_entry_with_batch(self):
|
|
||||||
item_code = self.make_item(
|
|
||||||
"Test New Batch Item ABCVSD",
|
|
||||||
{
|
|
||||||
"is_stock_item": 1,
|
|
||||||
"has_batch_no": 1,
|
|
||||||
"batch_number_series": "BNS9.####",
|
|
||||||
"create_new_batch": 1,
|
|
||||||
},
|
|
||||||
).name
|
|
||||||
|
|
||||||
warehouse = "_Test Warehouse - _TC"
|
|
||||||
|
|
||||||
# Stock Reco for 100, Balace Qty 100
|
|
||||||
stock_reco = create_stock_reconciliation(
|
|
||||||
item_code=item_code,
|
|
||||||
posting_date=nowdate(),
|
|
||||||
posting_time="11:00:00",
|
|
||||||
warehouse=warehouse,
|
|
||||||
qty=100,
|
|
||||||
rate=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
sles = frappe.get_all(
|
|
||||||
"Stock Ledger Entry",
|
|
||||||
fields=["actual_qty"],
|
|
||||||
filters={"voucher_no": stock_reco.name, "is_cancelled": 0},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(len(sles), 1)
|
|
||||||
|
|
||||||
stock_reco.reload()
|
|
||||||
batch_no = get_batch_from_bundle(stock_reco.items[0].serial_and_batch_bundle)
|
|
||||||
|
|
||||||
# Stock Reco for 100, Balace Qty 100
|
|
||||||
stock_reco1 = create_stock_reconciliation(
|
|
||||||
item_code=item_code,
|
|
||||||
posting_date=add_days(nowdate(), -1),
|
|
||||||
posting_time="11:00:00",
|
|
||||||
batch_no=batch_no,
|
|
||||||
warehouse=warehouse,
|
|
||||||
qty=60,
|
|
||||||
rate=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
sles = frappe.get_all(
|
|
||||||
"Stock Ledger Entry",
|
|
||||||
fields=["actual_qty"],
|
|
||||||
filters={"voucher_no": stock_reco.name, "is_cancelled": 0},
|
|
||||||
)
|
|
||||||
|
|
||||||
stock_reco1.reload()
|
|
||||||
get_batch_from_bundle(stock_reco1.items[0].serial_and_batch_bundle)
|
|
||||||
|
|
||||||
self.assertEqual(len(sles), 2)
|
|
||||||
|
|
||||||
for row in sles:
|
|
||||||
if row.actual_qty < 0:
|
|
||||||
self.assertEqual(row.actual_qty, -60)
|
|
||||||
|
|
||||||
def test_update_stock_reconciliation_while_reposting(self):
|
def test_update_stock_reconciliation_while_reposting(self):
|
||||||
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
|
||||||
|
|
||||||
@@ -1088,6 +1028,48 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
|||||||
|
|
||||||
self.assertEqual(flt(sle[0].qty_after_transaction), flt(100.0))
|
self.assertEqual(flt(sle[0].qty_after_transaction), flt(100.0))
|
||||||
|
|
||||||
|
def test_stock_reco_and_backdated_purchase_receipt(self):
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
|
||||||
|
item = self.make_item(
|
||||||
|
"Test Batch Item Original STOCK RECO Test",
|
||||||
|
{
|
||||||
|
"is_stock_item": 1,
|
||||||
|
"has_batch_no": 1,
|
||||||
|
"create_new_batch": 1,
|
||||||
|
"batch_number_series": "TEST-BATCH-SRCOSRWFEE-.###",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
warehouse = "_Test Warehouse - _TC"
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(
|
||||||
|
item_code=item.name,
|
||||||
|
warehouse=warehouse,
|
||||||
|
qty=100,
|
||||||
|
rate=100,
|
||||||
|
)
|
||||||
|
|
||||||
|
sr.reload()
|
||||||
|
self.assertTrue(sr.items[0].serial_and_batch_bundle)
|
||||||
|
self.assertFalse(sr.items[0].current_serial_and_batch_bundle)
|
||||||
|
batch = get_batch_from_bundle(sr.items[0].serial_and_batch_bundle)
|
||||||
|
|
||||||
|
se1 = make_stock_entry(
|
||||||
|
item_code=item.name,
|
||||||
|
target=warehouse,
|
||||||
|
qty=50,
|
||||||
|
basic_rate=100,
|
||||||
|
posting_date=add_days(nowdate(), -2),
|
||||||
|
)
|
||||||
|
|
||||||
|
batch1 = get_batch_from_bundle(se1.items[0].serial_and_batch_bundle)
|
||||||
|
self.assertFalse(batch1 == batch)
|
||||||
|
|
||||||
|
sr.reload()
|
||||||
|
self.assertTrue(sr.items[0].serial_and_batch_bundle)
|
||||||
|
self.assertFalse(sr.items[0].current_serial_and_batch_bundle)
|
||||||
|
|
||||||
|
|
||||||
def create_batch_item_with_batch(item_name, batch_id):
|
def create_batch_item_with_batch(item_name, batch_id):
|
||||||
batch_item_doc = create_item(item_name, is_stock_item=1)
|
batch_item_doc = create_item(item_name, is_stock_item=1)
|
||||||
|
|||||||
@@ -840,7 +840,7 @@ class update_entries_after:
|
|||||||
|
|
||||||
def reset_actual_qty_for_stock_reco(self, sle):
|
def reset_actual_qty_for_stock_reco(self, sle):
|
||||||
doc = frappe.get_cached_doc("Stock Reconciliation", sle.voucher_no)
|
doc = frappe.get_cached_doc("Stock Reconciliation", sle.voucher_no)
|
||||||
doc.recalculate_current_qty(sle.voucher_detail_no, sle.creation, sle.actual_qty > 0)
|
doc.recalculate_current_qty(sle.voucher_detail_no)
|
||||||
|
|
||||||
if sle.actual_qty < 0:
|
if sle.actual_qty < 0:
|
||||||
sle.actual_qty = (
|
sle.actual_qty = (
|
||||||
|
|||||||
Reference in New Issue
Block a user