perf: get_boms_in_bottom_up_order
- Create child-parent map once and fetch value from child key to get parents - Get parents recursively for a leaf node (get all ancestors) - Approx. 44 secs for 4lakh 70k boms
This commit is contained in:
parent
6d6616dbcd
commit
b6e46eea80
@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
from collections import deque
|
from collections import defaultdict, deque
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import List
|
from typing import List, Optional
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
@ -1130,35 +1130,77 @@ def get_children(parent=None, is_root=False, **filters):
|
|||||||
return bom_items
|
return bom_items
|
||||||
|
|
||||||
|
|
||||||
def get_boms_in_bottom_up_order(bom_no=None):
|
def get_boms_in_bottom_up_order(bom_no: Optional[str] = None) -> List:
|
||||||
def _get_parent(bom_no):
|
def _generate_child_parent_map():
|
||||||
return frappe.db.sql_list(
|
bom = frappe.qb.DocType("BOM")
|
||||||
"""
|
bom_item = frappe.qb.DocType("BOM Item")
|
||||||
select distinct bom_item.parent from `tabBOM Item` bom_item
|
|
||||||
where bom_item.bom_no = %s and bom_item.docstatus=1 and bom_item.parenttype='BOM'
|
|
||||||
and exists(select bom.name from `tabBOM` bom where bom.name=bom_item.parent and bom.is_active=1)
|
|
||||||
""",
|
|
||||||
bom_no,
|
|
||||||
)
|
|
||||||
|
|
||||||
count = 0
|
bom_parents = (
|
||||||
bom_list = []
|
frappe.qb.from_(bom_item)
|
||||||
if bom_no:
|
.join(bom)
|
||||||
bom_list.append(bom_no)
|
.on(bom_item.parent == bom.name)
|
||||||
else:
|
.select(bom_item.bom_no, bom_item.parent)
|
||||||
# get all leaf BOMs
|
.where(
|
||||||
bom_list = frappe.db.sql_list(
|
(bom_item.bom_no.isnotnull())
|
||||||
|
& (bom_item.bom_no != "")
|
||||||
|
& (bom.docstatus == 1)
|
||||||
|
& (bom.is_active == 1)
|
||||||
|
& (bom_item.parenttype == "BOM")
|
||||||
|
)
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
|
child_parent_map = defaultdict(list)
|
||||||
|
for bom in bom_parents:
|
||||||
|
child_parent_map[bom.bom_no].append(bom.parent)
|
||||||
|
|
||||||
|
return child_parent_map
|
||||||
|
|
||||||
|
def _get_flat_parent_map(leaf, child_parent_map):
|
||||||
|
parents_list = []
|
||||||
|
|
||||||
|
def _get_parents(node, parents_list):
|
||||||
|
"Returns updated ancestors list."
|
||||||
|
first_parents = child_parent_map.get(node) # immediate parents of node
|
||||||
|
if not first_parents: # top most node
|
||||||
|
return parents_list
|
||||||
|
|
||||||
|
parents_list.extend(first_parents)
|
||||||
|
parents_list = list(dict.fromkeys(parents_list).keys()) # remove duplicates
|
||||||
|
|
||||||
|
for nth_node in first_parents:
|
||||||
|
# recursively find parents
|
||||||
|
parents_list = _get_parents(nth_node, parents_list)
|
||||||
|
|
||||||
|
return parents_list
|
||||||
|
|
||||||
|
parents_list = _get_parents(leaf, parents_list)
|
||||||
|
return parents_list
|
||||||
|
|
||||||
|
def _get_leaf_boms():
|
||||||
|
return frappe.db.sql_list(
|
||||||
"""select name from `tabBOM` bom
|
"""select name from `tabBOM` bom
|
||||||
where docstatus=1 and is_active=1
|
where docstatus=1 and is_active=1
|
||||||
and not exists(select bom_no from `tabBOM Item`
|
and not exists(select bom_no from `tabBOM Item`
|
||||||
where parent=bom.name and ifnull(bom_no, '')!='')"""
|
where parent=bom.name and ifnull(bom_no, '')!='')"""
|
||||||
)
|
)
|
||||||
|
|
||||||
while count < len(bom_list):
|
bom_list = []
|
||||||
for child_bom in _get_parent(bom_list[count]):
|
if bom_no:
|
||||||
if child_bom not in bom_list:
|
bom_list.append(bom_no)
|
||||||
bom_list.append(child_bom)
|
else:
|
||||||
count += 1
|
bom_list = _get_leaf_boms()
|
||||||
|
|
||||||
|
child_parent_map = _generate_child_parent_map()
|
||||||
|
|
||||||
|
for leaf_bom in bom_list:
|
||||||
|
# generate list recursively bottom to top
|
||||||
|
parent_list = _get_flat_parent_map(leaf_bom, child_parent_map)
|
||||||
|
|
||||||
|
if not parent_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
bom_list.extend(parent_list)
|
||||||
|
bom_list = list(dict.fromkeys(bom_list).keys()) # remove duplicates
|
||||||
|
|
||||||
return bom_list
|
return bom_list
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user