Well, I have had limited success.
I wrote a simple (and embarrassing ) utility that scans my Quicken 2006 QIF 'all-export' file and appends a unique identifier at the end of the Payee field for transactions that would fall into this case. i.e. real transactions that would not be imported because they look too similar.
I could not attach my source code or binary. Copy and paste from the quote below if interested in trying it.
Compile by
- Code: Select all
g++ duplicateDefender.cpp -o duplicateDefender
Run with
- Code: Select all
./duplicateDefender "Quicken all export file.qif"
That will produce output.qif.
One way you can diff and compare is:
- Code: Select all
diff 'Quicken all export file.qif' output.qif
Its not smooth sailing from here however. As I mentioned, I am trying to move over ten years of transactions in 30 accounts.
I was excited to see the previously mentioned missing transactions were present. The account balances were still not correct.
Ultimately, I had to go through every account scanning around in comparison to my open Quicken register. I found about thirty transfer transactions that appeared twice in the registers and a handful of cases where two similar transaction should exist, but again only one was imported. It was fairly easy, but time consuming, to delete these duplicate transfers. (Easier than typing them in if they had been totally missing.) These remaining problems were not the transactions modified by my utility.
Another big, and unresolved problem remains. My investment account transactions did not import. Basically all I got was the cash transactions. No securities buys / sells, etc. I even tried importing a QIF file with only one investment accounts transactions. No luck. I see that the buys / sells are listed in the QIF file.
Can anyone offer any advice with this problem?I tried to search the forums myself for help on the investment thing. 'investment import' is too common a search phrase so no luck. Please reduce this sensitivity with the forum back-end. I've seen that error too many times already.
By the way, I am in part embarrassed because so many things could break with my utility if used on a QIF file structured in ways other than what I had right in front of me. Example sensitivities are the order that the D P M T fields appear in a record, where in the file the 'transactions' are listed, and the new line character used. If you try it, I suggest running a diff on the input and output file. Hopefully you only see the desired appends made to similar transactions.
- Code: Select all
/**
* duplicateDefender.cpp
* Appends unique tag at the end of adjacent similar transactions
* that might be filtered out by the MyMoney program
* on import.
*
* Usage: ./duplicateDefender 'quicken export file.qif'
* Will produce a output file: output.qif that has the desired modifications to problematic transactions.
*/
#include <iostream>
#include <fstream>
using namespace std;
const char LINE_SEP_CHAR = '\r'; // Quicken outputs file with cr character, not newline. This little inflexibility with the newline
// function could turn out to be quite cripling for usefullness with other programs.
int main(int argc, char* argv[])
{
for (int i=0; i<argc; i++) {
cout << "arg " << i << ": " << argv[i] << endl;
}
if (argc != 2 )
{
cerr << "Expected one input argument, the file name of the QIF file to scan. If this file has any spaces, inclose the filename in quotes." << endl;
return -1;
}
const char * inputFile = argv[1];
ifstream instream;
instream.open( inputFile );
if ( ! instream.is_open() )
{
cerr << "Unable to open input file: " << inputFile << endl;
return -1;
}
ofstream ostream;
string outputFile("output.qif");
ostream.open( outputFile.c_str(), fstream::trunc );
if ( ! ostream.is_open() )
{
cerr << "Unable to open output file: " << outputFile << endl;
return -1;
}
/* scan through the file identifying transaction and saving last date, amount, and payee.
* Upon finding subsequent matching transactions, permute the subsequent payee by appending
* unique string to the end of Payee.
*/
string lastPayee, lastAmount, lastDate, lastMemo;
const int MAX_LINE_LENGTH = 512;
char lineArray[MAX_LINE_LENGTH];
int linenumber = 0;
bool match = false;
int unique_counter = 0;
int fieldMatchesThisRecord(0);
bool startedTransactionSection = false;
string transactionStartString( "POpening Balance" );
do {
linenumber++;
instream.getline( lineArray, MAX_LINE_LENGTH, LINE_SEP_CHAR );
if (! startedTransactionSection) {
if (transactionStartString == lineArray) {
startedTransactionSection = true;
}
}
if (startedTransactionSection) {
switch (lineArray[0]) {
case 'D':
if ((lastDate == lineArray) && (strlen(lineArray)>1) ) {
//cout << "match " << endl;
match = true;
} else
{
match = false;
lastDate = lineArray;
}
fieldMatchesThisRecord++;
break;
case 'P':
if ((lastPayee == lineArray) && (strlen(lineArray)>1)) {
//cout << "match " << endl;
match = match && true;
} else
{
match = false;
lastPayee = lineArray;
}
fieldMatchesThisRecord++;
break;
case 'M':
lastMemo = lineArray;
break;
case 'T':
if ((lastAmount == lineArray) && (strlen(lineArray)>1)) {
//cout << "match " << endl;
match = match && true;
} else
{
match = false;
lastAmount = lineArray;
}
fieldMatchesThisRecord++;
/* at this point, we can decide if we should modify the payee field when there is a match, and dump these four fields out to output stream */
ostream << lastDate << endl;
if ( match && (fieldMatchesThisRecord == 3) ) {
ostream << lastPayee << " UNIQUIFY" << unique_counter++ << endl;
cout << "Matched Transaction modified: " << lastDate << " " << lastPayee << endl;
}
else
ostream << lastPayee << endl;
ostream << lastMemo << endl << lastAmount << endl;
break;
case '^':
fieldMatchesThisRecord = 0;
match = false; // resets for next transaction
// deliberately continuing to default
default:
// for non-critical lines, dump straight to output stream
ostream << lineArray << endl;
break;
}
}
else
ostream << lineArray << endl;
if (instream.fail()) {
cout << "istream fail detected. Actually ok at very end of file. " << endl;
}
} while ( !instream.eof() );
instream.close();
return 0;
}