Projekt

Allgemein

Profil

Herunterladen (108 KB) Statistiken
| Zweig: | Markierung: | Revision:
/****************************************************************************
* This file is part of the project AqFinance.
* AqFinance (c) by 2009-2017 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "ff_app.hpp"
#include "ff_modulemanager.hpp"
#include "ff_selectbankacc.hpp"
#include "ff_edittransactions.hpp"
#include "ff_conflicthandler.hpp"

#include <aqfoxext/fxx_app.hpp>
#include <aqfoxext/fxx_iconset.hpp>

#include <aqfinance/engine/modules/ae_statementimport.h>
#include <aqfinance/engine/modules/ae_statementexport.h>
#include <aqfinance/engine/modules/ae_recontransfers.h>
#include <aqfinance/engine/book/ae_utils.h>

#include <aqbanking/jobsingletransfer.h>
#include <aqbanking/jobinternaltransfer.h>
#include <aqbanking/jobsepatransfer.h>

#include <gwenhywfar/debug.h>
#include <gwenhywfar/gui.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/gwendate.h>
#include <gwenhywfar/pathmanager.h>
#include <gwenhywfar/directory.h>
#include <gwenhywfar/process.h>

#include <sys/stat.h>
#include <ctype.h>


#define MAX_CURRENCIES_PER_TRANS 16

#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)




typedef struct {
const char *appName;
const char *appPaths;
const char *appArgs;
} app_spec_tmpl;



/* TODO: add acrobat reader and maybe other apps */
#if defined(OS_WIN32)
# define WIN32_START_NAME "Windows Generic Document Starter"

#elif defined(OS_DARWIN)

static app_spec_tmpl _pdfApps[]={
{ "Preview", "/Applications/Preview.app/Contents/MacOS/Preview", "$(filename)" },
{ NULL, NULL, NULL}
};

// TODO: figure out what email clients to use on MAcOSX and how
static app_spec_tmpl _emailApps[]={
{ NULL, NULL, NULL}
};


#else

static app_spec_tmpl _pdfApps[]={
{ "okular", "/usr/bin/okular\t/usr/local/bin/okular", "$(filename)" },
{ "acroread", "/usr/bin/acroread\t/usr/local/bin/acroread", "$(filename)" },
{ "evince", "/usr/bin/evince\t/usr/local/bin/evince", "$(filename)" },
{ NULL, NULL, NULL}
};

static app_spec_tmpl _emailApps[]={
{ "kmail",
"/usr/bin/kmail\t/usr/local/bin/kmail",
"-s \"Rechnung $(job/code)\" --attach \"$(filename)\" --body \"$(body)\" \"$(job/addressEmail)\""
},
{ "claws-mail",
"/usr/bin/claws-mail\t/usr/local/bin/claws-mail",
"--compose \"mailto:$(job/addressEmail)?subject=Rechnung $(job/code)&body=$(body) --attach \"$(filename)\""
},
{ "thunderbird",
"/usr/bin/thunderbird\t/usr/local/bin/thunderbird",
"--compose \"to=$(job/addressEmail),subject=\'Rechnung $(job/code)\',body=$(body),attachment=\'file://$(filename)\'\""
},
{ NULL, NULL, NULL}
};

#endif


FF_App::FF_App(const FXString& name,
const FXString& vendor)
:FXXApp(name, vendor)
,m_book(NULL)
,m_moduleManager(NULL)
,m_banking(NULL)
,m_accountColor_asset(FXRGB(161,255,162))
,m_accountColor_liability(FXRGB(255,166,166))
,m_accountColor_equity(FXRGB(254, 255, 152))
,m_accountColor_income(FXRGB(161,255,162))
,m_accountColor_expense(FXRGB(255,166,166))
,m_useAccountingTerms(false)
,m_showBankAccountGraphs(true)
,m_appSpecsPdfViewer(NULL)
,m_appSpecsEmailClient(NULL)
,m_cacheMaxEntries(FF_APP_CACHE_MAX_ENTRIES)
,m_cacheMaxSize(FF_APP_CACHE_MAX_SIZE)
,m_jobList(NULL)
{
m_jobList=AB_Job_List2_new();
m_appSpecsPdfViewer=FF_AppSpec_List_new();
m_appSpecsEmailClient=FF_AppSpec_List_new();
}



FF_App::~FF_App() {
if (m_jobList) {
AB_Job_List2_free(m_jobList);
m_jobList=NULL;
}

if (m_appSpecsPdfViewer) {
FF_AppSpec_List_free(m_appSpecsPdfViewer);
m_appSpecsPdfViewer=NULL;
}

if (m_appSpecsEmailClient) {
FF_AppSpec_List_free(m_appSpecsEmailClient);
m_appSpecsEmailClient=NULL;
}
}



GWEN_CONFIGMGR *FF_App::getConfigManager() {
GWEN_CONFIGMGR *cm;

cm=AE_GetConfigManager();
if (cm==NULL) {
DBG_ERROR(0, "No config manager??");
}
return cm;
}



FXColor FF_App::getAccountColor(AE_ACCOUNT_TYPE t) const {
switch(AE_AccountType_GetGroup(t)) {
case AE_AccountGroup_Asset:
return getAccountColorAsset();
case AE_AccountGroup_Liability:
return getAccountColorLiability();
case AE_AccountGroup_Equity:
return getAccountColorEquity();
case AE_AccountGroup_Income:
return getAccountColorIncome();
case AE_AccountGroup_Expense:
return getAccountColorExpense();
case AE_AccountGroup_Unknown:
break;
}
return FXRGB(255, 255, 255);
}



FXXIconSet *FF_App::getIconSet(const FXString &name) {
FXIcon *ic;

ic=getIcon(name.text());
if (ic) {
FXXIconSet *is=new FXXIconSet(ic);
return is;
}

return NULL;
}



void FF_App::init(int& argc, char** argv, bool connect) {
FXXApp::init(argc, argv, connect);

#if defined(OS_WIN32) || defined(ENABLE_LOCAL_INSTALL)
/* add folder relative to EXE */
GWEN_PathManager_AddRelPath(FXX_PM_LIBNAME,
FXX_PM_LIBNAME,
FXX_PM_RESSOURCEDIR,
AQFINANCE_DATA_DIR,
GWEN_PathManager_RelModeExe);
#else
/* add absolute folder */
GWEN_PathManager_AddPath(FXX_PM_LIBNAME,
FXX_PM_LIBNAME,
FXX_PM_RESSOURCEDIR,
AQFINANCE_DATA_DIR);
#endif

}



void FF_App::fini() {
AB_JOB_LIST2_ITERATOR *jit;

jit=AB_Job_List2_First(m_jobList);
if (jit) {
AB_JOB *j;

j=AB_Job_List2Iterator_Data(jit);
while(j) {
AB_Job_free(j);
j=AB_Job_List2Iterator_Next(jit);
}
AB_Job_List2Iterator_free(jit);
}
AB_Job_List2_Clear(m_jobList);
}



void FF_App::_genPdfAppSpecs() {
GWEN_BUFFER *tbuf;
uint32_t pos;
int rv;

tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(tbuf, AE_GetUserDataFolder());
GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S "appspecs" GWEN_DIR_SEPARATOR_S "pdfViewer");
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(tbuf), GWEN_PATH_FLAGS_CHECKROOT);
if (rv<0) {
DBG_ERROR(AE_LOGDOMAIN, "Could not access path [%s]", GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
return;
}
GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S);
pos=GWEN_Buffer_GetPos(tbuf);

#ifndef OS_WIN32
{
const app_spec_tmpl *pt;

pt=_pdfApps;
while(pt->appName && *pt->appName) {
if (FF_AppSpec_List_GetByName(m_appSpecsPdfViewer, pt->appName)==NULL) {
if (pt->appPaths && *(pt->appPaths)) {
FXString str;
FXString t;
FXint n=0;
str=FXString(pt->appPaths);
while(!(t=str.section('\t',n)).empty()){
struct stat st;
rv=stat(t.text(), &st);
if (rv==0) {
FF_APPSPEC *as;
GWEN_DB_NODE *db;
as=FF_AppSpec_new();
FF_AppSpec_SetName(as, pt->appName);
FF_AppSpec_SetPath(as, t.text());
if (pt->appArgs && *(pt->appArgs))
FF_AppSpec_SetArguments(as, pt->appArgs);
db=GWEN_DB_Group_new("app");
FF_AppSpec_toDb(as, db);
FF_AppSpec_List_Add(as, m_appSpecsPdfViewer);
GWEN_Text_EscapeToBuffer(pt->appName, tbuf);
GWEN_Buffer_AppendString(tbuf, ".conf");
DBG_NOTICE(AE_LOGDOMAIN, "Writing appspec file [%s]", GWEN_Buffer_GetStart(tbuf));
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tbuf), GWEN_DB_FLAGS_DEFAULT);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
}
GWEN_DB_Group_free(db);
GWEN_Buffer_Crop(tbuf, 0, pos);
}
n++;
}
}
}
pt++;
}
}
#else
if (FF_AppSpec_List_GetByName(m_appSpecsPdfViewer, WIN32_START_NAME)==NULL) {
FF_APPSPEC *as;
GWEN_DB_NODE *db;

as=FF_AppSpec_new();
FF_AppSpec_SetName(as, WIN32_START_NAME);
FF_AppSpec_SetPath(as, "cmd.exe");
FF_AppSpec_SetArguments(as, "/Q /C \"$(filename)\"");

db=GWEN_DB_Group_new("app");
FF_AppSpec_toDb(as, db);
FF_AppSpec_List_Add(as, m_appSpecsPdfViewer);

GWEN_Text_EscapeToBuffer(FF_AppSpec_GetName(as), tbuf);
GWEN_Buffer_AppendString(tbuf, ".conf");
DBG_NOTICE(AE_LOGDOMAIN, "Writing appspec file [%s]", GWEN_Buffer_GetStart(tbuf));
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tbuf), GWEN_DB_FLAGS_DEFAULT);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
}
GWEN_DB_Group_free(db);

GWEN_Buffer_Crop(tbuf, 0, pos);
}
#endif
GWEN_Buffer_free(tbuf);
}



void FF_App::_genEmailAppSpecs() {
GWEN_BUFFER *tbuf;
uint32_t pos;
int rv;

tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(tbuf, AE_GetUserDataFolder());
GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S "appspecs" GWEN_DIR_SEPARATOR_S "emailClient");
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(tbuf), GWEN_PATH_FLAGS_CHECKROOT);
if (rv<0) {
DBG_ERROR(AE_LOGDOMAIN, "Could not access path [%s]", GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
return;
}
GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S);
pos=GWEN_Buffer_GetPos(tbuf);

#ifndef OS_WIN32
{
const app_spec_tmpl *pt;

pt=_emailApps;
while(pt->appName && *pt->appName) {
if (FF_AppSpec_List_GetByName(m_appSpecsEmailClient, pt->appName)==NULL) {
if (pt->appPaths && *(pt->appPaths)) {
FXString str;
FXString t;
FXint n=0;
str=FXString(pt->appPaths);
while(!(t=str.section('\t',n)).empty()){
struct stat st;
rv=stat(t.text(), &st);
if (rv==0) {
FF_APPSPEC *as;
GWEN_DB_NODE *db;
as=FF_AppSpec_new();
FF_AppSpec_SetName(as, pt->appName);
FF_AppSpec_SetPath(as, t.text());
if (pt->appArgs && *(pt->appArgs))
FF_AppSpec_SetArguments(as, pt->appArgs);
db=GWEN_DB_Group_new("app");
FF_AppSpec_toDb(as, db);
FF_AppSpec_List_Add(as, m_appSpecsEmailClient);
GWEN_Text_EscapeToBuffer(pt->appName, tbuf);
GWEN_Buffer_AppendString(tbuf, ".conf");
DBG_NOTICE(AE_LOGDOMAIN, "Writing appspec file [%s]", GWEN_Buffer_GetStart(tbuf));
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tbuf), GWEN_DB_FLAGS_DEFAULT);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
}
GWEN_DB_Group_free(db);
GWEN_Buffer_Crop(tbuf, 0, pos);
}
n++;
}
}
}
pt++;
}
}
#else
# if 0
// TODO: find out which program to start for emails
if (FF_AppSpec_List_GetByName(m_appSpecsPdfViewer, WIN32_START_NAME)==NULL) {
FF_APPSPEC *as;
GWEN_DB_NODE *db;

as=FF_AppSpec_new();
FF_AppSpec_SetName(as, WIN32_START_NAME);
FF_AppSpec_SetPath(as, "cmd.exe");
FF_AppSpec_SetArguments(as, "/Q /C \"$(filename)\"");

db=GWEN_DB_Group_new("app");
FF_AppSpec_toDb(as, db);
FF_AppSpec_List_Add(as, m_appSpecsPdfViewer);

GWEN_Text_EscapeToBuffer(FF_AppSpec_GetName(as), tbuf);
GWEN_Buffer_AppendString(tbuf, ".conf");
DBG_NOTICE(AE_LOGDOMAIN, "Writing appspec file [%s]", GWEN_Buffer_GetStart(tbuf));
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tbuf), GWEN_DB_FLAGS_DEFAULT);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
}
GWEN_DB_Group_free(db);

