From 85c12f049a03ca89252bf726ffedef6bd8e7923b Mon Sep 17 00:00:00 2001 From: Christoph Massmann <c.massmann@vianetz.com> Date: Thu, 18 Aug 2022 12:33:29 +0200 Subject: [PATCH 1/2] all accounts with no bankIdentifier are now summed up also --- moneymoney-sum-by-bank.scpt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/moneymoney-sum-by-bank.scpt b/moneymoney-sum-by-bank.scpt index 43dc6df..a095e30 100644 --- a/moneymoney-sum-by-bank.scpt +++ b/moneymoney-sum-by-bank.scpt @@ -83,20 +83,23 @@ on SumBankBalancesFromPlist(accountsPropertyListFile) tell application "System Events" tell property list file accountsPropertyListFile repeat with i from 1 to number of property list items - set bankIdentifier to "" - set accountName to "" + set accountName to value of property list item "name" of property list item i + + set isGroup to value of property list item "group" of property list item i + if isGroup is false then + try + set bankIdentifier to value of property list item "bankIdentifier" of property list item "attributes" of property list item i + on error errStr number errorNumber + log "WARNING: " & errStr & ". MoneyMoney Attribute 'bankIdentifier' not set for account " & accountName + set bankIdentifier to "Sonstige" + end try - try - set accountName to value of property list item "name" of property list item i - set bankIdentifier to value of property list item "bankIdentifier" of property list item "attributes" of property list item i set balances to value of property list item "balance" of property list item i repeat with balance in balances -- @todo make addition work also for different currencies, at the moment we assume all is the same currency my IncreaseBankBalance(bankIdentifier, get first item of balance, balancePerBankList) end repeat - on error errStr number errorNumber - log "WARNING: " & errStr & ". Probably MoneyMoney Attribute 'bankIdentifier' not set for account " & accountName & ". Skipping.." - end try + end if end repeat end tell end tell From 1273608f4ab5f7c3afc35d7bdac34f61865a03ee Mon Sep 17 00:00:00 2001 From: Christoph Massmann <cm@vianetz.com> Date: Thu, 4 Jan 2024 11:27:44 +0100 Subject: [PATCH 2/2] migrated Apple Script to Python for easier maintenance --- README.md | 55 ++++++------ moneymoney-sum-by-bank.py | 49 +++++++++++ moneymoney-sum-by-bank.scpt | 162 ------------------------------------ requirements.txt | 1 + 4 files changed, 74 insertions(+), 193 deletions(-) create mode 100644 moneymoney-sum-by-bank.py delete mode 100644 moneymoney-sum-by-bank.scpt create mode 100644 requirements.txt diff --git a/README.md b/README.md index 8ccfbb4..f48496f 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,43 @@ # MoneyMoney Extension: Sum by Bank -This is an AppleScript extension for the great [MoneyMoney software](https://moneymoney-app.com/) to generate an Excel list with all sums by bank account. +This is a Pyton script for the great [MoneyMoney software](https://moneymoney-app.com/) to generate a list with all balances by bank account. This is useful e.g. to export the total values per bank to a summary Excel document or to monitor certain threshold values per bank. ## Installation -For this AppleScript to work it is required to add a custom attribute `bankIdentifier` to each account in MoneyMoney -that you want to track. The total values are then summed up by this chosen bank identifier. +``` +pip install -r requirements.txt +``` -At the beginning of the Apple Script file `moneymney-sum-by-bank.scpt` you can then customize the behaviour of the script: - -|Variable|Description| -|--------|-----------| -|`exportFileName`|The name of the resulting Excel file. You can either use an existing file or leave it to missing value to create a new one.| -|`startRowIndex`/`startColumnIndex`|The index of the cell row/column to start the table.| -|`isSortDescending`|Whether to sort the resulting sums in a descending order or not.| -|`isCloseExcel`|Whether to close Excel after the export.| -|`cellThresholdValue`|Threshold value above that the cell is colored| -|`cellThresholdColor`|Threshold background color value| - -If you optionally want to use this AppleScript within the services menu of the _MoneyMoney_ application, the best way is to use the [Mac Automator](https://support.apple.com/de-de/guide/automator/aut73234890a/mac): +On Mac if you (optionally) want to use this Python script within the services menu of the _MoneyMoney_ application, the best way is to use the [Mac Automator](https://support.apple.com/de-de/guide/automator/aut73234890a/mac): 1. Create a new "Quick Action Workflow" in Automator -1. Choose "No Input" in "MoneyMoney" -1. Add the action "Execute AppleScript" and paste the contents of the file `moneymoney-sum-by-bank.scpt` into the text box -1. Save the workflow +2. Choose "No Input" in "MoneyMoney" +3. Add the action "Execute AppleScript" and paste this script into the text box and adapt the script path accordingly: + ```applescript + on run {input, parameters} + tell application "Terminal" + do script "python3 ~/path/to/script/moneymoney-sum-by-bank.py && read -s -n 1 key && exit 0" + end tell + + return input + end run + ``` +4. Save the workflow Then you have a new menu item with the chosen name in _MoneyMoney > Services_. ## Usage -After click on the new menu item in _MoneyMoney > Services_, Microsoft Excel will open and show all bank sums in a descending order: - - -As an alternative you can also simply double click on the `moneymney-sum-by-bank.scpt` script to execute it manually. +**Note:** The MoneyMoney application has to be unlocked when executing the script otherwise an error will be thrown. -For more information see also [my blog post](https://dev-investor.de/finanz-apps/money-money/maximum-pro-bank-extension/). - -## Notes +This Python script sums all account balances from MoneyMoney by BIC. If a BIC is not available (e.g. in case of an offline or a credit card account), +the script looks for a custom attribute `bankIdentifier` in the account settings and uses this as reference. +If neither of this information is available on the account and it has a balance, the value is added to "other". -- Tested with Excel for Mac 16.43/16.64 -- The MoneyMoney application has to be unlocked when executing the script otherwise an error will be thrown -- Basically a better way would be to automatically group by account bic but not all accounts do have a bic (e.g. credit cards). +The result of the Python script can e.g. be used in Excel: + -## Known Limitations -- Support only for Euro currency -- Accounts with no `bankIdentifier` attribute are ignored in export file +For more information see also [my blog post](https://dev-investor.de/finanz-apps/money-money/maximum-pro-bank-extension/). ## License diff --git a/moneymoney-sum-by-bank.py b/moneymoney-sum-by-bank.py new file mode 100644 index 0000000..78a4207 --- /dev/null +++ b/moneymoney-sum-by-bank.py @@ -0,0 +1,49 @@ +import pandas as pd +import plistlib +import subprocess +import logging + + +def run_apple_script(script): + command = ['osascript', '-e', script] + with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as pipe: + result = pipe.communicate() + if result[1]: + raise Exception('Could not run Apple Script: %s' % result[1].decode().strip()) + + return result + + +# @see https://moneymoney-app.com/applescript/ +def fetch_moneymoney_accounts() -> {}: + result = run_apple_script('tell application "MoneyMoney" to export accounts') + + # Parse XML property list. + try: + plist = plistlib.loads(result[0]) + except plistlib.InvalidFileException as exception: + raise Exception('Could not parse XML property list. %s' % repr(exception)) + + return plist + + +def moneymoney_sum_by_account() -> pd.DataFrame: + balance_per_bank_and_currency = [] + for account in fetch_moneymoney_accounts(): + if account['portfolio'] is True or account['group'] is True: + continue + + if not account['bankCode']: + account['bankCode'] = account['attributes']['bankIdentifier'] if 'bankIdentifier' in account['attributes'] else 'other' + logging.debug("Account %s has no bank code, using '%s'" % (account["name"], account['bankCode'])) + + for balance in account['balance']: + balance_per_bank_and_currency.append([account['bankCode'], balance[0], balance[1]]) + + df = pd.DataFrame(balance_per_bank_and_currency, columns=['bank', 'balance', 'currency']) + return df.groupby(['bank', 'currency']).agg({'balance': 'sum'}) + + +#logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) +df = moneymoney_sum_by_account() +print(df[df['balance'] > 0].sort_values(by='balance', ascending=False)) diff --git a/moneymoney-sum-by-bank.scpt b/moneymoney-sum-by-bank.scpt deleted file mode 100644 index a095e30..0000000 --- a/moneymoney-sum-by-bank.scpt +++ /dev/null @@ -1,162 +0,0 @@ ------------------------- --- CONFIGURATION - -global exportFileName, startRowIndex, startColumnIndex, isSortDescending, isCloseExcel, cellThresholdValue, cellThresholdColor - --- The name of the resulting Excel file. You can either use an existing file or leave it to missing value to create a new one. -set exportFileName to missing value - --- The index of the cell row/column to start the table. -set startRowIndex to 1 -set startColumnIndex to 1 - --- Whether to sort the resulting sums in a descending order or not. -set isSortDescending to true - --- Whether to close Excel after the export. -set isCloseExcel to false - --- Threshold value above that the cell is colored -set cellThresholdValue to 100000 -set cellThresholdColor to {255, 244, 233} ------------------------- - -global tmpDir --- Note: we do not use "path to temporary items from user domain" because - despite the call - this is not in the user space! -set tmpDir to (path to library folder from user domain as text) & "Caches:" - --- Export all accounts from MoneyMoney application into temporary folder. --- The temporary folder is necessary because the plist result of the "export accounts" command cannot be processed easily --- with AppleScript otherwise. -on ExportAccounts() - tell application "MoneyMoney" - set accounts to export accounts - end tell - - -- @todo check if there is any other way than to temporary safe the plist file - set UUID to do shell script "uuidgen" - set accountsPropertyListFile to (tmpDir & UUID & ".plist") - set accountsPropertyListFilePosix to POSIX path of accountsPropertyListFile - - open for access file the accountsPropertyListFile with write permission - write (accounts) to file the accountsPropertyListFile as «class utf8» - close access file the accountsPropertyListFile - - log "Accounts file has been generated to " & accountsPropertyListFilePosix - - return accountsPropertyListFilePosix -end ExportAccounts - -on DeleteFile(fileName) - log "INFO: removing temporary file " & fileName - - -- this statement returns an error if parameter fileName is not a real file - -- this way we prohibit removing a whole directory - do shell script "test -f " & fileName as POSIX file - - tell application "System Events" to delete alias fileName -end DeleteFile - --- Increase the balance value of the given bank in the balancePerBankList list -on IncreaseBankBalance(bankIdentifier, balance, balancePerBankList) - log "INFO: Increase bank balance of " & bankIdentifier & " by " & balance - - repeat with a from 1 to the count of balancePerBankList - if bankIdentifier of item a of balancePerBankList is bankIdentifier then - set newBalance to (balance of item a of balancePerBankList) + balance - log "DEBUG: Found existing balance. Set new balance to " & newBalance - set item a of balancePerBankList to {bankIdentifier:bankIdentifier, balance:newBalance} - - return balancePerBankList - end if - end repeat - - set the end of balancePerBankList to {bankIdentifier:bankIdentifier, balance:balance} - return balancePerBankList -end IncreaseBankBalance - --- Sum up all bank balances in the given plist file from MoneyMoney -on SumBankBalancesFromPlist(accountsPropertyListFile) - -- balancePerBankList is an object like {{bankIdentifier: "DKB", balance: 200, bankIdentifier: "Commerzbank", balance: 99, ..} - set balancePerBankList to {} - - tell application "System Events" - tell property list file accountsPropertyListFile - repeat with i from 1 to number of property list items - set accountName to value of property list item "name" of property list item i - - set isGroup to value of property list item "group" of property list item i - if isGroup is false then - try - set bankIdentifier to value of property list item "bankIdentifier" of property list item "attributes" of property list item i - on error errStr number errorNumber - log "WARNING: " & errStr & ". MoneyMoney Attribute 'bankIdentifier' not set for account " & accountName - set bankIdentifier to "Sonstige" - end try - - set balances to value of property list item "balance" of property list item i - repeat with balance in balances - -- @todo make addition work also for different currencies, at the moment we assume all is the same currency - my IncreaseBankBalance(bankIdentifier, get first item of balance, balancePerBankList) - end repeat - end if - end repeat - end tell - end tell - - if balancePerBankList is {} then - error "Temporary property list file " & accountsPropertyListFile & " could not be read or no MoneyMoney accounts with attribute 'bankIdentifier' exists." - end if - - return balancePerBankList -end SumBankBalancesFromPlist - --- Open Microsoft Excel application, insert bank sums and format and sort accordingly -on OpenExcelWithData(bankBalances) - tell application "Microsoft Excel" - activate - if (exportFileName is missing value) then - make new workbook - else - open exportFileName - end if - -- - set x to startRowIndex - - repeat with balanceData in bankBalances - set balance to balance of balanceData - set bank to bankIdentifier of balanceData - - set value of cell x of column startColumnIndex to balance - set value of cell x of column (startColumnIndex + 1) to bank - - if (balance > cellThresholdValue) then - set color of interior object of cell x of column startColumnIndex to cellThresholdColor - end if - - set x to (x + 1) - end repeat - - set number format of column startColumnIndex to "#,##0.00 €" - - if (isSortDescending is true) then - set sortingRange to "" & startRowIndex & ":" & x - sort range sortingRange key1 cell 1 of column startColumnIndex order1 sort descending - end if - - if (exportFileName is not missing value) then - save yes - end if - - if (isCloseExcel is true) then - close active workbook - end if - end tell -end OpenExcelWithData - -set accountsPropertyListFile to ExportAccounts() -set bankBalances to SumBankBalancesFromPlist(accountsPropertyListFile) - -OpenExcelWithData(bankBalances) - -DeleteFile(accountsPropertyListFile) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1411a4a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pandas \ No newline at end of file