diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index e661d8afbf4..7f387eea690 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -279,7 +279,7 @@ class SellingController(StockController):
_(
"""Row #{0}: Selling rate for item {1} is lower than its {2}.
Selling {3} should be atleast {4}.
Alternatively,
- you can disable selling price validation in {5} to bypass
+ you can disable '{5}' in {6} to bypass
this validation."""
).format(
idx,
@@ -287,7 +287,8 @@ class SellingController(StockController):
bold(ref_rate_field),
bold("net rate"),
bold(rate),
- get_link_to_form("Selling Settings", "Selling Settings"),
+ bold(frappe.get_meta("Selling Settings").get_label("validate_selling_price")),
+ get_link_to_form("Selling Settings"),
),
title=_("Invalid Selling Price"),
)
@@ -298,7 +299,6 @@ class SellingController(StockController):
return
is_internal_customer = self.get("is_internal_customer")
- valuation_rate_map = {}
for item in self.items:
if not item.item_code or item.is_free_item:
@@ -308,7 +308,9 @@ class SellingController(StockController):
"Item", item.item_code, ("last_purchase_rate", "is_stock_item")
)
- last_purchase_rate_in_sales_uom = last_purchase_rate * (item.conversion_factor or 1)
+ last_purchase_rate_in_sales_uom = flt(
+ last_purchase_rate * (item.conversion_factor or 1), item.precision("base_net_rate")
+ )
if flt(item.base_net_rate) < flt(last_purchase_rate_in_sales_uom):
throw_message(item.idx, item.item_name, last_purchase_rate_in_sales_uom, "last purchase rate")
@@ -316,50 +318,16 @@ class SellingController(StockController):
if is_internal_customer or not is_stock_item:
continue
- valuation_rate_map[(item.item_code, item.warehouse)] = None
-
- if not valuation_rate_map:
- return
-
- or_conditions = (
- f"""(item_code = {frappe.db.escape(valuation_rate[0])}
- and warehouse = {frappe.db.escape(valuation_rate[1])})"""
- for valuation_rate in valuation_rate_map
- )
-
- valuation_rates = frappe.db.sql(
- f"""
- select
- item_code, warehouse, valuation_rate
- from
- `tabBin`
- where
- ({" or ".join(or_conditions)})
- and valuation_rate > 0
- """,
- as_dict=True,
- )
-
- for rate in valuation_rates:
- valuation_rate_map[(rate.item_code, rate.warehouse)] = rate.valuation_rate
-
- for item in self.items:
- if not item.item_code or item.is_free_item:
- continue
-
- last_valuation_rate = valuation_rate_map.get((item.item_code, item.warehouse))
-
- if not last_valuation_rate:
- continue
-
- last_valuation_rate_in_sales_uom = last_valuation_rate * (item.conversion_factor or 1)
-
- if flt(item.base_net_rate) < flt(last_valuation_rate_in_sales_uom):
+ if item.get("incoming_rate") and item.base_net_rate < (
+ valuation_rate := flt(
+ item.incoming_rate * (item.conversion_factor or 1), item.precision("base_net_rate")
+ )
+ ):
throw_message(
item.idx,
item.item_name,
- last_valuation_rate_in_sales_uom,
- "valuation rate (Moving Average)",
+ valuation_rate,
+ "valuation rate",
)
def get_item_list(self):
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 29eabe2670e..65cc37cff88 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -2807,6 +2807,84 @@ class TestDeliveryNote(FrappeTestCase):
frappe.db.set_single_value("System Settings", "float_precision", original_flt_precision)
+<<<<<<< HEAD
+=======
+ def test_different_rate_for_same_serial_nos(self):
+ item_code = make_item(
+ "Test Different Rate Serial No Item",
+ properties={"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "DRSN-.#####"},
+ ).name
+
+ se = make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1, basic_rate=100)
+ serial_nos = get_serial_nos_from_bundle(se.items[0].serial_and_batch_bundle)
+
+ dn = create_delivery_note(
+ item_code=item_code,
+ qty=1,
+ rate=300,
+ use_serial_batch_fields=1,
+ serial_no="\n".join(serial_nos),
+ )
+
+ dn.reload()
+
+ sabb = frappe.get_doc("Serial and Batch Bundle", dn.items[0].serial_and_batch_bundle)
+ for entry in sabb.entries:
+ self.assertEqual(entry.incoming_rate, 100)
+
+ make_stock_entry(
+ item_code=item_code,
+ target="_Test Warehouse - _TC",
+ qty=1,
+ basic_rate=200,
+ use_serial_batch_fields=1,
+ serial_no="\n".join(serial_nos),
+ )
+ dn1 = create_delivery_note(
+ item_code=item_code,
+ qty=1,
+ rate=300,
+ use_serial_batch_fields=1,
+ serial_no="\n".join(serial_nos),
+ )
+
+ dn1.reload()
+
+ sabb = frappe.get_doc("Serial and Batch Bundle", dn1.items[0].serial_and_batch_bundle)
+ for entry in sabb.entries:
+ self.assertEqual(entry.incoming_rate, 200)
+
+ doc = frappe.new_doc("Repost Item Valuation")
+ doc.voucher_type = "Stock Entry"
+ doc.voucher_no = se.name
+ doc.submit()
+
+ sabb = frappe.get_doc("Serial and Batch Bundle", dn.items[0].serial_and_batch_bundle)
+ for entry in sabb.entries:
+ self.assertEqual(entry.incoming_rate, 100)
+
+ sabb = frappe.get_doc("Serial and Batch Bundle", dn1.items[0].serial_and_batch_bundle)
+ for entry in sabb.entries:
+ self.assertEqual(entry.incoming_rate, 200)
+
+ @IntegrationTestCase.change_settings("Selling Settings", {"validate_selling_price": 1})
+ def test_validate_selling_price(self):
+ item_code = make_item("VSP Item", properties={"is_stock_item": 1}).name
+ make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1, basic_rate=10)
+ make_stock_entry(item_code=item_code, target="_Test Warehouse - _TC", qty=1, basic_rate=1)
+
+ dn = create_delivery_note(
+ item_code=item_code,
+ qty=1,
+ rate=9,
+ do_not_save=True,
+ )
+ self.assertRaises(frappe.ValidationError, dn.save)
+ dn.items[0].incoming_rate = 0
+ dn.items[0].stock_qty = 2
+ dn.save()
+
+>>>>>>> 135a433018 (Merge pull request #52246 from mihir-kandoi/st58765)
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")