Merge pull request #6101 from bcornwellmott/ppt_test2
Upgraded PPT for more variety of MR creation options. Added tests
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json
index 26ba5b7..8438e07 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json
+++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json
@@ -9,6 +9,7 @@
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
+ "editable_grid": 0,
"fields": [
{
"allow_on_submit": 0,
@@ -475,33 +476,6 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "default": "1",
- "depends_on": "get_items_from",
- "description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
- "fieldname": "use_multi_level_bom",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Use Multi-Level BOM",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"fieldname": "items",
"fieldtype": "Table",
"hidden": 0,
@@ -699,19 +673,124 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "1",
+ "depends_on": "",
+ "description": "If checked, all the children of each production item will be included in the Material Requests.",
+ "fieldname": "use_multi_level_bom",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Use Multi-Level BOM",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "If checked, only Purchase material requests for final raw materials will be included in the Material Requests. Otherwise, Material Requests for parent items will be created",
+ "fieldname": "only_raw_materials",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Only Obtain Raw Materials",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "use_multi_level_bom",
+ "description": "If checked, raw materials for items that are sub-contracted will be included in the Material Requests",
+ "fieldname": "include_subcontracted",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Include sub-contracted raw materials",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 1,
"icon": "icon-calendar",
"idx": 1,
+ "image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-06-02 17:59:48.976304",
+ "modified": "2016-08-17 05:35:34.331954",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Planning Tool",
@@ -731,6 +810,7 @@
"print": 1,
"read": 1,
"report": 0,
+ "restrict": 0,
"role": "Manufacturing User",
"set_user_permissions": 0,
"share": 1,
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index 5fbcf1e..acb3ab8 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -175,7 +175,7 @@
and bom.is_active = 1) %s""" % \
(", ".join(["%s"] * len(mr_list)), item_condition), tuple(mr_list), as_dict=1)
- self.add_items(items)
+ self.add_items(items)
def add_items(self, items):
@@ -313,10 +313,10 @@
}
"""
item_list = []
-
+
for bom, so_wise_qty in bom_dict.items():
bom_wise_item_details = {}
- if self.use_multi_level_bom:
+ if self.use_multi_level_bom and self.only_raw_materials and self.include_subcontracted:
# get all raw materials with sub assembly childs
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
for d in frappe.db.sql("""select fb.item_code,
@@ -326,28 +326,46 @@
where bom.name = fb.parent and item.name = fb.item_code
and (item.is_sub_contracted_item = 0 or ifnull(item.default_bom, "")="")
and item.is_stock_item = 1
- and fb.docstatus<2 and bom.name=%s
- group by fb.item_code, fb.stock_uom""", bom, as_dict=1):
+ and fb.docstatus<2 and bom.name=%(bom)s
+ group by fb.item_code, fb.stock_uom""", {"bom":bom}, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
- for d in frappe.db.sql("""select bom_item.item_code,
- ifnull(sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
- bom_item.description, bom_item.stock_uom, item.min_order_qty
- from `tabBOM Item` bom_item, `tabBOM` bom, tabItem item
- where bom.name = bom_item.parent and bom.name = %s and bom_item.docstatus < 2
- and bom_item.item_code = item.name
- and item.is_stock_item = 1
- group by bom_item.item_code""", bom, as_dict=1):
- bom_wise_item_details.setdefault(d.item_code, d)
+ bom_wise_item_details = self.get_subitems(bom_wise_item_details, bom,1, \
+ self.use_multi_level_bom,self.only_raw_materials, self.include_subcontracted)
+
for item, item_details in bom_wise_item_details.items():
for so_qty in so_wise_qty:
item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
item_details.stock_uom, item_details.min_order_qty, so_qty[0]])
-
+
self.make_items_dict(item_list)
+ def get_subitems(self,bom_wise_item_details, bom, parent_qty, include_sublevel, only_raw, supply_subs):
+ for d in frappe.db.sql("""select bom_item.item_code, default_material_request_type,
+ ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
+ item.is_sub_contracted_item as is_sub_contracted, item.default_bom as default_bom
+ from `tabBOM Item` bom_item, `tabBOM` bom, tabItem item
+ where bom.name = bom_item.parent and bom.name = %(bom)s and bom_item.docstatus < 2
+ and bom_item.item_code = item.name
+ and item.is_stock_item = 1
+ group by bom_item.item_code""", {"bom": bom, "parent_qty": parent_qty}, as_dict=1):
+ if (d.default_material_request_type == "Purchase" and not (d.is_sub_contracted \
+ and only_raw and include_sublevel)) or (d.default_material_request_type == \
+ "Manufacture" and not only_raw):
+ if d.item_code in bom_wise_item_details:
+ bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty\
+ + d.qty
+ else:
+ bom_wise_item_details[d.item_code] = d
+ if include_sublevel:
+ if (d.default_material_request_type == "Purchase" and d.is_sub_contracted \
+ and supply_subs) or (d.default_material_request_type == "Manufacture"):
+ child_details = self.get_subitems(bom_wise_item_details,d.default_bom, \
+ d.qty, include_sublevel, only_raw, supply_subs)
+ return bom_wise_item_details
+
def make_items_dict(self, item_list):
for i in item_list:
self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]])
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py
new file mode 100644
index 0000000..ea4da0c
--- /dev/null
+++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py
@@ -0,0 +1,391 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+import frappe
+import frappe.defaults
+import unittest
+from frappe.test_runner import make_test_records
+
+from erpnext.manufacturing.doctype.production_planning_tool.production_planning_tool import ProductionPlanningTool
+
+# load test records and dependencies
+
+test_records = frappe.get_test_records('Production Planning Tool')
+
+test_dependencies = ["Item","BOM"]
+
+class TestEvent(unittest.TestCase):
+
+ def test_materials_requests_all_raw_multi_level(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [14,9,36,1,0,0,0,0,0,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=1, only_raw_materials=1, \
+ include_subcontracted=1)
+
+ def test_materials_requests_multi_no_subcontracted(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [14,5,20,0,0,0,0,0,0,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ # This one should fail for now
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=1, only_raw_materials=1, \
+ include_subcontracted=0)
+
+
+
+ def test_materials_requests_manufacture_and_sub_multi_level(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [14,9,36,1,2,5,2,1,4,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=1, only_raw_materials=0, \
+ include_subcontracted=1)
+
+ def test_materials_requests_manufacture_multi_level(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [14,5,20,0,2,5,2,1,4,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=1, only_raw_materials=0, \
+ include_subcontracted=0)
+
+
+
+ def test_materials_requests_single_level_purch_only(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [2,0,0,0,0,0,0,1,0,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=0, only_raw_materials=1, \
+ include_subcontracted=0)
+
+ def test_materials_requests_single_level(self):
+ items = ["_Test PPT Item Raw A","_Test PPT Item Raw B","_Test PPT Item Raw C","_Test PPT Item Raw D",
+ "_Test PPT Item Sub A","_Test PPT Item Sub B","_Test PPT Item Sub C","_Test PPT Item SC A",
+ "_Test PPT Item SC B","_Test PPT Item Master"]
+ quantities = [2,0,0,0,2,1,0,1,0,0]
+ types = ["Purchase","Purchase","Purchase","Purchase","Manufacture","Manufacture","Manufacture","Purchase",
+ "Purchase","Manufacture"]
+
+ self.runtest_materials_requests(items, quantities, types, use_multi_level_bom=0, only_raw_materials=0, \
+ include_subcontracted=0)
+
+ def runtest_materials_requests(self, items, quantities, types,use_multi_level_bom, only_raw_materials, \
+ include_subcontracted):
+
+ clear_material_requests()
+ create_test_records()
+
+ ppt = run_production_planning_tool(use_multi_level_bom=use_multi_level_bom,
+ only_raw_materials=only_raw_materials, include_subcontracted=include_subcontracted,
+ item_code = "_Test PPT Item Master", bom_no = "BOM-_Test PPT Item Master-001",
+ planned_qty = 1, planned_start_date = "5/5/2029",
+ warehouse = "_Test Warehouse - _TC", company = "_Test Company")
+
+ create_material_requests(ppt)
+
+ for item, qty, type in zip(items, quantities, types):
+ self.assertEqual(qty, get_requested_qty(item))
+ for mat_req_type in get_requested_types(item):
+ self.assertEqual(type, mat_req_type)
+
+def create_test_records():
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ subA = make_item("_Test PPT Item Sub A",{
+ "item_code": "_Test PPT Item Sub A",
+ "item_name": "_Test PPT Item Sub A",
+ "description": "A manufactured _Test PPT Item Sub Assembly",
+ "default_material_request_type": "Manufacture",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ subB = make_item("_Test PPT Item Sub B",{
+ "item_code": "_Test PPT Item Sub B",
+ "item_name": "_Test PPT Item Sub B",
+ "description": "A manufactured _Test PPT Item Sub Assembly",
+ "default_material_request_type": "Manufacture",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ subC = make_item("_Test PPT Item Sub C",{
+ "item_code": "_Test PPT Item Sub C",
+ "item_name": "_Test PPT Item Sub C",
+ "description": "A manufactured _Test PPT Item Sub Assembly",
+ "default_material_request_type": "Manufacture",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ sCA = make_item("_Test PPT Item SC A",{
+ "item_code": "_Test PPT Item SC A",
+ "item_name": "_Test PPT Item SC A",
+ "description": "A subcontracted part with raw materials",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 1,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+ subA = make_item("_Test PPT Item Sub A",{
+ "item_code": "_Test PPT Item Sub A",
+ "item_name": "_Test PPT Item Sub A",
+ "description": "A manufactured _Test PPT Item Sub Assembly",
+ "default_material_request_type": "Manufacture",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+ sCB = make_item("_Test PPT Item SC B",{
+ "item_code": "_Test PPT Item SC B",
+ "item_name": "_Test PPT Item SC B",
+ "description": "A subcontracted part with raw materials",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 1,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ rawA = make_item("_Test PPT Item Raw A",{
+ "item_code": "_Test PPT Item Raw A",
+ "item_name": "_Test PPT Item Raw A",
+ "description": "A raw material",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ rawB = make_item("_Test PPT Item Raw B",{
+ "item_code": "_Test PPT Item Raw B",
+ "item_name": "_Test PPT Item Raw B",
+ "description": "A raw material",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ rawC = make_item("_Test PPT Item Raw C",{
+ "item_code": "_Test PPT Item Raw C",
+ "item_name": "_Test PPT Item Raw C",
+ "description": "A raw material",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ rawD = make_item("_Test PPT Item Raw D",{
+ "item_code": "_Test PPT Item Raw D",
+ "item_name": "_Test PPT Item Raw D",
+ "description": "A raw material",
+ "default_material_request_type": "Purchase",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+ master = make_item("_Test PPT Item Master",{
+ "item_code": "_Test PPT Item Master",
+ "item_name": "_Test PPT Item Master",
+ "description": "The final assembly",
+ "default_material_request_type": "Manufacture",
+ "is_sub_contracted_item": 0,
+ "is_stock_item": 1,
+ "stock_uom": "_Test UOM",
+ "item_group": "_Test Item Group",
+ "default_warehouse": "_Test Warehouse - _TC"})
+
+
+
+ bom_subB = make_bom("BOM-_Test PPT Item Sub B-001",{"quantity":1.0,
+ "item": "_Test PPT Item Sub B",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "qty":1,
+ "rate":100, "amount": 100, "stock_uom": "_Test UOM"},
+ {"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "qty":4, "rate":100,
+ "amount": 400,"stock_uom": "_Test UOM"}])
+
+ bom_subC = make_bom("BOM-_Test PPT Item Sub C-001",{"quantity":1,
+ "item": "_Test PPT Item Sub C",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [
+ {"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
+ "doctype":"BOM Item", "qty":6, "rate":100, "amount": 600},
+ {"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
+ "bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "qty":2,
+ "rate":100, "amount": 200}])
+
+ bom_sCA = make_bom("BOM-_Test PPT Item SC A-001",{"quantity":1,
+ "item": "_Test PPT Item SC A",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [
+ {"item_code": "_Test PPT Item Raw D","item_name": "_Test PPT Item Raw D",
+ "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}])
+
+ bom_sCB = make_bom("BOM-_Test PPT Item SC B-001",{"quantity":1,
+ "item": "_Test PPT Item SC B",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [
+ {"item_code": "_Test PPT Item Raw B","item_name": "_Test PPT Item Raw B",
+ "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
+ {"item_code": "_Test PPT Item Raw C","item_name": "_Test PPT Item Raw C",
+ "doctype":"BOM Item", "qty":4, "rate":100, "amount": 400}])
+
+ bom_subA = make_bom("BOM-_Test PPT Item Sub A-001",{"quantity":1,
+ "item": "_Test PPT Item Sub A",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [
+ {"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
+ "bom_no":"BOM-_Test PPT Item Sub C-001", "doctype":"BOM Item",
+ "qty":1, "rate":100, "amount": 100},
+ {"item_code": "_Test PPT Item SC B","item_name": "_Test PPT Item SC B",
+ "bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "qty":2,
+ "rate":100, "amount": 200}])
+
+ bom_master = make_bom("BOM-_Test PPT Item Master-001",{"quantity":1,
+ "item": "_Test PPT Item Master",
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1,
+ "with_operations": 0}, [
+ {"item_code": "_Test PPT Item Sub A","item_name": "_Test PPT Item Sub A",
+ "bom_no":"BOM-_Test PPT Item Sub A-001",
+ "doctype":"BOM Item", "qty":2, "rate":100, "amount": 200},
+ {"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
+ "bom_no":"BOM-_Test PPT Item Sub B-001",
+ "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
+ {"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
+ "doctype":"BOM Item", "qty":2, "rate":100,
+ "amount": 200},
+ {"item_code": "_Test PPT Item SC A","item_name": "_Test PPT Item SC A",
+ "bom_no":"BOM-_Test PPT Item SC A-001",
+ "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}
+ ])
+
+
+def make_bom(name, properties=None, items=None):
+ if frappe.db.exists("BOM", name):
+ return frappe.get_doc("BOM", name)
+
+ bom = frappe.new_doc("BOM")
+ item = frappe.get_doc({
+ "doctype": "BOM",
+ "name": name,
+ "quantity": "1",
+ "with_operations": 0
+ })
+
+ if properties:
+ bom.update(properties)
+
+ if items:
+ for item in items:
+ bom.append("items", item)
+
+
+ bom.insert()
+ bom.submit()
+
+ return bom
+
+def clear_material_requests():
+ frappe.db.sql("delete from `tabMaterial Request Item`")
+ frappe.db.sql("delete from `tabMaterial Request`")
+
+
+def run_production_planning_tool(**args):
+ ppt = frappe.new_doc("Production Planning Tool")
+ args = frappe._dict(args)
+
+ if args.use_multi_level_bom:
+ ppt.use_multi_level_bom = args.use_multi_level_bom
+ else:
+ ppt.use_multi_level_bom = 0
+
+ if args.only_raw_materials:
+ ppt.only_raw_materials = args.only_raw_materials
+ else:
+ ppt.only_raw_materials = 0
+
+ if args.include_subcontracted:
+ ppt.include_subcontracted = args.include_subcontracted
+ else:
+ ppt.include_subcontracted = 0
+
+ if args.warehouse:
+ ppt.purchase_request_for_warehouse = args.warehouse
+
+ if args.company:
+ ppt.company = args.company
+ ppt.create_material_requests_for_all_required_qty = 1
+
+ ppt.append("items",{"item_code": args.item_code, "bom_no": args.bom_no, "planned_qty": args.planned_qty,
+ "planned_start_date": args.planned_start_date, "warehouse": args.warehouse})
+
+ return ppt
+
+def create_production_orders(ppt):
+ raise_production_orders(ppt)
+
+def create_material_requests(ppt):
+ ppt.raise_material_requests()
+
+def get_requested_qty(item_code):
+ total_qty = 0
+ for d in frappe.db.sql("""select item.qty as qty
+ from `tabMaterial Request` mat_req, `tabMaterial Request Item` item
+ where item.item_code = %(item_code)s and item.parent = mat_req.name""", {"item_code":item_code}, as_dict=1):
+ total_qty += d.qty
+ return total_qty
+
+def get_requested_types(item_code):
+ types = []
+ for d in frappe.db.sql("""select mat_req.material_request_type as type
+ from `tabMaterial Request` mat_req, `tabMaterial Request Item` item
+ where item.item_code = %(item_code)s and item.parent = mat_req.name""", {"item_code":item_code}, as_dict=1):
+ types.append(d.type)
+ return types
+
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/test_records.json b/erpnext/manufacturing/doctype/production_planning_tool/test_records.json
new file mode 100644
index 0000000..2e807ef
--- /dev/null
+++ b/erpnext/manufacturing/doctype/production_planning_tool/test_records.json
@@ -0,0 +1,3 @@
+[
+
+]