GWEN_Buffer_Crop(tbuf, 0, pos);
}
# endif
#endif
GWEN_Buffer_free(tbuf);
}



int FF_App::_loadAppSpecs(const char *typeName, FF_APPSPEC_LIST *spList) {
GWEN_STRINGLIST *sl;
GWEN_BUFFER *tbuf;

sl=GWEN_StringList_new();

/* first add user local files to the string list */
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(tbuf, AE_GetUserDataFolder());
GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S "appspecs" GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(tbuf, typeName);
GWEN_Directory_GetMatchingFilesRecursively(GWEN_Buffer_GetStart(tbuf), sl, "*.conf");
GWEN_Buffer_free(tbuf);

/* then add system-wide files */
GWEN_PathManager_GetMatchingFilesRecursively(AE_PM_LIBNAME, AE_PM_DATADIR, typeName, sl, "*.conf");

if (GWEN_StringList_Count(sl)) {
GWEN_STRINGLISTENTRY *se;

se=GWEN_StringList_FirstEntry(sl);
while(se) {
const char *s;

s=GWEN_StringListEntry_Data(se);
if (s && *s) {
GWEN_DB_NODE *db;
int rv;

db=GWEN_DB_Group_new("appSpec");
rv=GWEN_DB_ReadFile(db, s, GWEN_DB_FLAGS_DEFAULT | GWEN_PATH_FLAGS_CREATE_GROUP);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
}
else {
FF_APPSPEC *as;

as=FF_AppSpec_fromDb(db);
if (as) {
const char *n;

FF_AppSpec_SetDbFileName(as, s);
n=FF_AppSpec_GetName(as);
if (n && *n) {
if (FF_AppSpec_List_GetByName(spList, n)==NULL) {
/* not in list, add it */
DBG_INFO(AE_LOGDOMAIN, "Adding AppSpec [%s]", n);
FF_AppSpec_List_Add(as, spList);
}
else
FF_AppSpec_free(as);
}
else
FF_AppSpec_free(as);
}
}
GWEN_DB_Group_free(db);
}
se=GWEN_StringListEntry_Next(se);
}
}
else {
DBG_ERROR(AE_LOGDOMAIN, "No AppSpecs found for type [%s]", typeName);
GWEN_StringList_free(sl);
return GWEN_ERROR_NOT_FOUND;
}

GWEN_StringList_free(sl);
return 0;
}



int FF_App::loadSettings() {
int rv;
GWEN_DB_NODE *dbConfig;
const char *s;

/* load appspecs for PDF viewer */
_loadAppSpecs("pdfViewer", m_appSpecsPdfViewer);
_genPdfAppSpecs();

/* load appspecs for Email Client */
_loadAppSpecs("emailClient", m_appSpecsEmailClient);
_genEmailAppSpecs();

rv=GWEN_ConfigMgr_GetGroup(AE_GetConfigManager(),
"main",
"app",
&dbConfig);
if (rv<0) {
DBG_ERROR(0, "Error getting app configuration group (%d)", rv);
return rv;
}

s=GWEN_DB_GetCharValue(dbConfig, "pdfViewer", 0, NULL);
if (s && *s)
m_pdfViewerName=FXString(s);

s=GWEN_DB_GetCharValue(dbConfig, "emailClient", 0, NULL);
if (s && *s)
m_emailClientName=FXString(s);

m_cacheMaxEntries=GWEN_DB_GetIntValue(dbConfig, "cacheMaxEntries", 0, FF_APP_CACHE_MAX_ENTRIES);
m_cacheMaxSize=GWEN_DB_GetIntValue(dbConfig, "cacheMaxSize", 0, FF_APP_CACHE_MAX_SIZE);

m_showBankAccountGraphs=(GWEN_DB_GetIntValue(dbConfig, "showBankAccountGraphs", 0, 1))?true:false;
m_useAccountingTerms=(GWEN_DB_GetIntValue(dbConfig, "useAccountingTerms", 0, 0))?true:false;

GWEN_DB_Group_free(dbConfig);

return 0;
}



int FF_App::saveSettings() {
int rv;
GWEN_DB_NODE *dbConfig;

dbConfig=GWEN_DB_Group_new("config");

// store config
if (!(m_pdfViewerName.empty()))
GWEN_DB_SetCharValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "pdfViewer", m_pdfViewerName.text());

if (!(m_emailClientName.empty()))
GWEN_DB_SetCharValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "emailClient", m_emailClientName.text());

GWEN_DB_SetIntValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "cacheMaxEntries", m_cacheMaxEntries);
GWEN_DB_SetIntValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "cacheMaxSize", m_cacheMaxSize);

GWEN_DB_SetIntValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "showBankAccountGraphs", m_showBankAccountGraphs?1:0);
GWEN_DB_SetIntValue(dbConfig, GWEN_DB_FLAGS_OVERWRITE_VARS, "useAccountingTerms", m_useAccountingTerms?1:0);

rv=GWEN_ConfigMgr_LockGroup(AE_GetConfigManager(), "main", "app");
if (rv<0) {
DBG_ERROR(0, "Unable to lock configuration group (%d)", rv);
GWEN_DB_Group_free(dbConfig);
return rv;
}
else {
rv=GWEN_ConfigMgr_SetGroup(AE_GetConfigManager(),
"main",
"app",
dbConfig);
if (rv<0) {
DBG_ERROR(0, "Error setting configuration group (%d)", rv);
GWEN_ConfigMgr_UnlockGroup(AE_GetConfigManager(), "main", "app");
GWEN_DB_Group_free(dbConfig);
return rv;
}

rv=GWEN_ConfigMgr_UnlockGroup(AE_GetConfigManager(),
"main",
"app");
if (rv<0) {
DBG_ERROR(0, "Unable to lock configuration group (%d)", rv);
GWEN_DB_Group_free(dbConfig);
return rv;
}
}
GWEN_DB_Group_free(dbConfig);

return 0;
}




void FF_App::signalDbOpened(AE_BOOK *bk) {
if (m_moduleManager)
m_moduleManager->signalDbOpened(bk);
}



void FF_App::signalDbClosing() {
if (m_moduleManager)
m_moduleManager->signalDbClosing();
}



void FF_App::signalDbClosed() {
if (m_moduleManager)
m_moduleManager->signalDbClosed();
}



void FF_App::signalDbReload(AE_BOOK_TABLE_TYPE tt) {
if (m_moduleManager)
m_moduleManager->signalDbReload(tt);
}



bool FF_App::dbCheckDeleteObject(FXComposite *parent,
AE_BOOK_TABLE_TYPE tt,
AQDB_ID id) {
if (m_moduleManager)
return m_moduleManager->dbCheckDeleteObject(parent, tt, id);
else
return true;
}



void FF_App::signalJobListUpdated() {
if (m_moduleManager)
m_moduleManager->signalJobListUpdated();
}



void FF_App::signalAboutToSendJobs() {
if (m_moduleManager)
m_moduleManager->signalAboutToSendJobs();
}



void FF_App::addJobToList(AB_JOB *j) {
AB_Job_List2_PushBack(m_jobList, j);
}



int FF_App::addAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
AE_BOOK_TABLE_TYPE tt,
AE_ACCOUNT *acc,
int doLock) {
AE_BOOK *b;

b=m_book;
if (b) {
int rv;
AQDB_ID cid;

if (doLock) {
rv=AE_Book_BeginEdit(b, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}

/* first add account */
rv=AE_Book_AddAccount(b, tt, acc, 0);
if (rv<0) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}

/* maybe create initial transaction for primary commodity */
cid=AE_Account_GetPrimaryCommodityId(acc);
if (cid) {
AE_COMMODITY *co=NULL;
AE_TRANSACTION *t;
AE_SPLIT *sp;
AQDB_VALUE *v;
AE_ACCOUNT *eqAcc;
GWEN_DATE *dt;

/* read commodity */
rv=AE_Book_ReadCommodity(b, AE_Book_TableType_Commodity, cid, &co);
if (rv<0) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return GWEN_ERROR_GENERIC;
}

/* create initial transaction */
t=AE_Transaction_new();
dt=GWEN_Date_fromGregorian(1900, 1, 1);
AE_Transaction_SetDate(t, dt);
GWEN_Date_free(dt);
AE_Transaction_SetMemo(t, I18N("Opening Balance"));
AE_Transaction_AddFlags(t, AE_TRANSACTION_FLAGS_INITIAL);
AE_Transaction_AddRuntimeFlags(t,
AE_TRANSACTION_RTFLAGS_MODIFIED |
AE_TRANSACTION_RTFLAGS_SPLITS_MODIFIED);

v=AQDB_Value_new();
/* first split */
sp=AE_Split_new();
AE_Split_SetAccountId(sp, AE_Account_GetId(acc));
AE_Split_SetAmount(sp, v);
AE_Split_SetCommodityId(sp, AE_Commodity_GetId(co));
AE_Split_AddRuntimeFlags(sp, AE_SPLIT_RTFLAGS_MODIFIED);
AE_Transaction_AddSplit(t, sp);

/* get account for second split */
eqAcc=getAutoEquityAccount(p, at, co, 0);
if (eqAcc==NULL) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AQDB_Value_free(v);
AE_Transaction_free(t);
AE_Commodity_free(co);
return GWEN_ERROR_GENERIC;
}

/* second split */
sp=AE_Split_new();
AE_Split_SetAccountId(sp, AE_Account_GetId(eqAcc));
AE_Split_SetAmount(sp, v);
AE_Split_SetCommodityId(sp, AE_Commodity_GetId(co));
AE_Split_AddRuntimeFlags(sp, AE_SPLIT_RTFLAGS_MODIFIED);
AE_Transaction_AddSplit(t, sp);

/* store transaction */
rv=AE_Book_ApplyTransaction(b, t, NULL, 0);
if (rv<0) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AQDB_Value_free(v);
AE_Transaction_free(t);
AE_Commodity_free(co);
return rv;
}
AQDB_Value_free(v);
AE_Transaction_free(t);
AE_Commodity_free(co);
}

/* unlock */
if (doLock) {
rv=AE_Book_EndEdit(b, 0);
if (rv<0) {
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}

return 0;
}
else {
DBG_ERROR(AE_LOGDOMAIN, "No book");
return GWEN_ERROR_NOT_OPEN;
}
}



