From 338fff20db3499307f114b836ab8c3337a18da5a Mon Sep 17 00:00:00 2001 From: diptanilsaha Date: Thu, 16 Jul 2026 00:47:56 +0530 Subject: [PATCH 1/3] fix(assets): add permission checks on whitelisted methods on `asset_capitalization` (cherry picked from commit 09d721d1be80eca48edbc6ed52676febc329cc90) --- .../doctype/asset_capitalization/asset_capitalization.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index d234b162ba2..15128607e5b 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -734,6 +734,7 @@ def get_target_asset_details(asset=None, company=None): @frappe.whitelist() def get_consumed_stock_item_details(args): + frappe.has_permission("Stock Ledger Entry", throw=True) if isinstance(args, str): args = json.loads(args) @@ -743,6 +744,7 @@ def get_consumed_stock_item_details(args): item = frappe._dict() if args.item_code: item = frappe.get_cached_doc("Item", args.item_code) + item.check_permission() out.item_name = item.item_name out.batch_no = None @@ -752,6 +754,8 @@ def get_consumed_stock_item_details(args): out.stock_uom = item.stock_uom out.warehouse = get_item_warehouse(item, args, overwrite_warehouse=True) if item else None + if out.warehouse: + frappe.has_permission("Warehouse", doc=out.warehouse, throw=True) # Cost Center item_defaults = get_item_defaults(item.name, args.company) @@ -792,6 +796,9 @@ def get_warehouse_details(args): out = {} if args.warehouse and args.item_code: + frappe.has_permission("Item", doc=args.item_code, throw=True) + frappe.has_permission("Warehouse", doc=args.warehouse, throw=True) + frappe.has_permission("Stock Ledger Entry", throw=True) out = { "actual_qty": get_previous_sle(args).get("qty_after_transaction") or 0, "valuation_rate": get_incoming_rate(args, raise_error_if_no_rate=False), From 9cd5997500a3342dcbe0202b16394451c3f45b96 Mon Sep 17 00:00:00 2001 From: diptanilsaha Date: Wed, 15 Jul 2026 23:23:48 +0530 Subject: [PATCH 2/3] fix(item_variant): added permission checks on `enqueue_multiple_variant_creation` (cherry picked from commit 3b0cbc972eae6b1c062b42c03406406b3de687cd) --- erpnext/controllers/item_variant.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index a05ff7f3b7c..c801290049a 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -336,6 +336,7 @@ def create_variant(item, args, use_template_image=False): @frappe.whitelist() def enqueue_multiple_variant_creation(item, args, use_template_image=False): + frappe.has_permission("Item", ptype="create", throw=True) use_template_image = frappe.parse_json(use_template_image) # There can be innumerable attribute combinations, enqueue if isinstance(args, str): From c38c9d5d9b864dafedf84877c9fa0ec8381cd931 Mon Sep 17 00:00:00 2001 From: diptanilsaha Date: Thu, 16 Jul 2026 01:10:50 +0530 Subject: [PATCH 3/3] fix(payment_request): added permission checks on `resend_payment_email` (cherry picked from commit 0659bd704968543d95af0ba225c5e3aa4a29d987) --- .../payment_request/payment_request.js | 22 +++++++------- .../payment_request/payment_request.py | 29 +++++++++++++++---- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js index 5cca11ae2fd..93682430fcd 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.js +++ b/erpnext/accounts/doctype/payment_request/payment_request.js @@ -33,6 +33,8 @@ frappe.ui.form.on("Payment Request", "onload", function (frm, dt, dn) { }); frappe.ui.form.on("Payment Request", "refresh", function (frm) { + let sending_email = false; + if ( frm.doc.payment_request_type == "Inward" && frm.doc.payment_channel !== "Phone" && @@ -41,16 +43,16 @@ frappe.ui.form.on("Payment Request", "refresh", function (frm) { frm.doc.docstatus == 1 ) { frm.add_custom_button(__("Resend Payment Email"), function () { - frappe.call({ - method: "erpnext.accounts.doctype.payment_request.payment_request.resend_payment_email", - args: { docname: frm.doc.name }, - freeze: true, - freeze_message: __("Sending"), - callback: function (r) { - if (!r.exc) { - frappe.msgprint(__("Message Sent")); - } - }, + if (sending_email) { + frappe.show_alert({ message: __("Sending Email"), indicator: "blue" }); + return; + } + sending_email = true; + frappe.show_alert({ message: __("Sending Email"), indicator: "blue" }); + frm.call("resend_payment_email").then((r) => { + const msg = !r.exc ? __("Email Sent") : __("Email couldn't be sent."); + frappe.show_alert({ message: msg, indicator: !r.exc ? "green" : "red" }); + sending_email = false; }); }); } diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 01de1e34e21..f5dc2fb479e 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -411,6 +411,18 @@ class PaymentRequest(Document): return payment_entry + @frappe.whitelist(methods=["POST"]) + def resend_payment_email(self): + if not ( + self.docstatus == 1 + and self.payment_request_type == "Inward" + and self.payment_channel != "Phone" + and self.status not in ["Initiated", "Paid"] + ): + frappe.throw(_("Payment Link couldn't be sent.")) + + self.send_email() + def send_email(self): """send email with payment link""" email_args = { @@ -428,7 +440,17 @@ class PaymentRequest(Document): ) ], } - enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args) + job_id = f"send_payment_email::{self.name}" + enqueue( + method=frappe.sendmail, + queue="short", + timeout=300, + is_async=True, + job_id=job_id, + deduplicate=True, + enqueue_after_commit=True, + **email_args, + ) def get_message(self): """return message with payment gateway link""" @@ -827,11 +849,6 @@ def get_print_format_list(ref_doctype): return {"print_format": print_format_list} -@frappe.whitelist() -def resend_payment_email(docname): - return frappe.get_doc("Payment Request", docname).send_email() - - @frappe.whitelist() def make_payment_entry(docname): doc = frappe.get_doc("Payment Request", docname)