AUDIT: r17347 - gnucash/trunk/src/import-export/aqbanking - Bug #543049: Import all balances and txns in aqbanking contexts returned.

Andreas Köhler andi5 at cvs.gnucash.org
Sat Jul 19 22:09:16 EDT 2008


Author: andi5
Date: 2008-07-19 22:09:16 -0400 (Sat, 19 Jul 2008)
New Revision: 17347
Trac: http://svn.gnucash.org/trac/changeset/17347

Modified:
   gnucash/trunk/src/import-export/aqbanking/gnc-ab-getbalance.c
   gnucash/trunk/src/import-export/aqbanking/gnc-ab-gettrans.c
   gnucash/trunk/src/import-export/aqbanking/gnc-ab-transfer.c
   gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.c
   gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.h
   gnucash/trunk/src/import-export/aqbanking/gnc-file-aqb-import.c
Log:
Bug #543049: Import all balances and txns in aqbanking contexts returned.

* All aqbanking imports use the same code
* An account number returned by the bank may differ from the one sent, so that
  the correct result is not found
* The bank may also send transaction data and delete that on its servers.  This
  may lead to severe data loss if we did not tried to import of what is returned
  as much as possible

BP


Modified: gnucash/trunk/src/import-export/aqbanking/gnc-ab-getbalance.c
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-ab-getbalance.c	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-ab-getbalance.c	2008-07-20 02:09:16 UTC (rev 17347)
@@ -38,7 +38,6 @@
 #include "gnc-ab-utils.h"
 #include "gnc-gwen-gui.h"
 #include "gnc-ui.h"
-#include "RecnWindow.h"
 
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = G_LOG_DOMAIN;
@@ -53,15 +52,7 @@
     AB_JOB_LIST2 *job_list = NULL;
     GncGWENGui *gui = NULL;
     AB_IMEXPORTER_CONTEXT *context = NULL;
-    AB_IMEXPORTER_ACCOUNTINFO *acc_info = NULL;
-    AB_ACCOUNT_STATUS *status = NULL;
-    const AB_BALANCE *booked_bal, *noted_bal;
-    const AB_VALUE *booked_val = NULL, *noted_val = NULL;
-    gdouble booked_value, noted_value;
-    gnc_numeric value;
-    time_t booked_tt = 0;
-    GtkWidget *dialog;
-    gboolean show_recn_window = FALSE;
+    GncABImExContextImport *ieci = NULL;
 
     g_return_if_fail(parent && gnc_acc);
 
@@ -110,133 +101,12 @@
         goto cleanup;
     }
 
-    /* Lookup account in context */
-    acc_info = AB_ImExporterContext_FindAccountInfo(
-        context, gnc_ab_get_account_bankcode(gnc_acc),
-        gnc_ab_get_account_accountid(gnc_acc));
-    if (!acc_info) {
-        g_warning("gnc_ab_getbalance: No accountinfo result for this account");
-        goto cleanup;
-    }
+    /* Import the results */
+    ieci = gnc_ab_import_context(context, AWAIT_BALANCES, FALSE, NULL, parent);
 
