diff --git a/erpnext/docs/assets/img/manufacturing/ppt.png b/erpnext/docs/assets/img/manufacturing/ppt.png index f5018b75499..30096fff836 100644 Binary files a/erpnext/docs/assets/img/manufacturing/ppt.png and b/erpnext/docs/assets/img/manufacturing/ppt.png differ diff --git a/erpnext/docs/user/manual/en/manufacturing/tools/production-planning-tool.md b/erpnext/docs/user/manual/en/manufacturing/tools/production-planning-tool.md index 61ec4c76d9a..4bdc48767be 100644 --- a/erpnext/docs/user/manual/en/manufacturing/tools/production-planning-tool.md +++ b/erpnext/docs/user/manual/en/manufacturing/tools/production-planning-tool.md @@ -1,7 +1,7 @@ Production Planning Tool helps you plan production and purchase of Items for a period (usually a week or a month). -This list of Items can be generated from the open Sales Orders in the system +This list of Items can be generated from the open Sales Orders or pending Material Requests that can be Manufactured in the system and will generate: * Production Orders for each Item. @@ -13,30 +13,36 @@ To use the Production Planning Tool, go to: Production Planing Tool +#### Step 1: Specify source to get Production Items + +* You can select Sales Order or Material Request according to where you want to source the items from +* If you plan to add items manually, keep the "Get items from" field empty -#### Step 1: Select and get Sales Order -* Select sales orders for MRP using filters (Time, Item, and Customer) -* Click on Get Sales Order to generate a list. +#### Step 2: Select and get Sales Order / Material Request + +* Use filters to get the Sales Order / Material Request +* Click on Get Sales Order / Get Material Requests to generate a list. Production Planing Tool -#### Step 2: Get Item from Sales Orders. +#### Step 3: Get Items -You can add/remove or change quantity of these Items. +* Get the items for the Sales Order / Material request list +* You can add/remove or change quantity of these Items. Production Planing Tool -#### Step 3: Create Production Orders +#### Step 4: Create Production Orders Production Planing Tool -#### Step 4: Create Material Request +#### Step 5: Create Material Request Create Material Request for Items with projected shortfall. @@ -46,11 +52,11 @@ Create Material Request for Items with projected shortfall. The Production Planning Tool is used in two stages: - * Selection of Open Sales Orders for the period based on “Expected Delivery Date”. - * Selection of Items from those Sales Orders. + * Selection of open Sales Orders / pending Material Request for the period based on “Expected Delivery Date”. + * Selection of Items from those Sales Orders / Material Requests -The tool will update if you have already created Production Orders for a -particular Item against its Sales Order (“Planned Quantity”). +The tool will update if you have already created Production Orde rs for a +particular Item against its Sales Order (“Planned Quantity”) or Material Request. You can always edit the Item list and increase / reduce quantities to plan your production. diff --git a/erpnext/docs/user/manual/en/stock/material-request.md b/erpnext/docs/user/manual/en/stock/material-request.md index a609756d3e3..8afda601736 100644 --- a/erpnext/docs/user/manual/en/stock/material-request.md +++ b/erpnext/docs/user/manual/en/stock/material-request.md @@ -23,6 +23,7 @@ A Material Request can be of type: * Purchase - If the request material is to be purchased. * Material Transfer - If the requested material is to be shifted from one warehouse to another. * Material Issue - If the requested material is to be Issued. +* Manufacture - If the requested material is to be Produced. > Info: Material Request is not mandatory. It is ideal if you have centralized buying so that you can collect this information from various departments. diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index ead8105a923..b1678f15b7f 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -314,7 +314,8 @@ class ProductionOrder(Document): def set_actual_dates(self): if self.get("operations"): - actual_date = frappe.db.sql("""select min(actual_start_time) as start_date, max(actual_end_time) as end_date from `tabProduction Order Operation` + actual_date = frappe.db.sql("""select min(actual_start_time) as start_date, + max(actual_end_time) as end_date from `tabProduction Order Operation` where parent = %s and docstatus=1""", self.name, as_dict=1)[0] self.actual_start_date = actual_date.start_date self.actual_end_date = actual_date.end_date 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 19b5fd97845..699fb2a583c 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.json @@ -13,16 +13,16 @@ "bold": 0, "collapsible": 0, "default": "Sales Order", - "fieldname": "plan_using", + "fieldname": "get_items_from", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Plan Using", + "label": "Get Items From", "length": 0, "no_copy": 0, - "options": "Sales Order\nMaterial Request", + "options": "\nSales Order\nMaterial Request", "permlevel": 0, "precision": "", "print_hide": 0, @@ -38,7 +38,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "", + "depends_on": "get_items_from", "description": "", "fieldname": "filters", "fieldtype": "Section Break", @@ -87,7 +87,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval: doc.plan_using == \"Sales Order\"", + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", "fieldname": "customer", "fieldtype": "Link", "hidden": 0, @@ -112,7 +112,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval: doc.plan_using == \"Material Request\"", + "depends_on": "eval: doc.get_items_from == \"Material Request\"", "fieldname": "warehouse", "fieldtype": "Link", "hidden": 0, @@ -138,7 +138,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval: doc.plan_using == \"Sales Order\"", + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", "fieldname": "company", "fieldtype": "Link", "hidden": 0, @@ -232,7 +232,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval: doc.plan_using == \"Sales Order\"", + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", "fieldname": "section_break1", "fieldtype": "Section Break", "hidden": 0, @@ -305,7 +305,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval: doc.plan_using == \"Material Request\"", + "depends_on": "eval: doc.get_items_from == \"Material Request\"", "fieldname": "section_break_16", "fieldtype": "Section Break", "hidden": 0, @@ -403,6 +403,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "depends_on": "get_items_from", "fieldname": "get_items", "fieldtype": "Button", "hidden": 0, @@ -428,6 +429,7 @@ "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", @@ -629,7 +631,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2016-02-11 06:18:45.077263", + "modified": "2016-02-16 06:56:08.244906", "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 bec97d1c03c..ee5e4e75902 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -115,9 +115,9 @@ class ProductionPlanningTool(Document): mr.material_request_date = cstr(r['transaction_date']) def get_items(self): - if self.plan_using == "Sales Order": + if self.get_items_from == "Sales Order": self.get_so_items() - elif self.plan_using == "Material Request": + elif self.get_items_from == "Material Request": self.get_mr_items() def get_so_items(self): @@ -191,9 +191,9 @@ class ProductionPlanningTool(Document): pi.planned_qty = flt(p['pending_qty']) pi.pending_qty = flt(p['pending_qty']) - if self.plan_using == "Sales Order": + if self.get_items_from == "Sales Order": pi.sales_order = p['parent'] - elif self.plan_using == "Material Request": + elif self.get_items_from == "Material Request": pi.material_request = p['parent'] pi.material_request_item = p['name'] @@ -252,18 +252,18 @@ class ProductionPlanningTool(Document): } """ Club similar BOM and item for processing in case of Sales Orders """ - if self.plan_using == "Sales Order": + if self.get_items_from == "Material Request": + item_details.update({ + "qty": d.planned_qty + }) + item_dict[(d.item_code, d.material_request_item, d.warehouse)] = item_details + + else: item_details.update({ "qty":flt(item_dict.get((d.item_code, d.sales_order, d.warehouse),{}) .get("qty")) + flt(d.planned_qty) }) item_dict[(d.item_code, d.sales_order, d.warehouse)] = item_details - - elif self.plan_using == "Material Request": - item_details.update({ - "qty": d.planned_qty - }) - item_dict[(d.item_code, d.material_request_item, d.warehouse)] = item_details return item_dict @@ -293,11 +293,12 @@ class ProductionPlanningTool(Document): """ bom_dict = {} for d in self.get("items"): - if self.plan_using == "Sales Order": - bom_dict.setdefault(d.bom_no, []).append({d.sales_order: flt(d.planned_qty)}) - elif self.plan_using == "Material Request": - bom_dict.setdefault(d.bom_no, []).append({d.material_request_item: flt(d.planned_qty)}) - + if self.get_items_from == "Material Request": + bom_dict.setdefault(d.bom_no, []).append([d.material_request_item, flt(d.planned_qty)]) + else: + bom_dict.setdefault(d.bom_no, []).append([d.sales_order, flt(d.planned_qty)]) + return bom_dict + def download_raw_materials(self): """ Create csv data for required raw material to produce finished goods""" self.validate_data() @@ -341,7 +342,6 @@ class ProductionPlanningTool(Document): and item.is_stock_item = 1 group by item_code""", bom, as_dict=1): bom_wise_item_details.setdefault(d.item_code, d) - 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, @@ -405,7 +405,7 @@ class ProductionPlanningTool(Document): for item_details in so_item_qty: if requested_qty: sales_order = item_details[4] or "No Sales Order" - if self.plan_using == "Material Request": + if self.get_items_from == "Material Request": sales_order = "No Sales Order" if requested_qty <= item_details[0]: adjusted_qty = requested_qty