diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index 295cd983b3d..5258214dad2 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -11,6 +11,10 @@ from frappe.model import core_doctypes_list from frappe.model.document import Document from frappe.utils import cstr +from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import ( + get_allowed_types_from_settings, +) + class AccountingDimension(Document): # begin: auto-generated types @@ -106,6 +110,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None): doc_count = len(get_accounting_dimensions()) count = 0 + repostable_doctypes = get_allowed_types_from_settings() for doctype in doclist: @@ -121,6 +126,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None): "options": doc.document_type, "insert_after": insert_after_field, "owner": "Administrator", + "allow_on_submit": 1 if doctype in repostable_doctypes else 0, } meta = frappe.get_meta(doctype, cached=False) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 07fb5e857ca..72469ea1e11 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -14,6 +14,25 @@ frappe.ui.form.on("Journal Entry", { refresh: function(frm) { erpnext.toggle_naming_series(); + if (frm.doc.repost_required && frm.doc.docstatus===1) { + frm.set_intro(__("Accounting entries for this Journal Entry need to be reposted. Please click on 'Repost' button to update.")); + frm.add_custom_button(__('Repost Accounting Entries'), + () => { + frm.call({ + doc: frm.doc, + method: 'repost_accounting_entries', + freeze: true, + freeze_message: __('Reposting...'), + callback: (r) => { + if (!r.exc) { + frappe.msgprint(__('Accounting Entries are reposted.')); + frm.refresh(); + } + } + }); + }).removeClass('btn-default').addClass('btn-warning'); + } + if(frm.doc.docstatus > 0) { frm.add_custom_button(__('Ledger'), function() { frappe.route_options = { @@ -184,7 +203,6 @@ var update_jv_details = function(doc, r) { $.each(r, function(i, d) { var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts"); frappe.model.set_value(row.doctype, row.name, "account", d.account) - frappe.model.set_value(row.doctype, row.name, "balance", d.balance) }); refresh_field("accounts"); } @@ -193,7 +211,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro onload() { this.load_defaults(); this.setup_queries(); - this.setup_balance_formatter(); erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype); } @@ -292,19 +309,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro } - setup_balance_formatter() { - const formatter = function(value, df, options, doc) { - var currency = frappe.meta.get_field_currency(df, doc); - var dr_or_cr = value ? ('') : ""; - return "
" - + ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency)) - + " " + dr_or_cr - + "
"; - }; - this.frm.fields_dict.accounts.grid.update_docfield_property('balance', 'formatter', formatter); - this.frm.fields_dict.accounts.grid.update_docfield_property('party_balance', 'formatter', formatter); - } - reference_name(doc, cdt, cdn) { var d = frappe.get_doc(cdt, cdn); @@ -400,23 +404,22 @@ frappe.ui.form.on("Journal Entry Account", { if(!d.account && d.party_type && d.party) { if(!frm.doc.company) frappe.throw(__("Please select Company")); return frm.call({ - method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance", + method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_currency", child: d, args: { company: frm.doc.company, party_type: d.party_type, party: d.party, - cost_center: d.cost_center } }); } }, cost_center: function(frm, dt, dn) { - erpnext.journal_entry.set_account_balance(frm, dt, dn); + erpnext.journal_entry.set_account_details(frm, dt, dn); }, account: function(frm, dt, dn) { - erpnext.journal_entry.set_account_balance(frm, dt, dn); + erpnext.journal_entry.set_account_details(frm, dt, dn); }, debit_in_account_currency: function(frm, cdt, cdn) { @@ -600,14 +603,14 @@ $.extend(erpnext.journal_entry, { }); $.extend(erpnext.journal_entry, { - set_account_balance: function(frm, dt, dn) { + set_account_details: function(frm, dt, dn) { var d = locals[dt][dn]; if(d.account) { if(!frm.doc.company) frappe.throw(__("Please select Company first")); if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first")); return frappe.call({ - method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type", + method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_details_and_party_type", args: { account: d.account, date: frm.doc.posting_date, @@ -615,7 +618,6 @@ $.extend(erpnext.journal_entry, { debit: flt(d.debit_in_account_currency), credit: flt(d.credit_in_account_currency), exchange_rate: d.exchange_rate, - cost_center: d.cost_center }, callback: function(r) { if(r.message) { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 906760ec312..91febb34052 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -64,7 +64,8 @@ "stock_entry", "subscription_section", "auto_repeat", - "amended_from" + "amended_from", + "repost_required" ], "fields": [ { @@ -543,6 +544,15 @@ "label": "Is System Generated", "no_copy": 1, "read_only": 1 + }, + { + "default": "0", + "fieldname": "repost_required", + "fieldtype": "Check", + "hidden": 1, + "label": "Repost Required", + "print_hide": 1, + "read_only": 1 } ], "icon": "fa fa-file-text", diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index f06fafcc5cf..d5b9393ac08 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -13,6 +13,10 @@ from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import ( get_party_account_based_on_invoice_discounting, ) +from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import ( + validate_docs_for_deferred_accounting, + validate_docs_for_voucher_types, +) from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import ( get_party_tax_withholding_details, ) @@ -140,7 +144,6 @@ class JournalEntry(AccountsController): self.set_print_format_fields() self.validate_credit_debit_note() self.validate_empty_accounts_table() - self.set_account_and_party_balance() self.validate_inter_company_accounts() self.validate_depr_entry_voucher_type() @@ -150,6 +153,10 @@ class JournalEntry(AccountsController): if not self.title: self.title = self.get_title() + def validate_for_repost(self): + validate_docs_for_voucher_types(["Journal Entry"]) + validate_docs_for_deferred_accounting([self.name], []) + def submit(self): if len(self.accounts) > 100: msgprint(_("The task has been enqueued as a background job."), alert=True) @@ -173,6 +180,15 @@ class JournalEntry(AccountsController): self.update_inter_company_jv() self.update_invoice_discounting() + def on_update_after_submit(self): + if hasattr(self, "repost_required"): + self.needs_repost = self.check_if_fields_updated( + fields_to_check=[], child_tables={"accounts": []} + ) + if self.needs_repost: + self.validate_for_repost() + self.db_set("repost_required", self.needs_repost) + def on_cancel(self): # References for this Journal are removed on the `on_cancel` event in accounts_controller super(JournalEntry, self).on_cancel() @@ -1160,21 +1176,6 @@ class JournalEntry(AccountsController): if not self.get("accounts"): frappe.throw(_("Accounts table cannot be blank.")) - def set_account_and_party_balance(self): - account_balance = {} - party_balance = {} - for d in self.get("accounts"): - if d.account not in account_balance: - account_balance[d.account] = get_balance_on(account=d.account, date=self.posting_date) - - if (d.party_type, d.party) not in party_balance: - party_balance[(d.party_type, d.party)] = get_balance_on( - party_type=d.party_type, party=d.party, date=self.posting_date, company=self.company - ) - - d.account_balance = account_balance[d.account] - d.party_balance = party_balance[(d.party_type, d.party)] - @frappe.whitelist() def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None): @@ -1340,8 +1341,6 @@ def get_payment_entry(ref_doc, args): "account_type": frappe.get_cached_value("Account", args.get("party_account"), "account_type"), "account_currency": args.get("party_account_currency") or get_account_currency(args.get("party_account")), - "balance": get_balance_on(args.get("party_account")), - "party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")), "exchange_rate": exchange_rate, args.get("amount_field_party"): args.get("amount"), "is_advance": args.get("is_advance"), @@ -1489,30 +1488,23 @@ def get_outstanding(args): @frappe.whitelist() -def get_party_account_and_balance(company, party_type, party, cost_center=None): +def get_party_account_and_currency(company, party_type, party): if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) account = get_party_account(party_type, party, company) - account_balance = get_balance_on(account=account, cost_center=cost_center) - party_balance = get_balance_on( - party_type=party_type, party=party, company=company, cost_center=cost_center - ) - return { "account": account, - "balance": account_balance, - "party_balance": party_balance, "account_currency": frappe.get_cached_value("Account", account, "account_currency"), } @frappe.whitelist() -def get_account_balance_and_party_type( - account, date, company, debit=None, credit=None, exchange_rate=None, cost_center=None +def get_account_details_and_party_type( + account, date, company, debit=None, credit=None, exchange_rate=None ): - """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" + """Returns dict of account details and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) @@ -1532,7 +1524,6 @@ def get_account_balance_and_party_type( party_type = "" grid_values = { - "balance": get_balance_on(account, date, cost_center=cost_center), "party_type": party_type, "account_type": account_details.account_type, "account_currency": account_details.account_currency or company_currency, diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index a6e920b7ef6..798d3bb6c82 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -166,43 +166,37 @@ class TestJournalEntry(unittest.TestCase): jv.get("accounts")[1].credit_in_account_currency = 5000 jv.submit() - gl_entries = frappe.db.sql( - """select account, account_currency, debit, credit, - debit_in_account_currency, credit_in_account_currency - from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s - order by account asc""", - jv.name, - as_dict=1, - ) + self.voucher_no = jv.name - self.assertTrue(gl_entries) + self.fields = [ + "account", + "account_currency", + "debit", + "debit_in_account_currency", + "credit", + "credit_in_account_currency", + ] - expected_values = { - "_Test Bank USD - _TC": { - "account_currency": "USD", - "debit": 5000, - "debit_in_account_currency": 100, - "credit": 0, - "credit_in_account_currency": 0, - }, - "_Test Bank - _TC": { + self.expected_gle = [ + { + "account": "_Test Bank - _TC", "account_currency": "INR", "debit": 0, "debit_in_account_currency": 0, "credit": 5000, "credit_in_account_currency": 5000, }, - } + { + "account": "_Test Bank USD - _TC", + "account_currency": "USD", + "debit": 5000, + "debit_in_account_currency": 100, + "credit": 0, + "credit_in_account_currency": 0, + }, + ] - for field in ( - "account_currency", - "debit", - "debit_in_account_currency", - "credit", - "credit_in_account_currency", - ): - for i, gle in enumerate(gl_entries): - self.assertEqual(expected_values[gle.account][field], gle[field]) + self.check_gl_entries() # cancel jv.cancel() @@ -228,43 +222,37 @@ class TestJournalEntry(unittest.TestCase): rjv.posting_date = nowdate() rjv.submit() - gl_entries = frappe.db.sql( - """select account, account_currency, debit, credit, - debit_in_account_currency, credit_in_account_currency - from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s - order by account asc""", - rjv.name, - as_dict=1, - ) + self.voucher_no = rjv.name - self.assertTrue(gl_entries) + self.fields = [ + "account", + "account_currency", + "debit", + "credit", + "debit_in_account_currency", + "credit_in_account_currency", + ] - expected_values = { - "_Test Bank USD - _TC": { + self.expected_gle = [ + { + "account": "_Test Bank USD - _TC", "account_currency": "USD", "debit": 0, "debit_in_account_currency": 0, "credit": 5000, "credit_in_account_currency": 100, }, - "Sales - _TC": { + { + "account": "Sales - _TC", "account_currency": "INR", "debit": 5000, "debit_in_account_currency": 5000, "credit": 0, "credit_in_account_currency": 0, }, - } + ] - for field in ( - "account_currency", - "debit", - "debit_in_account_currency", - "credit", - "credit_in_account_currency", - ): - for i, gle in enumerate(gl_entries): - self.assertEqual(expected_values[gle.account][field], gle[field]) + self.check_gl_entries() def test_disallow_change_in_account_currency_for_a_party(self): # create jv in USD @@ -344,23 +332,25 @@ class TestJournalEntry(unittest.TestCase): jv.insert() jv.submit() - expected_values = { - "_Test Cash - _TC": {"cost_center": cost_center}, - "_Test Bank - _TC": {"cost_center": cost_center}, - } + self.voucher_no = jv.name - gl_entries = frappe.db.sql( - """select account, cost_center, debit, credit - from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s - order by account asc""", - jv.name, - as_dict=1, - ) + self.fields = [ + "account", + "cost_center", + ] - self.assertTrue(gl_entries) + self.expected_gle = [ + { + "account": "_Test Bank - _TC", + "cost_center": cost_center, + }, + { + "account": "_Test Cash - _TC", + "cost_center": cost_center, + }, + ] - for gle in gl_entries: - self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) + self.check_gl_entries() def test_jv_with_project(self): from erpnext.projects.doctype.project.test_project import make_project @@ -387,23 +377,22 @@ class TestJournalEntry(unittest.TestCase): jv.insert() jv.submit() - expected_values = { - "_Test Cash - _TC": {"project": project_name}, - "_Test Bank - _TC": {"project": project_name}, - } + self.voucher_no = jv.name - gl_entries = frappe.db.sql( - """select account, project, debit, credit - from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s - order by account asc""", - jv.name, - as_dict=1, - ) + self.fields = ["account", "project"] - self.assertTrue(gl_entries) + self.expected_gle = [ + { + "account": "_Test Bank - _TC", + "project": project_name, + }, + { + "account": "_Test Cash - _TC", + "project": project_name, + }, + ] - for gle in gl_entries: - self.assertEqual(expected_values[gle.account]["project"], gle.project) + self.check_gl_entries() def test_jv_account_and_party_balance_with_cost_centre(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center @@ -426,6 +415,79 @@ class TestJournalEntry(unittest.TestCase): account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center) self.assertEqual(expected_account_balance, account_balance) + def test_repost_accounting_entries(self): + from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center + + # Configure Repost Accounting Ledger for JVs + settings = frappe.get_doc("Repost Accounting Ledger Settings") + if not [x for x in settings.allowed_types if x.document_type == "Journal Entry"]: + settings.append("allowed_types", {"document_type": "Journal Entry", "allowed": True}) + settings.save() + + # Create JV with defaut cost center - _Test Cost Center + jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False) + jv.multi_currency = 0 + jv.submit() + + # Check GL entries before reposting + self.voucher_no = jv.name + + self.fields = [ + "account", + "debit_in_account_currency", + "credit_in_account_currency", + "cost_center", + ] + + self.expected_gle = [ + { + "account": "_Test Bank - _TC", + "debit_in_account_currency": 0, + "credit_in_account_currency": 100, + "cost_center": "_Test Cost Center - _TC", + }, + { + "account": "_Test Cash - _TC", + "debit_in_account_currency": 100, + "credit_in_account_currency": 0, + "cost_center": "_Test Cost Center - _TC", + }, + ] + + self.check_gl_entries() + + # Change cost center for bank account - _Test Cost Center for BS Account + create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") + jv.accounts[1].cost_center = "_Test Cost Center for BS Account - _TC" + jv.save() + + # Check if repost flag gets set on update after submit + self.assertTrue(jv.repost_required) + jv.repost_accounting_entries() + + # Check GL entries after reposting + jv.load_from_db() + self.expected_gle[0]["cost_center"] = "_Test Cost Center for BS Account - _TC" + self.check_gl_entries() + + def check_gl_entries(self): + gl = frappe.qb.DocType("GL Entry") + query = frappe.qb.from_(gl) + for field in self.fields: + query = query.select(gl[field]) + + query = query.where( + (gl.voucher_type == "Journal Entry") + & (gl.voucher_no == self.voucher_no) + & (gl.is_cancelled == 0) + ).orderby(gl.account) + + gl_entries = query.run(as_dict=True) + + for i in range(len(self.expected_gle)): + for field in self.fields: + self.assertEqual(self.expected_gle[i][field], gl_entries[i][field]) + def make_journal_entry( account1, diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 3132fe9b12b..00fd7b9d0ab 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -9,12 +9,10 @@ "field_order": [ "account", "account_type", - "balance", "col_break1", "bank_account", "party_type", "party", - "party_balance", "accounting_dimensions_section", "cost_center", "dimension_col_break", @@ -64,17 +62,7 @@ "print_hide": 1 }, { - "fieldname": "balance", - "fieldtype": "Currency", - "label": "Account Balance", - "no_copy": 1, - "oldfieldname": "balance", - "oldfieldtype": "Data", - "options": "account_currency", - "print_hide": 1, - "read_only": 1 - }, - { + "allow_on_submit": 1, "default": ":Company", "description": "If Income or Expense", "fieldname": "cost_center", @@ -107,14 +95,6 @@ "label": "Party", "options": "party_type" }, - { - "fieldname": "party_balance", - "fieldtype": "Currency", - "label": "Party Balance", - "options": "account_currency", - "print_hide": 1, - "read_only": 1 - }, { "fieldname": "currency_section", "fieldtype": "Section Break", @@ -223,6 +203,7 @@ "no_copy": 1 }, { + "allow_on_submit": 1, "fieldname": "project", "fieldtype": "Link", "label": "Project", @@ -287,7 +268,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2023-11-23 11:44:25.841187", + "modified": "2024-02-05 01:10:50.224840", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 0a9b9345a32..18ecd91d728 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -731,6 +731,7 @@ class PurchaseInvoice(BuyingController): "cash_bank_account", "write_off_account", "unrealized_profit_loss_account", + "is_opening", ] child_tables = {"items": ("expense_account",), "taxes": ("account_head",)} self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 3ab9f518d05..1343b39352c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -721,6 +721,7 @@ class SalesInvoice(SellingController): "write_off_account", "loyalty_redemption_account", "unrealized_profit_loss_account", + "is_opening", ] child_tables = { "items": ("income_account", "expense_account", "discount_account"), diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index b88148d4d5d..045e4fb7b6b 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -2419,27 +2419,20 @@ class AccountsController(TransactionBase): doc_before_update = self.get_doc_before_save() accounting_dimensions = get_accounting_dimensions() + ["cost_center", "project"] - # Check if opening entry check updated - needs_repost = doc_before_update.get("is_opening") != self.is_opening + # Parent Level Accounts excluding party account + fields_to_check += accounting_dimensions + for field in fields_to_check: + if doc_before_update.get(field) != self.get(field): + return True - if not needs_repost: - # Parent Level Accounts excluding party account - fields_to_check += accounting_dimensions - for field in fields_to_check: - if doc_before_update.get(field) != self.get(field): - needs_repost = 1 - break + # Check for child tables + for table in child_tables: + if check_if_child_table_updated( + doc_before_update.get(table), self.get(table), child_tables[table] + ): + return True - if not needs_repost: - # Check for child tables - for table in child_tables: - needs_repost = check_if_child_table_updated( - doc_before_update.get(table), self.get(table), child_tables[table] - ) - if needs_repost: - break - - return needs_repost + return False @frappe.whitelist() def repost_accounting_entries(self): @@ -3465,15 +3458,12 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil def check_if_child_table_updated( child_table_before_update, child_table_after_update, fields_to_check ): - accounting_dimensions = get_accounting_dimensions() + ["cost_center", "project"] - # Check if any field affecting accounting entry is altered - for index, item in enumerate(child_table_after_update): - for field in fields_to_check: - if child_table_before_update[index].get(field) != item.get(field): - return True + fields_to_check = list(fields_to_check) + get_accounting_dimensions() + ["cost_center", "project"] - for dimension in accounting_dimensions: - if child_table_before_update[index].get(dimension) != item.get(dimension): + # Check if any field affecting accounting entry is altered + for index, item in enumerate(child_table_before_update): + for field in fields_to_check: + if child_table_after_update[index].get(field) != item.get(field): return True return False diff --git a/erpnext/patches.txt b/erpnext/patches.txt index f0b104e2c5f..d5c0a4e80e4 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -353,6 +353,7 @@ erpnext.patches.v14_0.update_zero_asset_quantity_field execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction") erpnext.patches.v14_0.update_total_asset_cost_field erpnext.patches.v14_0.create_accounting_dimensions_in_reconciliation_tool +erpnext.patches.v15_0.allow_on_submit_dimensions_for_repostable_doctypes # below migration patch should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2023-12-20 diff --git a/erpnext/patches/v15_0/allow_on_submit_dimensions_for_repostable_doctypes.py b/erpnext/patches/v15_0/allow_on_submit_dimensions_for_repostable_doctypes.py new file mode 100644 index 00000000000..e75610d0a53 --- /dev/null +++ b/erpnext/patches/v15_0/allow_on_submit_dimensions_for_repostable_doctypes.py @@ -0,0 +1,14 @@ +import frappe + +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( + get_accounting_dimensions, +) +from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import ( + get_allowed_types_from_settings, +) + + +def execute(): + for dt in get_allowed_types_from_settings(): + for dimension in get_accounting_dimensions(): + frappe.db.set_value("Custom Field", dt + "-" + dimension, "allow_on_submit", 1)