-    /* Lookup newest data */
-    status = gnc_ab_get_best_accountstatus(acc_info);
-    if (!status) {
-        g_warning("gnc_ab_getbalance: No accountstatus result for this account");
-        goto cleanup;
-    }
-
-    /* Lookup booked balance and time */
-    booked_bal = AB_AccountStatus_GetBookedBalance(status);
-    if (booked_bal) {
-        const GWEN_TIME *ti = AB_Balance_GetTime(booked_bal);
-        if (ti) {
-            booked_tt =  GWEN_Time_toTime_t(ti);
-        } else {
-            /* No time found? Use today because the HBCI query asked for today's
-             * balance. */
-            booked_tt = gnc_timet_get_day_start(time(NULL));
-        }
-        booked_val = AB_Balance_GetValue(booked_bal);
-        if (booked_val) {
-            booked_value = AB_Value_GetValueAsDouble(booked_val);
-        } else {
-            g_warning("gnc_ab_getbalance: booked_val == NULL.  Assuming 0");
-            booked_value = 0.0;
-        }
-    } else {
-        g_warning("gnc_ab_getbalance: booked_bal == NULL.  Assuming 0");
-        booked_tt = 0;
-        booked_value = 0.0;
-    }
-
-    /* Lookup noted balance */
-    noted_bal = AB_AccountStatus_GetNotedBalance(status);
-    if (noted_bal) {
-        noted_val = AB_Balance_GetValue(noted_bal);
-        if (noted_val)
-            noted_value = AB_Value_GetValueAsDouble(noted_val);
-        else {
-            g_warning("gnc_ab_getbalance: noted_val == NULL.  Assuming 0");
-            noted_value = 0.0;
-        }
-    } else {
-        g_warning("gnc_ab_getbalance: noted_bal == NULL.  Assuming 0");
-        noted_value = 0.0;
-    }
-
-    value = double_to_gnc_numeric(booked_value,
-                                  xaccAccountGetCommoditySCU(gnc_acc),
-                                  GNC_RND_ROUND);
-    if (noted_value == 0.0 && booked_value == 0.0) {
-        dialog = gtk_message_dialog_new(
-            GTK_WINDOW(parent),
-            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-            GTK_MESSAGE_INFO,
-            GTK_BUTTONS_OK,
-            "%s",
-            /* Translators: Strings from this file are needed only in
-             * countries that have one of aqbanking's Online Banking
-             * techniques available. This is 'OFX DirectConnect'
-             * (U.S. and others), 'HBCI' (in Germany), or 'YellowNet'
-             * (Switzerland). If none of these techniques are available
-             * in your country, you may safely ignore strings from the
-             * import-export/hbci subdirectory. */
-            _("The downloaded Online Banking Balance was zero.\n\n"
-              "Either this is the correct balance, or your bank does not "
-              "support Balance download in this Online Banking version. "
-              "In the latter case you should choose a different "
-              "Online Banking version number in the Online Banking "
-              "(AqBanking or HBCI) Setup. After that, try again to "
-              "download the Online Banking Balance."));
-        gtk_dialog_run(GTK_DIALOG(dialog));
-        gtk_widget_destroy(dialog);
-
-    } else {
-        gnc_numeric reconc_balance = xaccAccountGetReconciledBalance(gnc_acc);
-
-        gchar *booked_str = gnc_AB_VALUE_to_readable_string(booked_val);
-        gchar *message1 = g_strdup_printf(
-            _("Result of Online Banking job: \n"
-              "Account booked balance is %s"),
-            booked_str);
-        gchar *message2 =
-            (noted_value == 0.0) ?
-            g_strdup("") :
-            g_strdup_printf(_("For your information: This account also "
-                              "has a noted balance of %s\n"),
-                            gnc_AB_VALUE_to_readable_string(noted_val));
-
-        if (gnc_numeric_equal(value, reconc_balance)) {
-            const gchar *message3 =
-                _("The booked balance is identical to the current "
-                  "reconciled balance of the account.");
-            dialog = gtk_message_dialog_new(
-                GTK_WINDOW(parent),
-                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                GTK_MESSAGE_INFO,
-                GTK_BUTTONS_OK,
-                "%s\n%s\n%s",
-                message1, message2, message3);
-            gtk_dialog_run(GTK_DIALOG(dialog));
-            gtk_widget_destroy(GTK_WIDGET(dialog));
-
-        } else {
-            const char *message3 = _("Reconcile account now?");
-
-            show_recn_window = gnc_verify_dialog(parent,TRUE, "%s\n%s\n%s",
-                                                 message1, message2, message3);
-        }
-        g_free(booked_str);
-        g_free(message1);
-        g_free(message2);
-    }
-
-    /* Show reconciliation window */
-    if (show_recn_window)
-        recnWindowWithBalance(parent, gnc_acc, value, booked_tt);
-
 cleanup:
+    if (ieci)
+        g_free(ieci);
     if (context)
         AB_ImExporterContext_free(context);
     if (gui)

Modified: gnucash/trunk/src/import-export/aqbanking/gnc-ab-gettrans.c
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-ab-gettrans.c	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-ab-gettrans.c	2008-07-20 02:09:16 UTC (rev 17347)
@@ -47,7 +47,6 @@
 typedef struct _TransListData TransListData;
 
 static gboolean gettrans_dates(GtkWidget *parent, Account *gnc_acc, GWEN_TIME **from_date, GWEN_TIME **to_date);
-static const AB_TRANSACTION *transaction_cb(const AB_TRANSACTION *ab_trans, gpointer user_data);
 
 struct _TransListData {
     Account *gnc_acc;
@@ -98,28 +97,6 @@
     return TRUE;
 }
 
-/**
- * Callback function for AB_ImExporterAccountInfo_TransactionsForEach().  The
- * conversion from AqBanking to GnuCash transaction is done here, once for each
- * AB_TRANSACTION.
- */
-static const AB_TRANSACTION *
-transaction_cb(const AB_TRANSACTION *ab_trans, gpointer user_data)
-{
-    TransListData *data = user_data;
-    Transaction *gnc_trans;
-
-    g_return_val_if_fail(ab_trans && data, NULL);
-
-    /* Create a GnuCash transaction from ab_trans */
-    gnc_trans = gnc_ab_trans_to_gnc(ab_trans, data->gnc_acc);
-
-    /* Instead of xaccTransCommitEdit(gnc_trans)  */
-    gnc_gen_trans_list_add_trans(data->importer_generic, gnc_trans);
-
-    return NULL;
-}
-
 void
 gnc_ab_gettrans(GtkWidget *parent, Account *gnc_acc)
 {
@@ -132,7 +109,7 @@
     AB_JOB_LIST2 *job_list = NULL;
     GncGWENGui *gui = NULL;
     AB_IMEXPORTER_CONTEXT *context = NULL;
-    AB_IMEXPORTER_ACCOUNTINFO *acc_info = NULL;
+    GncABImExContextImport *ieci = NULL;
 
     g_return_if_fail(parent && gnc_acc);
 
@@ -191,25 +168,10 @@
         goto cleanup;
     }
 
