From be57f51cea2172b38b1508b1044bc70bd7e8aede Mon Sep 17 00:00:00 2001 From: Pandiyan P Date: Sat, 11 Jul 2026 18:47:28 +0530 Subject: [PATCH] fix(accounts): retain invoice table on opening invoice creation error (#56353) Co-authored-by: diptanilsaha (cherry picked from commit ad17efe243671945823a01a1a3fefc29c9fa3c21) # Conflicts: # erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py --- .../opening_invoice_creation_tool.js | 17 ++++++++++++----- .../opening_invoice_creation_tool.py | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js index 4938e6690e5..824251dc87a 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js @@ -24,15 +24,22 @@ frappe.ui.form.on("Opening Invoice Creation Tool", { setTimeout( () => { frm.doc.import_in_progress = false; - frm.clear_table("invoices"); - frm.refresh_fields(); frm.page.clear_indicator(); frm.dashboard.hide_progress(); - if (frm.doc.invoice_type == "Sales") { - frappe.msgprint(__("Opening Sales Invoices have been created.")); + if (!data.errors) { + frm.clear_table("invoices"); + frm.refresh_fields(); + const message = + frm.doc.invoice_type == "Sales" + ? __("Opening Sales Invoice(s) have been created.") + : __("Opening Purchase Invoice(s) have been created."); + frappe.show_alert({ + message: message, + indicator: "green", + }); } else { - frappe.msgprint(__("Opening Purchase Invoices have been created.")); + frm.refresh_fields(); } }, 1500, diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 4003f533ded..c02a66bdbf4 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -254,22 +254,35 @@ class OpeningInvoiceCreationTool(Document): def start_import(invoices): errors = 0 names = [] + total = len(invoices) for idx, d in enumerate(invoices): +<<<<<<< HEAD +======= + # Scope each invoice to a savepoint so a failure only undoes that invoice. + # A plain rollback() would discard the whole transaction — including invoices + # imported earlier in this batch and the error logs of earlier failures (the + # latter only survive on mariadb because the Error Log table is MyISAM; on + # postgres they would be lost). Rolling back to a savepoint keeps both. + savepoint = f"opening_invoice_{frappe.generate_hash(length=8)}" + frappe.db.savepoint(savepoint) + is_last = idx == total - 1 +>>>>>>> ad17efe243 (fix(accounts): retain invoice table on opening invoice creation error (#56353)) try: invoice_number = None if d.invoice_number: invoice_number = d.invoice_number - publish(idx, len(invoices), d.doctype) doc = frappe.get_doc(d) doc.flags.ignore_mandatory = True doc.insert(set_name=invoice_number) doc.submit() frappe.db.commit() names.append(doc.name) + publish(idx, total, d.doctype, errors=errors if is_last else None) except Exception: errors += 1 frappe.db.rollback() doc.log_error("Opening invoice creation failed") + publish(idx, total, d.doctype, errors=errors if is_last else None) if errors: frappe.msgprint( _("You had {} errors while creating opening invoices. Check {} for more details").format( @@ -281,7 +294,7 @@ def start_import(invoices): return names -def publish(index, total, doctype): +def publish(index, total, doctype, errors=None): frappe.publish_realtime( "opening_invoice_creation_progress", dict( @@ -289,6 +302,7 @@ def publish(index, total, doctype): message=_("Creating {} out of {} {}").format(index + 1, total, doctype), count=index + 1, total=total, + errors=errors, ), user=frappe.session.user, )