mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-20 15:25:13 +00:00
fix: valuation rate for old batch
(cherry picked from commit d864d166f9)
This commit is contained in:
committed by
Mergify
parent
c2dd37a89e
commit
37a03f10ab
@@ -311,7 +311,7 @@ class SerialandBatchBundle(Document):
|
|||||||
def throw_error_message(self, message, exception=frappe.ValidationError):
|
def throw_error_message(self, message, exception=frappe.ValidationError):
|
||||||
frappe.throw(_(message), exception, title=_("Error"))
|
frappe.throw(_(message), exception, title=_("Error"))
|
||||||
|
|
||||||
def set_incoming_rate(self, parent=None, row=None, save=False, allow_negative_stock=False):
|
def set_incoming_rate(self, parent=None, row=None, save=False, allow_negative_stock=False, prev_sle=None):
|
||||||
if self.type_of_transaction not in ["Inward", "Outward"] or self.voucher_type in [
|
if self.type_of_transaction not in ["Inward", "Outward"] or self.voucher_type in [
|
||||||
"Installation Note",
|
"Installation Note",
|
||||||
"Job Card",
|
"Job Card",
|
||||||
@@ -321,15 +321,15 @@ class SerialandBatchBundle(Document):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if return_against := self.get_return_against(parent=parent):
|
if return_against := self.get_return_against(parent=parent):
|
||||||
self.set_valuation_rate_for_return_entry(return_against, row, save)
|
self.set_valuation_rate_for_return_entry(return_against, row, save, prev_sle=prev_sle)
|
||||||
elif self.type_of_transaction == "Outward":
|
elif self.type_of_transaction == "Outward":
|
||||||
self.set_incoming_rate_for_outward_transaction(
|
self.set_incoming_rate_for_outward_transaction(
|
||||||
row, save, allow_negative_stock=allow_negative_stock
|
row, save, allow_negative_stock=allow_negative_stock
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.set_incoming_rate_for_inward_transaction(row, save)
|
self.set_incoming_rate_for_inward_transaction(row, save, prev_sle=prev_sle)
|
||||||
|
|
||||||
def set_valuation_rate_for_return_entry(self, return_against, row, save=False):
|
def set_valuation_rate_for_return_entry(self, return_against, row, save=False, prev_sle=None):
|
||||||
if valuation_details := self.get_valuation_rate_for_return_entry(return_against):
|
if valuation_details := self.get_valuation_rate_for_return_entry(return_against):
|
||||||
for row in self.entries:
|
for row in self.entries:
|
||||||
if valuation_details:
|
if valuation_details:
|
||||||
@@ -361,7 +361,7 @@ class SerialandBatchBundle(Document):
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif self.type_of_transaction == "Inward":
|
elif self.type_of_transaction == "Inward":
|
||||||
self.set_incoming_rate_for_inward_transaction(row, save)
|
self.set_incoming_rate_for_inward_transaction(row, save, prev_sle=prev_sle)
|
||||||
|
|
||||||
def validate_returned_serial_batch_no(self, return_against, row, original_inv_details):
|
def validate_returned_serial_batch_no(self, return_against, row, original_inv_details):
|
||||||
if frappe.flags.through_repost_item_valuation:
|
if frappe.flags.through_repost_item_valuation:
|
||||||
@@ -529,7 +529,11 @@ class SerialandBatchBundle(Document):
|
|||||||
|
|
||||||
if save:
|
if save:
|
||||||
d.db_set(
|
d.db_set(
|
||||||
{"incoming_rate": d.incoming_rate, "stock_value_difference": d.stock_value_difference}
|
{
|
||||||
|
"incoming_rate": d.incoming_rate,
|
||||||
|
"stock_value_difference": d.stock_value_difference,
|
||||||
|
"stock_queue": d.get("stock_queue"),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate_negative_batch(self, batch_no, available_qty):
|
def validate_negative_batch(self, batch_no, available_qty):
|
||||||
@@ -606,7 +610,11 @@ class SerialandBatchBundle(Document):
|
|||||||
|
|
||||||
return return_against
|
return return_against
|
||||||
|
|
||||||
def set_incoming_rate_for_inward_transaction(self, row=None, save=False):
|
def set_incoming_rate_for_inward_transaction(self, row=None, save=False, prev_sle=None):
|
||||||
|
from erpnext.stock.utils import get_valuation_method
|
||||||
|
|
||||||
|
valuation_method = get_valuation_method(self.item_code)
|
||||||
|
|
||||||
valuation_field = "valuation_rate"
|
valuation_field = "valuation_rate"
|
||||||
if self.voucher_type in ["Sales Invoice", "Delivery Note", "Quotation"]:
|
if self.voucher_type in ["Sales Invoice", "Delivery Note", "Quotation"]:
|
||||||
valuation_field = "incoming_rate"
|
valuation_field = "incoming_rate"
|
||||||
@@ -630,19 +638,42 @@ class SerialandBatchBundle(Document):
|
|||||||
if not rate and self.voucher_detail_no and self.voucher_no:
|
if not rate and self.voucher_detail_no and self.voucher_no:
|
||||||
rate = frappe.db.get_value(child_table, self.voucher_detail_no, valuation_field)
|
rate = frappe.db.get_value(child_table, self.voucher_detail_no, valuation_field)
|
||||||
|
|
||||||
|
stock_queue = []
|
||||||
|
batches = []
|
||||||
|
if prev_sle and prev_sle.stock_queue:
|
||||||
|
batches = frappe.get_all(
|
||||||
|
"Batch",
|
||||||
|
filters={
|
||||||
|
"name": ("in", [d.batch_no for d in self.entries if d.batch_no]),
|
||||||
|
"use_batchwise_valuation": 0,
|
||||||
|
},
|
||||||
|
pluck="name",
|
||||||
|
)
|
||||||
|
|
||||||
|
if batches and valuation_method == "FIFO":
|
||||||
|
stock_queue = parse_json(prev_sle.stock_queue)
|
||||||
|
|
||||||
for d in self.entries:
|
for d in self.entries:
|
||||||
if self.is_rejected:
|
if self.is_rejected:
|
||||||
rate = 0.0
|
rate = 0.0
|
||||||
elif (d.incoming_rate == rate) and d.qty and d.stock_value_difference:
|
elif (d.incoming_rate == rate) and not stock_queue and d.qty and d.stock_value_difference:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
d.incoming_rate = flt(rate)
|
d.incoming_rate = flt(rate)
|
||||||
if d.qty:
|
if d.qty:
|
||||||
d.stock_value_difference = flt(d.qty) * d.incoming_rate
|
d.stock_value_difference = flt(d.qty) * d.incoming_rate
|
||||||
|
|
||||||
|
if stock_queue and valuation_method == "FIFO" and d.batch_no in batches:
|
||||||
|
stock_queue.append([d.qty, d.incoming_rate])
|
||||||
|
d.stock_queue = json.dumps(stock_queue)
|
||||||
|
|
||||||
if save:
|
if save:
|
||||||
d.db_set(
|
d.db_set(
|
||||||
{"incoming_rate": d.incoming_rate, "stock_value_difference": d.stock_value_difference}
|
{
|
||||||
|
"incoming_rate": d.incoming_rate,
|
||||||
|
"stock_value_difference": d.stock_value_difference,
|
||||||
|
"stock_queue": d.get("stock_queue"),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_serial_and_batch_values(self, parent, row, qty_field=None):
|
def set_serial_and_batch_values(self, parent, row, qty_field=None):
|
||||||
|
|||||||
@@ -285,6 +285,25 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
self.assertEqual(flt(sle.stock_value_difference), 1000.00 * -1)
|
self.assertEqual(flt(sle.stock_value_difference), 1000.00 * -1)
|
||||||
self.assertEqual(json.loads(sle.stock_queue), [[20, 200]])
|
self.assertEqual(json.loads(sle.stock_queue), [[20, 200]])
|
||||||
|
|
||||||
|
se = make_stock_entry(
|
||||||
|
item_code=batch_item_code,
|
||||||
|
target="_Test Warehouse - _TC",
|
||||||
|
qty=10,
|
||||||
|
rate=100,
|
||||||
|
batch_no=batch_id,
|
||||||
|
use_serial_batch_fields=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
sle = frappe.db.get_value(
|
||||||
|
"Serial and Batch Entry",
|
||||||
|
{"parent": se.items[0].serial_and_batch_bundle, "docstatus": 1},
|
||||||
|
["stock_value_difference", "stock_queue"],
|
||||||
|
as_dict=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(flt(sle.stock_value_difference), 1000.00)
|
||||||
|
self.assertEqual(json.loads(sle.stock_queue), [[20, 200], [10, 100]])
|
||||||
|
|
||||||
se = make_stock_entry(
|
se = make_stock_entry(
|
||||||
item_code=batch_item_code,
|
item_code=batch_item_code,
|
||||||
target="_Test Warehouse - _TC",
|
target="_Test Warehouse - _TC",
|
||||||
@@ -301,7 +320,7 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(flt(sle.stock_value_difference), 1000.00)
|
self.assertEqual(flt(sle.stock_value_difference), 1000.00)
|
||||||
self.assertEqual(json.loads(sle.stock_queue), [[20, 200]])
|
self.assertEqual(json.loads(sle.stock_queue), [[20, 200], [10, 100]])
|
||||||
|
|
||||||
se = make_stock_entry(
|
se = make_stock_entry(
|
||||||
item_code=batch_item_code,
|
item_code=batch_item_code,
|
||||||
@@ -319,6 +338,24 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertEqual(flt(sle.stock_value_difference), 5000.00 * -1)
|
self.assertEqual(flt(sle.stock_value_difference), 5000.00 * -1)
|
||||||
self.assertFalse(json.loads(sle.stock_queue or "[]"))
|
self.assertFalse(json.loads(sle.stock_queue or "[]"))
|
||||||
|
self.assertEqual(flt(sle.stock_value), 1000.0)
|
||||||
|
|
||||||
|
se = make_stock_entry(
|
||||||
|
item_code=batch_item_code,
|
||||||
|
source="_Test Warehouse - _TC",
|
||||||
|
qty=10,
|
||||||
|
use_serial_batch_fields=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
sle = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"item_code": batch_item_code, "is_cancelled": 0, "voucher_no": se.name},
|
||||||
|
["stock_value_difference", "stock_queue", "stock_value"],
|
||||||
|
as_dict=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(flt(sle.stock_value_difference), 1000.00 * -1)
|
||||||
|
self.assertFalse(json.loads(sle.stock_queue or "[]"))
|
||||||
self.assertEqual(flt(sle.stock_value), 0.0)
|
self.assertEqual(flt(sle.stock_value), 0.0)
|
||||||
|
|
||||||
def test_old_serial_no_valuation(self):
|
def test_old_serial_no_valuation(self):
|
||||||
|
|||||||
@@ -1019,7 +1019,9 @@ class update_entries_after:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
doc = frappe.get_doc("Serial and Batch Bundle", sle.serial_and_batch_bundle)
|
doc = frappe.get_doc("Serial and Batch Bundle", sle.serial_and_batch_bundle)
|
||||||
doc.set_incoming_rate(save=True, allow_negative_stock=self.allow_negative_stock)
|
doc.set_incoming_rate(
|
||||||
|
save=True, allow_negative_stock=self.allow_negative_stock, prev_sle=self.wh_data
|
||||||
|
)
|
||||||
doc.calculate_qty_and_amount(save=True)
|
doc.calculate_qty_and_amount(save=True)
|
||||||
|
|
||||||
if stock_queue := frappe.get_all(
|
if stock_queue := frappe.get_all(
|
||||||
|
|||||||
Reference in New Issue
Block a user