feat: enrich card transaction descriptions and add duplicate warning
Build full description from operationName, fullRemark, shortRemark, and description fields for card statement transactions. Show a warning banner when card transactions are present since duplicate detection across card and account statements is not possible due to different reference numbers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
677c1492e7
commit
dd5ffc0bed
|
|
@ -1412,6 +1412,14 @@ def get_card_statement_transactions(from_date, to_date, card_account_number, log
|
||||||
# Purpose (operationName serves as both purpose and counterparty description)
|
# Purpose (operationName serves as both purpose and counterparty description)
|
||||||
operation_name = (txn.get("operationName") or "").strip()
|
operation_name = (txn.get("operationName") or "").strip()
|
||||||
|
|
||||||
|
# Build enriched description from all available remark fields
|
||||||
|
desc_parts = [operation_name] if operation_name else []
|
||||||
|
for field in ("fullRemark", "shortRemark", "description"):
|
||||||
|
val = (txn.get(field) or "").strip()
|
||||||
|
if val and val not in desc_parts:
|
||||||
|
desc_parts.append(val)
|
||||||
|
full_description = " || ".join(desc_parts)
|
||||||
|
|
||||||
transactions.append({
|
transactions.append({
|
||||||
"ref_no": txn_id,
|
"ref_no": txn_id,
|
||||||
"date": str(parsed_date),
|
"date": str(parsed_date),
|
||||||
|
|
@ -1421,6 +1429,7 @@ def get_card_statement_transactions(from_date, to_date, card_account_number, log
|
||||||
"currency": currency,
|
"currency": currency,
|
||||||
"drcr": dr_cr,
|
"drcr": dr_cr,
|
||||||
"purpose": operation_name,
|
"purpose": operation_name,
|
||||||
|
"full_description": full_description,
|
||||||
"source_type": "card",
|
"source_type": "card",
|
||||||
"source_label": f"Card: {pan}",
|
"source_label": f"Card: {pan}",
|
||||||
})
|
})
|
||||||
|
|
@ -2202,7 +2211,7 @@ def _import_one_bank_transaction(txn_data, settings, voen_to_party, name_to_part
|
||||||
bt.deposit = amount if dr_cr == "C" else 0
|
bt.deposit = amount if dr_cr == "C" else 0
|
||||||
bt.withdrawal = amount if dr_cr == "D" else 0
|
bt.withdrawal = amount if dr_cr == "D" else 0
|
||||||
bt.currency = currency
|
bt.currency = currency
|
||||||
bt.description = purpose
|
bt.description = txn_data.get("full_description") or purpose
|
||||||
bt.reference_number = ref_no
|
bt.reference_number = ref_no
|
||||||
bt.transaction_id = ref_no
|
bt.transaction_id = ref_no
|
||||||
bt.company = settings.default_company
|
bt.company = settings.default_company
|
||||||
|
|
|
||||||
|
|
@ -527,7 +527,16 @@ KBBTImport.import = {
|
||||||
},
|
},
|
||||||
|
|
||||||
showTransactionSelection: function(txns) {
|
showTransactionSelection: function(txns) {
|
||||||
let txnTable = '<div style="max-height: 500px; overflow-y: auto;"><table class="table table-bordered kb-bt-txn-table" style="width: 100%; table-layout: fixed;">';
|
const hasCardTxns = txns.some(t => t.source_type === 'card');
|
||||||
|
|
||||||
|
let txnTable = '';
|
||||||
|
if (hasCardTxns) {
|
||||||
|
txnTable += '<div style="margin-bottom: 10px; padding: 10px 12px; background: var(--red-50, #fff5f5); border: 1px solid var(--red-200, #fecaca); border-radius: var(--border-radius); font-size: var(--text-base); color: var(--red-600, #dc2626);">';
|
||||||
|
txnTable += '⚠️ ' + __('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.');
|
||||||
|
txnTable += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
txnTable += '<div style="max-height: 500px; overflow-y: auto;"><table class="table table-bordered kb-bt-txn-table" style="width: 100%; table-layout: fixed;">';
|
||||||
txnTable += '<thead style="position: sticky; top: 0; z-index: 1; background: var(--bg-color, #fff);"><tr>' +
|
txnTable += '<thead style="position: sticky; top: 0; z-index: 1; background: var(--bg-color, #fff);"><tr>' +
|
||||||
'<th style="width: 4%;"><input type="checkbox" class="kb-bt-select-all-txns"></th>' +
|
'<th style="width: 4%;"><input type="checkbox" class="kb-bt-select-all-txns"></th>' +
|
||||||
'<th style="width: 14%;">' + __('Ref No') + '</th>' +
|
'<th style="width: 14%;">' + __('Ref No') + '</th>' +
|
||||||
|
|
@ -555,7 +564,7 @@ KBBTImport.import = {
|
||||||
'<td style="word-break: break-word;">' + (txn.counterparty || '') + '</td>' +
|
'<td style="word-break: break-word;">' + (txn.counterparty || '') + '</td>' +
|
||||||
'<td style="text-align: right;">' + amountFmt + ' ' + (txn.currency || '') + '</td>' +
|
'<td style="text-align: right;">' + amountFmt + ' ' + (txn.currency || '') + '</td>' +
|
||||||
'<td style="text-align: center;">' + drcrLabel + '</td>' +
|
'<td style="text-align: center;">' + drcrLabel + '</td>' +
|
||||||
'<td style="word-break: break-word; font-size: 0.9em;">' + (txn.purpose || '') + '</td>' +
|
'<td style="word-break: break-word; font-size: 0.9em;">' + (txn.full_description || txn.purpose || '') + '</td>' +
|
||||||
'</tr>';
|
'</tr>';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -485,7 +485,16 @@ KBImport.import = {
|
||||||
},
|
},
|
||||||
|
|
||||||
showTransactionSelection: function(txns) {
|
showTransactionSelection: function(txns) {
|
||||||
let txnTable = '<div style="max-height: 500px; overflow-y: auto;"><table class="table table-bordered kb-txn-table" style="width: 100%; table-layout: fixed;">';
|
const hasCardTxns = txns.some(t => t.source_type === 'card');
|
||||||
|
|
||||||
|
let txnTable = '';
|
||||||
|
if (hasCardTxns) {
|
||||||
|
txnTable += '<div style="margin-bottom: 10px; padding: 10px 12px; background: var(--red-50, #fff5f5); border: 1px solid var(--red-200, #fecaca); border-radius: var(--border-radius); font-size: var(--text-base); color: var(--red-600, #dc2626);">';
|
||||||
|
txnTable += '⚠️ ' + __('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.');
|
||||||
|
txnTable += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
txnTable += '<div style="max-height: 500px; overflow-y: auto;"><table class="table table-bordered kb-txn-table" style="width: 100%; table-layout: fixed;">';
|
||||||
txnTable += '<thead style="position: sticky; top: 0; z-index: 1; background: var(--bg-color, #fff);"><tr>' +
|
txnTable += '<thead style="position: sticky; top: 0; z-index: 1; background: var(--bg-color, #fff);"><tr>' +
|
||||||
'<th style="width: 4%;"><input type="checkbox" class="kb-select-all-txns"></th>' +
|
'<th style="width: 4%;"><input type="checkbox" class="kb-select-all-txns"></th>' +
|
||||||
'<th style="width: 14%;">' + __('Ref No') + '</th>' +
|
'<th style="width: 14%;">' + __('Ref No') + '</th>' +
|
||||||
|
|
@ -513,7 +522,7 @@ KBImport.import = {
|
||||||
'<td style="word-break: break-word;">' + (txn.counterparty || '') + '</td>' +
|
'<td style="word-break: break-word;">' + (txn.counterparty || '') + '</td>' +
|
||||||
'<td style="text-align: right;">' + amountFmt + ' ' + (txn.currency || '') + '</td>' +
|
'<td style="text-align: right;">' + amountFmt + ' ' + (txn.currency || '') + '</td>' +
|
||||||
'<td style="text-align: center;">' + drcrLabel + '</td>' +
|
'<td style="text-align: center;">' + drcrLabel + '</td>' +
|
||||||
'<td style="word-break: break-word; font-size: 0.9em;">' + (txn.purpose || '') + '</td>' +
|
'<td style="word-break: break-word; font-size: 0.9em;">' + (txn.full_description || txn.purpose || '') + '</td>' +
|
||||||
'</tr>';
|
'</tr>';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue