refactor(kapital-bank): move client JS into bundle; update settings, mappings, hooks, az locale

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-06-10 17:52:03 +00:00
parent b004ff32f4
commit bdf32afa2d
7 changed files with 429 additions and 92 deletions

View File

@ -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",
}

View File

@ -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",

View File

@ -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) {
</div>
</div>`;
}
// ═══════════════════════════════════════════════════════════════════════════════
// 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 = ` <span class="kb-wizard-tag skip">${__('Skipped')}</span>`;
} else if (st.done) {
badge = '✓'; cls = 'done'; tag = '';
} else if (isCur) {
badge = '➜'; cls = 'cur';
tag = ` <span class="kb-wizard-tag cur">${__('Current step')}</span>`;
} else {
badge = (i + 1); cls = 'todo'; tag = '';
}
const skipCtl = st.off ? '' :
`<span class="kb-wizard-skip" data-kb-skip="${st.key}">${
st.skipped ? __('Unskip') : __('Skip')}</span>`;
return `
<div class="kb-wizard-step ${cls}">
<div class="kb-wizard-step-main" data-kb-step="${i}">
<span class="kb-wizard-badge">${badge}</span>
<div class="kb-wizard-step-body">
<div class="kb-wizard-step-title">${esc(st.title)}${tag}</div>
<div class="kb-wizard-step-hint">${esc(st.hint)}</div>
</div>
</div>
${skipCtl}
</div>`;
}).join('');
const html = `
<div class="kb-wizard${keepOpen ? ' open' : ''}">
<div class="kb-wizard-bar">
<span class="kb-wizard-dot"></span>
<span class="kb-wizard-cur"><b>${__('Kapital Bank')}</b> · ${esc(cur.title)}</span>
<span class="kb-wizard-toggle">${__('Steps')}<span class="kb-wizard-chev"></span></span>
</div>
<div class="kb-wizard-list">${rows}</div>
</div>`;
_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);
});
},
});
}

View File

@ -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(

View File

@ -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",

View File

@ -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: <jeyerp@jeycloud.az>\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</div></div>"
msgstr ""
"<div id=\"kb-cards-container\"><div class=\"text-center text-muted\" "
"style=\"padding:20px;\">Kapital Bank-dan kartları əldə etmək üçün \"Məlumatı"
" Yüklə\" düyməsinə klikləyin</div></div>"
"style=\"padding:20px;\">Kapital Bank-dan kartları əldə etmək üçün "
"\"Məlumatı Yüklə\" düyməsinə klikləyin</div></div>"
#. Content of the 'Customers List' (HTML) field in DocType 'Kapital Bank
#. Settings'
@ -109,8 +110,8 @@ msgid ""
"irreversible. Are you sure?</p>"
msgstr ""
"<div style=\"color:red;font-weight:bold;\">XƏBƏRDARLIQ! Bu, bütün "
"uyğunlaşdırılmamış hesablar üçün yeni Bank Hesabı qeydləri "
"yaradacaq!</div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
"uyğunlaşdırılmamış hesablar üçün yeni Bank Hesabı qeydləri yaradacaq!</"
"div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
#. AI-generated
#: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:314
@ -120,8 +121,8 @@ msgid ""
"irreversible. Are you sure?</p>"
msgstr ""
"<div style=\"color:red;font-weight:bold;\">XƏBƏRDARLIQ! Bu, bütün "
"uyğunlaşdırılmamış kartlar üçün yeni Bank Hesabı qeydləri "
"yaradacaq!</div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
"uyğunlaşdırılmamış kartlar üçün yeni Bank Hesabı qeydləri yaradacaq!</"
"div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
#. AI-generated
#: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:693
@ -131,8 +132,8 @@ msgid ""
"irreversible. Are you sure?</p>"
msgstr ""
"<div style=\"color:red;font-weight:bold;\">XƏBƏRDARLIQ! Bu, bütün "
"uyğunlaşdırılmamış müştərilər üçün yeni Müştəri qeydləri "
"yaradacaq!</div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
"uyğunlaşdırılmamış müştərilər üçün yeni Müştəri qeydləri yaradacaq!</"
"div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
#. AI-generated
#: kapital_bank/kapital_bank/doctype/kapital_bank_settings/kapital_bank_settings.js:725
@ -142,8 +143,8 @@ msgid ""
"irreversible. Are you sure?</p>"
msgstr ""
"<div style=\"color:red;font-weight:bold;\">XƏBƏRDARLIQ! Bu, bütün "
"uyğunlaşdırılmamış təchizatçılar üçün yeni Təchizatçı qeydləri "
"yaradacaq!</div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
"uyğunlaşdırılmamış təchizatçılar üçün yeni Təchizatçı qeydləri yaradacaq!</"
"div><p>Bu əməliyyat geri qaytarıla bilməz. Əminsiniz?</p>"
#. 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

View File

@ -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...'));
}
},
goToSettings() { frappe.set_route('Form', 'Kapital Bank Settings'); },
});
})();
}