mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-01 16:54:36 +00:00
fix: Incorrect creation time at the time cancelling an entry causing an issue especially same posting datetime (backport #57380) (#57397)
* fix: Incorrect creation time at the time cancelling an entry causing an issue especially same posting datetime (#57380)
* fix: shift same-timestamp sibling SLEs when cancelling an entry
update_qty_in_future_sle compared against the reversal SLE's own
creation and skipped same-posting_datetime siblings on cancel, leaving
their qty_after_transaction stale and causing false negative stock
errors.
* fix: revert update_qty_in_future_sle cancel tie-break, it double-counted
(cherry picked from commit 8c0ec3c179)
# Conflicts:
# erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
* chore: fix conflicts
Fix test case for cancelling stock ledger entries with the same timestamp to ensure correct behavior.
* chore: fix conflicts
---------
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -1344,6 +1344,47 @@ class TestStockLedgerEntry(ERPNextTestSuite, StockTestMixin):
|
||||
# receipt2 now sits on a zero base -> 10 (not 0 from a double shift, nor a negative-stock error).
|
||||
self.assertEqual(qty_after(receipt2), 10)
|
||||
|
||||
def test_cancel_shifts_same_timestamp_delivery_notes(self):
|
||||
item = make_item().name
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
posting_date = today()
|
||||
posting_time = "10:00:00"
|
||||
|
||||
make_stock_entry(
|
||||
item_code=item,
|
||||
to_warehouse=warehouse,
|
||||
qty=100,
|
||||
rate=10,
|
||||
posting_date=posting_date,
|
||||
posting_time="09:00:00",
|
||||
)
|
||||
|
||||
dns = []
|
||||
for i in range(5):
|
||||
dns.append(
|
||||
create_delivery_note(
|
||||
item_code=item,
|
||||
warehouse=warehouse,
|
||||
qty=20,
|
||||
rate=10 * i,
|
||||
posting_date=posting_date,
|
||||
posting_time=posting_time,
|
||||
)
|
||||
)
|
||||
time.sleep(1)
|
||||
|
||||
dn = dns[2]
|
||||
dn.cancel()
|
||||
|
||||
expected_qty_after_transaction_of_dns3 = 40
|
||||
qty_after_transaction_of_dns3 = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_no": dns[3].name, "is_cancelled": 0},
|
||||
"qty_after_transaction",
|
||||
)
|
||||
|
||||
self.assertEqual(expected_qty_after_transaction_of_dns3, qty_after_transaction_of_dns3)
|
||||
|
||||
def test_get_next_stock_reco_respects_creation_order(self):
|
||||
# A stock reco sharing the exact posting timestamp of the current entry must only count as the
|
||||
# "next" reco when it was created after that entry. A reco created before it actually precedes
|
||||
|
||||
@@ -497,7 +497,9 @@ class update_entries_after:
|
||||
|
||||
self.data = frappe._dict()
|
||||
|
||||
if not self.repost_doc or not self.args.get("item_wh_wise_last_posted_sle"):
|
||||
if (not self.repost_doc or not self.args.get("item_wh_wise_last_posted_sle")) and not self.args.get(
|
||||
"cancelled"
|
||||
):
|
||||
self.initialize_previous_data(self.args)
|
||||
|
||||
self.build()
|
||||
@@ -805,10 +807,23 @@ 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])
|
||||
for sle in sl_entries:
|
||||
sle["timestamp"] = sle.posting_datetime
|
||||
self.process_sle(sle)
|
||||
|
||||
def seed_previous_sle_for_cancellation(self, anchor_sle):
|
||||
key = (anchor_sle.item_code, anchor_sle.warehouse)
|
||||
if key in self.prev_sle_dict:
|
||||
return
|
||||
|
||||
args = frappe._dict(anchor_sle)
|
||||
args["sle_id"] = args.name
|
||||
prev_sle = get_previous_sle_of_current_voucher(args)
|
||||
if prev_sle:
|
||||
self.prev_sle_dict[key] = prev_sle
|
||||
|
||||
def get_future_entries_to_fix(self):
|
||||
# includes current entry!
|
||||
args = self.data[self.args.warehouse].previous_sle or frappe._dict(
|
||||
|
||||
Reference in New Issue
Block a user