refactor: ability to build and load tree from DB
This commit is contained in:
parent
d53b34c0ce
commit
b2dde55f2c
@ -14,15 +14,15 @@ frappe.ui.form.on("Bisect Accounting Statements", {
|
||||
frm.add_custom_button(__('Up'), () =>
|
||||
frm.trigger("move_up")
|
||||
);
|
||||
frm.add_custom_button(__('Bisect'), () =>
|
||||
frm.trigger("bisect")
|
||||
frm.add_custom_button(__('Build Tree'), () =>
|
||||
frm.trigger("build_tree")
|
||||
);
|
||||
// frm.change_custom_button_type(__('Bisect'), null, 'primary');
|
||||
},
|
||||
bisect(frm) {
|
||||
build_tree(frm) {
|
||||
frm.call({
|
||||
doc: frm.doc,
|
||||
method: 'bisect',
|
||||
method: 'build_tree',
|
||||
callback: (r) => {
|
||||
console.log(r);
|
||||
}
|
||||
|
@ -11,7 +11,14 @@
|
||||
"column_break_qxbi",
|
||||
"to_date",
|
||||
"column_break_iwny",
|
||||
"algorithm"
|
||||
"algorithm",
|
||||
"section_break_lwr2",
|
||||
"current_from_date",
|
||||
"column_break_uuic",
|
||||
"current_to_date",
|
||||
"section_break_zbty",
|
||||
"current_node",
|
||||
"tree"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -38,13 +45,45 @@
|
||||
{
|
||||
"fieldname": "column_break_iwny",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_zbty",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "tree",
|
||||
"fieldtype": "JSON",
|
||||
"label": "Tree"
|
||||
},
|
||||
{
|
||||
"fieldname": "current_node",
|
||||
"fieldtype": "JSON",
|
||||
"label": "Current Node"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_lwr2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "current_from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Current From Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "current_to_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Current To Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_uuic",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2023-09-25 10:50:53.887235",
|
||||
"modified": "2023-09-25 17:05:13.384320",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bisect Accounting Statements",
|
||||
|
@ -2,6 +2,7 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import datetime
|
||||
import json
|
||||
from collections import deque
|
||||
from math import floor
|
||||
|
||||
@ -10,85 +11,162 @@ from dateutil.relativedelta import relativedelta
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import getdate
|
||||
from frappe.utils.data import DATETIME_FORMAT, guess_date_format
|
||||
|
||||
|
||||
class Node(object):
|
||||
def __init__(self):
|
||||
self.parent = None
|
||||
self.left_child = None
|
||||
self.right_child = None
|
||||
|
||||
self.current_period = None
|
||||
self.difference = 0.0
|
||||
self.profit_and_loss_summary = 0.0
|
||||
self.balance_sheet_summary = 0.0
|
||||
|
||||
def update_parent(self):
|
||||
pass
|
||||
|
||||
def update_left_child(self):
|
||||
pass
|
||||
|
||||
def update_right_child(self):
|
||||
pass
|
||||
|
||||
def make_node(
|
||||
def __init__(
|
||||
self,
|
||||
parent: int = None,
|
||||
period: (datetime, datetime) = None,
|
||||
left: int = None,
|
||||
right: int = None,
|
||||
):
|
||||
current_period = period
|
||||
self.parent = parent
|
||||
self.left_child = left
|
||||
self.right_child = right
|
||||
|
||||
self.period = period
|
||||
self.difference = 0.0
|
||||
self.profit_and_loss_summary = 0.0
|
||||
self.balance_sheet_summary = 0.0
|
||||
|
||||
def as_dict(self):
|
||||
return dict(
|
||||
parent=self.parent,
|
||||
left_child=self.left_child,
|
||||
right_child=self.right_child,
|
||||
period=(self.period[0].strftime(DATETIME_FORMAT), self.period[1].strftime(DATETIME_FORMAT)),
|
||||
difference=self.difference,
|
||||
profit_and_loss_summary=self.profit_and_loss_summary,
|
||||
balance_sheet_summary=self.balance_sheet_summary,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Node (parent: {self.parent}, left_child: {self.left_child}, right_child: {self.right_child}, period: {self.period})"
|
||||
|
||||
|
||||
class BTree(object):
|
||||
def __init__(self):
|
||||
self.btree = []
|
||||
self.current_node = None
|
||||
|
||||
def as_list(self):
|
||||
lst = []
|
||||
for x in self.btree:
|
||||
lst.append(x.as_dict())
|
||||
return lst
|
||||
|
||||
def bfs(self, from_date: datetime, to_date: datetime):
|
||||
root_node = Node(parent=None, period=(getdate(from_date), getdate(to_date)))
|
||||
root_node.parent = None
|
||||
|
||||
# add root node to tree
|
||||
self.btree.append(root_node)
|
||||
cur_node = root_node
|
||||
period_list = deque([root_node])
|
||||
|
||||
periods = []
|
||||
while period_list:
|
||||
cur_node = period_list.popleft()
|
||||
cur_node_index = len(self.btree) - 1
|
||||
|
||||
delta = cur_node.period[1] - cur_node.period[0]
|
||||
if delta.days == 0:
|
||||
continue
|
||||
else:
|
||||
cur_floor = floor(delta.days / 2)
|
||||
left = (cur_node.period[0], (cur_node.period[0] + relativedelta(days=+cur_floor)))
|
||||
left_node = Node(parent=cur_node_index, period=left)
|
||||
self.btree.append(left_node)
|
||||
cur_node.left_child = len(self.btree) - 1
|
||||
period_list.append(left_node)
|
||||
|
||||
right = ((cur_node.period[0] + relativedelta(days=+(cur_floor + 1))), cur_node.period[1])
|
||||
right_node = Node(parent=cur_node_index, period=right)
|
||||
self.btree.append(right_node)
|
||||
cur_node.right_child = len(self.btree) - 1
|
||||
period_list.append(right_node)
|
||||
|
||||
def dfs(self, from_date: datetime, to_date: datetime):
|
||||
root_node = Node(parent=None, period=(getdate(from_date), getdate(to_date)))
|
||||
root_node.parent = None
|
||||
|
||||
# add root node to tree
|
||||
self.btree.append(root_node)
|
||||
cur_node = root_node
|
||||
period_list = [root_node]
|
||||
|
||||
periods = []
|
||||
while period_list:
|
||||
cur_node = period_list.pop()
|
||||
cur_node_index = len(self.btree) - 1
|
||||
|
||||
delta = cur_node.period[1] - cur_node.period[0]
|
||||
if delta.days == 0:
|
||||
continue
|
||||
else:
|
||||
cur_floor = floor(delta.days / 2)
|
||||
left = (cur_node.period[0], (cur_node.period[0] + relativedelta(days=+cur_floor)))
|
||||
left_node = Node(parent=cur_node_index, period=left)
|
||||
self.btree.append(left_node)
|
||||
cur_node.left_child = len(self.btree) - 1
|
||||
period_list.append(left_node)
|
||||
|
||||
right = ((cur_node.period[0] + relativedelta(days=+(cur_floor + 1))), cur_node.period[1])
|
||||
right_node = Node(parent=cur_node_index, period=right)
|
||||
self.btree.append(right_node)
|
||||
cur_node.right_child = len(self.btree) - 1
|
||||
period_list.append(right_node)
|
||||
|
||||
def load_tree(self, tree: list, current_node: dict):
|
||||
self.btree = []
|
||||
tree = json.loads(tree)
|
||||
for x in tree:
|
||||
x = frappe._dict(x)
|
||||
n = Node(x.parent, x.period, x.left_child, x.right_child)
|
||||
n.period = x.period
|
||||
n.difference = x.difference
|
||||
x.profit_and_loss_summary = x.profit_and_loss_summary
|
||||
x.balance_sheet_summary = x.balance_sheet_summary
|
||||
self.btree.append(n)
|
||||
|
||||
current_node = frappe._dict(json.loads(current_node))
|
||||
n = Node(
|
||||
current_node.parent, current_node.period, current_node.left_child, current_node.right_child
|
||||
)
|
||||
n.period = current_node.period
|
||||
n.difference = current_node.difference
|
||||
n.profit_and_loss_summary = current_node.profit_and_loss_summary
|
||||
n.balance_sheet_summary = current_node.balance_sheet_summary
|
||||
self.current_node = n
|
||||
|
||||
def build_tree(self, from_date: datetime, to_date: datetime, alogrithm: str):
|
||||
if alogrithm == "BFS":
|
||||
self.bfs(from_date, to_date)
|
||||
|
||||
if alogrithm == "DFS":
|
||||
self.dfs(from_date, to_date)
|
||||
|
||||
# set root as current node
|
||||
self.current_node = self.btree[0]
|
||||
|
||||
def bisec_left(self):
|
||||
pass
|
||||
|
||||
def bisect_right(self):
|
||||
pass
|
||||
|
||||
def move_up(self):
|
||||
pass
|
||||
|
||||
|
||||
class BisectAccountingStatements(Document):
|
||||
def bfs(self):
|
||||
period_list = deque([(getdate(self.from_date), getdate(self.to_date))])
|
||||
periods = []
|
||||
dates = []
|
||||
while period_list:
|
||||
cur_frm_date, cur_to_date = period_list.popleft()
|
||||
delta = cur_to_date - cur_frm_date
|
||||
periods.append((cur_frm_date, cur_to_date, delta))
|
||||
if delta.days == 0:
|
||||
continue
|
||||
else:
|
||||
cur_floor = floor(delta.days / 2)
|
||||
left = (cur_frm_date, (cur_frm_date + relativedelta(days=+cur_floor)))
|
||||
right = ((cur_frm_date + relativedelta(days=+(cur_floor + 1))), cur_to_date)
|
||||
period_list.append(left)
|
||||
period_list.append(right)
|
||||
return periods
|
||||
|
||||
def dfs(self):
|
||||
period_list = [(getdate(self.from_date), getdate(self.to_date))]
|
||||
periods = []
|
||||
while period_list:
|
||||
cur_frm_date, cur_to_date = period_list.pop()
|
||||
delta = cur_to_date - cur_frm_date
|
||||
periods.append((cur_frm_date, cur_to_date, delta))
|
||||
if delta.days == 0:
|
||||
continue
|
||||
else:
|
||||
cur_floor = floor(delta.days / 2)
|
||||
left = (cur_frm_date, (cur_frm_date + relativedelta(days=+cur_floor)))
|
||||
right = ((cur_frm_date + relativedelta(days=+(cur_floor + 1))), cur_to_date)
|
||||
period_list.append(left)
|
||||
period_list.append(right)
|
||||
return periods
|
||||
|
||||
@frappe.whitelist()
|
||||
def bisect(self):
|
||||
if self.algorithm == "BFS":
|
||||
periods = self.bfs()
|
||||
|
||||
if self.algorithm == "DFS":
|
||||
periods = self.dfs()
|
||||
|
||||
print("Periods: ", len(periods))
|
||||
for x in periods:
|
||||
print(x)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BisectAccountingStatements, self).__init__(*args, **kwargs)
|
||||
if self.tree and self.current_node:
|
||||
self.tree_instance = BTree()
|
||||
self.tree_instance.load_tree(self.tree, self.current_node)
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
@ -100,3 +178,18 @@ class BisectAccountingStatements(Document):
|
||||
frappe.bold(self.from_date), frappe.bold(self.to_date)
|
||||
)
|
||||
)
|
||||
|
||||
@frappe.whitelist()
|
||||
def build_tree(self):
|
||||
self.tree_instance = BTree()
|
||||
self.tree_instance.build_tree(self.from_date, self.to_date, self.algorithm)
|
||||
print("printing tree")
|
||||
for x in self.tree_instance.btree:
|
||||
print(x)
|
||||
|
||||
print("Root", self.tree_instnace.current_node)
|
||||
|
||||
self.tree = json.dumps(self.tree_instance.as_list())
|
||||
self.current_node = json.dumps(self.tree_intance.btree[0].as_dict())
|
||||
|
||||
print(guess_date_format(json.loads(self.current_node)["period"][0]))
|
||||
|
Loading…
x
Reference in New Issue
Block a user