Merge pull request #57419 from kaulith/fix/update-items-row-removal-permission

fix: don't require cancel and delete perms to remove items via Update Items
This commit is contained in:
Mihir Kandoi
2026-07-29 16:42:26 +05:30
committed by GitHub
2 changed files with 46 additions and 0 deletions

View File

@@ -432,6 +432,7 @@ def validate_and_delete_children(parent, data, ordered_item=None) -> bool:
for d in deleted_children:
validate_child_on_delete(d, parent, ordered_item)
d.flags.ignore_permissions = True
d.cancel()
d.delete()

View File

@@ -691,6 +691,51 @@ class TestSalesOrder(ERPNextTestSuite):
frappe.ValidationError, update_child_qty_rate, "Sales Order", trans_item, so.name
)
def test_update_child_removing_item_without_cancel_and_delete_perms(self):
for workflow_name in frappe.get_all(
"Workflow", filters={"document_type": "Sales Order", "is_active": 1}, pluck="name"
):
workflow = frappe.get_doc("Workflow", workflow_name)
workflow.is_active = 0
workflow.save()
role = "_Test Sales Order Item Editor"
if not frappe.db.exists("Role", role):
frappe.get_doc({"doctype": "Role", "role_name": role, "desk_access": 1}).insert()
frappe.permissions.add_permission("Sales Order", role, 0)
for right, value in {
"read": 1,
"write": 1,
"create": 1,
"submit": 1,
"cancel": 0,
"delete": 0,
}.items():
frappe.permissions.update_permission_property("Sales Order", role, 0, right, value)
frappe.clear_cache()
so = make_sales_order(**{"item_list": [{"item_code": "_Test Item", "qty": 5, "rate": 1000}]})
trans_item = json.dumps(
[
{"item_code": "_Test Item", "qty": 5, "rate": 1000, "docname": so.items[0].name},
{"item_code": "_Test Item 2", "qty": 2, "rate": 500},
]
)
update_child_qty_rate("Sales Order", trans_item, so.name)
so.reload()
self.assertEqual(len(so.items), 2)
test_user = create_user("test_so_item_editor@example.com", role, "Accounts User", "Stock User")
trans_item = json.dumps(
[{"item_code": "_Test Item", "qty": 5, "rate": 1000, "docname": so.items[0].name}]
)
with self.set_user(test_user.name):
update_child_qty_rate("Sales Order", trans_item, so.name)
so.reload()
self.assertEqual(len(so.items), 1)
def test_update_child_qty_rate_with_workflow(self):
from frappe.model.workflow import apply_workflow