mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-21 07:38:29 +00:00
feat: allowing rate modification in update item in quotation
(cherry picked from commit 2ec02e477f)
This commit is contained in:
@@ -34,7 +34,7 @@ class TestPurchaseOrder(IntegrationTestCase):
|
|||||||
self.assertEqual(sq.get("items")[1].rate, 300)
|
self.assertEqual(sq.get("items")[1].rate, 300)
|
||||||
self.assertEqual(sq.get("items")[1].description, "test")
|
self.assertEqual(sq.get("items")[1].description, "test")
|
||||||
|
|
||||||
def test_update_supplier_quotation_child_rate_disallow(self):
|
def test_update_supplier_quotation_child_rate(self):
|
||||||
sq = frappe.copy_doc(self.globalTestRecords["Supplier Quotation"][0])
|
sq = frappe.copy_doc(self.globalTestRecords["Supplier Quotation"][0])
|
||||||
sq.submit()
|
sq.submit()
|
||||||
trans_item = json.dumps(
|
trans_item = json.dumps(
|
||||||
@@ -47,6 +47,22 @@ class TestPurchaseOrder(IntegrationTestCase):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
update_child_qty_rate("Supplier Quotation", trans_item, sq.name)
|
||||||
|
sq.reload()
|
||||||
|
self.assertEqual(sq.get("items")[0].rate, 300)
|
||||||
|
po = make_purchase_order(sq.name)
|
||||||
|
po.schedule_date = add_days(today(), 1)
|
||||||
|
po.submit()
|
||||||
|
trans_item = json.dumps(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"item_code": sq.items[0].item_code,
|
||||||
|
"rate": 20,
|
||||||
|
"qty": sq.items[0].qty,
|
||||||
|
"docname": sq.items[0].name,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
frappe.ValidationError, update_child_qty_rate, "Supplier Quotation", trans_item, sq.name
|
frappe.ValidationError, update_child_qty_rate, "Supplier Quotation", trans_item, sq.name
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3872,20 +3872,28 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
return frappe.db.get_single_value("Buying Settings", "allow_zero_qty_in_purchase_order") or False
|
return frappe.db.get_single_value("Buying Settings", "allow_zero_qty_in_purchase_order") or False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def validate_quantity(child_item, new_data):
|
def validate_quantity_and_rate(child_item, new_data):
|
||||||
if not flt(new_data.get("qty")) and not is_allowed_zero_qty():
|
if not flt(new_data.get("qty")) and not is_allowed_zero_qty():
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("Row #{0}: Quantity for Item {1} cannot be zero.").format(
|
_("Row #{0}:Quantity for Item {1} cannot be zero.").format(
|
||||||
new_data.get("idx"), frappe.bold(new_data.get("item_code"))
|
new_data.get("idx"), frappe.bold(new_data.get("item_code"))
|
||||||
),
|
),
|
||||||
title=_("Invalid Qty"),
|
title=_("Invalid Qty"),
|
||||||
)
|
)
|
||||||
|
|
||||||
if parent_doctype == "Sales Order" and flt(new_data.get("qty")) < flt(child_item.delivered_qty):
|
qty_limits = {
|
||||||
frappe.throw(_("Cannot set quantity less than delivered quantity"))
|
"Sales Order": ("delivered_qty", _("Cannot set quantity less than delivered quantity")),
|
||||||
|
"Purchase Order": ("received_qty", _("Cannot set quantity less than received quantity")),
|
||||||
|
}
|
||||||
|
|
||||||
if parent_doctype == "Purchase Order" and flt(new_data.get("qty")) < flt(child_item.received_qty):
|
if parent_doctype in qty_limits:
|
||||||
frappe.throw(_("Cannot set quantity less than received quantity"))
|
qty_field, error_message = qty_limits[parent_doctype]
|
||||||
|
if flt(new_data.get("qty")) < flt(child_item.get(qty_field)):
|
||||||
|
frappe.throw(
|
||||||
|
_("Row #{0}:").format(new_data.get("idx"))
|
||||||
|
+ error_message.format(frappe.bold(new_data.get("item_code"))),
|
||||||
|
title=_("Invalid Qty"),
|
||||||
|
)
|
||||||
|
|
||||||
if parent_doctype in ["Quotation", "Supplier Quotation"]:
|
if parent_doctype in ["Quotation", "Supplier Quotation"]:
|
||||||
if (parent_doctype == "Quotation" and not ordered_items) or (
|
if (parent_doctype == "Quotation" and not ordered_items) or (
|
||||||
@@ -3898,7 +3906,15 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
if parent_doctype == "Quotation"
|
if parent_doctype == "Quotation"
|
||||||
else purchased_items.get(child_item.name)
|
else purchased_items.get(child_item.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
if qty_to_check:
|
if qty_to_check:
|
||||||
|
if not rate_unchanged:
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Cannot update rate as item {0} is already ordered or purchased against this quotation"
|
||||||
|
).format(frappe.bold(new_data.get("item_code")))
|
||||||
|
)
|
||||||
|
|
||||||
if flt(new_data.get("qty")) < qty_to_check:
|
if flt(new_data.get("qty")) < qty_to_check:
|
||||||
frappe.throw(_("Cannot reduce quantity than ordered or purchased quantity"))
|
frappe.throw(_("Cannot reduce quantity than ordered or purchased quantity"))
|
||||||
|
|
||||||
@@ -4017,10 +4033,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
validate_quantity(child_item, d)
|
validate_quantity_and_rate(child_item, d)
|
||||||
if parent_doctype in ["Quotation", "Supplier Quotation"]:
|
|
||||||
if not rate_unchanged:
|
|
||||||
frappe.throw(_("Rates cannot be modified for quoted items"))
|
|
||||||
|
|
||||||
if flt(child_item.get("qty")) != flt(d.get("qty")):
|
if flt(child_item.get("qty")) != flt(d.get("qty")):
|
||||||
any_qty_changed = True
|
any_qty_changed = True
|
||||||
|
|||||||
@@ -59,8 +59,22 @@ class TestQuotation(IntegrationTestCase):
|
|||||||
qo.payment_schedule[0].due_date = add_days(qo.transaction_date, -2)
|
qo.payment_schedule[0].due_date = add_days(qo.transaction_date, -2)
|
||||||
self.assertRaises(frappe.ValidationError, qo.save)
|
self.assertRaises(frappe.ValidationError, qo.save)
|
||||||
|
|
||||||
def test_update_child_disallow_rate_change(self):
|
def test_update_child_rate_change(self):
|
||||||
qo = make_quotation(qty=4)
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
|
||||||
|
item_1 = make_item("_Test Item")
|
||||||
|
item_2 = make_item("_Test Item 1")
|
||||||
|
|
||||||
|
item_list = [
|
||||||
|
{"item_code": item_1.item_code, "warehouse": "_Test Warehouse - _TC", "qty": 10, "rate": 300},
|
||||||
|
{"item_code": item_2.item_code, "warehouse": "_Test Warehouse - _TC", "qty": 5, "rate": 400},
|
||||||
|
]
|
||||||
|
|
||||||
|
qo = make_quotation(item_list=item_list)
|
||||||
|
so = make_sales_order(qo.name, args={"filtered_children": [qo.items[0].name]})
|
||||||
|
so.delivery_date = nowdate()
|
||||||
|
so.submit()
|
||||||
|
qo.reload()
|
||||||
trans_item = json.dumps(
|
trans_item = json.dumps(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -68,10 +82,35 @@ class TestQuotation(IntegrationTestCase):
|
|||||||
"rate": 5000,
|
"rate": 5000,
|
||||||
"qty": qo.items[0].qty,
|
"qty": qo.items[0].qty,
|
||||||
"docname": qo.items[0].name,
|
"docname": qo.items[0].name,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"item_code": qo.items[1].item_code,
|
||||||
|
"rate": qo.items[1].rate,
|
||||||
|
"qty": qo.items[1].qty,
|
||||||
|
"docname": qo.items[1].name,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate, "Quotation", trans_item, qo.name)
|
self.assertRaises(frappe.ValidationError, update_child_qty_rate, "Quotation", trans_item, qo.name)
|
||||||
|
trans_item = json.dumps(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"item_code": qo.items[0].item_code,
|
||||||
|
"rate": qo.items[0].rate,
|
||||||
|
"qty": qo.items[0].qty,
|
||||||
|
"docname": qo.items[0].name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_code": qo.items[1].item_code,
|
||||||
|
"rate": 50,
|
||||||
|
"qty": qo.items[1].qty,
|
||||||
|
"docname": qo.items[1].name,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
update_child_qty_rate("Quotation", trans_item, qo.name)
|
||||||
|
qo.reload()
|
||||||
|
self.assertEqual(qo.items[1].rate, 50)
|
||||||
|
|
||||||
def test_update_child_removing_item(self):
|
def test_update_child_removing_item(self):
|
||||||
qo = make_quotation(qty=10)
|
qo = make_quotation(qty=10)
|
||||||
|
|||||||
Reference in New Issue
Block a user