From a5d8d3277560c794377a2449e534a1354dfba9a3 Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 9 Dec 2020 16:27:18 +0530 Subject: [PATCH] chore: Test and fixes - Tests as per new design flow - Fixed duplicate data bug in Warehouse Capacity Summary - Set Amount currently on applying rule in client side - Apply rules on server side before validate --- erpnext/public/js/controllers/transaction.js | 3 +- erpnext/stock/dashboard/item_dashboard.js | 2 +- .../purchase_receipt/purchase_receipt.py | 2 +- .../purchase_receipt/test_purchase_receipt.py | 2 + .../doctype/putaway_rule/test_putaway_rule.py | 135 +++++++++--------- .../stock/doctype/stock_entry/stock_entry.py | 2 +- 6 files changed, 72 insertions(+), 74 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 31efb6aa34..54634482b0 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2050,9 +2050,10 @@ erpnext.apply_putaway_rule = (frm) => { let items = result.message; items.forEach((row) => { - delete row["name"]; + delete row["name"]; // dont overwrite name from server side let child = frm.add_child("items"); Object.assign(child, row); + frm.script_manager.trigger("qty", child.doctype, child.name); }); frm.get_field("items").grid.refresh(); } diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 070589b3dc..20415bc07e 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -69,7 +69,7 @@ erpnext.stock.ItemDashboard = Class.extend({ // more this.content.find('.btn-more').on('click', function() { - me.start += this.page_length; + me.start += me.page_length; me.refresh(); }); diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 4372bdcc59..d36d5159db 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -83,7 +83,7 @@ class PurchaseReceipt(BuyingController): } ]) - def before_save(self): + def before_validate(self): from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule if self.get("items") and self.apply_putaway_rule: diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 9b8eeed1a1..7b3a83065b 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -979,6 +979,7 @@ def make_purchase_receipt(**args): pr.currency = args.currency or "INR" pr.is_return = args.is_return pr.return_against = args.return_against + pr.apply_putaway_rule = args.apply_putaway_rule qty = args.qty or 5 received_qty = args.received_qty or qty rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty) @@ -994,6 +995,7 @@ def make_purchase_receipt(**args): "rejected_warehouse": args.rejected_warehouse or "_Test Rejected Warehouse - _TC" if rejected_qty != 0 else "", "rate": args.rate if args.rate != None else 50, "conversion_factor": args.conversion_factor or 1.0, + "stock_qty": flt(qty) * (flt(args.conversion_factor) or 1.0), "serial_no": args.serial_no, "stock_uom": args.stock_uom or "_Test UOM", "uom": uom, diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py index 7b81784d5f..17619e01bc 100644 --- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py @@ -9,8 +9,8 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt class TestPutawayRule(unittest.TestCase): def setUp(self): @@ -42,17 +42,15 @@ class TestPutawayRule(unittest.TestCase): rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=300, uom="Kg", priority=2) - po = create_purchase_order(item_code="_Rice", qty=300) - self.assertEqual(len(po.items), 1) - - pr = make_purchase_receipt(po.name) + pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1, + do_not_submit=1) self.assertEqual(len(pr.items), 2) self.assertEqual(pr.items[0].qty, 200) self.assertEqual(pr.items[0].warehouse, warehouse_1) self.assertEqual(pr.items[1].qty, 100) self.assertEqual(pr.items[1].warehouse, warehouse_2) - po.cancel() + pr.delete() rule_1.delete() rule_2.delete() @@ -70,10 +68,8 @@ class TestPutawayRule(unittest.TestCase): # out of 500 kg capacity, occupy 100 kg in warehouse_1 stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=100, basic_rate=50) - po = create_purchase_order(item_code="_Rice", qty=700) - self.assertEqual(len(po.items), 1) - - pr = make_purchase_receipt(po.name) + pr = make_purchase_receipt(item_code="_Rice", qty=700, apply_putaway_rule=1, + do_not_submit=1) self.assertEqual(len(pr.items), 2) self.assertEqual(pr.items[0].qty, 500) # warehouse_2 has 500 kg free space, it is given priority @@ -82,8 +78,8 @@ class TestPutawayRule(unittest.TestCase): # warehouse_1 has 400 kg free space, it is given less priority self.assertEqual(pr.items[1].warehouse, warehouse_1) - po.cancel() stock_receipt.cancel() + pr.delete() rule_1.delete() rule_2.delete() @@ -97,21 +93,14 @@ class TestPutawayRule(unittest.TestCase): rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=200, uom="Kg") - po = create_purchase_order(item_code="_Rice", qty=350) - self.assertEqual(len(po.items), 1) - - pr = make_purchase_receipt(po.name) - - self.assertEqual(len(pr.items), 3) + pr = make_purchase_receipt(item_code="_Rice", qty=350, apply_putaway_rule=1, + do_not_submit=1) + self.assertEqual(len(pr.items), 2) self.assertEqual(pr.items[0].qty, 200) self.assertEqual(pr.items[0].warehouse, warehouse_2) self.assertEqual(pr.items[1].qty, 100) self.assertEqual(pr.items[1].warehouse, warehouse_1) - # extra qty has no warehouse assigned - self.assertEqual(pr.items[2].qty, 50) - self.assertEqual(pr.items[2].warehouse, '') - - po.cancel() + pr.delete() rule_1.delete() rule_2.delete() @@ -135,24 +124,19 @@ class TestPutawayRule(unittest.TestCase): uom="Bag") self.assertEqual(rule_2.stock_capacity, 4000) + # populate 'Rack 1' with 1 Bag, making the free space 2 Bags stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=1000, basic_rate=50) - po = create_purchase_order(item_code="_Rice", qty=6, do_not_save=True) - po.items[0].uom = "Bag" - po.save() - po.submit() - - self.assertEqual(po.items[0].stock_qty, 6000) - - pr = make_purchase_receipt(po.name) + pr = make_purchase_receipt(item_code="_Rice", qty=6, uom="Bag", stock_uom="Kg", + conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1) self.assertEqual(len(pr.items), 2) self.assertEqual(pr.items[0].qty, 4) self.assertEqual(pr.items[0].warehouse, warehouse_2) self.assertEqual(pr.items[1].qty, 2) self.assertEqual(pr.items[1].warehouse, warehouse_1) - po.cancel() stock_receipt.cancel() + pr.delete() rule_1.delete() rule_2.delete() @@ -180,24 +164,15 @@ class TestPutawayRule(unittest.TestCase): self.assertEqual(rule_2.stock_capacity, 500) # total capacity is 1500 Kg - po = create_purchase_order(item_code="_Rice", qty=2, do_not_save=True) - # PO for 2 Bags (2000 Kg) - po.items[0].uom = "Bag" - po.save() - po.submit() - - self.assertEqual(po.items[0].stock_qty, 2000) - - pr = make_purchase_receipt(po.name) - self.assertEqual(len(pr.items), 2) + pr = make_purchase_receipt(item_code="_Rice", qty=2, uom="Bag", stock_uom="Kg", + conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1) + self.assertEqual(len(pr.items), 1) self.assertEqual(pr.items[0].qty, 1) self.assertEqual(pr.items[0].warehouse, warehouse_1) # leftover space was for 500 kg (0.5 Bag) # Since Bag is a whole UOM, 1(out of 2) Bag will be unassigned - self.assertEqual(pr.items[1].qty, 1) - self.assertEqual(pr.items[1].warehouse, '') - po.cancel() + pr.delete() rule_1.delete() rule_2.delete() @@ -208,38 +183,58 @@ class TestPutawayRule(unittest.TestCase): rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200, uom="Kg") - rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=100, - uom="Kg", priority=2) - # total capacity is 300 Kg + # total capacity is 200 Kg - po = create_purchase_order(item_code="_Rice", qty=200, rate=100, do_not_save=True) - po.append("items", { - "item_code":"_Rice", + pr = make_purchase_receipt(item_code="_Rice", qty=100, apply_putaway_rule=1, + do_not_submit=1) + pr.append("items", { + "item_code": "_Rice", "warehouse": "_Test Warehouse - _TC", - "qty": 300, - "rate": 120, - "schedule_date": add_days(nowdate(), 1), - }) - po.save() - po.submit() - # PO for 500 Kg (two rows of same item, different rates) - self.assertEqual(len(po.items), 2) - - pr = make_purchase_receipt(po.name) - self.assertEqual(len(pr.items), 3) - self.assertEqual(pr.items[0].qty, 200) + "qty": 200, + "uom": "Kg", + "stock_uom": "Kg", + "stock_qty": 200, + "received_qty": 200, + "rate": 100, + "conversion_factor": 1.0, + }) # same item entered again in PR but with different rate + pr.save() + self.assertEqual(len(pr.items), 2) + self.assertEqual(pr.items[0].qty, 100) self.assertEqual(pr.items[0].warehouse, warehouse_1) - # same rules applied to second item row + self.assertEqual(pr.items[0].putaway_rule, rule_1.name) + # same rule applied to second item row # with previous assignment considered - self.assertEqual(pr.items[1].qty, 100) - self.assertEqual(pr.items[1].warehouse, warehouse_2) - # unassigned 200 Kg - self.assertEqual(pr.items[2].qty, 200) - self.assertEqual(pr.items[2].warehouse, '') + self.assertEqual(pr.items[1].qty, 100) # 100 unassigned in second row from 200 + self.assertEqual(pr.items[1].warehouse, warehouse_1) + self.assertEqual(pr.items[1].putaway_rule, rule_1.name) - po.cancel() + pr.delete() + rule_1.delete() + + def test_validate_over_receipt_in_warehouse(self): + """Test if overreceipt is blocked in the presence of putaway rules.""" + warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"}) + warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"}) + + rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200, + uom="Kg") + + pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1, + do_not_submit=1) + self.assertEqual(len(pr.items), 1) + self.assertEqual(pr.items[0].qty, 200) # 100 is unassigned fro 300 Kg + self.assertEqual(pr.items[0].warehouse, warehouse_1) + self.assertEqual(pr.items[0].putaway_rule, rule_1.name) + + # force overreceipt and disable apply putaway rule in PR + pr.items[0].qty = 300 + pr.items[0].stock_qty = 300 + pr.apply_putaway_rule = 0 + self.assertRaises(frappe.ValidationError, pr.save) + + pr.delete() rule_1.delete() - rule_2.delete() def create_putaway_rule(**args): args = frappe._dict(args) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index f07039f564..aed69e11dd 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -42,7 +42,7 @@ class StockEntry(StockController): for item in self.get("items"): item.update(get_bin_details(item.item_code, item.s_warehouse)) - def before_save(self): + def before_validate(self): from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule apply_rule = self.apply_putaway_rule and (self.purpose in ["Material Transfer", "Material Receipt"])