Adding additional variable to check printing
ClosedPublic

Authored by philhopkins on Aug 23 2019, 3:17 AM.

Details

Summary

When using check forms that contain a log for record keeping it is needed to print out all of the splits associated with a transaction when printing a check. This cannot be done since the split variables are not present in the check printing plugin. This patch will add the variables SplitAccountName and SplitValue for up to 11 splits within a transaction. The check template will then be able to access the split variables and print them when printing a check.

Diff Detail

Lint
Lint Skipped
Unit
Unit Tests Skipped
philhopkins requested review of this revision.Aug 23 2019, 3:17 AM
philhopkins created this revision.
philhopkins added a reviewer: KMyMoney.
tbaumgart requested changes to this revision.Aug 23 2019, 6:44 AM
tbaumgart added a subscriber: tbaumgart.
tbaumgart added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
209

Indentation seems to be off here.

218

A bit of improved and more Qt style version of the above:

for (int i = 0; i < 11; ++i) {
  const QString valueVariable = QString("$SPLITVALUE%1").arg(i);
  const QString accountVariable = QString("$SPLITACCOUNTNAME%1").arg(i);
  if (i < numSplits) {

so no need to use std::string and a lot of conversion back and forth.

219

A split could be denominated in a different currency (depending on the account found in splits()[i].accountId() ). This is not supported with your code. See e.g. line 206 above how to do a possible conversion.

222

Variable names need to be adjusted according to the above change.

This revision now requires changes to proceed.Aug 23 2019, 6:44 AM

Thanks for the feedback, my C++ skills are way out of date. I have made two of the three changes that were suggested. I do not understand the one about the currency and you reference line 206. That line gives the value in text not numbers. Line 207 gives the value in numbers and should be modified by the currency. My line 214 should give the value in numbers and is identical to line 207. It should be modified by the currency. If I am wrong please let me know.

I hope these changes fix the problems. Again thanks.

philhopkins marked 3 inline comments as done.Aug 24 2019, 3:35 AM
philhopkins added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
209

Should be fixed.

218

Shoud be fixed.

219

I don't understand, my code is the same as line 207 as I want the value in numbers not text as line 206 gives. Am I missing something here?

222

Fixed

philhopkins marked 8 inline comments as done.Aug 24 2019, 3:36 AM

Thanks for the review, please look at my changes.

tbaumgart requested changes to this revision.Aug 24 2019, 7:10 AM
tbaumgart added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
10

Change these

checkHTML.replace( valueVariable, MyMoneyUtils::formatMoney((*it).transaction().splits()[i].shares().abs(), currency));
​checkHTML.replace( accountVariable, (file->account((*it).transaction().splits()[i].accountId())).name());

to

const MyMoneyAccount splitAccount = file->account((*it).transaction().splits()[i].accountId());
const MyMoneySecurity accountCurrency = file->currency(account.currencyId());
checkHTML.replace( valueVariable, MyMoneyUtils::formatMoney((*it).transaction().splits()[i].shares().abs(), accountCurrency));
​​checkHTML.replace( accountVariable, splitAccount.name());
215

Change these

checkHTML.replace( valueVariable, MyMoneyUtils::formatMoney((*it).transaction().splits()[i].shares().abs(), currency));
​checkHTML.replace( accountVariable, (file->account((*it).transaction().splits()[i].accountId())).name());

to

const MyMoneyAccount splitAccount = file->account((*it).transaction().splits()[i].accountId());
const MyMoneySecurity accountCurrency = file->currency(account.currencyId());
checkHTML.replace( valueVariable, MyMoneyUtils::formatMoney((*it).transaction().splits()[i].shares().abs(), accountCurrency));
​​checkHTML.replace( accountVariable, splitAccount.name());

See also my explanation in the other comment.

219

Sorry about the confusion. Not seeing the full context of the function here in the patch, I thought convert() does currency conversion but it rather converts a number into text. Nevertheless, we need to take into account here that a split can be denominated in a different currency than the original one (multi-currency). The shares() method of a split always returns the amount in the currency of the account/category of the split. The value() method of the split returns the value in the common currency of the transaction, hence shares()/value() is the exchange rate used when entering the transaction. Using shares() with the currency of the transaction might therefore not be correct and you get false results. Of course, you won't notice any of the above if you only have one currency on file.

This revision now requires changes to proceed.Aug 24 2019, 7:10 AM

I have replaced shares with value in: checkHTML.replace( valueVariable, MyMoneyUtils::formatMoney((*it).transaction().splits()[i].value().abs(), currency));.
As has been pointed out if one or more of the splits are in a different currency shares will give the wrong amount for the split.

philhopkins marked an inline comment as done.Aug 26 2019, 3:02 AM
philhopkins added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
219

I have replaced shares with value due to the potential currency problems. This should give the proper amount.

philhopkins marked 2 inline comments as done.Aug 26 2019, 3:02 AM

This should now give the proper amount.

tbaumgart requested changes to this revision.Aug 26 2019, 2:51 PM
tbaumgart added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
207

The two lines here should then also use the split().value() method. Also, see my comment below.

219

This might bite you. currency currently represents the currency in which the selected split's account/category is denominated. Depending on the circumstances, this may not be the currency in which the value is represented. The split's value is always given in the currency provided as (*it).transaction().commodity(). But this may be different from the currency of your split.

I know this will never happen in a single currency dataset, but it can if you manage your finances in multiple currencies and we shoud be prepared, since I know of users who do that.

This revision now requires changes to proceed.Aug 26 2019, 2:51 PM

questions

kmymoney/plugins/checkprinting/checkprinting.cpp
219

Thomas, Thanks for all of your advice, it has been helpful. I haven't written C++ in over 15 years so I am very rusty.

With that said I am somewhat confused. I thought that by changing to value() is would show in the amount of the currency for the split but I don't understand wat else I should do here? Should I be showing the exchange rate? or something else? any advice will be appreciated.

Phil

tbaumgart added inline comments.Aug 26 2019, 4:13 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
209

It must have slipped through, but could you name the variable numSplits (lowercase initial letter). Also, you can safely make it a const int instead of int because it may not change anyway in this context.

210

Can you make the 11 a named constant? E.g. in the beginning of this function around line 166 by saying

const int maxSplits = 11;

and using maxSplits in the above for-loop?

219

This is not C++ related but how the application manages the data. Each split has two attributes: shares and value. Each transaction is denominated in a currency (transaction.currency()). The sum of the value attributes over all splits of a transaction must be zero for the transaction to be balanced (that is what double entry accounting is all about), where it does not matter in which currency that happens. The shares attribute represents the units in the currency of the account that the split references. So the sum of all shares over all splits of a specific account provides the balance of the account.

In the end, it depends on how you want the different currencies printed on the check. All this is only important in case one has multiple currencies. I just want to avoid that we add some code that works in single currency environments but gives the user a headache when using it with multiple currencies.

My initial code suggestion was to use the share value and print the respective currency symbol. This is correct and easy to accomplish. Everything else is much more complex as there are more corner cases.

Hope that makes it a bit more meaningful. If not, please let me know.

philhopkins added inline comments.Aug 26 2019, 4:21 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
219

Thanks, I agree I want this to be a generalized solution, not one that just works for me. I will add a variable to allow the curriency for the transaction to be printed. I am not sure if that is enough, though. Is there anything ese that I should include? Any I do realize that this is not a C++ issue but one of properly offering clear data to the user. Thanks again for your help.

Phil

philhopkins added inline comments.Aug 26 2019, 4:30 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
219

I do notice that for the transaction this seems to be transaction().commodity().

Phil

tbaumgart added inline comments.Aug 26 2019, 4:49 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
219

transaction.commodity() is the currency of the account in which the transaction was entered (either manually or via import). So in most cases (when the user also prints the check from this account) it is OK to use it for our purpose here.

Added the currency for the accout=nt/transaction

philhopkins marked 6 inline comments as done.Aug 26 2019, 5:07 PM
philhopkins marked 4 inline comments as done.
tbaumgart added inline comments.Aug 26 2019, 5:16 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
207

I still see split.shares() here instead of split.value().

209

(*it).transaction().commodity() returns the ID (which is the ISO 4217 code). In general we display the currencySymbol() of a security/currency.

philhopkins added inline comments.Aug 26 2019, 5:54 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
209

If I look at what is in the database for my user, I see "USD" not the ISO code. If the ISO code is stored for other currencies, how do I convert it to the currenctSysmbol()? Something like:
checkHTML.replace("$TRANSACTIONCURRENCY", ((*it).transaction().commodity(), currencySymbol()));
? Except that doesn't compile!
Phil

tbaumgart added inline comments.Aug 26 2019, 6:08 PM
kmymoney/plugins/checkprinting/checkprinting.cpp
209

Well, USD is the ISO 4217 code said currency. See https://en.wikipedia.org/wiki/ISO_4217 To get the currency symbol you go as follows:

const auto currencyId = (*it).transaction().commodity();
const auto currency = MyMoneyFile::instance()->currency(currencyId);
checkHTML.replace("$TRANSACTIONCURRENCY", currency.tradingSymbol());

Changed all sahres to value and updated currency to print the currency symbol.

philhopkins marked 4 inline comments as done.Aug 26 2019, 6:27 PM
philhopkins added inline comments.
kmymoney/plugins/checkprinting/checkprinting.cpp
207

I updated those old shares t value.

209

Thanks for the code sample, I have updated the code to user your suggestion and it now prints the currency symbol.

philhopkins marked 4 inline comments as done.Aug 26 2019, 6:27 PM
tbaumgart accepted this revision.Aug 26 2019, 7:16 PM

Please change NumSplits into numSplits before you commit. Or do you want me do add it to the repository?

This revision is now accepted and ready to land.Aug 26 2019, 7:16 PM
philhopkins updated this revision to Diff 64703.EditedAug 26 2019, 9:39 PM

Corrected variable name numSplits.

Thomas, What needs to be done now? I am at a loss now - how does this get merged into the code base?

Phil

This revision was automatically updated to reflect the committed changes.