test: add test cases for SRE
This commit is contained in:
parent
ac24d778e8
commit
a918adaa33
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user