added bulk edit to kb settings

This commit is contained in:
Ali 2026-03-05 22:25:48 +04:00
parent 126c455217
commit 6779cf89ec
3 changed files with 233 additions and 8 deletions

View File

@ -146,6 +146,17 @@ frappe.ui.form.on('Kapital Bank Settings', {
} }
}, __('Purpose')); }, __('Purpose'));
// ── Bulk Edit buttons for mapping tables ─────────────────────────────
const mapping_tables = [
'account_mappings', 'card_mappings', 'customer_mappings',
'supplier_mappings', 'transaction_mappings'
];
mapping_tables.forEach(table => {
frm.fields_dict[table]?.grid.add_custom_button(__('Bulk Edit'), () => {
bulk_edit_table(frm, table);
});
});
// ── Populate data tabs ──────────────────────────────────────────────── // ── Populate data tabs ────────────────────────────────────────────────
load_data_tabs(frm); load_data_tabs(frm);
} }
@ -1029,6 +1040,198 @@ function render_purposes_list(purposes, total_count) {
}); });
} }
// ═══════════════════════════════════════════════════════════════════════════════
// BULK EDIT
// ═══════════════════════════════════════════════════════════════════════════════
function bulk_edit_table(frm, table_field) {
const selected_rows = frm.fields_dict[table_field].grid.get_selected_children();
if (selected_rows.length === 0) {
frappe.msgprint(__("No rows selected. Please select rows to edit."));
return;
}
const child_doctype = selected_rows[0].doctype;
const meta = frappe.get_meta(child_doctype);
const field_options = [];
const field_map = {};
meta.fields.forEach(df => {
if (!['Section Break', 'Column Break', 'Tab Break', 'HTML', 'Table', 'Button'].includes(df.fieldtype)
&& !df.read_only && !df.hidden) {
field_options.push({
label: __(df.label || frappe.model.unscrub(df.fieldname)),
value: df.fieldname
});
field_map[df.fieldname] = df;
}
});
const d = new frappe.ui.Dialog({
title: __("Bulk Edit Selected Rows"),
fields: [
{
label: __("Field to Edit"),
fieldname: "field_to_edit",
fieldtype: "Select",
options: field_options,
reqd: 1
},
{
fieldname: "value_section",
fieldtype: "Section Break",
label: __("New Value"),
collapsible: 0,
hidden: 1
},
{
fieldname: "value_container",
fieldtype: "HTML",
options: '<div id="value_field_container"></div>'
}
],
primary_action_label: __("Apply"),
primary_action() {
const field_name = d.get_value("field_to_edit");
const field_def = field_map[field_name];
if (!field_name || !d.new_value_field) {
frappe.msgprint(__("Please select a field and enter a value."));
return;
}
const new_value = d.new_value_field.get_value();
if (new_value === undefined || new_value === null || new_value === "") {
frappe.msgprint(__("Please enter a new value."));
return;
}
// For Dynamic Link, also set the type field
const is_dynamic = field_def && field_def.fieldtype === "Dynamic Link";
const type_field = is_dynamic ? field_def.options : null;
const type_value = is_dynamic && d.dynamic_link_type_field
? d.dynamic_link_type_field.get_value() : null;
if (is_dynamic && !type_value) {
frappe.msgprint(__("Please select a type."));
return;
}
let count = 0;
const promises = [];
selected_rows.forEach(row => {
if (is_dynamic && type_field) {
promises.push(
frappe.model.set_value(row.doctype, row.name, type_field, type_value)
);
}
promises.push(
frappe.model.set_value(row.doctype, row.name, field_name, new_value)
.then(() => { count++; })
);
});
Promise.all(promises).then(() => {
frm.refresh_field(table_field);
frappe.show_alert({
message: __("Updated {0} rows", [count]),
indicator: 'green'
}, 5);
d.hide();
});
}
});
function clear_value_controls() {
if (d.new_value_field) {
d.new_value_field.$wrapper.remove();
delete d.new_value_field;
}
if (d.dynamic_link_type_field) {
d.dynamic_link_type_field.$wrapper.remove();
delete d.dynamic_link_type_field;
}
}
function make_value_control(field_def, container) {
d.new_value_field = frappe.ui.form.make_control({
df: {
label: __("New Value for {0}", [__(field_def.label || frappe.model.unscrub(field_def.fieldname))]),
fieldname: "new_value",
fieldtype: field_def.fieldtype === "Dynamic Link" ? "Link" : field_def.fieldtype,
options: field_def.options || "",
reqd: 1
},
parent: container,
render_input: true
});
d.new_value_field.refresh();
}
d.fields_dict.field_to_edit.$input.on('change', function() {
const field_name = d.get_value("field_to_edit");
const field_def = field_map[field_name];
if (!field_def) return;
d.set_df_property("value_section", "hidden", 0);
clear_value_controls();
const value_container = d.fields_dict.value_container.$wrapper.find("#value_field_container");
if (field_def.fieldtype === "Dynamic Link") {
// Find the linked Select field (e.g. counterparty_type for counterparty)
const type_df = field_map[field_def.options];
if (type_df) {
d.dynamic_link_type_field = frappe.ui.form.make_control({
df: {
label: __(type_df.label || frappe.model.unscrub(type_df.fieldname)),
fieldname: "dynamic_link_type",
fieldtype: type_df.fieldtype,
options: type_df.options || "",
reqd: 1
},
parent: value_container,
render_input: true
});
d.dynamic_link_type_field.refresh();
d.dynamic_link_type_field.$input.on('change', () => {
const selected_type = d.dynamic_link_type_field.get_value();
if (d.new_value_field) {
d.new_value_field.$wrapper.remove();
delete d.new_value_field;
}
if (selected_type) {
d.new_value_field = frappe.ui.form.make_control({
df: {
label: __("New Value for {0}", [__(field_def.label || frappe.model.unscrub(field_def.fieldname))]),
fieldname: "new_value",
fieldtype: "Link",
options: selected_type,
reqd: 1
},
parent: value_container,
render_input: true
});
d.new_value_field.refresh();
}
});
} else {
make_value_control(field_def, value_container);
}
} else {
make_value_control(field_def, value_container);
}
});
d.show();
}
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════
// HELPERS // HELPERS
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════

