mirror of
https://github.com/frappe/erpnext.git
synced 2026-10-29 22:57:42 +00:00
fix(stock): value legacy sales returns at the outgoing rate
A return against a delivery without a Serial and Batch Bundle gets the rate of each serial no / batch from the original stock ledger entry. This used the incoming rate of the entry. An outgoing entry has no incoming rate, so the return had a stock value of zero. Now the rate of an outgoing entry is its stock value difference divided by its qty. This is the same rate that get_rate_for_return uses for sales returns.
This commit is contained in:
@@ -3339,7 +3339,8 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
if packed_item.item_code not in serial_items:
|
||||
continue
|
||||
|
||||
serial_nos = get_serial_nos_from_bundle(packed_item.serial_and_batch_bundle)
|
||||
bundle = packed_item.serial_and_batch_bundle
|
||||
serial_nos = get_serial_nos_from_bundle(bundle)
|
||||
delivered_serial_nos[packed_item.item_code] = sorted(serial_nos)
|
||||
legacy_values = {"serial_no": "\n".join(serial_nos), "serial_and_batch_bundle": None}
|
||||
packed_item.db_set(legacy_values)
|
||||
@@ -3348,6 +3349,8 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
{"voucher_no": dn.name, "item_code": packed_item.item_code},
|
||||
legacy_values,
|
||||
)
|
||||
frappe.db.delete("Serial and Batch Entry", {"parent": bundle})
|
||||
frappe.db.delete("Serial and Batch Bundle", bundle)
|
||||
|
||||
return_dn = make_sales_return(dn.name)
|
||||
return_dn.submit()
|
||||
@@ -3360,6 +3363,15 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
}
|
||||
self.assertEqual(returned_serial_nos, delivered_serial_nos)
|
||||
|
||||
# The return gets the stock value of the delivery: 2 units at 100
|
||||
for item_code in serial_items:
|
||||
stock_value_difference = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_no": return_dn.name, "item_code": item_code, "is_cancelled": 0},
|
||||
"stock_value_difference",
|
||||
)
|
||||
self.assertEqual(stock_value_difference, 200)
|
||||
|
||||
@change_settings("Stock Settings", {"use_serial_batch_fields": 1})
|
||||
def test_partial_sales_return_for_product_bundle_with_serial_fields_and_bundle(self):
|
||||
bundle_item = make_item("_Packed Serial Fields Bundle Item", {"is_stock_item": 0}).name
|
||||
|
||||
@@ -620,7 +620,7 @@ class SerialandBatchBundle(Document):
|
||||
def get_legacy_valuation_rate_for_return_entry(
|
||||
self, return_against, return_against_voucher_detail_no, return_warehouse=None
|
||||
):
|
||||
"""Return the original line's incoming rate per serial no / batch from the SLE, for legacy receipts with no bundle."""
|
||||
"""Return the original line's rate per serial no / batch from the SLE, for legacy entries with no bundle."""
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
if not (self.has_serial_no or self.has_batch_no):
|
||||
@@ -629,7 +629,9 @@ class SerialandBatchBundle(Document):
|
||||
sle = frappe.qb.DocType("Stock Ledger Entry")
|
||||
query = (
|
||||
frappe.qb.from_(sle)
|
||||
.select(sle.serial_no, sle.batch_no, sle.incoming_rate)
|
||||
.select(
|
||||
sle.serial_no, sle.batch_no, sle.incoming_rate, sle.actual_qty, sle.stock_value_difference
|
||||
)
|
||||
.where(
|
||||
(sle.voucher_no == return_against)
|
||||
& (sle.voucher_detail_no == return_against_voucher_detail_no)
|
||||
@@ -644,18 +646,21 @@ class SerialandBatchBundle(Document):
|
||||
|
||||
data = []
|
||||
for d in query.run(as_dict=True):
|
||||
incoming_rate = d.incoming_rate
|
||||
if d.actual_qty < 0:
|
||||
# An outgoing entry (e.g. a delivery) has no incoming rate, use its outgoing value
|
||||
incoming_rate = abs(d.stock_value_difference / d.actual_qty)
|
||||
|
||||
if d.serial_no:
|
||||
for serial_no in get_serial_nos(d.serial_no):
|
||||
data.append(
|
||||
frappe._dict(
|
||||
{"serial_no": serial_no, "batch_no": d.batch_no, "incoming_rate": d.incoming_rate}
|
||||
{"serial_no": serial_no, "batch_no": d.batch_no, "incoming_rate": incoming_rate}
|
||||
)
|
||||
)
|
||||
elif d.batch_no:
|
||||
data.append(
|
||||
frappe._dict(
|
||||
{"serial_no": None, "batch_no": d.batch_no, "incoming_rate": d.incoming_rate}
|
||||
)
|
||||
frappe._dict({"serial_no": None, "batch_no": d.batch_no, "incoming_rate": incoming_rate})
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user