test: add test cases for SRE

This commit is contained in:
s-aga-r 2023-04-09 08:28:10 +05:30
parent ac24d778e8
commit a918adaa33

View File

@ -1,9 +1,251 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import frappe
from frappe.tests.utils import FrappeTestCase
class TestStockReservationEntry(FrappeTestCase):
pass
def setUp(self) -> None:
self.items = create_items()
create_material_receipts(self.items)
def tearDown(self) -> None:
return super().tearDown()
def test_validate_stock_reservation_settings(self) -> None:
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
validate_stock_reservation_settings,
)
voucher = frappe._dict(
{
"doctype": "Sales Order",
}
)
# 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)
# 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)
# 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)
def test_get_available_qty_to_reserve(self) -> None:
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
get_available_qty_to_reserve,
)
from erpnext.stock.utils import get_stock_balance
item_code, warehouse = "SR Item 1", "_Test Warehouse - _TC"
# Case - 1: When `Reserved Qty` is `0`, Available Qty to Reserve = Actual Qty
cancel_all_stock_reservation_entries()
available_qty_to_reserve = get_available_qty_to_reserve(item_code, warehouse)
expected_available_qty_to_reserve = get_stock_balance(item_code, warehouse)
self.assertEqual(available_qty_to_reserve, expected_available_qty_to_reserve)
# Case - 2: When `Reserved Qty` is `> 0`, Available Qty to Reserve = Actual Qty - Reserved Qty
sre = make_stock_reservation_entry(
item_code=item_code,
warehouse=warehouse,
ignore_validate=True,
)
available_qty_to_reserve = get_available_qty_to_reserve(item_code, warehouse)
expected_available_qty_to_reserve = get_stock_balance(item_code, warehouse) - sre.reserved_qty
self.assertEqual(available_qty_to_reserve, expected_available_qty_to_reserve)
def test_update_status(self) -> None:
sre = make_stock_reservation_entry(
reserved_qty=30,
ignore_validate=True,
do_not_submit=True,
)
# Draft: When DocStatus is `0`
sre.load_from_db()
self.assertEqual(sre.status, "Draft")
# Partially Reserved: When DocStatus is `1` and `Reserved Qty` < `Voucher Qty`
sre.submit()
sre.load_from_db()
self.assertEqual(sre.status, "Partially Reserved")
# Reserved: When DocStatus is `1` and `Reserved Qty` = `Voucher Qty`
sre.reserved_qty = sre.voucher_qty
sre.db_update()
sre.update_status()
sre.load_from_db()
self.assertEqual(sre.status, "Reserved")
# Partially Delivered: When DocStatus is `1` and (0 < `Delivered Qty` < `Voucher Qty`)
sre.delivered_qty = 10
sre.db_update()
sre.update_status()
sre.load_from_db()
self.assertEqual(sre.status, "Partially Delivered")
# Delivered: When DocStatus is `1` and `Delivered Qty` = `Voucher Qty`
sre.delivered_qty = sre.voucher_qty
sre.db_update()
sre.update_status()
sre.load_from_db()
self.assertEqual(sre.status, "Delivered")
# Cancelled: When DocStatus is `2`
sre.cancel()
sre.load_from_db()
self.assertEqual(sre.status, "Cancelled")
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`
so = make_sales_order(
item_code=item_code,
warehouse=warehouse,
qty=50,
rate=100,
do_not_submit=True,
)
so.reserve_stock = 0 # Stock Reservation Entries won't be created on submit
so.items[0].reserve_stock = 1
so.save()
so.submit()
# Step - 3: Create a `Stock Reservation Entry[1]` for the `Sales Order Item`
sre1 = make_stock_reservation_entry(
item_code=item_code,
warehouse=warehouse,
voucher_type="Sales Order",
voucher_no=so.name,
voucher_detail_no=so.items[0].name,
reserved_qty=30,
)
so.load_from_db()
sre1.load_from_db()
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`
sre2 = make_stock_reservation_entry(
item_code=item_code,
warehouse=warehouse,
voucher_type="Sales Order",
voucher_no=so.name,
voucher_detail_no=so.items[0].name,
reserved_qty=20,
)
so.load_from_db()
sre2.load_from_db()
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]`
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]`
sre2.cancel()
so.load_from_db()
sre2.load_from_db()
self.assertEqual(sre1.status, "Cancelled")
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
items_details = {
# Stock Items
"SR Item 1": {"is_stock_item": 1, "valuation_rate": 100},
"SR Item 2": {"is_stock_item": 1, "valuation_rate": 200, "stock_uom": "Kg"},
# Batch Items
"SR Batch Item 1": {"is_stock_item": 1, "valuation_rate": 100},
"SR Batch Item 2": {"is_stock_item": 1, "valuation_rate": 200, "stock_uom": "Kg"},
# Serial Items
"SR Serial Item 1": {"is_stock_item": 1, "valuation_rate": 100},
"SR Serial Item 2": {"is_stock_item": 1, "valuation_rate": 200, "stock_uom": "Kg"},
# Batch and Serial Items
"SR Batch and Serial Item 1": {"is_stock_item": 1, "valuation_rate": 100},
"SR Batch and Serial Item 2": {"is_stock_item": 1, "valuation_rate": 200, "stock_uom": "Kg"},
}
items = {}
for item_code, properties in items_details.items():
items[item_code] = make_item(item_code, properties)
return items
def create_material_receipts(
items: dict, warehouse: str = "_Test Warehouse - _TC", qty: float = 100
) -> None:
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
for item in items.values():
if item.is_stock_item:
make_stock_entry(
item_code=item.item_code,
qty=qty,
to_warehouse=warehouse,
rate=item.valuation_rate,
purpose="Material Receipt",
)
def cancel_all_stock_reservation_entries() -> None:
sre_list = frappe.db.get_all("Stock Reservation Entry", filters={"docstatus": 1}, pluck="name")
for sre in sre_list:
frappe.get_doc("Stock Reservation Entry", sre).cancel()
def make_stock_reservation_entry(**args):
doc = frappe.new_doc("Stock Reservation Entry")
args = frappe._dict(args)
doc.item_code = args.item_code or "SR Item 1"
doc.warehouse = args.warehouse or "_Test Warehouse - _TC"
doc.voucher_type = args.voucher_type
doc.voucher_no = args.voucher_no
doc.voucher_detail_no = args.voucher_detail_no
doc.available_qty = args.available_qty or 100
doc.voucher_qty = args.voucher_qty or 50
doc.stock_uom = args.stock_uom or "Nos"
doc.reserved_qty = args.reserved_qty or 50
doc.delivered_qty = args.delivered_qty or 0
doc.company = args.company or "_Test Company"
if args.ignore_validate:
doc.flags.ignore_validate = True
if not args.do_not_save:
doc.save()
if not args.do_not_submit:
doc.submit()
return doc