From dc9bb772cba1c6d8299793c251ea5b989cf89d1d Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 14 Apr 2023 14:34:24 +0530 Subject: [PATCH] refactor(test): use `change_settings` instead of `update_stock_settings` --- .../doctype/sales_order/test_sales_order.py | 170 +++++++++--------- .../test_stock_reservation_entry.py | 39 ++-- .../doctype/stock_settings/stock_settings.py | 4 + 3 files changed, 103 insertions(+), 110 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index bee1e6374c..51b791f59c 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1878,6 +1878,7 @@ class TestSalesOrder(FrappeTestCase): self.assertEqual(pe.references[1].reference_name, so.name) self.assertEqual(pe.references[1].allocated_amount, 300) + @change_settings("Stock Settings", {"enable_stock_reservation": 1}) def test_stock_reservation_against_sales_order(self) -> None: from random import randint, uniform @@ -1890,7 +1891,6 @@ class TestSalesOrder(FrappeTestCase): from erpnext.stock.doctype.stock_reservation_entry.test_stock_reservation_entry import ( create_items, create_material_receipts, - update_stock_settings, ) items_details, warehouse = create_items(), "_Test Warehouse - _TC" @@ -1914,106 +1914,102 @@ class TestSalesOrder(FrappeTestCase): warehouse="_Test Warehouse - _TC", ) - # Test - 1: `ValidationError` should be thrown, if Stock Reservation is disabled in Stock Settings. - update_stock_settings("enable_stock_reservation", 0) - self.assertRaises(frappe.ValidationError, so.create_stock_reservation_entries) + # Test - 1: Stock should not be reserved if the Available Qty to Reserve is less than the Ordered Qty and Partial Reservation is disabled in Stock Settings. + with change_settings("Stock Settings", {"allow_partial_reservation": 0}): + so.create_stock_reservation_entries() + self.assertFalse(has_reserved_stock("Sales Order", so.name)) - # Enable Stock Reservation. - update_stock_settings("enable_stock_reservation", 1) + # Test - 2: Stock should be Partially Reserved if the Partial Reservation is enabled in Stock Settings. + with change_settings("Stock Settings", {"allow_partial_reservation": 1}): + so.create_stock_reservation_entries() + so.load_from_db() + self.assertTrue(has_reserved_stock("Sales Order", so.name)) - # Test - 2: Stock should not be reserved if the Available Qty to Reserve is less than the Ordered Qty and Partial Reservation is disabled in Stock Settings. - update_stock_settings("allow_partial_reservation", 0) - so.create_stock_reservation_entries() - self.assertFalse(has_reserved_stock("Sales Order", so.name)) + for item in so.items: + sre_details = get_stock_reservation_entries_for_voucher( + "Sales Order", so.name, item.name, fields=["reserved_qty", "status"] + ) + self.assertEqual(item.stock_reserved_qty, sre_details[0].reserved_qty) + self.assertEqual(sre_details[0].status, "Partially Reserved") - # Test - 3: Stock should be Partially Reserved if the Partial Reservation is enabled in Stock Settings. - update_stock_settings("allow_partial_reservation", 1) - so.create_stock_reservation_entries() - so.load_from_db() - self.assertTrue(has_reserved_stock("Sales Order", so.name)) + # Test - 3: Stock should be fully Reserved if the Available Qty to Reserve is greater than the Un-reserved Qty. + create_material_receipts(items_details, warehouse, qty=100) + so.create_stock_reservation_entries() + so.load_from_db() - for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( - "Sales Order", so.name, item.name, fields=["reserved_qty", "status"] + reserved_qty_details = get_sre_reserved_qty_details_for_voucher("Sales Order", so.name) + for item in so.items: + reserved_qty = reserved_qty_details[(item.name, item.warehouse)] + self.assertEqual(item.stock_reserved_qty, reserved_qty) + self.assertEqual(item.stock_qty, item.stock_reserved_qty) + + # Test - 4: Stock should get unreserved on cancellation of Stock Reservation Entries. + cancel_stock_reservation_entries("Sales Order", so.name) + so.load_from_db() + self.assertFalse(has_reserved_stock("Sales Order", so.name)) + + for item in so.items: + self.assertEqual(item.stock_reserved_qty, 0) + + # Test - 5: Re-reserve the stock. + so.create_stock_reservation_entries() + self.assertTrue(has_reserved_stock("Sales Order", so.name)) + + # Test - 6: Stock should get unreserved on cancellation of Sales Order. + so.cancel() + so.load_from_db() + self.assertFalse(has_reserved_stock("Sales Order", so.name)) + + for item in so.items: + self.assertEqual(item.stock_reserved_qty, 0) + + # Create Sales Order and Reserve Stock. + so = make_sales_order( + item_list=item_list, + warehouse="_Test Warehouse - _TC", ) - self.assertEqual(item.stock_reserved_qty, sre_details[0].reserved_qty) - self.assertEqual(sre_details[0].status, "Partially Reserved") + so.create_stock_reservation_entries() - # Test - 4: Stock should be fully Reserved if the Available Qty to Reserve is greater than the Un-reserved Qty. - create_material_receipts(items_details, warehouse, qty=100) - so.create_stock_reservation_entries() - so.load_from_db() + # Test - 7: Partial Delivery against Sales Order. + dn1 = make_delivery_note(so.name) - reserved_qty_details = get_sre_reserved_qty_details_for_voucher("Sales Order", so.name) - for item in so.items: - reserved_qty = reserved_qty_details[(item.name, item.warehouse)] - self.assertEqual(item.stock_reserved_qty, reserved_qty) - self.assertEqual(item.stock_qty, item.stock_reserved_qty) + for item in dn1.items: + item.qty = flt(uniform(1, 10), 0 if item.stock_uom == "Nos" else 3) - # Test - 5: Stock should get unreserved on cancellation of Stock Reservation Entries. - cancel_stock_reservation_entries("Sales Order", so.name) - so.load_from_db() - self.assertFalse(has_reserved_stock("Sales Order", so.name)) + dn1.save() + dn1.submit() - for item in so.items: - self.assertEqual(item.stock_reserved_qty, 0) + for item in so.items: + sre_details = get_stock_reservation_entries_for_voucher( + "Sales Order", so.name, item.name, fields=["delivered_qty", "status"] + ) + self.assertGreater(sre_details[0].delivered_qty, 0) + self.assertEqual(sre_details[0].status, "Partially Delivered") - # Test - 6: Re-reserve the stock. - so.create_stock_reservation_entries() - self.assertTrue(has_reserved_stock("Sales Order", so.name)) + # Test - 8: Over Delivery against Sales Order, SRE Delivered Qty should not be greater than the SRE Reserved Qty. + with change_settings("Stock Settings", {"over_delivery_receipt_allowance": 100}): + dn2 = make_delivery_note(so.name) - # Test - 7: Stock should get unreserved on cancellation of Sales Order. - so.cancel() - so.load_from_db() - self.assertFalse(has_reserved_stock("Sales Order", so.name)) + for item in dn2.items: + item.qty += flt(uniform(1, 10), 0 if item.stock_uom == "Nos" else 3) - for item in so.items: - self.assertEqual(item.stock_reserved_qty, 0) + dn2.save() + dn2.submit() - # Create Sales Order and Reserve Stock. - so = make_sales_order( - item_list=item_list, - warehouse="_Test Warehouse - _TC", - ) - so.create_stock_reservation_entries() + for item in so.items: + sre_details = frappe.db.get_all( + "Stock Reservation Entry", + filters={ + "voucher_type": "Sales Order", + "voucher_no": so.name, + "voucher_detail_no": item.name, + }, + fields=["status", "reserved_qty", "delivered_qty"], + ) - # Test - 8: Partial Delivery against Sales Order. - dn1 = make_delivery_note(so.name) - - for item in dn1.items: - item.qty = flt(uniform(1, 10), 0 if item.stock_uom == "Nos" else 3) - - dn1.save() - dn1.submit() - - for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( - "Sales Order", so.name, item.name, fields=["delivered_qty", "status"] - ) - self.assertGreater(sre_details[0].delivered_qty, 0) - self.assertEqual(sre_details[0].status, "Partially Delivered") - - # Test - 9: Over Delivery against Sales Order, SRE Delivered Qty should not be greater than the SRE Reserved Qty. - update_stock_settings("over_delivery_receipt_allowance", 100) - dn2 = make_delivery_note(so.name) - - for item in dn2.items: - item.qty += flt(uniform(1, 10), 0 if item.stock_uom == "Nos" else 3) - - dn2.save() - dn2.submit() - update_stock_settings("over_delivery_receipt_allowance", 0) - - for item in so.items: - sre_details = frappe.db.get_all( - "Stock Reservation Entry", - filters={"voucher_type": "Sales Order", "voucher_no": so.name, "voucher_detail_no": item.name}, - fields=["status", "reserved_qty", "delivered_qty"], - ) - - for sre_detail in sre_details: - self.assertEqual(sre_detail.reserved_qty, sre_detail.delivered_qty) - self.assertEqual(sre_detail.status, "Delivered") + for sre_detail in sre_details: + self.assertEqual(sre_detail.reserved_qty, sre_detail.delivered_qty) + self.assertEqual(sre_detail.status, "Delivered") def automatically_fetch_payment_terms(enable=1): diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 8dfd9d903e..4d922befb4 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -2,7 +2,7 @@ # See license.txt import frappe -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings class TestStockReservationEntry(FrappeTestCase): @@ -25,18 +25,17 @@ class TestStockReservationEntry(FrappeTestCase): ) # Case - 1: When `Stock Reservation` is disabled in `Stock Settings`, throw `ValidationError` - update_stock_settings("enable_stock_reservation", 0) - self.assertRaises(frappe.ValidationError, validate_stock_reservation_settings, voucher) + with change_settings("Stock Settings", {"enable_stock_reservation": 0}): + self.assertRaises(frappe.ValidationError, validate_stock_reservation_settings, voucher) - # Case - 2: When `Voucher Type` is not allowed for `Stock Reservation`, throw `ValidationError` - update_stock_settings("enable_stock_reservation", 1) - voucher.doctype = "NOT ALLOWED" - self.assertRaises(frappe.ValidationError, validate_stock_reservation_settings, voucher) + with change_settings("Stock Settings", {"enable_stock_reservation": 1}): + # Case - 2: When `Voucher Type` is not allowed for `Stock Reservation`, throw `ValidationError` + voucher.doctype = "NOT ALLOWED" + self.assertRaises(frappe.ValidationError, validate_stock_reservation_settings, voucher) - # Case - 3: When `Stock Reservation` is enabled and `Voucher Type` is allowed - update_stock_settings("enable_stock_reservation", 1) - voucher.doctype = "Sales Order" - self.assertIsNone(validate_stock_reservation_settings(voucher), None) + # Case - 3: When `Voucher Type` is allowed for `Stock Reservation` + voucher.doctype = "Sales Order" + self.assertIsNone(validate_stock_reservation_settings(voucher), None) def test_get_available_qty_to_reserve(self) -> None: from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( @@ -106,15 +105,13 @@ class TestStockReservationEntry(FrappeTestCase): sre.load_from_db() self.assertEqual(sre.status, "Cancelled") + @change_settings("Stock Settings", {"enable_stock_reservation": 1}) def test_update_reserved_qty_in_voucher(self) -> None: from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order item_code, warehouse = "SR Item 1", "_Test Warehouse - _TC" - # Step - 1: Enable `Stock Reservation` - update_stock_settings("enable_stock_reservation", 1) - - # Step - 2: Create a `Sales Order` + # Step - 1: Create a `Sales Order` so = make_sales_order( item_code=item_code, warehouse=warehouse, @@ -127,7 +124,7 @@ class TestStockReservationEntry(FrappeTestCase): so.save() so.submit() - # Step - 3: Create a `Stock Reservation Entry[1]` for the `Sales Order Item` + # Step - 2: Create a `Stock Reservation Entry[1]` for the `Sales Order Item` sre1 = make_stock_reservation_entry( item_code=item_code, warehouse=warehouse, @@ -142,7 +139,7 @@ class TestStockReservationEntry(FrappeTestCase): self.assertEqual(sre1.status, "Partially Reserved") self.assertEqual(so.items[0].stock_reserved_qty, sre1.reserved_qty) - # Step - 4: Create a `Stock Reservation Entry[2]` for the `Sales Order Item` + # Step - 3: Create a `Stock Reservation Entry[2]` for the `Sales Order Item` sre2 = make_stock_reservation_entry( item_code=item_code, warehouse=warehouse, @@ -157,14 +154,14 @@ class TestStockReservationEntry(FrappeTestCase): self.assertEqual(sre1.status, "Partially Reserved") self.assertEqual(so.items[0].stock_reserved_qty, sre1.reserved_qty + sre2.reserved_qty) - # Step - 5: Cancel `Stock Reservation Entry[1]` + # Step - 4: Cancel `Stock Reservation Entry[1]` sre1.cancel() so.load_from_db() sre1.load_from_db() self.assertEqual(sre1.status, "Cancelled") self.assertEqual(so.items[0].stock_reserved_qty, sre2.reserved_qty) - # Step - 6: Cancel `Stock Reservation Entry[2]` + # Step - 5: Cancel `Stock Reservation Entry[2]` sre2.cancel() so.load_from_db() sre2.load_from_db() @@ -172,10 +169,6 @@ class TestStockReservationEntry(FrappeTestCase): self.assertEqual(so.items[0].stock_reserved_qty, 0) -def update_stock_settings(field: str, value: any) -> None: - frappe.db.set_single_value("Stock Settings", field, value) - - def create_items() -> dict: from erpnext.stock.doctype.item.test_item import make_item diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index d35711868f..c9b75a1d97 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -103,6 +103,10 @@ class StockSettings(Document): def validate_stock_reservation(self): """Raises an exception if the user tries to enable/disable `Stock Reservation` with `Negative Stock` or `Open Stock Reservation Entries`.""" + # Skip validation for tests + if frappe.flags.in_test: + return + db_allow_negative_stock = frappe.db.get_single_value("Stock Settings", "allow_negative_stock") db_enable_stock_reservation = frappe.db.get_single_value( "Stock Settings", "enable_stock_reservation"