GnuCash  5.6-150-g038405b370+
gnc-ab-utils.c
1 /*
2  * gnc-ab-utils.c --
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation Voice: +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19  * Boston, MA 02110-1301, USA gnu@gnu.org
20  */
21 
30 #include <config.h>
31 
32 #include "gnc-ab-utils.h"
33 
34 #include <glib/gi18n.h>
35 #include <gwenhywfar/gwenhywfar.h>
36 #include <aqbanking/banking.h>
37 #include <aqbanking/types/balance.h>
38 #if (AQBANKING_VERSION_INT >= 60400)
39 #include <aqbanking/types/refaccount.h>
40 #include <gnc-aqbanking-templates.h>
41 #endif
42 #include "window-reconcile.h"
43 #include "Transaction.h"
44 #include "dialog-ab-trans.h"
45 #include "gnc-ab-kvp.h"
46 #include "gnc-glib-utils.h"
47 #include "gnc-gwen-gui.h"
48 #include "gnc-prefs.h"
49 #include "gnc-ui.h"
50 #include "import-account-matcher.h"
51 #include "import-main-matcher.h"
52 #include "qof.h"
53 #include "engine-helpers.h"
54 #include <aqbanking/gui/abgui.h>
55 
56 /* This static indicates the debugging module that this .o belongs to. */
57 G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
58 
59 /* Global variables for AB_BANKING caching. */
60 static AB_BANKING *gnc_AB_BANKING = NULL;
61 static gint gnc_AB_BANKING_refcount = 0;
62 
63 static gpointer join_ab_strings_cb (const gchar *str, gpointer user_data);
64 static Account *gnc_ab_accinfo_to_gnc_acc (GtkWidget *parent,
65  AB_IMEXPORTER_ACCOUNTINFO *account_info);
66 static Account *gnc_ab_txn_to_gnc_acc (GtkWidget *parent,
67  const AB_TRANSACTION *transaction);
68 static const AB_TRANSACTION *txn_transaction_cb (const AB_TRANSACTION *element,
69  gpointer user_data);
70 static AB_IMEXPORTER_ACCOUNTINFO *txn_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element,
71  gpointer user_data);
72 static AB_IMEXPORTER_ACCOUNTINFO *bal_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element,
73  gpointer user_data);
74 
76 {
77  guint awaiting;
78  gboolean txn_found;
79  Account *gnc_acc;
80  GNC_AB_ACCOUNT_SPEC *ab_acc;
81  gboolean execute_txns;
82  AB_BANKING *api;
83  GtkWidget *parent;
84  GNC_AB_JOB_LIST2 *job_list;
85  GNCImportMainMatcher *generic_importer;
86  GData *tmp_job_list;
87 };
88 
89 static inline gboolean is_leap_year (int year)
90 {
91  return (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0 ));
92 }
93 
94 static inline time64
95 gnc_gwen_date_to_time64 (const GNC_GWEN_DATE* date)
96 {
97  int day = GWEN_Date_GetDay (date);
98  int month = GWEN_Date_GetMonth (date);
99  int year = GWEN_Date_GetYear (date);
100  /* Some banks use nominal 30-day months and set the value date as
101  * the day after the posted date. In February this can appear to
102  * be an invalid date because February has fewer than 30 days. If
103  * that's the case then back up a day to get a real date for
104  * posting.
105  */
106  while (month == 2 && day <= 30 && day > (is_leap_year (year) ? 29 : 28))
107  --day;
108  return gnc_dmy2time64_neutral (day, month, year);
109 }
110 
111 void
113 {
114  gchar* gwen_logging = g_strdup (g_getenv ("GWEN_LOGLEVEL"));
115  gchar* aqb_logging = g_strdup (g_getenv ("AQBANKING_LOGLEVEL"));
116 
117  /* Initialize gwen library */
118  GWEN_Init();
119 
120  /* Initialize gwen logging */
121  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_VERBOSE_DEBUG))
122  {
123  if (!gwen_logging)
124  {
125  GWEN_Logger_SetLevel (NULL, GWEN_LoggerLevel_Info);
126  GWEN_Logger_SetLevel (GWEN_LOGDOMAIN, GWEN_LoggerLevel_Info);
127  }
128  if (!aqb_logging)
129  GWEN_Logger_SetLevel (AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Debug);
130  }
131  else
132  {
133  if (!gwen_logging)
134  {
135  GWEN_Logger_SetLevel (NULL, GWEN_LoggerLevel_Error);
136  GWEN_Logger_SetLevel (GWEN_LOGDOMAIN, GWEN_LoggerLevel_Error);
137  }
138  if (!aqb_logging)
139  GWEN_Logger_SetLevel (AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Warning);
140  }
141  g_free (gwen_logging);
142  g_free (aqb_logging);
144 }
145 
146 void
148 {
149  /* Shutdown the GWEN_GUIs */
151  GWEN_Logger_SetLevel (NULL, GWEN_LoggerLevel_Error);
152  GWEN_Logger_SetLevel (GWEN_LOGDOMAIN, GWEN_LoggerLevel_Warning);
153  GWEN_Logger_SetLevel (AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Warning);
154 
155  /* Finalize gwen library */
156  GWEN_Fini();
157 }
158 
159 static GWEN_GUI *gnc_gwengui_extended_by_ABBanking;
160 
161 AB_BANKING *
163 {
164  AB_BANKING *api;
165 
166  if (gnc_AB_BANKING)
167  {
168  /* API cached. */
169  api = gnc_AB_BANKING;
170 
171  /* Init the API again. */
172  if (gnc_AB_BANKING_refcount == 0)
173  g_return_val_if_fail (AB_Banking_Init (api) == 0, NULL);
174 
175  }
176  else
177  {
178  api = AB_Banking_new (PROJECT_NAME, NULL, 0);
179  g_return_val_if_fail (api, NULL);
180 
181  /* These two values must be set because newest bank regulation requires
182  the bank servers to require it. The string itself results from our
183  registration with the German bank association at
184  https://www.hbci-zka.de/register/prod_register.htm (where the
185  registration was requested and is managed by cstim). The function call was
186  introduced in aqbanking-5.99.25 and aqbanking-5.7.9. */
187  AB_Banking_RuntimeConfig_SetCharValue (api, "fintsRegistrationKey", "412748A1836CDD07181CE1910");
188  AB_Banking_RuntimeConfig_SetCharValue (api, "fintsApplicationVersionString", PROJECT_VERSION);
189 
190  /* Init the API */
191  g_return_val_if_fail (AB_Banking_Init (api) == 0, NULL);
192  gnc_gwengui_extended_by_ABBanking = GWEN_Gui_GetGui ();
193  AB_Gui_Extend (gnc_gwengui_extended_by_ABBanking, api);
194 
195  /* Cache it */
196  gnc_AB_BANKING = api;
197  gnc_AB_BANKING_refcount = 0;
198  }
199 
200  gnc_AB_BANKING_refcount++;
201 
202  return api;
203 }
204 
205 void
206 gnc_AB_BANKING_delete (AB_BANKING *api)
207 {
208  if (!api)
209  api = gnc_AB_BANKING;
210 
211  if (api)
212  {
213  if (api == gnc_AB_BANKING)
214  {
215  gnc_AB_BANKING = NULL;
216  gnc_AB_BANKING_fini (api);
217  }
218 
219  AB_Banking_free (api);
220  }
221 }
222 
223 
224 gint
225 gnc_AB_BANKING_fini (AB_BANKING *api)
226 {
227  if (api == gnc_AB_BANKING)
228  {
229  if (--gnc_AB_BANKING_refcount == 0)
230  {
231  if (gnc_gwengui_extended_by_ABBanking)
232  AB_Gui_Unextend (gnc_gwengui_extended_by_ABBanking);
233  gnc_gwengui_extended_by_ABBanking = NULL;
234  return AB_Banking_Fini (api);
235  }
236  }
237  else
238  {
239  if (gnc_gwengui_extended_by_ABBanking)
240  AB_Gui_Unextend (gnc_gwengui_extended_by_ABBanking);
241  gnc_gwengui_extended_by_ABBanking = NULL;
242  return AB_Banking_Fini (api);
243  }
244  return 0;
245 }
246 
247 GNC_AB_ACCOUNT_SPEC *
248 gnc_ab_get_ab_account (const AB_BANKING *api, Account *gnc_acc)
249 {
250  GNC_AB_ACCOUNT_SPEC *ab_account = NULL;
251  const gchar *bankcode = NULL;
252  const gchar *accountid = NULL;
253  guint32 account_uid = 0;
254 
255  bankcode = gnc_ab_get_account_bankcode (gnc_acc);
256  accountid = gnc_ab_get_account_accountid (gnc_acc);
257  account_uid = gnc_ab_get_account_uid (gnc_acc);
258 
259  if (account_uid > 0)
260  {
261  gint rv;
262 
263  rv = AB_Banking_GetAccountSpecByUniqueId (api, account_uid, &ab_account);
264 
265  if ( (rv<0 || !ab_account) && bankcode && *bankcode &&
266  accountid && *accountid)
267  {
268 /* Finding the account by code and number is suspended in AQBANKING 6 pending
269  * implementation of a replacement for AB_Banking_GetAccountByCodeAndNumber.
270  */
271  PINFO("gnc_ab_get_ab_account: No AB_ACCOUNT found for UID %d, "
272  "trying bank code\n", account_uid);
273  return NULL;
274  }
275  return ab_account;
276  }
277 
278  return NULL;
279 }
280 
281 gchar *
282 gnc_AB_VALUE_to_readable_string (const AB_VALUE *value)
283 {
284  if (value)
285  return g_strdup_printf ("%.2f %s",
286  AB_Value_GetValueAsDouble (value),
287  AB_Value_GetCurrency (value));
288  else
289  return g_strdup_printf ("%.2f", 0.0);
290 }
291 
292 
293 gchar*
294 gnc_ab_create_online_id (const gchar *bankcode, const gchar *accountnumber)
295 {
296  gchar *online_id;
297 
298  /* The accountnumber may have leading zeros, depending on where them
299  * accountnumber is came from, e.g. the accountnumber of accountinfo
300  * has no leading zeros while the (local)accountnumber of a transaction
301  * has leading zeros.
302  * So remove all leading '0', to get a consistent online_id.
303  */
304  while (accountnumber && *accountnumber == '0')
305  accountnumber++;
306 
307  online_id = g_strconcat (bankcode ? bankcode : "",
308  accountnumber ? accountnumber : "",
309  (gchar*)NULL);
310 
311  return online_id;
312 }
313 
318 static gpointer
319 join_ab_strings_cb (const gchar *str, gpointer user_data)
320 {
321  gchar **acc = user_data;
322  gchar *tmp;
323 
324  if (!str || !*str)
325  return NULL;
326 
327  tmp = g_utf8_normalize (str, -1, G_NORMALIZE_NFC);
328  g_strstrip (tmp);
330 
331  if (*acc)
332  {
333  if (!strstr (*acc, tmp))
334  {
335  gchar *join = g_strjoin (" ", *acc, tmp, (gchar*) NULL);
336  g_free (*acc);
337  *acc = join;
338  }
339  g_free (tmp);
340  }
341  else
342  {
343  *acc = tmp;
344  }
345  return NULL;
346 }
347 
348 gchar *
349 gnc_ab_get_remote_name (const AB_TRANSACTION *ab_trans)
350 {
351  const char* ab_remote_name;
352  gchar *gnc_other_name = NULL;
353 
354  g_return_val_if_fail (ab_trans, NULL);
355 
356  ab_remote_name = AB_Transaction_GetRemoteName (ab_trans);
357  if (ab_remote_name)
358  gnc_other_name = g_strdup(ab_remote_name);
359  if (!gnc_other_name || !*gnc_other_name)
360  {
361  g_free (gnc_other_name);
362  gnc_other_name = NULL;
363  }
364 
365  return gnc_other_name;
366 }
367 
368 gchar *
369 gnc_ab_get_purpose (const AB_TRANSACTION *ab_trans, gboolean is_ofx)
370 {
371  GWEN_STRINGLIST *ab_purpose;
372  const char *ab_transactionText = NULL;
373  gchar *gnc_description = NULL;
374 
375  g_return_val_if_fail (ab_trans, g_strdup (""));
376 
377  if (!is_ofx && gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_USE_TRANSACTION_TXT))
378  {
379  /* According to AqBanking, some of the non-swift lines have a special
380  * meaning. Some banks place valuable text into the transaction text,
381  * hence we put this text in front of the purpose. */
382  ab_transactionText = AB_Transaction_GetTransactionText (ab_trans);
383  if (ab_transactionText && *ab_transactionText)
384  gnc_description = g_utf8_normalize (ab_transactionText, -1, G_NORMALIZE_NFC);
385  }
386 
387  ab_purpose = AB_Transaction_GetPurposeAsStringList (ab_trans);
388  if (ab_purpose)
389  GWEN_StringList_ForEach (ab_purpose, join_ab_strings_cb,
390  &gnc_description);
391 
392  GWEN_StringList_free (ab_purpose);
393 
394  return gnc_description;
395 }
396 
397 /* Ultimate Creditor and Ultimate Debtor are newish parameters added
398  * to SWIFT MT940 and CAMT.053 designating the originating
399  * payer or payee on the transaction. It's unlikely, but still
400  * possible, that a bank would use both this markup and the Non-swift
401  * TransactionText or RemoteName tags.
402  */
403 static gchar *
404 ab_ultimate_creditor_debtor_to_gnc (const AB_TRANSACTION *ab_trans,
405  gboolean is_ofx)
406 {
407  const gchar* ultimate;
408 
409  if (is_ofx)
410  return NULL;
411 
412  ultimate = AB_Transaction_GetUltimateCreditor (ab_trans);
413 
414  if (!ultimate || !*ultimate)
415  ultimate = AB_Transaction_GetUltimateDebtor (ab_trans);
416 
417  if (!ultimate || !*ultimate)
418  return NULL;
419 
420  return g_strdup (ultimate);
421 }
422 
423 gchar *
424 gnc_ab_description_to_gnc (const AB_TRANSACTION *ab_trans, gboolean is_ofx)
425 {
426  GList *acc = NULL;
427  gchar *retval;
428 
429  acc = g_list_prepend (acc, gnc_ab_get_remote_name (ab_trans));
430  acc = g_list_prepend (acc, gnc_ab_get_purpose (ab_trans, is_ofx));
431  acc = g_list_prepend (acc, ab_ultimate_creditor_debtor_to_gnc (ab_trans, is_ofx));
432  retval = gnc_g_list_stringjoin_nodups (acc, "; ");
433 
434  g_list_free_full (acc, g_free);
435  return retval ? retval : g_strdup (_("Unspecified"));
436 }
437 
438 gchar *
439 gnc_ab_memo_to_gnc (const AB_TRANSACTION *ab_trans)
440 {
441  const gchar *ab_remote_accountnumber =
442  AB_Transaction_GetRemoteAccountNumber (ab_trans);
443  const gchar *ab_remote_bankcode =
444  AB_Transaction_GetRemoteBankCode (ab_trans);
445 
446  gchar *ab_other_accountid;
447  gchar *ab_other_bankcode;
448 
449  gboolean have_accountid;
450  gboolean have_bankcode;
451 
452  gchar *retval;
453 
454  // For SEPA transactions, we need to ask for something different here
455  if (!ab_remote_accountnumber)
456  ab_remote_accountnumber = AB_Transaction_GetRemoteIban (ab_trans);
457  if (!ab_remote_bankcode)
458  ab_remote_bankcode = AB_Transaction_GetRemoteBic (ab_trans);
459 
460  ab_other_accountid = g_strdup (ab_remote_accountnumber ? ab_remote_accountnumber : "");
461  ab_other_bankcode = g_strdup (ab_remote_bankcode ? ab_remote_bankcode : "");
462 
463  /* Ensure string is in utf8 */
464  gnc_utf8_strip_invalid (ab_other_accountid);
465  gnc_utf8_strip_invalid (ab_other_bankcode);
466 
467  /* and -then- trim it */
468  g_strstrip (ab_other_accountid);
469  g_strstrip (ab_other_bankcode);
470 
471 
472  have_accountid = ab_other_accountid && *ab_other_accountid;
473  have_bankcode = ab_other_bankcode && *ab_other_bankcode;
474 
475  if ( have_accountid || have_bankcode )
476  {
477  retval = g_strdup_printf ("%s %s %s %s",
478  have_accountid ? _("Account") : "",
479  have_accountid ? ab_other_accountid : "",
480  have_bankcode ? _("Bank") : "",
481  have_bankcode ? ab_other_bankcode : ""
482  );
483  g_strstrip (retval);
484  }
485  else
486  {
487  retval = g_strdup ("");
488  }
489 
490  g_free (ab_other_accountid);
491  g_free (ab_other_bankcode);
492 
493  return retval;
494 }
495 
496 Transaction *
497 gnc_ab_trans_to_gnc (const AB_TRANSACTION *ab_trans, Account *gnc_acc)
498 {
499  QofBook *book;
500  Transaction *gnc_trans;
501  const gchar *fitid;
502  const GNC_GWEN_DATE *value_date, *post_date;
503  time64 post_time;
504  const char *custref;
505  gchar *description;
506  Split *split;
507  gchar *memo;
508 
509  g_return_val_if_fail (ab_trans && gnc_acc, NULL);
510 
511  /* Create new GnuCash transaction for the given AqBanking one */
512  book = gnc_account_get_book (gnc_acc);
513  gnc_trans = xaccMallocTransaction (book);
514  xaccTransBeginEdit (gnc_trans);
515 
516  /* Date / Time */
517  /* SWIFT import formats (in particular MT940) provide for two
518  * dates, the entry date and the value date (valuta is value in
519  * German). The value date is the effective date for financial
520  * calculation purposes and is mandatory, the entry date is the
521  * date that the financial institution posted the
522  * transaction. Unfortunately if the transaction field doesn't
523  * provide an entry date AQBanking substitutes the date from the
524  * last balance instead of using the value date or NULL, making
525  * the field unreliable.
526  */
527  value_date = AB_Transaction_GetValutaDate (ab_trans);
528  if (value_date)
529  post_time = gnc_gwen_date_to_time64 (value_date);
530  else if ((post_date = AB_Transaction_GetDate (ab_trans))) // always true
531  post_time = gnc_gwen_date_to_time64 (post_date);
532  else
533  {
534  g_warning ("transaction_cb: Import had no transaction date");
535  post_time = gnc_time (NULL);
536  }
537  xaccTransSetDatePostedSecsNormalized (gnc_trans, post_time);
538 
539  xaccTransSetDateEnteredSecs (gnc_trans, gnc_time (NULL));
540 
541  /* Currency. We take simply the default currency of the gnucash account */
542  xaccTransSetCurrency (gnc_trans, xaccAccountGetCommodity (gnc_acc));
543 
544  /* Trans-Num or Split-Action set with gnc_set_num_action below per book
545  * option */
546 
547  fitid = AB_Transaction_GetFiId (ab_trans);
548 
549  /* Description */
550  description = gnc_ab_description_to_gnc (ab_trans, (fitid && *fitid));
551  xaccTransSetDescription (gnc_trans, description);
552  g_free (description);
553 
554  /* Notes. */
555  /* xaccTransSetNotes(gnc_trans, g_notes); */
556  /* But Nobody ever uses the Notes field? */
557 
558  /* Add one split */
559  split = xaccMallocSplit (book);
560  xaccSplitSetParent (split, gnc_trans);
561  xaccSplitSetAccount (split, gnc_acc);
562 
563  /* Set the transaction number or split action field based on book option.
564  * We use the "customer reference", if there is one. */
565  custref = AB_Transaction_GetCustomerReference (ab_trans);
566  if (custref && *custref && g_ascii_strncasecmp (custref, "NONREF", 6) != 0)
567  gnc_set_num_action (gnc_trans, split, custref, NULL);
568 
569  /* Set OFX unique transaction ID */
570  if (fitid && *fitid)
571  xaccSplitSetOnlineID (split, fitid);
572 
573  /* FIXME: Extract function */
574  {
575  /* Amount into the split */
576  const AB_VALUE *ab_value = AB_Transaction_GetValue (ab_trans);
577  double d_value = ab_value ? AB_Value_GetValueAsDouble (ab_value) : 0.0;
578  AB_TRANSACTION_TYPE ab_type = AB_Transaction_GetType (ab_trans);
579  gnc_numeric gnc_amount;
580 
581  /*printf("Transaction with value %f has type %d\n", d_value, ab_type);*/
582  /* If the value is positive, but the transaction type says the
583  money is transferred away from our account (Transfer instead of
584  DebitNote), we switch the value to negative. */
585  if (d_value > 0.0 && ab_type == AB_Transaction_TypeTransfer)
586  d_value = -d_value;
587 
588  gnc_amount = double_to_gnc_numeric (
589  d_value,
590  xaccAccountGetCommoditySCU (gnc_acc),
592  if (!ab_value)
593  g_warning ("transaction_cb: Oops, value was NULL. Using 0");
594  xaccSplitSetBaseValue (split, gnc_amount, xaccAccountGetCommodity (gnc_acc));
595  }
596 
597  /* Memo in the Split. */
598  memo = gnc_ab_memo_to_gnc (ab_trans);
599  xaccSplitSetMemo (split, memo);
600  g_free (memo);
601 
602  return gnc_trans;
603 }
604 
613 static Account *
614 gnc_ab_accinfo_to_gnc_acc (GtkWidget *parent, AB_IMEXPORTER_ACCOUNTINFO *acc_info)
615 {
616  const gchar *bankcode, *accountnumber;
617  gchar *online_id;
618  Account *gnc_acc;
619 
620  g_return_val_if_fail (acc_info, NULL);
621 
622  bankcode = AB_ImExporterAccountInfo_GetBankCode (acc_info);
623  accountnumber = AB_ImExporterAccountInfo_GetAccountNumber (acc_info);
624  online_id = gnc_ab_create_online_id (bankcode, accountnumber);
625  gnc_acc = gnc_import_select_account (parent, online_id, 1,
626  AB_ImExporterAccountInfo_GetAccountName (acc_info),
627  NULL, ACCT_TYPE_NONE, NULL, NULL);
628  if (!gnc_acc)
629  {
630  g_warning ("gnc_ab_accinfo_to_gnc_acc: Could not determine source account"
631  " for online_id %s", online_id);
632  }
633  g_free (online_id);
634 
635  return gnc_acc;
636 }
637 
638 
647 static Account *
648 gnc_ab_txn_to_gnc_acc (GtkWidget *parent, const AB_TRANSACTION *transaction)
649 {
650  const gchar *bankcode, *accountnumber;
651  gchar *online_id;
652  Account *gnc_acc;
653 
654  g_return_val_if_fail(transaction, NULL);
655 
656  bankcode = AB_Transaction_GetLocalBankCode (transaction);
657  accountnumber = AB_Transaction_GetLocalAccountNumber (transaction);
658  if (!bankcode && !accountnumber)
659  {
660  return NULL;
661  }
662 
663  online_id = gnc_ab_create_online_id (bankcode, accountnumber);
664  gnc_acc = gnc_import_select_account (parent, online_id, 1,
665  AB_Transaction_GetLocalName (transaction),
666  NULL, ACCT_TYPE_NONE, NULL, NULL);
667  if (!gnc_acc)
668  {
669  g_warning ("gnc_ab_txn_to_gnc_acc: Could not determine source account"
670  " for online_id %s", online_id);
671  }
672  g_free (online_id);
673 
674  return gnc_acc;
675 }
676 
677 static const AB_TRANSACTION *
678 txn_transaction_cb (const AB_TRANSACTION *element, gpointer user_data)
679 {
680  GncABImExContextImport *data = user_data;
681  Transaction *gnc_trans;
682  GncABTransType trans_type;
683  Account* txnacc;
684 
685  g_return_val_if_fail (element && data, NULL);
686 
687  /* Create a GnuCash transaction from ab_trans */
688  txnacc = gnc_ab_txn_to_gnc_acc (GTK_WIDGET(data->parent), element);
689  gnc_trans = gnc_ab_trans_to_gnc (element, txnacc ? txnacc : data->gnc_acc);
690 
691  if (data->execute_txns && data->ab_acc)
692  {
693  AB_TRANSACTION *ab_trans = AB_Transaction_dup (element);
694  GNC_AB_JOB *job;
695 
696  /* NEW: The imported transaction has been imported into gnucash.
697  * Now also add it as a job to aqbanking */
698  AB_Transaction_SetLocalBankCode (
699  ab_trans, AB_AccountSpec_GetBankCode (data->ab_acc));
700  AB_Transaction_SetLocalAccountNumber (
701  ab_trans, AB_AccountSpec_GetAccountNumber (data->ab_acc));
702  AB_Transaction_SetLocalCountry (ab_trans, "DE");
703 
704 
705  switch (AB_Transaction_GetType (ab_trans))
706  {
707  case AB_Transaction_TypeDebitNote:
708  trans_type = SINGLE_DEBITNOTE;
709  break;
710  case AB_Transaction_TypeTransaction:
711  /* trans_type = SINGLE_INTERNAL_TRANSFER;
712  * break; */
713  case AB_Transaction_TypeTransfer:
714  default:
715  trans_type = SEPA_TRANSFER;
716  break;
717  } /* switch */
718 
719  job = gnc_ab_get_trans_job (data->ab_acc, ab_trans, trans_type);
720 
721  /* Check whether we really got a job */
722  if (!job || AB_AccountSpec_GetTransactionLimitsForCommand (data->ab_acc, AB_Transaction_GetCommand (job)) == NULL)
723  {
724  /* Oops, no job, probably not supported by bank */
725  if (gnc_verify_dialog (
726  GTK_WINDOW(data->parent), FALSE, "%s",
727  _("The backend found an error during the preparation "
728  "of the job. It is not possible to execute this job.\n"
729  "\n"
730  "Most probably the bank does not support your chosen "
731  "job or your Online Banking account does not have the permission "
732  "to execute this job. More error messages might be "
733  "visible on your console log.\n"
734  "\n"
735  "Do you want to enter the job again?")))
736  {
737  gnc_error_dialog (GTK_WINDOW(data->parent),
738  "Sorry, not implemented yet. Please check the console or trace file logs to see which job was rejected.");
739  }
740  }
741  else
742  {
743  gnc_gen_trans_list_add_trans_with_ref_id (data->generic_importer,
744  gnc_trans,
745  AB_Transaction_GetUniqueId (job));
746  /* AB_Job_List2_PushBack(data->job_list, job); -> delayed until trans is successfully imported */
747  g_datalist_set_data (&data->tmp_job_list, gnc_AB_JOB_to_readable_string (job), job);
748  }
749  AB_Transaction_free (ab_trans);
750  }
751  else
752  {
753  /* Instead of xaccTransCommitEdit(gnc_trans) */
754  gnc_gen_trans_list_add_trans (data->generic_importer, gnc_trans);
755  }
756 
757  return NULL;
758 }
759 
760 static void gnc_ab_trans_processed_cb (GNCImportTransInfo *trans_info,
761  gboolean imported,
762  gpointer user_data)
763 {
764  GncABImExContextImport *data = user_data;
765  gchar *jobname = gnc_AB_JOB_ID_to_string (gnc_import_TransInfo_get_ref_id (trans_info));
766  GNC_AB_JOB *job = g_datalist_get_data (&data->tmp_job_list, jobname);
767 
768  if (imported)
769  {
770  AB_Transaction_List2_PushBack (data->job_list, job);
771  }
772  else
773  {
774  AB_Transaction_free (job);
775  }
776 
777  g_datalist_remove_data (&data->tmp_job_list, jobname);
778 }
779 
780 gchar *
781 gnc_AB_JOB_to_readable_string (const GNC_AB_JOB *job)
782 {
783  if (job)
784  {
785  return gnc_AB_JOB_ID_to_string (AB_Transaction_GetUniqueId (job));
786  }
787  else
788  {
789  return gnc_AB_JOB_ID_to_string (0);
790  }
791 }
792 gchar *
793 gnc_AB_JOB_ID_to_string (gulong job_id)
794 {
795  return g_strdup_printf ("job_%lu", job_id);
796 }
797 
798 
799 
800 static AB_IMEXPORTER_ACCOUNTINFO *
801 txn_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
802 {
803  GncABImExContextImport *data = user_data;
804  Account *gnc_acc;
805 
806  g_return_val_if_fail (element && data, NULL);
807 
808  if (data->awaiting & IGNORE_TRANSACTIONS)
809  /* Ignore them */
810  return NULL;
811 
812  if (!AB_ImExporterAccountInfo_GetFirstTransaction (element, AB_Transaction_TypeStatement, 0))
813 /* No transaction found */
814  return NULL;
815  else
816  data->awaiting |= FOUND_TRANSACTIONS;
817 
818  if (!(data->awaiting & AWAIT_TRANSACTIONS))
819  {
820  if (gnc_verify_dialog (GTK_WINDOW(data->parent), TRUE, "%s",
821  _("The bank has sent transaction information "
822  "in its response."
823  "\n"
824  "Do you want to import it?")))
825  {
826  data->awaiting |= AWAIT_TRANSACTIONS;
827  }
828  else
829  {
830  data->awaiting |= IGNORE_TRANSACTIONS;
831  return NULL;
832  }
833  }
834 
835  /* Lookup the corresponding gnucash account */
836  gnc_acc = gnc_ab_accinfo_to_gnc_acc (GTK_WIDGET(data->parent), element);
837  if (!gnc_acc) return NULL;
838  data->gnc_acc = gnc_acc;
839 
840  if (data->execute_txns)
841  {
842  /* Retrieve the aqbanking account that belongs to this gnucash
843  * account */
844  data->ab_acc = gnc_ab_get_ab_account (data->api, gnc_acc);
845  if (!data->ab_acc)
846  {
847  gnc_error_dialog (GTK_WINDOW(data->parent), "%s",
848  _("No Online Banking account found for this "
849  "gnucash account. These transactions will "
850  "not be executed by Online Banking."));
851  }
852  }
853  else
854  {
855  data->ab_acc = NULL;
856  }
857 
858  if (!data->generic_importer)
859  {
860  data->generic_importer = gnc_gen_trans_list_new (data->parent, NULL,
861  TRUE, 14, TRUE);
862  if (data->execute_txns)
863  {
864  gnc_gen_trans_list_add_tp_cb (data->generic_importer,
865  gnc_ab_trans_processed_cb, data);
866  }
867  }
868 
869  /* Iterate through all transactions */
870  {
871  AB_TRANSACTION_LIST *ab_trans_list = AB_ImExporterAccountInfo_GetTransactionList (element);
872  if (ab_trans_list)
873  AB_Transaction_List_ForEachByType (ab_trans_list,
874  txn_transaction_cb, data,
875  AB_Transaction_TypeStatement, 0);
876  }
877  return NULL;
878 }
879 
880 static AB_IMEXPORTER_ACCOUNTINFO *
881 bal_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
882 {
883  GncABImExContextImport *data = user_data;
884  Account *gnc_acc;
885  const AB_BALANCE *booked_bal, *noted_bal;
886  const AB_VALUE *booked_val = NULL, *noted_val = NULL;
887  gdouble booked_value, noted_value;
888  gnc_numeric value;
889  time64 booked_tt = 0;
890  GtkWidget *dialog;
891  gboolean show_recn_window = FALSE;
892 
893  g_return_val_if_fail (element && data, NULL);
894 
895  if (data->awaiting & IGNORE_BALANCES)
896  /* Ignore them */
897  return NULL;
898 
899  if (!AB_ImExporterAccountInfo_GetFirstBalance (element))
900  /* No balance found */
901  return NULL;
902  else
903  data->awaiting |= FOUND_BALANCES;
904 
905  /* Lookup the most recent BALANCE available */
906  booked_bal = AB_Balance_List_GetLatestByType (AB_ImExporterAccountInfo_GetBalanceList (element),
907  AB_Balance_TypeBooked);
908 
909  if (!(data->awaiting & AWAIT_BALANCES))
910  {
911  GtkWindow *parent = data->generic_importer ?
912  GTK_WINDOW(gnc_gen_trans_list_widget (data->generic_importer)) :
913  GTK_WINDOW(data->parent);
914  const char* balance_msg =
915  _("The bank has sent balance information in its response.\n"
916  "Do you want to import it?");
917  /* Ignore zero balances if we don't await a balance */
918  if (!booked_bal || AB_Value_IsZero (AB_Balance_GetValue (booked_bal)))
919  return NULL;
920 
921  /* Ask the user whether to import unawaited non-zero balance */
922  if (gnc_verify_dialog (parent, TRUE, "%s", balance_msg))
923  {
924  data->awaiting |= AWAIT_BALANCES;
925  }
926  else
927  {
928  data->awaiting |= IGNORE_BALANCES;
929  return NULL;
930  }
931  }
932 
933  /* Lookup the corresponding gnucash account */
934  gnc_acc = gnc_ab_accinfo_to_gnc_acc (GTK_WIDGET(data->parent), element);
935  if (!gnc_acc) return NULL;
936  data->gnc_acc = gnc_acc;
937 
938  /* Lookup booked balance and time */
939  if (booked_bal)
940  {
941  const GWEN_DATE *ti = AB_Balance_GetDate (booked_bal);
942  if (ti)
943  {
944  booked_tt = gnc_gwen_date_to_time64 (ti);
945  }
946  else
947  {
948  /* No time found? Use today because the HBCI query asked for today's
949  * balance. */
950  booked_tt = gnc_time64_get_day_neutral (gnc_time (NULL));
951  }
952  booked_val = AB_Balance_GetValue (booked_bal);
953  if (booked_val)
954  {
955  booked_value = AB_Value_GetValueAsDouble (booked_val);
956  }
957  else
958  {
959  g_warning ("bal_accountinfo_cb: booked_val == NULL. Assuming 0");
960  booked_value = 0.0;
961  }
962  }
963  else
964  {
965  g_warning ("bal_accountinfo_cb: booked_bal == NULL. Assuming 0");
966  booked_tt = 0;
967  booked_value = 0.0;
968  }
969 
970  /* Lookup noted balance */
971  noted_bal = AB_Balance_List_GetLatestByType (AB_ImExporterAccountInfo_GetBalanceList (element),
972  AB_Balance_TypeNoted);
973  if (noted_bal)
974  {
975  noted_val = AB_Balance_GetValue (noted_bal);
976  if (noted_val)
977  noted_value = AB_Value_GetValueAsDouble (noted_val);
978  else
979  {
980  g_warning ("bal_accountinfo_cb: noted_val == NULL. Assuming 0");
981  noted_value = 0.0;
982  }
983  }
984  else
985  {
986  g_warning ("bal_accountinfo_cb: noted_bal == NULL. Assuming 0");
987  noted_value = 0.0;
988  }
989 
990  value = double_to_gnc_numeric (booked_value,
991  xaccAccountGetCommoditySCU (gnc_acc),
993  if (noted_value == 0.0 && booked_value == 0.0)
994  {
995  dialog = gtk_message_dialog_new (
996  GTK_WINDOW(data->parent),
997  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
998  GTK_MESSAGE_INFO,
999  GTK_BUTTONS_OK,
1000  "%s",
1001  /* Translators: Strings from this file are needed only in
1002  countries that have one of aqbanking's Online Banking
1003  techniques available. This is 'OFX DirectConnect'
1004  (U.S. and others), 'HBCI' (in Germany), or 'YellowNet'
1005  (Switzerland). If none of these techniques are available
1006  in your country, you may safely ignore strings from the
1007  import-export/hbci subdirectory. */
1008  _("The downloaded Online Banking Balance was zero.\n\n"
1009  "Either this is the correct balance, or your bank does not "
1010  "support Balance download in this Online Banking version. "
1011  "In the latter case you should choose a different "
1012  "Online Banking version number in the Online Banking "
1013  "(AqBanking or HBCI) Setup. After that, try again to "
1014  "download the Online Banking Balance."));
1015  gtk_dialog_run (GTK_DIALOG(dialog));
1016  gtk_widget_destroy (dialog);
1017 
1018  }
1019  else
1020  {
1021  gnc_numeric reconc_balance = xaccAccountGetReconciledBalance (gnc_acc);
1022 
1023  gchar *booked_str = gnc_AB_VALUE_to_readable_string (booked_val);
1024  gchar *message1 = g_strdup_printf (
1025  _("Result of Online Banking job:\n"
1026  "Account booked balance is %s"),
1027  booked_str);
1028  gchar *message2 =
1029  (noted_value == 0.0) ?
1030  g_strdup ("") :
1031  g_strdup_printf (_("For your information: This account also "
1032  "has a noted balance of %s\n"),
1033  gnc_AB_VALUE_to_readable_string (noted_val));
1034 
1035  if (gnc_numeric_equal (value, reconc_balance))
1036  {
1037  const gchar *message3 =
1038  _("The booked balance is identical to the current "
1039  "reconciled balance of the account.");
1040  dialog = gtk_message_dialog_new (
1041  GTK_WINDOW(data->parent),
1042  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1043  GTK_MESSAGE_INFO,
1044  GTK_BUTTONS_OK,
1045  "%s\n%s\n%s",
1046  message1, message2, message3);
1047  gtk_dialog_run (GTK_DIALOG(dialog));
1048  gtk_widget_destroy (GTK_WIDGET(dialog));
1049 
1050  }
1051  else
1052  {
1053  const char *message3 = _("Reconcile account now?");
1054 
1055  show_recn_window = gnc_verify_dialog (GTK_WINDOW(data->parent), TRUE, "%s\n%s\n%s",
1056  message1, message2, message3);
1057  }
1058  g_free (booked_str);
1059  g_free (message1);
1060  g_free (message2);
1061  }
1062 
1063  /* Show reconciliation window */
1064  if (show_recn_window)
1065  recnWindowWithBalance (GTK_WIDGET(data->parent), gnc_acc, value, booked_tt);
1066 
1067  return NULL;
1068 }
1069 
1070 GncABImExContextImport *
1071 gnc_ab_import_context (AB_IMEXPORTER_CONTEXT *context,
1072  guint awaiting, gboolean execute_txns,
1073  AB_BANKING *api, GtkWidget *parent)
1074 {
1075  GncABImExContextImport *data = g_new (GncABImExContextImport, 1);
1076  AB_IMEXPORTER_ACCOUNTINFO_LIST *ab_ail;
1077  g_return_val_if_fail (context, NULL);
1078  /* Do not await and ignore at the same time */
1079  g_return_val_if_fail (!(awaiting & AWAIT_BALANCES)
1080  || !(awaiting & IGNORE_BALANCES),
1081  NULL);
1082  g_return_val_if_fail (!(awaiting & AWAIT_TRANSACTIONS)
1083  || !(awaiting & IGNORE_TRANSACTIONS),
1084  NULL);
1085  /* execute_txns must be FALSE if txns are not awaited */
1086  g_return_val_if_fail (awaiting & AWAIT_TRANSACTIONS || !execute_txns, NULL);
1087  /* An api is needed for the jobs */
1088  g_return_val_if_fail (!execute_txns || api, NULL);
1089 
1090  data->awaiting = awaiting;
1091  data->txn_found = FALSE;
1092  data->execute_txns = execute_txns;
1093  data->api = api;
1094  data->parent = parent;
1095  data->job_list = AB_Transaction_List2_new ();
1096  data->tmp_job_list = NULL;
1097  data->generic_importer = NULL;
1098 
1099  g_datalist_init (&data->tmp_job_list);
1100 
1101  /* Import transactions */
1102  ab_ail = AB_ImExporterContext_GetAccountInfoList (context);
1103  if (ab_ail && AB_ImExporterAccountInfo_List_GetCount (ab_ail))
1104  {
1105  if (!(awaiting & IGNORE_TRANSACTIONS))
1106  AB_ImExporterAccountInfo_List_ForEach (ab_ail,
1107  txn_accountinfo_cb,
1108  data);
1109 
1110  /* populate and display the matching window */
1111  if (data->generic_importer)
1112  gnc_gen_trans_list_show_all (data->generic_importer);
1113 
1114  /* Check balances */
1115  if (!(awaiting & IGNORE_BALANCES))
1116  AB_ImExporterAccountInfo_List_ForEach (ab_ail,
1117  bal_accountinfo_cb,
1118  data);
1119  }
1120 
1121  /* Check bank-messages */
1122  {
1123  AB_MESSAGE * bankmsg = AB_ImExporterContext_GetFirstMessage (context);
1124  while (bankmsg)
1125  {
1126  const char* subject = AB_Message_GetSubject (bankmsg);
1127  const char* text = AB_Message_GetText (bankmsg);
1128  gnc_info_dialog (GTK_WINDOW(data->parent), "%s\n%s %s\n%s",
1129  _("The bank has sent a message in its response."),
1130  _("Subject:"),
1131  subject,
1132  text);
1133 
1134  bankmsg = AB_Message_List_Next (bankmsg);
1135  }
1136  }
1137 
1138  return data;
1139 }
1140 
1141 guint
1142 gnc_ab_ieci_get_found (GncABImExContextImport *ieci)
1143 {
1144  g_return_val_if_fail (ieci, 0);
1145 
1146  return ieci->awaiting;
1147 }
1148 
1149 GNC_AB_JOB_LIST2 *
1150 gnc_ab_ieci_get_job_list (GncABImExContextImport *ieci)
1151 {
1152  g_return_val_if_fail (ieci, NULL);
1153 
1154  return ieci->job_list;
1155 }
1156 
1157 gboolean
1158 gnc_ab_ieci_run_matcher (GncABImExContextImport *ieci)
1159 {
1160  g_return_val_if_fail (ieci, FALSE);
1161 
1162  return gnc_gen_trans_list_run (ieci->generic_importer);
1163 }
1164 
1165 GWEN_DB_NODE *
1167 {
1168  int rv;
1169  GWEN_DB_NODE *perm_certs = NULL;
1170  AB_BANKING *banking = gnc_AB_BANKING_new ();
1171 
1172  g_return_val_if_fail (banking, NULL);
1173  rv = AB_Banking_LoadSharedConfig (banking, "certs", &perm_certs);
1174  gnc_AB_BANKING_fini (banking);
1175  g_return_val_if_fail (rv >= 0, NULL);
1176  return perm_certs;
1177 }
1178 
1179 #if (AQBANKING_VERSION_INT >= 60400)
1180 GList*
1181 gnc_ab_trans_templ_list_new_from_ref_accounts (GNC_AB_ACCOUNT_SPEC *ab_acc)
1182 {
1183  GList *retval = NULL;
1184  AB_REFERENCE_ACCOUNT *ra;
1185  AB_REFERENCE_ACCOUNT_LIST *ral;
1186  GWEN_BUFFER *accNameForTemplate = GWEN_Buffer_new (0,120,0,0);
1187  gnc_numeric zero = gnc_numeric_zero ();
1188 
1189  /* get the target account list */
1190  ral = AB_AccountSpec_GetRefAccountList (ab_acc);
1191  ra = AB_ReferenceAccount_List_First (ral);
1192 
1193  /* fill the template list with the target accounts */
1194  while (ra)
1195  {
1196  GncABTransTempl *new_templ = gnc_ab_trans_templ_new ();
1197  const char *iban = AB_ReferenceAccount_GetIban (ra);
1198  const char *accName = AB_ReferenceAccount_GetAccountName (ra);
1199  GWEN_Buffer_Reset (accNameForTemplate);
1200  if (accName)
1201  {
1202  GWEN_Buffer_AppendString (accNameForTemplate, accName);
1203  GWEN_Buffer_AppendString (accNameForTemplate, ": ");
1204  }
1205  GWEN_Buffer_AppendString (accNameForTemplate, iban);
1206  gnc_ab_trans_templ_set_name (new_templ, GWEN_Buffer_GetStart (accNameForTemplate));
1207  gnc_ab_trans_templ_set_recp_name (new_templ, AB_ReferenceAccount_GetOwnerName (ra));
1208  gnc_ab_trans_templ_set_recp_account (new_templ, AB_ReferenceAccount_GetIban (ra));
1209  gnc_ab_trans_templ_set_recp_bankcode (new_templ, AB_ReferenceAccount_GetBic (ra));
1210  gnc_ab_trans_templ_set_amount (new_templ, zero);
1211  retval = g_list_prepend (retval, new_templ);
1212  ra = AB_ReferenceAccount_List_Next (ra);
1213  }
1214  retval = g_list_reverse (retval);
1215 
1216  GWEN_Buffer_free (accNameForTemplate);
1217 
1218  return retval;
1219 }
1220 #endif
1221 static int
1222 ab_node_pair_compare (AB_Node_Pair* left, AB_Node_Pair* right)
1223 {
1224  return left ? (right ? g_strcmp0 (left->name, right->name) : -1) :
1225  (right ? 1 : 0);
1226 }
1227 
1228 GList*
1229 gnc_ab_imexporter_list (AB_BANKING* api)
1230 {
1231  GList* desc_list = NULL;
1232  GWEN_PLUGIN_DESCRIPTION_LIST2 *il =
1233  AB_Banking_GetImExporterDescrs (api);
1234  GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *ilit;
1235  g_return_val_if_fail (il, NULL);
1236  ilit = GWEN_PluginDescription_List2_First(il);
1237 
1238  for (GWEN_PLUGIN_DESCRIPTION *pd =
1239  GWEN_PluginDescription_List2Iterator_Data(ilit);
1240  pd;
1241  pd = GWEN_PluginDescription_List2Iterator_Next(ilit))
1242  {
1243  AB_Node_Pair *node = NULL;
1244 
1245  node = g_slice_new (AB_Node_Pair);
1246  node->name = g_strdup(GWEN_PluginDescription_GetName(pd));
1247  node->descr = g_strdup(GWEN_PluginDescription_GetShortDescr(pd));
1248  desc_list = g_list_prepend (desc_list, node);
1249  }
1250  GWEN_PluginDescription_List2_free(il);
1251  return g_list_sort (desc_list, (GCompareFunc)ab_node_pair_compare);
1252 }
1253 
1254 GList*
1255 gnc_ab_imexporter_profile_list (AB_BANKING* api, const char* importer_name)
1256 {
1257  GList* prof_list = NULL;
1258  GWEN_DB_NODE* db = AB_Banking_GetImExporterProfiles(api, importer_name);
1259  g_return_val_if_fail (db, NULL);
1260 
1261  for (GWEN_DB_NODE *profile = GWEN_DB_GetFirstGroup(db); profile;
1262  profile = GWEN_DB_GetNextGroup(profile))
1263  {
1264  AB_Node_Pair *node = g_slice_new(AB_Node_Pair);
1265  if (!profile) continue;
1266  node->name = g_strdup(GWEN_DB_GetCharValue(profile, "name", 0, NULL));
1267  node->descr = g_strdup(GWEN_DB_GetCharValue(profile, "shortDescr", 0, NULL));
1268  prof_list = g_list_prepend (prof_list, node);
1269  }
1270  return g_list_sort (prof_list, (GCompareFunc)ab_node_pair_compare);
1271 }
Dialog for AqBanking transaction data.
guint32 gnc_ab_get_account_uid(const Account *a)
Return the unique id for the AB_BANKING account in the Account a.
Definition: gnc-ab-kvp.c:79
gchar * gnc_ab_create_online_id(const gchar *bankcode, const gchar *accountnumber)
Creates an online ID from bank code and account number.
Definition: gnc-ab-utils.c:294
gchar * gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans)
Retrieve the merged "remote name" fields from a transaction.
Definition: gnc-ab-utils.c:349
GList * gnc_ab_imexporter_list(AB_BANKING *api)
Retrieve the available AQBanking importers.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition: Split.cpp:1320
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
time64 gnc_dmy2time64_neutral(gint day, gint month, gint year)
Converts a day, month, and year to a time64 representing 11:00:00 UTC 11:00:00 UTC falls on the same ...
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
void gnc_gen_trans_list_show_all(GNCImportMainMatcher *info)
Shows widgets.
void gnc_GWEN_Gui_shutdown(void)
Free all memory related to both the full-blown and minimalistic GUI objects.
Definition: gnc-gwen-gui.c:290
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2726
gchar * gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans, gboolean is_ofx)
Retrieve the merged purpose fields from a transaction.
Definition: gnc-ab-utils.c:369
STRUCTS.
void gnc_ab_trans_templ_set_amount(GncABTransTempl *t, gnc_numeric amount)
Replace the amount stored in a template.
gchar * gnc_AB_VALUE_to_readable_string(const AB_VALUE *value)
Print the value of value with two decimal places and value&#39;s currency appended, or 0...
Definition: gnc-ab-utils.c:282
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gchar * gnc_AB_JOB_ID_to_string(gulong job_id)
Return the job_id as string.
Definition: gnc-ab-utils.c:793
Transaction matcher main window.
void gnc_utf8_strip_invalid_and_controls(gchar *str)
Strip any non-utf8 characters and any control characters (everything < 0x20, , , ...
gchar * gnc_ab_memo_to_gnc(const AB_TRANSACTION *ab_trans)
Create the appropriate memo field for a GnuCash Split by the information given in the AB_TRANSACTION ...
Definition: gnc-ab-utils.c:439
Account * gnc_import_select_account(GtkWidget *parent, const gchar *account_online_id_value, gboolean prompt_on_no_match, const gchar *account_human_description, const gnc_commodity *new_account_default_commodity, GNCAccountType new_account_default_type, Account *default_selection, gboolean *ok_pressed)
Must be called with a string containing a unique identifier for the account.
gboolean gnc_ab_ieci_run_matcher(GncABImExContextImport *ieci)
Run the generic transaction matcher dialog.
void gnc_gen_trans_list_add_tp_cb(GNCImportMainMatcher *info, GNCTransactionProcessedCB trans_processed_cb, gpointer user_data)
Add transaction processed callback to the transaction importer.
void gnc_ab_trans_templ_set_recp_account(GncABTransTempl *t, const gchar *recp_account)
Replace the Account Number of the recipient stored in a template.
Generic and very flexible account matcher/picker.
GNC_AB_JOB_LIST2 * gnc_ab_ieci_get_job_list(GncABImExContextImport *ieci)
Extract the job list from data.
void gnc_ab_trans_templ_set_name(GncABTransTempl *t, const gchar *name)
Set the name of a template.
guint32 gnc_import_TransInfo_get_ref_id(const GNCImportTransInfo *info)
Returns the reference id for this TransInfo.
const gchar * gnc_ab_get_account_bankcode(const Account *a)
Return the bankcode string in the Account a.
Definition: gnc-ab-kvp.c:59
void gnc_gen_trans_list_add_trans(GNCImportMainMatcher *gui, Transaction *trans)
Add a newly imported Transaction to the Transaction Importer.
GWEN_DB_NODE * gnc_ab_get_permanent_certs(void)
get the GWEN_DB_NODE from AqBanking configuration files
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
void gnc_ab_trans_templ_set_recp_name(GncABTransTempl *t, const gchar *recp_name)
Replace the Account Number of the recipient stored in a template.
void gnc_ab_trans_templ_set_recp_bankcode(GncABTransTempl *t, const gchar *recp_bankcode)
Replace the Bank Code of the recipient stored in a template.
GncABTransTempl * gnc_ab_trans_templ_new()
Create a template with unset contents.
gchar * gnc_ab_description_to_gnc(const AB_TRANSACTION *ab_trans, gboolean is_ofx)
Create the appropriate description field for a GnuCash Transaction by the information given in the AB...
Definition: gnc-ab-utils.c:424
GtkWidget * gnc_gen_trans_list_widget(GNCImportMainMatcher *info)
Returns the widget of this dialog.
Transaction * gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc)
Create an unbalanced and dirty GnuCash transaction with a split to gnc_acc from the information avail...
Definition: gnc-ab-utils.c:497
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
gchar * gnc_AB_JOB_to_readable_string(const GNC_AB_JOB *job)
Return the job as string.
Definition: gnc-ab-utils.c:781
GNCImportMainMatcher * gnc_gen_trans_list_new(GtkWidget *parent, const gchar *heading, bool all_from_same_account, gint match_date_hardlimit, bool show_all)
Create a new generic transaction dialog window and return it.
AB_BANKING * gnc_AB_BANKING_new(void)
If there is a cached AB_BANKING object, return it initialized.
Definition: gnc-ab-utils.c:162
void gnc_utf8_strip_invalid(gchar *str)
Strip any non-UTF-8 characters from a string.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccAccountGetReconciledBalance(const Account *acc)
Get the current balance of the account, only including reconciled transactions.
Definition: Account.cpp:3462
GList * gnc_ab_imexporter_profile_list(AB_BANKING *api, const char *importer_name)
Retrieve the available format templates for an AQBanking importer.
gint gnc_AB_BANKING_fini(AB_BANKING *api)
Finish the AB_BANKING api.
Definition: gnc-ab-utils.c:225
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
GLib helper routines.
gchar * gnc_g_list_stringjoin_nodups(GList *list_of_strings, const gchar *sep)
Like stringjoin but ensures that the string to be added isn&#39;t already part of the return string...
Generic api to store and retrieve preferences.
QofBook reference.
Definition: qofbook-p.hpp:46
void gnc_gen_trans_list_add_trans_with_ref_id(GNCImportMainMatcher *gui, Transaction *trans, guint32 ref_id)
Add a newly imported Transaction to the Transaction Importer and provide an external reference id for...
GNC_AB_JOB * gnc_ab_get_trans_job(GNC_AB_ACCOUNT_SPEC *ab_acc, const AB_TRANSACTION *ab_trans, GncABTransType trans_type)
Return the AqBanking job associated with the transaction.
void gnc_AB_BANKING_delete(AB_BANKING *api)
Delete the AB_BANKING api.
Definition: gnc-ab-utils.c:206
void gnc_GWEN_Fini(void)
Finalize the gwenhywfar library.
Definition: gnc-ab-utils.c:147
GncABImExContextImport * gnc_ab_import_context(AB_IMEXPORTER_CONTEXT *context, guint awaiting, gboolean execute_txns, AB_BANKING *api, GtkWidget *parent)
Import balances and transactions found in a AB_IMEXPORTER_CONTEXT into GnuCash.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3389
void xaccSplitSetOnlineID(Split *split, const char *id)
The online_id is the OFX/HBCI "FITID" recorded on a split when it is imported.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
bool gnc_gen_trans_list_run(GNCImportMainMatcher *info)
Run this dialog and return only after the user pressed Ok, Cancel, or closed the window.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
GNC_AB_ACCOUNT_SPEC * gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc)
Get the corresponding AqBanking account to the GnuCash account gnc_acc.
Definition: gnc-ab-utils.c:248
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
const gchar * gnc_ab_get_account_accountid(const Account *a)
Return accountid string in the Account a.
Definition: gnc-ab-kvp.c:39
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void gnc_GWEN_Init(void)
Initialize the gwenhywfar library by calling GWEN_Init() and setting up gwenhywfar logging...
Definition: gnc-ab-utils.c:112
AqBanking KVP handling.
GUI callbacks for AqBanking.
guint gnc_ab_ieci_get_found(GncABImExContextImport *ieci)
Extract awaiting from data.
Not a type.
Definition: Account.h:105
API for Transactions and Splits (journal entries)
void gnc_GWEN_Gui_log_init(void)
Hook our logging into the gwenhywfar logging framework by creating a minimalistic GWEN_GUI with only ...
Definition: gnc-gwen-gui.c:229
AqBanking utility functions.
time64 gnc_time64_get_day_neutral(time64 time_val)
The gnc_time64_get_day_neutral() routine will take the given time in seconds and adjust it to 10:59:0...
Definition: gnc-date.cpp:1377