int FF_App::_importContext(FXComposite *p, AB_IMEXPORTER_CONTEXT *ctx,
AE_STATEMENT_LIST *statementsToImport) {
AE_BOOK *b;

b=m_book;
if (b) {
AB_IMEXPORTER_ACCOUNTINFO *iea;
AE_BANKACCOUNT_LIST *baList;
uint32_t pid;
int rv;
AE_BANKBALANCE_LIST *notedList=NULL;
AE_BANKBALANCE_LIST *bookedList=NULL;
AE_PARTNER_LIST *partnerList=NULL;
AE_PARTNER *pt;

/* read current list of noted balances */
notedList=AE_BankBalance_List_new();
rv=AE_Book_ReadBankBalanceList(b, AE_Book_TableType_NotedBalance, notedList);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_BankBalance_List_free(notedList);
notedList=NULL;
}

/* read current list of booked balances */
bookedList=AE_BankBalance_List_new();
rv=AE_Book_ReadBankBalanceList(b, AE_Book_TableType_BookedBalance, bookedList);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_BankBalance_List_free(bookedList);
bookedList=NULL;
}

baList=AE_BankAccount_List_new();
rv=AE_Book_ReadBankAccountList(b, AE_Book_TableType_BankAccount, baList);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_BankBalance_List_free(bookedList);
AE_BankAccount_List_free(baList);
return rv;
}

partnerList=AE_Partner_List_new();
rv=AE_Book_ReadPartnerList(b, AE_Book_TableType_Partner, partnerList);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Partner_List_free(partnerList);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
return rv;
}
/* read accounts and addresses for the partners */
pt=AE_Partner_List_First(partnerList);
while(pt) {
AE_Book_ReadPartnerSubObjects(b, pt);
pt=AE_Partner_List_Next(pt);
}


pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT |
GWEN_GUI_PROGRESS_ALLOW_EMBED,
I18N("Importing Accounts"),
I18N("Importing accounts."),
AB_ImExporterContext_GetAccountInfoCount(ctx),
0);

/* import account info */
iea=AB_ImExporterContext_GetFirstAccountInfo(ctx);
while(iea) {
AE_BANKACCOUNT *ba;
AB_ACCOUNT_STATUS *ast;
AQDB_ID aid=0;
AE_BANKBALANCE *bb=NULL;
AE_BANKBALANCE *bn=NULL;
AE_STATEMENT_LIST *newStatements;
AE_STATEMENT_LIST *newTransfers;
int i;
const char *sBankId;
const char *sAcctId;

/* determine bank account id */
DBG_ERROR(0, "Handling account");
/* generate log message */
sBankId=AB_ImExporterAccountInfo_GetBankName(iea);
if (sBankId==NULL)
sBankId=AB_ImExporterAccountInfo_GetBankCode(iea);
if (sBankId==NULL)
sBankId=AB_ImExporterAccountInfo_GetBic(iea);
if (sBankId==NULL)
sBankId=I18N("unknown bank");
sAcctId=AB_ImExporterAccountInfo_GetAccountName(iea);
if (sAcctId==NULL)
sAcctId=AB_ImExporterAccountInfo_GetAccountNumber(iea);
if (sAcctId==NULL)
sAcctId=AB_ImExporterAccountInfo_GetIban(iea);
GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Info,
I18N("Importing data for account \"%s\" at \"%s\""),
sAcctId, sBankId);

/* find corresponding bank account */
ba=AE_BankAccount_List_First(baList);
while(ba) {
const char *s1;
const char *s2;
bool mightMatch=true;

if (AE_BankAccount_GetOwnerType(ba)!=0 ||
AE_BankAccount_GetOwnerId(ba)!=0)
mightMatch=false;

/* compare bank code */
if (mightMatch) {
s1=AB_ImExporterAccountInfo_GetBankCode(iea);
s2=AE_BankAccount_GetBankCode(ba);
if (s1 && *s1 && s2 && *s2)
mightMatch=(strcasecmp(s1, s2)!=0)?false:true;
}

/* compare account number */
if (mightMatch) {
s1=AB_ImExporterAccountInfo_GetAccountNumber(iea);
s2=AE_BankAccount_GetAccountNumber(ba);
if (s1 && *s1 && s2 && *s2) {
/* skip blanks and leading zeroes */
while(*s1 && ((uint8_t)(*s1))<33)
s1++;
while(*s1=='0')
s1++;
/* skip blanks and leading zeroes */
while(*s2 && ((uint8_t)(*s2))<33)
s2++;
while(*s2=='0')
s2++;
/* compare */
mightMatch=(strcasecmp(s1, s2)!=0)?false:true;
}
}
/* compare iban */
if (mightMatch) {
s1=AB_ImExporterAccountInfo_GetIban(iea);
s2=AE_BankAccount_GetIban(ba);
if (s1 && *s1 && s2 && *s2)
mightMatch=(strcasecmp(s1, s2)!=0)?false:true;
}
if (mightMatch)
break;
ba=AE_BankAccount_List_Next(ba);
}
if (ba) {
aid=AE_BankAccount_GetId(ba);
DBG_ERROR(0, "Found bank account id %d", int(aid));
GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Info,
I18N("Found corresponding bank account for account \"%s\" at \"%s\""),
sAcctId, sBankId);
}
else {
const char *s;

ba=AE_BankAccount_new();
s=AB_ImExporterAccountInfo_GetBankName(iea);
AE_BankAccount_SetBankName(ba, s);
s=AB_ImExporterAccountInfo_GetAccountName(iea);
AE_BankAccount_SetAccountName(ba, s);
s=AB_ImExporterAccountInfo_GetBankCode(iea);
AE_BankAccount_SetBankCode(ba, s);
s=AB_ImExporterAccountInfo_GetAccountNumber(iea);
AE_BankAccount_SetAccountNumber(ba, s);
s=AB_ImExporterAccountInfo_GetBic(iea);
AE_BankAccount_SetBic(ba, s);
s=AB_ImExporterAccountInfo_GetIban(iea);
AE_BankAccount_SetIban(ba, s);


DBG_ERROR(0, "Could not determine account, asking user");
DBG_ERROR(0, "AccName=%s, BankCode=%s, AccountNumber=%s",
AB_ImExporterAccountInfo_GetAccountName(iea),
AB_ImExporterAccountInfo_GetBankCode(iea),
AB_ImExporterAccountInfo_GetAccountNumber(iea));
GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Info,
I18N("No corresponding bank account found for account \"%s\" at \"%s\""),
sAcctId, sBankId);
if (!FF_SelectBankAccount::selectAccount(this, p,
I18N("Select Account"),
ba, aid)) {
AE_BankAccount_free(ba);
GWEN_Gui_ProgressEnd(pid);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return GWEN_ERROR_USER_ABORTED;
}
AE_BankAccount_free(ba);
ba=NULL;
}

/* search for booked balance in database */
if (bookedList) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Looking for booked balance"));
bb=AE_BankBalance_List_First(bookedList);
while(bb) {
if (AE_BankBalance_GetAccountId(bb)==aid)
break;
bb=AE_BankBalance_List_Next(bb);
}
}

/* search for noted balance database */
if (notedList) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Looking for noted balance"));
bn=AE_BankBalance_List_First(notedList);
while(bn) {
if (AE_BankBalance_GetAccountId(bn)==aid)
break;
bn=AE_BankBalance_List_Next(bn);
}
}

/* get balances */
for (i=0; i<2; i++) {
const AB_BALANCE *abal=NULL;
AE_BANKBALANCE *balance=NULL;

if (i==0) {
/* best booked balance */
balance=bb;
ast=AE_StatementImport_GetBestBalance(iea, 0);
if (ast)
abal=AB_AccountStatus_GetBookedBalance(ast);
}
else {
/* best noted balance */
balance=bn;
ast=AE_StatementImport_GetBestBalance(iea, 1);
if (ast)
abal=AB_AccountStatus_GetBookedBalance(ast);
}

if (abal) {
const AB_VALUE *v=AB_Balance_GetValue(abal);
const GWEN_TIME *ti=AB_Balance_GetTime(abal);
GWEN_DATE *gd=NULL;

if (ti)
gd=GWEN_Date_fromTime(ti);

if (v) {
GWEN_BUFFER *tbuf;
AB_VALUE *v2;
AQDB_VALUE *nv;
const char *s;
/* value */
if (balance==NULL)
balance=AE_BankBalance_new();
v2=AB_Value_dup(v);
AB_Value_SetCurrency(v2, NULL);
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
AB_Value_toString(v2, tbuf);
AB_Value_free(v2);
nv=AQDB_Value_fromString(GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
AE_BankBalance_SetValue(balance, nv);
AQDB_Value_free(nv);

/* currency */
s=AB_Value_GetCurrency(v);
AE_BankBalance_SetCurrency(balance, s);

/* date */
AE_BankBalance_SetDate(balance, gd);

/* account id */
AE_BankBalance_SetAccountId(balance, aid);

if (i==0)
bb=balance;
else
bn=balance;
}
GWEN_Date_free(gd);
}
}

DBG_ERROR(0, "Balances: %s %s", bb?"+booked":"-booked", bn?"+noted":"-noted");

newStatements=AE_Statement_List_new();
newTransfers=AE_Statement_List_new();

/* read list of new statements */
DBG_ERROR(0, "Extracting new statements");
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Extracting new statements"));
rv=AE_StatementImport_ExtractNewStatements(b, iea, AE_Book_TableType_BankStatement,
aid, newStatements, pid);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

/* read list of new transfers */
DBG_ERROR(0, "Extracting new transfers");
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Extracting new transfers"));
rv=AE_StatementImport_ExtractNewStatements(b, iea, AE_Book_TableType_BankTransfer,
aid, newTransfers, pid);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

/* lock database */
rv=AE_Book_BeginEdit(b, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

#if 0
/* assign partners to new statements */
DBG_ERROR(0, "Assigning partners to new statements");
if (AE_Statement_List_GetCount(newStatements)) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Assigning partners to transfers"));
rv=AE_StatementImport_AssignPartnersToStatements(b, AE_Book_TableType_BankStatement, newStatements, 0);
if (rv<0) {
DBG_INFO(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error while assigning partners to statements: %d"), rv);
return rv;
}
}
#endif

/* import statements into database, move them to the statementsToImport list */
DBG_ERROR(0, "Importing %d new statements", AE_Statement_List_GetCount(newStatements));
if (AE_Statement_List_GetCount(newStatements)) {
AE_STATEMENT *st;
uint32_t lpid;

GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Info,
I18N("Importing %d new statements"),
AE_Statement_List_GetCount(newStatements));
lpid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT |
GWEN_GUI_PROGRESS_ALLOW_EMBED |
GWEN_GUI_PROGRESS_DELAY,
I18N("Importing Statements"),
I18N("Importing new statements."),
AE_Statement_List_GetCount(newStatements),
pid);

while( (st=AE_Statement_List_First(newStatements)) ) {
AE_Statement_List_Del(st);
AE_Statement_List_Add(st, statementsToImport);
rv=AE_Book_AddStatement(b, AE_Book_TableType_BankStatement, st, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(lpid);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
rv=GWEN_Gui_ProgressAdvance(lpid, GWEN_GUI_PROGRESS_ONE);
if (rv==GWEN_ERROR_USER_ABORTED) {
DBG_ERROR(0, "User aborted");
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(lpid);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_Statement_List_free(newStatements);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
}
GWEN_Gui_ProgressEnd(lpid);
}
AE_Statement_List_free(newStatements);

/* assign partners to new transfers */
DBG_ERROR(0, "Assigning partners to new transfers");
if (AE_Statement_List_GetCount(newTransfers)) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Assigning partners to transfers"));
rv=AE_StatementImport_AssignPartnersToStatements(b, m_banking, AE_Book_TableType_BankTransfer, newTransfers, 0);
if (rv<0) {
DBG_INFO(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error while assigning partners to transfers: %d"), rv);
return rv;
}
}

/* import transfers into database */
DBG_ERROR(0, "Importing new transfers");
if (AE_Statement_List_GetCount(newTransfers)) {
AE_STATEMENT *st;
uint32_t lpid;

GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Info,
I18N("Importing %d new transfers"),
AE_Statement_List_GetCount(newTransfers));
lpid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT |
GWEN_GUI_PROGRESS_ALLOW_EMBED |
GWEN_GUI_PROGRESS_DELAY,
I18N("Importing Transfers"),
I18N("Importing new transfers."),
AE_Statement_List_GetCount(newTransfers),
pid);
st=AE_Statement_List_First(newTransfers);
while(st) {
rv=AE_Book_AddStatement(b, AE_Book_TableType_BankTransfer, st, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(lpid);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
rv=GWEN_Gui_ProgressAdvance(lpid, GWEN_GUI_PROGRESS_ONE);
if (rv==GWEN_ERROR_USER_ABORTED) {
DBG_ERROR(0, "User aborted");
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
GWEN_Gui_ProgressEnd(lpid);
GWEN_Gui_ProgressEnd(pid);
AE_Statement_List_free(newTransfers);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
st=AE_Statement_List_Next(st);
}
GWEN_Gui_ProgressEnd(lpid);
}
AE_Statement_List_free(newTransfers);

/* update transfers */
DBG_ERROR(0, "Updating transfers");
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Updating existing transfers"));
rv=AE_StatementImport_UpdateTransfers(b, iea, AE_Book_TableType_BankTransfer,
aid, pid);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

/* import standing orders */
DBG_ERROR(0, "Updating standing orders");
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Updating standing orders"));
rv=AE_StatementImport_ImportStandingOrders(b, iea, AE_Book_TableType_BankStandingOrder,
aid, pid);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

/* import best booked balance */
DBG_ERROR(0, "Importing booked balance");
if (bb) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Importing booked balance"));
if (AE_BankBalance_GetId(bb)==0) {
/* new balance, add it */
DBG_ERROR(0, "Adding booked balance");
AE_BankBalance_List_Add(bb, bookedList);
rv=AE_Book_AddBankBalance(b, AE_Book_TableType_BookedBalance,
bb,
0);
}
else
rv=AE_Book_WriteBankBalance(b, AE_Book_TableType_BookedBalance,
bb,
0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
}

/* import best noted balance */
DBG_ERROR(0, "Importing noted balances");
if (bn) {
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Info, I18N("Importing noted balance"));
if (AE_BankBalance_GetId(bn)==0) {
/* new balance, add it */
DBG_ERROR(0, "Adding noted balance");
AE_BankBalance_List_Add(bn, notedList);
rv=AE_Book_AddBankBalance(b, AE_Book_TableType_NotedBalance,
bn,
0);
}
else
rv=AE_Book_WriteBankBalance(b, AE_Book_TableType_NotedBalance,
bn,
0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}
}

/* unlock database */
rv=AE_Book_EndEdit(b, 0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressEnd(pid);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

/* next */
rv=GWEN_Gui_ProgressAdvance(pid, GWEN_GUI_PROGRESS_ONE);
if (rv==GWEN_ERROR_USER_ABORTED) {
DBG_ERROR(0, "User aborted");
GWEN_Gui_ProgressEnd(pid);
AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return rv;
}

DBG_ERROR(0, "Done with this account");
iea=AB_ImExporterContext_GetNextAccountInfo(ctx);
}
GWEN_Gui_ProgressEnd(pid);

/* inform all modules about db changes */
signalDbReload(AE_Book_TableType_BankStatement);
signalDbReload(AE_Book_TableType_NotedBalance);
signalDbReload(AE_Book_TableType_BookedBalance);
signalDbReload(AE_Book_TableType_BankTransfer);
signalDbReload(AE_Book_TableType_Account);

AE_BankAccount_List_free(baList);
AE_BankBalance_List_free(bookedList);
AE_BankBalance_List_free(notedList);
AE_Partner_List_free(partnerList);
return 0;
}
else {
DBG_ERROR(0, "Book not open");
return GWEN_ERROR_NOT_OPEN;
}
}



