From eb4c476490ea32cd94e0b6cc3715abe99f1d4e0a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 15 Sep 2023 21:24:53 +0530 Subject: [PATCH 01/31] refactor: primitive summary for p&l and balance sheet --- erpnext/accounts/report/balance_sheet/balance_sheet.py | 6 +++--- .../profit_and_loss_statement/profit_and_loss_statement.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index b225aac7b5..5d6ca23a6b 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -97,11 +97,11 @@ def execute(filters=None): chart = get_chart_data(filters, columns, asset, liability, equity) - report_summary = get_report_summary( + report_summary, primitive_summary = get_report_summary( period_list, asset, liability, equity, provisional_profit_loss, currency, filters ) - return columns, data, message, chart, report_summary + return columns, data, message, chart, report_summary, primitive_summary def get_provisional_profit_loss( @@ -217,7 +217,7 @@ def get_report_summary( "datatype": "Currency", "currency": currency, }, - ] + ], (net_asset - net_liability + net_equity) def get_chart_data(filters, columns, asset, liability, equity): diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py index 66353358a0..002c05c9e3 100644 --- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py +++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py @@ -66,11 +66,11 @@ def execute(filters=None): currency = filters.presentation_currency or frappe.get_cached_value( "Company", filters.company, "default_currency" ) - report_summary = get_report_summary( + report_summary, primitive_summary = get_report_summary( period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters ) - return columns, data, None, chart, report_summary + return columns, data, None, chart, report_summary, primitive_summary def get_report_summary( @@ -112,7 +112,7 @@ def get_report_summary( "datatype": "Currency", "currency": currency, }, - ] + ], net_profit def get_net_profit_loss(income, expense, period_list, company, currency=None, consolidated=False): From decdbd278200bb83baa7c5f08bd706c1c7c5406a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 15 Sep 2023 21:38:15 +0530 Subject: [PATCH 02/31] feat: bisect doctype --- .../bisect_accounting_statements/__init__.py | 0 .../bisect_accounting_statements.js | 8 +++ .../bisect_accounting_statements.json | 54 +++++++++++++++++++ .../bisect_accounting_statements.py | 9 ++++ .../test_bisect_accounting_statements.py | 9 ++++ 5 files changed, 80 insertions(+) create mode 100644 erpnext/accounts/doctype/bisect_accounting_statements/__init__.py create mode 100644 erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js create mode 100644 erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json create mode 100644 erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py create mode 100644 erpnext/accounts/doctype/bisect_accounting_statements/test_bisect_accounting_statements.py diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/__init__.py b/erpnext/accounts/doctype/bisect_accounting_statements/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js new file mode 100644 index 0000000000..7e1fb48fe3 --- /dev/null +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Bisect Accounting Statements", { +// refresh(frm) { + +// }, +// }); diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json new file mode 100644 index 0000000000..1ffa3adcb3 --- /dev/null +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -0,0 +1,54 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-09-15 21:28:28.054773", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from", + "column_break_qxbi", + "to" + ], + "fields": [ + { + "fieldname": "from", + "fieldtype": "Date", + "label": "From" + }, + { + "fieldname": "to", + "fieldtype": "Date", + "label": "To" + }, + { + "fieldname": "column_break_qxbi", + "fieldtype": "Column Break" + } + ], + "hide_toolbar": 1, + "index_web_pages_for_search": 1, + "issingle": 1, + "links": [], + "modified": "2023-09-15 21:36:21.516679", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Bisect Accounting Statements", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py new file mode 100644 index 0000000000..8ab97b47a8 --- /dev/null +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class BisectAccountingStatements(Document): + pass diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/test_bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/test_bisect_accounting_statements.py new file mode 100644 index 0000000000..56ecc94a18 --- /dev/null +++ b/erpnext/accounts/doctype/bisect_accounting_statements/test_bisect_accounting_statements.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestBisectAccountingStatements(FrappeTestCase): + pass From 4c8a8c3bcd9bf21918a78de244789c7de76cede9 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 18 Sep 2023 12:35:24 +0530 Subject: [PATCH 03/31] refactor: some logic --- .../bisect_accounting_statements.js | 22 +++++++-- .../bisect_accounting_statements.json | 48 ++++++++++++++----- .../bisect_accounting_statements.py | 17 ++++++- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 7e1fb48fe3..96b9709bee 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -1,8 +1,20 @@ // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -// frappe.ui.form.on("Bisect Accounting Statements", { -// refresh(frm) { - -// }, -// }); +frappe.ui.form.on("Bisect Accounting Statements", { + refresh(frm) { + frm.add_custom_button(__('Bisect'), () => + frm.trigger("bisect") + ); + frm.change_custom_button_type(__('Bisect'), null, 'primary'); + }, + bisect(frm) { + frm.call({ + doc: frm.doc, + method: 'bisect', + callback: (r) => { + console.log(r); + } + }); + } +}); diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index 1ffa3adcb3..de7eba7c63 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -7,31 +7,53 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "from", + "from_date", "column_break_qxbi", - "to" + "to_date", + "section_break_3x70", + "period_from", + "column_break_5ett", + "period_to" ], "fields": [ - { - "fieldname": "from", - "fieldtype": "Date", - "label": "From" - }, - { - "fieldname": "to", - "fieldtype": "Date", - "label": "To" - }, { "fieldname": "column_break_qxbi", "fieldtype": "Column Break" + }, + { + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Date" + }, + { + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date" + }, + { + "fieldname": "section_break_3x70", + "fieldtype": "Section Break" + }, + { + "fieldname": "period_from", + "fieldtype": "Date", + "label": "Period From" + }, + { + "fieldname": "column_break_5ett", + "fieldtype": "Column Break" + }, + { + "fieldname": "period_to", + "fieldtype": "Date", + "label": "Period To" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-15 21:36:21.516679", + "modified": "2023-09-16 08:02:33.472406", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 8ab97b47a8..2e209d2a63 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -1,9 +1,22 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -# import frappe +from math import ceil, floor + +import frappe +from dateutil.relativedelta import relativedelta from frappe.model.document import Document +from frappe.utils import getdate class BisectAccountingStatements(Document): - pass + @frappe.whitelist() + def bisect(self): + cur_frm_date, cur_to_date = getdate(self.from_date), getdate(self.to_date) + while True: + delta = cur_to_date - cur_frm_date + if delta.days == 0: + return + cur_floor = floor(delta.days / 2) + cur_to_date = cur_frm_date + relativedelta(days=+cur_floor) + print((cur_frm_date, cur_to_date), delta, cur_floor) From 5a25c80f2eb434313b65b1b3b08bd0ea5e393461 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 10:35:54 +0530 Subject: [PATCH 04/31] refactor: Depth First Search(DFS) --- .../bisect_accounting_statements.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 2e209d2a63..6be28c87bc 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -1,7 +1,7 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from math import ceil, floor +from math import floor import frappe from dateutil.relativedelta import relativedelta @@ -12,11 +12,18 @@ from frappe.utils import getdate class BisectAccountingStatements(Document): @frappe.whitelist() def bisect(self): - cur_frm_date, cur_to_date = getdate(self.from_date), getdate(self.to_date) - while True: + period_list = [(getdate(self.from_date), getdate(self.to_date))] + dates = [] + while period_list: + cur_frm_date, cur_to_date = period_list.pop() delta = cur_to_date - cur_frm_date - if delta.days == 0: - return + if not delta.days > 0: + continue + cur_floor = floor(delta.days / 2) - cur_to_date = cur_frm_date + relativedelta(days=+cur_floor) - print((cur_frm_date, cur_to_date), delta, cur_floor) + next_to_date = cur_frm_date + relativedelta(days=+cur_floor) + left = (cur_frm_date, next_to_date) + period_list.append(left) + next_frm_date = cur_frm_date + relativedelta(days=+(cur_floor + 1)) + right = (next_frm_date, cur_to_date) + period_list.append(right) From 26503a205f07a80f124c3dc5a59c039ed8ea708b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 10:39:39 +0530 Subject: [PATCH 05/31] refactor: simplify DFS --- .../bisect_accounting_statements.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 6be28c87bc..73a9e71960 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -21,9 +21,7 @@ class BisectAccountingStatements(Document): continue cur_floor = floor(delta.days / 2) - next_to_date = cur_frm_date + relativedelta(days=+cur_floor) - left = (cur_frm_date, next_to_date) + 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) - next_frm_date = cur_frm_date + relativedelta(days=+(cur_floor + 1)) - right = (next_frm_date, cur_to_date) period_list.append(right) From 03a38ed0257cdee5ae1ec645877691ed1292ba9c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 11:05:30 +0530 Subject: [PATCH 06/31] refactor: support for BFS and DFS --- .../bisect_accounting_statements.json | 27 ++++------ .../bisect_accounting_statements.py | 50 +++++++++++++++---- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index de7eba7c63..b2f3c4bb90 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -10,10 +10,8 @@ "from_date", "column_break_qxbi", "to_date", - "section_break_3x70", - "period_from", - "column_break_5ett", - "period_to" + "column_break_iwny", + "algorithm" ], "fields": [ { @@ -31,29 +29,22 @@ "label": "To Date" }, { - "fieldname": "section_break_3x70", - "fieldtype": "Section Break" + "default": "BFS", + "fieldname": "algorithm", + "fieldtype": "Select", + "label": "Algorithm", + "options": "BFS\nDFS" }, { - "fieldname": "period_from", - "fieldtype": "Date", - "label": "Period From" - }, - { - "fieldname": "column_break_5ett", + "fieldname": "column_break_iwny", "fieldtype": "Column Break" - }, - { - "fieldname": "period_to", - "fieldtype": "Date", - "label": "Period To" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-16 08:02:33.472406", + "modified": "2023-09-25 10:50:53.887235", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 73a9e71960..bdd1809535 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -1,6 +1,7 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +from collections import deque from math import floor import frappe @@ -10,18 +11,49 @@ from frappe.utils import getdate class BisectAccountingStatements(Document): - @frappe.whitelist() - def bisect(self): - period_list = [(getdate(self.from_date), getdate(self.to_date))] + 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 - if not delta.days > 0: + 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 - 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) + @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) From 2de3e6ce6d38cfc8b520365de79044d616fbd24b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 11:13:50 +0530 Subject: [PATCH 07/31] refactor: date validation --- .../bisect_accounting_statements.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index bdd1809535..e032083f90 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -6,6 +6,7 @@ from math import floor import frappe from dateutil.relativedelta import relativedelta +from frappe import _ from frappe.model.document import Document from frappe.utils import getdate @@ -57,3 +58,14 @@ class BisectAccountingStatements(Document): print("Periods: ", len(periods)) for x in periods: print(x) + + def validate(self): + self.validate_dates() + + def validate_dates(self): + if getdate(self.from_date) > getdate(self.to_date): + frappe.throw( + _("From Date: {0} cannot be greater than To date: {1}").format( + frappe.bold(self.from_date), frappe.bold(self.to_date) + ) + ) From a4270291511954b0e68fc126626967f4939c7617 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 12:16:27 +0530 Subject: [PATCH 08/31] refactor: more buttons --- .../bisect_accounting_statements.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 96b9709bee..69bd56e73f 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -3,10 +3,21 @@ frappe.ui.form.on("Bisect Accounting Statements", { refresh(frm) { + frm.add_custom_button(__('Bisect Left'), () => + frm.trigger("bisect_left") + ); + + frm.add_custom_button(__('Bisect Right'), () => + frm.trigger("bisect_right") + ); + + frm.add_custom_button(__('Up'), () => + frm.trigger("move_up") + ); frm.add_custom_button(__('Bisect'), () => frm.trigger("bisect") ); - frm.change_custom_button_type(__('Bisect'), null, 'primary'); + // frm.change_custom_button_type(__('Bisect'), null, 'primary'); }, bisect(frm) { frm.call({ From d53b34c0ce9f469fec79b0cbc08e4cbc47344b46 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 12:16:47 +0530 Subject: [PATCH 09/31] refactor: introduce `node` class --- .../bisect_accounting_statements.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index e032083f90..3582033abc 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -1,6 +1,7 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +import datetime from collections import deque from math import floor @@ -11,6 +12,36 @@ from frappe.model.document import Document from frappe.utils import getdate +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( + self, + parent: int = None, + period: (datetime, datetime) = None, + left: int = None, + right: int = None, + ): + current_period = period + + class BisectAccountingStatements(Document): def bfs(self): period_list = deque([(getdate(self.from_date), getdate(self.to_date))]) From b2dde55f2ccf337e2b07aac8b62c24791c4975c9 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 20:59:39 +0530 Subject: [PATCH 10/31] refactor: ability to build and load tree from DB --- .../bisect_accounting_statements.js | 8 +- .../bisect_accounting_statements.json | 43 +++- .../bisect_accounting_statements.py | 227 ++++++++++++------ 3 files changed, 205 insertions(+), 73 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 69bd56e73f..732b2b0f9c 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -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); } diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index b2f3c4bb90..e0b84adeeb 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -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", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 3582033abc..7c68f18775 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -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])) From 705ef4f5a31aac60ac879adecbede33ffd573588 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 21:16:18 +0530 Subject: [PATCH 11/31] refactor: add basic navigation 1. remove unnecessary columns 2. added basic tree navigation --- .../bisect_accounting_statements.js | 27 ++++++++++++ .../bisect_accounting_statements.json | 24 +---------- .../bisect_accounting_statements.py | 42 ++++++++++++++++--- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 732b2b0f9c..4e478ee4ab 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -19,6 +19,33 @@ frappe.ui.form.on("Bisect Accounting Statements", { ); // frm.change_custom_button_type(__('Bisect'), null, 'primary'); }, + bisect_left(frm) { + frm.call({ + doc: frm.doc, + method: 'bisect_left', + callback: (r) => { + console.log(r); + } + }); + }, + bisect_right(frm) { + frm.call({ + doc: frm.doc, + method: 'bisect_right', + callback: (r) => { + console.log(r); + } + }); + }, + move_up(frm) { + frm.call({ + doc: frm.doc, + method: 'move_up', + callback: (r) => { + console.log(r); + } + }); + }, build_tree(frm) { frm.call({ doc: frm.doc, diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index e0b84adeeb..c5715fe2ea 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -12,10 +12,6 @@ "to_date", "column_break_iwny", "algorithm", - "section_break_lwr2", - "current_from_date", - "column_break_uuic", - "current_to_date", "section_break_zbty", "current_node", "tree" @@ -59,31 +55,13 @@ "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 17:05:13.384320", + "modified": "2023-09-25 21:15:47.905386", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 7c68f18775..accc8a9b42 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -124,8 +124,12 @@ class BTree(object): 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 = Node(x.parent, None, x.left_child, x.right_child) + date_format = guess_date_format(x.period[0]) + n.period = ( + datetime.datetime.strptime(x.period[0], date_format), + datetime.datetime.strptime(x.period[1], date_format), + ) n.difference = x.difference x.profit_and_loss_summary = x.profit_and_loss_summary x.balance_sheet_summary = x.balance_sheet_summary @@ -187,9 +191,37 @@ class BisectAccountingStatements(Document): for x in self.tree_instance.btree: print(x) - print("Root", self.tree_instnace.current_node) + print("Root", self.tree_instance.current_node) self.tree = json.dumps(self.tree_instance.as_list()) - self.current_node = json.dumps(self.tree_intance.btree[0].as_dict()) + self.current_node = json.dumps(self.tree_instance.btree[0].as_dict()) - print(guess_date_format(json.loads(self.current_node)["period"][0])) + @frappe.whitelist() + def bisect_left(self): + if self.tree_instance.current_node is not None: + if self.tree_instance.current_node.left_child is not None: + self.current_node = self.tree_instance.btree[self.tree_instance.current_node.left_child] + self.current_node = json.dumps(self.current_node.as_dict()) + self.save() + else: + frappe.msgprint("No more children on Left") + + @frappe.whitelist() + def bisect_right(self): + if self.tree_instance.current_node is not None: + if self.tree_instance.current_node.right_child is not None: + self.current_node = self.tree_instance.btree[self.tree_instance.current_node.right_child] + self.current_node = json.dumps(self.current_node.as_dict()) + self.save() + else: + frappe.msgprint("No more children on Right") + + @frappe.whitelist() + def move_up(self): + if self.tree_instance.current_node is not None: + if self.tree_instance.current_node.parent is not None: + self.current_node = self.tree_instance.btree[self.tree_instance.current_node.parent] + self.current_node = json.dumps(self.current_node.as_dict()) + self.save() + else: + frappe.msgprint("Reached Root") From de2eba0d98409083c43affb485f4a44241e79b87 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 22:01:07 +0530 Subject: [PATCH 12/31] chore: remove unwanted code --- .../bisect_accounting_statements.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index accc8a9b42..950d5afab3 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -66,7 +66,6 @@ class BTree(object): 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 @@ -97,7 +96,6 @@ class BTree(object): cur_node = root_node period_list = [root_node] - periods = [] while period_list: cur_node = period_list.pop() cur_node_index = len(self.btree) - 1 From 85f2a6dd545a6e55d3c4d7fe64bea39a3122598c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Sep 2023 22:06:05 +0530 Subject: [PATCH 13/31] feat: nodes doctype --- erpnext/accounts/doctype/nodes/__init__.py | 0 erpnext/accounts/doctype/nodes/nodes.js | 8 ++ erpnext/accounts/doctype/nodes/nodes.json | 89 ++++++++++++++++++++ erpnext/accounts/doctype/nodes/nodes.py | 9 ++ erpnext/accounts/doctype/nodes/test_nodes.py | 9 ++ 5 files changed, 115 insertions(+) create mode 100644 erpnext/accounts/doctype/nodes/__init__.py create mode 100644 erpnext/accounts/doctype/nodes/nodes.js create mode 100644 erpnext/accounts/doctype/nodes/nodes.json create mode 100644 erpnext/accounts/doctype/nodes/nodes.py create mode 100644 erpnext/accounts/doctype/nodes/test_nodes.py diff --git a/erpnext/accounts/doctype/nodes/__init__.py b/erpnext/accounts/doctype/nodes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/nodes/nodes.js b/erpnext/accounts/doctype/nodes/nodes.js new file mode 100644 index 0000000000..bd74d68637 --- /dev/null +++ b/erpnext/accounts/doctype/nodes/nodes.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Nodes", { +// refresh(frm) { + +// }, +// }); diff --git a/erpnext/accounts/doctype/nodes/nodes.json b/erpnext/accounts/doctype/nodes/nodes.json new file mode 100644 index 0000000000..1238c8136a --- /dev/null +++ b/erpnext/accounts/doctype/nodes/nodes.json @@ -0,0 +1,89 @@ +{ + "actions": [], + "autoname": "autoincrement", + "creation": "2023-09-25 22:01:33.961832", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "root", + "left_child", + "right_child", + "period_from_date", + "period_to_date", + "difference", + "balance_sheet_summary", + "profit_loss_summary" + ], + "fields": [ + { + "fieldname": "root", + "fieldtype": "Link", + "label": "Root", + "options": "Nodes" + }, + { + "fieldname": "left_child", + "fieldtype": "Link", + "label": "Left Child", + "options": "Nodes" + }, + { + "fieldname": "right_child", + "fieldtype": "Link", + "label": "Right Child", + "options": "Nodes" + }, + { + "fieldname": "period_from_date", + "fieldtype": "Datetime", + "label": "Period_from_date" + }, + { + "fieldname": "period_to_date", + "fieldtype": "Datetime", + "label": "Period To Date" + }, + { + "fieldname": "difference", + "fieldtype": "Float", + "label": "Difference" + }, + { + "fieldname": "balance_sheet_summary", + "fieldtype": "Float", + "label": "Balance Sheet Summary" + }, + { + "fieldname": "profit_loss_summary", + "fieldtype": "Float", + "label": "Profit and Loss Summary" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-09-25 22:05:49.577861", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Nodes", + "naming_rule": "Autoincrement", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/nodes/nodes.py b/erpnext/accounts/doctype/nodes/nodes.py new file mode 100644 index 0000000000..67d5d69bfe --- /dev/null +++ b/erpnext/accounts/doctype/nodes/nodes.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class Nodes(Document): + pass diff --git a/erpnext/accounts/doctype/nodes/test_nodes.py b/erpnext/accounts/doctype/nodes/test_nodes.py new file mode 100644 index 0000000000..feeef765e0 --- /dev/null +++ b/erpnext/accounts/doctype/nodes/test_nodes.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestNodes(FrappeTestCase): + pass From 9d2025636689cf0c6f44f9784537d9eb132b820c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Sep 2023 08:43:59 +0530 Subject: [PATCH 14/31] chore: use doctype as btree --- .../bisect_accounting_statements.py | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 950d5afab3..53319b3c58 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -58,33 +58,51 @@ class BTree(object): 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 + node = frappe.new_doc("Nodes") + node.period_from_date = from_date + node.period_to_date = to_date + node.root = None + node.insert() - # add root node to tree - self.btree.append(root_node) - cur_node = root_node - period_list = deque([root_node]) + period_list = deque([node]) while period_list: cur_node = period_list.popleft() - cur_node_index = len(self.btree) - 1 - delta = cur_node.period[1] - cur_node.period[0] + print(cur_node.as_dict()) + delta = cur_node.period_to_date - cur_node.period_from_date 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 + left = ( + cur_node.period_from_date, + (cur_node.period_from_date + relativedelta(days=+cur_floor)), + ) + left_node = frappe.get_doc( + { + "doctype": "Nodes", + "period_from_date": cur_node.period_from_date, + "period_to_date": left, + "root": cur_node.name, + } + ).insert() + cur_node.left_child = left_node.name 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 + right = ( + (cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))), + cur_node.period_to_date, + ) + right_node = frappe.get_doc( + { + "doctype": "Nodes", + "period_from_date": right, + "period_to_date": cur_node.period_to_date, + "root": cur_node.name, + } + ).insert() + cur_node.right_child = right_node period_list.append(right_node) def dfs(self, from_date: datetime, to_date: datetime): @@ -144,6 +162,7 @@ class BTree(object): self.current_node = n def build_tree(self, from_date: datetime, to_date: datetime, alogrithm: str): + frappe.db.delete("Nodes") if alogrithm == "BFS": self.bfs(from_date, to_date) From 99fbd8ad186c989faa86863d5902a3b4d2015505 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Sep 2023 12:28:38 +0530 Subject: [PATCH 15/31] refactor: use DB to store tree and state --- .../bisect_accounting_statements.json | 19 +- .../bisect_accounting_statements.py | 304 +++++++----------- 2 files changed, 115 insertions(+), 208 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index c5715fe2ea..0de820a80f 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -13,8 +13,7 @@ "column_break_iwny", "algorithm", "section_break_zbty", - "current_node", - "tree" + "current_node" ], "fields": [ { @@ -23,12 +22,12 @@ }, { "fieldname": "from_date", - "fieldtype": "Date", + "fieldtype": "Datetime", "label": "From Date" }, { "fieldname": "to_date", - "fieldtype": "Date", + "fieldtype": "Datetime", "label": "To Date" }, { @@ -46,22 +45,18 @@ "fieldname": "section_break_zbty", "fieldtype": "Section Break" }, - { - "fieldname": "tree", - "fieldtype": "JSON", - "label": "Tree" - }, { "fieldname": "current_node", - "fieldtype": "JSON", - "label": "Current Node" + "fieldtype": "Link", + "label": "Current Node", + "options": "Nodes" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-25 21:15:47.905386", + "modified": "2023-09-26 12:09:23.649156", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 53319b3c58..8730772e29 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -2,7 +2,6 @@ # For license information, please see license.txt import datetime -import json from collections import deque from math import floor @@ -11,184 +10,10 @@ 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, - parent: int = None, - period: (datetime, datetime) = None, - left: int = None, - right: int = None, - ): - 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): - node = frappe.new_doc("Nodes") - node.period_from_date = from_date - node.period_to_date = to_date - node.root = None - node.insert() - - period_list = deque([node]) - - while period_list: - cur_node = period_list.popleft() - - print(cur_node.as_dict()) - delta = cur_node.period_to_date - cur_node.period_from_date - if delta.days == 0: - continue - else: - cur_floor = floor(delta.days / 2) - left = ( - cur_node.period_from_date, - (cur_node.period_from_date + relativedelta(days=+cur_floor)), - ) - left_node = frappe.get_doc( - { - "doctype": "Nodes", - "period_from_date": cur_node.period_from_date, - "period_to_date": left, - "root": cur_node.name, - } - ).insert() - cur_node.left_child = left_node.name - period_list.append(left_node) - - right = ( - (cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))), - cur_node.period_to_date, - ) - right_node = frappe.get_doc( - { - "doctype": "Nodes", - "period_from_date": right, - "period_to_date": cur_node.period_to_date, - "root": cur_node.name, - } - ).insert() - cur_node.right_child = right_node - 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] - - 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, None, x.left_child, x.right_child) - date_format = guess_date_format(x.period[0]) - n.period = ( - datetime.datetime.strptime(x.period[0], date_format), - datetime.datetime.strptime(x.period[1], date_format), - ) - 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): - frappe.db.delete("Nodes") - 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 +from frappe.utils.data import guess_date_format class BisectAccountingStatements(Document): - 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() @@ -200,45 +25,132 @@ class BisectAccountingStatements(Document): ) ) + def bfs(self, from_date: datetime, to_date: datetime): + # Make Root node + node = frappe.new_doc("Nodes") + node.root = None + node.period_from_date = from_date + node.period_to_date = to_date + node.insert() + + period_queue = deque([node]) + while period_queue: + cur_node = period_queue.popleft() + delta = cur_node.period_to_date - cur_node.period_from_date + if delta.days == 0: + continue + else: + cur_floor = floor(delta.days / 2) + next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor) + left_node = frappe.new_doc("Nodes") + left_node.period_from_date = cur_node.period_from_date + left_node.period_to_date = next_to_date + left_node.root = cur_node.name + left_node.insert() + cur_node.left_child = left_node.name + period_queue.append(left_node) + + next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1)) + right_node = frappe.new_doc("Nodes") + right_node.period_from_date = next_from_date + right_node.period_to_date = cur_node.period_to_date + right_node.root = cur_node.name + right_node.insert() + cur_node.right_child = right_node.name + period_queue.append(right_node) + + cur_node.save() + + def dfs(self, from_date: datetime, to_date: datetime): + # Make Root node + node = frappe.new_doc("Nodes") + node.root = None + node.period_from_date = from_date + node.period_to_date = to_date + node.insert() + + period_stack = [node] + while period_stack: + cur_node = period_stack.pop() + delta = cur_node.period_to_date - cur_node.period_from_date + if delta.days == 0: + continue + else: + cur_floor = floor(delta.days / 2) + next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor) + left_node = frappe.new_doc("Nodes") + left_node.period_from_date = cur_node.period_from_date + left_node.period_to_date = next_to_date + left_node.root = cur_node.name + left_node.insert() + cur_node.left_child = left_node.name + period_stack.append(left_node) + + next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1)) + right_node = frappe.new_doc("Nodes") + right_node.period_from_date = next_from_date + right_node.period_to_date = cur_node.period_to_date + right_node.root = cur_node.name + right_node.insert() + cur_node.right_child = right_node.name + period_stack.append(right_node) + + cur_node.save() + @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) + frappe.db.delete("Nodes") - print("Root", self.tree_instance.current_node) + # Convert str to datetime format + dt_format = guess_date_format(self.from_date) + from_date = datetime.datetime.strptime(self.from_date, dt_format) + to_date = datetime.datetime.strptime(self.to_date, dt_format) - self.tree = json.dumps(self.tree_instance.as_list()) - self.current_node = json.dumps(self.tree_instance.btree[0].as_dict()) + if self.algorithm == "BFS": + self.bfs(from_date, to_date) + + if self.algorithm == "DFS": + self.dfs(from_date, to_date) + + # set root as current node + root = frappe.db.get_all("Nodes", filters={"root": ["is", "not set"]})[0] + frappe.db.set_single_value("Bisect Accounting Statements", "current_node", root.name) @frappe.whitelist() def bisect_left(self): - if self.tree_instance.current_node is not None: - if self.tree_instance.current_node.left_child is not None: - self.current_node = self.tree_instance.btree[self.tree_instance.current_node.left_child] - self.current_node = json.dumps(self.current_node.as_dict()) + if self.current_node is not None: + cur_node = frappe.get_doc("Nodes", self.current_node) + if cur_node.left_child is not None: + lft_node = frappe.get_doc("Nodes", cur_node.left_child) + self.current_node = cur_node.left_child + self.from_date = lft_node.period_from_date + self.to_date = lft_node.period_to_date self.save() else: frappe.msgprint("No more children on Left") @frappe.whitelist() def bisect_right(self): - if self.tree_instance.current_node is not None: - if self.tree_instance.current_node.right_child is not None: - self.current_node = self.tree_instance.btree[self.tree_instance.current_node.right_child] - self.current_node = json.dumps(self.current_node.as_dict()) + if self.current_node is not None: + cur_node = frappe.get_doc("Nodes", self.current_node) + if cur_node.right_child is not None: + rgt_node = frappe.get_doc("Nodes", cur_node.right_child) + self.current_node = cur_node.right_child + self.from_date = rgt_node.period_from_date + self.to_date = rgt_node.period_to_date self.save() else: frappe.msgprint("No more children on Right") @frappe.whitelist() def move_up(self): - if self.tree_instance.current_node is not None: - if self.tree_instance.current_node.parent is not None: - self.current_node = self.tree_instance.btree[self.tree_instance.current_node.parent] - self.current_node = json.dumps(self.current_node.as_dict()) + if self.current_node is not None: + cur_node = frappe.get_doc("Nodes", self.current_node) + if cur_node.root is not None: + root = frappe.get_doc("Nodes", cur_node.root) + self.current_node = cur_node.root + self.from_date = root.period_from_date + self.to_date = root.period_to_date self.save() else: frappe.msgprint("Reached Root") From f7b7b2b438c3c5496097de1a740d6d4ede09605b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Sep 2023 20:33:13 +0530 Subject: [PATCH 16/31] refactor: calculate summary on tree navigation --- .../bisect_accounting_statements.js | 3 +- .../bisect_accounting_statements.json | 77 ++++++++++++++++++- .../bisect_accounting_statements.py | 29 +++++-- 3 files changed, 99 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 4e478ee4ab..7abe4f87ae 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -17,7 +17,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { frm.add_custom_button(__('Build Tree'), () => frm.trigger("build_tree") ); - // frm.change_custom_button_type(__('Bisect'), null, 'primary'); }, bisect_left(frm) { frm.call({ @@ -54,5 +53,5 @@ frappe.ui.form.on("Bisect Accounting Statements", { console.log(r); } }); - } + }, }); diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index 0de820a80f..c76ef4d06f 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -7,13 +7,26 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "company", + "column_break_hcam", "from_date", "column_break_qxbi", "to_date", "column_break_iwny", "algorithm", "section_break_zbty", - "current_node" + "current_node", + "sandbox", + "section_break_hmsy", + "current_from_date", + "column_break_uqyd", + "current_to_date", + "section_break_hbyo", + "p_l_summary", + "column_break_aivo", + "b_s_summary", + "column_break_gvwx", + "difference" ], "fields": [ { @@ -50,13 +63,73 @@ "fieldtype": "Link", "label": "Current Node", "options": "Nodes" + }, + { + "fieldname": "sandbox", + "fieldtype": "HTML", + "label": "sandbox" + }, + { + "fieldname": "section_break_hmsy", + "fieldtype": "Section Break" + }, + { + "fieldname": "current_from_date", + "fieldtype": "Datetime", + "label": "Current From Date" + }, + { + "fieldname": "current_to_date", + "fieldtype": "Datetime", + "label": "Current To Date" + }, + { + "fieldname": "column_break_uqyd", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_hbyo", + "fieldtype": "Section Break" + }, + { + "fieldname": "p_l_summary", + "fieldtype": "Data", + "label": "P&L Summary" + }, + { + "fieldname": "b_s_summary", + "fieldtype": "Data", + "label": "Balance Sheet Summary" + }, + { + "fieldname": "difference", + "fieldtype": "Data", + "label": "Difference" + }, + { + "fieldname": "column_break_aivo", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_gvwx", + "fieldtype": "Column Break" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" + }, + { + "fieldname": "column_break_hcam", + "fieldtype": "Column Break" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-26 12:09:23.649156", + "modified": "2023-09-26 21:07:14.290963", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 8730772e29..d2b60a4225 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -116,6 +116,20 @@ class BisectAccountingStatements(Document): root = frappe.db.get_all("Nodes", filters={"root": ["is", "not set"]})[0] frappe.db.set_single_value("Bisect Accounting Statements", "current_node", root.name) + def get_report_summary(self): + filters = { + "company": self.company, + "filter_based_on": "Date Range", + "period_start_date": self.current_from_date, + "period_end_date": self.current_to_date, + "periodicity": "Yearly", + } + pl_summary = frappe.get_doc("Report", "Profit and Loss Statement") + self.p_l_summary = pl_summary.execute_script_report(filters=filters)[5] + bs_summary = frappe.get_doc("Report", "Balance Sheet") + self.b_s_summary = bs_summary.execute_script_report(filters=filters)[5] + self.difference = abs(self.p_l_summary - self.b_s_summary) + @frappe.whitelist() def bisect_left(self): if self.current_node is not None: @@ -123,8 +137,9 @@ class BisectAccountingStatements(Document): if cur_node.left_child is not None: lft_node = frappe.get_doc("Nodes", cur_node.left_child) self.current_node = cur_node.left_child - self.from_date = lft_node.period_from_date - self.to_date = lft_node.period_to_date + self.current_from_date = lft_node.period_from_date + self.current_to_date = lft_node.period_to_date + self.get_report_summary() self.save() else: frappe.msgprint("No more children on Left") @@ -136,8 +151,9 @@ class BisectAccountingStatements(Document): if cur_node.right_child is not None: rgt_node = frappe.get_doc("Nodes", cur_node.right_child) self.current_node = cur_node.right_child - self.from_date = rgt_node.period_from_date - self.to_date = rgt_node.period_to_date + self.current_from_date = rgt_node.period_from_date + self.current_to_date = rgt_node.period_to_date + self.get_report_summary() self.save() else: frappe.msgprint("No more children on Right") @@ -149,8 +165,9 @@ class BisectAccountingStatements(Document): if cur_node.root is not None: root = frappe.get_doc("Nodes", cur_node.root) self.current_node = cur_node.root - self.from_date = root.period_from_date - self.to_date = root.period_to_date + self.current_from_date = root.period_from_date + self.current_to_date = root.period_to_date + self.get_report_summary() self.save() else: frappe.msgprint("Reached Root") From bd3dc6482e9621132a64fecc7e2f203b64812068 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Sep 2023 21:29:54 +0530 Subject: [PATCH 17/31] chore: hide some internal fields --- .../bisect_accounting_statements.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index c76ef4d06f..d413f70c15 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -61,12 +61,14 @@ { "fieldname": "current_node", "fieldtype": "Link", + "hidden": 1, "label": "Current Node", "options": "Nodes" }, { "fieldname": "sandbox", "fieldtype": "HTML", + "hidden": 1, "label": "sandbox" }, { @@ -129,7 +131,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-26 21:07:14.290963", + "modified": "2023-09-26 21:25:48.779453", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 16db6c2f47ec7b803c765d9e04c5f50c4bd6b95f Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 09:35:25 +0530 Subject: [PATCH 18/31] refactor: working heatmap --- .../bisect_accounting_statements.js | 58 +++++++++++++++---- .../bisect_accounting_statements.json | 30 +++++----- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 7abe4f87ae..1c1e3cc6ca 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -2,27 +2,58 @@ // For license information, please see license.txt frappe.ui.form.on("Bisect Accounting Statements", { + onload(frm) { + frm.trigger("render_heatmap"); + }, refresh(frm) { - frm.add_custom_button(__('Bisect Left'), () => - frm.trigger("bisect_left") - ); + frm.add_custom_button(__('Bisect Left'), () => { + frm.trigger("bisect_left"); + }); - frm.add_custom_button(__('Bisect Right'), () => - frm.trigger("bisect_right") - ); + frm.add_custom_button(__('Bisect Right'), () => { + frm.trigger("bisect_right"); + }); - frm.add_custom_button(__('Up'), () => - frm.trigger("move_up") - ); - frm.add_custom_button(__('Build Tree'), () => - frm.trigger("build_tree") - ); + frm.add_custom_button(__('Up'), () => { + frm.trigger("move_up"); + }); + frm.add_custom_button(__('Build Tree'), () => { + frm.trigger("build_tree"); + }); + }, + render_heatmap(frm) { + let bisect_heatmap = frm.get_field("bisect_heatmap").$wrapper; + bisect_heatmap.addClass("bisect_heatmap_location"); + + // milliseconds in a day + let msiad=24*60*60*1000; + let datapoints = {}; + let fr_dt = new Date(frm.doc.current_from_date).getTime(); + let to_dt = new Date(frm.doc.current_to_date).getTime(); + for(let x=fr_dt; x <= to_dt; x+=msiad){ + let epoch_in_seconds = x/1000; + datapoints[epoch_in_seconds] = 1; + } + console.log(datapoints); + + new frappe.Chart(".bisect_heatmap_location", { + type: "heatmap", + title: "Bisecting On", + data: { + dataPoints: datapoints, + start: new Date(frm.doc.from_date), + end: new Date(frm.doc.to_date), + }, + countLabel: 'Difference', + discreteDomains: 1 + }); }, bisect_left(frm) { frm.call({ doc: frm.doc, method: 'bisect_left', callback: (r) => { + frm.trigger("render_heatmap"); console.log(r); } }); @@ -32,6 +63,7 @@ frappe.ui.form.on("Bisect Accounting Statements", { doc: frm.doc, method: 'bisect_right', callback: (r) => { + frm.trigger("render_heatmap"); console.log(r); } }); @@ -41,6 +73,7 @@ frappe.ui.form.on("Bisect Accounting Statements", { doc: frm.doc, method: 'move_up', callback: (r) => { + frm.trigger("render_heatmap"); console.log(r); } }); @@ -50,6 +83,7 @@ frappe.ui.form.on("Bisect Accounting Statements", { doc: frm.doc, method: 'build_tree', callback: (r) => { + frm.trigger("render_heatmap"); console.log(r); } }); diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index d413f70c15..9a7242fe92 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -14,13 +14,14 @@ "to_date", "column_break_iwny", "algorithm", - "section_break_zbty", + "section_break_8ph9", "current_node", - "sandbox", "section_break_hmsy", "current_from_date", "column_break_uqyd", "current_to_date", + "section_break_ngid", + "bisect_heatmap", "section_break_hbyo", "p_l_summary", "column_break_aivo", @@ -54,10 +55,6 @@ "fieldname": "column_break_iwny", "fieldtype": "Column Break" }, - { - "fieldname": "section_break_zbty", - "fieldtype": "Section Break" - }, { "fieldname": "current_node", "fieldtype": "Link", @@ -65,12 +62,6 @@ "label": "Current Node", "options": "Nodes" }, - { - "fieldname": "sandbox", - "fieldtype": "HTML", - "hidden": 1, - "label": "sandbox" - }, { "fieldname": "section_break_hmsy", "fieldtype": "Section Break" @@ -125,13 +116,26 @@ { "fieldname": "column_break_hcam", "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_ngid", + "fieldtype": "Section Break" + }, + { + "fieldname": "section_break_8ph9", + "fieldtype": "Section Break" + }, + { + "fieldname": "bisect_heatmap", + "fieldtype": "HTML", + "label": "Heatmap" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-26 21:25:48.779453", + "modified": "2023-09-27 12:10:40.044935", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From f6831fba1370e569299c63f592fcd2a09a1dbc76 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 14:40:57 +0530 Subject: [PATCH 19/31] chore: hide internal fields and better painting logic for heatmap --- .../bisect_accounting_statements.js | 15 ++++++++---- .../bisect_accounting_statements.json | 24 ++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 1c1e3cc6ca..c00e49d380 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -28,11 +28,18 @@ frappe.ui.form.on("Bisect Accounting Statements", { // milliseconds in a day let msiad=24*60*60*1000; let datapoints = {}; - let fr_dt = new Date(frm.doc.current_from_date).getTime(); - let to_dt = new Date(frm.doc.current_to_date).getTime(); + let fr_dt = new Date(frm.doc.from_date).getTime(); + let to_dt = new Date(frm.doc.to_date).getTime(); + let bisect_start = new Date(frm.doc.current_from_date).getTime(); + let bisect_end = new Date(frm.doc.current_to_date).getTime(); + for(let x=fr_dt; x <= to_dt; x+=msiad){ let epoch_in_seconds = x/1000; - datapoints[epoch_in_seconds] = 1; + if ((bisect_start <= x) && (x <= bisect_end )) { + datapoints[epoch_in_seconds] = 1.0; + } else { + datapoints[epoch_in_seconds] = 0.0; + } } console.log(datapoints); @@ -45,7 +52,7 @@ frappe.ui.form.on("Bisect Accounting Statements", { end: new Date(frm.doc.to_date), }, countLabel: 'Difference', - discreteDomains: 1 + discreteDomains: 1, }); }, bisect_left(frm) { diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index 9a7242fe92..84d021d7da 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -58,23 +58,25 @@ { "fieldname": "current_node", "fieldtype": "Link", - "hidden": 1, "label": "Current Node", "options": "Nodes" }, { "fieldname": "section_break_hmsy", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hidden": 1 }, { "fieldname": "current_from_date", "fieldtype": "Datetime", - "label": "Current From Date" + "label": "Current From Date", + "read_only": 1 }, { "fieldname": "current_to_date", "fieldtype": "Datetime", - "label": "Current To Date" + "label": "Current To Date", + "read_only": 1 }, { "fieldname": "column_break_uqyd", @@ -87,17 +89,20 @@ { "fieldname": "p_l_summary", "fieldtype": "Data", - "label": "P&L Summary" + "label": "P&L Summary", + "read_only": 1 }, { "fieldname": "b_s_summary", "fieldtype": "Data", - "label": "Balance Sheet Summary" + "label": "Balance Sheet Summary", + "read_only": 1 }, { "fieldname": "difference", "fieldtype": "Data", - "label": "Difference" + "label": "Difference", + "read_only": 1 }, { "fieldname": "column_break_aivo", @@ -123,7 +128,8 @@ }, { "fieldname": "section_break_8ph9", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hidden": 1 }, { "fieldname": "bisect_heatmap", @@ -135,7 +141,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 12:10:40.044935", + "modified": "2023-09-27 14:32:09.962067", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 6492019383a56669869457d3b6b8cdb2083f7df7 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 14:44:48 +0530 Subject: [PATCH 20/31] chore: rename btree and remove debugging statements --- .../bisect_accounting_statements.js | 5 ---- .../bisect_accounting_statements.json | 7 ++--- .../bisect_accounting_statements.py | 28 +++++++++---------- .../{nodes => bisect_nodes}/__init__.py | 0 .../nodes.js => bisect_nodes/bisect_nodes.js} | 2 +- .../bisect_nodes.json} | 12 ++++---- .../nodes.py => bisect_nodes/bisect_nodes.py} | 2 +- .../test_bisect_nodes.py} | 2 +- 8 files changed, 26 insertions(+), 32 deletions(-) rename erpnext/accounts/doctype/{nodes => bisect_nodes}/__init__.py (100%) rename erpnext/accounts/doctype/{nodes/nodes.js => bisect_nodes/bisect_nodes.js} (80%) rename erpnext/accounts/doctype/{nodes/nodes.json => bisect_nodes/bisect_nodes.json} (88%) rename erpnext/accounts/doctype/{nodes/nodes.py => bisect_nodes/bisect_nodes.py} (86%) rename erpnext/accounts/doctype/{nodes/test_nodes.py => bisect_nodes/test_bisect_nodes.py} (80%) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index c00e49d380..e9fc330a70 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -41,7 +41,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { datapoints[epoch_in_seconds] = 0.0; } } - console.log(datapoints); new frappe.Chart(".bisect_heatmap_location", { type: "heatmap", @@ -61,7 +60,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { method: 'bisect_left', callback: (r) => { frm.trigger("render_heatmap"); - console.log(r); } }); }, @@ -71,7 +69,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { method: 'bisect_right', callback: (r) => { frm.trigger("render_heatmap"); - console.log(r); } }); }, @@ -81,7 +78,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { method: 'move_up', callback: (r) => { frm.trigger("render_heatmap"); - console.log(r); } }); }, @@ -91,7 +87,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { method: 'build_tree', callback: (r) => { frm.trigger("render_heatmap"); - console.log(r); } }); }, diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index 84d021d7da..f62d39377e 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -59,7 +59,7 @@ "fieldname": "current_node", "fieldtype": "Link", "label": "Current Node", - "options": "Nodes" + "options": "Bisect Nodes" }, { "fieldname": "section_break_hmsy", @@ -128,8 +128,7 @@ }, { "fieldname": "section_break_8ph9", - "fieldtype": "Section Break", - "hidden": 1 + "fieldtype": "Section Break" }, { "fieldname": "bisect_heatmap", @@ -141,7 +140,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 14:32:09.962067", + "modified": "2023-09-27 15:05:44.285832", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index d2b60a4225..58b8748628 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -27,7 +27,7 @@ class BisectAccountingStatements(Document): def bfs(self, from_date: datetime, to_date: datetime): # Make Root node - node = frappe.new_doc("Nodes") + node = frappe.new_doc("Bisect Nodes") node.root = None node.period_from_date = from_date node.period_to_date = to_date @@ -42,7 +42,7 @@ class BisectAccountingStatements(Document): else: cur_floor = floor(delta.days / 2) next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor) - left_node = frappe.new_doc("Nodes") + left_node = frappe.new_doc("Bisect Nodes") left_node.period_from_date = cur_node.period_from_date left_node.period_to_date = next_to_date left_node.root = cur_node.name @@ -51,7 +51,7 @@ class BisectAccountingStatements(Document): period_queue.append(left_node) next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1)) - right_node = frappe.new_doc("Nodes") + right_node = frappe.new_doc("Bisect Nodes") right_node.period_from_date = next_from_date right_node.period_to_date = cur_node.period_to_date right_node.root = cur_node.name @@ -63,7 +63,7 @@ class BisectAccountingStatements(Document): def dfs(self, from_date: datetime, to_date: datetime): # Make Root node - node = frappe.new_doc("Nodes") + node = frappe.new_doc("Bisect Nodes") node.root = None node.period_from_date = from_date node.period_to_date = to_date @@ -78,7 +78,7 @@ class BisectAccountingStatements(Document): else: cur_floor = floor(delta.days / 2) next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor) - left_node = frappe.new_doc("Nodes") + left_node = frappe.new_doc("Bisect Nodes") left_node.period_from_date = cur_node.period_from_date left_node.period_to_date = next_to_date left_node.root = cur_node.name @@ -87,7 +87,7 @@ class BisectAccountingStatements(Document): period_stack.append(left_node) next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1)) - right_node = frappe.new_doc("Nodes") + right_node = frappe.new_doc("Bisect Nodes") right_node.period_from_date = next_from_date right_node.period_to_date = cur_node.period_to_date right_node.root = cur_node.name @@ -99,7 +99,7 @@ class BisectAccountingStatements(Document): @frappe.whitelist() def build_tree(self): - frappe.db.delete("Nodes") + frappe.db.delete("Bisect Nodes") # Convert str to datetime format dt_format = guess_date_format(self.from_date) @@ -113,7 +113,7 @@ class BisectAccountingStatements(Document): self.dfs(from_date, to_date) # set root as current node - root = frappe.db.get_all("Nodes", filters={"root": ["is", "not set"]})[0] + root = frappe.db.get_all("Bisect Nodes", filters={"root": ["is", "not set"]})[0] frappe.db.set_single_value("Bisect Accounting Statements", "current_node", root.name) def get_report_summary(self): @@ -133,9 +133,9 @@ class BisectAccountingStatements(Document): @frappe.whitelist() def bisect_left(self): if self.current_node is not None: - cur_node = frappe.get_doc("Nodes", self.current_node) + cur_node = frappe.get_doc("Bisect Nodes", self.current_node) if cur_node.left_child is not None: - lft_node = frappe.get_doc("Nodes", cur_node.left_child) + lft_node = frappe.get_doc("Bisect Nodes", cur_node.left_child) self.current_node = cur_node.left_child self.current_from_date = lft_node.period_from_date self.current_to_date = lft_node.period_to_date @@ -147,9 +147,9 @@ class BisectAccountingStatements(Document): @frappe.whitelist() def bisect_right(self): if self.current_node is not None: - cur_node = frappe.get_doc("Nodes", self.current_node) + cur_node = frappe.get_doc("Bisect Nodes", self.current_node) if cur_node.right_child is not None: - rgt_node = frappe.get_doc("Nodes", cur_node.right_child) + rgt_node = frappe.get_doc("Bisect Nodes", cur_node.right_child) self.current_node = cur_node.right_child self.current_from_date = rgt_node.period_from_date self.current_to_date = rgt_node.period_to_date @@ -161,9 +161,9 @@ class BisectAccountingStatements(Document): @frappe.whitelist() def move_up(self): if self.current_node is not None: - cur_node = frappe.get_doc("Nodes", self.current_node) + cur_node = frappe.get_doc("Bisect Nodes", self.current_node) if cur_node.root is not None: - root = frappe.get_doc("Nodes", cur_node.root) + root = frappe.get_doc("Bisect Nodes", cur_node.root) self.current_node = cur_node.root self.current_from_date = root.period_from_date self.current_to_date = root.period_to_date diff --git a/erpnext/accounts/doctype/nodes/__init__.py b/erpnext/accounts/doctype/bisect_nodes/__init__.py similarity index 100% rename from erpnext/accounts/doctype/nodes/__init__.py rename to erpnext/accounts/doctype/bisect_nodes/__init__.py diff --git a/erpnext/accounts/doctype/nodes/nodes.js b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.js similarity index 80% rename from erpnext/accounts/doctype/nodes/nodes.js rename to erpnext/accounts/doctype/bisect_nodes/bisect_nodes.js index bd74d68637..6dea25fc92 100644 --- a/erpnext/accounts/doctype/nodes/nodes.js +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.js @@ -1,7 +1,7 @@ // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -// frappe.ui.form.on("Nodes", { +// frappe.ui.form.on("Bisect Nodes", { // refresh(frm) { // }, diff --git a/erpnext/accounts/doctype/nodes/nodes.json b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json similarity index 88% rename from erpnext/accounts/doctype/nodes/nodes.json rename to erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json index 1238c8136a..db41704795 100644 --- a/erpnext/accounts/doctype/nodes/nodes.json +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json @@ -1,7 +1,7 @@ { "actions": [], "autoname": "autoincrement", - "creation": "2023-09-25 22:01:33.961832", + "creation": "2023-09-27 14:56:38.112462", "default_view": "List", "doctype": "DocType", "editable_grid": 1, @@ -21,19 +21,19 @@ "fieldname": "root", "fieldtype": "Link", "label": "Root", - "options": "Nodes" + "options": "Bisect Nodes" }, { "fieldname": "left_child", "fieldtype": "Link", "label": "Left Child", - "options": "Nodes" + "options": "Bisect Nodes" }, { "fieldname": "right_child", "fieldtype": "Link", "label": "Right Child", - "options": "Nodes" + "options": "Bisect Nodes" }, { "fieldname": "period_from_date", @@ -63,10 +63,10 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-09-25 22:05:49.577861", + "modified": "2023-09-27 15:09:27.715523", "modified_by": "Administrator", "module": "Accounts", - "name": "Nodes", + "name": "Bisect Nodes", "naming_rule": "Autoincrement", "owner": "Administrator", "permissions": [ diff --git a/erpnext/accounts/doctype/nodes/nodes.py b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py similarity index 86% rename from erpnext/accounts/doctype/nodes/nodes.py rename to erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py index 67d5d69bfe..0d176f974a 100644 --- a/erpnext/accounts/doctype/nodes/nodes.py +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py @@ -5,5 +5,5 @@ from frappe.model.document import Document -class Nodes(Document): +class BisectNodes(Document): pass diff --git a/erpnext/accounts/doctype/nodes/test_nodes.py b/erpnext/accounts/doctype/bisect_nodes/test_bisect_nodes.py similarity index 80% rename from erpnext/accounts/doctype/nodes/test_nodes.py rename to erpnext/accounts/doctype/bisect_nodes/test_bisect_nodes.py index feeef765e0..5399df139f 100644 --- a/erpnext/accounts/doctype/nodes/test_nodes.py +++ b/erpnext/accounts/doctype/bisect_nodes/test_bisect_nodes.py @@ -5,5 +5,5 @@ from frappe.tests.utils import FrappeTestCase -class TestNodes(FrappeTestCase): +class TestBisectNodes(FrappeTestCase): pass From c4c3090f46af16f52b34dab116b49856b9da2025 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 15:10:42 +0530 Subject: [PATCH 21/31] chore: hide internal variables section --- .../bisect_accounting_statements.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index f62d39377e..4ad03528c5 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -128,7 +128,8 @@ }, { "fieldname": "section_break_8ph9", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hidden": 1 }, { "fieldname": "bisect_heatmap", @@ -140,7 +141,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 15:05:44.285832", + "modified": "2023-09-27 15:10:36.394474", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 5e2d21c033fdf6147ec58286d08cac75d6fedf23 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 15:27:27 +0530 Subject: [PATCH 22/31] chore: code cleanup --- .../bisect_accounting_statements.js | 2 +- .../bisect_accounting_statements.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index e9fc330a70..486630e162 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -50,7 +50,7 @@ frappe.ui.form.on("Bisect Accounting Statements", { start: new Date(frm.doc.from_date), end: new Date(frm.doc.to_date), }, - countLabel: 'Difference', + countLabel: 'Bisecting', discreteDomains: 1, }); }, diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 58b8748628..0a1de6414f 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -114,7 +114,11 @@ class BisectAccountingStatements(Document): # set root as current node root = frappe.db.get_all("Bisect Nodes", filters={"root": ["is", "not set"]})[0] - frappe.db.set_single_value("Bisect Accounting Statements", "current_node", root.name) + self.get_report_summary() + self.current_node = root.name + self.current_from_date = self.from_date + self.current_to_date = self.to_date + self.save() def get_report_summary(self): filters = { From 395299803f3d5818fa0e17bac95f515fe06b2a09 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 15:41:53 +0530 Subject: [PATCH 23/31] chore: add screen freeze on wait --- .../bisect_accounting_statements.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 486630e162..519246b9bb 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -58,6 +58,8 @@ frappe.ui.form.on("Bisect Accounting Statements", { frm.call({ doc: frm.doc, method: 'bisect_left', + freeze: true, + freeze_message: __("Bisecting Left ..."), callback: (r) => { frm.trigger("render_heatmap"); } @@ -66,6 +68,8 @@ frappe.ui.form.on("Bisect Accounting Statements", { bisect_right(frm) { frm.call({ doc: frm.doc, + freeze: true, + freeze_message: __("Bisecting Right ..."), method: 'bisect_right', callback: (r) => { frm.trigger("render_heatmap"); @@ -75,6 +79,8 @@ frappe.ui.form.on("Bisect Accounting Statements", { move_up(frm) { frm.call({ doc: frm.doc, + freeze: true, + freeze_message: __("Moving up in tree ..."), method: 'move_up', callback: (r) => { frm.trigger("render_heatmap"); @@ -84,6 +90,8 @@ frappe.ui.form.on("Bisect Accounting Statements", { build_tree(frm) { frm.call({ doc: frm.doc, + freeze: true, + freeze_message: __("Rebuilding BTree for period ..."), method: 'build_tree', callback: (r) => { frm.trigger("render_heatmap"); From ea3071db6643f7802611e7a0ae8857d75583dd96 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 15:53:19 +0530 Subject: [PATCH 24/31] chore: UI cleanup --- .../bisect_accounting_statements.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index 4ad03528c5..a9fa7f0695 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -16,12 +16,12 @@ "algorithm", "section_break_8ph9", "current_node", + "section_break_ngid", + "bisect_heatmap", "section_break_hmsy", "current_from_date", "column_break_uqyd", "current_to_date", - "section_break_ngid", - "bisect_heatmap", "section_break_hbyo", "p_l_summary", "column_break_aivo", @@ -63,19 +63,18 @@ }, { "fieldname": "section_break_hmsy", - "fieldtype": "Section Break", - "hidden": 1 + "fieldtype": "Section Break" }, { "fieldname": "current_from_date", "fieldtype": "Datetime", - "label": "Current From Date", + "label": "Bisecting From", "read_only": 1 }, { "fieldname": "current_to_date", "fieldtype": "Datetime", - "label": "Current To Date", + "label": "Bisecting To", "read_only": 1 }, { @@ -141,7 +140,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 15:10:36.394474", + "modified": "2023-09-27 15:52:14.083727", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 993e2bfbf9f75958d5283fcbbcaa5e6f80e88f86 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 16:05:14 +0530 Subject: [PATCH 25/31] refactor: adding labels to important section --- .../bisect_accounting_statements.js | 1 - .../bisect_accounting_statements.json | 37 ++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js index 519246b9bb..ece0fb33e5 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js @@ -44,7 +44,6 @@ frappe.ui.form.on("Bisect Accounting Statements", { new frappe.Chart(".bisect_heatmap_location", { type: "heatmap", - title: "Bisecting On", data: { dataPoints: datapoints, start: new Date(frm.doc.from_date), diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index a9fa7f0695..b66c17b648 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -19,14 +19,19 @@ "section_break_ngid", "bisect_heatmap", "section_break_hmsy", + "bisecting_from", "current_from_date", "column_break_uqyd", + "bisecting_to", "current_to_date", "section_break_hbyo", + "heading_cppb", "p_l_summary", "column_break_aivo", + "balance_sheet_summary", "b_s_summary", "column_break_gvwx", + "difference_heading", "difference" ], "fields": [ @@ -68,13 +73,11 @@ { "fieldname": "current_from_date", "fieldtype": "Datetime", - "label": "Bisecting From", "read_only": 1 }, { "fieldname": "current_to_date", "fieldtype": "Datetime", - "label": "Bisecting To", "read_only": 1 }, { @@ -88,19 +91,16 @@ { "fieldname": "p_l_summary", "fieldtype": "Data", - "label": "P&L Summary", "read_only": 1 }, { "fieldname": "b_s_summary", "fieldtype": "Data", - "label": "Balance Sheet Summary", "read_only": 1 }, { "fieldname": "difference", "fieldtype": "Data", - "label": "Difference", "read_only": 1 }, { @@ -134,13 +134,38 @@ "fieldname": "bisect_heatmap", "fieldtype": "HTML", "label": "Heatmap" + }, + { + "fieldname": "heading_cppb", + "fieldtype": "Heading", + "label": "Profit and Loss Summary" + }, + { + "fieldname": "balance_sheet_summary", + "fieldtype": "Heading", + "label": "Balance Sheet Summary" + }, + { + "fieldname": "difference_heading", + "fieldtype": "Heading", + "label": "Difference" + }, + { + "fieldname": "bisecting_from", + "fieldtype": "Heading", + "label": "Bisecting From" + }, + { + "fieldname": "bisecting_to", + "fieldtype": "Heading", + "label": "Bisecting To" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 15:52:14.083727", + "modified": "2023-09-27 16:08:18.155873", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 228aa1a244632505bb466f1252c14ce5950b1ef7 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Sep 2023 16:22:20 +0530 Subject: [PATCH 26/31] chore: change data type for summary fields --- .../bisect_accounting_statements.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index b66c17b648..d70ae1f90e 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -7,6 +7,7 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "section_break_cvfg", "company", "column_break_hcam", "from_date", @@ -90,17 +91,17 @@ }, { "fieldname": "p_l_summary", - "fieldtype": "Data", + "fieldtype": "Float", "read_only": 1 }, { "fieldname": "b_s_summary", - "fieldtype": "Data", + "fieldtype": "Float", "read_only": 1 }, { "fieldname": "difference", - "fieldtype": "Data", + "fieldtype": "Float", "read_only": 1 }, { @@ -159,13 +160,17 @@ "fieldname": "bisecting_to", "fieldtype": "Heading", "label": "Bisecting To" + }, + { + "fieldname": "section_break_cvfg", + "fieldtype": "Section Break" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 16:08:18.155873", + "modified": "2023-09-27 16:22:10.670836", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", From 90c6d4dc85701902ad9d12b31716db098831dc10 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Dec 2023 16:50:17 +0530 Subject: [PATCH 27/31] chore: restrict only to administrator and type info --- .../bisect_accounting_statements.json | 5 +++-- .../bisect_accounting_statements.py | 20 +++++++++++++++++++ .../doctype/bisect_nodes/bisect_nodes.json | 5 +++-- .../doctype/bisect_nodes/bisect_nodes.py | 19 ++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json index d70ae1f90e..e129fa60c2 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json @@ -170,7 +170,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-09-27 16:22:10.670836", + "modified": "2023-12-01 16:49:54.073890", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Accounting Statements", @@ -182,11 +182,12 @@ "email": 1, "print": 1, "read": 1, - "role": "System Manager", + "role": "Administrator", "share": 1, "write": 1 } ], + "read_only": 1, "sort_field": "modified", "sort_order": "DESC", "states": [] diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 0a1de6414f..e2a67d14b7 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -14,6 +14,26 @@ from frappe.utils.data import guess_date_format class BisectAccountingStatements(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + algorithm: DF.Literal["BFS", "DFS"] + b_s_summary: DF.Float + company: DF.Link | None + current_from_date: DF.Datetime | None + current_node: DF.Link | None + current_to_date: DF.Datetime | None + difference: DF.Float + from_date: DF.Datetime | None + p_l_summary: DF.Float + to_date: DF.Datetime | None + # end: auto-generated types + def validate(self): self.validate_dates() diff --git a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json index db41704795..f352d7a31a 100644 --- a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json @@ -63,7 +63,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-09-27 15:09:27.715523", + "modified": "2023-12-01 16:49:57.146867", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Nodes", @@ -78,11 +78,12 @@ "print": 1, "read": 1, "report": 1, - "role": "System Manager", + "role": "Administrator", "share": 1, "write": 1 } ], + "read_only": 1, "sort_field": "modified", "sort_order": "DESC", "states": [] diff --git a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py index 0d176f974a..e49eabbff5 100644 --- a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py @@ -6,4 +6,23 @@ from frappe.model.document import Document class BisectNodes(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + balance_sheet_summary: DF.Float + difference: DF.Float + left_child: DF.Link | None + name: DF.Int | None + period_from_date: DF.Datetime | None + period_to_date: DF.Datetime | None + profit_loss_summary: DF.Float + right_child: DF.Link | None + root: DF.Link | None + # end: auto-generated types + pass From ca14ae8f1bc69539ca3a2f49f92e2b6c667a40b3 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Dec 2023 17:07:39 +0530 Subject: [PATCH 28/31] refactor: save results in node --- .../bisect_accounting_statements.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index e2a67d14b7..216f553084 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -154,6 +154,13 @@ class BisectAccountingStatements(Document): self.b_s_summary = bs_summary.execute_script_report(filters=filters)[5] self.difference = abs(self.p_l_summary - self.b_s_summary) + def update_node(self): + current_node = frappe.get_doc("Bisect Nodes", self.current_node) + current_node.balance_sheet_summary = self.b_s_summary + current_node.profit_loss_summary = self.p_l_summary + current_node.difference = self.difference + current_node.save() + @frappe.whitelist() def bisect_left(self): if self.current_node is not None: @@ -164,6 +171,7 @@ class BisectAccountingStatements(Document): self.current_from_date = lft_node.period_from_date self.current_to_date = lft_node.period_to_date self.get_report_summary() + self.update_node() self.save() else: frappe.msgprint("No more children on Left") @@ -178,6 +186,7 @@ class BisectAccountingStatements(Document): self.current_from_date = rgt_node.period_from_date self.current_to_date = rgt_node.period_to_date self.get_report_summary() + self.update_node() self.save() else: frappe.msgprint("No more children on Right") @@ -192,6 +201,7 @@ class BisectAccountingStatements(Document): self.current_from_date = root.period_from_date self.current_to_date = root.period_to_date self.get_report_summary() + self.update_node() self.save() else: frappe.msgprint("Reached Root") From 0925706d5efac2cbdfe5240e0310c1a9738a3560 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Dec 2023 17:46:28 +0530 Subject: [PATCH 29/31] refactor: flag to differentiate generated and default values --- .../accounts/doctype/bisect_nodes/bisect_nodes.json | 11 +++++++++-- erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json index f352d7a31a..03fad261c3 100644 --- a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.json @@ -14,7 +14,8 @@ "period_to_date", "difference", "balance_sheet_summary", - "profit_loss_summary" + "profit_loss_summary", + "generated" ], "fields": [ { @@ -59,11 +60,17 @@ "fieldname": "profit_loss_summary", "fieldtype": "Float", "label": "Profit and Loss Summary" + }, + { + "default": "0", + "fieldname": "generated", + "fieldtype": "Check", + "label": "Generated" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-12-01 16:49:57.146867", + "modified": "2023-12-01 17:46:12.437996", "modified_by": "Administrator", "module": "Accounts", "name": "Bisect Nodes", diff --git a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py index e49eabbff5..f50776641d 100644 --- a/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py +++ b/erpnext/accounts/doctype/bisect_nodes/bisect_nodes.py @@ -16,6 +16,7 @@ class BisectNodes(Document): balance_sheet_summary: DF.Float difference: DF.Float + generated: DF.Check left_child: DF.Link | None name: DF.Int | None period_from_date: DF.Datetime | None From 14c8c8c33d8f8df636ed5b3de589cc872f6aaf7b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 1 Dec 2023 17:52:36 +0530 Subject: [PATCH 30/31] refactor: cache results --- .../bisect_accounting_statements.py | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 216f553084..1d6fd621aa 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -66,6 +66,7 @@ class BisectAccountingStatements(Document): left_node.period_from_date = cur_node.period_from_date left_node.period_to_date = next_to_date left_node.root = cur_node.name + left_node.generated = False left_node.insert() cur_node.left_child = left_node.name period_queue.append(left_node) @@ -75,6 +76,7 @@ class BisectAccountingStatements(Document): right_node.period_from_date = next_from_date right_node.period_to_date = cur_node.period_to_date right_node.root = cur_node.name + right_node.generated = False right_node.insert() cur_node.right_child = right_node.name period_queue.append(right_node) @@ -102,6 +104,7 @@ class BisectAccountingStatements(Document): left_node.period_from_date = cur_node.period_from_date left_node.period_to_date = next_to_date left_node.root = cur_node.name + left_node.generated = False left_node.insert() cur_node.left_child = left_node.name period_stack.append(left_node) @@ -111,6 +114,7 @@ class BisectAccountingStatements(Document): right_node.period_from_date = next_from_date right_node.period_to_date = cur_node.period_to_date right_node.root = cur_node.name + right_node.generated = False right_node.insert() cur_node.right_child = right_node.name period_stack.append(right_node) @@ -159,8 +163,26 @@ class BisectAccountingStatements(Document): current_node.balance_sheet_summary = self.b_s_summary current_node.profit_loss_summary = self.p_l_summary current_node.difference = self.difference + current_node.generated = True current_node.save() + def current_node_has_summary_info(self): + "Assertion method" + return frappe.db.get_value("Bisect Nodes", self.current_node, "generated") + + def fetch_summary_info_from_current_node(self): + current_node = frappe.get_doc("Bisect Nodes", self.current_node) + self.p_l_summary = current_node.balance_sheet_summary + self.b_s_summary = current_node.profit_loss_summary + self.difference = abs(self.p_l_summary - self.b_s_summary) + + def fetch_or_calculate(self): + if self.current_node_has_summary_info(): + self.fetch_summary_info_from_current_node() + else: + self.get_report_summary() + self.update_node() + @frappe.whitelist() def bisect_left(self): if self.current_node is not None: @@ -170,8 +192,7 @@ class BisectAccountingStatements(Document): self.current_node = cur_node.left_child self.current_from_date = lft_node.period_from_date self.current_to_date = lft_node.period_to_date - self.get_report_summary() - self.update_node() + self.fetch_or_calculate() self.save() else: frappe.msgprint("No more children on Left") @@ -185,8 +206,7 @@ class BisectAccountingStatements(Document): self.current_node = cur_node.right_child self.current_from_date = rgt_node.period_from_date self.current_to_date = rgt_node.period_to_date - self.get_report_summary() - self.update_node() + self.fetch_or_calculate() self.save() else: frappe.msgprint("No more children on Right") @@ -200,8 +220,7 @@ class BisectAccountingStatements(Document): self.current_node = cur_node.root self.current_from_date = root.period_from_date self.current_to_date = root.period_to_date - self.get_report_summary() - self.update_node() + self.fetch_or_calculate() self.save() else: frappe.msgprint("Reached Root") From 0890b414b14d67803abe2ee5be72ebdcf9f6bee4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Dec 2023 17:31:34 +0530 Subject: [PATCH 31/31] chore: resolve linter issues --- .../bisect_accounting_statements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py index 1d6fd621aa..da273b9f89 100644 --- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py +++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py @@ -195,7 +195,7 @@ class BisectAccountingStatements(Document): self.fetch_or_calculate() self.save() else: - frappe.msgprint("No more children on Left") + frappe.msgprint(_("No more children on Left")) @frappe.whitelist() def bisect_right(self): @@ -209,7 +209,7 @@ class BisectAccountingStatements(Document): self.fetch_or_calculate() self.save() else: - frappe.msgprint("No more children on Right") + frappe.msgprint(_("No more children on Right")) @frappe.whitelist() def move_up(self): @@ -223,4 +223,4 @@ class BisectAccountingStatements(Document): self.fetch_or_calculate() self.save() else: - frappe.msgprint("Reached Root") + frappe.msgprint(_("Reached Root"))