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