int FF_App::_importSetFirstSplit(FXComposite *p,
AE_ACCOUNT_TREE *at,
AE_COMMODITY_LIST *cl,
AE_BANKACCOUNT_LIST *bal,
AE_TRANSACTION *t) {
const AQDB_VALUE *v;
const AE_STATEMENT *st;

st=AE_Transaction_GetStatement(t);
assert(st);

v=AE_Statement_GetValue(st);
if (v) {
AE_SPLIT *sp;
AQDB_ID aid;
const char *s;

sp=AE_Split_new();
AE_Split_SetAmount(sp, v);

s=AE_Statement_GetCurrency(st);
if (!(s && *s))
s="EUR";
if (s) {
AE_COMMODITY *co;

co=AE_Commodity_List_GetByCode(cl, s);
if (co==NULL)
co=AE_Commodity_List_GetBySymbol(cl, s);
if (co==NULL) {
/* TODO: let the user pick the commodity */
DBG_ERROR(0, "Unknown commodity [%s]", s);
}
else {
AE_Split_SetCommodityId(sp, AE_Commodity_GetId(co));
}
}
else {
DBG_ERROR(0, "No currency in statement");
}

aid=AE_Statement_GetBankAccountId(st);
if (aid==0) {
DBG_ERROR(0, "No bank account assigned to transaction");
AE_Split_free(sp);
return GWEN_ERROR_BAD_DATA;
}
else {
AE_BANKACCOUNT *ba;
AE_ACCOUNT *acc;

ba=AE_BankAccount_List_GetById(bal, aid);
if (ba==NULL) {
DBG_ERROR(0, "Bank account %08x not found", aid);
AE_Split_free(sp);
return GWEN_ERROR_BAD_DATA;
}

acc=getAccountForBankAccount(p, at, cl, ba,
AE_Split_GetCommodityId(sp),
1);
if (acc==NULL) {
AE_Split_free(sp);
return GWEN_ERROR_BAD_DATA;
}

AE_Split_SetAccountId(sp, AE_Account_GetId(acc));
if (AE_Split_GetCommodityId(sp)==0)
AE_Split_SetCommodityId(sp, AE_Account_GetPrimaryCommodityId(acc));
}

/* mark split as automatically matched with high confidence */
AE_Split_AddRuntimeFlags(sp, AE_SPLIT_RTFLAGS_MATCHAUTO2 | AE_SPLIT_RTFLAGS_FIX);
AE_Transaction_AddSplit(t, sp);
}
else {
DBG_ERROR(0, "No value");
return GWEN_ERROR_BAD_DATA;
}

return 0;
}



AE_ACCOUNT *FF_App::getAutoEquityAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
const AE_COMMODITY *co,
int doLock) {
AE_ACCOUNT *acc;
int rv;
AQDB_ID coId;

coId=AE_Commodity_GetId(co);

acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_AutoEquity &&
AE_Account_GetPrimaryCommodityId(acc)==coId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc==NULL) {
AQDB_ID parentId;
AE_ACCOUNT *parent;
const char *s;
char accNameBuf[64];

/* account not found, need to create it. find toplevel equity account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Equity)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Equity);

AE_Account_SetName(acc, I18N("Account|Equity"));
AE_Account_SetDescription(acc, I18N("Account|Equity Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;

/* create auto equity account */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_AutoEquity);
AE_Account_SetParentId(acc, parentId);
AE_Account_SetPrimaryCommodityId(acc, coId);

s=AE_Commodity_GetCode(co);
if (s==NULL)
s=AE_Commodity_GetName(co);
if (s==NULL)
s=AE_Commodity_GetSymbol(co);
if (s==NULL) {
DBG_ERROR(0, "Commodity %08x has no code/name/symbol", AE_Commodity_GetId(co));
s=I18N("unknown");
}

snprintf(accNameBuf, sizeof(accNameBuf)-1, I18N("Equity-%s"), s);
accNameBuf[sizeof(accNameBuf)-1]=0;

AE_Account_SetName(acc, accNameBuf);
AE_Account_SetDescription(acc, I18N("Automatic Equity Account"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
signalDbReload(AE_Book_TableType_Account);
AE_Account_Tree_AddChild(parent, acc);
}

return acc;
}



AE_ACCOUNT *FF_App::getCashAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
const AE_COMMODITY *co,
int doLock) {
AE_ACCOUNT *acc;
int rv;
AQDB_ID coId;

coId=AE_Commodity_GetId(co);

acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Cash &&
AE_Account_GetPrimaryCommodityId(acc)==coId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc==NULL) {
AQDB_ID parentId;
AE_ACCOUNT *parent;
const char *s;
char accNameBuf[64];

/* account not found, need to create it. find toplevel asset account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Asset)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Asset);

AE_Account_SetName(acc, I18N("Asset"));
AE_Account_SetDescription(acc, I18N("Asset Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;

/* create cash account */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Cash);
AE_Account_SetParentId(acc, parentId);
AE_Account_SetPrimaryCommodityId(acc, coId);

s=AE_Commodity_GetCode(co);
if (s==NULL)
s=AE_Commodity_GetName(co);
if (s==NULL)
s=AE_Commodity_GetSymbol(co);
if (s==NULL) {
DBG_ERROR(0, "Commodity %08x has no code/name/symbol", AE_Commodity_GetId(co));
s=I18N("unknown");
}

snprintf(accNameBuf, sizeof(accNameBuf)-1, I18N("Cash-%s"), s);
accNameBuf[sizeof(accNameBuf)-1]=0;

AE_Account_SetName(acc, accNameBuf);
AE_Account_SetDescription(acc, I18N("Cash Account"));
rv=addAccount(p, at, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_AddChild(parent, acc);
signalDbReload(AE_Book_TableType_Account);
}

return acc;
}



AE_ACCOUNT *FF_App::getPartnerReceivableAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
const AE_PARTNER *pt,
int doLock) {
AE_ACCOUNT *acc;
int rv;
AQDB_ID pId;
AQDB_ID coId;
GWEN_BUFFER *tbuf;

pId=AE_Partner_GetId(pt);
coId=AE_Partner_GetCommodityId(pt);

acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Receivable &&
AE_Account_GetPrimaryCommodityId(acc)==coId &&
AE_Account_GetPartnerId(acc)==pId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc==NULL) {
AQDB_ID parentId;
AE_ACCOUNT *parent;
const char *s;

/* account not found, need to create it. find toplevel asset account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Asset)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Asset);

AE_Account_SetName(acc, I18N("Asset"));
AE_Account_SetDescription(acc, I18N("Asset Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;
parentId=AE_Account_GetId(parent);

/* find receivable account */
acc=AE_Account_Tree_GetFirstChild(parent);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Receivable)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Receivable);

AE_Account_SetName(acc, I18N("Account|Receivable"));
AE_Account_SetDescription(acc, I18N("Account|Accounts/Receivable"));
AE_Account_SetParentId(acc, parentId);
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_AddChild(parent, acc);
}
parent=acc;

/* create auto receivable account */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Receivable);
AE_Account_SetParentId(acc, parentId);
AE_Account_SetPartnerId(acc, pId);
AE_Account_SetPrimaryCommodityId(acc, coId);

tbuf=GWEN_Buffer_new(0, 64, 0, 1);
s=AE_Partner_GetTitle(pt);
if (s && *s)
GWEN_Buffer_AppendString(tbuf, s);
s=AE_Partner_GetFirstName(pt);
if (s && *s) {
if (GWEN_Buffer_GetUsedBytes(tbuf))
GWEN_Buffer_AppendString(tbuf, " ");
GWEN_Buffer_AppendString(tbuf, s);
}
s=AE_Partner_GetLastName(pt);
if (s && *s) {
if (GWEN_Buffer_GetUsedBytes(tbuf))
GWEN_Buffer_AppendString(tbuf, " ");
GWEN_Buffer_AppendString(tbuf, s);
}

s=GWEN_Buffer_GetStart(tbuf);
if (*s==0)
GWEN_Buffer_AppendString(tbuf, I18N("-unnamed account-"));
AE_Account_SetName(acc, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);

AE_Account_SetDescription(acc, I18N("Account|Account/Receivable for Customer"));
rv=addAccount(p, at, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
signalDbReload(AE_Book_TableType_Account);
AE_Account_Tree_AddChild(parent, acc);
}

return acc;
}



