Merge pull request #31353 from marination/so-to-wo-bom
fix: Pick Template BOM if variant BOM absent in WO popup from SO
This commit is contained in:
commit
c83b4043b8
@ -25,6 +25,7 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import (
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||
from erpnext.stock.doctype.item.item import get_item_defaults
|
||||
from erpnext.stock.get_item_details import get_default_bom
|
||||
from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
|
||||
|
||||
form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
|
||||
@ -423,8 +424,9 @@ class SalesOrder(SellingController):
|
||||
|
||||
for table in [self.items, self.packed_items]:
|
||||
for i in table:
|
||||
bom = get_default_bom_item(i.item_code)
|
||||
bom = get_default_bom(i.item_code)
|
||||
stock_qty = i.qty if i.doctype == "Packed Item" else i.stock_qty
|
||||
|
||||
if not for_raw_material_request:
|
||||
total_work_order_qty = flt(
|
||||
frappe.db.sql(
|
||||
@ -438,32 +440,19 @@ class SalesOrder(SellingController):
|
||||
pending_qty = stock_qty
|
||||
|
||||
if pending_qty and i.item_code not in product_bundle_parents:
|
||||
if bom:
|
||||
items.append(
|
||||
dict(
|
||||
name=i.name,
|
||||
item_code=i.item_code,
|
||||
description=i.description,
|
||||
bom=bom,
|
||||
warehouse=i.warehouse,
|
||||
pending_qty=pending_qty,
|
||||
required_qty=pending_qty if for_raw_material_request else 0,
|
||||
sales_order_item=i.name,
|
||||
)
|
||||
)
|
||||
else:
|
||||
items.append(
|
||||
dict(
|
||||
name=i.name,
|
||||
item_code=i.item_code,
|
||||
description=i.description,
|
||||
bom="",
|
||||
warehouse=i.warehouse,
|
||||
pending_qty=pending_qty,
|
||||
required_qty=pending_qty if for_raw_material_request else 0,
|
||||
sales_order_item=i.name,
|
||||
)
|
||||
items.append(
|
||||
dict(
|
||||
name=i.name,
|
||||
item_code=i.item_code,
|
||||
description=i.description,
|
||||
bom=bom or "",
|
||||
warehouse=i.warehouse,
|
||||
pending_qty=pending_qty,
|
||||
required_qty=pending_qty if for_raw_material_request else 0,
|
||||
sales_order_item=i.name,
|
||||
)
|
||||
)
|
||||
|
||||
return items
|
||||
|
||||
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||
@ -1167,13 +1156,6 @@ def update_status(status, name):
|
||||
so.update_status(status)
|
||||
|
||||
|
||||
def get_default_bom_item(item_code):
|
||||
bom = frappe.get_all("BOM", dict(item=item_code, is_active=True), order_by="is_default desc")
|
||||
bom = bom[0].name if bom else None
|
||||
|
||||
return bom
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_raw_material_request(items, company, sales_order, project=None):
|
||||
if not frappe.has_permission("Sales Order", "write"):
|
||||
|
@ -1380,6 +1380,59 @@ class TestSalesOrder(FrappeTestCase):
|
||||
except Exception:
|
||||
self.fail("Can not cancel sales order with linked cancelled payment entry")
|
||||
|
||||
def test_work_order_pop_up_from_sales_order(self):
|
||||
"Test `get_work_order_items` in Sales Order picks the right BOM for items to manufacture."
|
||||
|
||||
from erpnext.controllers.item_variant import create_variant
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||
|
||||
make_item( # template item
|
||||
"Test-WO-Tshirt",
|
||||
{
|
||||
"has_variant": 1,
|
||||
"variant_based_on": "Item Attribute",
|
||||
"attributes": [{"attribute": "Test Colour"}],
|
||||
},
|
||||
)
|
||||
make_item("Test-RM-Cotton") # RM for BOM
|
||||
|
||||
for colour in (
|
||||
"Red",
|
||||
"Green",
|
||||
):
|
||||
variant = create_variant("Test-WO-Tshirt", {"Test Colour": colour})
|
||||
variant.save()
|
||||
|
||||
template_bom = make_bom(item="Test-WO-Tshirt", rate=100, raw_materials=["Test-RM-Cotton"])
|
||||
red_var_bom = make_bom(item="Test-WO-Tshirt-R", rate=100, raw_materials=["Test-RM-Cotton"])
|
||||
|
||||
so = make_sales_order(
|
||||
**{
|
||||
"item_list": [
|
||||
{
|
||||
"item_code": "Test-WO-Tshirt-R",
|
||||
"qty": 1,
|
||||
"rate": 1000,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
},
|
||||
{
|
||||
"item_code": "Test-WO-Tshirt-G",
|
||||
"qty": 1,
|
||||
"rate": 1000,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
wo_items = so.get_work_order_items()
|
||||
|
||||
self.assertEqual(wo_items[0].get("item_code"), "Test-WO-Tshirt-R")
|
||||
self.assertEqual(wo_items[0].get("bom"), red_var_bom.name)
|
||||
|
||||
# Must pick Template Item BOM for Test-WO-Tshirt-G as it has no BOM
|
||||
self.assertEqual(wo_items[1].get("item_code"), "Test-WO-Tshirt-G")
|
||||
self.assertEqual(wo_items[1].get("bom"), template_bom.name)
|
||||
|
||||
def test_request_for_raw_materials(self):
|
||||
item = make_item(
|
||||
"_Test Finished Item",
|
||||
|
@ -1352,12 +1352,22 @@ def get_price_list_currency_and_exchange_rate(args):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_default_bom(item_code=None):
|
||||
if item_code:
|
||||
bom = frappe.db.get_value(
|
||||
"BOM", {"docstatus": 1, "is_default": 1, "is_active": 1, "item": item_code}
|
||||
def _get_bom(item):
|
||||
bom = frappe.get_all(
|
||||
"BOM", dict(item=item, is_active=True, is_default=True, docstatus=1), limit=1
|
||||
)
|
||||
if bom:
|
||||
return bom
|
||||
return bom[0].name if bom else None
|
||||
|
||||
if not item_code:
|
||||
return
|
||||
|
||||
bom_name = _get_bom(item_code)
|
||||
|
||||
template_item = frappe.db.get_value("Item", item_code, "variant_of")
|
||||
if not bom_name and template_item:
|
||||
bom_name = _get_bom(template_item)
|
||||
|
||||
return bom_name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
Loading…
Reference in New Issue
Block a user