mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-24 13:57:05 +00:00
fix(stock): seed bin values when cancelling a stock voucher (#59250)
* fix(stock): seed bin values when cancelling a stock voucher
cancellation flags every sle of the voucher before update_entries_after
runs, so get_sle_against_current_voucher returns nothing and the seeding
added in #57380 never fires. prev_sle_dict stays empty, update_bin()
writes nothing, and the bin keeps the stock value and valuation rate it
had before the cancellation while its quantity is restored.
seed from the args when the query comes back empty, leaving the existing
anchor in place whenever a live entry shares the posting datetime.
* test(stock): cover bin stock value after cancelling a transfer
a transfer between two warehouses that both hold stock, then cancelled:
both bins must return to their previous quantity, valuation rate and
stock value. fails on develop with 500.0 != 1000.
(cherry picked from commit 62cb38d36b)
This commit is contained in:
committed by
Mergify
parent
6af589208b
commit
3ab13e12d4
@@ -96,6 +96,27 @@ class TestBin(ERPNextTestSuite):
|
||||
self.assertEqual(bin.valuation_rate, 0)
|
||||
self.assertEqual(bin.stock_value, 0)
|
||||
|
||||
def test_cancelling_transfer_restores_bin_stock_value(self):
|
||||
"""Cancelling a transfer must put back the stock value of both bins, not just the quantity."""
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
|
||||
item_code = make_item().name
|
||||
source = "_Test Warehouse - _TC"
|
||||
target = "_Test Warehouse 1 - _TC"
|
||||
make_stock_entry(item_code=item_code, target=source, qty=10, rate=100, posting_time="01:00:00")
|
||||
make_stock_entry(item_code=item_code, target=target, qty=10, rate=200, posting_time="02:00:00")
|
||||
|
||||
se = make_stock_entry(
|
||||
item_code=item_code, source=source, target=target, qty=5, posting_time="03:00:00"
|
||||
)
|
||||
se.cancel()
|
||||
|
||||
for warehouse, valuation_rate, stock_value in ((source, 100, 1000), (target, 200, 2000)):
|
||||
bin = frappe.get_doc("Bin", {"item_code": item_code, "warehouse": warehouse})
|
||||
self.assertEqual(bin.actual_qty, 10)
|
||||
self.assertEqual(bin.valuation_rate, valuation_rate)
|
||||
self.assertEqual(bin.stock_value, stock_value)
|
||||
|
||||
def test_deleting_last_voucher_resets_bin(self):
|
||||
"""Deleting the only voucher wipes its ledger entries outright, the bin must still be cleared."""
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
|
||||
@@ -965,8 +965,10 @@ class update_entries_after:
|
||||
|
||||
def process_sle_against_current_timestamp(self):
|
||||
sl_entries = get_sle_against_current_voucher(self.args)
|
||||
if self.args.get("cancelled") and sl_entries:
|
||||
self.seed_previous_sle_for_cancellation(sl_entries[0])
|
||||
if self.args.get("cancelled"):
|
||||
# Cancellation flags every entry of the voucher first, so this query usually returns
|
||||
# nothing and the args are the only anchor left to seed the previous values from.
|
||||
self.seed_previous_sle_for_cancellation(sl_entries[0] if sl_entries else self.args)
|
||||
for sle in sl_entries:
|
||||
sle["timestamp"] = sle.posting_datetime
|
||||
self.process_sle(sle)
|
||||
@@ -977,7 +979,7 @@ class update_entries_after:
|
||||
return
|
||||
|
||||
args = frappe._dict(anchor_sle)
|
||||
args["sle_id"] = args.name
|
||||
args["sle_id"] = args.get("name")
|
||||
prev_sle = get_previous_sle_of_current_voucher(args)
|
||||
if prev_sle:
|
||||
self.prev_sle_dict[key] = prev_sle
|
||||
|
||||
Reference in New Issue
Block a user