AE_ACCOUNT *FF_App::getPartnerPayableAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
const AE_PARTNER *pt,
int doLock) {
AE_ACCOUNT *acc;
int rv;
AQDB_ID pId;
AQDB_ID coId;
GWEN_BUFFER *tbuf;

pId=AE_Partner_GetId(pt);
coId=AE_Partner_GetCommodityId(pt);

acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Payable &&
AE_Account_GetPrimaryCommodityId(acc)==coId &&
AE_Account_GetPartnerId(acc)==pId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc==NULL) {
AQDB_ID parentId;
AE_ACCOUNT *parent;
const char *s;

/* account not found, need to create it. find toplevel asset account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Liability)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Liability);

AE_Account_SetName(acc, I18N("Account|Liability"));
AE_Account_SetDescription(acc, I18N("Account|Liability Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;
parentId=AE_Account_GetId(parent);

/* find receivable account */
acc=AE_Account_Tree_GetFirstChild(parent);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Payable)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Payable);

AE_Account_SetName(acc, I18N("Account|Payable"));
AE_Account_SetDescription(acc, I18N("Account|Accounts/Payable"));
AE_Account_SetParentId(acc, parentId);
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_AddChild(parent, acc);
}
parent=acc;

/* create auto receivable account */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Payable);
AE_Account_SetParentId(acc, parentId);
AE_Account_SetPartnerId(acc, pId);
AE_Account_SetPrimaryCommodityId(acc, coId);

tbuf=GWEN_Buffer_new(0, 64, 0, 1);
s=AE_Partner_GetTitle(pt);
if (s && *s)
GWEN_Buffer_AppendString(tbuf, s);
s=AE_Partner_GetFirstName(pt);
if (s && *s) {
if (GWEN_Buffer_GetUsedBytes(tbuf))
GWEN_Buffer_AppendString(tbuf, " ");
GWEN_Buffer_AppendString(tbuf, s);
}
s=AE_Partner_GetLastName(pt);
if (s && *s) {
if (GWEN_Buffer_GetUsedBytes(tbuf))
GWEN_Buffer_AppendString(tbuf, " ");
GWEN_Buffer_AppendString(tbuf, s);
}

s=GWEN_Buffer_GetStart(tbuf);
if (*s==0)
GWEN_Buffer_AppendString(tbuf, I18N("-unnamed account-"));
AE_Account_SetName(acc, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);

AE_Account_SetDescription(acc, I18N("Account|Account/Payable for Customer"));
rv=addAccount(p, at, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
signalDbReload(AE_Book_TableType_Account);
AE_Account_Tree_AddChild(parent, acc);
}

return acc;
}



AE_ACCOUNT *FF_App::getAccountForBankAccount(FXComposite *p,
AE_ACCOUNT_TREE *at,
AE_COMMODITY_LIST *cl,
const AE_BANKACCOUNT *ba,
AQDB_ID commodityId,
int doLock) {
AE_ACCOUNT *acc;
AQDB_ID bankAccountId;
int rv;

bankAccountId=AE_BankAccount_GetId(ba);

/* first find a complete match */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Bank &&
AE_Account_GetBankAccountId(acc)==bankAccountId &&
AE_Account_GetPrimaryCommodityId(acc)==commodityId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc==NULL) {
/* not found, so try partial match so that we can create a sub-account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Bank &&
AE_Account_GetBankAccountId(acc)==bankAccountId)
break;
acc=AE_Account_Tree_GetBelow(acc);
}

if (acc) {
AE_ACCOUNT *parent;
AE_COMMODITY *co;
const char *s;

/* found a matching account */
parent=acc;
co=AE_Commodity_List_GetById(cl, commodityId);
if (co==NULL) {
/* TODO: let the user pick the commodity */
DBG_ERROR(0, "Unknown commodity");
return NULL;
}

acc=AE_Account_new();
AE_Account_SetParentId(acc, AE_Account_GetId(parent));
AE_Account_SetType(acc, AE_AccountType_Bank);
AE_Account_SetBankAccountId(acc, AE_Account_GetBankAccountId(parent));
s=AE_Commodity_GetCode(co);
if (!(s && *s))
s=AE_Commodity_GetName(co);
AE_Account_SetName(acc, s);
AE_Account_SetPrimaryCommodityId(acc, AE_Commodity_GetId(co));
AE_Account_SetDescription(acc, I18N("Account|Account in different currency"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
signalDbReload(AE_Book_TableType_Account);
AE_Account_Tree_AddChild(parent, acc);
}
}

if (acc==NULL) {
AQDB_ID parentId;
AE_ACCOUNT *parent;
const char *s1;
const char *s2;
char accNameBuf[256];
char accDescrBuf[256];

/* account not found, need to create it. find toplevel asset account */
acc=AE_Account_Tree_GetFirst(at);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Asset)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Asset);
AE_Account_AddFlags(acc, AE_ACCOUNT_FLAGS_PLACEHOLDER);

AE_Account_SetName(acc, I18N("Account|Asset"));
AE_Account_SetDescription(acc, I18N("Account|Asset Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;

/* find bank account parent */
acc=AE_Account_Tree_GetFirstChild(parent);
while(acc) {
if (AE_Account_GetType(acc)==AE_AccountType_Bank &&
AE_Account_GetFlags(acc) & AE_ACCOUNT_FLAGS_PLACEHOLDER)
break;
acc=AE_Account_Tree_GetNext(acc);
}
if (acc==NULL) {
/* create bank account parent */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Bank);
AE_Account_SetParentId(acc, parentId);
AE_Account_AddFlags(acc, AE_ACCOUNT_FLAGS_PLACEHOLDER);
AE_Account_SetName(acc, I18N("Bank Accounts"));
AE_Account_SetDescription(acc, I18N("Bank Accounts"));
rv=AE_Book_AddAccount(m_book, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
AE_Account_Tree_Add(at, acc);
}
parent=acc;

/* create bank account */
parentId=AE_Account_GetId(parent);
acc=AE_Account_new();
AE_Account_SetType(acc, AE_AccountType_Bank);
AE_Account_SetParentId(acc, parentId);
AE_Account_SetBankAccountId(acc, bankAccountId);

s1=AE_BankAccount_GetCurrency(ba);
if (!(s1 && *s1)) {
DBG_ERROR(0, "No currency in bank account, assuming EUR");
s1="EUR";
}
if (s1 && *s1) {
AE_COMMODITY *co;

co=AE_Commodity_List_GetByCode(cl, s1);
if (co==NULL)
co=AE_Commodity_List_GetBySymbol(cl, s1);
if (co==NULL) {
/* TODO: let the user pick the commodity */
DBG_ERROR(0, "Unknown commodity [%s]", s1);
}
else {
AE_Account_SetPrimaryCommodityId(acc, AE_Commodity_GetId(co));
}
}

s1=AE_BankAccount_GetBankName(ba);
s2=AE_BankAccount_GetAccountName(ba);
if (s1 && *s1 && s2 && *s2) {
snprintf(accNameBuf, sizeof(accNameBuf)-1,
I18N("%s at %s"), s2, s1);
}
else {
s1=AE_BankAccount_GetBankCode(ba);
s2=AE_BankAccount_GetAccountNumber(ba);
if (s1 && *s1 && s2 && *s2) {
snprintf(accNameBuf, sizeof(accNameBuf)-1,
I18N("%s at %s"), s2, s1);
}
else {
s1=AE_BankAccount_GetIban(ba);
if (s1) {
snprintf(accNameBuf, sizeof(accNameBuf)-1,
I18N("%s"), s1);
}
else
snprintf(accNameBuf, sizeof(accNameBuf)-1,
I18N("unnamed bank account %08x"),
AE_BankAccount_GetId(ba));
}
}
accNameBuf[sizeof(accNameBuf)-1]=0;

s1=AE_BankAccount_GetAccountName(ba);
if (s1==NULL)
s1=AE_BankAccount_GetAccountNumber(ba);
if (s1==NULL)
s1=AE_BankAccount_GetIban(ba);
if (s1==NULL) {
DBG_ERROR(0, "Bank account %08x has no name/number/iban", AE_BankAccount_GetId(ba));
s1=I18N("unknown");
}
AE_Account_SetName(acc, s1);

s1=AE_BankAccount_GetBankCode(ba);
s2=AE_BankAccount_GetAccountNumber(ba);
if (s1 && *s1 && s2 && *s2) {
snprintf(accDescrBuf, sizeof(accDescrBuf)-1,
I18N("%s at %s"), s2, s1);
}
else {
s1=AE_BankAccount_GetIban(ba);
if (s1) {
snprintf(accDescrBuf, sizeof(accDescrBuf)-1,
"%s", s1);
}
else
snprintf(accDescrBuf, sizeof(accDescrBuf)-1,
I18N("unnamed bank account %08x"),
AE_BankAccount_GetId(ba));
}
accDescrBuf[sizeof(accDescrBuf)-1]=0;

AE_Account_SetDescription(acc, accDescrBuf);
rv=addAccount(p, at, AE_Book_TableType_Account, acc, doLock);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_free(acc);
return NULL;
}
signalDbReload(AE_Book_TableType_Account);
AE_Account_Tree_AddChild(parent, acc);
}

return acc;
}



int FF_App::_importSetMissingSplit(FXComposite *p,
AE_ACCOUNT_TREE *at,
AE_COMMODITY_LIST *cl,
AE_TRANSACTION *t) {
int rv;
int i;
int cnt;
const AE_STATEMENT *st;
AQDB_ID currencies[MAX_CURRENCIES_PER_TRANS];
AE_BOOK *b;

b=m_book;

st=AE_Transaction_GetStatement(t);
rv=AE_Transaction_SampleCommodities(t, currencies, MAX_CURRENCIES_PER_TRANS);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
return rv;
}

cnt=rv;
if (cnt==1) {
const char *s;

DBG_DEBUG(0, "Checking category");
s=AE_Statement_GetCategory(st);
if (s && *s) {
AE_ACCOUNT *acc;

/* try do find the account by category */
DBG_DEBUG(0, "Looking for category [%s]", s);
rv=AE_StatementImport_GetAccountForCategory(b, s, at, currencies[0],
&acc, 1);
if (rv<0) {
DBG_ERROR(0, "Could not get account for category [%s]", s);
}
else {
AQDB_VALUE *v;

v=AE_Transaction_CalculateSum(t, currencies[0]);
if (v) {
AE_SPLIT *sp;
AE_COMMODITY *co;

AQDB_Value_Negate(v);
co=AE_Commodity_List_GetById(cl, currencies[0]);
assert(co);

sp=AE_Split_new();
AE_Split_SetAmount(sp, v);
AE_Split_SetCommodityId(sp, currencies[0]);
AQDB_Value_free(v);

AE_Split_SetAccountId(sp, AE_Account_GetId(acc));
/* we are sure about the assignment since it comes directly from the category */
AE_Split_AddRuntimeFlags(sp, AE_SPLIT_RTFLAGS_MATCHAUTO2);
AE_Transaction_AddSplit(t, sp);

return 0;
}
}
}
}

for (i=0; i<cnt; i++) {
AQDB_VALUE *v;

v=AE_Transaction_CalculateSum(t, currencies[i]);
if (v) {
AE_SPLIT *sp;
AE_COMMODITY *co;
AE_ACCOUNT *acc;

AQDB_Value_Negate(v);
co=AE_Commodity_List_GetById(cl, currencies[i]);
assert(co);

sp=AE_Split_new();
AE_Split_SetAmount(sp, v);
AE_Split_SetCommodityId(sp, currencies[i]);
AQDB_Value_free(v);

/* TODO: use some rule-based methods to determine the missing split */
acc=getAutoEquityAccount(p, at, co, 1);
if (acc==NULL) {
DBG_ERROR(0, "here (%d)", rv);
AE_Split_free(sp);
return rv;
}

AE_Split_SetAccountId(sp, AE_Account_GetId(acc));
AE_Transaction_AddSplit(t, sp);
}
else {
DBG_ERROR(0, "here (%d)", rv);
return rv;
}
}

return 0;
}



