fix(file-format): auto-detect columns on sample upload, quiet alerts
Two changes that drop the manual step from the column-mapping setup: - Auto-detect now runs implicitly when the user attaches a Sample Excel File. The Auto-detect Columns Button field is removed (Preview Sample stays — it answers a different question). Auto-detect only fires when the Column Mappings table is empty; a user-edited table is never overwritten silently. - Replaced the modal "Auto-detect Complete" / "Sample File Error" / "Empty Header Row" msgprints with small bottom-right show_alert toasts. The result is one line — "Auto-mapped 9 of 11 columns" — with green/orange/red indicator instead of a full-screen dialog. The synonym dictionary used by detection lives in code at jey_erp/bank_integration/excel_parser.py (_HEADER_SYNONYMS).
This commit is contained in:
parent
54ac6288fd
commit
381aebdbdb
|
|
@ -124,7 +124,7 @@ frappe.ui.form.on('Bank Statement Importer', {
|
|||
},
|
||||
|
||||
sample_file(frm) {
|
||||
BIFileFormat.applySampleHeaders(frm);
|
||||
BIFileFormat.onSampleFileChange(frm);
|
||||
},
|
||||
|
||||
header_row(frm) {
|
||||
|
|
@ -134,10 +134,6 @@ frappe.ui.form.on('Bank Statement Importer', {
|
|||
preview_sample_btn(frm) {
|
||||
BIFileFormat.showPreview(frm);
|
||||
},
|
||||
|
||||
auto_detect_btn(frm) {
|
||||
BIFileFormat.autoDetect(frm);
|
||||
},
|
||||
});
|
||||
|
||||
// ─── File Format helpers ─────────────────────────────────────────────────────
|
||||
|
|
@ -172,11 +168,10 @@ const BIFileFormat = {
|
|||
},
|
||||
callback: (r) => {
|
||||
if (!r.message || !r.message.success) {
|
||||
frappe.msgprint({
|
||||
title: __('Sample File Error'),
|
||||
indicator: 'red',
|
||||
frappe.show_alert({
|
||||
message: (r.message && r.message.message) || __('Could not read sample file.'),
|
||||
});
|
||||
indicator: 'red',
|
||||
}, 5);
|
||||
return;
|
||||
}
|
||||
const headers = r.message.headers || [];
|
||||
|
|
@ -189,16 +184,21 @@ const BIFileFormat = {
|
|||
message: __("No headers found in row {0}. Adjust 'Header Row'.", [frm.doc.header_row || 1]),
|
||||
indicator: 'orange',
|
||||
}, 5);
|
||||
} else {
|
||||
frappe.show_alert({
|
||||
message: __('{0} column header(s) loaded.', [headers.length]),
|
||||
indicator: 'green',
|
||||
}, 3);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// Called when the user attaches / replaces the Sample Excel File. Refresh
|
||||
// the Excel Column dropdown and, if the table is still empty, run
|
||||
// auto-detect silently. We never overwrite a user-filled table.
|
||||
onSampleFileChange(frm) {
|
||||
this.applySampleHeaders(frm, /*force*/ true);
|
||||
const hasRows = (frm.doc.column_mappings || []).some(r => r.excel_column || r.standard_field);
|
||||
if (!frm.doc.sample_file || hasRows) return;
|
||||
this.autoDetect(frm, /*silent*/ true);
|
||||
},
|
||||
|
||||
setColumnOptions(frm, headers) {
|
||||
const grid = frm.fields_dict.column_mappings && frm.fields_dict.column_mappings.grid;
|
||||
if (!grid) return;
|
||||
|
|
@ -286,72 +286,48 @@ const BIFileFormat = {
|
|||
});
|
||||
},
|
||||
|
||||
autoDetect(frm) {
|
||||
if (!frm.doc.sample_file) {
|
||||
frappe.msgprint(__('Upload a Sample Excel File first.'));
|
||||
return;
|
||||
}
|
||||
const existing = (frm.doc.column_mappings || []).filter(r => r.excel_column || r.standard_field);
|
||||
const proceed = () => {
|
||||
frappe.call({
|
||||
method: 'jey_erp.bank_integration.excel_parser.auto_detect_column_mappings',
|
||||
args: {
|
||||
file_url: frm.doc.sample_file,
|
||||
header_row: frm.doc.header_row || 1,
|
||||
},
|
||||
callback: (r) => {
|
||||
if (!r.message || !r.message.success) {
|
||||
frappe.msgprint({
|
||||
title: __('Auto-detect Error'),
|
||||
indicator: 'red',
|
||||
message: (r.message && r.message.message) || __('Could not read sample file.'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const mappings = r.message.mappings || [];
|
||||
if (!mappings.length) {
|
||||
frappe.msgprint({
|
||||
title: __('No Headers Found'),
|
||||
indicator: 'orange',
|
||||
message: __("No headers found in row {0}. Adjust 'Header Row'.", [frm.doc.header_row || 1]),
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Replace the table contents in-place.
|
||||
frm.clear_table('column_mappings');
|
||||
mappings.forEach(m => {
|
||||
const row = frm.add_child('column_mappings');
|
||||
row.excel_column = m.excel_column;
|
||||
row.standard_field = m.standard_field || '';
|
||||
});
|
||||
frm.refresh_field('column_mappings');
|
||||
frm.dirty();
|
||||
autoDetect(frm, silent) {
|
||||
if (!frm.doc.sample_file) return;
|
||||
frappe.call({
|
||||
method: 'jey_erp.bank_integration.excel_parser.auto_detect_column_mappings',
|
||||
args: {
|
||||
file_url: frm.doc.sample_file,
|
||||
header_row: frm.doc.header_row || 1,
|
||||
},
|
||||
callback: (r) => {
|
||||
if (!r.message || !r.message.success) {
|
||||
frappe.show_alert({
|
||||
message: (r.message && r.message.message) || __('Could not read sample file.'),
|
||||
indicator: 'red',
|
||||
}, 5);
|
||||
return;
|
||||
}
|
||||
const mappings = r.message.mappings || [];
|
||||
if (!mappings.length) {
|
||||
frappe.show_alert({
|
||||
message: __("No headers found in row {0}. Adjust 'Header Row'.", [frm.doc.header_row || 1]),
|
||||
indicator: 'orange',
|
||||
}, 5);
|
||||
return;
|
||||
}
|
||||
frm.clear_table('column_mappings');
|
||||
mappings.forEach(m => {
|
||||
const row = frm.add_child('column_mappings');
|
||||
row.excel_column = m.excel_column;
|
||||
row.standard_field = m.standard_field || '';
|
||||
});
|
||||
frm.refresh_field('column_mappings');
|
||||
frm.dirty();
|
||||
|
||||
const matched = r.message.matched_count || 0;
|
||||
const total = r.message.total_headers || mappings.length;
|
||||
const unmatched = r.message.unmatched || [];
|
||||
let msg = __('Mapped {0} of {1} column(s).', [matched, total]);
|
||||
if (unmatched.length) {
|
||||
msg += '<br><br>' + __('Unmapped columns (set Standard Field manually if needed):') +
|
||||
'<br><code>' + unmatched.map(frappe.utils.escape_html).join(', ') + '</code>';
|
||||
}
|
||||
msg += '<br><br>' + __('Review the table, then <b>Save</b> the form to confirm.');
|
||||
frappe.msgprint({
|
||||
title: __('Auto-detect Complete'),
|
||||
indicator: matched === total ? 'green' : (matched > 0 ? 'orange' : 'red'),
|
||||
message: msg,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
if (existing.length) {
|
||||
frappe.confirm(
|
||||
__('This will replace the {0} existing Column Mapping row(s). Continue?', [existing.length]),
|
||||
proceed,
|
||||
);
|
||||
} else {
|
||||
proceed();
|
||||
}
|
||||
const matched = r.message.matched_count || 0;
|
||||
const total = r.message.total_headers || mappings.length;
|
||||
const indicator = matched === total ? 'green' : (matched > 0 ? 'orange' : 'red');
|
||||
frappe.show_alert({
|
||||
message: __('Auto-mapped {0} of {1} columns.', [matched, total]),
|
||||
indicator,
|
||||
}, silent ? 4 : 6);
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
"sample_file",
|
||||
"ff_sample_actions_section",
|
||||
"preview_sample_btn",
|
||||
"ff_sample_actions_col",
|
||||
"auto_detect_btn",
|
||||
"ff_format_section",
|
||||
"header_row",
|
||||
"amount_mode",
|
||||
|
|
@ -180,22 +178,11 @@
|
|||
},
|
||||
{
|
||||
"depends_on": "eval:doc.sample_file",
|
||||
"description": "Show the first 20 data rows from the sample file with mapping status per column.",
|
||||
"description": "Show the first 20 data rows from the sample file with mapping status per column. Column mappings are auto-detected when you attach a file — re-attach to re-run detection.",
|
||||
"fieldname": "preview_sample_btn",
|
||||
"fieldtype": "Button",
|
||||
"label": "Preview Sample"
|
||||
},
|
||||
{
|
||||
"fieldname": "ff_sample_actions_col",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.sample_file",
|
||||
"description": "Replace the Column Mappings table with a best-effort guess based on the sample file's headers.",
|
||||
"fieldname": "auto_detect_btn",
|
||||
"fieldtype": "Button",
|
||||
"label": "Auto-detect Columns"
|
||||
},
|
||||
{
|
||||
"fieldname": "ff_format_section",
|
||||
"fieldtype": "Section Break",
|
||||
|
|
|
|||
Loading…
Reference in New Issue