mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-14 23:18:40 +00:00
fix(controllers): correct negative rate settings link
(cherry picked from commit 4089f138f2)
This commit is contained in:
@@ -54,19 +54,28 @@ class TestPurchaseOrder(ERPNextTestSuite):
|
|||||||
po.save()
|
po.save()
|
||||||
self.assertEqual(po.items[1].qty, 1)
|
self.assertEqual(po.items[1].qty, 1)
|
||||||
|
|
||||||
def test_purchase_order_negative_grand_total_blocked_by_default(self):
|
@ERPNextTestSuite.change_settings("Buying Settings", {"allow_negative_rates_for_items": 0})
|
||||||
|
def test_purchase_order_negative_grand_total_blocked_without_setting(self):
|
||||||
po = create_purchase_order(qty=1, rate=100, do_not_save=True)
|
po = create_purchase_order(qty=1, rate=100, do_not_save=True)
|
||||||
po.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150, "schedule_date": nowdate()})
|
po.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150, "schedule_date": nowdate()})
|
||||||
self.assertRaises(frappe.ValidationError, po.save)
|
self.assertRaises(frappe.ValidationError, po.save)
|
||||||
|
|
||||||
@ERPNextTestSuite.change_settings("Buying Settings", {"allow_negative_rates_for_items": 1})
|
@ERPNextTestSuite.change_settings("Buying Settings", {"allow_negative_rates_for_items": 1})
|
||||||
def test_purchase_order_negative_grand_total_allowed_with_setting(self):
|
def test_purchase_order_negative_grand_total_allowed_with_setting(self):
|
||||||
"""A supplier change order can net to a negative grand total (credit owed)."""
|
"""Use a negative rate to represent a credit while order quantities remain positive."""
|
||||||
po = create_purchase_order(qty=1, rate=100, do_not_save=True)
|
po = create_purchase_order(qty=1, rate=100, do_not_save=True)
|
||||||
po.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150, "schedule_date": nowdate()})
|
po.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150, "schedule_date": nowdate()})
|
||||||
po.save()
|
po.save()
|
||||||
|
po.submit()
|
||||||
|
self.assertEqual(po.docstatus, 1)
|
||||||
self.assertTrue(po.base_grand_total < 0)
|
self.assertTrue(po.base_grand_total < 0)
|
||||||
|
|
||||||
|
@ERPNextTestSuite.change_settings("Buying Settings", {"allow_negative_rates_for_items": 1})
|
||||||
|
def test_purchase_order_negative_rate_setting_does_not_allow_negative_quantity(self):
|
||||||
|
po = create_purchase_order(qty=1, rate=100, do_not_save=True)
|
||||||
|
po.append("items", {"item_code": "_Test Item 2", "qty": -1, "rate": 100})
|
||||||
|
self.assertRaises(frappe.ValidationError, po.save)
|
||||||
|
|
||||||
def test_purchase_order_zero_qty(self):
|
def test_purchase_order_zero_qty(self):
|
||||||
po = create_purchase_order(qty=0, do_not_save=True)
|
po = create_purchase_order(qty=0, do_not_save=True)
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,9 @@ class StatusUpdater(Document):
|
|||||||
|
|
||||||
def validate_qty(self):
|
def validate_qty(self):
|
||||||
"""Validates qty at row level"""
|
"""Validates qty at row level"""
|
||||||
|
selling_doctypes = ("Sales Order", "Sales Invoice", "Delivery Note")
|
||||||
|
buying_doctypes = ("Purchase Order", "Purchase Invoice", "Purchase Receipt")
|
||||||
|
|
||||||
for args in self.status_updater:
|
for args in self.status_updater:
|
||||||
if "target_ref_field" not in args or args.get("validate_qty") is False:
|
if "target_ref_field" not in args or args.get("validate_qty") is False:
|
||||||
# if target_ref_field is not specified or validate_qty is explicitly set to False, skip validation
|
# if target_ref_field is not specified or validate_qty is explicitly set to False, skip validation
|
||||||
@@ -291,12 +294,8 @@ class StatusUpdater(Document):
|
|||||||
if hasattr(d, "qty") and flt(d.qty) > 0 and self.get("is_return"):
|
if hasattr(d, "qty") and flt(d.qty) > 0 and self.get("is_return"):
|
||||||
frappe.throw(_("For an item {0}, quantity must be negative number").format(d.item_code))
|
frappe.throw(_("For an item {0}, quantity must be negative number").format(d.item_code))
|
||||||
|
|
||||||
if (
|
if (not selling_negative_rate_allowed and self.doctype in selling_doctypes) or (
|
||||||
not selling_negative_rate_allowed
|
not buying_negative_rate_allowed and self.doctype in buying_doctypes
|
||||||
and self.doctype in ["Sales Order", "Sales Invoice", "Delivery Note"]
|
|
||||||
) or (
|
|
||||||
not buying_negative_rate_allowed
|
|
||||||
and self.doctype in ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
|
|
||||||
):
|
):
|
||||||
if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0:
|
if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0:
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
@@ -307,7 +306,7 @@ class StatusUpdater(Document):
|
|||||||
frappe.bold(_("`Allow Negative rates for Items`")),
|
frappe.bold(_("`Allow Negative rates for Items`")),
|
||||||
get_link_to_form(
|
get_link_to_form(
|
||||||
"Selling Settings"
|
"Selling Settings"
|
||||||
if self.doctype in ["Sales Invoice", "Delivery Note"]
|
if self.doctype in selling_doctypes
|
||||||
else "Buying Settings"
|
else "Buying Settings"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -157,19 +157,38 @@ class TestSalesOrder(ERPNextTestSuite):
|
|||||||
)
|
)
|
||||||
update_child_qty_rate("Sales Order", trans_item, so.name)
|
update_child_qty_rate("Sales Order", trans_item, so.name)
|
||||||
|
|
||||||
def test_sales_order_negative_grand_total_blocked_by_default(self):
|
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_negative_rates_for_items": 0})
|
||||||
|
def test_sales_order_negative_grand_total_blocked_without_setting(self):
|
||||||
so = make_sales_order(qty=1, rate=100, do_not_save=True)
|
so = make_sales_order(qty=1, rate=100, do_not_save=True)
|
||||||
so.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150})
|
so.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150})
|
||||||
self.assertRaises(frappe.ValidationError, so.save)
|
self.assertRaises(frappe.ValidationError, so.save)
|
||||||
|
|
||||||
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_negative_rates_for_items": 1})
|
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_negative_rates_for_items": 1})
|
||||||
def test_sales_order_negative_grand_total_allowed_with_setting(self):
|
def test_sales_order_negative_grand_total_allowed_with_setting(self):
|
||||||
"""A subscription downgrade / change order can net to a negative grand total."""
|
"""Use a negative rate to represent a credit while order quantities remain positive."""
|
||||||
so = make_sales_order(qty=1, rate=100, do_not_save=True)
|
so = make_sales_order(qty=1, rate=100, do_not_save=True)
|
||||||
so.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150})
|
so.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -150})
|
||||||
so.save()
|
so.save()
|
||||||
|
so.submit()
|
||||||
|
self.assertEqual(so.docstatus, 1)
|
||||||
self.assertTrue(so.base_grand_total < 0)
|
self.assertTrue(so.base_grand_total < 0)
|
||||||
|
|
||||||
|
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_negative_rates_for_items": 0})
|
||||||
|
def test_sales_order_negative_rate_error_links_to_selling_settings(self):
|
||||||
|
so = make_sales_order(qty=1, rate=100, do_not_save=True)
|
||||||
|
so.append("items", {"item_code": "_Test Item 2", "qty": 1, "rate": -10})
|
||||||
|
so.save()
|
||||||
|
|
||||||
|
with self.assertRaises(frappe.ValidationError) as error:
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
self.assertIn("selling-settings", str(error.exception))
|
||||||
|
|
||||||
|
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_negative_rates_for_items": 1})
|
||||||
|
def test_sales_order_negative_rate_setting_does_not_allow_negative_quantity(self):
|
||||||
|
so = make_sales_order(qty=-1, rate=100, do_not_save=True)
|
||||||
|
self.assertRaises(frappe.NonNegativeError, so.save)
|
||||||
|
|
||||||
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_multiple_items": 1})
|
@ERPNextTestSuite.change_settings("Selling Settings", {"allow_multiple_items": 1})
|
||||||
def test_sales_order_qty(self):
|
def test_sales_order_qty(self):
|
||||||
so = make_sales_order(qty=1, do_not_save=True)
|
so = make_sales_order(qty=1, do_not_save=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user