View File

@ -1,6 +1,6 @@
{ {
"actions": [], "actions": [],
"creation": "2026-02-24 00:00:00.000000", "creation": "2026-02-24 00:00:00",
"doctype": "DocType", "doctype": "DocType",
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
@ -219,8 +219,7 @@
}, },
{ {
"fieldname": "data_tab_html", "fieldname": "data_tab_html",
"fieldtype": "HTML", "fieldtype": "HTML"
"options": ""
}, },
{ {
"fieldname": "mappings_tab", "fieldname": "mappings_tab",
@ -229,8 +228,7 @@
}, },
{ {
"fieldname": "mappings_tab_html", "fieldname": "mappings_tab_html",
"fieldtype": "HTML", "fieldtype": "HTML"
"options": ""
}, },
{ {
"fieldname": "account_mappings_tab", "fieldname": "account_mappings_tab",
@ -244,6 +242,7 @@
"label": "Account Mappings" "label": "Account Mappings"
}, },
{ {
"allow_bulk_edit": 1,
"fieldname": "account_mappings", "fieldname": "account_mappings",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Account Mappings", "label": "Account Mappings",
@ -261,6 +260,7 @@
"label": "Card Mappings" "label": "Card Mappings"
}, },
{ {
"allow_bulk_edit": 1,
"fieldname": "card_mappings", "fieldname": "card_mappings",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Card Mappings", "label": "Card Mappings",
@ -278,6 +278,7 @@
"label": "Customer Mappings" "label": "Customer Mappings"
}, },
{ {
"allow_bulk_edit": 1,
"fieldname": "customer_mappings", "fieldname": "customer_mappings",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Customer Mappings", "label": "Customer Mappings",
@ -295,6 +296,7 @@
"label": "Supplier Mappings" "label": "Supplier Mappings"
}, },
{ {
"allow_bulk_edit": 1,
"fieldname": "supplier_mappings", "fieldname": "supplier_mappings",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Supplier Mappings", "label": "Supplier Mappings",
@ -321,7 +323,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2026-02-27 00:00:00.000000", "modified": "2026-03-05 22:08:29.828228",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Kapital Bank", "module": "Kapital Bank",
"name": "Kapital Bank Settings", "name": "Kapital Bank Settings",
@ -331,10 +333,8 @@
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1,
"role": "System Manager", "role": "System Manager",
"share": 1, "share": 1,
"write": 1 "write": 1

View File

@ -0,0 +1,22 @@
# Copyright (c) 2026, Jey ERP and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class IntegrationTestKapitalBankSettings(IntegrationTestCase):
"""
Integration tests for KapitalBankSettings.
Use this class for testing interactions between multiple components.
"""
pass