int FF_App::importAsTransactions(FXComposite *p, AE_STATEMENT_LIST *sl) {
AE_BOOK *b;

b=m_book;
if (b) {
AE_TRANSACTION_LIST *tl;
AE_STATEMENT *st;
AE_ACCOUNT_TREE *at;
AE_COMMODITY_LIST *cl;
AE_BANKACCOUNT_LIST *bal;
int rv;

at=AE_Account_Tree_new();
rv=AE_Book_ReadAccountTree(b, AE_Book_TableType_Account, at);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Account_Tree_free(at);
return rv;
}

cl=AE_Commodity_List_new();
rv=AE_Book_ReadCommodityList(b, AE_Book_TableType_Commodity, cl);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
return rv;
}

bal=AE_BankAccount_List_new();
rv=AE_Book_ReadBankAccountList(b, AE_Book_TableType_BankAccount, bal);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
return rv;
}

tl=AE_Transaction_List_new();
st=AE_Statement_List_First(sl);
if (st) {
uint32_t lpid;

lpid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT |
GWEN_GUI_PROGRESS_ALLOW_EMBED |
GWEN_GUI_PROGRESS_DELAY,
I18N("Creating Transactions and Splits"),
I18N("Now creating transactions and splits from new transaction statements"),
AE_Statement_List_GetCount(sl),
0);
GWEN_Gui_ProgressLog2(lpid, GWEN_LoggerLevel_Info,
I18N("Creating splits and transactions for %d statements"),
AE_Statement_List_GetCount(sl));

while(st) {
AE_TRANSACTION *t;
int rv;
GWEN_BUFFER *tbuf;
const char *s;
t=AE_Transaction_new();
AE_Statement_Attach(st);
AE_Transaction_SetStatement(t, st);
AE_Transaction_SetStatementId(t, AE_Statement_GetId(st));
AE_Transaction_SetDate(t, AE_Statement_GetDate(st));
AE_Transaction_AddRuntimeFlags(t,
AE_TRANSACTION_RTFLAGS_IMPORT |
AE_TRANSACTION_RTFLAGS_NEW |
AE_TRANSACTION_RTFLAGS_MATCHNONE);
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
s=AE_Statement_GetRemoteName(st);
if (s && *s)
GWEN_Buffer_AppendString(tbuf, s);
s=AE_Statement_GetPurpose(st);
if (!(s && *s))
s=AE_Statement_GetInfoText(st);
if (s && *s){
if (GWEN_Buffer_GetUsedBytes(tbuf))
GWEN_Buffer_AppendString(tbuf, "\n");
GWEN_Buffer_AppendString(tbuf, s);
}
AE_Transaction_SetMemo(t, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
/* set first split */
rv=_importSetFirstSplit(p, at, cl, bal, t);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Transaction_free(t);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}
/* set second split */
rv=_importSetMissingSplit(p, at, cl, t);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Transaction_free(t);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}
AE_Transaction_List_Add(t, tl);

rv=GWEN_Gui_ProgressAdvance(lpid, GWEN_GUI_PROGRESS_ONE);
if (rv==GWEN_ERROR_USER_ABORTED) {
DBG_ERROR(0, "User aborted");
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

st=AE_Statement_List_Next(st);
}
GWEN_Gui_ProgressEnd(lpid);
}

/* show transactions to user */
if (FF_EditTransactions::editTransactions(this, p, I18N("Import Transactions"), tl)) {
AE_TRANSACTION *t;

/* import transactions */
t=AE_Transaction_List_First(tl);
if (t) {
uint32_t lpid;

lpid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT |
GWEN_GUI_PROGRESS_ALLOW_EMBED |
GWEN_GUI_PROGRESS_DELAY,
I18N("Storing Transactions and Splits"),
I18N("Now writing transactions and splits to database"),
AE_Transaction_List_GetCount(tl),
0);
GWEN_Gui_ProgressLog2(lpid, GWEN_LoggerLevel_Info,
I18N("Writing %d transactions to database"),
AE_Transaction_List_GetCount(tl));
DBG_ERROR(0, "Writing %d transactions", AE_Transaction_List_GetCount(tl));

rv=AE_Book_BeginEdit(b, 0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
GWEN_Gui_ProgressLog2(lpid, GWEN_LoggerLevel_Error,
I18N("Error locking database (%d)"),
rv);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

/* reread the account tree since it could have been changed from within the
* editTransaction dialog.
*/
AE_Account_Tree_Clear(at);
rv=AE_Book_ReadAccountTree(b, AE_Book_TableType_Account, at);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

rv=AE_Book_ReadAccountTreeBalances(b, at);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

while(t) {
/* add transaction */
rv=AE_Book_ApplyTransactionWithBalances(b, at, t, NULL, 0);
if (rv<0) {
FXMessageBox::error(this, FX::MBOX_OK,
I18N("Database Error"),
I18N("Could not write transaction and splits to database (error: %d)"),
rv);
DBG_ERROR(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

rv=GWEN_Gui_ProgressAdvance(lpid, GWEN_GUI_PROGRESS_ONE);
if (rv==GWEN_ERROR_USER_ABORTED) {
DBG_ERROR(0, "User aborted");
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

t=AE_Transaction_List_Next(t);
} /* while t */

/* write back balances */
rv=AE_Book_WriteAccountTreeBalances(b, at, 0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

/* reconcile transfers */
rv=AE_ReconTransfers_ReconTransfers(b, 0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

/* unlock db */
rv=AE_Book_EndEdit(b, 0);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
GWEN_Gui_ProgressEnd(lpid);
return rv;
}

GWEN_Gui_ProgressEnd(lpid);
} /* if t */
}

AE_Transaction_List_free(tl);
AE_BankAccount_List_free(bal);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);

signalDbReload(AE_Book_TableType_Account);
signalDbReload(AE_Book_TableType_Transaction);
signalDbReload(AE_Book_TableType_Split);
}
return 0;
}



int FF_App::importContext(FXComposite *p, AB_IMEXPORTER_CONTEXT *ctx) {
int rv;
AE_STATEMENT_LIST *newStatements;

rv=AB_Banking_FillGapsInImExporterContext(m_banking, ctx);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
/* ignore result here */
}

newStatements=AE_Statement_List_new();
rv=_importContext(p, ctx, newStatements);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Statement_List_free(newStatements);
return rv;
}

/* import transactions */
DBG_ERROR(0, "Got %d new statements", AE_Statement_List_GetCount(newStatements));

if (AE_Statement_List_GetCount(newStatements)) {
rv=importAsTransactions(p, newStatements);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Statement_List_free(newStatements);
return rv;
}
}

/* done */
AE_Statement_List_free(newStatements);
return 0;
}



bool FF_App::checkTransaction(FXComposite *p,
AE_ACCOUNT_TREE *at,
AE_COMMODITY_LIST *cl,
const AE_TRANSACTION *t,
bool quiet) {
int rv;
int i;
int cnt;
AE_SPLIT *sp;
AQDB_ID currencies[MAX_CURRENCIES_PER_TRANS];


sp=AE_Split_List_First(AE_Transaction_GetSplitList(t));
while(sp) {
if (AE_Split_GetAccountId(sp)==0) {
DBG_ERROR(AE_LOGDOMAIN, "Account id 0");
if (!quiet)
FXMessageBox::error(p, MBOX_OK,
I18N("Input Error"),
"%s",
I18N("At least one split has no account."));
return GWEN_ERROR_BAD_DATA;
}
sp=AE_Split_List_Next(sp);
}

rv=AE_Transaction_SampleCommodities(t, currencies, MAX_CURRENCIES_PER_TRANS);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
return rv;
}

cnt=rv;
for (i=0; i<cnt; i++) {
AQDB_VALUE *v;

v=AE_Transaction_CalculateSum(t, currencies[i]);
if (v) {
if (!AQDB_Value_IsZero(v)) {
AE_COMMODITY *co;
FXString commodity;

co=AE_Commodity_List_GetById(cl, currencies[i]);
if (co) {
const char *s;

s=AE_Commodity_GetSymbol(co);
if (s==NULL || *s==0)
s=AE_Commodity_GetCode(co);
if (s && *s) {
commodity=FXString(s);
}
}

if (!quiet) {
if (cnt==1)
FXMessageBox::error(p, MBOX_OK,
I18N("Input Error"),
"%s",
I18N("The sum of all splits does not equal zero"));
else
FXMessageBox::error(p, MBOX_OK,
I18N("Input Error"),
/* translator: %s is the name/symbol of the commodity */
I18N("The %s sum of all splits does not equal zero"),
commodity.text());
}
AQDB_Value_free(v);
return false;
}
AQDB_Value_free(v);
}
else {
DBG_ERROR(0, "here (%d)", rv);
return rv;
}
}

return true;
}



bool FF_App::checkTransaction(FXComposite *p,
const AE_TRANSACTION *t,
bool quiet) {
if (m_book) {
AE_ACCOUNT_TREE *at;
AE_COMMODITY_LIST *cl;
int rv;
bool res;

at=AE_Account_Tree_new();
rv=AE_Book_ReadAccountTree(m_book, AE_Book_TableType_Account, at);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Database Error"),
I18N("Error reading account tree from database (%d)"), rv);
AE_Account_Tree_free(at);
return false;
}

cl=AE_Commodity_List_new();
rv=AE_Book_ReadCommodityList(m_book, AE_Book_TableType_Commodity, cl);
if (rv<0) {
DBG_ERROR(0, "here (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Database Error"),
I18N("Error reading commodity list from database (%d)"), rv);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
return false;
}

res=checkTransaction(p, at, cl, t, quiet);
AE_Commodity_List_free(cl);
AE_Account_Tree_free(at);
return res;
}
else {
DBG_ERROR(0, "Book not open");
return false;
}
}



int FF_App::presentConflictList(const FXString &title,
const FXString &text,
AE_DBCONFLICT_LIST *tmpList) {
AE_DBCONFLICT_LIST *handledList;
uint32_t cnt;
int rv;

handledList=AE_DbConflict_List_new();
while(AE_DbConflict_List_GetCount(tmpList)) {
AE_DBCONFLICT *cfl;
AE_DBCONFLICT_LIST *newList;

if (!FF_ConflictHandler::handleConflicts(this, title, text, tmpList)) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_DbConflict_List_free(tmpList);
AE_DbConflict_List_free(handledList);
return GWEN_ERROR_USER_ABORTED;
}

/* determine new conflicts introduced by selected solutions */
newList=AE_DbConflict_List_new();
cfl=AE_DbConflict_List_First(tmpList);
while(cfl) {
AE_DBCONFLICTSOLUTION *sol;

sol=AE_DbConflict_GetSelectedSolution(cfl);
assert(sol);
rv=AE_DbConflictSolution_CheckConflicts(sol, cfl, newList);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error checking for conflicts: %d"), rv);
AE_DbConflict_List_free(newList);
AE_DbConflict_List_free(tmpList);
AE_DbConflict_List_free(handledList);
return rv;
}

cfl=AE_DbConflict_List_Next(cfl);
}

/* remove ids from new conflicts which are deleted in earlier conflicts */
cfl=AE_DbConflict_List_First(tmpList);
while(cfl) {
GWEN_IDLIST64_ITERATOR *it;

/* remove ids which are deleted in earlier conflicts */
it=GWEN_IdList64_Iterator_new(AE_DbConflict_GetIdList(cfl));
if (it) {
AQDB_ID id;

id=GWEN_IdList64_Iterator_GetFirstId(it);
while(id) {
AE_DBCONFLICT *hcfl;

/* find earlier conflict which handles this id */
hcfl=AE_DbConflict_List_First(handledList);
while(hcfl) {
if (AE_DbConflict_GetDbType(cfl)==AE_DbConflict_GetDbType(hcfl) &&
GWEN_IdList64_HasId(AE_DbConflict_GetIdList(hcfl), id)) {
AE_DBCONFLICTSOLUTION *sol;
sol=AE_DbConflict_GetSelectedSolution(hcfl);
assert(sol);
if (AE_DbConflictSolution_GetActionType(sol)==AQDB_ActionType_Remove) {
/* previous was deleted, so we can remove the id from the new list */
GWEN_IdList64_DelId(AE_DbConflict_GetIdList(hcfl), id);
break;
}
}
hcfl=AE_DbConflict_List_Next(hcfl);
}

id=GWEN_IdList64_Iterator_GetNextId(it);
}
}

cfl=AE_DbConflict_List_Next(cfl);
}