-    /* Lookup account in context */
-    acc_info = AB_ImExporterContext_FindAccountInfo(
-        context, gnc_ab_get_account_bankcode(gnc_acc),
-        gnc_ab_get_account_accountid(gnc_acc));
-    if (!acc_info) {
-        g_warning("gnc_ab_gettrans: No accountinfo result for this account");
-        goto cleanup;
-    }
-
-    if (AB_ImExporterAccountInfo_GetFirstTransaction(acc_info)) {
-        /* Import transactions */
-
-        TransListData data;
-        data.importer_generic = gnc_gen_trans_list_new(parent, NULL, TRUE, 14);
-        data.gnc_acc = gnc_acc;
-
-        AB_ImExporterAccountInfo_TransactionsForEach(acc_info, transaction_cb,
-                                                     &data);
-    } else {
+    /* Import the results */
+    ieci = gnc_ab_import_context(context, AWAIT_TRANSACTIONS, FALSE, NULL,
+                                 parent);
+    if (!(gnc_ab_ieci_get_found(ieci) & FOUND_TRANSACTIONS)) {
         /* No transaction found */
         GtkWidget *dialog = gtk_message_dialog_new(
             GTK_WINDOW(parent),
@@ -227,6 +189,8 @@
     gnc_ab_set_account_trans_retrieval(gnc_acc, until_timespec);
 
 cleanup:
+    if (ieci)
+        g_free(ieci);
     if (context)
         AB_ImExporterContext_free(context);
     if (gui)

Modified: gnucash/trunk/src/import-export/aqbanking/gnc-ab-transfer.c
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-ab-transfer.c	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-ab-transfer.c	2008-07-20 02:09:16 UTC (rev 17347)
@@ -133,6 +133,8 @@
         gchar *description;
         gchar *memo;
         Transaction *gnc_trans = NULL;
+        AB_IMEXPORTER_CONTEXT *context = NULL;
+        GncABImExContextImport *ieci = NULL;
 
         /* Get a GUI object */
         gui = gnc_GWEN_Gui_get(parent);
@@ -226,8 +228,11 @@
         }
 
         if (result == GNC_RESPONSE_NOW) {
+            /* Create a context to store possible results */
+            context = AB_ImExporterContext_new();
+
             /* Finally, execute the job */
-            successful = AB_Banking_ExecuteJobs(api, job_list, NULL, 0) == 0;
+            successful = AB_Banking_ExecuteJobs(api, job_list, context, 0) == 0;
 
             if (!successful
                 || AB_Job_GetStatus(job) != AB_Job_StatusFinished) {
@@ -248,6 +253,9 @@
                     aborted = TRUE;
                 }
             }
+
+            /* Import the results, awaiting nothing */
+            ieci = gnc_ab_import_context(context, 0, FALSE, NULL, parent);
         }
         /* Simply ignore any other case */
 
@@ -259,6 +267,10 @@
             xaccTransCommitEdit(gnc_trans);
             gnc_trans = NULL;
         }
