mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-17 18:45:20 +00:00
fix(manufacturing): handle empty raw materials in workstation (#58927)
(cherry picked from commit 3be0c7801a)
This commit is contained in:
@@ -1906,6 +1906,9 @@ def make_stock_entry(source_name: str, target_doc: Document | str | None = None)
|
|||||||
target.qty = pending_rm_qty
|
target.qty = pending_rm_qty
|
||||||
|
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
|
if not source.items:
|
||||||
|
frappe.throw(_("This Job Card has no raw materials to transfer."))
|
||||||
|
|
||||||
if source.finished_good and not source.target_warehouse:
|
if source.finished_good and not source.target_warehouse:
|
||||||
frappe.throw(_("Please set the Target Warehouse in the Job Card"))
|
frappe.throw(_("Please set the Target Warehouse in the Job Card"))
|
||||||
|
|
||||||
|
|||||||
@@ -3,18 +3,95 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
|
from erpnext.manufacturing.doctype.job_card.job_card import make_stock_entry
|
||||||
from erpnext.manufacturing.doctype.operation.test_operation import make_operation
|
from erpnext.manufacturing.doctype.operation.test_operation import make_operation
|
||||||
from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom
|
from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom
|
||||||
from erpnext.manufacturing.doctype.workstation.workstation import (
|
from erpnext.manufacturing.doctype.workstation.workstation import (
|
||||||
NotInWorkingHoursError,
|
NotInWorkingHoursError,
|
||||||
WorkstationHolidayError,
|
WorkstationHolidayError,
|
||||||
check_if_within_operating_hours,
|
check_if_within_operating_hours,
|
||||||
|
get_raw_materials,
|
||||||
update_job_card,
|
update_job_card,
|
||||||
)
|
)
|
||||||
from erpnext.tests.utils import ERPNextTestSuite
|
from erpnext.tests.utils import ERPNextTestSuite
|
||||||
|
|
||||||
|
|
||||||
class TestWorkstation(ERPNextTestSuite):
|
class TestWorkstation(ERPNextTestSuite):
|
||||||
|
def test_get_raw_materials_without_items(self):
|
||||||
|
for skip_transfer, backflush_from_wip in ((0, 0), (1, 0), (1, 1)):
|
||||||
|
with self.subTest(skip_transfer=skip_transfer, backflush_from_wip=backflush_from_wip):
|
||||||
|
job_card = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Job Card",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"skip_material_transfer": skip_transfer,
|
||||||
|
"backflush_from_wip_warehouse": backflush_from_wip,
|
||||||
|
"wip_warehouse": "_Test Warehouse 1 - _TC",
|
||||||
|
}
|
||||||
|
).insert(ignore_mandatory=True)
|
||||||
|
|
||||||
|
for method in (get_raw_materials, make_stock_entry):
|
||||||
|
with self.subTest(method=method.__name__):
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
frappe.ValidationError, "This Job Card has no raw materials to transfer"
|
||||||
|
):
|
||||||
|
method(job_card.name)
|
||||||
|
|
||||||
|
job_card.reload()
|
||||||
|
self.assertFalse(job_card.items)
|
||||||
|
self.assertFalse(frappe.db.exists("Stock Entry", {"job_card": job_card.name}))
|
||||||
|
|
||||||
|
def test_get_raw_materials_availability(self):
|
||||||
|
for skip_transfer, backflush_from_wip, transferred_qty in (
|
||||||
|
(0, 0, 2),
|
||||||
|
(0, 0, 5),
|
||||||
|
(1, 0, 0),
|
||||||
|
(1, 1, 0),
|
||||||
|
):
|
||||||
|
with self.subTest(
|
||||||
|
skip_transfer=skip_transfer,
|
||||||
|
backflush_from_wip=backflush_from_wip,
|
||||||
|
transferred_qty=transferred_qty,
|
||||||
|
):
|
||||||
|
job_card = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Job Card",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"skip_material_transfer": skip_transfer,
|
||||||
|
"backflush_from_wip_warehouse": backflush_from_wip,
|
||||||
|
"wip_warehouse": "_Test Warehouse 1 - _TC",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"source_warehouse": "_Test Warehouse - _TC",
|
||||||
|
"required_qty": 5,
|
||||||
|
"transferred_qty": transferred_qty,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_mandatory=True)
|
||||||
|
|
||||||
|
materials = get_raw_materials(job_card.name)
|
||||||
|
|
||||||
|
self.assertEqual(len(materials), 1)
|
||||||
|
material = materials[0]
|
||||||
|
warehouse = "_Test Warehouse 1 - _TC" if backflush_from_wip else "_Test Warehouse - _TC"
|
||||||
|
stock_qty = (
|
||||||
|
frappe.db.get_value(
|
||||||
|
"Bin", {"item_code": "_Test Item", "warehouse": warehouse}, "actual_qty"
|
||||||
|
)
|
||||||
|
or 0
|
||||||
|
)
|
||||||
|
self.assertEqual(material.item_code, "_Test Item")
|
||||||
|
self.assertEqual(material.required_qty, 5)
|
||||||
|
self.assertEqual(material.transferred_qty, transferred_qty)
|
||||||
|
self.assertEqual(material.warehouse, warehouse)
|
||||||
|
self.assertEqual(material.stock_qty, stock_qty)
|
||||||
|
self.assertEqual(
|
||||||
|
material.material_availability_status,
|
||||||
|
int(stock_qty >= 5) if skip_transfer else int(transferred_qty >= 5),
|
||||||
|
)
|
||||||
|
|
||||||
def test_update_job_card_rejects_disallowed_method(self):
|
def test_update_job_card_rejects_disallowed_method(self):
|
||||||
# The whitelisted update_job_card endpoint must only run an allowlisted set of Job Card
|
# The whitelisted update_job_card endpoint must only run an allowlisted set of Job Card
|
||||||
# methods. An arbitrary method name must be rejected (PermissionError) before the document
|
# methods. An arbitrary method name must be rejected (PermissionError) before the document
|
||||||
|
|||||||
@@ -346,8 +346,8 @@ def get_raw_materials(job_card: str):
|
|||||||
filters={"name": job_card},
|
filters={"name": job_card},
|
||||||
)
|
)
|
||||||
|
|
||||||
if not raw_materials:
|
if not raw_materials or not raw_materials[0].item_code:
|
||||||
return []
|
frappe.throw(_("This Job Card has no raw materials to transfer."))
|
||||||
|
|
||||||
for row in raw_materials:
|
for row in raw_materials:
|
||||||
warehouse = row.source_warehouse
|
warehouse = row.source_warehouse
|
||||||
|
|||||||
Reference in New Issue
Block a user