From e977fc5deef0dd093cf8ef9766a9a25c11f625e4 Mon Sep 17 00:00:00 2001 From: Ben Cornwell-Mott Date: Tue, 16 Aug 2016 06:01:52 -0700 Subject: [PATCH 1/4] Upgraded PPT for more variety of MR creation options. Added tests --- .../production_planning_tool.json | 64 +++- .../production_planning_tool.py | 42 ++- .../test_production_planning_tool.py | 336 ++++++++++++++++++ .../test_records.json | 3 + 4 files changed, 426 insertions(+), 19 deletions(-) create mode 100644 erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py create mode 100644 erpnext/manufacturing/doctype/production_planning_tool/test_records.json 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 26ba5b756f..0843f32949 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, @@ -468,7 +469,7 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 0, + "set_only_once": 0, "unique": 0 }, { @@ -476,8 +477,8 @@ "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.", + "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, @@ -498,6 +499,59 @@ "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 + }, { "allow_on_submit": 0, "bold": 0, @@ -705,13 +759,14 @@ "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-07-27 19:37:49.608457", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Planning Tool", @@ -731,6 +786,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 5fbcf1eb90..debfc350c0 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 @@ class ProductionPlanningTool(Document): 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 @@ class ProductionPlanningTool(Document): } """ 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,40 @@ class ProductionPlanningTool(Document): 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 0000000000..af7eadcc12 --- /dev/null +++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py @@ -0,0 +1,336 @@ +# 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 0000000000..2e807efe7f --- /dev/null +++ b/erpnext/manufacturing/doctype/production_planning_tool/test_records.json @@ -0,0 +1,3 @@ +[ + +] From 06bfecea73e67512e771c6831ab5d3d5f563a916 Mon Sep 17 00:00:00 2001 From: Ben Cornwell-Mott Date: Wed, 17 Aug 2016 05:42:25 -0700 Subject: [PATCH 2/4] Fixed formatting of code and repositioned checkboxes in PPT. --- .../production_planning_tool.json | 186 ++++++++++-------- .../production_planning_tool.py | 38 ++-- .../test_production_planning_tool.py | 64 ++++-- 3 files changed, 172 insertions(+), 116 deletions(-) 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 0843f32949..8438e07ba7 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json @@ -469,86 +469,6 @@ "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 }, @@ -753,6 +673,110 @@ "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, @@ -766,7 +790,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2016-07-27 19:37:49.608457", + "modified": "2016-08-17 05:35:34.331954", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Planning Tool", 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 debfc350c0..acb3ab8f1b 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -332,7 +332,8 @@ class ProductionPlanningTool(Document): else: # Get all raw materials considering SA items as raw materials, # so no childs of SA items - 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) + 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: @@ -343,21 +344,26 @@ class ProductionPlanningTool(Document): 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) + 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): 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 index af7eadcc12..c93a3dde04 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py @@ -17,58 +17,84 @@ 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"] + 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"] + 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) + 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"] + 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"] + 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) + 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"] + 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"] + 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) + 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"] + 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"] + 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) + 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"] + 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"] + 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) + 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"] + 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"] + 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) + 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") + 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): From d5a9d475e724953ec88b4491ab272e0731a20ca2 Mon Sep 17 00:00:00 2001 From: Ben Cornwell-Mott Date: Wed, 17 Aug 2016 05:45:43 -0700 Subject: [PATCH 3/4] Adjusted formatting --- .../test_production_planning_tool.py | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) 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 index c93a3dde04..b535e8b8c8 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py @@ -231,7 +231,8 @@ def create_test_records(): "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"}, + "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"} ]) @@ -240,8 +241,11 @@ def create_test_records(): "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} + "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, @@ -249,7 +253,8 @@ def create_test_records(): "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} + "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, @@ -257,26 +262,37 @@ def create_test_records(): "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} + "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} + "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} + "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} ]) @@ -336,7 +352,8 @@ def run_production_planning_tool(**args): 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}) + 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 @@ -348,14 +365,16 @@ def create_material_requests(ppt): 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 + 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 + 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 From a7c98ba0fef99b7556a175189bfe82954e230efb Mon Sep 17 00:00:00 2001 From: Ben Cornwell-Mott Date: Wed, 17 Aug 2016 05:56:00 -0700 Subject: [PATCH 4/4] More formatting adjustments --- .../test_production_planning_tool.py | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) 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 index b535e8b8c8..ea4da0cb94 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py @@ -87,14 +87,18 @@ class TestEvent(unittest.TestCase): 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): + 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") + 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): @@ -231,10 +235,10 @@ def create_test_records(): "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"} - ]) + "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", @@ -242,20 +246,20 @@ def create_test_records(): "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} - ]) + {"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} - ]) + "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", @@ -263,35 +267,41 @@ def create_test_records(): "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} - ]) + {"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} - ]) + {"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", + {"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", + {"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, + {"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", + {"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} ])