feat(bank-statement-importer): adaptive workflow guide above tabs

Users had no way to know the setup is ordered — they would land on
Match/Create buttons before the registries had anything to match, or
go to Load Data before configuring the file format.

A small four-step indicator now sits at the top of the form, with the
current step highlighted and a one-line hint pointing at the next
action. State is read off the form itself (column_mappings filled? any
mapping tables populated?), so the guide moves forward as the user
makes progress and disappears once setup is done as much as the form
can tell.

The four steps:
  1. Configure format    → File Format tab + sample file
  2. Load registries     → Load Data button
  3. Match & Create      → Data tab + Match/Create toolbar buttons
  4. Import statements   → Bank Transaction list → Import From
This commit is contained in:
Ali 2026-05-18 13:20:57 +00:00
parent a27e9b08f5
commit 83a2cb6259
1 changed files with 73 additions and 0 deletions

View File

@ -17,6 +17,7 @@ frappe.ui.form.on('Bank Statement Importer', {
refresh(frm) {
BIFileFormat.applySampleHeaders(frm);
_bi_render_workflow_guide(frm);
if (frm.is_new()) return;
@ -490,6 +491,78 @@ function _show_load_data_dialog(frm) {
// DATA TAB — registry overviews (Accounts / Customers / Suppliers / Purposes)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// WORKFLOW GUIDE — adaptive 4-step banner above the tabs.
// Highlights the next action based on the form's current state so users don't
// have to memorise the sequence (Setup → Load Data → Match/Create → Use).
// ═══════════════════════════════════════════════════════════════════════════════
function _bi_render_workflow_guide(frm) {
if (frm.is_new()) {
frm.set_intro(
__('Fill in Bank Name and Save to begin setup. Then configure the File Format tab.'),
'blue'
);
return;
}
const hasFormat = (frm.doc.column_mappings || []).some(r => r.excel_column && r.standard_field);
const hasAccountMappings = (frm.doc.account_mappings || []).length > 0;
const hasCustomerMappings = (frm.doc.customer_mappings || []).length > 0;
const hasSupplierMappings = (frm.doc.supplier_mappings || []).length > 0;
const hasAnyMapping = hasAccountMappings || hasCustomerMappings || hasSupplierMappings;
const step = (n, label, active) => {
const color = active ? 'var(--primary)' : 'var(--text-muted)';
const weight = active ? '600' : '400';
const bg = active ? 'var(--alert-bg-blue, #e7f1ff)' : 'transparent';
return `<span style="
display:inline-flex; align-items:center; gap:6px;
padding:2px 10px; border-radius:12px;
background:${bg}; color:${color}; font-weight:${weight};
font-size:12px;">
<span style="
display:inline-flex; align-items:center; justify-content:center;
width:18px; height:18px; border-radius:50%;
background:${active ? 'var(--primary)' : 'var(--gray-300)'};
color:#fff; font-size:11px; font-weight:600;">${n}</span>
${frappe.utils.escape_html(label)}
</span>`;
};
let current, hint, color;
if (!hasFormat) {
current = 1;
hint = __("Open the <b>File Format</b> tab. Upload a sample statement — auto-detect fills the column mappings.");
color = 'orange';
} else if (!hasAnyMapping) {
current = 2;
hint = __("Click <b>Load Data</b> (top-right) to register counterparties and purposes from a real statement.");
color = 'orange';
} else {
// Heuristic: once any mapping table has rows, users still need to link
// each registry entry to an ERP record. We can't cheaply count registry
// rows here without an extra call, so we just point at the Data tab.
current = 3;
hint = __("Open the <b>Data</b> tab. Use the <b>Match</b> / <b>Create</b> buttons (top-right) to link each registry entry to an ERPNext record. When done, import statements via Bank Transaction list → Import From.");
color = 'blue';
}
const stepper =
'<div style="display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-bottom:8px;">' +
step(1, __('Configure format'), current === 1) +
'<span style="color:var(--gray-400);"></span>' +
step(2, __('Load registries'), current === 2) +
'<span style="color:var(--gray-400);"></span>' +
step(3, __('Match & Create'), current === 3) +
'<span style="color:var(--gray-400);"></span>' +
step(4, __('Import statements'), false) +
'</div>' +
`<div style="font-size:13px; color:var(--text-muted);">${hint}</div>`;
frm.set_intro(stepper, color);
}
function _bi_load_data_tabs(frm) {
const name = frm.doc.name;
_bi_load_tab(name, 'accounts', 'bi-accounts-container', _bi_render_accounts);