fix: validate Work Order qty against Production Plan (#29721)
* fix: validate Work Order qty against Production Plan * chore: err msg when max_qty is 0 * test: add test for overproduction * fix: CI
This commit is contained in:
@@ -9,6 +9,7 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import (
|
|||||||
get_sales_orders,
|
get_sales_orders,
|
||||||
get_warehouse_list,
|
get_warehouse_list,
|
||||||
)
|
)
|
||||||
|
from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
from erpnext.stock.doctype.item.test_item import create_item
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
@@ -466,26 +467,29 @@ class TestProductionPlan(ERPNextTestCase):
|
|||||||
bom = make_bom(item=item, raw_materials=raw_materials)
|
bom = make_bom(item=item, raw_materials=raw_materials)
|
||||||
|
|
||||||
# Create Production Plan
|
# Create Production Plan
|
||||||
pln = create_production_plan(item_code=bom.item, planned_qty=10)
|
pln = create_production_plan(item_code=bom.item, planned_qty=5)
|
||||||
|
|
||||||
# All the created Work Orders
|
# All the created Work Orders
|
||||||
wo_list = []
|
wo_list = []
|
||||||
|
|
||||||
# Create and Submit 1st Work Order for 5 qty
|
# Create and Submit 1st Work Order for 3 qty
|
||||||
create_work_order(item, pln, 5)
|
create_work_order(item, pln, 3)
|
||||||
|
pln.reload()
|
||||||
|
self.assertEqual(pln.po_items[0].ordered_qty, 3)
|
||||||
|
|
||||||
|
# Create and Submit 2nd Work Order for 2 qty
|
||||||
|
create_work_order(item, pln, 2)
|
||||||
pln.reload()
|
pln.reload()
|
||||||
self.assertEqual(pln.po_items[0].ordered_qty, 5)
|
self.assertEqual(pln.po_items[0].ordered_qty, 5)
|
||||||
|
|
||||||
# Create and Submit 2nd Work Order for 3 qty
|
# Overproduction
|
||||||
create_work_order(item, pln, 3)
|
self.assertRaises(OverProductionError, create_work_order, item=item, pln=pln, qty=2)
|
||||||
pln.reload()
|
|
||||||
self.assertEqual(pln.po_items[0].ordered_qty, 8)
|
|
||||||
|
|
||||||
# Cancel 1st Work Order
|
# Cancel 1st Work Order
|
||||||
wo1 = frappe.get_doc("Work Order", wo_list[0])
|
wo1 = frappe.get_doc("Work Order", wo_list[0])
|
||||||
wo1.cancel()
|
wo1.cancel()
|
||||||
pln.reload()
|
pln.reload()
|
||||||
self.assertEqual(pln.po_items[0].ordered_qty, 3)
|
self.assertEqual(pln.po_items[0].ordered_qty, 2)
|
||||||
|
|
||||||
# Cancel 2nd Work Order
|
# Cancel 2nd Work Order
|
||||||
wo2 = frappe.get_doc("Work Order", wo_list[1])
|
wo2 = frappe.get_doc("Work Order", wo_list[1])
|
||||||
|
|||||||
@@ -632,6 +632,21 @@ class WorkOrder(Document):
|
|||||||
if not self.qty > 0:
|
if not self.qty > 0:
|
||||||
frappe.throw(_("Quantity to Manufacture must be greater than 0."))
|
frappe.throw(_("Quantity to Manufacture must be greater than 0."))
|
||||||
|
|
||||||
|
if self.production_plan and self.production_plan_item:
|
||||||
|
qty_dict = frappe.db.get_value("Production Plan Item", self.production_plan_item, ["planned_qty", "ordered_qty"], as_dict=1)
|
||||||
|
|
||||||
|
allowance_qty =flt(frappe.db.get_single_value("Manufacturing Settings",
|
||||||
|
"overproduction_percentage_for_work_order"))/100 * qty_dict.get("planned_qty", 0)
|
||||||
|
|
||||||
|
max_qty = qty_dict.get("planned_qty", 0) + allowance_qty - qty_dict.get("ordered_qty", 0)
|
||||||
|
|
||||||
|
if max_qty < 1:
|
||||||
|
frappe.throw(_("Cannot produce more item for {0}")
|
||||||
|
.format(self.production_item), OverProductionError)
|
||||||
|
elif self.qty > max_qty:
|
||||||
|
frappe.throw(_("Cannot produce more than {0} items for {1}")
|
||||||
|
.format(max_qty, self.production_item), OverProductionError)
|
||||||
|
|
||||||
def validate_transfer_against(self):
|
def validate_transfer_against(self):
|
||||||
if not self.docstatus == 1:
|
if not self.docstatus == 1:
|
||||||
# let user configure operations until they're ready to submit
|
# let user configure operations until they're ready to submit
|
||||||
|
|||||||
Reference in New Issue
Block a user