/* remove ids from previous conflicts which are deleted in newer conflicts */
cfl=AE_DbConflict_List_First(tmpList);
while(cfl) {
AE_DBCONFLICTSOLUTION *sol;

sol=AE_DbConflict_GetSelectedSolution(cfl);
assert(sol);
if (AE_DbConflictSolution_GetActionType(sol)==AQDB_ActionType_Remove) {
GWEN_IDLIST64_ITERATOR *it;

/* remove ids which are deleted in earlier conflicts */
it=GWEN_IdList64_Iterator_new(AE_DbConflict_GetIdList(cfl));
if (it) {
AQDB_ID id;

id=GWEN_IdList64_Iterator_GetFirstId(it);
while(id) {
AE_DBCONFLICT *hcfl;

/* find earlier conflict which handles this id */
hcfl=AE_DbConflict_List_First(handledList);
while(hcfl) {
if (AE_DbConflict_GetDbType(cfl)==AE_DbConflict_GetDbType(hcfl) &&
GWEN_IdList64_HasId(AE_DbConflict_GetIdList(hcfl), id)) {
AE_DBCONFLICTSOLUTION *sol;

sol=AE_DbConflict_GetSelectedSolution(hcfl);
assert(sol);
GWEN_IdList64_DelId(AE_DbConflict_GetIdList(hcfl), id);
}
hcfl=AE_DbConflict_List_Next(hcfl);
}

id=GWEN_IdList64_Iterator_GetNextId(it);
}
}
}

cfl=AE_DbConflict_List_Next(cfl);
}

/* move tmpList entries to handled list */
while( (cfl=AE_DbConflict_List_First(tmpList)) ) {
AE_DbConflict_List_Del(cfl);
AE_DbConflict_List_Add(cfl, handledList);
}
AE_DbConflict_List_free(tmpList);
tmpList=newList;
newList=NULL; /* just precaution */
}

/* apply solutions (last to first) */
cnt=AE_DbConflict_List_GetCount(handledList);
if (cnt) {
AE_DBCONFLICT *cfl;
uint32_t n=0;
uint32_t pid;

pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
GWEN_GUI_PROGRESS_SHOW_PROGRESS |
GWEN_GUI_PROGRESS_SHOW_ABORT,
I18N("Resolving Conflicts"),
I18N("Applying selected conflict solutions."),
cnt,
0);

cfl=AE_DbConflict_List_First(handledList);
while( (cfl=AE_DbConflict_List_Last(handledList)) ) {
AE_DBCONFLICTSOLUTION *sol;

sol=AE_DbConflict_GetSelectedSolution(cfl);
assert(sol);
rv=AE_DbConflictSolution_Exec(sol, cfl);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error applying conflict solution: %d"), rv);
AE_DbConflict_List_free(tmpList);
AE_DbConflict_List_free(handledList);
GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, I18N("Error writing transaction: %d"), rv);
GWEN_Gui_ProgressEnd(pid);
return rv;
}

AE_DbConflict_List_Del(cfl);
AE_DbConflict_free(cfl);
n++;

rv=GWEN_Gui_ProgressAdvance(pid, n);
if (rv==GWEN_ERROR_USER_ABORTED) {
AE_DbConflict_List_free(tmpList);
AE_DbConflict_List_free(handledList);
GWEN_Gui_ProgressLog(pid, GWEN_LoggerLevel_Error, I18N("Aborted by user"));
GWEN_Gui_ProgressEnd(pid);
return rv;
}

}
GWEN_Gui_ProgressEnd(pid);
}

AE_DbConflict_List_free(tmpList);
AE_DbConflict_List_free(handledList);

return 0;
}



int FF_App::_handleConflicts(const FXString &title,
const FXString &text,
AQDB_ACTION_TYPE action,
AE_BOOK_TABLE_TYPE tt,
AQDB_ID oid) {
AE_DBCONFLICT_LIST *tmpList;
int rv;

tmpList=AE_DbConflict_List_new();
rv=AE_Book_GetConflicts(m_book, action, tt, oid, tmpList);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error checking for conflicts: %d"), rv);
AE_DbConflict_List_free(tmpList);
return rv;
}

/* takes over tmpList */
rv=presentConflictList(title, text, tmpList);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}

return 0;
}



bool FF_App::deleteAccount(AQDB_ID id) {
int rv;
AE_ACCOUNT *a=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadAccount(m_book, AE_Book_TableType_Account, id, &a);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading account from database: %d"), rv);
AE_Account_free(a);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this account leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_Account,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Account_free(a);
return false;
}

rv=AE_Book_DeleteAccount(m_book, AE_Book_TableType_Account, a, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting account: %d"), rv);
AE_Account_free(a);
return false;
}
AE_Account_free(a);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deleteTransaction(AQDB_ID id) {
int rv;
AE_TRANSACTION *t=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadTransaction(m_book, AE_Book_TableType_Transaction, id, &t);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading account from database: %d"), rv);
AE_Transaction_free(t);
return false;
}

/* read sub-objects */
rv=AE_Book_ReadTransactionSubObjects(m_book, t);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading account from database: %d"), rv);
AE_Transaction_free(t);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this account leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_Transaction,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Transaction_free(t);
return false;
}

rv=AE_Book_ApplyTransaction(m_book, NULL, t, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting transaction: %d"), rv);
AE_Transaction_free(t);
return false;
}
AE_Transaction_free(t);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deleteBankAccount(AQDB_ID id) {
int rv;
AE_BANKACCOUNT *ba=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadBankAccount(m_book, AE_Book_TableType_BankAccount, id, &ba);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading bank account from database: %d"), rv);
AE_BankAccount_free(ba);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this bank account leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_BankAccount,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_BankAccount_free(ba);
return false;
}

rv=AE_Book_DeleteBankAccount(m_book, AE_Book_TableType_BankAccount, ba, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting bank account: %d"), rv);
AE_BankAccount_free(ba);
return false;
}
AE_BankAccount_free(ba);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deleteJob(AQDB_ID id) {
int rv;
AE_JOB *j=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadJob(m_book, AE_Book_TableType_Job, id, &j);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading job from database: %d"), rv);
AE_Job_free(j);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this job leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_Job,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Job_free(j);
return false;
}

rv=AE_Book_DeleteJob(m_book, AE_Book_TableType_Job, j, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting bank account: %d"), rv);
AE_Job_free(j);
return false;
}
AE_Job_free(j);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deleteTask(AQDB_ID id) {
int rv;
AE_TASK *tk=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadTask(m_book, AE_Book_TableType_Task, id, &tk);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading task from database: %d"), rv);
AE_Task_free(tk);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this task leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_Task,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Task_free(tk);
return false;
}

rv=AE_Book_DeleteTask(m_book, AE_Book_TableType_Task, tk, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting bank account: %d"), rv);
AE_Task_free(tk);
return false;
}
AE_Task_free(tk);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deletePartner(AQDB_ID id) {
int rv;
AE_PARTNER *pt=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadPartner(m_book, AE_Book_TableType_Partner, id, &pt);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading job from database: %d"), rv);
AE_Partner_free(pt);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this partner leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_Partner,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Partner_free(pt);
return false;
}

rv=AE_Book_DeletePartner(m_book, AE_Book_TableType_Partner, pt, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting partner: %d"), rv);
AE_Partner_free(pt);
return false;
}
AE_Partner_free(pt);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



bool FF_App::deletePartnerGroup(AQDB_ID id) {
int rv;
AE_GROUP *grp=NULL;

rv=AE_Book_BeginEdit(m_book, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Unable to lock database: %d"), rv);
return false;
}

rv=AE_Book_ReadGroup(m_book, AE_Book_TableType_PartnerGroup, id, &grp);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading job from database: %d"), rv);
AE_Group_free(grp);
return false;
}

rv=_handleConflicts(I18N("Data Conflicts"),
I18N("<p>Deleting this partner group leads to the following conflicts. "
"Please select appropriate solutions.</p>"
"<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
AQDB_ActionType_Remove,
AE_Book_TableType_PartnerGroup,
id);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
AE_Group_free(grp);
return false;
}

rv=AE_Book_DeleteGroup(m_book, AE_Book_TableType_PartnerGroup, grp, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error deleting partner group: %d"), rv);
AE_Group_free(grp);
return false;
}
AE_Group_free(grp);

rv=AE_Book_EndEdit(m_book, 0);
if (rv<0) {
AE_Book_EndEdit(m_book, AQDB_ACTION_FLAGS_ABORT);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error unlocking database: %d"), rv);
return false;
}

return true;
}



int FF_App::_execWithArgs(const FF_APPSPEC_LIST *asl, const FXString &an,
const char *fname, GWEN_DB_NODE *db) {
if (an.empty()) {
FXMessageBox::error(this, MBOX_OK,
I18N("Setup Error"),
"%s",
I18N("You have not yet specified an external PDF viewer.\n"
"You can do that from within the application setup dialog (menu: Edit/settings)"));
return GWEN_ERROR_INVALID;
}
else {
FF_APPSPEC *as;

as=FF_AppSpec_List_GetByName(asl, an.text());
if (as) {
const char *appName;
const char *appArgs;
GWEN_BUFFER *argBuf;
GWEN_PROCESS *pr;
GWEN_PROCESS_STATE pst;

argBuf=GWEN_Buffer_new(0, 256, 0, 1);
appName=FF_AppSpec_GetPath(as);
appArgs=FF_AppSpec_GetArguments(as);
if (!(appArgs && *appArgs))
GWEN_Buffer_AppendString(argBuf, fname);
else {
int rv;

/* replace vars in appArgs */
rv=AE_Utils_Replace_Vars(appArgs, argBuf, db);
if (rv<0) {
FXMessageBox::error(this, MBOX_OK,
I18N("Setup Error"),
I18N("There seems to be an error in the argument settings for the application %s."),
an.text());
GWEN_Buffer_free(argBuf);
return rv;
}
}

pr=GWEN_Process_new();
pst=GWEN_Process_Start(pr, appName, GWEN_Buffer_GetStart(argBuf));
if (pst!=GWEN_ProcessStateRunning) {
FXMessageBox::error(this, MBOX_OK,
I18N("Error"),
I18N("The following command couldn't be started: %s %s (%d)"),
appName, GWEN_Buffer_GetStart(argBuf), int(pst));
GWEN_Buffer_free(argBuf);
return GWEN_ERROR_IO;
}
GWEN_Buffer_free(argBuf);

/* process is now running */
DBG_INFO(AE_LOGDOMAIN, "Started app: %s %s", an.text(), GWEN_Buffer_GetStart(argBuf));
GWEN_Process_free(pr);
}
else {
FXMessageBox::error(this, MBOX_OK,
I18N("Setup Error"),
I18N("There is no application specification for %s"),
an.text());
return GWEN_ERROR_NOT_FOUND;
}
}

return 0;
}



int FF_App::viewPdfFile(const char *fname, GWEN_DB_NODE *db) {
return _execWithArgs(m_appSpecsPdfViewer, m_pdfViewerName, fname, db);
}



int FF_App::emailPdfFile(const char *fname, GWEN_DB_NODE *db) {
return _execWithArgs(m_appSpecsEmailClient, m_emailClientName, fname, db);
}



int FF_App::createLoadCellPhoneJob(const AE_LOAD_CELLPHONE *lc, AB_JOB **pJob) {
AB_ACCOUNT *a;
AB_JOB *j;
int rv;

a=AB_Banking_GetAccount(m_banking, AE_LoadCellPhone_GetBankAccountId(lc));
if (a==NULL) {
DBG_ERROR(0, "Account %d not found", AE_LoadCellPhone_GetBankAccountId(lc));
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("AqBanking account not found"));
return GWEN_ERROR_NOT_FOUND;
}

