From 1c79fc4ebcdc1888faaf42d1abd4847becef5039 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 4 Jul 2023 14:14:26 +0530 Subject: [PATCH 01/24] feat: introduce doctypes for repost --- .../repost_accounting_ledger/__init__.py | 0 .../repost_accounting_ledger.js | 8 +++ .../repost_accounting_ledger.json | 69 +++++++++++++++++++ .../repost_accounting_ledger.py | 9 +++ .../test_repost_accounting_ledger.py | 9 +++ .../__init__.py | 0 .../repost_accounting_ledger_items.json | 40 +++++++++++ .../repost_accounting_ledger_items.py | 9 +++ 8 files changed, 144 insertions(+) create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/__init__.py create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger_items/__init__.py create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.py diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/__init__.py b/erpnext/accounts/doctype/repost_accounting_ledger/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js new file mode 100644 index 000000000000..fc71667c6916 --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.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("Repost Accounting Ledger", { +// refresh(frm) { + +// }, +// }); diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json new file mode 100644 index 000000000000..aa18dd0923f3 --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -0,0 +1,69 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-07-04 13:07:32.923675", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "delete_old_entries", + "vouchers", + "amended_from" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Repost Accounting Ledger", + "print_hide": 1, + "read_only": 1 + }, + { + "default": "0", + "fieldname": "delete_old_entries", + "fieldtype": "Check", + "label": "Delete Old Entries" + }, + { + "fieldname": "vouchers", + "fieldtype": "Table", + "label": "Vouchers", + "options": "Repost Accounting Ledger Items" + } + ], + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [], + "modified": "2023-07-04 14:15:15.781246", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Repost Accounting Ledger", + "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/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py new file mode 100644 index 000000000000..e5f3d47d0ecd --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.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 RepostAccountingLedger(Document): + pass diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py new file mode 100644 index 000000000000..7f1ed55a0c0a --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.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 TestRepostAccountingLedger(FrappeTestCase): + pass diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_items/__init__.py b/erpnext/accounts/doctype/repost_accounting_ledger_items/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json b/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json new file mode 100644 index 000000000000..4a2041f88c6b --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json @@ -0,0 +1,40 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-07-04 14:14:01.243848", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "voucher_type", + "voucher_no" + ], + "fields": [ + { + "fieldname": "voucher_type", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Voucher Type", + "options": "DocType" + }, + { + "fieldname": "voucher_no", + "fieldtype": "Dynamic Link", + "in_list_view": 1, + "label": "Voucher No", + "options": "voucher_type" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-07-04 14:15:51.165584", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Repost Accounting Ledger Items", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.py b/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.py new file mode 100644 index 000000000000..9221f447355c --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.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 RepostAccountingLedgerItems(Document): + pass From 4a200674dae65489e9a43ce00c3bbe9319231fef Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 4 Jul 2023 14:52:30 +0530 Subject: [PATCH 02/24] refactor: basic filters and validations --- .../repost_accounting_ledger.js | 29 ++++++++++++++++--- .../repost_accounting_ledger.py | 17 +++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js index fc71667c6916..6146300ddb84 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js @@ -1,8 +1,29 @@ // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -// frappe.ui.form.on("Repost Accounting Ledger", { -// refresh(frm) { +frappe.ui.form.on("Repost Accounting Ledger", { + setup: function(frm) { + frm.fields_dict['vouchers'].grid.get_field('voucher_type').get_query = function(doc) { + return { + filters: { + name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']] + } + } + } -// }, -// }); + frm.fields_dict['vouchers'].grid.get_field('voucher_no').get_query = function(doc) { + if (doc.company) { + return { + filters: { + company: doc.company, + docstatus: 1 + } + } + } + } + }, + + refresh: function(frm) { + + }, +}); diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index e5f3d47d0ecd..7aa6acd10dfd 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -1,9 +1,22 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -# import frappe +import frappe from frappe.model.document import Document class RepostAccountingLedger(Document): - pass + def validate(self): + pass + + def validate_period_closing_voucher(self): + pass + + def validate_vouchers(self): + voucher_types = set([x.voucher_type for x in self.vouchers]) + for x in voucher_types: + vouchers = set([x.voucher_no for x in self.vouchers if x.voucher_type == x]) + filtered = set( + [x[0] for x in frappe.db.get_all(x, filters={"name": ["in", vouchers]}, as_list=1)] + ) + # if vouchers.difference(filtered) From acb7c9131e7de1fb5a3c917ef37b3f91cf1a3504 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 27 Jul 2023 14:13:53 +0530 Subject: [PATCH 03/24] chore: basic validations --- .../repost_accounting_ledger.js | 2 +- .../repost_accounting_ledger.json | 12 +++- .../repost_accounting_ledger.py | 56 +++++++++++++++---- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js index 6146300ddb84..757b2dc06831 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js @@ -6,7 +6,7 @@ frappe.ui.form.on("Repost Accounting Ledger", { frm.fields_dict['vouchers'].grid.get_field('voucher_type').get_query = function(doc) { return { filters: { - name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']] + name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']], } } } diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json index aa18dd0923f3..f067fc1221c5 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -8,7 +8,9 @@ "engine": "InnoDB", "field_order": [ "company", + "column_break_vpup", "delete_old_entries", + "section_break_metl", "vouchers", "amended_from" ], @@ -39,12 +41,20 @@ "fieldtype": "Table", "label": "Vouchers", "options": "Repost Accounting Ledger Items" + }, + { + "fieldname": "column_break_vpup", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_metl", + "fieldtype": "Section Break" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-07-04 14:15:15.781246", + "modified": "2023-07-27 10:49:37.708857", "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger", diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 7aa6acd10dfd..2d4b63ec43cc 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -2,21 +2,57 @@ # For license information, please see license.txt import frappe +from frappe import _ from frappe.model.document import Document +from frappe.utils.data import comma_and class RepostAccountingLedger(Document): + def __init__(self, *args, **kwargs): + super(RepostAccountingLedger, self).__init__(*args, **kwargs) + self._allowed_types = set( + ["Purchase Invoice", "Sales Invoice", "Payment Entry", "Journal Entry"] + ) + def validate(self): - pass + self.validate_vouchers() + self.validate_for_closed_fiscal_year() + + def validate_for_closed_fiscal_year(self): + if self.vouchers: + latest_pcv = ( + frappe.db.get_all( + "Period Closing Voucher", + filters={"company": self.company}, + order_by="posting_date desc", + pluck="posting_date", + limit=1, + ) + or None + ) + if not latest_pcv: + return - def validate_period_closing_voucher(self): - pass + for vtype in self._allowed_types: + if names := [x.voucher_no for x in self.vouchers if x.voucher_type == vtype]: + latest_voucher = frappe.db.get_all( + vtype, + filters={"name": ["in", names]}, + pluck="posting_date", + order_by="posting_date desc", + limit=1, + )[0] + if latest_voucher and latest_pcv > latest_voucher: + frappe.throw(_("Cannot Resubmit Ledger entries for vouchers in Closed fiscal year.")) def validate_vouchers(self): - voucher_types = set([x.voucher_type for x in self.vouchers]) - for x in voucher_types: - vouchers = set([x.voucher_no for x in self.vouchers if x.voucher_type == x]) - filtered = set( - [x[0] for x in frappe.db.get_all(x, filters={"name": ["in", vouchers]}, as_list=1)] - ) - # if vouchers.difference(filtered) + if self.vouchers: + # Validate voucher types + voucher_types = set([x.voucher_type for x in self.vouchers]) + if disallowed_types := voucher_types.difference(self._allowed_types): + frappe.throw( + _("{0} types are not allowed. Only {1} are.").format( + frappe.bold(comma_and(list(disallowed_types))), + frappe.bold(comma_and(list(self._allowed_types))), + ) + ) From 462aa4b49758e4f9150e10586dd1716ab6b427b7 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 27 Jul 2023 15:53:55 +0530 Subject: [PATCH 04/24] chore: added barebones function to generate ledger entries --- .../repost_accounting_ledger.json | 18 +++++++++------- .../repost_accounting_ledger.py | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json index f067fc1221c5..8d56c9bb11dc 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -1,6 +1,7 @@ { "actions": [], "allow_rename": 1, + "autoname": "format:ACC-REPOST-{#####}", "creation": "2023-07-04 13:07:32.923675", "default_view": "List", "doctype": "DocType", @@ -9,7 +10,7 @@ "field_order": [ "company", "column_break_vpup", - "delete_old_entries", + "delete_cancelled_entries", "section_break_metl", "vouchers", "amended_from" @@ -30,12 +31,6 @@ "print_hide": 1, "read_only": 1 }, - { - "default": "0", - "fieldname": "delete_old_entries", - "fieldtype": "Check", - "label": "Delete Old Entries" - }, { "fieldname": "vouchers", "fieldtype": "Table", @@ -49,15 +44,22 @@ { "fieldname": "section_break_metl", "fieldtype": "Section Break" + }, + { + "default": "0", + "fieldname": "delete_cancelled_entries", + "fieldtype": "Check", + "label": "Delete Cancelled Ledger Entries" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-07-27 10:49:37.708857", + "modified": "2023-07-27 15:47:58.975034", "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger", + "naming_rule": "Expression", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 2d4b63ec43cc..cb8d02112305 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -56,3 +56,24 @@ def validate_vouchers(self): frappe.bold(comma_and(list(self._allowed_types))), ) ) + + def print_gle(self): + vouchers = [(x.voucher_type, x.voucher_no) for x in self.vouchers] + repost_accounting_ledger(vouchers) + frappe.throw("stopping...") + + def before_submit(self): + self.print_gle() + + +def repost_accounting_ledger(vouchers: list = None) -> None: + if vouchers: + for x in vouchers: + doc = frappe.get_doc(x[0], x[1]) + + if doc.doctype in ["Payment Entry", "Journal Entry"]: + gle_map = doc.build_gl_map() + else: + gle_map = doc.get_gl_entries() + + [print(x) for x in gle_map] From 1f7a8920284608af06dd98a07f2fd79f758c9fd5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 27 Jul 2023 20:08:48 +0530 Subject: [PATCH 05/24] chore: repost on submit --- .../repost_accounting_ledger.py | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index cb8d02112305..f637f4db6934 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -59,21 +59,39 @@ def validate_vouchers(self): def print_gle(self): vouchers = [(x.voucher_type, x.voucher_no) for x in self.vouchers] - repost_accounting_ledger(vouchers) + repost_accounting_ledger(self.name) frappe.throw("stopping...") - def before_submit(self): - self.print_gle() - - -def repost_accounting_ledger(vouchers: list = None) -> None: - if vouchers: - for x in vouchers: - doc = frappe.get_doc(x[0], x[1]) - + def show_preview(self): + for x in self.vouchers: + doc = frappe.get_doc(x.voucher_type, x.voucher_no) if doc.doctype in ["Payment Entry", "Journal Entry"]: gle_map = doc.build_gl_map() else: gle_map = doc.get_gl_entries() - [print(x) for x in gle_map] + def on_submit(self): + # self.print_gle() + repost_accounting_ledger(self.name) + + +@frappe.whitelist() +def repost_accounting_ledger(account_repost_doc=str) -> None: + if account_repost_doc: + repost_doc = frappe.get_doc("Repost Accounting Ledger", account_repost_doc) + + if repost_doc.docstatus == 1: + for x in repost_doc.vouchers: + doc = frappe.get_doc(x.voucher_type, x.voucher_no) + + if doc.doctype in ["Sales Invoice"]: + if repost_doc.delete_cancelled_entries: + frappe.db.delete("GL Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) + frappe.db.delete( + "Payment Ledger Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name} + ) + else: + doc.make_gl_entries_on_cancel() + + doc.make_gl_entries() + frappe.db.commit() From 87fae2fd806a913e6583dbec630614e70c407ba4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 28 Jul 2023 11:09:59 +0530 Subject: [PATCH 06/24] chore: repost in background --- .../repost_accounting_ledger.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index f637f4db6934..5fbd7cd23faf 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -57,11 +57,6 @@ def validate_vouchers(self): ) ) - def print_gle(self): - vouchers = [(x.voucher_type, x.voucher_no) for x in self.vouchers] - repost_accounting_ledger(self.name) - frappe.throw("stopping...") - def show_preview(self): for x in self.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) @@ -71,12 +66,19 @@ def show_preview(self): gle_map = doc.get_gl_entries() def on_submit(self): - # self.print_gle() - repost_accounting_ledger(self.name) + # repost_accounting_ledger(self.name) + job_name = "repost_accounting_ledger_" + self.name + frappe.enqueue( + method="erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger.start_repost", + account_repost_doc=self.name, + is_async=True, + job_name=job_name, + ) + frappe.msgprint(_("Repost has started in the background")) @frappe.whitelist() -def repost_accounting_ledger(account_repost_doc=str) -> None: +def start_repost(account_repost_doc=str) -> None: if account_repost_doc: repost_doc = frappe.get_doc("Repost Accounting Ledger", account_repost_doc) From 0712b56eb174393fe6ba58b9584a1ae13d9d76a8 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 28 Jul 2023 13:35:12 +0530 Subject: [PATCH 07/24] chore: include payment entry and journal entry --- .../repost_accounting_ledger.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 5fbd7cd23faf..2a63dfd3f563 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -66,7 +66,6 @@ def show_preview(self): gle_map = doc.get_gl_entries() def on_submit(self): - # repost_accounting_ledger(self.name) job_name = "repost_accounting_ledger_" + self.name frappe.enqueue( method="erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger.start_repost", @@ -86,14 +85,23 @@ def start_repost(account_repost_doc=str) -> None: for x in repost_doc.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) - if doc.doctype in ["Sales Invoice"]: - if repost_doc.delete_cancelled_entries: - frappe.db.delete("GL Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) - frappe.db.delete( - "Payment Ledger Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name} - ) - else: + if repost_doc.delete_cancelled_entries: + frappe.db.delete("GL Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) + frappe.db.delete( + "Payment Ledger Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name} + ) + + if doc.doctype in ["Sales Invoice", "Purchase Invoice"]: + if not repost_doc.delete_cancelled_entries: + doc.docstatus = 2 doc.make_gl_entries_on_cancel() + doc.docstatus = 1 doc.make_gl_entries() + + elif doc.doctype in ["Payment Entry", "Journal Entry"]: + if not repost_doc.delete_cancelled_entries: + doc.make_gl_entries(1) + doc.make_gl_entries() + frappe.db.commit() From 9b855e605d5ddcbb9d4e5a4df6fafe0dfac9ec95 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 28 Jul 2023 14:06:30 +0530 Subject: [PATCH 08/24] chore: ignore repost doc on cancel --- erpnext/accounts/doctype/journal_entry/journal_entry.js | 2 +- erpnext/accounts/doctype/journal_entry/journal_entry.py | 2 ++ erpnext/accounts/doctype/payment_entry/payment_entry.js | 2 +- erpnext/accounts/doctype/payment_entry/payment_entry.py | 2 ++ erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 +- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 2 ++ erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 ++ 8 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 8d8cbefa71b5..35a378856b00 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry"); frappe.ui.form.on("Journal Entry", { setup: function(frm) { frm.add_fetch("bank_account", "account", "account"); - frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule']; + frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger"]; }, refresh: function(frm) { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 1e1b3ba642ad..22e092c0d04b 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -96,6 +96,8 @@ def on_cancel(self): "Payment Ledger Entry", "Repost Payment Ledger", "Repost Payment Ledger Items", + "Repost Accounting Ledger", + "Repost Accounting Ledger Items", ) self.make_gl_entries(1) self.update_advance_paid() diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 33f263433b78..86a565a4f719 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -9,7 +9,7 @@ erpnext.accounts.taxes.setup_tax_filters("Advance Taxes and Charges"); frappe.ui.form.on('Payment Entry', { onload: function(frm) { - frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', "Journal Entry", "Repost Payment Ledger"]; + frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger', 'Repost Accounting Ledger']; if(frm.doc.__islocal) { if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index cc42f9faec18..64b4d167082d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -147,6 +147,8 @@ def on_cancel(self): "Payment Ledger Entry", "Repost Payment Ledger", "Repost Payment Ledger Items", + "Repost Accounting Ledger", + "Repost Accounting Ledger Items", ) super(PaymentEntry, self).on_cancel() self.make_gl_entries(cancel=1) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 89d62078ccf1..66438a7efaba 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -35,7 +35,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying. super.onload(); // Ignore linked advances - this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice', "Repost Payment Ledger"]; + this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice', "Repost Payment Ledger", "Repost Accounting Ledger"]; if(!this.frm.doc.__islocal) { // show credit_to in print format diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index d175df579eed..9935086fe99d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1439,6 +1439,8 @@ def on_cancel(self): "Repost Item Valuation", "Repost Payment Ledger", "Repost Payment Ledger Items", + "Repost Accounting Ledger", + "Repost Accounting Ledger Items", "Payment Ledger Entry", "Tax Withheld Vouchers", "Serial and Batch Bundle", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index b45bc41e96f3..a4bcdb41db5f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -37,7 +37,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e super.onload(); this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log', - 'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger"]; + 'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger", "Repost Accounting Ledger"]; if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) { // show debit_to in print format diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f08bf18cfc94..8fec7556d9b9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -386,6 +386,8 @@ def on_cancel(self): "Repost Item Valuation", "Repost Payment Ledger", "Repost Payment Ledger Items", + "Repost Accounting Ledger", + "Repost Accounting Ledger Items", "Payment Ledger Entry", "Serial and Batch Bundle", ) From 47bfe2c34ac25c2630f546a6e02e98491f496c64 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 31 Jul 2023 20:09:39 +0530 Subject: [PATCH 09/24] chore: preview method --- .../repost_accounting_ledger.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 2a63dfd3f563..fff49faced07 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -57,7 +57,8 @@ def validate_vouchers(self): ) ) - def show_preview(self): + def generate_preview(self): + self.gl_entries = [] for x in self.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) if doc.doctype in ["Payment Entry", "Journal Entry"]: @@ -65,6 +66,34 @@ def show_preview(self): else: gle_map = doc.get_gl_entries() + # add empty row + self.gl_entries.append(gle_map + []) + + def format_preview(self): + from erpnext.accounts.report.general_ledger.general_ledger import get_columns + from erpnext.controllers.stock_controller import get_columns, get_data + + if self.gl_entries: + fields = [ + "posting_date", + "account", + "debit", + "credit", + "against", + "party", + "party_type", + "cost_center", + "against_voucher_type", + "against_voucher", + ] + + filters = {"company": self.company} + columns = get_columns(filters) + data = self.gl_entries + + gl_columns = get_columns(columns, fields) + gl_data = get_data(fields, self.gl_entries) + def on_submit(self): job_name = "repost_accounting_ledger_" + self.name frappe.enqueue( From f6a9d93c65f2eeec6324e06fc18597abf6ed59d2 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Aug 2023 14:09:47 +0530 Subject: [PATCH 10/24] chore: rudimentary form of preview --- .../repost_accounting_ledger.html | 34 +++++++++++ .../repost_accounting_ledger.js | 27 ++++++++- .../repost_accounting_ledger.py | 58 +++++++++++-------- 3 files changed, 93 insertions(+), 26 deletions(-) create mode 100644 erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html new file mode 100644 index 000000000000..93d9770d405f --- /dev/null +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html @@ -0,0 +1,34 @@ + + + + + + {% for col in gl_columns%} + + {% endfor %} + + + + {% for col in gl_columns%} + + {% endfor %} + + +{% for gl in gl_data%} + + {% for col in gl %} + + {% endfor %} + +{% endfor %} +
{{ col.label }}
+ {{ col }} +
diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js index 757b2dc06831..5f76f1e940aa 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js @@ -24,6 +24,29 @@ frappe.ui.form.on("Repost Accounting Ledger", { }, refresh: function(frm) { - - }, + frm.add_custom_button(__('Show Preview'), () => { + // frappe.open_in_new_tab = true; + frm.call({ + method: 'generate_preview', + // method: 'format_preview', + doc: frm.doc, + freeze: true, + freeze_message: __('Generating Preview'), + callback: function(r) { + if (r && r.message) { + let content = r.message; + let opts = { + title: "Preview", + subtitle: "preview", + content: content, + print_settings: {orientation: "landscape"}, + columns: [], + data: [], + } + frappe.render_grid(opts); + } + } + }); + }); + } }); diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index fff49faced07..47b609bd3aa6 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -57,7 +57,7 @@ def validate_vouchers(self): ) ) - def generate_preview(self): + def generate_preview_data(self): self.gl_entries = [] for x in self.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) @@ -67,32 +67,42 @@ def generate_preview(self): gle_map = doc.get_gl_entries() # add empty row - self.gl_entries.append(gle_map + []) + self.gl_entries.extend(gle_map + []) + + @frappe.whitelist() + def generate_preview(self): + from erpnext.accounts.report.general_ledger.general_ledger import get_columns as get_gl_columns + from erpnext.controllers.stock_controller import get_data - def format_preview(self): - from erpnext.accounts.report.general_ledger.general_ledger import get_columns - from erpnext.controllers.stock_controller import get_columns, get_data + gl_columns = [] + gl_data = [] + self.generate_preview_data() if self.gl_entries: - fields = [ - "posting_date", - "account", - "debit", - "credit", - "against", - "party", - "party_type", - "cost_center", - "against_voucher_type", - "against_voucher", - ] - - filters = {"company": self.company} - columns = get_columns(filters) - data = self.gl_entries - - gl_columns = get_columns(columns, fields) - gl_data = get_data(fields, self.gl_entries) + # fields = [ + # "posting_date", + # "account", + # "debit", + # "credit", + # "against", + # "party", + # "party_type", + # "cost_center", + # "voucher_type", + # "voucher_no", + # "against_voucher_type", + # "against_voucher", + # ] + + filters = {"company": self.company, "include_dimensions": 1} + + gl_columns = get_gl_columns(filters) + gl_data = get_data([x["fieldname"] for x in gl_columns], self.gl_entries) + rendered_page = frappe.render_template( + "erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html", + {"gl_columns": gl_columns, "gl_data": gl_data}, + ) + return rendered_page def on_submit(self): job_name = "repost_accounting_ledger_" + self.name From 87b1dc1132789f0a7d73eddf59193ea062eb0bde Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Aug 2023 15:03:08 +0530 Subject: [PATCH 11/24] refactor: preview template --- .../repost_accounting_ledger.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 47b609bd3aa6..5c21dca61e9b 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -2,7 +2,7 @@ # For license information, please see license.txt import frappe -from frappe import _ +from frappe import _, qb from frappe.model.document import Document from frappe.utils.data import comma_and @@ -59,6 +59,7 @@ def validate_vouchers(self): def generate_preview_data(self): self.gl_entries = [] + self.get_existing_ledger_entries() for x in self.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) if doc.doctype in ["Payment Entry", "Journal Entry"]: @@ -66,8 +67,24 @@ def generate_preview_data(self): else: gle_map = doc.get_gl_entries() - # add empty row - self.gl_entries.extend(gle_map + []) + self.gl_entries.extend(self.gles.get((x.voucher_type, x.voucher_no)).existing) + self.gl_entries.extend(gle_map) + + def get_existing_ledger_entries(self): + vouchers = [x.voucher_no for x in self.vouchers] + gl = qb.DocType("GL Entry") + existing_gles = ( + qb.from_(gl) + .select(gl.star) + .where((gl.voucher_no.isin(vouchers)) & (gl.is_cancelled == 1)) + .run(as_dict=True) + ) + self.gles = frappe._dict({}) + + for gle in existing_gles: + self.gles.setdefault((gle.voucher_type, gle.voucher_no), frappe._dict({})).setdefault( + "existing", [] + ).append(gle) @frappe.whitelist() def generate_preview(self): @@ -79,21 +96,6 @@ def generate_preview(self): self.generate_preview_data() if self.gl_entries: - # fields = [ - # "posting_date", - # "account", - # "debit", - # "credit", - # "against", - # "party", - # "party_type", - # "cost_center", - # "voucher_type", - # "voucher_no", - # "against_voucher_type", - # "against_voucher", - # ] - filters = {"company": self.company, "include_dimensions": 1} gl_columns = get_gl_columns(filters) @@ -102,6 +104,7 @@ def generate_preview(self): "erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html", {"gl_columns": gl_columns, "gl_data": gl_data}, ) + return rendered_page def on_submit(self): From c63e3c617017311cb80b01b3aa7230bca10650b6 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Aug 2023 15:40:47 +0530 Subject: [PATCH 12/24] refactor: basic background colors to differentiate old and new --- .../repost_accounting_ledger.html | 16 ++++++-- .../repost_accounting_ledger.py | 40 ++++++++++--------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html index 93d9770d405f..2dec8f753f2b 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html @@ -6,6 +6,12 @@ .print-format td { vertical-align:middle !important; } + .old { + background-color: #FFB3C0; + } + .new { + background-color: #B3FFCC; + } @@ -23,10 +29,14 @@ {% for gl in gl_data%} - - {% for col in gl %} +{% if gl["old"]%} + +{% else %} + +{% endif %} + {% for col in gl_columns %} - {{ col }} + {{ gl[col.fieldname] }} {% endfor %} diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 5c21dca61e9b..f70e70779c3c 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -57,26 +57,13 @@ def validate_vouchers(self): ) ) - def generate_preview_data(self): - self.gl_entries = [] - self.get_existing_ledger_entries() - for x in self.vouchers: - doc = frappe.get_doc(x.voucher_type, x.voucher_no) - if doc.doctype in ["Payment Entry", "Journal Entry"]: - gle_map = doc.build_gl_map() - else: - gle_map = doc.get_gl_entries() - - self.gl_entries.extend(self.gles.get((x.voucher_type, x.voucher_no)).existing) - self.gl_entries.extend(gle_map) - def get_existing_ledger_entries(self): vouchers = [x.voucher_no for x in self.vouchers] gl = qb.DocType("GL Entry") existing_gles = ( qb.from_(gl) .select(gl.star) - .where((gl.voucher_no.isin(vouchers)) & (gl.is_cancelled == 1)) + .where((gl.voucher_no.isin(vouchers)) & (gl.is_cancelled == 0)) .run(as_dict=True) ) self.gles = frappe._dict({}) @@ -84,12 +71,26 @@ def get_existing_ledger_entries(self): for gle in existing_gles: self.gles.setdefault((gle.voucher_type, gle.voucher_no), frappe._dict({})).setdefault( "existing", [] - ).append(gle) + ).append(gle.update({"old": True})) + + def generate_preview_data(self): + self.gl_entries = [] + self.get_existing_ledger_entries() + for x in self.vouchers: + doc = frappe.get_doc(x.voucher_type, x.voucher_no) + if doc.doctype in ["Payment Entry", "Journal Entry"]: + gle_map = doc.build_gl_map() + else: + gle_map = doc.get_gl_entries() + + old_entries = self.gles.get((x.voucher_type, x.voucher_no)) + if old_entries: + self.gl_entries.extend(old_entries.existing) + self.gl_entries.extend(gle_map) @frappe.whitelist() def generate_preview(self): from erpnext.accounts.report.general_ledger.general_ledger import get_columns as get_gl_columns - from erpnext.controllers.stock_controller import get_data gl_columns = [] gl_data = [] @@ -97,9 +98,12 @@ def generate_preview(self): self.generate_preview_data() if self.gl_entries: filters = {"company": self.company, "include_dimensions": 1} + for x in get_gl_columns(filters): + if x["fieldname"] == "gl_entry": + x["fieldname"] = "name" + gl_columns.append(x) - gl_columns = get_gl_columns(filters) - gl_data = get_data([x["fieldname"] for x in gl_columns], self.gl_entries) + gl_data = self.gl_entries rendered_page = frappe.render_template( "erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.html", {"gl_columns": gl_columns, "gl_data": gl_data}, From 9930dd210b624ea6f228f05861147ec5556d73ce Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 3 Aug 2023 14:10:36 +0530 Subject: [PATCH 13/24] chore: remove commented code --- .../repost_accounting_ledger/repost_accounting_ledger.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js index 5f76f1e940aa..3a87a380d199 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.js @@ -25,10 +25,8 @@ frappe.ui.form.on("Repost Accounting Ledger", { refresh: function(frm) { frm.add_custom_button(__('Show Preview'), () => { - // frappe.open_in_new_tab = true; frm.call({ method: 'generate_preview', - // method: 'format_preview', doc: frm.doc, freeze: true, freeze_message: __('Generating Preview'), From 6fe09bf656b540e98dc5c8b1b8944a7b92613fdc Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 3 Aug 2023 15:31:40 +0530 Subject: [PATCH 14/24] test: basic functionality --- .../test_repost_accounting_ledger.py | 60 ++++++++++++++++++- erpnext/accounts/test/accounts_mixin.py | 6 +- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index 7f1ed55a0c0a..e753fb25f1da 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -1,9 +1,63 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -# import frappe +import frappe +from frappe import qb +from frappe.query_builder.functions import Sum from frappe.tests.utils import FrappeTestCase +from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import start_repost +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.test.accounts_mixin import AccountsTestMixin -class TestRepostAccountingLedger(FrappeTestCase): - pass + +class TestRepostAccountingLedger(AccountsTestMixin, FrappeTestCase): + def setUp(self): + self.create_company() + self.create_customer() + self.create_item() + + def teadDown(self): + frappe.db.rollback() + + def test_repost_on_both_ledgers(self): + si = create_sales_invoice( + item=self.item, + company=self.company, + customer=self.customer, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + rate=100, + ) + + # manually set an incorrect debit amount in DB + gle = frappe.db.get_all("GL Entry", filters={"voucher_no": si.name, "account": self.debit_to}) + frappe.db.set_value("GL Entry", gle[0], "debit", 90) + + gl = qb.DocType("GL Entry") + res = ( + qb.from_(gl) + .select(gl.voucher_no, Sum(gl.debit).as_("debit"), Sum(gl.credit).as_("credit")) + .where((gl.voucher_no == si.name) & (gl.is_cancelled == 0)) + .run() + ) + # Ledger has incorrect amount + self.assertNotEqual(res[0], (si.name, 100, 100)) + + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + ral.save().submit() + + # background jobs don't run on test cases. Manually triggering repost function. + start_repost(ral.name) + + res = ( + qb.from_(gl) + .select(gl.voucher_no, Sum(gl.debit).as_("debit"), Sum(gl.credit).as_("credit")) + .where((gl.voucher_no == si.name) & (gl.is_cancelled == 0)) + .run() + ) + # Ledger should reflect correct amount post repost + self.assertEqual(res[0], (si.name, 100, 100)) diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index c82164ef6447..7701e1ebb582 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -4,7 +4,7 @@ class AccountsTestMixin: - def create_customer(self, customer_name, currency=None): + def create_customer(self, customer_name="_Test Customer", currency=None): if not frappe.db.exists("Customer", customer_name): customer = frappe.new_doc("Customer") customer.customer_name = customer_name @@ -17,7 +17,7 @@ def create_customer(self, customer_name, currency=None): else: self.customer = customer_name - def create_supplier(self, supplier_name, currency=None): + def create_supplier(self, supplier_name="_Test Supplier", currency=None): if not frappe.db.exists("Supplier", supplier_name): supplier = frappe.new_doc("Supplier") supplier.supplier_name = supplier_name @@ -31,7 +31,7 @@ def create_supplier(self, supplier_name, currency=None): else: self.supplier = supplier_name - def create_item(self, item_name, is_stock=0, warehouse=None, company=None): + def create_item(self, item_name="_Test Item", is_stock=0, warehouse=None, company=None): item = create_item(item_name, is_stock_item=is_stock, warehouse=warehouse, company=company) self.item = item.name From 42b4a7e23f3195981f068ea20587bdf13b072d55 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 09:31:54 +0530 Subject: [PATCH 15/24] chore: fix conflict --- erpnext/accounts/doctype/payment_entry/payment_entry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 86a565a4f719..f131be2dfeda 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -9,7 +9,7 @@ erpnext.accounts.taxes.setup_tax_filters("Advance Taxes and Charges"); frappe.ui.form.on('Payment Entry', { onload: function(frm) { - frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger', 'Repost Accounting Ledger']; + frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger']; if(frm.doc.__islocal) { if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null); From 0a36e0ed5f164a996a554cba7cca498a3f651090 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 10:33:27 +0530 Subject: [PATCH 16/24] chore: prevent repost on invoices with deferred accounting --- .../repost_accounting_ledger.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index f70e70779c3c..7ccd9f9d8b9d 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -17,6 +17,33 @@ def __init__(self, *args, **kwargs): def validate(self): self.validate_vouchers() self.validate_for_closed_fiscal_year() + self.validate_for_deferred_accounting() + + def validate_for_deferred_accounting(self): + sales_docs = [x.voucher_no for x in self.vouchers if x.voucher_type == "Sales Invoice"] + docs_with_deferred_revenue = frappe.db.get_all( + "Sales Invoice Item", + filters={"parent": ["in", sales_docs], "docstatus": 1, "enable_deferred_revenue": True}, + fields=["parent"], + as_list=1, + ) + + purchase_docs = [x.voucher_no for x in self.vouchers if x.voucher_type == "Purchase Invoice"] + docs_with_deferred_expense = frappe.db.get_all( + "Purchase Invoice Item", + filters={"parent": ["in", purchase_docs], "docstatus": 1, "enable_deferred_expense": 1}, + fields=["parent"], + as_list=1, + ) + + if docs_with_deferred_revenue or docs_with_deferred_expense: + frappe.throw( + _("Documents: {0} have deferred revenue/expense enabled for them. Cannot repost.").format( + frappe.bold( + comma_and([x[0] for x in docs_with_deferred_expense + docs_with_deferred_revenue]) + ) + ) + ) def validate_for_closed_fiscal_year(self): if self.vouchers: @@ -128,6 +155,9 @@ def start_repost(account_repost_doc=str) -> None: repost_doc = frappe.get_doc("Repost Accounting Ledger", account_repost_doc) if repost_doc.docstatus == 1: + # Prevent repost on invoices with deferred accounting + repost_doc.validate_for_deferred_accounting() + for x in repost_doc.vouchers: doc = frappe.get_doc(x.voucher_type, x.voucher_no) From 1386c8ed8defb8124cf2d5a047e6edc506abb689 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 11:53:09 +0530 Subject: [PATCH 17/24] refactor(test): rename and test basic validations and methods --- .../test_repost_accounting_ledger.py | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index e753fb25f1da..301dad491c9b 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -6,6 +6,8 @@ from frappe.query_builder.functions import Sum from frappe.tests.utils import FrappeTestCase +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry +from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import start_repost from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.test.accounts_mixin import AccountsTestMixin @@ -20,7 +22,7 @@ def setUp(self): def teadDown(self): frappe.db.rollback() - def test_repost_on_both_ledgers(self): + def test_basic_functions(self): si = create_sales_invoice( item=self.item, company=self.company, @@ -31,6 +33,35 @@ def test_repost_on_both_ledgers(self): rate=100, ) + preq = frappe.get_doc( + make_payment_request( + dt=si.doctype, + dn=si.name, + payment_request_type="Inward", + party_type="Customer", + party=si.customer, + ) + ) + preq.save().submit() + + # Test Validation Error + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.delete_cancelled_entries = True + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + ral.append( + "vouchers", {"voucher_type": preq.doctype, "voucher_no": preq.name} + ) # this should throw validation error + self.assertRaises(frappe.ValidationError, ral.save) + ral.vouchers.pop() + preq.cancel() + preq.delete() + + pe = get_payment_entry(si.doctype, si.name) + pe.save().submit() + ral.append("vouchers", {"voucher_type": pe.doctype, "voucher_no": pe.name}) + ral.save() + # manually set an incorrect debit amount in DB gle = frappe.db.get_all("GL Entry", filters={"voucher_no": si.name, "account": self.debit_to}) frappe.db.set_value("GL Entry", gle[0], "debit", 90) @@ -42,14 +73,17 @@ def test_repost_on_both_ledgers(self): .where((gl.voucher_no == si.name) & (gl.is_cancelled == 0)) .run() ) - # Ledger has incorrect amount + + # Assert incorrect ledger balance self.assertNotEqual(res[0], (si.name, 100, 100)) - ral = frappe.new_doc("Repost Accounting Ledger") - ral.company = self.company - ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + # Submit report document ral.save().submit() + # assert preview data is generated + preview = ral.generate_preview() + self.assertIsNotNone(preview) + # background jobs don't run on test cases. Manually triggering repost function. start_repost(ral.name) @@ -59,5 +93,6 @@ def test_repost_on_both_ledgers(self): .where((gl.voucher_no == si.name) & (gl.is_cancelled == 0)) .run() ) + # Ledger should reflect correct amount post repost self.assertEqual(res[0], (si.name, 100, 100)) From 0e2c43a24eca8d8a62102fbb299e3ef8b41aa770 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 14:57:49 +0530 Subject: [PATCH 18/24] refactor(test): test all validations --- .../repost_accounting_ledger.py | 2 +- .../test_repost_accounting_ledger.py | 53 +++++++++++++++++++ erpnext/accounts/test/accounts_mixin.py | 47 ++++++++++++---- 3 files changed, 90 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 7ccd9f9d8b9d..4cf2ed2f46cc 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -69,7 +69,7 @@ def validate_for_closed_fiscal_year(self): order_by="posting_date desc", limit=1, )[0] - if latest_voucher and latest_pcv > latest_voucher: + if latest_voucher and latest_pcv[0] >= latest_voucher: frappe.throw(_("Cannot Resubmit Ledger entries for vouchers in Closed fiscal year.")) def validate_vouchers(self): diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index 301dad491c9b..d7e074cc072f 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -5,12 +5,14 @@ from frappe import qb from frappe.query_builder.functions import Sum from frappe.tests.utils import FrappeTestCase +from frappe.utils import add_days, nowdate, today from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import start_repost from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.test.accounts_mixin import AccountsTestMixin +from erpnext.accounts.utils import get_fiscal_year class TestRepostAccountingLedger(AccountsTestMixin, FrappeTestCase): @@ -96,3 +98,54 @@ def test_basic_functions(self): # Ledger should reflect correct amount post repost self.assertEqual(res[0], (si.name, 100, 100)) + + def test_deferred_accounting_valiations(self): + si = create_sales_invoice( + item=self.item, + company=self.company, + customer=self.customer, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + rate=100, + do_not_submit=True, + ) + si.items[0].enable_deferred_revenue = True + si.items[0].deferred_revenue_account = self.deferred_revenue + si.items[0].service_start_date = nowdate() + si.items[0].service_end_date = add_days(nowdate(), 90) + si.save().submit() + + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + self.assertRaises(frappe.ValidationError, ral.save) + + def test_pcv_validation(self): + si = create_sales_invoice( + item=self.item, + company=self.company, + customer=self.customer, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + rate=100, + ) + pcv = frappe.get_doc( + { + "doctype": "Period Closing Voucher", + "transaction_date": today(), + "posting_date": today(), + "company": self.company, + "fiscal_year": get_fiscal_year(today(), company=self.company)[0], + "cost_center": self.cost_center, + "closing_account_head": self.retained_earnings, + "remarks": "test", + } + ) + pcv.save().submit() + + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + self.assertRaises(frappe.ValidationError, ral.save) diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index 7701e1ebb582..80ed81993e71 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -62,19 +62,44 @@ def create_company(self, company_name="_Test Company", abbr="_TC"): self.debit_usd = "Debtors USD - " + abbr self.cash = "Cash - " + abbr self.creditors = "Creditors - " + abbr + self.retained_earnings = "Retained Earnings - " + abbr - # create bank account - bank_account = "HDFC - " + abbr - if frappe.db.exists("Account", bank_account): - self.bank = bank_account - else: - bank_acc = frappe.get_doc( + # Deferred revenue, expense and bank accounts + other_accounts = [ + frappe._dict( + { + "attribute_name": "deferred_revenue", + "account_name": "Deferred Revenue", + "parent_account": "Current Liabilities - " + abbr, + } + ), + frappe._dict( { - "doctype": "Account", + "attribute_name": "deferred_expense", + "account_name": "Deferred Expense", + "parent_account": "Current Assets - " + abbr, + } + ), + frappe._dict( + { + "attribute_name": "bank", "account_name": "HDFC", "parent_account": "Bank Accounts - " + abbr, - "company": self.company, } - ) - bank_acc.save() - self.bank = bank_acc.name + ), + ] + for acc in other_accounts: + acc_name = acc.account_name + " - " + abbr + if frappe.db.exists("Account", acc_name): + setattr(self, acc.attribute_name, acc_name) + else: + new_acc = frappe.get_doc( + { + "doctype": "Account", + "account_name": acc.account_name + " - " + abbr, + "parent_account": acc.parent_account, + "company": self.company, + } + ) + new_acc.save() + setattr(self, acc.attribute_name, new_acc.name) From 5096dbf323424aee5d3ea366e2c9e4ad3f38ff6c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 16:19:04 +0530 Subject: [PATCH 19/24] fix(test): use proper name account name --- erpnext/accounts/test/accounts_mixin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index 80ed81993e71..a4322d3db542 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -91,12 +91,12 @@ def create_company(self, company_name="_Test Company", abbr="_TC"): for acc in other_accounts: acc_name = acc.account_name + " - " + abbr if frappe.db.exists("Account", acc_name): - setattr(self, acc.attribute_name, acc_name) + setattr(self, acc.attribute_name, acc.acc_name) else: new_acc = frappe.get_doc( { "doctype": "Account", - "account_name": acc.account_name + " - " + abbr, + "account_name": acc.account_name, "parent_account": acc.parent_account, "company": self.company, } From f2c460857ae739d7f19d3f3698c125c1dd045826 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 7 Aug 2023 17:07:26 +0530 Subject: [PATCH 20/24] refactor(test): fix failing test case --- .../test_repost_accounting_ledger.py | 6 +++--- erpnext/accounts/test/accounts_mixin.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index d7e074cc072f..e94ba97cbbaa 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -24,7 +24,7 @@ def setUp(self): def teadDown(self): frappe.db.rollback() - def test_basic_functions(self): + def test_01_basic_functions(self): si = create_sales_invoice( item=self.item, company=self.company, @@ -99,7 +99,7 @@ def test_basic_functions(self): # Ledger should reflect correct amount post repost self.assertEqual(res[0], (si.name, 100, 100)) - def test_deferred_accounting_valiations(self): + def test_02_deferred_accounting_valiations(self): si = create_sales_invoice( item=self.item, company=self.company, @@ -121,7 +121,7 @@ def test_deferred_accounting_valiations(self): ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) self.assertRaises(frappe.ValidationError, ral.save) - def test_pcv_validation(self): + def test_03_pcv_validation(self): si = create_sales_invoice( item=self.item, company=self.company, diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index a4322d3db542..70bbf7e694dd 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -91,7 +91,7 @@ def create_company(self, company_name="_Test Company", abbr="_TC"): for acc in other_accounts: acc_name = acc.account_name + " - " + abbr if frappe.db.exists("Account", acc_name): - setattr(self, acc.attribute_name, acc.acc_name) + setattr(self, acc.attribute_name, acc_name) else: new_acc = frappe.get_doc( { From 013af71753aabfcc5959a838faea2a0d26d36cbc Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 8 Aug 2023 14:41:02 +0530 Subject: [PATCH 21/24] refactor(test): clear old entries --- .../test_repost_accounting_ledger.py | 1 + erpnext/accounts/test/accounts_mixin.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index e94ba97cbbaa..47479da91628 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -20,6 +20,7 @@ def setUp(self): self.create_company() self.create_customer() self.create_item() + self.clear_old_entries() def teadDown(self): frappe.db.rollback() diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index 70bbf7e694dd..4d08fcaf9508 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -103,3 +103,9 @@ def create_company(self, company_name="_Test Company", abbr="_TC"): ) new_acc.save() setattr(self, acc.attribute_name, new_acc.name) + + def clear_old_entries(self): + if self.company: + tdr = frappe.new_doc("Transaction Deletion Record") + tdr.company = self.company + tdr.save().submit() From 7ad3c059c39f9a3cc7befc7c3cc6c678016e5a0e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 8 Aug 2023 15:20:47 +0530 Subject: [PATCH 22/24] refactor(test): simpler logic to clear old records --- .../test_repost_accounting_ledger.py | 5 ++++- erpnext/accounts/test/accounts_mixin.py | 6 ------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index 47479da91628..11ecbe5f631d 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -20,7 +20,6 @@ def setUp(self): self.create_company() self.create_customer() self.create_item() - self.clear_old_entries() def teadDown(self): frappe.db.rollback() @@ -123,6 +122,10 @@ def test_02_deferred_accounting_valiations(self): self.assertRaises(frappe.ValidationError, ral.save) def test_03_pcv_validation(self): + # Clear old GL entries so PCV can be submitted. + gl = frappe.qb.DocType("GL Entry") + qb.from_(gl).delete().where(gl.company == self.company).run() + si = create_sales_invoice( item=self.item, company=self.company, diff --git a/erpnext/accounts/test/accounts_mixin.py b/erpnext/accounts/test/accounts_mixin.py index 4d08fcaf9508..70bbf7e694dd 100644 --- a/erpnext/accounts/test/accounts_mixin.py +++ b/erpnext/accounts/test/accounts_mixin.py @@ -103,9 +103,3 @@ def create_company(self, company_name="_Test Company", abbr="_TC"): ) new_acc.save() setattr(self, acc.attribute_name, new_acc.name) - - def clear_old_entries(self): - if self.company: - tdr = frappe.new_doc("Transaction Deletion Record") - tdr.company = self.company - tdr.save().submit() From b00ae70cbc9900988d6d68751fec045254627dd1 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 8 Aug 2023 16:06:37 +0530 Subject: [PATCH 23/24] refactor(test): make use of deletion flag --- .../repost_accounting_ledger/test_repost_accounting_ledger.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index 11ecbe5f631d..e7f1d862379b 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -118,6 +118,7 @@ def test_02_deferred_accounting_valiations(self): ral = frappe.new_doc("Repost Accounting Ledger") ral.company = self.company + ral.delete_cancelled_entries = False ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) self.assertRaises(frappe.ValidationError, ral.save) @@ -151,5 +152,6 @@ def test_03_pcv_validation(self): ral = frappe.new_doc("Repost Accounting Ledger") ral.company = self.company + ral.delete_cancelled_entries = True ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) self.assertRaises(frappe.ValidationError, ral.save) From 4c560430795ac2c97787453c3cbfce1d252de977 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 8 Aug 2023 17:25:46 +0530 Subject: [PATCH 24/24] refactor(test): split into multiple test cases --- .../test_repost_accounting_ledger.py | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py index e7f1d862379b..0e75dd2e3e17 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/test_repost_accounting_ledger.py @@ -4,7 +4,7 @@ import frappe from frappe import qb from frappe.query_builder.functions import Sum -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, nowdate, today from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry @@ -79,13 +79,9 @@ def test_01_basic_functions(self): # Assert incorrect ledger balance self.assertNotEqual(res[0], (si.name, 100, 100)) - # Submit report document + # Submit repost document ral.save().submit() - # assert preview data is generated - preview = ral.generate_preview() - self.assertIsNotNone(preview) - # background jobs don't run on test cases. Manually triggering repost function. start_repost(ral.name) @@ -118,11 +114,11 @@ def test_02_deferred_accounting_valiations(self): ral = frappe.new_doc("Repost Accounting Ledger") ral.company = self.company - ral.delete_cancelled_entries = False ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) self.assertRaises(frappe.ValidationError, ral.save) - def test_03_pcv_validation(self): + @change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1}) + def test_04_pcv_validation(self): # Clear old GL entries so PCV can be submitted. gl = frappe.qb.DocType("GL Entry") qb.from_(gl).delete().where(gl.company == self.company).run() @@ -152,6 +148,55 @@ def test_03_pcv_validation(self): ral = frappe.new_doc("Repost Accounting Ledger") ral.company = self.company - ral.delete_cancelled_entries = True ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) self.assertRaises(frappe.ValidationError, ral.save) + + pcv.reload() + pcv.cancel() + pcv.delete() + + def test_03_deletion_flag_and_preview_function(self): + si = create_sales_invoice( + item=self.item, + company=self.company, + customer=self.customer, + debit_to=self.debit_to, + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + rate=100, + ) + + pe = get_payment_entry(si.doctype, si.name) + pe.save().submit() + + # without deletion flag set + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.delete_cancelled_entries = False + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + ral.append("vouchers", {"voucher_type": pe.doctype, "voucher_no": pe.name}) + ral.save() + + # assert preview data is generated + preview = ral.generate_preview() + self.assertIsNotNone(preview) + + ral.save().submit() + + # background jobs don't run on test cases. Manually triggering repost function. + start_repost(ral.name) + + self.assertIsNotNone(frappe.db.exists("GL Entry", {"voucher_no": si.name, "is_cancelled": 1})) + self.assertIsNotNone(frappe.db.exists("GL Entry", {"voucher_no": pe.name, "is_cancelled": 1})) + + # with deletion flag set + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = self.company + ral.delete_cancelled_entries = True + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + ral.append("vouchers", {"voucher_type": pe.doctype, "voucher_no": pe.name}) + ral.save().submit() + + start_repost(ral.name) + self.assertIsNone(frappe.db.exists("GL Entry", {"voucher_no": si.name, "is_cancelled": 1})) + self.assertIsNone(frappe.db.exists("GL Entry", {"voucher_no": pe.name, "is_cancelled": 1}))