diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 23b32379413..f2e72b2e2a4 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -378,7 +378,11 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2022-03-25 09:15:25.017664", +======= + "modified": "2021-08-23 17:26:03.799876", +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 173c730bb31..f36090fde06 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -451,6 +451,7 @@ class ProductionPlan(Document): for d in self.po_items: item_details = { +<<<<<<< HEAD "production_item": d.item_code, "use_multi_level_bom": d.include_exploded_items, "sales_order": d.sales_order, @@ -467,6 +468,23 @@ class ProductionPlan(Document): "product_bundle_item": d.product_bundle_item, "planned_start_date": d.planned_start_date, "project": self.project, +======= + "production_item" : d.item_code, + "use_multi_level_bom" : d.include_exploded_items, + "sales_order" : d.sales_order, + "sales_order_item" : d.sales_order_item, + "material_request" : d.material_request, + "material_request_item" : d.material_request_item, + "bom_no" : d.bom_no, + "description" : d.description, + "stock_uom" : d.stock_uom, + "company" : self.company, + "fg_warehouse" : d.warehouse, + "production_plan" : self.name, + "production_plan_item" : d.name, + "product_bundle_item" : d.product_bundle_item, + "planned_start_date" : d.planned_start_date +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) } if not item_details["project"] and d.sales_order: @@ -604,7 +622,11 @@ class ProductionPlan(Document): wo = frappe.new_doc("Work Order") wo.update(item) +<<<<<<< HEAD wo.planned_start_date = item.get("planned_start_date") or item.get("schedule_date") +======= + wo.planned_start_date = item.get('planned_start_date') or item.get('schedule_date') +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) if item.get("warehouse"): wo.fg_warehouse = item.get("warehouse") @@ -763,9 +785,18 @@ def download_raw_materials(doc, warehouses=None): doc.warehouse = None frappe.flags.show_qty_in_stock_uom = 1 +<<<<<<< HEAD items = get_items_for_material_requests( doc, warehouses=warehouses, get_parent_warehouse_data=True ) +======= + items = get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True) + + for d in items: + item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('warehouse'), + d.get('required_bom_qty'), d.get('projected_qty'), d.get('actual_qty'), d.get('ordered_qty'), + d.get('planned_qty'), d.get('reserved_qty_for_production'), d.get('safety_stock'), d.get('quantity')]) +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) for d in items: item_list.append( @@ -810,6 +841,7 @@ def download_raw_materials(doc, warehouses=None): def get_exploded_items(item_details, company, bom_no, include_non_stock_items, planned_qty=1): +<<<<<<< HEAD bei = frappe.qb.DocType("BOM Explosion Item") bom = frappe.qb.DocType("BOM") item = frappe.qb.DocType("Item") @@ -915,6 +947,64 @@ def get_subitems( ) .groupby(bom_item.item_code) ).run(as_dict=True) +======= + for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, + ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0)*%s as qty, item.item_name, + bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, + item.default_material_request_type, item.min_order_qty, item_default.default_warehouse, + item.purchase_uom, item_uom.conversion_factor, item.safety_stock + from + `tabBOM Explosion Item` bei + JOIN `tabBOM` bom ON bom.name = bei.parent + JOIN `tabItem` item ON item.name = bei.item_code + LEFT JOIN `tabItem Default` item_default + ON item_default.parent = item.name and item_default.company=%s + LEFT JOIN `tabUOM Conversion Detail` item_uom + ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom + where + bei.docstatus < 2 + and bom.name=%s and item.is_stock_item in (1, {0}) + group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1), + (planned_qty, company, bom_no), as_dict=1): + if not d.conversion_factor and d.purchase_uom: + d.conversion_factor = get_uom_conversion_factor(d.item_code, d.purchase_uom) + item_details.setdefault(d.get('item_code'), d) + + return item_details + +def get_uom_conversion_factor(item_code, uom): + return frappe.db.get_value('UOM Conversion Detail', + {'parent': item_code, 'uom': uom}, 'conversion_factor') + +def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_items, + include_subcontracted_items, parent_qty, planned_qty=1): + items = frappe.db.sql(""" + SELECT + bom_item.item_code, default_material_request_type, item.item_name, + ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(planned_qty)s, 0) as qty, + item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, + item.default_bom as default_bom, bom_item.description as description, + bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, item.safety_stock as safety_stock, + item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor + FROM + `tabBOM Item` bom_item + JOIN `tabBOM` bom ON bom.name = bom_item.parent + JOIN tabItem item ON bom_item.item_code = item.name + LEFT JOIN `tabItem Default` item_default + ON item.name = item_default.parent and item_default.company = %(company)s + LEFT JOIN `tabUOM Conversion Detail` item_uom + ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom + where + bom.name = %(bom)s + and bom_item.docstatus < 2 + and item.is_stock_item in (1, {0}) + group by bom_item.item_code""".format(0 if include_non_stock_items else 1),{ + 'bom': bom_no, + 'parent_qty': parent_qty, + 'planned_qty': planned_qty, + 'company': company + }, as_dict=1) +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) for d in items: if not data.get("include_exploded_items") or not d.default_bom: @@ -961,6 +1051,7 @@ def get_material_request_items( if not row["purchase_uom"]: row["purchase_uom"] = row["stock_uom"] +<<<<<<< HEAD if row["purchase_uom"] != row["stock_uom"]: if not (row["conversion_factor"] or frappe.flags.show_qty_in_stock_uom): frappe.throw( @@ -968,6 +1059,14 @@ def get_material_request_items( row["purchase_uom"], row["stock_uom"], row.item_code ) ) +======= + if row['purchase_uom'] != row['stock_uom']: + if not (row['conversion_factor'] or frappe.flags.show_qty_in_stock_uom): + frappe.throw(_("UOM Conversion factor ({0} -> {1}) not found for item: {2}") + .format(row['purchase_uom'], row['stock_uom'], row.item_code)) + + required_qty = required_qty / row['conversion_factor'] +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) required_qty = required_qty / row["conversion_factor"] @@ -1214,9 +1313,14 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d elif data.get("item_code"): item_master = frappe.get_doc("Item", data["item_code"]).as_dict() purchase_uom = item_master.purchase_uom or item_master.stock_uom +<<<<<<< HEAD conversion_factor = ( get_uom_conversion_factor(item_master.name, purchase_uom) if item_master.purchase_uom else 1.0 ) +======= + conversion_factor = (get_uom_conversion_factor(item_master.name, purchase_uom) + if item_master.purchase_uom else 1.0) +>>>>>>> 2a8cd05b44 (fix: production plan UX and validation message (#27278)) item_details[item_master.name] = frappe._dict( {