Clearing ParentTxn tags in jython
It’s been a while since I tinkered with md jython. I seem to be doing things incorrectly, and any guidance would be appreciated. I don’t know java very much, only python.
I sometimes manually add a keyword to a ParentTxn in error - I only want a tag in relevant splits.
I’ve written a little jython to detect these and programatically move the tags to each split and delete the parent tags. This is my code:
# """All tags deleted from ParentTxn and added to related Split(s)."""
txns = [t for t in txnset if isinstance(t, ParentTxn) and t.getKeywords()]
len = len(txns)
for txn in txns: # cycle through Parents with tag(s)
parent_tags = txn.getKeywords() # ArrayList(unicode)
txn.setKeywords([]) # clear Parent's tags
for i in range(txn.getSplitCount()):
this_split = txn.getSplit(i)
split_tags = this_split.getKeywords()
for tag in parent_tags:
Misc.addNoDuplicates(split_tags, tag) # add to existing split tags
this_split.setKeywords(split_tags)
txn.syncItem()
if txns:
print "{0} ParentTxn Keywords moved to SplitTxns.”.format(len)
This all works correctly in updating the split tags EXCEPT that instead of nothing as ParentTxn tags, the ParentTxn now shows a tag of “private” (one of my other tags). I don’t know why “private” is being selected.What am I doing wrong?
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Stuart Beesley ... on 16 Oct, 2020 12:08 PM
Nice script! - I just played with this and it seems that the parent does not hold tag data - it’s always empty. On a txn with no split and a tag there is actually 1 split and this holds the txn and the tag. Given this, I don’t see how your parents can hold tags. I just tried to create this in MD and it won’t let me. So I cannot actually do what you are suggesting. Do you have an old version of MD? Perhaps the logic changed….
Regards
Stuart B
[a fellow user]
2 Posted by Stuart Beesley ... on 16 Oct, 2020 04:00 PM
In fact I just ran a script over my entire DB and I did in fact find (only) 1 record with a parent tag (dated 2016). When I duplicate it and/or edit it, then the parent tag remains. However, if I rekey the txn exactly the same from scratch then I cannot get parent tag to populate. It always goes in split(0) tags... If you right click a txn in MD and choose show record details, you will see the raw data and where the tags are. So I do now believe the functionality changed and you can no longer set a parent (or master record) tag, only tags against the splits going forward.... ??
Stuart
[a fellow user]
3 Posted by Stuart Beesley ... on 16 Oct, 2020 04:03 PM
PS - thanks for the Python List Comprehension example ("txns = [t for t in txnset if isinstance(t, ParentTxn) and t.getKeywords()]"). Whilst I guessed what this did, I had to learn the syntax.. Nice coding!
If you think I'm wrong about the parent tags, let me know?
Stuart
[a fellow user]
4 Posted by davidcullen on 17 Oct, 2020 01:36 AM
Stuart,
Thanks for taking the time to respond. I'll play around a little further. The script was working about six month's ago.
I heartily recommend exploring List Comprehensions further. They can really make coding read a lot cleaner (but they are not always easier to read than normal loops).
5 Posted by Stuart Beesley ... on 17 Oct, 2020 06:03 AM
Let me know what you find. I’m interested in the answer too..
Regards Stuart
On 17 Oct 2020, at 02:36, davidcullen <[email blocked]> wrote:
6 Posted by Stuart Beesley ... on 17 Oct, 2020 10:46 AM
Hi, an update……
It seems that you are correct. You *CAN* store tags against the parent, but not when actually viewing the parent txn in MD. The parent transaction in MD will only show the tags of its splits (odd but true)! To see the parent’s tags, you have to view the other side (the split) and then these Txns in MD show you the parent’s tags (or sometimes their own tags shown in []s, but these disappear when you go to type). So if I visit a split and then set the tag I am now actually setting the parent’s tags… And this means I can test your script!!
OK, so you script fails for me..
When I run it, getKeywords() is returning one of these <type 'java.util.Collections$UnmodifiableRandomAccessList’>
So when Misc.addNoDuplicates() runs it crashes, with an error (I assume it can’t modify an unmodifiable list).
So I changed the script as per below.. This worked for me. It stored the parent’s tags in the split’s tags (appended) and it blanked the parent’s tags to nothing..
In fact I’ve tried all sorts of changing and blanking the parent’s tags and it works fine…
Have you right-clicked the record to view the Txn details (raw data) and see what’s showing there?
—
txns = [t for t in txnset if isinstance(t, ParentTxn) and t.getKeywords()]
for x in txns:
print x
lenx = len(txns)
for txn in txns: # cycle through Parents with tag(s)
myPT=[]
parent_tags = txn.getKeywords() # ArrayList(unicode)
for pt in parent_tags:
myPT.append(pt)
txn.setKeywords([]) # clear Parent's tags
for i in range(txn.getSplitCount()):
this_split = txn.getSplit(i)
split_tags = this_split.getKeywords()
myST=[]
for st in split_tags:
myST.append(st)
for tag in myPT:
Misc.addNoDuplicates(myST, tag) # add to existing split tags
this_split.setKeywords(myST)
txn.syncItem()
if txns:
print "{0} ParentTxn Keywords moved to SplitTxns.".format(lenx)
—
Interested to know what you find..?
\
On 16 Oct 2020, at 13:07, Stuart Beesley <[email blocked]> wrote:
Nice script! - I just played with this and it seems that the parent does not hold tag data - it’s always empty. On a txn with no split and a tag there is actually 1 split and this holds the txn and the tag. Given this, I don’t see how your parents can hold tags. I just tried to create this in MD and it won’t let me. So I cannot actually do what you are suggesting. Do you have an old version of MD? Perhaps the logic changed….
Regards
Stuart B
[a fellow user]
7 Posted by Stuart Beesley ... on 17 Oct, 2020 10:13 PM
An addition from Sean: “getKeys() used to return an unmodifiable list, but people got into trouble with that because they'd add an item to the list expecting it to be saved and it wouldn't, or they would add something to the list expecting it not to be saved (as in a copy) and it might be. I've forgotten which one was the original problem, but either way returning an unmodifiable list resolves the ambiguity”.
This makes me think you are on an older version of MD? Perhaps try your script on 2020.1? (Not the beta preview 2021.0)?
8 Posted by davidcullen on 18 Oct, 2020 06:43 AM
I am using md 2019.3 (1880). I will install md 2020 and try again. However, I'll be away a few days so may not post results till I get back.
9 Posted by davidcullen on 19 Oct, 2020 06:41 AM
Stuart,
This works (eventually). When first run, md shows the new 3 txns, but each shows a tax date of 00/00/0000 although, when I right click the new txn in md, it prompts me (each one separately) to Save the Transaction - and when I do so, the tax date of 00/00/0000 disappears!This is getting very strange. I may be doing something wrong (or not doing something I should). I haven’t tried this programming much since my recent stroke (recovering well) so forgive me if I overlooked something obvious.
Anyway, I have now installed md 2020.2(1929). I haven't yet tried to programmatically “transfer” parent tags to splits (my ultimate goal), but I have tried the following code to create transactions:
The 3 new txns show in md as (1) only a split keyword showing in the usual way. (2) a parent txn with keyword (showing [keyword] when viewing the split txn), and (3) both parent and split keywords (with the appropriate one showing when viewing the parent txn or right clicking Show Other Side to view the split.
Any insights you can give would be appreciated.
I'll keep exploring further....
10 Posted by davidcullen on 19 Oct, 2020 07:08 AM
When I run the following code to find the parent txns with keywords, it correctly finds two txns (Example Transaction 2 & Example Transaction 3 in the previous examples).
However, the output for each does not show the parent tags (parentTag) at all yet when viewed in md itself, those parent tags still are visible.Strange...
Support Staff 11 Posted by Sean Reilly on 19 Oct, 2020 09:51 AM
Hi David,
I think the differing output there is only because of the different implementations of .toString() on SplitTxn and ParentTxn. SplitTxn's toString() shows the keywords/tags but ParentTxn's doesn't. They actually are the same behind the scenes.
Thanks,
Sean
12 Posted by Stuart Beesley ... on 19 Oct, 2020 10:46 AM
Sean just beat me to it…. ;-> (but then he has that right as the ‘creator'… :-> )
As mentioned, the class methods that print themselves are different and simply don’t display the tags on the ParentTxn… Code below:
ParentTxn.toString()
====
public String toString() {
synchronized (this) {
StringBuffer sb = new StringBuffer("[ParentTxn(" + this.syncID + ") ");
sb.append(getDateInt()).append(' ');
sb.append("desc=");
sb.append(getDescription());
sb.append("; ");
sb.append("val=");
sb.append(getValue());
sb.append("; ");
sb.append("stat=");
sb.append(getStatusChar());
sb.append("; ");
sb.append("#splits=");
sb.append(getSplitCount());
sb.append("; ");
sb.append("chk=");
sb.append(getCheckNumber());
sb.append("; ");
sb.append("acct=");
sb.append(getAccount());
sb.append("; ");
if (isDirty())
sb.append("dirty; ");
sb.append("splits=");
for (int i = 0; i < getSplitCount(); i++) {
sb.append(getSplit(i));
sb.append(", ");
}
sb.append("; ]");
return sb.toString();
}
}
====
SplitTxn.toString()
====
public String toString() {
StringBuffer sb = new StringBuffer("SplitTxn: ");
sb.append("val=");
sb.append(getValue());
sb.append("; ");
sb.append("amt=");
sb.append(getParentAmount());
sb.append("; ");
sb.append("desc=");
sb.append(getDescription());
sb.append("; ");
sb.append("stat=");
sb.append(getStatusChar());
sb.append("; ");
sb.append("cat=");
sb.append(getAccount());
sb.append("; ");
if (getTags() != null) {
SyncRecord syncRecord = getTags();
sb.append("tags=[");
for (String key : syncRecord.keySet())
sb.append("(" + key + ":" + (String)syncRecord.get(key) + ")");
sb.append("];");
}
if (isDirty())
sb.append("dirty; ");
sb.append(" ]");
return sb.toString();
}
======
Stuart
[a fellow user]
13 Posted by Stuart Beesley ... on 19 Oct, 2020 12:08 PM
I don’t think you are properly constructing the Transactions. I get the same as you with your code… Looking at the Transaction details….. On a good Txn, the Tax date seems to be set to the same as the date, and chk and memo exist as “”. This seems to work:
Add this:
txn.setMemo("")
txn.setCheckNumber("")
txn.setTaxDateInt(20201019)
And possibly set oldID to -1
I see there’s a constructor called:
makeParentTxn(
AccountBook,
book,
int date,
int taxDate,
long dateEntered,
java.lang.String checkNumber,
Account account,
java.lang.String description,
java.lang.String memo,
long id,
byte status)
Which actually does this:
public static ParentTxn makeParentTxn(AccountBook book, int date, int taxDate, long dateEntered, String checkNumber, Account account, String description, String memo, long id, byte status) {
ParentTxn txn = new ParentTxn(book);
txn.setEditingMode();
txn.setDateInt(date);
txn.setTaxDateInt(taxDate);
txn.setDateEntered(dateEntered);
txn.setCheckNumber(checkNumber);
txn.setAccount(account);
txn.setDescription(description);
txn.setMemo(memo);
txn.setOldTxnID(id);
txn.setStatus(status);
return txn;
So I assume this is the minimum set for a Txn…
Hope this helps?
?
Stuart
14 Posted by Stuart Beesley ... on 19 Oct, 2020 01:27 PM
For fun….. This code updates the ParentTxn’s print/toString() to include tags/keywords. I did try to override the actual method, but it’s prevented by a Final java class preventing it:
---
from com.infinitekind.moneydance.model import ParentTxn
from com.infinitekind.moneydance.model import SplitTxn
from java.lang import StringBuffer
root = moneydance.getCurrentAccount() # Account
book = moneydance.getCurrentAccountBook() # AccountBook
txnset = book.getTransactionSet() # TransactionSet
def my_toString(txn):
sb = StringBuffer("[ParentTxn(" + txn.getUUID() + ") ");
sb.append(txn.getDateInt()).append(' ');
sb.append("desc=");
sb.append(txn.getDescription());
sb.append("; ");
sb.append("val=");
sb.append(txn.getValue());
sb.append("; ");
sb.append("stat=");
sb.append(txn.getStatusChar());
sb.append("; ");
sb.append("#splits=");
sb.append(txn.getSplitCount());
sb.append("; ");
sb.append("chk=");
sb.append(txn.getCheckNumber());
sb.append("; ");
sb.append("acct=");
sb.append(txn.getAccount());
sb.append("Keywords=");
sb.append(txn.getKeywords());
sb.append("; ");
if (txn.isDirty()):
sb.append("dirty; ");
sb.append("splits=");
for i in range(0, txn.getSplitCount()):
sb.append(txn.getSplit(i));
sb.append(", ");
sb.append("; ]");
return sb.toString();
#-- make new txns
acc1 = root.getAccountByName("TEST")
acc2 = root.getAccountByName("Bills")
#-- 1
txn = ParentTxn(book)
txn.setDescription("Example Transaction x1")
txn.setDateInt(20201019)
txn.setAccount(acc1)
txn.setMemo("")
txn.setCheckNumber("")
txn.setTaxDateInt(20201019)
txnSplit = SplitTxn(txn)
txnSplit.setAmount(100)
txnSplit.setParentAmount(1.0, -100)
txnSplit.setAccount(acc2)
txnSplit.setDescription("Split Test")
txnSplit.setKeywords(["splitTag"])
txn.addSplit(txnSplit)
txn.syncItem()
print my_toString(txn)
#-- 2
txn = ParentTxn(book)
txn.setDescription("Example Transaction x2")
txn.setDateInt(20201019)
txn.setAccount(acc1)
txn.setKeywords(["parentTag"])
txn.setMemo("")
txn.setCheckNumber("")
txn.setTaxDateInt(20201019)
txnSplit = SplitTxn(txn)
txnSplit.setAmount(100)
txnSplit.setParentAmount(1.0, -100)
txnSplit.setAccount(acc2)
txnSplit.setDescription("Split Test")
txn.addSplit(txnSplit)
txn.syncItem()
print my_toString(txn)
#-- 3
txn = ParentTxn(book)
txn.setDescription("Example Transaction x3")
txn.setDateInt(20201019)
txn.setAccount(acc1)
txn.setKeywords(["parentTag"])
txn.setMemo("")
txn.setCheckNumber("")
txn.setTaxDateInt(20201019)
txnSplit = SplitTxn(txn)
txnSplit.setAmount(100)
txnSplit.setParentAmount(1.0, -100)
txnSplit.setAccount(acc2)
txnSplit.setDescription("Split Test")
txnSplit.setKeywords(["splitTag"])
txn.addSplit(txnSplit)
txn.syncItem()
print my_toString(txn)
---
15 Posted by davidcullen on 20 Oct, 2020 09:12 AM
Thanks for all your insights. It seems things are working correctly now (having upgraded to md 2020.2. Here is my code:
This code appears now to successfully transfer ant parent tags to the relevant splits and then remove the keywords from the parent txns. This is exactly what I wanted. Occasionally, I wrongly key in a keyword to a parent (only splits should have tags, I think). The problem was that it was very difficult to locate the bad parent tags once made (to correct them manually). This script solves things automatically. The script now uses python sets to avoid duplication of tags, rather than md Misc.addNoDuplicates() as I encountered errors wth immutable java lists. Anyway, things now seem to work fine.The key point of all this seems to be that you can create keywords for ParentTxns (but this seems to cause problems) so the script detects and “moves” any to the relevant splits automatically.
I also liked your “toString()” modification. I tweeked this a little so the function can accept either a ParentTxn or a SplitTxn as an argument, with:
then following all of your code. It works!Finally, a newbie question you may be able tho help with. How did you find out about the built-in toString() class methods? Where do I look? Please bear in mind that I am only a little conversant with java - I mainly use python.
16 Posted by Stuart Beesley ... on 20 Oct, 2020 09:26 AM
Ah, well we are both on a learning journey there… Another more experienced user passed on these tips to me (thanks <you know who you are>)..
Download a Java decompiler - e.g. http://java-decompiler.github.io <http://java-decompiler.github.io/>
Locate the moneydance.jar file within the Moneydance application package/contents
Load this into the decompiler.
Play
Jython is quite useful as you can Override java classes/methods to make them work for you in Python - especially SwingX packages
SCB
17 Posted by davidcullen on 21 Oct, 2020 12:54 AM
Stuart,
Many thanks. I got JD-GUI for Mac.
DC
davidcullen closed this discussion on 22 Oct, 2020 01:32 AM.