[office/kmymoney] kmymoney/plugins/csv/import: CSV Importer: support Fee column in bank statements
Dawid Wrobel <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 8f3fdf30346b655852e15a71818981a98ca9ce0c by Dawid Wrobel, on behalf of Dawid Wróbel.
Committed on 19/07/2026 at 11:10.
Pushed by wrobelda into branch 'master'.
CSV Importer: support Fee column in bank statements
- Adds support for additional Fee column in banking statements
- relies on existing fee calculation logic in MyMoneyStatementReader
- adds relevant CSV importer test
M +5 -0 kmymoney/plugins/csv/import/bankingwizardpage.cpp
M +38 -0 kmymoney/plugins/csv/import/bankingwizardpage.ui
M +20 -3 kmymoney/plugins/csv/import/core/csvimportercore.cpp
M +32 -0 kmymoney/plugins/csv/import/core/tests/test-csvimportercore.cpp
M +2 -0 kmymoney/plugins/csv/import/core/tests/test-csvimportercore.h
https://invent.kde.org/office/kmymoney/-/commit/8f3fdf30346b655852e15a71818981a98ca9ce0c
diff --git a/kmymoney/plugins/csv/import/bankingwizardpage.cpp b/kmymoney/plugins/csv/import/bankingwizardpage.cpp
index ef2b030a6..ca5891906 100644
--- a/kmymoney/plugins/csv/import/bankingwizardpage.cpp
+++ b/kmymoney/plugins/csv/import/bankingwizardpage.cpp
@@ -63,6 +63,7 @@ BankingPage::BankingPage(CSVWizard* dlg, CSVImporterCore* imp)
{Column::Category, ui->m_categoryCol},
{Column::CreditDebitIndicator, ui->m_creditDebitIndicatorCol},
{Column::Balance, ui->m_balanceCol},
+ {Column::Fee, ui->m_feeCol},
};
connect(ui->m_clear, &QAbstractButton::clicked, this, &BankingPage::clearColumns);
@@ -101,6 +102,9 @@ BankingPage::BankingPage(CSVWizard* dlg, CSVImporterCore* imp)
connect(ui->m_balanceCol, signal, this, [&](int col) { // clazy:exclude=connect-non-signal
validateSelectedColumn(col, Column::Balance);
});
+ connect(ui->m_feeCol, signal, this, [&](int col) { // clazy:exclude=connect-non-signal
+ validateSelectedColumn(col, Column::Fee);
+ });
connect(ui->m_creditIndicator, &QLineEdit::textEdited, this, [&](const QString& indicator) {
m_profile->m_creditIndicator = indicator;
@@ -130,6 +134,7 @@ BankingPage::BankingPage(CSVWizard* dlg, CSVImporterCore* imp)
connectClearButton(m_payeeCol);
connectClearButton(m_categoryCol);
connectClearButton(m_balanceCol);
+ connectClearButton(m_feeCol);
connectClearButton(m_amountCol);
connectClearButton(m_creditDebitIndicatorCol);
connectClearButton(m_debitCol);
diff --git a/kmymoney/plugins/csv/import/bankingwizardpage.ui b/kmymoney/plugins/csv/import/bankingwizardpage.ui
index 71c215734..8e16afb8f 100644
--- a/kmymoney/plugins/csv/import/bankingwizardpage.ui
+++ b/kmymoney/plugins/csv/import/bankingwizardpage.ui
@@ -355,6 +355,42 @@
</property>
</widget>
</item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="labelBnk_fee">
+ <property name="text">
+ <string>Fee</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>m_feeCol</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QComboBox" name="m_feeCol">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Select column containing fee field.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QToolButton" name="m_feeColClear">
+ <property name="toolTip">
+ <string>Clear fee field selection.</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -740,6 +776,8 @@
<tabstop>m_memoColClear</tabstop>
<tabstop>m_balanceCol</tabstop>
<tabstop>m_balanceColClear</tabstop>
+ <tabstop>m_feeCol</tabstop>
+ <tabstop>m_feeColClear</tabstop>
<tabstop>m_amountTabWidget</tabstop>
<tabstop>m_amountCol</tabstop>
<tabstop>m_amountColClear</tabstop>
diff --git a/kmymoney/plugins/csv/import/core/csvimportercore.cpp b/kmymoney/plugins/csv/import/core/csvimportercore.cpp
index 9b93a0003..3137bb3ad 100644
--- a/kmymoney/plugins/csv/import/core/csvimportercore.cpp
+++ b/kmymoney/plugins/csv/import/core/csvimportercore.cpp
@@ -2,7 +2,7 @@
SPDX-FileCopyrightText: 2010 Allan Anderson <[email protected]>
SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <[email protected]>
SPDX-FileCopyrightText: 2020 Thomas Baumgart <[email protected]>
- SPDX-FileCopyrightText: 2021 Dawid Wróbel <[email protected]>
+ SPDX-FileCopyrightText: 2021-2026 Dawid Wróbel <[email protected]>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -927,6 +927,24 @@ bool CSVImporterCore::processBankRow(MyMoneyStatement& st, const BankingProfile*
return false;
}
+ // process fee field
+ col = profile->m_colTypeNum.value(Column::Fee, -1);
+ if (col != -1) {
+ if (profile->m_decimalSymbol == DecimalSymbol::Auto) {
+ DecimalSymbol decimalSymbol = m_decimalSymbolIndexMap.value(col);
+ m_file->m_parse->setDecimalSymbol(decimalSymbol);
+ }
+
+ txt = m_file->m_model->item(row, col)->text();
+ if (txt.startsWith(QLatin1Char('('))) // check if brackets notation is used for negative numbers
+ txt.remove(QRegularExpression(QStringLiteral("[()]")));
+
+ if (!txt.isEmpty()) {
+ const auto fee = MyMoneyMoney(m_file->m_parse->possiblyReplaceSymbol(txt)).abs();
+ tr.m_fees = fee;
+ }
+ }
+
MyMoneyStatement::Split s1;
s1.m_amount = tr.m_amount;
s1.m_strMemo = tr.m_strMemo;
@@ -1056,8 +1074,7 @@ bool CSVImporterCore::processInvestRow(MyMoneyStatement& st, const InvestmentPro
MyMoneyMoney fee(m_file->m_parse->possiblyReplaceSymbol(txt));
if (profile->m_feeIsPercentage && profile->m_feeRate.isEmpty()) // fee is percent
fee *= tr.m_amount / MyMoneyMoney(100); // as percentage
- fee.abs();
- tr.m_fees = fee;
+ tr.m_fees = fee.abs();
}
}
diff --git a/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.cpp b/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.cpp
index a8415d217..e56b908fc 100644
--- a/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.cpp
+++ b/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.cpp
@@ -1,5 +1,6 @@
/*
SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <[email protected]>
+ SPDX-FileCopyrightText: 2026 Dawid Wróbel <[email protected]>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -207,6 +208,37 @@ void CSVImporterCoreTest::testImportByAmount()
QVERIFY(st.m_listTransactions[1].m_amount == MyMoneyMoney(56.78));
}
+void CSVImporterCoreTest::testImportByAmountWithFee()
+{
+ QString csvContent;
+ csvContent += QLatin1String("\"Trans Date\",\"Post Date\",\"Description\",\"Amount\",\"Fee\",\"Category\"\n");
+ csvContent += QLatin1String("05/16/2016,05/17/2016,FOO1,100.00,2.50,BAR\n");
+ csvContent += QLatin1String("06/17/2016,06/18/2016,FOO2,-100.00,2.50,BAR\n");
+ csvContent += QLatin1String("07/18/2016,07/19/2016,FOO3,-100.00,-2.50,BAR\n");
+ csvContent += QLatin1String("08/19/2016,08/20/2016,FOO4,100.00,,BAR\n");
+
+ QString filename("import-by-amount-with-fee.csv");
+ writeStatementToCSV(csvContent, filename);
+ amountProfile->m_colTypeNum.insert(Column::Fee, 4);
+ amountProfile->m_colTypeNum[Column::Category] = 5;
+ amountProfile->m_colNumType.remove(4);
+ amountProfile->m_colNumType.insert(4, Column::Fee);
+ amountProfile->m_colNumType.insert(5, Column::Category);
+
+ auto st = csvImporter->unattendedImport(filename, amountProfile);
+ QVERIFY(st.m_listTransactions.count() == 4);
+ QVERIFY(st.m_listTransactions[0].m_fees == MyMoneyMoney(2.50));
+ QVERIFY(st.m_listTransactions[0].m_amount == MyMoneyMoney(100.00));
+ QVERIFY(st.m_listTransactions[0].m_listSplits.first().m_amount == MyMoneyMoney(-100.00));
+ QVERIFY(st.m_listTransactions[1].m_fees == MyMoneyMoney(2.50));
+ QVERIFY(st.m_listTransactions[1].m_amount == MyMoneyMoney(-100.00));
+ QVERIFY(st.m_listTransactions[1].m_listSplits.first().m_amount == MyMoneyMoney(100.00));
+ QVERIFY(st.m_listTransactions[2].m_fees == MyMoneyMoney(2.50));
+ QVERIFY(st.m_listTransactions[2].m_amount == MyMoneyMoney(-100.00));
+ QVERIFY(st.m_listTransactions[3].m_fees == MyMoneyMoney());
+ QVERIFY(st.m_listTransactions[3].m_amount == MyMoneyMoney(100.00));
+}
+
void CSVImporterCoreTest::testImportByName()
{
auto stockNames = csvImporter->m_mapSymbolName.values();
diff --git a/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.h b/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.h
index 37fec7e71..66b737e86 100644
--- a/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.h
+++ b/kmymoney/plugins/csv/import/core/tests/test-csvimportercore.h
@@ -1,5 +1,6 @@
/*
SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <[email protected]>
+ SPDX-FileCopyrightText: 2026 Dawid Wróbel <[email protected]>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -38,6 +39,7 @@ private Q_SLOTS:
void testPriceFractionSetting();
void testImportByDebitCredit();
void testImportByAmount();
+ void testImportByAmountWithFee();
void testImportByName();
void testImportBySymbol();
void testFeeColumn();