+        if (ieci)
+            g_free(ieci);
+        if (context)
+            AB_ImExporterContext_free(context);
         if (job_list) {
             AB_Job_List2_free(job_list);
             job_list = NULL;

Modified: gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.c
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.c	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.c	2008-07-20 02:09:16 UTC (rev 17347)
@@ -33,11 +33,16 @@
 #include <gwenhywfar/gwenhywfar.h>
 #include <aqbanking/banking.h>
 
+#include "RecnWindow.h"
 #include "Transaction.h"
+#include "dialog-ab-trans.h"
 #include "gnc-ab-kvp.h"
 #include "gnc-ab-utils.h"
 #include "gnc-glib-utils.h"
 #include "gnc-gwen-gui.h"
+#include "gnc-ui.h"
+#include "import-account-matcher.h"
+#include "import-main-matcher.h"
 #include "import-utilities.h"
 #include "qof.h"
 
@@ -49,7 +54,27 @@
 static gint gnc_AB_BANKING_refcount = 0;
 
 static gpointer join_ab_strings_cb(const gchar *str, gpointer user_data);
+static Account *gnc_ab_accinfo_to_gnc_acc(
+    AB_IMEXPORTER_ACCOUNTINFO *account_info);
+static const AB_TRANSACTION *txn_transaction_cb(
+    const AB_TRANSACTION *element, gpointer user_data);
+static AB_IMEXPORTER_ACCOUNTINFO *txn_accountinfo_cb(
+    AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data);
+static AB_IMEXPORTER_ACCOUNTINFO *bal_accountinfo_cb(
+    AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data);
 
+struct _GncABImExContextImport {
+    guint awaiting;
+    gboolean txn_found;
+    Account *gnc_acc;
+    AB_ACCOUNT *ab_acc;
+    gboolean execute_txns;
+    AB_BANKING *api;
+    GtkWidget *parent;
+    AB_JOB_LIST2 *job_list;
+    GNCImportMainMatcher *generic_importer;
+};
+
 void
 gnc_GWEN_Init(void)
 {
@@ -393,22 +418,381 @@
     return gnc_trans;
 }
 
-AB_ACCOUNT_STATUS *
-gnc_ab_get_best_accountstatus(AB_IMEXPORTER_ACCOUNTINFO *acc_info)
+/**
+ * Call gnc_import_select_account() on the online id constructed using
+ * the information in @a acc_info.
+ *
+ * @param acc_info AB_IMEXPORTER_ACCOUNTINFO
+ * @return A GnuCash account, or NULL otherwise
+ */
+static Account *
+gnc_ab_accinfo_to_gnc_acc(AB_IMEXPORTER_ACCOUNTINFO *acc_info)
 {
+    gchar *online_id;
+    Account *gnc_acc;
+
+    g_return_val_if_fail(acc_info, NULL);
+
+    online_id = g_strconcat(AB_ImExporterAccountInfo_GetBankCode(acc_info),
+                            AB_ImExporterAccountInfo_GetAccountNumber(acc_info),
+                            (gchar*)NULL);
+    gnc_acc = gnc_import_select_account(
+        NULL, online_id, 1, AB_ImExporterAccountInfo_GetAccountName(acc_info),
+        NULL, ACCT_TYPE_NONE, NULL, NULL);
+    if (!gnc_acc) {
+        g_warning("gnc_ab_accinfo_to_gnc_acc: Could not determine source account"
+                  " for online_id %s", online_id);
+    }
+    g_free(online_id);
+
+    return gnc_acc;
+}
+
+static const AB_TRANSACTION *
+txn_transaction_cb(const AB_TRANSACTION *element, gpointer user_data)
+{
+    GncABImExContextImport *data = user_data;
+    Transaction *gnc_trans;
+
+    g_return_val_if_fail(element && data, NULL);
+
+    /* Create a GnuCash transaction from ab_trans */
+    gnc_trans = gnc_ab_trans_to_gnc(element, data->gnc_acc);
+
+    /* Instead of xaccTransCommitEdit(gnc_trans)  */
+    gnc_gen_trans_list_add_trans(data->generic_importer, gnc_trans);
+
+    if (data->execute_txns && data->ab_acc) {
+        AB_TRANSACTION *ab_trans = AB_Transaction_dup(element);
+        AB_JOB *job;
+
+        /* NEW: The imported transaction has been imported into gnucash.
+         * Now also add it as a job to aqbanking */
+        AB_Transaction_SetLocalBankCode(
+            ab_trans, AB_Account_GetBankCode(data->ab_acc));
+        AB_Transaction_SetLocalAccountNumber(
+            ab_trans, AB_Account_GetAccountNumber(data->ab_acc));
+        AB_Transaction_SetLocalCountry(ab_trans, "DE");
+
+        job = gnc_ab_get_trans_job(data->ab_acc, ab_trans, SINGLE_DEBITNOTE);
+
+        /* Check whether we really got a job */
+        if (!job) {
+            /* Oops, no job, probably not supported by bank */
+            if (gnc_verify_dialog(
+                    NULL, FALSE, "%s",
+                    _("The backend found an error during the preparation "
+                      "of the job. It is not possible to execute this job. \n"
+                      "\n"
+                      "Most probable the bank does not support your chosen "
+                      "job or your Online Banking account does not have the permission "
+                      "to execute this job. More error messages might be "
+                      "visible on your console log.\n"
+                      "\n"
+                      "Do you want to enter the job again?"))) {
+                gnc_error_dialog(NULL, "Sorry, not implemented yet.");
+            }
+            /* else */
+        }
+        AB_Job_List2_PushBack(data->job_list, job);
+
+        AB_Transaction_free(ab_trans);
+    }
+
+    return NULL;
+}
+
+static AB_IMEXPORTER_ACCOUNTINFO *
+txn_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
+{
+    GncABImExContextImport *data = user_data;
+    Account *gnc_acc;
+
+    g_return_val_if_fail(element && data, NULL);
+
+    if (data->awaiting & IGNORE_TRANSACTIONS)
+        /* Ignore them */
+        return NULL;
+
+    if (!AB_ImExporterAccountInfo_GetFirstTransaction(element))
+        /* No transaction found */
+        return NULL;
+    else
+        data->awaiting |= FOUND_TRANSACTIONS;
+
+    if (!(data->awaiting & AWAIT_TRANSACTIONS)) {
+        if (gnc_verify_dialog(data->parent, TRUE, "%s",
+                              _("The bank has sent transaction information "
+                                "in its response."
+                                "\n"
+                                "Do you want to import it?"))) {
+            data->awaiting |= AWAIT_TRANSACTIONS;
+        } else {
+            data->awaiting |= IGNORE_TRANSACTIONS;
+            return NULL;
+        }
+    }
+
+    /* Lookup the corresponding gnucash account */
+    gnc_acc = gnc_ab_accinfo_to_gnc_acc(element);
+    if (!gnc_acc) return NULL;
+    data->gnc_acc = gnc_acc;
+
+    if (data->execute_txns) {
+        /* Retrieve the aqbanking account that belongs to this gnucash
+         * account */
+        data->ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
+        if (!data->ab_acc) {
+            gnc_error_dialog(NULL, "%s",
+                             _("No Online Banking account found for this "
+                               "gnucash account. These transactions will "
+                               "not be executed by Online Banking."));
+        }
+    } else {
+        data->ab_acc = NULL;
+    }
+
+    if (!data->generic_importer)
+        data->generic_importer = gnc_gen_trans_list_new(data->parent, NULL,
+                                                        TRUE, 14);
+
+    /* Iterate through all transactions */
+    AB_ImExporterAccountInfo_TransactionsForEach(element, txn_transaction_cb,
+                                                 data);
+
+    return NULL;
+}
+
+static AB_IMEXPORTER_ACCOUNTINFO *
+bal_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
+{
+    GncABImExContextImport *data = user_data;
+    Account *gnc_acc;
     AB_ACCOUNT_STATUS *item, *best = NULL;
     const GWEN_TIME *best_time;
+    const AB_BALANCE *booked_bal, *noted_bal;
+    const AB_VALUE *booked_val = NULL, *noted_val = NULL;
+    gdouble booked_value, noted_value;
+    gnc_numeric value;
+    time_t booked_tt = 0;
+    GtkWidget *dialog;
+    gboolean show_recn_window = FALSE;
 
-    g_return_val_if_fail(acc_info, NULL);
+    g_return_val_if_fail(element && data, NULL);
 
-    item = AB_ImExporterAccountInfo_GetFirstAccountStatus(acc_info);
+    if (data->awaiting & IGNORE_BALANCES)
+        /* Ignore them */
+        return NULL;
+
+    if (!AB_ImExporterAccountInfo_GetFirstAccountStatus(element))
+        /* No balance found */
+        return NULL;
+    else
+        data->awaiting |= FOUND_BALANCES;
+
+    if (!(data->awaiting & AWAIT_BALANCES)) {
+        if (gnc_verify_dialog(data->parent, TRUE, "%s",
+                              _("The bank has sent balance information "
+                                "in its response."
+                                "\n"
+                                "Do you want to import it?"))) {
+            data->awaiting |= AWAIT_BALANCES;
+        } else {
+            data->awaiting |= IGNORE_BALANCES;
+            return NULL;
+        }
+    }
+
+    /* Lookup the corresponding gnucash account */
+    gnc_acc = gnc_ab_accinfo_to_gnc_acc(element);
+    if (!gnc_acc) return NULL;
+    data->gnc_acc = gnc_acc;
+
+    /* Lookup the most recent ACCOUNT_STATUS available */
+    item = AB_ImExporterAccountInfo_GetFirstAccountStatus(element);
     while (item) {
         const GWEN_TIME *item_time = AB_AccountStatus_GetTime(item);
         if (!best || GWEN_Time_Diff(best_time, item_time) < 0.0) {
             best = item;
             best_time = item_time;
         }
-        item = AB_ImExporterAccountInfo_GetNextAccountStatus(acc_info);
+        item = AB_ImExporterAccountInfo_GetNextAccountStatus(element);
     }
-    return best;
+
+    /* Lookup booked balance and time */
+    booked_bal = AB_AccountStatus_GetBookedBalance(best);
+    if (booked_bal) {
+        const GWEN_TIME *ti = AB_Balance_GetTime(booked_bal);
+        if (ti) {
+            booked_tt =  GWEN_Time_toTime_t(ti);
+        } else {
+            /* No time found? Use today because the HBCI query asked for today's
+             * balance. */
+            booked_tt = gnc_timet_get_day_start(time(NULL));
+        }
+        booked_val = AB_Balance_GetValue(booked_bal);
+        if (booked_val) {
+            booked_value = AB_Value_GetValueAsDouble(booked_val);
+        } else {
+            g_warning("bal_accountinfo_cb: booked_val == NULL.  Assuming 0");
+            booked_value = 0.0;
+        }
+    } else {
+        g_warning("bal_accountinfo_cb: booked_bal == NULL.  Assuming 0");
+        booked_tt = 0;
+        booked_value = 0.0;
+    }
+
+    /* Lookup noted balance */
+    noted_bal = AB_AccountStatus_GetNotedBalance(best);
+    if (noted_bal) {
+        noted_val = AB_Balance_GetValue(noted_bal);
+        if (noted_val)
+            noted_value = AB_Value_GetValueAsDouble(noted_val);
+        else {
+            g_warning("bal_accountinfo_cb: noted_val == NULL.  Assuming 0");
+            noted_value = 0.0;
+        }
+    } else {
+        g_warning("bal_accountinfo_cb: noted_bal == NULL.  Assuming 0");
+        noted_value = 0.0;
+    }
+
+    value = double_to_gnc_numeric(booked_value,
+                                  xaccAccountGetCommoditySCU(gnc_acc),
+                                  GNC_RND_ROUND);
+    if (noted_value == 0.0 && booked_value == 0.0) {
+        dialog = gtk_message_dialog_new(
+            GTK_WINDOW(data->parent),
+            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+            GTK_MESSAGE_INFO,
+            GTK_BUTTONS_OK,
+            "%s",
+            /* Translators: Strings from this file are needed only in
+             * countries that have one of aqbanking's Online Banking
+             * techniques available. This is 'OFX DirectConnect'
+             * (U.S. and others), 'HBCI' (in Germany), or 'YellowNet'
+             * (Switzerland). If none of these techniques are available
+             * in your country, you may safely ignore strings from the
+             * import-export/hbci subdirectory. */
+            _("The downloaded Online Banking Balance was zero.\n\n"
+              "Either this is the correct balance, or your bank does not "
+              "support Balance download in this Online Banking version. "
+              "In the latter case you should choose a different "
+              "Online Banking version number in the Online Banking "
+              "(AqBanking or HBCI) Setup. After that, try again to "
+              "download the Online Banking Balance."));
+        gtk_dialog_run(GTK_DIALOG(dialog));
+        gtk_widget_destroy(dialog);
+
+    } else {
+        gnc_numeric reconc_balance = xaccAccountGetReconciledBalance(gnc_acc);
+
+        gchar *booked_str = gnc_AB_VALUE_to_readable_string(booked_val);
+        gchar *message1 = g_strdup_printf(
+            _("Result of Online Banking job: \n"
+              "Account booked balance is %s"),
+            booked_str);
+        gchar *message2 =
+            (noted_value == 0.0) ?
+            g_strdup("") :
+            g_strdup_printf(_("For your information: This account also "
+                              "has a noted balance of %s\n"),
+                            gnc_AB_VALUE_to_readable_string(noted_val));
+
+        if (gnc_numeric_equal(value, reconc_balance)) {
+            const gchar *message3 =
+                _("The booked balance is identical to the current "
+                  "reconciled balance of the account.");
+            dialog = gtk_message_dialog_new(
+                GTK_WINDOW(data->parent),
+                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                GTK_MESSAGE_INFO,
+                GTK_BUTTONS_OK,
+                "%s\n%s\n%s",
+                message1, message2, message3);
+            gtk_dialog_run(GTK_DIALOG(dialog));
+            gtk_widget_destroy(GTK_WIDGET(dialog));
+
+        } else {
+            const char *message3 = _("Reconcile account now?");
+
+            show_recn_window = gnc_verify_dialog(data->parent,TRUE, "%s\n%s\n%s",
+                                                 message1, message2, message3);
+        }
+        g_free(booked_str);
+        g_free(message1);
+        g_free(message2);
+    }
+
+    /* Show reconciliation window */
+    if (show_recn_window)
+        recnWindowWithBalance(data->parent, gnc_acc, value, booked_tt);
+
+    return NULL;
 }
+
+GncABImExContextImport *
+gnc_ab_import_context(AB_IMEXPORTER_CONTEXT *context,
+                      guint awaiting, gboolean execute_txns,
+                      AB_BANKING *api, GtkWidget *parent)
+{
+    GncABImExContextImport *data = g_new(GncABImExContextImport, 1);
+
+    g_return_val_if_fail(context, NULL);
+    /* Do not await and ignore at the same time */
+    g_return_val_if_fail(!(awaiting & AWAIT_BALANCES)
+                         || !(awaiting & IGNORE_BALANCES),
+                         NULL);
+    g_return_val_if_fail(!(awaiting & AWAIT_TRANSACTIONS)
+                         || !(awaiting & IGNORE_TRANSACTIONS),
+                         NULL);
+    /* execute_txns must be FALSE if txns are not awaited */
+    g_return_val_if_fail(awaiting & AWAIT_TRANSACTIONS || !execute_txns, NULL);
+    /* An api is needed for the jobs */
+    g_return_val_if_fail(!execute_txns || api, NULL);
+
+    data->awaiting = awaiting;
+    data->txn_found = FALSE;
+    data->execute_txns = execute_txns;
+    data->api = api;
+    data->parent = parent;
+    data->job_list = NULL;
+    data->generic_importer = NULL;
+
+    /* Import transactions */
+    if (!(awaiting & IGNORE_TRANSACTIONS))
+        AB_ImExporterContext_AccountInfoForEach(context, txn_accountinfo_cb,
+                                                data);
+
+    /* Check balances */
+    if (!(awaiting & IGNORE_BALANCES))
+        AB_ImExporterContext_AccountInfoForEach(context, bal_accountinfo_cb,
+                                                data);
+
+    return data;
+}
+
+guint
+gnc_ab_ieci_get_found(GncABImExContextImport *ieci)
+{
+    g_return_val_if_fail(ieci, 0);
+
+    return ieci->awaiting;
+}
+
+AB_JOB_LIST2 *
+gnc_ab_ieci_get_job_list(GncABImExContextImport *ieci)
+{
+    g_return_val_if_fail(ieci, NULL);
+
+    return ieci->job_list;
+}
+
+gboolean
+gnc_ab_ieci_run_matcher(GncABImExContextImport *ieci)
+{
+    g_return_val_if_fail(ieci, FALSE);
+
+    return gnc_gen_trans_list_run(ieci->generic_importer);
+}

Modified: gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.h
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.h	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-ab-utils.h	2008-07-20 02:09:16 UTC (rev 17347)
@@ -34,6 +34,7 @@
 #define GNC_AB_UTILS_H
 
 #include <glib.h>
+#include <gtk/gtk.h>
 #include <aqbanking/banking.h>
 
 #include "Account.h"
@@ -45,6 +46,15 @@
 #define KEY_FORMAT_SWIFT942 "format_swift_mt942"
 #define KEY_FORMAT_DTAUS "format_dtaus"
 
+typedef struct _GncABImExContextImport GncABImExContextImport;
+
+#define AWAIT_BALANCES      1 << 1
+#define FOUND_BALANCES      1 << 2
+#define IGNORE_BALANCES     1 << 3
+#define AWAIT_TRANSACTIONS  1 << 4
+#define FOUND_TRANSACTIONS  1 << 5
+#define IGNORE_TRANSACTIONS 1 << 6
+
 /**
  * Initialize the gwenhywfar library by calling GWEN_Init() and setting up
  * gwenhywfar logging.
@@ -156,16 +166,58 @@
 Transaction *gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc);
 
 /**
- * Lookup the most recent ACCOUNT_STATUS available in an ACCOUNTINFO as
- * extracted from an IMEXPORTER_CONTEXT.  This can be used to determine the
- * reported account balance most up-to-date.
+ * Import balances and transactions found in a AB_IMEXPORTER_CONTEXT into
+ * GnuCash.  By using @a awaiting the caller can specify what the user will
+ * expect to receive.  By using @a execute_txns, transactions in @a context can
+ * be used to generate corresponding AqBanking jobs, e.g. after a file import.
  *
- * @param acc_info ACCOUNTINFO
- * @return An AB_ACCOUNT_STATUS internal to @a acc_info, or NULL otherwise
+ * @param context AB_IMEXPORTER_CONTEXT to import
+ *
+ * @param awaiting Information the caller expects to receive or wants to ignore,
+ * bitmask of AWAIT_* or IGNORE_* values
+ *
+ * @param execute_txns If @a awaiting contains AWAIT_TRANSACTIONS, whether to
+ * create an aqbanking job for each of the transactions found
+ *
+ * @param api If @a execute_txns is TRUE, the AB_BANKING to get
+ * AB_ACCOUNTs from
+ *
+ * @param parent Widget to set new dialogs transient for, may be NULL
+ *
+ * @return A new GncABImExContextImport object which must be freed with
+ * g_free(), or NULL otherwise.  If execute_txns is TRUE, additionally
+ * gnc_ab_ieci_get_job_list() must be called and the result freed with
+ * AB_Job_List2_FreeAll()
  */
-AB_ACCOUNT_STATUS *gnc_ab_get_best_accountstatus(
-    AB_IMEXPORTER_ACCOUNTINFO *acc_info);
+GncABImExContextImport *gnc_ab_import_context(
+    AB_IMEXPORTER_CONTEXT *context, guint awaiting, gboolean execute_txns,
+    AB_BANKING *api, GtkWidget *parent);
 
+/**
+ * Extract awaiting from @a data.
+ *
+ * @param ieci The return value of gnc_ab_import_context()
+ * @return The initial awaiting bitmask plus IGNORE_* for unexpected and then
+ * ignored items, and FOUND_* for non-empty items
+ */
+guint gnc_ab_ieci_get_found(GncABImExContextImport *ieci);
+
+/**
+ * Extract the job list from @a data.
+ *
+ * @param ieci The return value of gnc_ab_import_context()
+ * @return The list of jobs, freeable with AB_Job_List2_FreeAll()
+ */
+AB_JOB_LIST2 *gnc_ab_ieci_get_job_list(GncABImExContextImport *ieci);
+
+/**
+ * Run the generic transaction matcher dialog.
+ *
+ * @param ieci The return value of gnc_ab_import_context()
+ * @return The return value of gnc_gen_trans_list_run().
+ */
+gboolean gnc_ab_ieci_run_matcher(GncABImExContextImport *ieci);
+
 G_END_DECLS
 
 /** @} */

Modified: gnucash/trunk/src/import-export/aqbanking/gnc-file-aqb-import.c
===================================================================
--- gnucash/trunk/src/import-export/aqbanking/gnc-file-aqb-import.c	2008-07-20 02:09:06 UTC (rev 17346)
+++ gnucash/trunk/src/import-export/aqbanking/gnc-file-aqb-import.c	2008-07-20 02:09:16 UTC (rev 17347)
@@ -53,143 +53,6 @@
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = GNC_MOD_IMPORT;
 
-typedef struct _ImportData ImportData;
-
-static const AB_TRANSACTION *transaction_cb(
-    const AB_TRANSACTION *element, gpointer user_data);
-static AB_IMEXPORTER_ACCOUNTINFO *accountinfo_cb(
-    AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data);
-static AB_JOB_LIST2 *import_context(
-    AB_BANKING *api, AB_IMEXPORTER_CONTEXT *context,
-    GNCImportMainMatcher *importer_generic_gui, gboolean execute_transactions);
-
-struct _ImportData {
-    AB_BANKING *api;
-    GNCImportMainMatcher *importer_generic;
-    gboolean execute_transactions;
-    AB_JOB_LIST2 *job_list;
-    Account *gnc_acc;
-    AB_ACCOUNT *ab_acc;
-};
-
-static const AB_TRANSACTION *
-transaction_cb(const AB_TRANSACTION *element, gpointer user_data)
-{
-    ImportData *data = user_data;
-    Transaction *gnc_trans;
-    AB_JOB *job;
-
-    g_return_val_if_fail(element && data, NULL);
-
-    /* Create a GnuCash transaction from ab_trans */
-    gnc_trans = gnc_ab_trans_to_gnc(element, data->gnc_acc);
-
-    /* Instead of xaccTransCommitEdit(gnc_trans)  */
-    gnc_gen_trans_list_add_trans(data->importer_generic, gnc_trans);
-
-    if (data->ab_acc) {
-        AB_TRANSACTION *ab_trans = AB_Transaction_dup(element);
-
-        /* NEW: The imported transaction has been imported into gnucash.
-         * Now also add it as a job to aqbanking */
-        AB_Transaction_SetLocalBankCode(
-            ab_trans, AB_Account_GetBankCode(data->ab_acc));
-        AB_Transaction_SetLocalAccountNumber(
-            ab_trans, AB_Account_GetAccountNumber(data->ab_acc));
-        AB_Transaction_SetLocalCountry(ab_trans, "DE");
-
-        job = gnc_ab_get_trans_job(data->ab_acc, ab_trans, SINGLE_DEBITNOTE);
-
-        /* Check whether we really got a job */
-        if (!job) {
-            /* Oops, no job, probably not supported by bank */
-            if (gnc_verify_dialog(
-                    NULL, FALSE, "%s",
-                    _("The backend found an error during the preparation "
-                      "of the job. It is not possible to execute this job. \n"
-                      "\n"
-                      "Most probable the bank does not support your chosen "
-                      "job or your Online Banking account does not have the permission "
-                      "to execute this job. More error messages might be "
-                      "visible on your console log.\n"
-                      "\n"
-                      "Do you want to enter the job again?"))) {
-                gnc_error_dialog(NULL, "Sorry, not implemented yet.");
-            }
-            /* else */
-        }
-        AB_Job_List2_PushBack(data->job_list, job);
-
-        AB_Transaction_free(ab_trans);
-    }
-
-    return NULL;
-}
-
-static AB_IMEXPORTER_ACCOUNTINFO *
-accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
-{
-    Account *gnc_acc;
-    ImportData *data = user_data;
-    const gchar *bank_code =
-        AB_ImExporterAccountInfo_GetBankCode(element);
-    const gchar *account_number =
-        AB_ImExporterAccountInfo_GetAccountNumber(element);
-    const gchar *account_name =
-        AB_ImExporterAccountInfo_GetAccountName(element);
-    gchar *online_id;
-
-    g_return_val_if_fail(element && data, NULL);
-
-    online_id = g_strconcat(bank_code, account_number, (gchar*)NULL);
-    gnc_acc = gnc_import_select_account(NULL, online_id, 1, account_name, NULL,
-                                        ACCT_TYPE_NONE, NULL, NULL);
-    g_free(online_id);
-
-    if (gnc_acc) {
-        /* Store chosen gnucash account in callback data */
-        data->gnc_acc = gnc_acc;
-
-        if (data->execute_transactions) {
-            /* Retrieve the aqbanking account that belongs to this gnucash
-             * account */
-            data->ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
-            if (!data->ab_acc) {
-                gnc_error_dialog(NULL, "%s",
-                                 _("No Online Banking account found for this "
-                                   "gnucash account. These transactions will "
-                                   "not be executed by Online Banking."));
-            }
-        } else {
-            data->ab_acc = NULL;
-        }
-
-        /* Iterate through all transactions.  */
-        AB_ImExporterAccountInfo_TransactionsForEach(element, transaction_cb,
-                                                     data);
-    }
-    return NULL;
-}
-
-static AB_JOB_LIST2 *
-import_context(AB_BANKING *api, AB_IMEXPORTER_CONTEXT *context,
-               GNCImportMainMatcher *importer_generic_gui,
-               gboolean execute_transactions)
-{
-    ImportData data;
-
-    g_return_val_if_fail(api && context && importer_generic_gui, NULL);
-    data.api = api;
-    data.importer_generic = importer_generic_gui;
-    data.execute_transactions = execute_transactions;
-    data.job_list = NULL;
-
-    /* Iterate through all accounts */
-    AB_ImExporterContext_AccountInfoForEach(context, accountinfo_cb, &data);
-
-    return data.job_list;
-}
-
 void
 gnc_file_aqbanking_import(const gchar *aqbanking_importername,
                           const gchar *aqbanking_profilename,
@@ -206,7 +69,7 @@
     GWEN_DB_NODE *db_profile;
     AB_IMEXPORTER_CONTEXT *context = NULL;
     GWEN_IO_LAYER *io, *buffio;
-    GNCImportMainMatcher *importer_generic_gui = NULL;
+    GncABImExContextImport *ieci = NULL;
     AB_JOB_LIST2 *job_list = NULL;
 
     /* Select a file */
@@ -308,15 +171,17 @@
     /* Close the file */
     GWEN_Io_Layer_free(buffio);
 
-    /* Create importer GUI */
-    importer_generic_gui = gnc_gen_trans_list_new(NULL, NULL, TRUE, 14);
+    /* Import the results */
+    ieci = gnc_ab_import_context(context, AWAIT_TRANSACTIONS,
+                                 execute_transactions,
+                                 execute_transactions ? api : NULL,
+                                 NULL);
 
-    /* Import the transactions from the context into gnucash */
-    job_list = import_context(api, context, importer_generic_gui,
-                              execute_transactions);
+    /* Extract the list of jobs */
+    job_list = gnc_ab_ieci_get_job_list(ieci);
 
     if (execute_transactions) {
-        if (gnc_gen_trans_list_run(importer_generic_gui)) {
+        if (gnc_ab_ieci_run_matcher(ieci)) {
             /* FIXME */
             /* gnc_hbci_multijob_execute(NULL, api, job_list, gui); */
         }
@@ -324,9 +189,9 @@
 
 cleanup:
     if (job_list)
-        AB_Job_List2_free(job_list);
-    if (importer_generic_gui)
-        gnc_gen_trans_list_delete(importer_generic_gui);
+        AB_Job_List2_FreeAll(job_list);
+    if (ieci)
+        g_free(ieci);
     if (context)
         AB_ImExporterContext_free(context);
     if (db_profiles)



More information about the gnucash-changes mailing list