diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 637a86846f9..a27689d6052 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -319,6 +319,38 @@ class PurchaseOrder(BuyingController): ).format(item_code, flt(qty, precision), itemwise_min_order_qty.get(item_code)) ) + self.warn_marginal_min_order_qty(itemwise_qty, itemwise_min_order_qty) + + def warn_marginal_min_order_qty(self, itemwise_qty, itemwise_min_order_qty): + """Toast when an item's ordered qty exceeds its minimum only by purchase UOM rounding.""" + if not self.is_new(): + return + + precision = self.items[0].precision("stock_qty") + itemwise_step = frappe._dict() + itemwise_stock_uom = frappe._dict() + for d in self.get("items"): + step = 10 ** -d.precision("qty") * flt(d.conversion_factor) + itemwise_step[d.item_code] = max(itemwise_step.get(d.item_code, 0), step) + itemwise_stock_uom[d.item_code] = d.stock_uom + + for item_code, qty in itemwise_qty.items(): + min_order_qty = flt(itemwise_min_order_qty.get(item_code)) + overage = flt(qty) - min_order_qty + if min_order_qty and flt(overage, precision) > 0 and overage < itemwise_step[item_code]: + frappe.toast( + _( + "Item {0}: Ordered qty {1} {2} exceeds the minimum order qty {3} {2} by {4} {2} due to purchase UOM rounding." + ).format( + item_code, + flt(qty, precision), + itemwise_stock_uom[item_code], + min_order_qty, + flt(overage, precision), + ), + indicator="orange", + ) + def get_schedule_dates(self): for d in self.get("items"): if d.material_request_item and not d.schedule_date: