Bug 491828 - Currency settings show incorrect
Summary: Currency settings show incorrect
Status: REOPENED
Alias: None
Product: kmymoney
Classification: Applications
Component: general (show other bugs)
Version: git (master)
Platform: Microsoft Windows Microsoft Windows
: NOR normal
Target Milestone: ---
Assignee: KMyMoney Devel Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-08-17 15:13 UTC by Tony
Modified: 2024-09-10 15:18 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In: 5.2
Sentry Crash Report:


Attachments
Screenshots of Bitcoin currency editors of v 5.1.3 and master (16.33 KB, application/x-zip-compressed)
2024-08-17 15:13 UTC, Tony
Details
QLocale testcase source (922 bytes, application/x-7z-compressed)
2024-08-23 07:20 UTC, Ralf Habacker
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tony 2024-08-17 15:13:40 UTC
Created attachment 172708 [details]
Screenshots of Bitcoin currency editors of v 5.1.3 and master

SUMMARY
Using KMyMoney 5.1 Version 5.1.3-eef0ff1, the Currency editor shows the Smallest account unit and Smallest cash unit of Bitcoin to be 0.00000001.

Using the master branch of KMyMoney (build 3407), the Currency editor shows £0.00 for these properties.

Possibly as a result of this behaviour, the Transaction Report of transactions in an account whose currency is Bitcoin displays the amounts as BTC £0.02. KMyMoney 5.1 shows BTC 0.01760000. The transaction editor also shows £0.02.

SOFTWARE/OS VERSIONS
Windows: 10

ADDITIONAL INFORMATION
Attached are screenshots of the Currency Editor from v 5.1.3 and master 3407.
Comment 1 Thomas Baumgart 2024-08-19 11:51:40 UTC
Very strange behavior which differs on Linux and Windows:

The code section

    precision = MyMoneyMoney::denomToPrec(currency.smallestAccountFraction());
    smallestFraction = MyMoneyMoney::ONE / MyMoneyMoney(currency.smallestAccountFraction());
    qDebug() << "account precision" << precision << smallestFraction.formatMoney(QString(), precision);

provides the following output on Linux:

   account precision 8 "0,00000001"

but on Windows we get

   account precision 8 "0,00 €"

I have not clue what is going on here. This explains why 0,00 € is shown in the dialog when editing the currency. BTW, the display in the edit currency is identical no matter if compiled with MSVC (KDE CI/CD) or cross-compiled (snapshots).
Comment 2 Ralf Habacker 2024-08-19 13:46:51 UTC
(In reply to Thomas Baumgart from comment #1)
> Very strange behavior which differs on Linux and Windows:

To exclude influences from the entire application, I suggest inserting an additional unit test in kmymoney/mymoney/tests/mymoneysecurity-test.cpp, e.g. 

void MyMoneySecurityTest::testSmallestAccountUnit()
{
    MyMoneySecurity currency("BTC", "Bitcoin", "BTC", 100000000, 100000000);
    int precision = MyMoneyMoney::denomToPrec(currency.smallestAccountFraction());
    MyMoneyMoney smallestFraction = MyMoneyMoney::ONE / MyMoneyMoney(currency.smallestAccountFraction());
    QCOMPARE(smallestFraction.formatMoney(QString(), precision), QLatin1String("0.00000001"));
}

which can then be used more easily for debugging.
Comment 3 Ralf Habacker 2024-08-19 14:52:40 UTC
(In reply to Ralf Habacker from comment #2)

As the problem here is the call to formatMoney() it may be named better: 

void MyMoneySecurityTest::testFormatMoney()
{
    MyMoneySecurity currency("BTC", "Bitcoin", "BTC", 100000000, 100000000);
    int precision = MyMoneyMoney::denomToPrec(currency.smallestAccountFraction());
    MyMoneyMoney smallestFraction = MyMoneyMoney::ONE / MyMoneyMoney(currency.smallestAccountFraction());
    QCOMPARE(smallestFraction.formatMoney(QString(), precision), QLatin1String("0.00000001"));
}
Comment 4 Ralf Habacker 2024-08-19 18:46:23 UTC
With a mingw build I edited Türkische Lira (alt), which shows in the log

editing currency "Türkische Lira (alt)" "TL" 100 100
cash precision 2 "0,01 Ç"
account precision 2 "0,01 Ç"

Then I added "Bitcoin" as currency 

adding currency "Bitcoin" "BTC" 100000000 100000000

and edited it: 

editing currency "Bitcoin" "BTC" 100000000 100000000
cash precision 8 "0,00 Ç"
account precision 8 "0,00 Ç"

which should still using currency "TL" -> The currency used has not been updated.
Comment 5 Ralf Habacker 2024-08-19 18:47:11 UTC
(In reply to Ralf Habacker from comment #4)
> which should still using currency "TL" -> The currency used has not been updated.

correction:  which is still using currency "TL" -> The currency used has not been
Comment 6 Ralf Habacker 2024-08-19 19:37:58 UTC
(In reply to Thomas Baumgart from comment #1)
>     precision =

I changed the relevant code section to 

precision = MyMoneyMoney::denomToPrec(currency.smallestAccountFraction());
smallestFraction = MyMoneyMoney::ONE / MyMoneyMoney(currency.smallestAccountFraction());
qDebug() << "account precision" << precision << smallestFraction.formatMoney(QString(), precision) << smallestFaction.toDouble() << smallestFaction.toString()

and got 

cash precision 8 "0,00 Bitcoin" 1e-08 "1/100000000"
account precision 8 "0,00 Bitcoin" 1e-08 "1/100000000"

which indicates that there is a issue with the formatMoney() method.
Comment 7 Ralf Habacker 2024-08-19 23:52:16 UTC
(In reply to Ralf Habacker from comment #6)
> which indicates that there is a issue with the formatMoney() method.

I think this error was introduced with https://invent.kde.org/office/kmymoney/-/commit/0487f47b6da4b2cee47a13983f375eda7f205501 in the method mentioned below

QString MyMoneyMoney::formatMoney(const QString& currency, const int prec, bool showThousandSeparator) const
{
    if (eMyMoney::Money::_useQtInternalFormmater) {
        return eMyMoney::Money::_locale.toCurrencyString(this->toDouble(), currency, prec);
    }

`eMyMoney::Money::_useQtInternalFormmater` is true and thus the formatting of the numbers is carried out by Qt, which does not work here.  Commenting out the whole if part, returns the expected value in the smallest ... unit.
Comment 8 Ralf Habacker 2024-08-19 23:57:28 UTC
(In reply to Ralf Habacker from comment #4)
...
> editing currency "Türkische Lira (alt)" "TL" 100 100
> cash precision 2 "0,01 Ç"
> account precision 2 "0,01 Ç"
...
> editing currency "Bitcoin" "BTC" 100000000 100000000
> cash precision 8 "0,00 Ç"
> account precision 8 "0,00 Ç"
> 
> which is still using currency "TL" -> The currency used has not been updated.

This issue is caused by using 

    smallestFraction.formatMoney(QString(), precision) 

by changing this call to use currency.name() instead

    smallestFraction.formatMoney(currency.name(), precision) 

and with the fix mentioned in comment 7 I get

cash precision 8 "0,00000001 Bitcoin"
Comment 9 Ralf Habacker 2024-08-20 09:20:42 UTC
This issue does not occur with a basic Qt test case. Running the following tests build with MinGW as simple qt console app

        const QLocale btc("BTC");
        QCOMPARE(btc.toCurrencyString(double(1e-1), "BTC", 1), QString("0.1BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-2), "BTC", 2), QString("0.01BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-3), "BTC", 3), QString("0.001BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-4), "BTC", 4), QString("0.0001BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-5), "BTC", 5), QString("0.00001BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-6), "BTC", 6), QString("0.000001BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-7), "BTC", 7), QString("0.0000001BTC"));
        QCOMPARE(btc.toCurrencyString(double(1e-8), "BTC", 8), QString("0.00000001BTC"));

 does not fail. There must be something different in kmymoney.
Comment 10 Bug Janitor Service 2024-08-20 09:42:04 UTC
A possibly relevant merge request was started @ https://invent.kde.org/office/kmymoney/-/merge_requests/226
Comment 11 Ralf Habacker 2024-08-20 10:21:06 UTC
(In reply to Bug Janitor Service from comment #10)
> A possibly relevant merge request was started @
> https://invent.kde.org/office/kmymoney/-/merge_requests/226

Sorry, I used wrong bug number, please ignore this comment.
Comment 12 Thomas Baumgart 2024-08-20 15:48:34 UTC
Git commit 2b802594c5ecb94f75f472c11ebdd4a520eb8984 by Thomas Baumgart.
Committed on 20/08/2024 at 15:47.
Pushed by tbaumgart into branch 'master'.

Improve detection of currency formatting

QLocale::toCurrencyString() returns different strings on Windows and
Linux when using a value without fraction (e.g. 100). On Linux the
output in locale de_DE was "100 €" and the same code on Windows returned
"100,00 €". That caused the existing implementation of the format
detection to fail.

Changing the test value to 123.45 and enhancing the regex to extract the
parts solves the issue.
FIXED-IN: 5.2

M  +4    -3    kmymoney/mymoney/mymoneymoney.cpp

https://invent.kde.org/office/kmymoney/-/commit/2b802594c5ecb94f75f472c11ebdd4a520eb8984
Comment 13 Tony 2024-08-20 21:31:12 UTC
I confirm that the Currency Editor and the Transaction Reports are fixed. The Balance field of the Ledger shows only two digits instead of eight for the Bitcoin account. I think it showed the £ symbol in front of it in the Windows 3407 build. (I just deleted it so I can't confirm it.)

I'm unsure whether I should re-open this or submit a new ticket. If you prefer a new ticket I can create it.
Comment 14 Ralf Habacker 2024-08-21 06:35:16 UTC
(In reply to Tony from comment #13)
> I confirm that the Currency Editor and the Transaction Reports are fixed.
> The Balance field of the Ledger shows only two digits instead of eight for
> the Bitcoin account. I think it showed the £ symbol in front of it in the
> Windows 3407 build. (I just deleted it so I can't confirm it.)

In analyzing this problem, I found that I need to make the changes mentioned in comment 8 before using commit https://invent.kde.org/office/kmymoney/-/commit/2b802594c5ecb94f75f472c11ebdd4a520eb8984 to fix this problem as well.
Comment 15 Tony 2024-08-21 20:04:31 UTC
There's another related problem when trying to enter into the Ledger a transfer from an EUR account to a BTC account. When entering the transaction into the EUR account, I can only enter a BTC amount of up to 2 decimal places, not 8 decimal places. And if I try to change the BTC amount in the BTC account, then the EUR amount changes.
Comment 16 Ralf Habacker 2024-08-22 07:42:36 UTC
Additional info: 

Starting kmymoney on a german Windows 10 system from command line shows in the console:

  Monetary values will be formatted based on locale "de_DE" Example:  "123,45 Ç"

The used locale seems to be wrong.
Comment 17 Ralf Habacker 2024-08-22 08:13:17 UTC
(In reply to Ralf Habacker from comment #16)
>   Monetary values will be formatted based on locale "de_DE" Example: 
> "123,45 Ç"
> 
> The used locale seems to be wrong.

To be more precise: The locale used seems to be correct, but the currency symbol does not match.
Comment 18 Tony 2024-08-22 18:00:25 UTC
(In reply to Ralf Habacker from comment #17)
> (In reply to Ralf Habacker from comment #16)
> >   Monetary values will be formatted based on locale "de_DE" Example: 
> > "123,45 Ç"
> > 
> > The used locale seems to be wrong.
> 
> To be more precise: The locale used seems to be correct, but the currency
> symbol does not match.

The only information that KMyMoney would want from the OS's locale in order to format a money amount would be the thousands separator and decimal separator; the rest should come from the currency of the account, asset etc, or the base currency defined in KMyMoney.
Comment 19 Ralf Habacker 2024-08-23 07:20:23 UTC
Created attachment 172871 [details]
QLocale testcase source

Since kmymoney uses QLocale for formatting currency amounts, I created a Qt-only test case to see if the problem exists in the Qt library.

The result is that the tests performed on native Linux, Linux with Wine and native Windows 10 produce identical results.

$  test-qlocale-tocurrencystring/build-linux/testqlocaletocurrencystring
********* Start testing of QLocaleTest *********
Config: Using QtTest library 5.15.8, Qt 5.15.8 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 7.5.0), opensuse-leap 15.5
PASS   : QLocaleTest::initTestCase()
PASS   : QLocaleTest::TestToCurrencyString()
PASS   : QLocaleTest::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms
********* Finished testing of QLocaleTest *********

 $ wine build/testqlocaletocurrencystring.exe 
********* Start testing of QLocaleTest *********
Config: Using QtTest library 5.15.14, Qt 5.15.14 (i386-little_endian-ilp32 shared (dynamic) release build; by GCC 13.
2.0), windows 10
PASS   : QLocaleTest::initTestCase()
PASS   : QLocaleTest::testToCurrencyString()
PASS   : QLocaleTest::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 52ms
********* Finished testing of QLocaleTest *********

W:\src\test-qt5\test-qlocale-toCurrencyString\build> testqlocaletocurrencystring.exe
********* Start testing of QLocaleTest *********
Config: Using QtTest library 5.15.14, Qt 5.15.14 (i386-little_endian-ilp32 shared (dynamic) release build; by GCC 13.2.0), windows 10
PASS   : QLocaleTest::initTestCase()
PASS   : QLocaleTest::TestToCurrencyString()
PASS   : QLocaleTest::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 4ms
********* Finished testing of QLocaleTest *********

For the output of the smallest part of virtual currencies, such as cryptocurrencies, there is a flaw in the method used.

QString QLocale::toCurrencyString(double value, const QString &symbol, int precision)

If the value for the parameter symbol is NULL, QString() or QString(""), a currency symbol is always output in the default currency of the relevant locale (and this is also different, e.g. in the last two cases '€' or 'EUR' is used for 'de_DE'), which is inappropriate for outputting the smallest part of virtual currencies such as cryptocurrencies. 

If no output of a currency symbol is desired, a workaround is to use QString(" ") as the parameter (see the last 3 tests in the test case).
Comment 20 Thomas Baumgart 2024-08-25 09:33:49 UTC
> Since kmymoney uses QLocale for formatting currency amounts, ...
That is not completely correct. KMyMoney uses QLocale::toCurrencyString() only, if it was not able to match its test pattern in the output of QLocale::toCurrencyString(). This is the case for some e.g. arabic locales to my knowledge. KMyMoney indicates that with a debug output of "Using Qt internal formatter". If that output is not visible after the start of the application and outputting the result of the test pattern, then it uses it's own logic.
Comment 21 Tony 2024-09-10 15:18:26 UTC
I have just tried the latest build (3490) and the Balance column of the ledger continues to show the amount as, e.g. 0.16 instead of 0.16688250 (the 8 decimal places configured for the BTC currency)