From bdf32afa2d7b4e961b30c59e7d45ba24ce85fd8c Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Wed, 10 Jun 2026 17:52:03 +0000 Subject: [PATCH] refactor(kapital-bank): move client JS into bundle; update settings, mappings, hooks, az locale Co-Authored-By: Claude Opus 4.8 (1M context) --- kapital_bank/hooks.py | 10 +- .../kapital_bank_customer_mapping.json | 4 +- .../kapital_bank_settings.js | 240 ++++++++++++++++++ .../kapital_bank_settings.py | 101 ++++++-- .../kapital_bank_supplier_mapping.json | 4 +- kapital_bank/locale/az.po | 115 ++++----- .../js/kapital_bank_import.bundle.js} | 47 ++-- 7 files changed, 429 insertions(+), 92 deletions(-) rename kapital_bank/{client/bank_transaction.js => public/js/kapital_bank_import.bundle.js} (92%) diff --git a/kapital_bank/hooks.py b/kapital_bank/hooks.py index 0302511..76f6676 100644 --- a/kapital_bank/hooks.py +++ b/kapital_bank/hooks.py @@ -15,15 +15,21 @@ after_migrate = "kapital_bank.setup.after_migrate" # mapping-source select) lives in jey_erp/public/js/bank_reconciliation_tool.js # and works with both Kapital Bank Settings and Bank Integration mappings via # the universal resolver in jey_erp/bank_integration/mapping_resolver.py. +# Kapital Bank importer (KBBTImport) + its registration into jey_erp's shared +# "Import From..." bank-import menu. Loaded globally so it is available wherever +# the menu appears (Bank Transaction / Payment Entry lists, Bank Reconciliation +# Tool) — not only on the Bank Transaction doctype. +app_include_js = [ + "kapital_bank_import.bundle.js", +] + doctype_js = { "Payment Entry": "client/payment_entry.js", - "Bank Transaction": "client/bank_transaction.js", "Payment Request": "client/payment_request.js", } doctype_list_js = { "Payment Entry": "client/payment_entry.js", - "Bank Transaction": "client/bank_transaction.js", "Kapital Bank Bank Code": "client/kapital_bank_bank_code.js", } diff --git a/kapital_bank/kapital_bank/doctype/kapital_bank_customer_mapping/kapital_bank_customer_mapping.json b/kapital_bank/kapital_bank/doctype/kapital_bank_customer_mapping/kapital_bank_customer_mapping.json index a7efbea..f5c3d66 100644 --- a/kapital_bank/kapital_bank/doctype/kapital_bank_customer_mapping/kapital_bank_customer_mapping.json +++ b/kapital_bank/kapital_bank/doctype/kapital_bank_customer_mapping/kapital_bank_customer_mapping.json @@ -24,10 +24,12 @@ "reqd": 1 }, { + "fetch_from": "kb_customer_name.tax_id", "fieldname": "tax_id", "fieldtype": "Data", "in_list_view": 1, - "label": "Tax ID" + "label": "Tax ID", + "read_only": 1 }, { "fieldname": "erp_customer", diff --git a/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js b/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js index 98e751a..d9ed018 100644 --- a/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js +++ b/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js @@ -184,6 +184,9 @@ frappe.ui.form.on('Kapital Bank Settings', { }); }); + // ── Workflow wizard (current step + expandable step list) ───────────── + _kb_render_form_wizard(frm); + // ── Populate data tabs ──────────────────────────────────────────────── load_data_tabs(frm); } @@ -1295,3 +1298,240 @@ function list_header(label, total_count, refresh_id) { `; } + +// ═══════════════════════════════════════════════════════════════════════════════ +// WORKFLOW WIZARD — compact bar at the top of the Kapital Bank Settings form. +// Mirrors the Bank Integration Profile wizard, adapted to KB's API-driven flow: +// connect → fetch from the bank → map accounts/cards & counterparties → rules → +// import → reconcile. Shows the CURRENT step; clicking expands the full list. +// ═══════════════════════════════════════════════════════════════════════════════ + +function _kb_inject_wizard_styles() { + if (document.getElementById('kb-wizard-styles')) return; + const css = ` + .kb-wizard { margin: 0 0 12px; border: 1px solid var(--border-color, #e2e6e9); + border-radius: 8px; background: var(--card-bg, #fff); overflow: hidden; } + .kb-wizard-bar { display: flex; align-items: center; gap: 9px; padding: 9px 12px; + cursor: pointer; user-select: none; } + .kb-wizard-bar:hover { background: var(--bg-light-gray, #f4f5f6); } + .kb-wizard-dot { width: 9px; height: 9px; border-radius: 50%; + background: var(--blue-500, #2490ef); flex: 0 0 auto; } + .kb-wizard-cur { flex: 1 1 auto; } + .kb-wizard-cur b { margin-right: 4px; } + .kb-wizard-toggle { font-size: 12px; color: var(--text-muted); white-space: nowrap; + display: inline-flex; align-items: center; gap: 4px; } + .kb-wizard-chev { display: inline-block; + transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1); } + .kb-wizard.open .kb-wizard-chev { transform: rotate(180deg); } + .kb-wizard-list { max-height: 0; overflow: hidden; + padding: 0 6px; border-top: 0 solid var(--border-color, #eef0f2); + transition: max-height 0.45s ease-in-out, padding 0.45s ease-in-out, + border-width 0.45s ease-in-out; } + .kb-wizard.open .kb-wizard-list { max-height: 640px; padding: 6px; + border-top-width: 1px; } + .kb-wizard-step { display: flex; align-items: flex-start; gap: 10px; + padding: 8px; border-radius: 6px; } + .kb-wizard-step-main { display: flex; align-items: flex-start; gap: 10px; + flex: 1 1 auto; cursor: pointer; min-width: 0; } + .kb-wizard-step:hover { background: var(--bg-light-gray, #f4f5f6); } + .kb-wizard-step.cur { background: var(--highlight-color, #f0f4ff); } + .kb-wizard-step.done { opacity: 0.65; } + .kb-wizard-step.skipped { opacity: 0.5; } + .kb-wizard-badge { flex: 0 0 22px; width: 22px; height: 22px; border-radius: 50%; + display: inline-flex; align-items: center; justify-content: center; + font-weight: 600; font-size: 12px; margin-top: 1px; + background: var(--control-bg, #f4f5f6); } + .kb-wizard-step.done .kb-wizard-badge { background: var(--green-100, #d4f3e0); + color: var(--green-600, #1f9d55); } + .kb-wizard-step.cur .kb-wizard-badge { background: var(--blue-500, #2490ef); + color: #fff; } + .kb-wizard-step-title { font-weight: 600; } + .kb-wizard-step-hint { font-size: 12px; color: var(--text-muted); margin-top: 2px; } + .kb-wizard-tag { font-size: 11px; font-weight: 600; margin-left: 6px; } + .kb-wizard-tag.cur { color: var(--blue-600, #1373cc); } + .kb-wizard-tag.skip { color: var(--text-muted); } + .kb-wizard-skip { flex: 0 0 auto; font-size: 11px; color: var(--text-muted); + cursor: pointer; white-space: nowrap; padding: 2px 4px; align-self: center; } + .kb-wizard-skip:hover { color: var(--text-color, #1f272e); text-decoration: underline; }`; + const style = document.createElement('style'); + style.id = 'kb-wizard-styles'; + style.textContent = css; + document.head.appendChild(style); +} + +// Skip state is per-user (localStorage). Single doctype, so a fixed key. +function _kb_skip_key() { return 'kb_wizard_skipped::Kapital Bank Settings'; } +function _kb_get_skipped() { + try { return JSON.parse(localStorage.getItem(_kb_skip_key()) || '[]'); } + catch (e) { return []; } +} +function _kb_set_skipped(arr) { + try { localStorage.setItem(_kb_skip_key(), JSON.stringify(arr)); } catch (e) { /* ignore */ } +} + +// Focus a field that may live inside a custom_subtabs subtab. scroll_to_field only +// activates the parent tab and leaves the subtab content hidden, so for subtab +// fields we click the subtab button (its handler reveals the content). +function _kb_focus_field(frm, fieldname) { + const wrapper = (frm.layout && frm.layout.wrapper) || frm.$wrapper; + const field = frm.get_field(fieldname); + const $pane = field && field.$wrapper ? field.$wrapper.closest('.tab-pane') : $(); + const paneId = $pane.attr('id'); + if (paneId) { + const $btn = wrapper.find( + `.sub-tab button.nav-link[data-target-id="${paneId}"], ` + + `.sub-tab a.nav-link[data-target-id="${paneId}"]` + ); + if ($btn.length) { + $btn.first().trigger('click'); + setTimeout(() => { + if (field.$wrapper && field.$wrapper[0]) { + field.$wrapper[0].scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + }, 80); + return; + } + } + frm.scroll_to_field(fieldname); +} + +function _kb_render_form_wizard(frm, keepOpen) { + frappe.call({ + method: 'kapital_bank.bank_api.get_kb_reference_data_summary', + callback(r) { + const s = (r.message && r.message.summary) || {}; + const g = (k) => s[k] || { total: 0, mapped: 0 }; + const acc = g('accounts'), card = g('cards'); + const cust = g('customers'), sup = g('suppliers'), pur = g('purposes'); + + const registryTotal = acc.total + card.total + cust.total + sup.total + pur.total; + const acctCardTotal = acc.total + card.total; + const acctCardMapped = acc.mapped + card.mapped; + const partyTotal = cust.total + sup.total; + const partyMapped = cust.mapped + sup.mapped; + + const hasLogin = !!frm.doc.default_login; + const hasData = registryTotal > 0; + const acctCardDone = acctCardTotal > 0 && acctCardMapped === acctCardTotal; + const partyDone = partyTotal > 0 && partyMapped === partyTotal; + const hasTxnRules = (frm.doc.transaction_mappings || []).length > 0; + + const skipped = _kb_get_skipped(); + + // Steps 6-7 live on other doctypes — always navigation, not skippable. + const steps = [ + { + key: 'connect', done: hasLogin, + title: __('Connect Kapital Bank'), + hint: __('Set the default login and company defaults used to reach the bank API.'), + action: () => _kb_focus_field(frm, 'default_login'), + }, + { + key: 'load', done: hasData, + title: __('Load data from the bank'), + hint: __('Fetch accounts, cards, counterparties and purposes from the Kapital Bank API.'), + action: () => show_load_data_dialog(frm), + }, + { + key: 'mapacc', done: acctCardDone, + title: __('Map accounts & cards'), + hint: __('Link Kapital Bank accounts and cards to ERP Bank Accounts (Accounts / Cards menus above).'), + action: () => _kb_focus_field(frm, 'account_mappings'), + }, + { + key: 'mapparty', done: partyDone, + title: __('Map counterparties'), + hint: __('Match or create customers and suppliers (Customers / Suppliers menus above).'), + action: () => _kb_focus_field(frm, 'customer_mappings'), + }, + { + key: 'rules', done: hasTxnRules, + title: __('Configure transaction rules'), + hint: __('Define how purposes map to Payment Entries / Journal Entries.'), + action: () => _kb_focus_field(frm, 'transaction_mappings'), + }, + { + key: 'import', off: true, + title: __('Import transactions'), + hint: __('In the Bank Transaction list: Bank Integrations → Import Bank Statement.'), + action: () => frappe.set_route('List', 'Bank Transaction'), + }, + { + key: 'reconcile', off: true, + title: __('Create documents & reconcile'), + hint: __('In the Bank Reconciliation Tool: pick the account and Create & Reconcile.'), + action: () => frappe.set_route('Form', 'Bank Reconciliation Tool'), + }, + ]; + steps.forEach((st) => { st.skipped = !st.off && skipped.indexOf(st.key) !== -1; }); + + let currentIdx = steps.findIndex((st) => !st.off && !st.done && !st.skipped); + if (currentIdx === -1) currentIdx = 5; // all on-form steps done/skipped → "Import" + const cur = steps[currentIdx]; + + const esc = frappe.utils.escape_html; + const rows = steps.map((st, i) => { + const isCur = i === currentIdx; + let badge, cls, tag; + if (st.skipped) { + badge = '–'; cls = 'skipped'; + tag = ` ${__('Skipped')}`; + } else if (st.done) { + badge = '✓'; cls = 'done'; tag = ''; + } else if (isCur) { + badge = '➜'; cls = 'cur'; + tag = ` ${__('Current step')}`; + } else { + badge = (i + 1); cls = 'todo'; tag = ''; + } + + const skipCtl = st.off ? '' : + `${ + st.skipped ? __('Unskip') : __('Skip')}`; + + return ` +
+
+ ${badge} +
+
${esc(st.title)}${tag}
+
${esc(st.hint)}
+
+
+ ${skipCtl} +
`; + }).join(''); + + const html = ` +
+
+ + ${__('Kapital Bank')} · ${esc(cur.title)} + ${__('Steps')} +
+
${rows}
+
`; + + _kb_inject_wizard_styles(); + + const $host = frm.$wrapper.find('.form-layout').first(); + frm.$wrapper.find('.kb-wizard').remove(); + const $w = $(html); + $host.prepend($w); + + $w.find('.kb-wizard-bar').on('click', () => $w.toggleClass('open')); + $w.find('.kb-wizard-step-main').on('click', function () { + steps[$(this).data('kb-step')].action(); + }); + $w.find('.kb-wizard-skip').on('click', function (e) { + e.stopPropagation(); + const key = $(this).data('kb-skip'); + const set = _kb_get_skipped(); + const idx = set.indexOf(key); + if (idx === -1) set.push(key); else set.splice(idx, 1); + _kb_set_skipped(set); + _kb_render_form_wizard(frm, /* keepOpen */ true); + }); + }, + }); +} diff --git a/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.py b/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.py index e6a3c4b..18b1443 100644 --- a/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.py +++ b/kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.py @@ -4,22 +4,37 @@ from frappe.model.document import Document class KapitalBankSettings(Document): def on_update(self): + # Keep the registry records in sync with the mapping child tables, both ways: + # * a row with a linked target (Bank Account / ERP party) -> registry + # record becomes Mapped (and inherits its attributes); + # * removing a row OR clearing that link flips the record back to New. self._sync_account_statuses() self._sync_customer_statuses() self._sync_supplier_statuses() self._sync_card_statuses() def _sync_account_statuses(self): - """Reset Kapital Bank Account status to 'New' when its mapping row is removed - from account_mappings, or when the row's Bank Account link is cleared.""" - mapped_ibans = {row.iban for row in self.account_mappings if row.iban and row.bank_account} + """Kapital Bank Account becomes Mapped when its mapping row links a Bank + Account, and reverts to New when the row is removed or the link cleared.""" + mapped_ibans = set() + for row in self.account_mappings: + if not (row.iban and row.bank_account): + continue + mapped_ibans.add(row.iban) + current = frappe.db.get_value( + "Kapital Bank Account", row.iban, ["status", "bank_account"], as_dict=True + ) + if not current: + continue + desired = {"status": "Mapped", "bank_account": row.bank_account} + if any(current.get(k) != v for k, v in desired.items()): + frappe.db.set_value("Kapital Bank Account", row.iban, desired, update_modified=False) orphaned = frappe.get_all( "Kapital Bank Account", filters={"status": "Mapped"}, fields=["name"], ) - for account in orphaned: if account.name not in mapped_ibans: frappe.db.set_value( @@ -33,16 +48,37 @@ class KapitalBankSettings(Document): ) def _sync_customer_statuses(self): - """Reset Kapital Bank Customer status to 'New' when its mapping row is removed - from customer_mappings, or when the row's ERP Customer link is cleared.""" - mapped_names = {row.kb_customer_name for row in self.customer_mappings if row.kb_customer_name and row.erp_customer} + """Kapital Bank Customer becomes Mapped when its mapping row links an ERP + Customer, and reverts to New when the row is removed or the link cleared.""" + mapped_names = set() + for row in self.customer_mappings: + if not (row.kb_customer_name and row.erp_customer): + continue + mapped_names.add(row.kb_customer_name) + current = frappe.db.get_value( + "Kapital Bank Customer", row.kb_customer_name, + ["status", "mapped_customer", "customer_group", "territory", "payment_terms"], + as_dict=True, + ) + if not current: + continue + desired = { + "status": "Mapped", + "mapped_customer": row.erp_customer, + "customer_group": row.customer_group or None, + "territory": row.territory or None, + "payment_terms": row.payment_terms or None, + } + if any(current.get(k) != v for k, v in desired.items()): + frappe.db.set_value( + "Kapital Bank Customer", row.kb_customer_name, desired, update_modified=False + ) orphaned = frappe.get_all( "Kapital Bank Customer", filters={"status": "Mapped"}, fields=["name", "customer_name"], ) - for customer in orphaned: if customer.name not in mapped_names: frappe.db.set_value( @@ -59,16 +95,36 @@ class KapitalBankSettings(Document): ) def _sync_supplier_statuses(self): - """Reset Kapital Bank Supplier status to 'New' when its mapping row is removed - from supplier_mappings, or when the row's ERP Supplier link is cleared.""" - mapped_names = {row.kb_supplier_name for row in self.supplier_mappings if row.kb_supplier_name and row.erp_supplier} + """Kapital Bank Supplier becomes Mapped when its mapping row links an ERP + Supplier, and reverts to New when the row is removed or the link cleared.""" + mapped_names = set() + for row in self.supplier_mappings: + if not (row.kb_supplier_name and row.erp_supplier): + continue + mapped_names.add(row.kb_supplier_name) + current = frappe.db.get_value( + "Kapital Bank Supplier", row.kb_supplier_name, + ["status", "mapped_supplier", "supplier_group", "payment_terms"], + as_dict=True, + ) + if not current: + continue + desired = { + "status": "Mapped", + "mapped_supplier": row.erp_supplier, + "supplier_group": row.supplier_group or None, + "payment_terms": row.payment_terms or None, + } + if any(current.get(k) != v for k, v in desired.items()): + frappe.db.set_value( + "Kapital Bank Supplier", row.kb_supplier_name, desired, update_modified=False + ) orphaned = frappe.get_all( "Kapital Bank Supplier", filters={"status": "Mapped"}, fields=["name", "supplier_name"], ) - for supplier in orphaned: if supplier.name not in mapped_names: frappe.db.set_value( @@ -84,16 +140,29 @@ class KapitalBankSettings(Document): ) def _sync_card_statuses(self): - """Reset Kapital Bank Card status to 'New' when its mapping row is removed - from card_mappings, or when the row's Bank Account link is cleared.""" - mapped_accounts = {row.account_number for row in self.card_mappings if row.account_number and row.bank_account} + """Kapital Bank Card becomes Mapped when its mapping row links a Bank + Account, and reverts to New when the row is removed or the link cleared.""" + mapped_accounts = set() + for row in self.card_mappings: + if not (row.account_number and row.bank_account): + continue + mapped_accounts.add(row.account_number) + current = frappe.db.get_value( + "Kapital Bank Card", row.account_number, ["status", "bank_account"], as_dict=True + ) + if not current: + continue + desired = {"status": "Mapped", "bank_account": row.bank_account} + if any(current.get(k) != v for k, v in desired.items()): + frappe.db.set_value( + "Kapital Bank Card", row.account_number, desired, update_modified=False + ) orphaned = frappe.get_all( "Kapital Bank Card", filters={"status": "Mapped"}, fields=["name", "account_number"], ) - for card in orphaned: if card.name not in mapped_accounts: frappe.db.set_value( diff --git a/kapital_bank/kapital_bank/doctype/kapital_bank_supplier_mapping/kapital_bank_supplier_mapping.json b/kapital_bank/kapital_bank/doctype/kapital_bank_supplier_mapping/kapital_bank_supplier_mapping.json index d3c0408..746062d 100644 --- a/kapital_bank/kapital_bank/doctype/kapital_bank_supplier_mapping/kapital_bank_supplier_mapping.json +++ b/kapital_bank/kapital_bank/doctype/kapital_bank_supplier_mapping/kapital_bank_supplier_mapping.json @@ -23,10 +23,12 @@ "reqd": 1 }, { + "fetch_from": "kb_supplier_name.tax_id", "fieldname": "tax_id", "fieldtype": "Data", "in_list_view": 1, - "label": "Tax ID" + "label": "Tax ID", + "read_only": 1 }, { "fieldname": "erp_supplier", diff --git a/kapital_bank/locale/az.po b/kapital_bank/locale/az.po index 7fe261d..8113b05 100644 --- a/kapital_bank/locale/az.po +++ b/kapital_bank/locale/az.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: Kapital Bank VERSION\n" "Report-Msgid-Bugs-To: info@jeyerp.az\n" "POT-Creation-Date: 2026-04-24 19:34+0000\n" -"PO-Revision-Date: 2026-04-24 19:37+0000\n" +"PO-Revision-Date: 2026-05-24 23:53+0000\n" "Last-Translator: \n" "Language-Team: Azerbaijani\n" "Language: az\n" @@ -17,6 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Generated-By: Babel 2.16.0\n" +"X-Generator: Poedit 3.4.2\n" #. AI-generated #: kapital_bank/client/bank_transaction.js:206 @@ -65,8 +66,8 @@ msgid "" "Bank" msgstr "" "
Kapital Bank-dan kartları əldə etmək üçün \"Məlumatı" -" Yüklə\" düyməsinə klikləyin
" +"style=\"padding:20px;\">Kapital Bank-dan kartları əldə etmək üçün " +"\"Məlumatı Yüklə\" düyməsinə klikləyin" #. Content of the 'Customers List' (HTML) field in DocType 'Kapital Bank #. Settings' @@ -109,8 +110,8 @@ msgid "" "irreversible. Are you sure?

" msgstr "" "
XƏBƏRDARLIQ! Bu, bütün " -"uyğunlaşdırılmamış hesablar üçün yeni Bank Hesabı qeydləri " -"yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" +"uyğunlaşdırılmamış hesablar üçün yeni Bank Hesabı qeydləri yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:314 @@ -120,8 +121,8 @@ msgid "" "irreversible. Are you sure?

" msgstr "" "
XƏBƏRDARLIQ! Bu, bütün " -"uyğunlaşdırılmamış kartlar üçün yeni Bank Hesabı qeydləri " -"yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" +"uyğunlaşdırılmamış kartlar üçün yeni Bank Hesabı qeydləri yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:693 @@ -131,8 +132,8 @@ msgid "" "irreversible. Are you sure?

" msgstr "" "
XƏBƏRDARLIQ! Bu, bütün " -"uyğunlaşdırılmamış müştərilər üçün yeni Müştəri qeydləri " -"yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" +"uyğunlaşdırılmamış müştərilər üçün yeni Müştəri qeydləri yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:725 @@ -142,8 +143,8 @@ msgid "" "irreversible. Are you sure?

" msgstr "" "
XƏBƏRDARLIQ! Bu, bütün " -"uyğunlaşdırılmamış təchizatçılar üçün yeni Təchizatçı qeydləri " -"yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" +"uyğunlaşdırılmamış təchizatçılar üçün yeni Təchizatçı qeydləri yaradacaq!

Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?

" #. Option for the 'Source Type' (Select) field in DocType 'Kapital Bank #. Transaction' @@ -291,7 +292,7 @@ msgstr "{0} hesab uyğunlaşdırmaya əlavə edildi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:589 msgid "Added {0} cards to mapping" -msgstr "Eşləşdirməyə {0} kart əlavə edildi" +msgstr "Uyğunlaşdırma {0} kart əlavə edildi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:617 @@ -301,7 +302,7 @@ msgstr "Xəritələməyə {0} müştəri əlavə edildi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:684 msgid "Added {0} rows to mapping ({1} purposes)" -msgstr "Eşləməyə {0} sətir əlavə edildi ({1} məqsəd)" +msgstr "Uyğunlaşdırmaya {0} sətir əlavə edildi ({1} təyinat üzrə)" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:645 @@ -369,13 +370,13 @@ msgstr "Çıxış etmək istədiyinizə əminsiniz?" #: kapital_bank/kapital_bank/doctype/kapital_bank_api_test/kapital_bank_api_test.js:7 #: kapital_bank/kapital_bank/doctype/kapital_bank_api_test/kapital_bank_api_test.js:8 msgid "Auth" -msgstr "Auth" +msgstr "Təsdiq" #. Label of the auth_status (Select) field in DocType 'Kapital Bank Login' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_login/kapital_bank_login.json msgid "Auth Status" -msgstr "Autentifikasiya Statusu" +msgstr "Təsdiq Statusu" #. Option for the 'Auth Status' (Select) field in DocType 'Kapital Bank Login' #. AI-generated @@ -388,7 +389,7 @@ msgstr "Təsdiqlənib" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_login/kapital_bank_login.json msgid "Authentication" -msgstr "Autentifikasiya" +msgstr "Təsdiqlənmə" #. Option for the 'Mapping Type' (Select) field in DocType 'Kapital Bank #. Customer Mapping' @@ -465,7 +466,7 @@ msgstr "Bank köçürməsi uğurla ləğv edildi." #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_payment/kapital_bank_payment.json msgid "Beneficiary Bank Code" -msgstr "Benefisiar Bank Kodu" +msgstr "Vəsaiti Alan Bankın Kodu" #. Option for the 'Direction' (Select) field in DocType 'Kapital Bank Purpose' #. AI-generated @@ -619,9 +620,9 @@ msgstr "" #: kapital_bank/client/bank_transaction.js:535 #: kapital_bank/client/payment_entry.js:493 msgid "" -"Card transactions may already be imported from other accounts. The bank uses" -" different reference numbers for card and account statements, so duplicates " -"cannot be detected automatically." +"Card transactions may already be imported from other accounts. The bank " +"uses different reference numbers for card and account statements, so " +"duplicates cannot be detected automatically." msgstr "" "Kart əməliyyatları artıq digər hesablardan idxal edilmiş ola bilər. Bank " "kart və hesab çıxarışları üçün fərqli istinad nömrələrindən istifadə edir, " @@ -733,8 +734,8 @@ msgid "" "Consider replacement of Azerbaijani letters with Latin equivalents when " "matching" msgstr "" -"Uyğunlaşdırarkən Azərbaycan hərflərinin Latın qarşılıqları ilə əvəzlənməsini" -" nəzərə alın" +"Uyğunlaşdırarkən Azərbaycan hərflərinin Latın qarşılıqları ilə " +"əvəzlənməsini nəzərə alın" #. Label of the cost_center (Link) field in DocType 'Kapital Bank Transaction #. Mapping' @@ -800,17 +801,17 @@ msgstr "Kartlar üçün Bank Hesabları yaradın" #. AI-generated #: kapital_bank/client/mapping.js:141 msgid "Create Mappings" -msgstr "Xəritələmələr Yarat" +msgstr "Uyğunlaşdırmalar Yaradın" #. AI-generated #: kapital_bank/client/mapping.js:8 msgid "Create Purpose Mapping" -msgstr "Məqsəd Uyğunlaşdırması Yarat" +msgstr "Təyinat Uyğunlaşdırması Yarat" #. AI-generated #: kapital_bank/client/mapping.js:116 msgid "Create Purpose Mappings" -msgstr "Məqsəd Uyğunluqlarını Yarat" +msgstr "Təyinat Uyğunlaşdırmaları Yarat" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:102 @@ -1001,7 +1002,7 @@ msgstr "Bitmə Tarixi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Bank" -msgstr "Defolt Bank" +msgstr "Əsas Bank" #. Label of the default_party_settings_section (Section Break) field in #. DocType @@ -1009,48 +1010,48 @@ msgstr "Defolt Bank" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Business Partner Settings" -msgstr "Defolt Biznes Tərəfdaş Parametrləri" +msgstr "Əsas Biznes Tərəfdaşı Tənzimləmələri" #. Label of the default_company (Link) field in DocType 'Kapital Bank #. Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Company" -msgstr "Defolt Şirkət" +msgstr "Əsas Şirkət" #. Label of the default_customer_group (Link) field in DocType 'Kapital Bank #. Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Customer Group" -msgstr "Defolt Müştəri Qrupu" +msgstr "Əsas Müştəri Qrupu" #. Label of the default_login (Link) field in DocType 'Kapital Bank Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Login" -msgstr "Defolt giriş" +msgstr "Əsas Giriş" #. Label of the default_payment_terms (Link) field in DocType 'Kapital Bank #. Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Payment Terms" -msgstr "Defolt Ödəniş Şərtləri" +msgstr "Əsas Ödəniş Şərtləri" #. Label of the default_supplier_group (Link) field in DocType 'Kapital Bank #. Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Supplier Group" -msgstr "Defolt Təchizatçı Qrupu" +msgstr "Əsas Təchizatçı Qrupu" #. Label of the default_territory (Link) field in DocType 'Kapital Bank #. Settings' #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.json msgid "Default Territory" -msgstr "Defolt Ərazi" +msgstr "Əsas Ərazi" #. AI-generated #: kapital_bank/client/bank_reconciliation_tool.js:150 @@ -1091,8 +1092,8 @@ msgstr "Sənəd Növü" msgid "" "Document contains unsaved changes. Save before performing the operation?" msgstr "" -"Sənəddə yadda saxlanılmamış dəyişikliklər var. Əməliyyatı yerinə yetirməzdən" -" əvvəl yadda saxlanılsın?" +"Sənəddə yadda saxlanılmamış dəyişikliklər var. Əməliyyatı yerinə " +"yetirməzdən əvvəl yadda saxlanılsın?" #. AI-generated #: kapital_bank/client/bank_reconciliation_tool.js:305 @@ -1289,8 +1290,8 @@ msgstr "" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:405 msgid "" -"Extract unique purposes from account statement transactions for the selected" -" period" +"Extract unique purposes from account statement transactions for the " +"selected period" msgstr "" "Seçilmiş dövr üzrə hesab çıxarışı əməliyyatlarından unikal təyinatları " "çıxarın" @@ -1360,7 +1361,7 @@ msgstr "{0} Ödəniş Tələbində 'Məbləğ' sahəsi sıfırdır." #. AI-generated #: kapital_bank/payment_api.py:80 msgid "Field 'Beneficiary Bank Account' is not set." -msgstr "\"Benefisiar Bank Hesabı\" sahəsi təyin edilməyib." +msgstr "\"Vəsaiti alan bankın hesabı\"sahəsi təyin edilməyib." #. AI-generated #: kapital_bank/payment_api.py:87 @@ -1381,7 +1382,7 @@ msgstr "" #. AI-generated #: kapital_bank/payment_api.py:65 msgid "Field 'Kapital Bank Account' is not set." -msgstr "'Kapital Bank Account' sahəsi təyin edilməyib." +msgstr "'Kapital Bank Hesabı' sahəsi təyin edilməyib." #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:1091 @@ -1545,7 +1546,7 @@ msgstr "Aktivdir" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_login/kapital_bank_login.json msgid "Is Default" -msgstr "Defolt" +msgstr "Əsasdır" #. Label of the jwt_refresh_token (Password) field in DocType 'Kapital Bank #. Login' @@ -1645,19 +1646,19 @@ msgstr "Kapital Bank Müştəri Uyğunlaşdırması" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_login/kapital_bank_login.json msgid "Kapital Bank Login" -msgstr "Kapital Bank Login" +msgstr "Kapital Bank Girişi" #. Name of a DocType #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_payment/kapital_bank_payment.json msgid "Kapital Bank Payment" -msgstr "Kapital Bank Payment" +msgstr "Kapital Bank Ödənişi" #. Name of a DocType #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_purpose/kapital_bank_purpose.json msgid "Kapital Bank Purpose" -msgstr "Kapital Bank Purpose" +msgstr "Kapital Bank Ödəniş Təyinatı" #. Name of a DocType #. AI-generated @@ -1669,7 +1670,7 @@ msgstr "Kapital Bank Parametrləri" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_supplier/kapital_bank_supplier.json msgid "Kapital Bank Supplier" -msgstr "Kapital Bank Supplier" +msgstr "Kapital Bank Təchizatçısı" #. Name of a DocType #. AI-generated @@ -1857,7 +1858,7 @@ msgstr "Uyğunlaşdırılıb" #: kapital_bank/kapital_bank/doctype/kapital_bank_customer_mapping/kapital_bank_customer_mapping.json #: kapital_bank/kapital_bank/doctype/kapital_bank_supplier_mapping/kapital_bank_supplier_mapping.json msgid "Mapping Type" -msgstr "Xəritələmə Tipi" +msgstr "Uyğunlaşdırma Növü" #. Label of the mappings_tab (Tab Break) field in DocType 'Kapital Bank #. Settings' @@ -1981,7 +1982,7 @@ msgstr "Şəbəkə xətası" #: kapital_bank/client/bank_reconciliation_tool.js:320 #: kapital_bank/client/mapping.js:192 msgid "Network error creating mappings" -msgstr "Xəritələmələr yaradılarkən şəbəkə xətası" +msgstr "Uyğunlaşdırmalar yaradılarkən şəbəkə xətası baş verdi" #. AI-generated #: kapital_bank/client/bank_transaction.js:517 @@ -2052,7 +2053,7 @@ msgstr "" #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:879 msgid "No cards in registry. Use \"Load Data\" to fetch from Kapital Bank." msgstr "" -"Reyestrdə kart yoxdur. Kapital Bank-dan əldə etmək üçün \"Load Data\" " +"Reyestrdə kart yoxdur. Kapital Bank-dan əldə etmək üçün \"Məlumatı Yüklə\" " "istifadə edin." #. AI-generated @@ -2095,8 +2096,8 @@ msgid "" "No purposes registered yet. Use \"Load Data\" to extract purposes from " "statements." msgstr "" -"Hələ heç bir məqsəd qeydiyyatdan keçməyib. Hesabatlardan məqsədləri çıxarmaq" -" üçün \"Load Data\" düyməsindən istifadə edin." +"Hələ heç bir məqsəd qeydiyyatdan keçməyib. Hesabatlardan məqsədləri " +"çıxarmaq üçün \"Load Data\" düyməsindən istifadə edin." #. AI-generated #: kapital_bank/client/bank_reconciliation_tool.js:93 @@ -2153,7 +2154,7 @@ msgstr "Uyğunlaşdırılmamış təchizatçı tapılmadı" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_login/kapital_bank_login.json msgid "Not Authenticated" -msgstr "Autentifikasiya olunmayıb" +msgstr "Təsdiqlənməyib" #. Label of the notes (Data) field in DocType 'Kapital Bank Transaction #. Mapping' @@ -2297,7 +2298,7 @@ msgstr "Ödəniş Sorğusu {0} etibarsız statusa malikdir: {1}." #. AI-generated #: kapital_bank/payment_api.py:58 msgid "Payment Request {0} is not of type Outward." -msgstr "Ödəniş Sorğusu {0} Outward tipində deyil." +msgstr "Ödəniş Sorğusu {0} Məxaric tipində deyil." #. AI-generated #: kapital_bank/payment_api.py:55 @@ -2872,8 +2873,8 @@ msgid "" "This will automatically match unmapped customers with similar Customer " "names. Continue?" msgstr "" -"Bu, uyğunlaşdırılmamış müştəriləri oxşar Müştəri adları ilə avtomatik olaraq" -" uyğunlaşdıracaq. Davam edilsin?" +"Bu, uyğunlaşdırılmamış müştəriləri oxşar Müştəri adları ilə avtomatik " +"olaraq uyğunlaşdıracaq. Davam edilsin?" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:209 @@ -2906,7 +2907,7 @@ msgstr "Bitiş Tarixi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_payment/kapital_bank_payment.json msgid "To Tax No" -msgstr "Vergi No-ya qədər" +msgstr "Müştərinin VÖEN" #. Label of the token_expiry (Datetime) field in DocType 'Kapital Bank Login' #. AI-generated @@ -2947,7 +2948,7 @@ msgstr "Tapılan əməliyyatlar: " #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_api_test/kapital_bank_api_test.js:19 msgid "Transfer Status" -msgstr "Transfer Statusu" +msgstr "Köçürmə Statusu" #. AI-generated #: kapital_bank/client/payment_request.js:43 @@ -3089,7 +3090,7 @@ msgstr "artıq idxal edilib: {0}" #: kapital_bank/client/bank_transaction.js:454 #: kapital_bank/client/payment_entry.js:415 msgid "cross-account duplicates: {0}" -msgstr "hesablararası dublikatlar: {0}" +msgstr "hesablararası təkrarlananlar: {0}" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:374 @@ -3106,7 +3107,7 @@ msgstr "digər valyuta hesabı: {0}" #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:374 #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:1277 msgid "total" -msgstr "Cəmi" +msgstr "cəmi" #. AI-generated #: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:374 diff --git a/kapital_bank/client/bank_transaction.js b/kapital_bank/public/js/kapital_bank_import.bundle.js similarity index 92% rename from kapital_bank/client/bank_transaction.js rename to kapital_bank/public/js/kapital_bank_import.bundle.js index f518c9e..3e0cf99 100644 --- a/kapital_bank/client/bank_transaction.js +++ b/kapital_bank/public/js/kapital_bank_import.bundle.js @@ -721,20 +721,37 @@ KBBTImport.import = { } }; -// ======= LIST VIEW SETUP ======= -// Coexists with jey_erp's bank_transaction_list.js which creates the -// shared "Import From..." button group; we add our item into the same group. -(function () { - const existing = frappe.listview_settings['Bank Transaction'] || {}; - const prevOnload = existing.onload; - frappe.listview_settings['Bank Transaction'] = Object.assign({}, existing, { - onload(listview) { - if (typeof prevOnload === 'function') { - try { prevOnload(listview); } catch (e) { console.error(e); } +// ─────────────────────────────────────────────────────────────────────────────── +// Register Kapital Bank as a bank-import source in jey_erp's shared "Import +// From..." menu (Bank Transaction list, Payment Entry list, Bank Reconciliation +// Tool). Loaded globally via app_include_js, so KBBTImport is available wherever +// the menu is shown — including the BRT, where the per-doctype script is not. +// ─────────────────────────────────────────────────────────────────────────────── + +window.KBBTImport = KBBTImport; + +frappe.provide('jey_erp'); +jey_erp.bank_sources = jey_erp.bank_sources || []; +if (!jey_erp.bank_sources.some((s) => s.key === 'kapital')) { + jey_erp.bank_sources.push({ + key: 'kapital', + label: __('Kapital Bank'), + importLabel: __('Kapital Bank (API)'), + settingsLabel: __('Kapital Bank Settings'), + runImport(ctx) { + ctx = ctx || {}; + // Let the caller (e.g. the Bank Reconciliation Tool) react when the + // API import finishes — KBBTImport runs its own progress/list refresh, + // but the BRT needs to reload its reconciliation table afterwards. + if (typeof ctx.onComplete === 'function') { + const handler = (d) => { + frappe.realtime.off('kb_bt_import_complete', handler); + ctx.onComplete({ imported: (d && d.imported) || 0, errors: (d && d.errors) || [], transactions: [] }); + }; + frappe.realtime.on('kb_bt_import_complete', handler); } - listview.page.add_inner_button(__('Load from Kapital Bank'), function () { - KBBTImport.import.showDialog(); - }, __('Import From...')); - } + KBBTImport.import.showDialog(); + }, + goToSettings() { frappe.set_route('Form', 'Kapital Bank Settings'); }, }); -})(); +}