j=AB_JobLoadCellPhone_new(a);
rv=AB_Job_CheckAvailability(j);
if (rv<0) {
DBG_ERROR(0, "Job not available (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
I18N("Cellphone job is not available (%d)"), rv);
AB_Job_free(j);
return rv;
}
else {
const AB_CELLPHONE_PRODUCT_LIST *pl;
const AB_CELLPHONE_PRODUCT *p;
const char *sProvider;
const char *sProduct;
const char *s;
const AQDB_VALUE *vOrig;

pl=AB_JobLoadCellPhone_GetCellPhoneProductList(j);
if (pl==NULL) {
DBG_ERROR(0, "Job not available (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("No products available."));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}

sProvider=AE_LoadCellPhone_GetProviderName(lc);
if (sProvider && *sProvider==0)
sProvider=NULL;
sProduct=AE_LoadCellPhone_GetProductName(lc);
if (sProduct && *sProduct==0)
sProduct=NULL;
p=AB_CellPhoneProduct_List_First(pl);
while(p) {
const char *xProvider;
const char *xProduct;

xProvider=AB_CellPhoneProduct_GetProviderName(p);
xProduct=AB_CellPhoneProduct_GetProductName(p);
if (xProvider && *xProvider==0)
xProvider=NULL;
if (xProduct && *xProduct==0)
xProduct=NULL;

if ( ((sProvider && xProvider && strcasecmp(sProvider, xProvider)==0) ||
(sProvider==NULL && xProvider==NULL)) &&
((sProduct && xProduct && strcasecmp(sProduct, xProduct)==0) ||
(sProduct==NULL && xProduct==NULL))
)
break;
p=AB_CellPhoneProduct_List_Next(p);
}

if (p==NULL) {
DBG_ERROR(0, "Product not found");
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
I18N("Products \"%s/%s\" not found."),
sProvider?sProvider:I18N("none"),
sProduct?sProduct:I18N("none"));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}
AB_JobLoadCellPhone_SetCellPhoneProduct(j, p);

s=AE_LoadCellPhone_GetPhoneNumber(lc);
if (!(s && *s)) {
DBG_ERROR(0, "No phone number");
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("No phone number."));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}
else {
FXString sNum;

while(*s) {
if (isdigit(*s) || *s=='+')
sNum+=*s;
s++;
}
if (sNum.empty()) {
DBG_ERROR(0, "No phone number");
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("Invalid phone number."));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}
AB_JobLoadCellPhone_SetPhoneNumber(j, sNum.text());
}

vOrig=AE_LoadCellPhone_GetValue(lc);
s=AE_LoadCellPhone_GetCurrency(lc);
if (!(vOrig && s && *s)) {
DBG_ERROR(0, "No phone number");
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("Missing or incomplete amount."));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}
else {
GWEN_BUFFER *tbuf;
AB_VALUE *vb;

tbuf=GWEN_Buffer_new(0, 256, 0, 1);
AQDB_Value_toString(vOrig, tbuf);
GWEN_Buffer_AppendString(tbuf, ":");
GWEN_Buffer_AppendString(tbuf, s);
vb=AB_Value_fromString(GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
if (vb==NULL) {
DBG_ERROR(0, "Invalid amount");
FXMessageBox::error(this, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("Invalid amount."));
AB_Job_free(j);
return GWEN_ERROR_NOT_FOUND;
}
AB_JobLoadCellPhone_SetValue(j, vb);
AB_Value_free(vb);
}
}

*pJob=j;
return 0;
}



int FF_App::_cancelSingleTransferJob(AB_JOB *j, bool doLock) {
const AB_TRANSACTION *t;

t=AB_Job_GetTransaction(j);
if (t) {
AE_BOOK *b;

b=m_book;
if (b) {
int rv;
uint32_t appId;

appId=AB_Transaction_GetIdForApplication(t);
if (appId>0) {
AE_STATEMENT *st=NULL;

if (doLock) {
rv=AE_Book_BeginEdit(b, 0);
if (rv<0) {
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}

/* read */
rv=AE_Book_ReadStatement(b, AE_Book_TableType_BankTransfer, appId, &st);
if (rv<0) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error reading transfer from db (%d)."), rv);
return rv;
}

/* modify */
AE_Statement_SetStatus(st, AE_Statement_StatusAborted);

/* write */
rv=AE_Book_WriteStatement(b, AE_Book_TableType_BankTransfer, st, 0);
if (rv<0) {
if (doLock)
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
FXMessageBox::error(this, MBOX_OK,
I18N("Database Error"),
I18N("Error writing transfer back to db (%d)."), rv);
return rv;
}

/* unlock */
if (doLock) {
rv=AE_Book_EndEdit(b, 0);
if (rv<0) {
AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}

/* inform all views */
signalDbReload(AE_Book_TableType_BankTransfer);

return 0;
} /* if appId */
else {
/* no app id */
DBG_ERROR(0, "No idForApplication in transfer");
return GWEN_ERROR_INVALID;
}
} /* if b */
else {
DBG_ERROR(AE_LOGDOMAIN, "No book");
return GWEN_ERROR_NOT_OPEN;
}
}
else {
DBG_ERROR(0, "No transaction");
return GWEN_ERROR_INVALID;
}
}



int FF_App::_cancelCreateStoJob(AB_JOB *j, bool doLock) {
// TODO
return 0;
}



int FF_App::_cancelModifyStoJob(AB_JOB *j, bool doLock) {
// TODO
return 0;
}



int FF_App::cancelJob(AB_JOB *j, bool doLock) {
int rv=0;

switch(AB_Job_GetType(j)) {
case AB_Job_TypeTransfer:
case AB_Job_TypeInternalTransfer:
rv=_cancelSingleTransferJob(j, doLock);
break;

case AB_Job_TypeCreateStandingOrder:
rv=_cancelCreateStoJob(j, doLock);
break;

case AB_Job_TypeModifyStandingOrder:
rv=_cancelModifyStoJob(j, doLock);
break;

case AB_Job_TypeUnknown:
case AB_Job_TypeGetBalance:
case AB_Job_TypeGetTransactions:
case AB_Job_TypeDebitNote:
case AB_Job_TypeEuTransfer:
case AB_Job_TypeGetStandingOrders:
case AB_Job_TypeGetDatedTransfers:
case AB_Job_TypeDeleteStandingOrder:
case AB_Job_TypeCreateDatedTransfer:
case AB_Job_TypeModifyDatedTransfer:
case AB_Job_TypeDeleteDatedTransfer:
case AB_Job_TypeLoadCellPhone:
case AB_Job_TypeSepaTransfer:
case AB_Job_TypeSepaDebitNote:
rv=0;
break;
}

/* set status to "aborted" */
AB_Job_SetStatus(j, AB_Job_StatusError);

return rv;
}





int FF_App::execStatement(FXComposite *p, AE_STATEMENT *st, AQDB_ID tid) {
AE_BOOK *b;
AB_BANKING *ab;
b=getBook();
ab=getBanking();
if (b && ab) {
AE_BANKACCOUNT *ba=NULL;
AB_ACCOUNT *a;
AB_JOB *j;
AB_TRANSACTION *t;
int rv;
uint32_t baId=0;

rv=AE_Book_ReadBankAccount(b, AE_Book_TableType_BankAccount, AE_Statement_GetBankAccountId(st), &ba);
if (rv<0) {
DBG_ERROR(0, "Error reading bank account %lu",
(unsigned long int) AE_Statement_GetBankAccountId(st));
FXMessageBox::error(p, MBOX_OK,
I18N("Database Error"),
I18N("Error reading bank account %lu from database (%d)"),
(unsigned long int) AE_Statement_GetBankAccountId(st),
rv);
return GWEN_ERROR_NOT_FOUND;
}
baId=AE_BankAccount_GetBankingId(ba);
AE_BankAccount_free(ba);

a=AB_Banking_GetAccount(ab, baId);
if (a==NULL) {
DBG_ERROR(0, "Account %d not found", AE_Statement_GetBankAccountId(st));
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
"%s",
I18N("AqBanking account not found"));
return GWEN_ERROR_NOT_FOUND;
}

switch(AE_Statement_GetFlags(st) & AE_STATEMENT_FLAGS_XFER_TYPE_MASK) {
case AE_STATEMENT_FLAGS_XFER_TYPE_STD_XFER:
j=AB_JobSingleTransfer_new(a);
rv=AB_Job_CheckAvailability(j);
if (rv<0) {
DBG_ERROR(0, "Job not available (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("Transfer job is not available (%d)"), rv);
AB_Job_free(j);
return rv;
}
/* transform to banking transaction */
t=AB_Transaction_new();
rv=AE_StatementExport_StatementToTransaction(st, t);
if (rv<0) {
DBG_ERROR(0, "Error transforming statement to AB_TRANSACTION (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("Unable to create a banking transaction (%d)"), rv);
AB_Transaction_free(t);
AB_Job_free(j);
return rv;
}
/* always set data to NULL for non-dated transfers */
AB_Transaction_SetDate(t, NULL);
AB_Transaction_SetIdForApplication(t, tid);
AB_Job_SetTransaction(j, t);
addJobToList(j);
signalJobListUpdated();
break;

case AE_STATEMENT_FLAGS_XFER_TYPE_INT_XFER:
j=AB_JobInternalTransfer_new(a);
rv=AB_Job_CheckAvailability(j);
if (rv<0) {
DBG_ERROR(0, "Job not available (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("Internal transfer job is not available (%d)"), rv);
AB_Job_free(j);
return rv;
}
/* transform to banking transaction */
t=AB_Transaction_new();
rv=AE_StatementExport_StatementToTransaction(st, t);
if (rv<0) {
DBG_ERROR(0, "Error transforming statement to AB_TRANSACTION (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("Unable to create a banking transaction (%d)"), rv);
AB_Transaction_free(t);
AB_Job_free(j);
return rv;
}
/* always set data to NULL for non-dated transfers */
AB_Transaction_SetDate(t, NULL);
AB_Transaction_SetIdForApplication(t, tid);
AB_Job_SetTransaction(j, t);

addJobToList(j);
signalJobListUpdated();
break;

case AE_STATEMENT_FLAGS_XFER_TYPE_SEPA_XFER:
j=AB_JobSepaTransfer_new(a);
rv=AB_Job_CheckAvailability(j);
if (rv<0) {
DBG_ERROR(0, "Job not available (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("SEPA Transfer job is not available (%d)"), rv);
AB_Job_free(j);
return rv;
}
/* transform to banking transaction */
t=AB_Transaction_new();
rv=AE_StatementExport_StatementToTransaction(st, t);
if (rv<0) {
DBG_ERROR(0, "Error transforming statement to AB_TRANSACTION (%d)", rv);
FXMessageBox::error(p, MBOX_OK,
I18N("Banking Error"),
I18N("Unable to create a banking transaction (%d)"), rv);
AB_Transaction_free(t);
AB_Job_free(j);
return rv;
}
/* always set data to NULL for non-dated transfers */
AB_Transaction_SetDate(t, NULL);
AB_Transaction_SetIdForApplication(t, tid);
AB_Job_SetTransaction(j, t);
addJobToList(j);
signalJobListUpdated();
break;

default:
DBG_ERROR(0, "Unexpected transfer type (%d)",
AE_Statement_GetFlags(st) & AE_STATEMENT_FLAGS_XFER_TYPE_MASK);
FXMessageBox::error(p, MBOX_OK,
I18N("Internal Error"),
I18N("Unexpected transfer type (%d)"),
AE_Statement_GetFlags(st) & AE_STATEMENT_FLAGS_XFER_TYPE_MASK);
return GWEN_ERROR_INTERNAL;
}

return 0;
}
else {
DBG_ERROR(0, "Aborted by user");
return GWEN_ERROR_USER_ABORTED;
}
}






(3-3/17)