From 85d2d3411683832e8f4fbe54790da3327f03cc2a Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 16 Jul 2024 16:08:39 +0530 Subject: [PATCH] fix: same posting date and time causing incorrect valuation rate (#42351) --- .../delivery_note/test_delivery_note.py | 87 +++++++++++++++++++ .../serial_and_batch_bundle.py | 1 + erpnext/stock/serial_batch_bundle.py | 12 ++- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 8a0af0d466d..69ef77e95ae 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -1945,6 +1945,93 @@ class TestDeliveryNote(FrappeTestCase): returned_serial_nos = get_serial_nos_from_bundle(dn_return.items[0].serial_and_batch_bundle) self.assertEqual(serial_nos, returned_serial_nos) + def test_same_posting_date_and_posting_time(self): + item_code = make_item( + "Test Same Posting Datetime Item", + properties={ + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "SS-ART11-TESTBATCH.#####", + "is_stock_item": 1, + }, + ).name + + se = make_stock_entry( + item_code=item_code, + target="_Test Warehouse - _TC", + qty=100, + basic_rate=50, + posting_date=add_days(nowdate(), -1), + ) + + batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + + posting_date = today() + posting_time = nowtime() + dn1 = create_delivery_note( + posting_date=posting_date, + posting_time=posting_time, + item_code=item_code, + rate=300, + qty=25, + batch_no=batch_no, + use_serial_batch_fields=1, + ) + + dn2 = create_delivery_note( + posting_date=posting_date, + posting_time=posting_time, + item_code=item_code, + rate=300, + qty=25, + batch_no=batch_no, + use_serial_batch_fields=1, + ) + + dn3 = create_delivery_note( + posting_date=posting_date, + posting_time=posting_time, + item_code=item_code, + rate=300, + qty=25, + batch_no=batch_no, + use_serial_batch_fields=1, + ) + + dn4 = create_delivery_note( + posting_date=posting_date, + posting_time=posting_time, + item_code=item_code, + rate=300, + qty=25, + batch_no=batch_no, + use_serial_batch_fields=1, + ) + + for dn in [dn1, dn2, dn3, dn4]: + sles = frappe.get_all( + "Stock Ledger Entry", + fields=["stock_value_difference", "actual_qty"], + filters={"is_cancelled": 0, "voucher_no": dn.name, "docstatus": 1}, + ) + + for sle in sles: + self.assertEqual(sle.actual_qty, 25.0 * -1) + self.assertEqual(sle.stock_value_difference, 25.0 * 50 * -1) + + dn5 = create_delivery_note( + posting_date=posting_date, + posting_time=posting_time, + item_code=item_code, + rate=300, + qty=25, + batch_no=batch_no, + use_serial_batch_fields=1, + do_not_submit=True, + ) + + self.assertRaises(frappe.ValidationError, dn5.submit) + def create_delivery_note(**args): dn = frappe.new_doc("Delivery Note") diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index c3fd28fcfa6..3ada8f0bbcd 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -300,6 +300,7 @@ class SerialandBatchBundle(Document): "batch_nos": {row.batch_no: row for row in self.entries if row.batch_no}, "voucher_type": self.voucher_type, "voucher_detail_no": self.voucher_detail_no, + "creation": self.creation, } ) diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index c5346d2b0a3..2207b2e3c74 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -599,9 +599,15 @@ class BatchNoValuation(DeprecatedBatchNoValuation): timestamp_condition = "" if self.sle.posting_date and self.sle.posting_time: - timestamp_condition = CombineDatetime( - parent.posting_date, parent.posting_time - ) <= CombineDatetime(self.sle.posting_date, self.sle.posting_time) + timestamp_condition = CombineDatetime(parent.posting_date, parent.posting_time) < CombineDatetime( + self.sle.posting_date, self.sle.posting_time + ) + + if self.sle.creation: + timestamp_condition |= ( + CombineDatetime(parent.posting_date, parent.posting_time) + == CombineDatetime(self.sle.posting_date, self.sle.posting_time) + ) & (parent.creation < self.sle.creation) query = ( frappe.qb.from_(parent)