Merge pull request #59158 from frappe/mergify/bp/version-15-hotfix/pr-59155

fix(stock): continue putaway allocation after undersized whole-uom rules (backport #59155)
This commit is contained in:
Sudharsanan Ashok
2026-09-18 15:16:10 +05:30
committed by GitHub
2 changed files with 45 additions and 3 deletions

View File

@@ -10,6 +10,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, cstr, floor, flt, nowdate
from pydantic import InstanceOf
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.utils import get_stock_balance
@@ -100,10 +101,17 @@ def get_available_putaway_capacity(rule):
@frappe.whitelist()
def apply_putaway_rule(doctype, items, company, sync=None, purpose=None):
def apply_putaway_rule(
doctype: str,
items: InstanceOf[list] | str,
company: str,
sync: str | bool | None = None,
purpose: str | None = None,
):
"""Applies Putaway Rule on line items.
items: List of Purchase Receipt/Stock Entry Items
items: List of Purchase Receipt/Stock Entry Items, updated in place.
InstanceOf preserves the caller's list during argument validation.
company: Company in the Purchase Receipt/Stock Entry
doctype: Doctype to apply rule on
purpose: Purpose of Stock Entry
@@ -172,7 +180,7 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None):
stock_qty_to_allocate = qty_to_allocate * item.conversion_factor
if not qty_to_allocate:
break
continue
updated_table = add_row(
item, qty_to_allocate, rule.warehouse, updated_table, rule.name, serial_nos=serial_nos

View File

@@ -181,6 +181,40 @@ class TestPutawayRule(FrappeTestCase):
rule_1.delete()
rule_2.delete()
def test_putaway_rules_skip_undersized_whole_uom_rule(self):
item = frappe.get_doc("Item", "_Rice")
if not frappe.db.get_value("UOM Conversion Detail", {"parent": item.name, "uom": "Bag"}):
item.append("uoms", {"uom": "Bag", "conversion_factor": 1000})
item.save()
frappe.db.set_value("UOM", "Bag", "must_be_whole_number", 1)
rule_1 = create_putaway_rule(
item_code=item.name, warehouse=self.warehouse_1, capacity=500, uom="Kg", priority=1
)
rule_2 = create_putaway_rule(
item_code=item.name, warehouse=self.warehouse_2, capacity=2000, uom="Kg", priority=2
)
pr = make_purchase_receipt(
item_code=item.name,
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].warehouse, self.warehouse_2)
self.assertEqual(pr.items[0].putaway_rule, rule_2.name)
self.assertEqual(pr.items[0].qty, 2)
self.assertEqual(pr.items[0].stock_qty, 2000)
pr.delete()
rule_1.delete()
rule_2.delete()
def test_putaway_rules_with_reoccurring_item(self):
"""Test rules on same item entered multiple times with different rate."""
rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200, uom="Kg")