|
/****************************************************************************
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|