207
210
SKGTRACEINRC(2, "SKGImportExportManager::exportQIF", err);
208
211
SKGTRACEL(10) << "Input filename=" << fileName << endl;
211
QFile file(fileName);
212
if (!file.open(QIODevice::WriteOnly)) {
213
err.setReturnCode(ERR_INVALIDARG);
214
err.setMessage(tr("Save file [%1] failed").arg(fileName));
216
QTextStream stream(&file);
217
SKGTRACEL(2) << "Text codec=" << QTextCodec::codecForLocale ()->name() << endl;
219
err=document->beginTransaction("#INTERNAL#", 2);
220
if (err.isSucceeded()) {
223
SKGObjectBase::SKGListSKGObjectBase categories;
224
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "v_category_display_tmp", "1=1 ORDER BY t_fullname, id", categories);
225
int nbcat=categories.count();
226
if (err.isSucceeded() && nbcat) {
227
stream << "!Type:Cat\n";
228
err=document->beginTransaction("#INTERNAL#", nbcat);
229
for (int i=0; err.isSucceeded() && i<nbcat; ++i) {
230
SKGCategoryObject cat=categories.at(i);
231
stream << "N" << cat.getFullName() << endl;
232
if (SKGServices::stringToDouble(cat.getAttribute("f_REALCURRENTAMOUNT"))<0) {
233
stream << "E" << endl;
235
stream << "I" << endl;
215
QFile file(fileName);
216
if (!file.open(QIODevice::WriteOnly)) {
217
err.setReturnCode(ERR_INVALIDARG);
218
err.setMessage(tr("Save file [%1] failed").arg(fileName));
220
QTextStream stream(&file);
221
SKGTRACEL(2) << "Text codec=" << QTextCodec::codecForLocale ()->name() << endl;
223
err=document->beginTransaction("#INTERNAL#", 2);
224
if (err.isSucceeded()) {
227
SKGObjectBase::SKGListSKGObjectBase categories;
228
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "v_category_display_tmp", "1=1 ORDER BY t_fullname, id", categories);
229
int nbcat=categories.count();
230
if (err.isSucceeded() && nbcat) {
231
stream << "!Type:Cat\n";
232
err=document->beginTransaction("#INTERNAL#", nbcat);
233
for (int i=0; err.isSucceeded() && i<nbcat; ++i) {
234
SKGCategoryObject cat=categories.at(i);
235
stream << "N" << cat.getFullName() << endl;
236
if (SKGServices::stringToDouble(cat.getAttribute("f_REALCURRENTAMOUNT"))<0) {
237
stream << "E" << endl;
239
stream << "I" << endl;
241
stream << "^" << endl;
242
if (err.isSucceeded()) err=document->stepForward(i+1);
237
stream << "^" << endl;
238
if (err.isSucceeded()) err=document->stepForward(i+1);
245
if (err.isSucceeded()) err=document->endTransaction(true);
246
else document->endTransaction(false);
241
if (err.isSucceeded()) err=document->endTransaction(true);
242
else document->endTransaction(false);
244
if (err.isSucceeded()) err=document->stepForward(1);
247
QString currentAccountName;
248
SKGObjectBase::SKGListSKGObjectBase operations;
249
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "v_operation_display", "1=1 ORDER BY t_ACCOUNT, d_date, id", operations);
250
int nb=operations.count();
251
if (err.isSucceeded()) {
252
err=document->beginTransaction("#INTERNAL#", nb);
253
for (int i=0; err.isSucceeded() && i<nb; ++i) {
254
SKGOperationObject operation=operations.at(i);
257
QString accountName=operation.getAttribute("t_ACCOUNT");
259
//In the same account ?
260
if (accountName!=currentAccountName) {
261
SKGAccountObject account(document);
262
account.setName(accountName);
266
account.getBank(bank);
269
stream << "!Account\n";
270
stream << 'N' << accountName << endl;
271
stream << 'T' << account.getType() << endl;
272
QString number=bank.getNumber();
273
QString bnumber=account.getAgencyNumber();
274
QString cnumber=account.getNumber();
275
if (!bnumber.isEmpty()) {
276
if (!number.isEmpty()) number+='-';
279
if (!cnumber.isEmpty()) {
280
if (!number.isEmpty()) number+='-';
283
stream << 'D' << number << endl;
284
//stream << "/" Statement balance date
285
//stream << "$" Statement balance amount
286
stream << '^' << endl;
287
currentAccountName=accountName;
289
stream << "!Type:Bank\n";
297
N/A U Transaction amount (higher possible value than T)
298
DONE C Cleared status
299
DONE N Number (check or reference number)
300
DONE P Payee/description
302
N/A A Address (up to 5 lines; 6th line is an optional message)
303
DONE L Category (category/class or transfer/class)
304
DONE S Category in split (category/class or transfer/class)
306
DONE $ Dollar amount of split
307
N/A % Percentage of split if percentages are used
308
N/A F Reimbursable business expense flag
309
N/A X Small Business extensions
313
stream << 'D' << SKGServices::dateToSqlString(QDateTime(operation.getDate())) << endl;
314
stream << 'T' << SKGServices::doubleToString(operation.getCurrentAmount()) << endl;
316
int number=operation.getNumber();
317
if (number) stream << 'N' << operation.getNumber() << endl;
319
QString payee=operation.getPayee();
320
if (payee.length()) stream << 'P' << payee << endl;
322
QString memo=operation.getMode()+" "+operation.getComment();
324
if (memo.length()) stream << 'M' << memo << endl;
326
SKGOperationObject::OperationStatus status=operation.getStatus();
327
stream << "C" << (status==SKGOperationObject::POINTED ? "C": (status==SKGOperationObject::CHECKED ? "R": "" )) << endl;
330
SKGObjectBase::SKGListSKGObjectBase suboperations;
331
err=operation.getSubOperations(suboperations);
332
if (err.isSucceeded()) {
333
int nb=suboperations.size();
336
for (int i=0; i<nb; ++i) {
337
SKGSubOperationObject suboperation=suboperations.at(i);
248
if (err.isSucceeded()) err=document->stepForward(1);
251
QString currentAccountName;
252
SKGObjectBase::SKGListSKGObjectBase operations;
253
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "v_operation_display", "1=1 ORDER BY t_ACCOUNT, d_date, id", operations);
254
int nb=operations.count();
255
if (err.isSucceeded()) {
256
err=document->beginTransaction("#INTERNAL#", nb);
257
for (int i=0; err.isSucceeded() && i<nb; ++i) {
258
SKGOperationObject operation=operations.at(i);
261
QString accountName=operation.getAttribute("t_ACCOUNT");
263
//In the same account ?
264
if (accountName!=currentAccountName) {
265
SKGAccountObject account(document);
266
account.setName(accountName);
270
account.getBank(bank);
273
stream << "!Account\n";
274
stream << 'N' << accountName << endl;
275
stream << 'T' << account.getType() << endl;
276
QString number=bank.getNumber();
277
QString bnumber=account.getAgencyNumber();
278
QString cnumber=account.getNumber();
279
if (!bnumber.isEmpty()) {
280
if (!number.isEmpty()) number+='-';
283
if (!cnumber.isEmpty()) {
284
if (!number.isEmpty()) number+='-';
287
stream << 'D' << number << endl;
288
//stream << "/" Statement balance date
289
//stream << "$" Statement balance amount
290
stream << '^' << endl;
291
currentAccountName=accountName;
293
stream << "!Type:Bank\n";
301
N/A U Transaction amount (higher possible value than T)
302
DONE C Cleared status
303
DONE N Number (check or reference number)
304
DONE P Payee/description
306
N/A A Address (up to 5 lines; 6th line is an optional message)
307
DONE L Category (category/class or transfer/class)
308
DONE S Category in split (category/class or transfer/class)
310
DONE $ Dollar amount of split
311
N/A % Percentage of split if percentages are used
312
N/A F Reimbursable business expense flag
313
N/A X Small Business extensions
317
stream << 'D' << SKGServices::dateToSqlString(QDateTime(operation.getDate())) << endl;
318
stream << 'T' << SKGServices::doubleToString(operation.getCurrentAmount()) << endl;
320
int number=operation.getNumber();
321
if (number) stream << 'N' << operation.getNumber() << endl;
323
QString payee=operation.getPayee();
324
if (payee.length()) stream << 'P' << payee << endl;
326
QString memo=operation.getMode()+" "+operation.getComment();
328
if (memo.length()) stream << 'M' << memo << endl;
330
SKGOperationObject::OperationStatus status=operation.getStatus();
331
stream << "C" << (status==SKGOperationObject::POINTED ? "C": (status==SKGOperationObject::CHECKED ? "R": "" )) << endl;
334
SKGObjectBase::SKGListSKGObjectBase suboperations;
335
err=operation.getSubOperations(suboperations);
336
if (err.isSucceeded()) {
337
int nb=suboperations.size();
340
for (int i=0; i<nb; ++i) {
341
SKGSubOperationObject suboperation=suboperations.at(i);
342
SKGCategoryObject cat;
343
suboperation.getCategory(cat);
345
QString category=cat.getFullName();
346
if (category.length()) stream << 'S' << category << endl;
347
stream << '$' << SKGServices::doubleToString(suboperation.getQuantity()) << endl;
351
SKGSubOperationObject suboperation=suboperations.at(0);
338
352
SKGCategoryObject cat;
339
353
suboperation.getCategory(cat);
341
355
QString category=cat.getFullName();
342
if (category.length()) stream << 'S' << category << endl;
343
stream << '$' << SKGServices::doubleToString(suboperation.getQuantity()) << endl;
356
if (category.length()) stream << 'L' << category << endl;
347
SKGSubOperationObject suboperation=suboperations.at(0);
348
SKGCategoryObject cat;
349
suboperation.getCategory(cat);
351
QString category=cat.getFullName();
352
if (category.length()) stream << 'L' << category << endl;
360
stream << '^' << endl;
361
if (err.isSucceeded()) err=document->stepForward(i+1);
356
stream << '^' << endl;
357
if (err.isSucceeded()) err=document->stepForward(i+1);
364
if (err.isSucceeded()) err=document->endTransaction(true);
365
else document->endTransaction(false);
367
if (err.isSucceeded()) err=document->stepForward(2);
360
368
if (err.isSucceeded()) err=document->endTransaction(true);
361
369
else document->endTransaction(false);
363
if (err.isSucceeded()) err=document->stepForward(2);
364
if (err.isSucceeded()) err=document->endTransaction(true);
365
else document->endTransaction(false);
372
377
if (err.isFailed()) {
373
378
err.addError(ERR_FAIL, tr("%1 failed").arg("SKGImportExportManager::exportQIF"));
678
687
SKGTRACEL(10) << "Input filename=" << fileName << endl;
680
689
//Begin transaction
681
err=document->beginTransaction("#INTERNAL#", 3);
682
if (err.isSucceeded()) {
683
//Create account if needed
684
QDateTime now=QDateTime::currentDateTime();
685
QString postFix=SKGServices::dateToSqlString(now);
688
if (getCSVMapping().count()==0) {
689
err= setCSVMapping(NULL);
690
if (err.isSucceeded()) err=document->sendMessage(tr("Use automatic CSV mapping detection"));
694
if (err.isSucceeded()) err=document->stepForward(1);
691
err=document->beginTransaction("#INTERNAL#", 3);
697
692
if (err.isSucceeded()) {
698
QFile file(fileName);
699
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
700
err.setReturnCode(ERR_INVALIDARG);
701
err.setMessage(tr("Open file [%1] failed").arg(fileName));
703
QTextStream stream(&file);
704
if (!codec.isEmpty()) stream.setCodec(codec.toAscii().constData());
706
//Ignore useless lines
707
int headerIndex=getCSVHeaderIndex();
708
for (int i=0; i<=headerIndex; ++i)
714
int posdate=csvMapping.indexOf("date");
716
while (!stream.atEnd()) {
718
QString line=stream.readLine().trimmed();
719
if (!line.isEmpty()) {
720
lines.push_back(line);
723
QStringList field=SKGServices::splitCSVLine(line);
724
if (posdate<field.count()) dates.push_back(field.at(posdate));
733
QString dateFormat=SKGServices::getDateFormat(dates);
734
if (dateFormat.isEmpty()) {
735
err.setReturnCode(ERR_FAIL);
736
err.setMessage(tr("Date format not supported"));
738
if (err.isSucceeded())
739
err=document->sendMessage(tr("Import of [%1] with code [%2] and date format [%3]").arg(fileName).arg(codec).arg(dateFormat));
742
if (err.isSucceeded()) err=document->stepForward(2);
745
if (err.isSucceeded()) {
747
err=document->beginTransaction("#INTERNAL#", nb);
749
//Save last mapping used in a settings
751
int nbMap=csvMapping.count();
752
for (int i=0; i<nbMap;++i) {
753
if (i) mappingDesc+='|';
754
mappingDesc+=csvMapping.at(i);
756
if (err.isSucceeded()) err=document->setParameter("SKG_LAST_CSV_MAPPING_USED", mappingDesc);
758
SKGUnitObject defUnit;
759
SKGAccountObject defAccount;
760
int nbOperationsNotImported=0;
761
for (int i = 0; err.isSucceeded() && i < nb; ++i) {
762
SKGOperationObject currentOperation(document);
763
SKGSubOperationObject currentSubOperation(document);
765
//Valuate mandatory attribute with default value
766
if (csvMapping.indexOf("unit")==-1) {
767
err=getDefaultUnit(defUnit);
768
if (err.isSucceeded()) err=currentOperation.setUnit(defUnit);
770
if (err.isSucceeded() && csvMapping.indexOf("account")==-1) {
771
err=getDefaultAccount(defAccount);
772
if (err.isSucceeded()) err=currentOperation.setParentAccount(defAccount);
775
QString line=lines.at(i);
776
QByteArray hash = QCryptographicHash::hash(line.toUtf8(), QCryptographicHash::Md5);
778
SKGObjectBase opWithThisHash;
779
if (SKGObjectBase::getObject(document, "operation", "t_imported='Y' AND t_import_id='"+QString(hash.toHex())+'\'', opWithThisHash).isSucceeded()) nbOperationsNotImported++;
781
QStringList atts=SKGServices::splitCSVLine(line);
782
int nbcol=csvMapping.count();
783
for (int c=0; err.isSucceeded() && c<nbcol; ++c) {
784
QString col=csvMapping[c];
785
int pos=csvMapping.indexOf(col);
787
if (pos!=-1) val=atts.at(pos).trimmed();
789
err=currentOperation.setDate(SKGServices::stringToTime(SKGServices::dateToSqlString(val, dateFormat)).date());
790
} else if (col=="number") {
791
if (!val.isEmpty()) err=currentOperation.setNumber(SKGServices::stringToInt(val));
792
} else if (col=="mode") {
793
err=currentOperation.setMode(val);
794
} else if (col=="payee") {
795
err=currentOperation.setPayee(val);
796
} else if (col=="comment") {
797
err=currentOperation.setComment(val);
798
} else if (col=="status") {
799
err=currentOperation.setStatus(val=="C" ? SKGOperationObject::CHECKED : val=="P" ? SKGOperationObject::POINTED :SKGOperationObject::NONE);
800
} else if (col=="bookmarked") {
801
err=currentOperation.bookmark(val=="Y");
802
} else if (col=="amount" && !csvMapping.contains("quantity")) {
803
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
804
} else if (col=="quantity") {
805
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
806
} else if (col=="sign") {
807
if (val=="DEBIT" || val=="-") { // krazy:exclude=doublequote_chars
808
double cval=currentSubOperation.getQuantity();
809
if (cval>0) err=currentSubOperation.setQuantity(-cval);
811
} else if (col=="unit") {
813
SKGUnitObject unit(document);
814
if (val!=defUnit.getName()) { //For performance
815
err=unit.setName(val);
816
if (err.isSucceeded()) err=unit.setSymbol(val);
817
if (err.isSucceeded() && unit.load().isFailed()) err=unit.save(false); //Save only
819
//This unit is now the default one, it's better for performance
825
SKGUnitValueObject unitval;
826
if (err.isSucceeded()) err=unit.addUnitValue(unitval);
827
if (err.isSucceeded()) {
828
int posAmount=csvMapping.indexOf("amount");
829
int posQuantity=csvMapping.indexOf("quantity");
830
if (posAmount!=-1 && posQuantity!=-1) {
831
err=unitval.setQuantity(SKGServices::stringToDouble(atts.at(posAmount))/SKGServices::stringToDouble(atts.at(posQuantity)));
693
//Create account if needed
694
QDateTime now=QDateTime::currentDateTime();
695
QString postFix=SKGServices::dateToSqlString(now);
698
if (getCSVMapping().count()==0) {
699
err= setCSVMapping(NULL);
700
if (err.isSucceeded()) err=document->sendMessage(tr("Use automatic CSV mapping detection"));
704
if (err.isSucceeded()) err=document->stepForward(1);
707
if (err.isSucceeded()) {
708
QFile file(fileName);
709
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
710
err.setReturnCode(ERR_INVALIDARG);
711
err.setMessage(tr("Open file [%1] failed").arg(fileName));
713
QTextStream stream(&file);
714
if (!codec.isEmpty()) stream.setCodec(codec.toAscii().constData());
716
//Ignore useless lines
717
int headerIndex=getCSVHeaderIndex();
718
for (int i=0; i<=headerIndex; ++i)
724
int posdate=csvMapping.indexOf("date");
726
while (!stream.atEnd()) {
728
QString line=stream.readLine().trimmed();
729
if (!line.isEmpty()) {
730
lines.push_back(line);
733
QStringList field=SKGServices::splitCSVLine(line);
734
if (posdate<field.count()) dates.push_back(field.at(posdate));
743
QString dateFormat=SKGServices::getDateFormat(dates);
744
if (dateFormat.isEmpty()) {
745
err.setReturnCode(ERR_FAIL);
746
err.setMessage(tr("Date format not supported"));
748
if (err.isSucceeded())
749
err=document->sendMessage(tr("Import of [%1] with code [%2] and date format [%3]").arg(fileName).arg(codec).arg(dateFormat));
752
if (err.isSucceeded()) err=document->stepForward(2);
755
if (err.isSucceeded()) {
757
err=document->beginTransaction("#INTERNAL#", nb);
759
//Save last mapping used in a settings
761
int nbMap=csvMapping.count();
762
for (int i=0; i<nbMap;++i) {
763
if (i) mappingDesc+='|';
764
mappingDesc+=csvMapping.at(i);
766
if (err.isSucceeded()) err=document->setParameter("SKG_LAST_CSV_MAPPING_USED", mappingDesc);
768
SKGUnitObject defUnit;
769
SKGAccountObject defAccount;
770
int nbOperationsNotImported=0;
771
for (int i = 0; err.isSucceeded() && i < nb; ++i) {
772
SKGOperationObject currentOperation(document);
773
SKGSubOperationObject currentSubOperation(document);
775
//Valuate mandatory attribute with default value
776
if (csvMapping.indexOf("unit")==-1) {
777
err=getDefaultUnit(defUnit);
778
if (err.isSucceeded()) err=currentOperation.setUnit(defUnit);
780
if (err.isSucceeded() && csvMapping.indexOf("account")==-1) {
781
err=getDefaultAccount(defAccount);
782
if (err.isSucceeded()) err=currentOperation.setParentAccount(defAccount);
785
QString line=lines.at(i);
786
QByteArray hash = QCryptographicHash::hash(line.toUtf8(), QCryptographicHash::Md5);
788
SKGObjectBase opWithThisHash;
789
if (SKGObjectBase::getObject(document, "operation", "t_imported='Y' AND t_import_id='"+QString(hash.toHex())+'\'', opWithThisHash).isSucceeded()) nbOperationsNotImported++;
791
QStringList atts=SKGServices::splitCSVLine(line);
792
int nbcol=csvMapping.count();
793
for (int c=0; err.isSucceeded() && c<nbcol; ++c) {
794
QString col=csvMapping[c];
795
int pos=csvMapping.indexOf(col);
797
if (pos!=-1) val=atts.at(pos).trimmed();
799
err=currentOperation.setDate(SKGServices::stringToTime(SKGServices::dateToSqlString(val, dateFormat)).date());
800
} else if (col=="number") {
801
if (!val.isEmpty()) err=currentOperation.setNumber(SKGServices::stringToInt(val));
802
} else if (col=="mode") {
803
err=currentOperation.setMode(val);
804
} else if (col=="payee") {
805
err=currentOperation.setPayee(val);
806
} else if (col=="comment") {
807
err=currentOperation.setComment(val);
808
} else if (col=="status") {
809
err=currentOperation.setStatus(val=="C" ? SKGOperationObject::CHECKED : val=="P" ? SKGOperationObject::POINTED :SKGOperationObject::NONE);
810
} else if (col=="bookmarked") {
811
err=currentOperation.bookmark(val=="Y");
812
} else if (col=="amount" && !csvMapping.contains("quantity")) {
813
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
814
} else if (col=="quantity") {
815
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
816
} else if (col=="sign") {
817
if (val=="DEBIT" || val=="-") { // krazy:exclude=doublequote_chars
818
double cval=currentSubOperation.getQuantity();
819
if (cval>0) err=currentSubOperation.setQuantity(-cval);
821
} else if (col=="unit") {
823
SKGUnitObject unit(document);
824
if (val!=defUnit.getName()) { //For performance
825
err=unit.setName(val);
826
if (err.isSucceeded()) err=unit.setSymbol(val);
827
if (err.isSucceeded() && unit.load().isFailed()) err=unit.save(false); //Save only
829
//This unit is now the default one, it's better for performance
833
err=unitval.setQuantity(1);
836
if (err.isSucceeded()) err=unitval.setDate(now.date());
837
if (err.isSucceeded()) err=unitval.save();
838
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
839
} else if (col=="account") {
840
//Looking for account
841
if (val!=defAccount.getName()) { //For performance
842
SKGAccountObject account(document);
843
account.setName(val);
845
if (err.isFailed()) {
846
//Not found, we have to create one
847
SKGBankObject bank(document);
848
QString name=tr("Bank for import %1").arg(postFix);
849
err=bank.setName(name);
850
if (err.isSucceeded() && bank.load().isFailed()) {
851
err=bank.save(false); //Save only
852
if (err.isSucceeded()) err=document->sendMessage(tr("Default bank [%1] created for import").arg(name));
854
if (err.isSucceeded()) err=bank.addAccount(account);
855
if (err.isSucceeded()) err=account.setName(val);
856
if (err.isSucceeded() && account.load().isFailed()) err=account.save(false); //Save only
859
//This account is now the default one, it's better for performance
862
if (err.isSucceeded()) err=currentOperation.setParentAccount(defAccount);
863
} else if (col=="category") {
865
if (!val.isEmpty()) {
866
SKGCategoryObject Category;
867
val.replace('/', OBJECTSEPARATOR);
868
val.replace(':', OBJECTSEPARATOR);
869
val.replace(',', OBJECTSEPARATOR);
870
val.replace(';', OBJECTSEPARATOR);
871
err=SKGCategoryObject::createPathCategory(document,val, Category);
872
if (err.isSucceeded()) err=currentSubOperation.setCategory(Category);
835
SKGUnitValueObject unitval;
836
if (err.isSucceeded()) err=unit.addUnitValue(unitval);
837
if (err.isSucceeded()) {
838
int posAmount=csvMapping.indexOf("amount");
839
int posQuantity=csvMapping.indexOf("quantity");
840
if (posAmount!=-1 && posQuantity!=-1) {
841
err=unitval.setQuantity(SKGServices::stringToDouble(atts.at(posAmount))/SKGServices::stringToDouble(atts.at(posQuantity)));
843
err=unitval.setQuantity(1);
846
if (err.isSucceeded()) err=unitval.setDate(now.date());
847
if (err.isSucceeded()) err=unitval.save();
848
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
849
} else if (col=="account") {
850
//Looking for account
851
if (val!=defAccount.getName()) { //For performance
852
SKGAccountObject account(document);
853
account.setName(val);
855
if (err.isFailed()) {
856
//Not found, we have to create one
857
SKGBankObject bank(document);
858
QString name=tr("Bank for import %1").arg(postFix);
859
err=bank.setName(name);
860
if (err.isSucceeded() && bank.load().isFailed()) {
861
err=bank.save(false); //Save only
862
if (err.isSucceeded()) err=document->sendMessage(tr("Default bank [%1] created for import").arg(name));
864
if (err.isSucceeded()) err=bank.addAccount(account);
865
if (err.isSucceeded()) err=account.setName(val);
866
if (err.isSucceeded() && account.load().isFailed()) err=account.save(false); //Save only
869
//This account is now the default one, it's better for performance
872
if (err.isSucceeded()) err=currentOperation.setParentAccount(defAccount);
873
} else if (col=="category") {
875
if (!val.isEmpty()) {
876
SKGCategoryObject Category;
877
val.replace('/', OBJECTSEPARATOR);
878
val.replace(':', OBJECTSEPARATOR);
879
val.replace(',', OBJECTSEPARATOR);
880
val.replace(';', OBJECTSEPARATOR);
881
err=SKGCategoryObject::createPathCategory(document,val, Category);
882
if (err.isSucceeded()) err=currentSubOperation.setCategory(Category);
888
if (err.isSucceeded()) err=currentOperation.setAttribute("t_imported", "P");
889
if (err.isSucceeded()) err=currentOperation.setImportID(hash.toHex());
891
if (err.isSucceeded()) err=currentOperation.save(false); //Save only
892
if (err.isSucceeded()) err=currentSubOperation.setParentOperation(currentOperation);
893
if (err.isSucceeded()) err=currentSubOperation.save(false, false); //Save only without reload
878
if (err.isSucceeded()) err=currentOperation.setAttribute("t_imported", "P");
879
if (err.isSucceeded()) err=currentOperation.setImportID(hash.toHex());
881
if (err.isSucceeded()) err=currentOperation.save(false); //Save only
882
if (err.isSucceeded()) err=currentSubOperation.setParentOperation(currentOperation);
883
if (err.isSucceeded()) err=currentSubOperation.save(false, false); //Save only without reload
895
if (err.isSucceeded() && i%20==0) err = SKGServices::executeSqliteOrder(document, "ANALYZE");
896
if (err.isSucceeded()) err=document->stepForward(i+1);
885
if (err.isSucceeded() && i%20==0) err = SKGServices::executeSqliteOrder(document, "ANALYZE");
886
if (err.isSucceeded()) err=document->stepForward(i+1);
898
if (err.isSucceeded()) err = SKGServices::executeSqliteOrder(document, "UPDATE operation SET t_imported='Y' WHERE t_imported='P'");
900
if (err.isSucceeded()) err=document->endTransaction(true);
901
else document->endTransaction(false);
903
if (err.isSucceeded() && nbOperationsNotImported)
904
err=document->sendMessage(tr("%1 operation(s) not imported because already existing").arg(nbOperationsNotImported));
907
if (err.isSucceeded()) err=document->stepForward(3);
888
if (err.isSucceeded()) err = SKGServices::executeSqliteOrder(document, "UPDATE operation SET t_imported='Y' WHERE t_imported='P'");
890
if (err.isSucceeded()) err=document->endTransaction(true);
891
else document->endTransaction(false);
893
if (err.isSucceeded() && nbOperationsNotImported)
894
err=document->sendMessage(tr("%1 operation(s) not imported because already existing").arg(nbOperationsNotImported));
897
if (err.isSucceeded()) err=document->stepForward(3);
912
if (err.isSucceeded()) err=document->endTransaction(true);
913
else document->endTransaction(false);
902
if (err.isSucceeded()) err=document->endTransaction(true);
903
else document->endTransaction(false);
905
916
if (err.isFailed()) {
906
917
err.addError(ERR_FAIL, tr("%1 failed").arg("SKGImportExportManager::importCSV"));
1246
1262
//http://web.intuit.com/support/quicken/docs/d_qif.html
1248
1264
//Begin transaction
1249
err=document->beginTransaction("#INTERNAL#", 3);
1250
if (err.isSucceeded()) {
1251
//Create account if needed
1252
QDateTime now=QDateTime::currentDateTime();
1253
QString postFix=SKGServices::dateToSqlString(now);
1256
if (err.isSucceeded()) err=document->stepForward(1);
1259
QFile file(fileName);
1260
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1261
err.setReturnCode(ERR_INVALIDARG);
1262
err.setMessage(tr("Open file [%1] failed").arg(fileName));
1264
QTextStream stream(&file);
1265
if (!codec.isEmpty()) stream.setCodec(codec.toAscii().constData());
1267
//load file in memory
1270
bool inAccountSection=false;
1271
while (!stream.atEnd()) {
1273
//Check line if line is empty or is a commented
1274
QString line=stream.readLine().trimmed();
1275
if (line.length()>0 && line[0]!='#') {
1276
lines.push_back(line);
1277
//Manage !Account section
1278
if (line=="^" && inAccountSection) {
1279
inAccountSection=false;
1280
} else if (QString::compare(line, "!account", Qt::CaseInsensitive)==0) {
1281
inAccountSection=true;
1284
//We try to find automatically the date format
1285
else if (!inAccountSection &&line[0]=='D') {
1286
dates.push_back(line.right(line.length()-1));
1295
QString dateFormat=SKGServices::getDateFormat(dates);
1296
if (dateFormat.isEmpty()) {
1297
err.setReturnCode(ERR_FAIL);
1298
err.setMessage(tr("Date format not supported"));
1300
if (err.isSucceeded())
1301
err=document->sendMessage(tr("Import of [%1] with code [%2] and date format [%3]").arg(fileName).arg(codec).arg(dateFormat));
1304
if (err.isSucceeded()) err=document->stepForward(2);
1307
if (err.isSucceeded()) {
1308
SKGOperationObject currentOperation;
1309
SKGSubOperationObject currentSubOperation;
1310
QDate currentOperationDate;
1311
bool latestSubCatMustBeRemoved=false;
1312
QChar inSection='B';
1313
bool investmentAccount=false;
1314
int quantityFactor=1;
1315
QString currentUnitForInvestment;
1316
int nbOperationsNotImported=0;
1317
double currentUnitPrice=1;
1319
int nb=lines.size();
1320
err=document->beginTransaction("#INTERNAL#", nb);
1321
SKGAccountObject* account=NULL;
1322
QString stringForHash;
1323
for (int i = 0; err.isSucceeded() && i < nb; ++i) {
1324
QString line=lines.at(i);
1327
if (line.length()>1) {
1328
val=line.right(line.length()-1).trimmed();
1331
//Manage !Account section
1332
if (QString::compare(line, "!type:bank", Qt::CaseInsensitive)==0 ||
1333
QString::compare(line, "!type:cash", Qt::CaseInsensitive)==0 ||
1334
QString::compare(line, "!type:ccash", Qt::CaseInsensitive)==0 ||
1335
QString::compare(line, "!type:ccard", Qt::CaseInsensitive)==0 ||
1336
QString::compare(line, "!type:oth a", Qt::CaseInsensitive)==0 ||
1337
QString::compare(line, "!type:invst", Qt::CaseInsensitive)==0) {
1339
investmentAccount=(QString::compare(val, "type:invst", Qt::CaseInsensitive)==0);
1340
} else if (QString::compare(line, "!account", Qt::CaseInsensitive)==0) {
1342
} else if (QString::compare(line, "!type:cat", Qt::CaseInsensitive)==0) {
1344
if (err.isSucceeded()) err=document->sendMessage(tr("Categories found and imported"));
1345
} else if (line.at(0)=='!') {
1347
} else if (inSection=='C') {
1350
SKGCategoryObject Category;
1351
val.replace('/', OBJECTSEPARATOR);
1352
val.replace(':', OBJECTSEPARATOR);
1353
val.replace(',', OBJECTSEPARATOR);
1354
val.replace(';', OBJECTSEPARATOR);
1355
err=SKGCategoryObject::createPathCategory(document,val, Category);
1357
} else if (inSection=='A') {
1360
//Check if the account already exist
1361
SKGAccountObject account2;
1362
err=SKGNamedObject::getObjectByName(document, "account", val, account2);
1363
if (err.isFailed()) {
1365
SKGBankObject bank(document);
1366
err=bank.setName(tr("Bank for import %1").arg(postFix));
1367
if (err.isSucceeded() && bank.load().isFailed()) err=bank.save(false);
1368
if (err.isSucceeded()) err=bank.addAccount(account2);
1369
if (err.isSucceeded()) err=account2.setName(val);
1370
if (err.isSucceeded() && account2.load().isFailed()) err=account2.save(false); //Save only
1373
if (err.isSucceeded()) {
1378
account=new SKGAccountObject(account2);
1380
} else if (op=='D') {
1381
if (account) err=account->setNumber(val);
1382
} else if (op=='^') {
1385
if (account) err=account->save();
1387
} else if (inSection=='B') {
1388
//Operation creation
1390
>>>> Items for Non-Investment Accounts <<<<
1393
U Transaction amount (higher possible value than T)
1394
DONE C Cleared status
1395
DONE N Number (check or reference number)
1396
DONE P Payee/description
1398
A Address (up to 5 lines; 6th line is an optional message)
1399
DONE L Category (category/class or transfer/class)
1400
DONE S Category in split (category/class or transfer/class)
1402
DONE $ Dollar amount of split
1403
TODO % Percentage of split if percentages are used
1404
F Reimbursable business expense flag
1405
X Small Business extensions
1408
>>>> Items for Investment Accounts <<<<
1413
DONE Q Quantity (number of shares or split ratio)
1414
DONE T Transaction amount
1415
DONE C Cleared status
1416
P Text in the first line for transfers and reminders
1419
L Account for the transfer
1420
$ Amount transferred
1423
stringForHash+=line;
1266
err=document->beginTransaction("#INTERNAL#", 3);
1267
if (err.isSucceeded()) {
1268
//Create account if needed
1269
QDateTime now=QDateTime::currentDateTime();
1270
QString postFix=SKGServices::dateToSqlString(now);
1273
if (err.isSucceeded()) err=document->stepForward(1);
1276
QFile file(fileName);
1277
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1278
err.setReturnCode(ERR_INVALIDARG);
1279
err.setMessage(tr("Open file [%1] failed").arg(fileName));
1281
QTextStream stream(&file);
1282
if (!codec.isEmpty()) stream.setCodec(codec.toAscii().constData());
1284
//load file in memory
1287
bool inAccountSection=false;
1288
while (!stream.atEnd()) {
1290
//Check line if line is empty or is a commented
1291
QString line=stream.readLine().trimmed();
1292
if (line.length()>0 && line[0]!='#') {
1293
lines.push_back(line);
1294
//Manage !Account section
1295
if (line=="^" && inAccountSection) {
1296
inAccountSection=false;
1297
} else if (QString::compare(line, "!account", Qt::CaseInsensitive)==0) {
1298
inAccountSection=true;
1301
//We try to find automatically the date format
1302
else if (!inAccountSection &&line[0]=='D') {
1303
dates.push_back(line.right(line.length()-1));
1312
QString dateFormat=SKGServices::getDateFormat(dates);
1313
if (dateFormat.isEmpty()) {
1314
err.setReturnCode(ERR_FAIL);
1315
err.setMessage(tr("Date format not supported"));
1317
if (err.isSucceeded())
1318
err=document->sendMessage(tr("Import of [%1] with code [%2] and date format [%3]").arg(fileName).arg(codec).arg(dateFormat));
1321
if (err.isSucceeded()) err=document->stepForward(2);
1324
if (err.isSucceeded()) {
1325
SKGOperationObject currentOperation;
1326
SKGSubOperationObject currentSubOperation;
1327
QDate currentOperationDate;
1328
bool latestSubCatMustBeRemoved=false;
1329
QChar inSection='B';
1330
bool investmentAccount=false;
1331
int quantityFactor=1;
1332
QString currentUnitForInvestment;
1333
int nbOperationsNotImported=0;
1334
double currentUnitPrice=1;
1336
int nb=lines.size();
1337
err=document->beginTransaction("#INTERNAL#", nb);
1338
SKGAccountObject* account=NULL;
1339
QString stringForHash;
1340
for (int i = 0; err.isSucceeded() && i < nb; ++i) {
1341
QString line=lines.at(i);
1344
if (line.length()>1) {
1345
val=line.right(line.length()-1).trimmed();
1348
//Manage !Account section
1349
if (QString::compare(line, "!type:bank", Qt::CaseInsensitive)==0 ||
1350
QString::compare(line, "!type:cash", Qt::CaseInsensitive)==0 ||
1351
QString::compare(line, "!type:ccash", Qt::CaseInsensitive)==0 ||
1352
QString::compare(line, "!type:ccard", Qt::CaseInsensitive)==0 ||
1353
QString::compare(line, "!type:oth a", Qt::CaseInsensitive)==0 ||
1354
QString::compare(line, "!type:invst", Qt::CaseInsensitive)==0) {
1356
investmentAccount=(QString::compare(val, "type:invst", Qt::CaseInsensitive)==0);
1357
} else if (QString::compare(line, "!account", Qt::CaseInsensitive)==0) {
1359
} else if (QString::compare(line, "!type:cat", Qt::CaseInsensitive)==0) {
1361
if (err.isSucceeded()) err=document->sendMessage(tr("Categories found and imported"));
1362
} else if (line.at(0)=='!') {
1364
} else if (inSection=='C') {
1367
SKGCategoryObject Category;
1368
val.replace('/', OBJECTSEPARATOR);
1369
val.replace(':', OBJECTSEPARATOR);
1370
val.replace(',', OBJECTSEPARATOR);
1371
val.replace(';', OBJECTSEPARATOR);
1372
err=SKGCategoryObject::createPathCategory(document,val, Category);
1374
} else if (inSection=='A') {
1377
//Check if the account already exist
1378
SKGAccountObject account2;
1379
err=SKGNamedObject::getObjectByName(document, "account", val, account2);
1380
if (err.isFailed()) {
1382
SKGBankObject bank(document);
1383
err=bank.setName(tr("Bank for import %1").arg(postFix));
1384
if (err.isSucceeded() && bank.load().isFailed()) err=bank.save(false);
1385
if (err.isSucceeded()) err=bank.addAccount(account2);
1386
if (err.isSucceeded()) err=account2.setName(val);
1387
if (err.isSucceeded() && account2.load().isFailed()) err=account2.save(false); //Save only
1390
if (err.isSucceeded()) {
1395
account=new SKGAccountObject(account2);
1397
} else if (op=='D') {
1398
if (account) err=account->setNumber(val);
1399
} else if (op=='^') {
1402
if (account) err=account->save();
1404
} else if (inSection=='B') {
1405
//Operation creation
1427
Dates in US QIF files are usually in the format MM/DD/YY, although
1428
four-digit years are not uncommon. Dates sometimes occur without the
1429
slash separator, or using other separators in place of the slash,
1430
commonly '-' and '.'. US Quicken seems to be using the ' to indicate
1431
post-2000 two-digit years (such as 01/01'00 for Jan 1 2000). Some
1432
banks appear to be using a completely undifferentiated numeric QString
1433
formateed YYYYMMDD in downloaded QIF files.
1407
>>>> Items for Non-Investment Accounts <<<<
1410
U Transaction amount (higher possible value than T)
1411
DONE C Cleared status
1412
DONE N Number (check or reference number)
1413
DONE P Payee/description
1415
A Address (up to 5 lines; 6th line is an optional message)
1416
DONE L Category (category/class or transfer/class)
1417
DONE S Category in split (category/class or transfer/class)
1419
DONE $ Dollar amount of split
1420
TODO % Percentage of split if percentages are used
1421
F Reimbursable business expense flag
1422
X Small Business extensions
1425
>>>> Items for Investment Accounts <<<<
1430
DONE Q Quantity (number of shares or split ratio)
1431
DONE T Transaction amount
1432
DONE C Cleared status
1433
P Text in the first line for transfers and reminders
1436
L Account for the transfer
1437
$ Amount transferred
1435
//Operation creation
1436
if (err.isSucceeded()) {
1437
if (account!=NULL) err=account->addOperation(currentOperation);
1440
stringForHash+=line;
1444
Dates in US QIF files are usually in the format MM/DD/YY, although
1445
four-digit years are not uncommon. Dates sometimes occur without the
1446
slash separator, or using other separators in place of the slash,
1447
commonly '-' and '.'. US Quicken seems to be using the ' to indicate
1448
post-2000 two-digit years (such as 01/01'00 for Jan 1 2000). Some
1449
banks appear to be using a completely undifferentiated numeric QString
1450
formateed YYYYMMDD in downloaded QIF files.
1452
//Operation creation
1453
if (err.isSucceeded()) {
1454
if (account!=NULL) err=account->addOperation(currentOperation);
1456
SKGAccountObject defAccount;
1457
err=getDefaultAccount(defAccount);
1458
if (err.isSucceeded()) err=defAccount.addOperation(currentOperation);
1463
currentOperationDate=SKGServices::stringToTime(SKGServices::dateToSqlString(val, dateFormat)).date();
1464
if (err.isSucceeded()) err=currentOperation.setDate(currentOperationDate);
1467
if (err.isSucceeded()) {
1468
//Create unit if needed
1470
err=getDefaultUnit(unit, ¤tOperationDate);
1471
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
1474
if (err.isSucceeded()) currentOperation.save();
1476
//Create suboperation
1477
if (err.isSucceeded()) err=currentOperation.addSubOperation(currentSubOperation);
1478
} else if (op=='Y') {
1480
currentUnitForInvestment=val;
1482
SKGUnitObject unit(document);
1483
err = unit.setName(currentUnitForInvestment);
1484
if (unit.load().isFailed()) {
1485
if (err.isSucceeded()) err = unit.setSymbol(currentUnitForInvestment);
1486
if (err.isSucceeded()) err = unit.setType(SKGUnitObject::SHARE);
1487
if (err.isSucceeded()) err = unit.save(false); //Save only
1489
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
1490
} else if (op=='O') {
1492
SKGOperationObject commission;
1493
if (account!=NULL) err=account->addOperation(commission);
1439
1495
SKGAccountObject defAccount;
1440
1496
err=getDefaultAccount(defAccount);
1441
if (err.isSucceeded()) err=defAccount.addOperation(currentOperation);
1446
currentOperationDate=SKGServices::stringToTime(SKGServices::dateToSqlString(val, dateFormat)).date();
1447
if (err.isSucceeded()) err=currentOperation.setDate(currentOperationDate);
1450
if (err.isSucceeded()) {
1451
//Create unit if needed
1453
err=getDefaultUnit(unit, ¤tOperationDate);
1454
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
1457
if (err.isSucceeded()) currentOperation.save();
1459
//Create suboperation
1460
if (err.isSucceeded()) err=currentOperation.addSubOperation(currentSubOperation);
1461
} else if (op=='Y') {
1463
currentUnitForInvestment=val;
1465
SKGUnitObject unit(document);
1466
err = unit.setName(currentUnitForInvestment);
1467
if (unit.load().isFailed()) {
1468
if (err.isSucceeded()) err = unit.setSymbol(currentUnitForInvestment);
1469
if (err.isSucceeded()) err = unit.setType(SKGUnitObject::SHARE);
1470
if (err.isSucceeded()) err = unit.save(false); //Save only
1472
if (err.isSucceeded()) err=currentOperation.setUnit(unit);
1473
} else if (op=='O') {
1475
SKGOperationObject commission;
1476
if (account!=NULL) err=account->addOperation(commission);
1478
SKGAccountObject defAccount;
1479
err=getDefaultAccount(defAccount);
1480
if (err.isSucceeded()) err=defAccount.addOperation(commission);
1482
if (err.isSucceeded()) err=commission.setDate(currentOperationDate);
1483
if (err.isSucceeded()) err=commission.setAttribute("t_imported", "P");
1484
if (err.isSucceeded()) {
1485
//Create unit if needed
1487
err=getDefaultUnit(unit, ¤tOperationDate);
1488
if (err.isSucceeded()) err=commission.setUnit(unit);
1490
if (err.isSucceeded()) err=commission.save(); //Save only
1491
if (err.isSucceeded()) err=currentOperation.setGroupOperation(commission);
1493
SKGSubOperationObject subcommission;
1494
if (err.isSucceeded()) err=commission.addSubOperation(subcommission);
1495
if (err.isSucceeded()) err=subcommission.setQuantity(-SKGServices::stringToDouble(val));
1496
if (err.isSucceeded()) err=subcommission.save(false, false); //Save only whitout reload
1497
} else if (op=='I') {
1499
currentUnitPrice=SKGServices::stringToDouble(val);
1500
err=document->addOrModifyUnitValue(currentUnitForInvestment,
1501
currentOperationDate,
1503
} else if (op=='N') {
1504
if (investmentAccount) {
1509
Aktab Same as ShrsOut.
1510
AktSplit Same as StkSplit.
1511
Aktzu Same as ShrsIn.
1513
BuyX Buy shares. Used with an L line.
1514
Cash Miscellaneous cash transaction. Used with an L line.
1515
CGMid Mid-term capital gains.
1516
CGMidX Mid-term capital gains. For use with an L line.
1517
CGLong Long-term capital gains.
1518
CGLongX Long-term capital gains. For use with an L line.
1519
CGShort Short-term capital gains.
1520
CGShortX Short-term capital gains. For use with an L line.
1521
ContribX Same as XIn. Used for tax-advantaged accounts.
1522
CvrShrt Buy shares to cover a short sale.
1523
CvrShrtX Buy shares to cover a short sale. Used with an L line.
1524
Div Dividend received.
1525
DivX Dividend received. For use with an L line.
1526
Errinerg Same as Reminder.
1527
Exercise Exercise an option.
1528
ExercisX Exercise an option. For use with an L line.
1529
Expire Mark an option as expired. (Uses D, N, Y & M lines)
1530
Grant Receive a grant of stock options.
1532
IntX Same as IntIncX.
1533
IntInc Interest received.
1534
IntIncX Interest received. For use with an L line.
1535
K.gewsp Same as CGShort. (German)
1536
K.gewspX Same as CGShortX. (German)2307068
1537
Kapgew Same as CGLong. Kapitalgewinnsteuer.(German)
1538
KapgewX Same as CGLongX. Kapitalgewinnsteuer. (German)
1539
Kauf Same as Buy. (German)
1540
KaufX Same as BuyX. (German)
1541
MargInt Margin interest paid.
1542
MargIntX Margin interest paid. For use with an L line.
1543
MiscExp Miscellaneous expense.
1544
MiscExpX Miscellaneous expense. For use with an L line.
1545
MiscInc Miscellaneous income.
1546
MiscIncX Miscellaneous income. For use with an L line.
1547
ReinvDiv Reinvested dividend.
1548
ReinvInt Reinvested interest.
1549
ReinvLG Reinvested long-term capital gains.
1550
Reinvkur Same as ReinvLG.
1551
Reinvksp Same as ReinvSh.
1552
ReinvMd Reinvested mid-term capital gains.
1553
ReinvSG Same as ReinvSh.
1554
ReinvSh Reinvested short-term capital gains.
1555
Reinvzin Same as ReinvDiv.
1556
Reminder Reminder. (Uses D, N, C & M lines)
1557
RtrnCap Return of capital.
1558
RtrnCapX Return of capital. For use with an L line.
1560
SellX Sell shares. For use with an L line.
1562
ShrsIn Deposit shares.
1563
ShrsOut Withdraw shares.
1564
StkSplit Share split.
1565
Verkauf Same as Sell. (German)
1566
VerkaufX Same as SellX. (German)
1567
Vest Mark options as vested. (Uses N, Y, Q, C & M lines)
1568
WithDrwX Same as XOut. Used for tax-advantaged accounts.
1569
XIn Transfer cash from another account.
1570
XOut Transfer cash to another account.
1573
if (val.contains("sell") || val.contains("verkauf") || val.contains("miscexp")) quantityFactor=-1;
1497
if (err.isSucceeded()) err=defAccount.addOperation(commission);
1499
if (err.isSucceeded()) err=commission.setDate(currentOperationDate);
1500
if (err.isSucceeded()) err=commission.setAttribute("t_imported", "P");
1501
if (err.isSucceeded()) {
1502
//Create unit if needed
1504
err=getDefaultUnit(unit, ¤tOperationDate);
1505
if (err.isSucceeded()) err=commission.setUnit(unit);
1507
if (err.isSucceeded()) err=commission.save(); //Save only
1508
if (err.isSucceeded()) err=currentOperation.setGroupOperation(commission);
1510
SKGSubOperationObject subcommission;
1511
if (err.isSucceeded()) err=commission.addSubOperation(subcommission);
1512
if (err.isSucceeded()) err=subcommission.setQuantity(-SKGServices::stringToDouble(val));
1513
if (err.isSucceeded()) err=subcommission.save(false, false); //Save only whitout reload
1514
} else if (op=='I') {
1516
currentUnitPrice=SKGServices::stringToDouble(val);
1517
err=document->addOrModifyUnitValue(currentUnitForInvestment,
1518
currentOperationDate,
1520
} else if (op=='N') {
1521
if (investmentAccount) {
1526
Aktab Same as ShrsOut.
1527
AktSplit Same as StkSplit.
1528
Aktzu Same as ShrsIn.
1530
BuyX Buy shares. Used with an L line.
1531
Cash Miscellaneous cash transaction. Used with an L line.
1532
CGMid Mid-term capital gains.
1533
CGMidX Mid-term capital gains. For use with an L line.
1534
CGLong Long-term capital gains.
1535
CGLongX Long-term capital gains. For use with an L line.
1536
CGShort Short-term capital gains.
1537
CGShortX Short-term capital gains. For use with an L line.
1538
ContribX Same as XIn. Used for tax-advantaged accounts.
1539
CvrShrt Buy shares to cover a short sale.
1540
CvrShrtX Buy shares to cover a short sale. Used with an L line.
1541
Div Dividend received.
1542
DivX Dividend received. For use with an L line.
1543
Errinerg Same as Reminder.
1544
Exercise Exercise an option.
1545
ExercisX Exercise an option. For use with an L line.
1546
Expire Mark an option as expired. (Uses D, N, Y & M lines)
1547
Grant Receive a grant of stock options.
1549
IntX Same as IntIncX.
1550
IntInc Interest received.
1551
IntIncX Interest received. For use with an L line.
1552
K.gewsp Same as CGShort. (German)
1553
K.gewspX Same as CGShortX. (German)2307068
1554
Kapgew Same as CGLong. Kapitalgewinnsteuer.(German)
1555
KapgewX Same as CGLongX. Kapitalgewinnsteuer. (German)
1556
Kauf Same as Buy. (German)
1557
KaufX Same as BuyX. (German)
1558
MargInt Margin interest paid.
1559
MargIntX Margin interest paid. For use with an L line.
1560
MiscExp Miscellaneous expense.
1561
MiscExpX Miscellaneous expense. For use with an L line.
1562
MiscInc Miscellaneous income.
1563
MiscIncX Miscellaneous income. For use with an L line.
1564
ReinvDiv Reinvested dividend.
1565
ReinvInt Reinvested interest.
1566
ReinvLG Reinvested long-term capital gains.
1567
Reinvkur Same as ReinvLG.
1568
Reinvksp Same as ReinvSh.
1569
ReinvMd Reinvested mid-term capital gains.
1570
ReinvSG Same as ReinvSh.
1571
ReinvSh Reinvested short-term capital gains.
1572
Reinvzin Same as ReinvDiv.
1573
Reminder Reminder. (Uses D, N, C & M lines)
1574
RtrnCap Return of capital.
1575
RtrnCapX Return of capital. For use with an L line.
1577
SellX Sell shares. For use with an L line.
1579
ShrsIn Deposit shares.
1580
ShrsOut Withdraw shares.
1581
StkSplit Share split.
1582
Verkauf Same as Sell. (German)
1583
VerkaufX Same as SellX. (German)
1584
Vest Mark options as vested. (Uses N, Y, Q, C & M lines)
1585
WithDrwX Same as XOut. Used for tax-advantaged accounts.
1586
XIn Transfer cash from another account.
1587
XOut Transfer cash to another account.
1590
if (val.contains("sell") || val.contains("verkauf") || val.contains("miscexp")) quantityFactor=-1;
1591
err=currentOperation.setComment(val);
1592
if (err.isSucceeded()) err=currentOperation.setMode(tr("Title"));
1594
//N Num (check or reference number)
1597
int number=val.toInt(&ok);
1598
if (ok && number!=0) {
1599
err=currentOperation.setNumber(number);
1601
err=currentOperation.setMode(val);
1604
} else if (op=='Q') {
1605
//Q Quantity (number of shares or split ratio)
1607
err=currentSubOperation.setQuantity(quantityFactor*SKGServices::stringToDouble(val));
1608
} else if (op=='T') {
1611
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val)/currentUnitPrice);
1612
if (err.isSucceeded() && investmentAccount) {
1613
err=currentOperation.setProperty("SKG_OP_ORIGINAL_AMOUNT", val);
1615
} else if (op=='$') {
1616
//Dollar amount of split
1618
if (!investmentAccount) {
1619
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
1622
if (err.isSucceeded()) err=currentSubOperation.save();
1624
//Create suboperation
1625
if (err.isSucceeded()) err=currentOperation.addSubOperation(currentSubOperation);
1627
latestSubCatMustBeRemoved=true;
1629
} else if (op=='P') {
1632
//Clean QIF coming from bankperfect
1633
val.remove("[auto]");
1635
err=currentOperation.setPayee(val);
1636
} else if (op=='M') {
1574
1639
err=currentOperation.setComment(val);
1575
if (err.isSucceeded()) err=currentOperation.setMode(tr("Title"));
1577
//N Num (check or reference number)
1580
int number=val.toInt(&ok);
1581
if (ok && number!=0) {
1582
err=currentOperation.setNumber(number);
1640
} else if (op=='S' || op=='L') {
1641
//S Category in split (Category/Transfer/Class)//L Category (Category/Subcategory/Transfer/Class)
1642
//TODO LCategory of transaction
1643
//L[Transfer account]
1644
//LCategory of transaction/Class of transaction
1645
//L[Transfer account]/Class of transaction//Set Category
1646
SKGCategoryObject Category;
1647
val.replace('/', OBJECTSEPARATOR);
1648
val.replace(':', OBJECTSEPARATOR);
1649
val.replace(',', OBJECTSEPARATOR);
1650
val.replace(';', OBJECTSEPARATOR);
1651
err=SKGCategoryObject::createPathCategory(document,val, Category);
1652
if (err.isSucceeded()) err=currentSubOperation.setCategory(Category);
1653
} else if (op=='C') {
1656
err=currentOperation.setStatus((val=="C" ? SKGOperationObject::POINTED : (val=="R" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE )));
1657
} else if (op=='^') {
1661
QByteArray hash = QCryptographicHash::hash(stringForHash.toUtf8(), QCryptographicHash::Md5);
1662
SKGObjectBase opWithThisHash;
1663
if (SKGObjectBase::getObject(document, "operation", "t_imported='Y' AND t_import_id='"+QString(hash.toHex())+'\'', opWithThisHash).isSucceeded()) {
1664
err=currentOperation.remove();
1665
nbOperationsNotImported++;
1584
err=currentOperation.setMode(val);
1667
if (err.isSucceeded()) err=currentOperation.setAttribute("t_imported", "P");
1668
if (err.isSucceeded()) err=currentOperation.setImportID(hash.toHex());
1669
if (err.isSucceeded()) err=currentOperation.save();
1670
if (!latestSubCatMustBeRemoved && err.isSucceeded()) err=currentSubOperation.save();
1587
} else if (op=='Q') {
1588
//Q Quantity (number of shares or split ratio)
1590
err=currentSubOperation.setQuantity(quantityFactor*SKGServices::stringToDouble(val));
1591
} else if (op=='T') {
1594
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val)/currentUnitPrice);
1595
if (err.isSucceeded() && investmentAccount) {
1596
err=currentOperation.setProperty("SKG_OP_ORIGINAL_AMOUNT", val);
1598
} else if (op=='$') {
1599
//Dollar amount of split
1601
if (!investmentAccount) {
1602
err=currentSubOperation.setQuantity(SKGServices::stringToDouble(val));
1605
if (err.isSucceeded()) err=currentSubOperation.save();
1607
//Create suboperation
1608
if (err.isSucceeded()) err=currentOperation.addSubOperation(currentSubOperation);
1610
latestSubCatMustBeRemoved=true;
1612
} else if (op=='P') {
1615
//Clean QIF coming from bankperfect
1616
val.remove("[auto]");
1618
err=currentOperation.setPayee(val);
1619
} else if (op=='M') {
1622
err=currentOperation.setComment(val);
1623
} else if (op=='S' || op=='L') {
1624
//S Category in split (Category/Transfer/Class)//L Category (Category/Subcategory/Transfer/Class)
1625
//TODO LCategory of transaction
1626
//L[Transfer account]
1627
//LCategory of transaction/Class of transaction
1628
//L[Transfer account]/Class of transaction//Set Category
1629
SKGCategoryObject Category;
1630
val.replace('/', OBJECTSEPARATOR);
1631
val.replace(':', OBJECTSEPARATOR);
1632
val.replace(',', OBJECTSEPARATOR);
1633
val.replace(';', OBJECTSEPARATOR);
1634
err=SKGCategoryObject::createPathCategory(document,val, Category);
1635
if (err.isSucceeded()) err=currentSubOperation.setCategory(Category);
1636
} else if (op=='C') {
1639
err=currentOperation.setStatus((val=="C" ? SKGOperationObject::POINTED : (val=="R" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE )));
1640
} else if (op=='^') {
1644
QByteArray hash = QCryptographicHash::hash(stringForHash.toUtf8(), QCryptographicHash::Md5);
1645
SKGObjectBase opWithThisHash;
1646
if (SKGObjectBase::getObject(document, "operation", "t_imported='Y' AND t_import_id='"+QString(hash.toHex())+'\'', opWithThisHash).isSucceeded()) {
1647
err=currentOperation.remove();
1648
nbOperationsNotImported++;
1672
latestSubCatMustBeRemoved=false;
1673
currentUnitForInvestment="";
1650
if (err.isSucceeded()) err=currentOperation.setAttribute("t_imported", "P");
1651
if (err.isSucceeded()) err=currentOperation.setImportID(hash.toHex());
1652
if (err.isSucceeded()) err=currentOperation.save();
1653
if (!latestSubCatMustBeRemoved && err.isSucceeded()) err=currentSubOperation.save();
1678
// A Address (up to five lines; the sixth line is an optional message)
1655
latestSubCatMustBeRemoved=false;
1656
currentUnitForInvestment="";
1661
// A Address (up to five lines; the sixth line is an optional message)
1666
if (err.isSucceeded() && i%100==0) err = SKGServices::executeSqliteOrder(document, "ANALYZE");
1667
if (err.isSucceeded()) err=document->stepForward(i+1);
1670
if (err.isSucceeded()) err = SKGServices::executeSqliteOrder(document, "UPDATE operation SET t_imported='Y' WHERE t_imported='P'");
1676
if (err.isSucceeded()) err=document->endTransaction(true);
1677
else document->endTransaction(false);
1679
if (err.isSucceeded() && nbOperationsNotImported)
1680
err=document->sendMessage(tr("%1 operation(s) not imported because already existing").arg(nbOperationsNotImported));
1683
if (err.isSucceeded()) err=document->stepForward(3);
1683
if (err.isSucceeded() && i%100==0) err = SKGServices::executeSqliteOrder(document, "ANALYZE");
1684
if (err.isSucceeded()) err=document->stepForward(i+1);
1687
if (err.isSucceeded()) err = SKGServices::executeSqliteOrder(document, "UPDATE operation SET t_imported='Y' WHERE t_imported='P'");
1693
if (err.isSucceeded()) err=document->endTransaction(true);
1694
else document->endTransaction(false);
1696
if (err.isSucceeded() && nbOperationsNotImported)
1697
err=document->sendMessage(tr("%1 operation(s) not imported because already existing").arg(nbOperationsNotImported));
1700
if (err.isSucceeded()) err=document->stepForward(3);
1704
if (err.isSucceeded()) err=document->endTransaction(true);
1705
else document->endTransaction(false);
1687
if (err.isSucceeded()) err=document->endTransaction(true);
1688
else document->endTransaction(false);
1690
1708
if (err.isFailed()) {
1691
1709
err.addError(ERR_FAIL, tr("%1 failed").arg("SKGImportExportManager::importQIF"));
1797
1816
SKGTRACEINRC(2, "SKGImportExportManager::cleanBankPerfectImport", err);
1800
1818
//Begin transaction
1801
err=document->beginTransaction("#INTERNAL#", 5);
1802
if (err.isSucceeded()) {
1803
//Step 1 Clean cheque
1804
err=SKGServices::executeSqliteOrder(document, "UPDATE operation set t_mode='Cheque', t_comment='', i_number=substr(t_mode,4,1000)+0 where t_mode like 'Chq %'");
1805
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document, "UPDATE operation set t_mode='Cheque', t_comment='', i_number=substr(t_comment,3,1000)+0 where t_mode like 'Ch%' AND t_comment like 'n%'");
1808
if (err.isSucceeded()) err=document->stepForward(1);
1810
//TODO Step 2 [auto]
1813
if (err.isSucceeded()) err=document->stepForward(2);
1815
//Step 3 Splitted operations
1816
SKGStringListList listTmp;
1817
if (err.isSucceeded()) err=SKGServices::executeSelectSqliteOrder(document,
1818
"SELECT id, d_date, t_comment, t_payee FROM operation WHERE i_group_id=0 AND t_payee like '[1/%'",
1820
int nb=listTmp.count();
1821
for (int i=1; err.isSucceeded() && i<nb ;++i) { //First line ignored because of it's header
1822
QString id=listTmp.at(i).at(0);
1823
QString date=listTmp.at(i).at(1);
1824
QString comment=listTmp.at(i).at(2);
1825
QString payee=listTmp.at(i).at(3);
1826
QRegExp rx("(\\S+) +(.+)");
1827
if (rx.indexIn(payee)!=-1) {
1828
payee=SKGServices::stringToSqlString(rx.cap(2));
1820
err=document->beginTransaction("#INTERNAL#", 5);
1821
if (err.isSucceeded()) {
1822
//Step 1 Clean cheque
1823
err=SKGServices::executeSqliteOrder(document, "UPDATE operation set t_mode='Cheque', t_comment='', i_number=substr(t_mode,4,1000)+0 where t_mode like 'Chq %'");
1824
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document, "UPDATE operation set t_mode='Cheque', t_comment='', i_number=substr(t_comment,3,1000)+0 where t_mode like 'Ch%' AND t_comment like 'n%'");
1827
if (err.isSucceeded()) err=document->stepForward(1);
1829
//TODO Step 2 [auto]
1832
if (err.isSucceeded()) err=document->stepForward(2);
1834
//Step 3 Splitted operations
1835
SKGStringListList listTmp;
1836
if (err.isSucceeded()) err=SKGServices::executeSelectSqliteOrder(document,
1837
"SELECT id, d_date, t_comment, t_payee FROM operation WHERE i_group_id=0 AND t_payee like '[1/%'",
1839
int nb=listTmp.count();
1840
for (int i=1; err.isSucceeded() && i<nb ;++i) { //First line ignored because of it's header
1841
QString id=listTmp.at(i).at(0);
1842
QString date=listTmp.at(i).at(1);
1843
QString comment=listTmp.at(i).at(2);
1844
QString payee=listTmp.at(i).at(3);
1845
QRegExp rx("(\\S+) +(.+)");
1846
if (rx.indexIn(payee)!=-1) {
1847
payee=SKGServices::stringToSqlString(rx.cap(2));
1850
QString wcop="d_date='"+date+"' AND t_comment='"+SKGServices::stringToSqlString(comment)+'\'';
1851
err=SKGServices::executeSqliteOrder(document,
1852
"UPDATE suboperation SET rd_operation_id="+id+" WHERE "
1853
"rd_operation_id!="+id+" AND rd_operation_id in (SELECT id FROM operation WHERE "+wcop+')');
1855
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1856
"DELETE FROM operation WHERE id!="+id+" AND "+wcop);
1858
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1859
"UPDATE operation SET t_comment='', t_payee='"+SKGServices::stringToSqlString(payee)+"' WHERE id="+id);
1831
QString wcop="d_date='"+date+"' AND t_comment='"+SKGServices::stringToSqlString(comment)+'\'';
1832
err=SKGServices::executeSqliteOrder(document,
1833
"UPDATE suboperation SET rd_operation_id="+id+" WHERE "
1834
"rd_operation_id!="+id+" AND rd_operation_id in (SELECT id FROM operation WHERE "+wcop+')');
1836
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1837
"DELETE FROM operation WHERE id!="+id+" AND "+wcop);
1839
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1840
"UPDATE operation SET t_comment='', t_payee='"+SKGServices::stringToSqlString(payee)+"' WHERE id="+id);
1844
if (err.isSucceeded()) err=document->stepForward(3);
1847
SKGObjectBase::SKGListSKGObjectBase opTitreList;
1848
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "operation", "t_mode='Titre'", opTitreList);
1850
int nb2=opTitreList.count();
1851
for (int i=0; err.isSucceeded() && i<nb2 ;++i) {
1852
SKGOperationObject op=opTitreList[i];
1854
//Payee is like this: <NB> <NAME> achet� <VALUE>
1855
//Example: 57.496 FCP EADS EXPANSION achet� 13,421
1856
QRegExp rx("(\\S+) (.+) \\S+ (\\S+)");
1857
QString payee=op.getPayee();
1858
if (rx.indexIn(payee)!=-1) {
1860
double nb=SKGServices::stringToDouble(rx.cap(1));
1861
QString unitName =rx.cap(2);
1862
double value=SKGServices::stringToDouble(rx.cap(3));
1864
SKGObjectBase::SKGListSKGObjectBase subOps;
1865
err=op.getSubOperations(subOps);
1866
if (err.isSucceeded() && subOps.count()==1 && nb!=0) {
1868
//Create or Update unit
1869
SKGSubOperationObject subOp=subOps.at(0);
1870
SKGUnitObject unit(document);
1871
if (err.isSucceeded()) err=document->addOrModifyUnitValue(unitName, op.getDate(), value);
1872
if (err.isSucceeded()) err=document->addOrModifyUnitValue(unitName, QDate::currentDate(), subOp.getQuantity()/nb);
1873
if (err.isSucceeded()) {
1874
err=unit.setName(unitName);
1875
if (err.isSucceeded()) err=unit.load();
1863
if (err.isSucceeded()) err=document->stepForward(3);
1866
SKGObjectBase::SKGListSKGObjectBase opTitreList;
1867
if (err.isSucceeded()) err=SKGObjectBase::getObjects(document, "operation", "t_mode='Titre'", opTitreList);
1869
int nb2=opTitreList.count();
1870
for (int i=0; err.isSucceeded() && i<nb2 ;++i) {
1871
SKGOperationObject op=opTitreList[i];
1873
//Payee is like this: <NB> <NAME> achet� <VALUE>
1874
//Example: 57.496 FCP EADS EXPANSION achet� 13,421
1875
QRegExp rx("(\\S+) (.+) \\S+ (\\S+)");
1876
QString payee=op.getPayee();
1877
if (rx.indexIn(payee)!=-1) {
1879
double nb=SKGServices::stringToDouble(rx.cap(1));
1880
QString unitName =rx.cap(2);
1881
double value=SKGServices::stringToDouble(rx.cap(3));
1883
SKGObjectBase::SKGListSKGObjectBase subOps;
1884
err=op.getSubOperations(subOps);
1885
if (err.isSucceeded() && subOps.count()==1 && nb!=0) {
1887
//Create or Update unit
1888
SKGSubOperationObject subOp=subOps.at(0);
1889
SKGUnitObject unit(document);
1890
if (err.isSucceeded()) err=document->addOrModifyUnitValue(unitName, op.getDate(), value);
1891
if (err.isSucceeded()) err=document->addOrModifyUnitValue(unitName, QDate::currentDate(), subOp.getQuantity()/nb);
1892
if (err.isSucceeded()) {
1893
err=unit.setName(unitName);
1894
if (err.isSucceeded()) err=unit.load();
1896
if (err.isSucceeded()) err=unit.setType(SKGUnitObject::SHARE);
1897
if (err.isSucceeded()) err=unit.setInternetCode(op.getComment());
1898
if (err.isSucceeded()) err=unit.save();
1899
if (err.isSucceeded()) err=op.setUnit(unit);
1900
if (err.isSucceeded()) err=op.setPayee("");
1901
if (err.isSucceeded()) err=subOp.setQuantity(nb);
1902
if (err.isSucceeded()) err=subOp.save(true, false); //No reload
1903
if (err.isSucceeded()) err=op.save(true, false); //No reload
1877
if (err.isSucceeded()) err=unit.setType(SKGUnitObject::SHARE);
1878
if (err.isSucceeded()) err=unit.setInternetCode(op.getComment());
1879
if (err.isSucceeded()) err=unit.save();
1880
if (err.isSucceeded()) err=op.setUnit(unit);
1881
if (err.isSucceeded()) err=op.setPayee("");
1882
if (err.isSucceeded()) err=subOp.setQuantity(nb);
1883
if (err.isSucceeded()) err=subOp.save(true, false); //No reload
1884
if (err.isSucceeded()) err=op.save(true, false); //No reload
1909
if (err.isSucceeded()) err=document->stepForward(4);
1911
//Step 5 Update payee with "Transfer" already defined as transfer
1912
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1913
"UPDATE operation SET t_payee='' WHERE t_payee like 'Transfert %' AND i_group_id!=0");
1916
if (err.isSucceeded()) err=document->stepForward(5);
1890
if (err.isSucceeded()) err=document->stepForward(4);
1892
//Step 5 Update payee with "Transfer" already defined as transfer
1893
if (err.isSucceeded()) err=SKGServices::executeSqliteOrder(document,
1894
"UPDATE operation SET t_payee='' WHERE t_payee like 'Transfert %' AND i_group_id!=0");
1897
if (err.isSucceeded()) err=document->stepForward(5);
1918
if (err.isSucceeded()) err=document->endTransaction(true);
1919
else document->endTransaction(false);
1899
if (err.isSucceeded()) err=document->endTransaction(true);
1900
else document->endTransaction(false);
1902
1921
if (err.isFailed()) {
1903
1922
err.addError(ERR_FAIL, tr("%1 failed").arg("SKGImportExportManager::cleanBankPerfectImport"));