-
Notifications
You must be signed in to change notification settings - Fork 28
Microsoft Money Mapping File
Microsoft Money does not provide a way to export all transactions for all accounts to an OFX or QIF file. It only allows exporting one account at a time. The can be so unwieldy as to totally prevent one from exporting all data and importing it to other personal finance software. However, csv2ofx can provide a nice solution.
The solution consists of 3 steps:
1. generate an MS Money report for all transactions in all accounts and save as a CSV file.
2. process the CSV file with csv2ofx to create a single OFX or QIF file with all your MS Money data.
3. import the resulting data into any other personal finance software such as GnuCash.
Details
To generate an MS Money report and save as a CSV file, see this link
To process the CSV file created by MS Money, use the following csv2ofx_custom.py file:
(watch out for formatting issues caused by the wiki. If you have a problem with this file, click “edit” on the wiki page and copy the original text between the code tags).
from csvutils import *
def yodlee_dscr(row,grid):&
" use user description for payee 1st, the original description"
od=fromCSVCol(row,grid,‘Original Description’)
ud=fromCSVCol(row,grid,‘User Description’)
if len(ud)>0:
return “%s – %s” % (od,ud)
return oddef yodlee_memo(row,grid):
memo=fromCSVCol(row,grid,‘Memo’) # sometimes None
cat=fromCSVCol(row,grid,‘Category’)
cls=fromCSVCol(row,grid,‘Classification’)
if len(memo)>0:
return “%s – %s – %s” % ( memo, cat, cls)
return “%s – %s” % ( cat, cls )def msmoney_memo(row,grid):
memo=fromCSVCol(row,grid,‘Memo’) # sometimes None
cat=fromCSVCol(row,grid,‘Category’)
cls=fromCSVCol(row,grid,‘Projects’)
if len(memo)>0:
return “%s – %s – %s” % ( memo, cat, cls)
return “%s – %s” % ( cat, cls )def parse_payee(row,grid):
payee=fromCSVCol(row,grid,‘Payee’)
if len(payee)>0:
return payee
return “unknown payee”def toOFXDate(date):
if len(date)>0:
yearlen=len(date.split(‘/’)[-1])
return datetime.strptime(date,yearlen==2 and ‘%m/%d/%y’ or ‘%Y-%m-%d’).strftime(‘%m-%d-%Y’)
return ""yodlee = {
‘OFX’:{ ‘skip’:lambda row,grid: fromCSVCol(row,grid,‘Split Type’) == ‘Split’, ‘BANKID’:lambda row,grid: fromCSVCol(row,grid,‘Account Name’).split(’ – ’)0, ‘ACCTID’:lambda row,grid: fromCSVCol(row,grid,‘Account Name’).split(’ – ’)[-1], ‘DTPOSTED’:lambda row,grid: toOFXDate(fromCSVCol(row,grid,‘Date’)), ‘TRNAMT’:lambda row,grid: fromCSVCol(row,grid,‘Amount’), ‘FITID’:lambda row,grid: fromCSVCol(row,grid,‘Transaction Id’), ‘PAYEE’:lambda row,grid: yodlee_dscr(row,grid), ‘MEMO’:lambda row,grid: yodlee_memo(row,grid), ‘CURDEF’:lambda row,grid: fromCSVCol(row,grid,‘Currency’), ‘CHECKNUM’:lambda row,grid: fromCSVCol(row,grid,‘Transaction Id’) }, ‘QIF’:{ ‘split’:lambda row,grid: fromCSVCol(row,grid,‘Split Type’) == ‘Split’, ‘Account’:lambda row,grid: fromCSVCol(row,grid,‘Account Name’), ‘AccountDscr’:lambda row,grid: ’ ‘.join(fromCSVCol(row,grid,’Account Name’).split(‘-’)[1:]), ‘Date’:lambda row,grid: fromCSVCol(row,grid,‘Date’), ‘Payee’:lambda row,grid: fromCSVCol(row,grid,‘Original Description’), ‘Memo’:lambda row,grid: fromCSVCol(row,grid,‘User Description’) + ’ ’ + fromCSVCol(row,grid,‘Memo’), ‘Category’:lambda row,grid: fromCSVCol(row,grid,‘Category’)‘-’fromCSVCol(row,grid,‘Classification’), ‘Class’:lambda row,grid: ’’, ‘Amount’:lambda row,grid: fromCSVCol(row,grid,‘Amount’), ‘Number’:lambda row,grid: ‘na’ }}
cu = {
‘OFX’:{
‘skip’:lambda row,grid: False,
‘BANKID’:lambda row,grid: ‘Credit Union’,
‘ACCTID’:lambda row,grid: ‘My Account’,
‘DTPOSTED’:lambda row,grid: toOFXDate(fromCSVCol(row,grid,‘Date’)),
‘TRNAMT’:lambda row,grid: fromCSVCol(row,grid,‘Amount’).replace(‘$’,‘’),
’FITID’:lambda row,grid: row,
‘PAYEE’:lambda row,grid: fromCSVCol(row,grid,‘Description’),
‘MEMO’:lambda row,grid: fromCSVCol(row,grid,‘Comments’),
‘CURDEF’:lambda row,grid: ‘USD’,
‘CHECKNUM’:lambda row,grid: fromCSVCol(row,grid,‘Check Number’)
},
‘QIF’:{
‘split’:lambda row,grid:False,
‘Account’:lambda row,grid: ‘Credit Union’,
‘AccountDscr’:lambda row,grid: ‘Credit Union Account’,
‘Date’:lambda row,grid: fromCSVCol(row,grid,‘Date’),
‘Payee’:lambda row,grid: fromCSVCol(row,grid,‘Description’),
‘Memo’:lambda row,grid: fromCSVCol(row,grid,‘Comments’),
‘Category’:lambda row,grid:‘Unclassified’,
‘Class’:lambda row,grid:‘’,
’Amount’:lambda row,grid:fromCSVCol(row,grid,‘Amount’),
‘Number’:lambda row,grid:fromCSVCol(row,grid,‘Check Number’)
}
}msmoneyrep = {
‘OFX’:{ ‘skip’:lambda row,grid: fromCSVCol(row,grid,‘Split Type’) == ‘Split’, ‘BANKID’:lambda row,grid: fromCSVCol(row,grid,‘Account Name’).split(’ – ’)0, ‘ACCTID’:lambda row,grid: fromCSVCol(row,grid,‘Account Name’).split(’ – ’)[-1], ‘DTPOSTED’:lambda row,grid: toOFXDate(fromCSVCol(row,grid,‘Date’)), ‘TRNAMT’:lambda row,grid: fromCSVCol(row,grid,‘Amount’), ‘FITID’:lambda row,grid: fromCSVCol(row,grid,‘Num’), ‘PAYEE’:lambda row,grid: fromCSVCol(row,grid,‘Payee’), ‘MEMO’:lambda row,grid: msmoney_memo(row,grid), ‘CURDEF’:lambda row,grid: fromCSVCol(row,grid,‘Currency’), ‘CHECKNUM’:lambda row,grid: fromCSVCol(row,grid,‘Num’) }, ‘QIF’:{ #‘skip’:lambda row,grid: fromCSVCol(row,grid,‘Date’) == ’’, #no skip function in QIF ‘split’:lambda row,grid: fromCSVCol(row,grid,‘Date’) == ’’, #split should be determined by absence of date and other fields. ‘Account’:lambda row,grid: fromCSVCol(row,grid,‘Account’), ‘AccountDscr’:lambda row,grid: fromCSVCol(row,grid,‘Account’), ‘Date’:lambda row,grid: toOFXDate(fromCSVCol(row,grid,‘Date’)), ‘Payee’:lambda row,grid: parse_payee(row,grid), ‘Memo’:lambda row,grid: fromCSVCol(row,grid,‘C’) + ‘: ’ + fromCSVCol(row,grid,’Memo’), ‘Category’:lambda row,grid: fromCSVCol(row,grid,‘Category’), ‘Class’:lambda row,grid: fromCSVCol(row,grid,‘Projects’), ‘Amount’:lambda row,grid: fromCSVCol(row,grid,‘Amount’), ‘Number’:lambda row,grid: fromCSVCol(row,grid,‘Num’) }}
all_mappings = {’Yodlee’:yodlee, ‘Credit Union’:cu, ‘MS Money Report (CSV)’:msmoneyrep}