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_strdup (str);
329  g_strstrip (tmp);
331 
332  if (*acc)
333  {
334  gchar *join = g_strjoin (" ", *acc, tmp, (gchar*) NULL);
335  g_free (*acc);
336  g_free (tmp);
337  *acc = join;
338  }
339  else
340  {
341  *acc = tmp;
342  }
343  return NULL;
344 }
345 
346 gchar *
347 gnc_ab_get_remote_name (const AB_TRANSACTION *ab_trans)
348 {
349  const char* ab_remote_name;
350  gchar *gnc_other_name = NULL;
351 
352  g_return_val_if_fail (ab_trans, NULL);
353 
354  ab_remote_name = AB_Transaction_GetRemoteName (ab_trans);
355  if (ab_remote_name)
356  gnc_other_name = g_strdup(ab_remote_name);
357  if (!gnc_other_name || !*gnc_other_name)
358  {
359  g_free (gnc_other_name);
360  gnc_other_name = NULL;
361  }
362 
363  return gnc_other_name;
364 }
365 
366 gchar *
367 gnc_ab_get_purpose (const AB_TRANSACTION *ab_trans, gboolean is_ofx)
368 {
369  GWEN_STRINGLIST *ab_purpose;
370  const char *ab_transactionText = NULL;
371  gchar *gnc_description = NULL;
372 
373  g_return_val_if_fail (ab_trans, g_strdup (""));
374 
375  if (!is_ofx && gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_USE_TRANSACTION_TXT))
376  {
377  /* According to AqBanking, some of the non-swift lines have a special
378  * meaning. Some banks place valuable text into the transaction text,
379  * hence we put this text in front of the purpose. */
380  ab_transactionText = AB_Transaction_GetTransactionText (ab_trans);
381  if (ab_transactionText && *ab_transactionText)
382  gnc_description = g_strdup (ab_transactionText);
383  }
384 
385  ab_purpose = AB_Transaction_GetPurposeAsStringList (ab_trans);
386  if (ab_purpose)
387  GWEN_StringList_ForEach (ab_purpose, join_ab_strings_cb,
388  &gnc_description);
389 
390  GWEN_StringList_free (ab_purpose);
391 
392  return gnc_description;
393 }
394 
395 /* Ultimate Creditor and Ultimate Debtor are newish parameters added
396  * to SWIFT MT940 and CAMT.053 designating the originating
397  * payer or payee on the transaction. It's unlikely, but still
398  * possible, that a bank would use both this markup and the Non-swift
399  * TransactionText or RemoteName tags.
400  */
401 static gchar *
402 ab_ultimate_creditor_debtor_to_gnc (const AB_TRANSACTION *ab_trans,
403  gboolean is_ofx)
404 {
405  const gchar* ultimate;
406 
407  if (is_ofx)
408  return NULL;
409 
410  ultimate = AB_Transaction_GetUltimateCreditor (ab_trans);
411 
412  if (!ultimate || !*ultimate)
413  ultimate = AB_Transaction_GetUltimateDebtor (ab_trans);
414 
415  if (!ultimate || !*ultimate)
416  return NULL;
417 
418  return g_strdup (ultimate);
419 }
420 
421 gchar *
422 gnc_ab_description_to_gnc (const AB_TRANSACTION *ab_trans, gboolean is_ofx)
423 {
424  GList *acc = NULL;
425  gchar *retval;
426 
427  acc = g_list_prepend (acc, gnc_ab_get_remote_name (ab_trans));
428  acc = g_list_prepend (acc, gnc_ab_get_purpose (ab_trans, is_ofx));
429  acc = g_list_prepend (acc, ab_ultimate_creditor_debtor_to_gnc (ab_trans, is_ofx));
430  retval = gnc_g_list_stringjoin_nodups (acc, "; ");
431 
432  g_list_free_full (acc, g_free);
433  return retval ? retval : g_strdup (_("Unspecified"));
434 }
435 
436 gchar *
437 gnc_ab_memo_to_gnc (const AB_TRANSACTION *ab_trans)
438 {
439  const gchar *ab_remote_accountnumber =
440  AB_Transaction_GetRemoteAccountNumber (ab_trans);
441  const gchar *ab_remote_bankcode =
442  AB_Transaction_GetRemoteBankCode (ab_trans);
443 
444  gchar *ab_other_accountid;
445  gchar *ab_other_bankcode;
446 
447  gboolean have_accountid;
448  gboolean have_bankcode;
449 
450  gchar *retval;
451 
452  // For SEPA transactions, we need to ask for something different here
453  if (!ab_remote_accountnumber)
454  ab_remote_accountnumber = AB_Transaction_GetRemoteIban (ab_trans);
455  if (!ab_remote_bankcode)
456  ab_remote_bankcode = AB_Transaction_GetRemoteBic (ab_trans);
457 
458  ab_other_accountid = g_strdup (ab_remote_accountnumber ? ab_remote_accountnumber : "");
459  ab_other_bankcode = g_strdup (ab_remote_bankcode ? ab_remote_bankcode : "");
460 
461  /* Ensure string is in utf8 */
462  gnc_utf8_strip_invalid (ab_other_accountid);
463  gnc_utf8_strip_invalid (ab_other_bankcode);
464 
465  /* and -then- trim it */
466  g_strstrip (ab_other_accountid);
467  g_strstrip (ab_other_bankcode);
468 
469 
470  have_accountid = ab_other_accountid && *ab_other_accountid;
471  have_bankcode = ab_other_bankcode && *ab_other_bankcode;
472 
473  if ( have_accountid || have_bankcode )
474  {
475  retval = g_strdup_printf ("%s %s %s %s",
476  have_accountid ? _("Account") : "",
477  have_accountid ? ab_other_accountid : "",
478  have_bankcode ? _("Bank") : "",
479  have_bankcode ? ab_other_bankcode : ""
480  );
481  g_strstrip (retval);
482  }
483  else
484  {
485  retval = g_strdup ("");
486  }
487 
488  g_free (ab_other_accountid);
489  g_free (ab_other_bankcode);
490 
491  return retval;
492 }
493 
494 Transaction *
495 gnc_ab_trans_to_gnc (const AB_TRANSACTION *ab_trans, Account *gnc_acc)
496 {
497  QofBook *book;
498  Transaction *gnc_trans;
499  const gchar *fitid;
500  const GNC_GWEN_DATE *value_date, *post_date;
501  time64 post_time;
502  const char *custref;
503  gchar *description;
504  Split *split;
505  gchar *memo;
506 
507  g_return_val_if_fail (ab_trans && gnc_acc, NULL);
508 
509  /* Create new GnuCash transaction for the given AqBanking one */
510  book = gnc_account_get_book (gnc_acc);
511  gnc_trans = xaccMallocTransaction (book);
512  xaccTransBeginEdit (gnc_trans);
513 
514  /* Date / Time */
515  /* SWIFT import formats (in particular MT940) provide for two
516  * dates, the entry date and the value date (valuta is value in
517  * German). The value date is the effective date for financial
518  * calculation purposes and is mandatory, the entry date is the
519  * date that the financial institution posted the
520  * transaction. Unfortunately if the transaction field doesn't
521  * provide an entry date AQBanking substitutes the date from the
522  * last balance instead of using the value date or NULL, making
523  * the field unreliable.
524  */
525  value_date = AB_Transaction_GetValutaDate (ab_trans);
526  if (value_date)
527  post_time = gnc_gwen_date_to_time64 (value_date);
528  else if ((post_date = AB_Transaction_GetDate (ab_trans))) // always true
529  post_time = gnc_gwen_date_to_time64 (post_date);
530  else
531  {
532  g_warning ("transaction_cb: Import had no transaction date");
533  post_time = gnc_time (NULL);
534  }
535  xaccTransSetDatePostedSecsNormalized (gnc_trans, post_time);
536 
537  xaccTransSetDateEnteredSecs (gnc_trans, gnc_time (NULL));
538 
539  /* Currency. We take simply the default currency of the gnucash account */
540  xaccTransSetCurrency (gnc_trans, xaccAccountGetCommodity (gnc_acc));
541 
542  /* Trans-Num or Split-Action set with gnc_set_num_action below per book
543  * option */
544 
545  fitid = AB_Transaction_GetFiId (ab_trans);
546 
547  /* Description */
548  description = gnc_ab_description_to_gnc (ab_trans, (fitid && *fitid));
549  xaccTransSetDescription (gnc_trans, description);
550  g_free (description);
551 
552  /* Notes. */
553  /* xaccTransSetNotes(gnc_trans, g_notes); */
554  /* But Nobody ever uses the Notes field? */
555 
556  /* Add one split */
557  split = xaccMallocSplit (book);
558  xaccSplitSetParent (split, gnc_trans);
559  xaccSplitSetAccount (split, gnc_acc);
560 
561  /* Set the transaction number or split action field based on book option.
562  * We use the "customer reference", if there is one. */
563  custref = AB_Transaction_GetCustomerReference (ab_trans);
564  if (custref && *custref && g_ascii_strncasecmp (custref, "NONREF", 6) != 0)
565  gnc_set_num_action (gnc_trans, split, custref, NULL);
566 
567  /* Set OFX unique transaction ID */
568  if (fitid && *fitid)
569  gnc_import_set_split_online_id (split, fitid);
570 
571  /* FIXME: Extract function */
572  {
573  /* Amount into the split */
574  const AB_VALUE *ab_value = AB_Transaction_GetValue (ab_trans);
575  double d_value = ab_value ? AB_Value_GetValueAsDouble (ab_value) : 0.0;
576  AB_TRANSACTION_TYPE ab_type = AB_Transaction_GetType (ab_trans);
577  gnc_numeric gnc_amount;
578 
579  /*printf("Transaction with value %f has type %d\n", d_value, ab_type);*/
580  /* If the value is positive, but the transaction type says the
581  money is transferred away from our account (Transfer instead of
582  DebitNote), we switch the value to negative. */
583  if (d_value > 0.0 && ab_type == AB_Transaction_TypeTransfer)
584  d_value = -d_value;
585 
586  gnc_amount = double_to_gnc_numeric (
587  d_value,
588  xaccAccountGetCommoditySCU (gnc_acc),
590  if (!ab_value)
591  g_warning ("transaction_cb: Oops, value was NULL. Using 0");
592  xaccSplitSetBaseValue (split, gnc_amount, xaccAccountGetCommodity (gnc_acc));
593  }
594 
595  /* Memo in the Split. */
596  memo = gnc_ab_memo_to_gnc (ab_trans);
597  xaccSplitSetMemo (split, memo);
598  g_free (memo);
599 
600  return gnc_trans;
601 }
602 
611 static Account *
612 gnc_ab_accinfo_to_gnc_acc (GtkWidget *parent, AB_IMEXPORTER_ACCOUNTINFO *acc_info)
613 {
614  const gchar *bankcode, *accountnumber;
615  gchar *online_id;
616  Account *gnc_acc;
617 
618  g_return_val_if_fail (acc_info, NULL);
619 
620  bankcode = AB_ImExporterAccountInfo_GetBankCode (acc_info);
621  accountnumber = AB_ImExporterAccountInfo_GetAccountNumber (acc_info);
622  online_id = gnc_ab_create_online_id (bankcode, accountnumber);
623  gnc_acc = gnc_import_select_account (parent, online_id, 1,
624  AB_ImExporterAccountInfo_GetAccountName (acc_info),
625  NULL, ACCT_TYPE_NONE, NULL, NULL);
626  if (!gnc_acc)
627  {
628  g_warning ("gnc_ab_accinfo_to_gnc_acc: Could not determine source account"
629  " for online_id %s", online_id);
630  }
631  g_free (online_id);
632 
633  return gnc_acc;
634 }
635 
636 
645 static Account *
646 gnc_ab_txn_to_gnc_acc (GtkWidget *parent, const AB_TRANSACTION *transaction)
647 {
648  const gchar *bankcode, *accountnumber;
649  gchar *online_id;
650  Account *gnc_acc;
651 
652  g_return_val_if_fail(transaction, NULL);
653 
654  bankcode = AB_Transaction_GetLocalBankCode (transaction);
655  accountnumber = AB_Transaction_GetLocalAccountNumber (transaction);
656  if (!bankcode && !accountnumber)
657  {
658  return NULL;
659  }
660 
661  online_id = gnc_ab_create_online_id (bankcode, accountnumber);
662  gnc_acc = gnc_import_select_account (parent, online_id, 1,
663  AB_Transaction_GetLocalName (transaction),
664  NULL, ACCT_TYPE_NONE, NULL, NULL);
665  if (!gnc_acc)
666  {
667  g_warning ("gnc_ab_txn_to_gnc_acc: Could not determine source account"
668  " for online_id %s", online_id);
669  }
670  g_free (online_id);
671 
672  return gnc_acc;
673 }
674 
675 static const AB_TRANSACTION *
676 txn_transaction_cb (const AB_TRANSACTION *element, gpointer user_data)
677 {
678  GncABImExContextImport *data = user_data;
679  Transaction *gnc_trans;
680  GncABTransType trans_type;
681  Account* txnacc;
682 
683  g_return_val_if_fail (element && data, NULL);
684 
685  /* Create a GnuCash transaction from ab_trans */
686  txnacc = gnc_ab_txn_to_gnc_acc (GTK_WIDGET(data->parent), element);
687  gnc_trans = gnc_ab_trans_to_gnc (element, txnacc ? txnacc : data->gnc_acc);
688 
689  if (data->execute_txns && data->ab_acc)
690  {
691  AB_TRANSACTION *ab_trans = AB_Transaction_dup (element);
692  GNC_AB_JOB *job;
693 
694  /* NEW: The imported transaction has been imported into gnucash.
695  * Now also add it as a job to aqbanking */
696  AB_Transaction_SetLocalBankCode (
697  ab_trans, AB_AccountSpec_GetBankCode (data->ab_acc));
698  AB_Transaction_SetLocalAccountNumber (
699  ab_trans, AB_AccountSpec_GetAccountNumber (data->ab_acc));
700  AB_Transaction_SetLocalCountry (ab_trans, "DE");
701 
702 
703  switch (AB_Transaction_GetType (ab_trans))
704  {
705  case AB_Transaction_TypeDebitNote:
706  trans_type = SINGLE_DEBITNOTE;
707  break;
708  case AB_Transaction_TypeTransaction:
709  /* trans_type = SINGLE_INTERNAL_TRANSFER;
710  * break; */
711  case AB_Transaction_TypeTransfer:
712  default:
713  trans_type = SEPA_TRANSFER;
714  break;
715  } /* switch */
716 
717  job = gnc_ab_get_trans_job (data->ab_acc, ab_trans, trans_type);
718 
719  /* Check whether we really got a job */
720  if (!job || AB_AccountSpec_GetTransactionLimitsForCommand (data->ab_acc, AB_Transaction_GetCommand (job)) == NULL)
721  {
722  /* Oops, no job, probably not supported by bank */
723  if (gnc_verify_dialog (
724  GTK_WINDOW(data->parent), FALSE, "%s",
725  _("The backend found an error during the preparation "
726  "of the job. It is not possible to execute this job.\n"
727  "\n"
728  "Most probably the bank does not support your chosen "
729  "job or your Online Banking account does not have the permission "
730  "to execute this job. More error messages might be "
731  "visible on your console log.\n"
732  "\n"
733  "Do you want to enter the job again?")))
734  {
735  gnc_error_dialog (GTK_WINDOW(data->parent),
736  "Sorry, not implemented yet. Please check the console or trace file logs to see which job was rejected.");
737  }
738  }
739  else
740  {
741  gnc_gen_trans_list_add_trans_with_ref_id (data->generic_importer,
742  gnc_trans,
743  AB_Transaction_GetUniqueId (job));
744  /* AB_Job_List2_PushBack(data->job_list, job); -> delayed until trans is successfully imported */
745  g_datalist_set_data (&data->tmp_job_list, gnc_AB_JOB_to_readable_string (job), job);
746  }
747  AB_Transaction_free (ab_trans);
748  }
749  else
750  {
751  /* Instead of xaccTransCommitEdit(gnc_trans) */
752  gnc_gen_trans_list_add_trans (data->generic_importer, gnc_trans);
753  }
754 
755  return NULL;
756 }
757 
758 static void gnc_ab_trans_processed_cb (GNCImportTransInfo *trans_info,
759  gboolean imported,
760  gpointer user_data)
761 {
762  GncABImExContextImport *data = user_data;
763  gchar *jobname = gnc_AB_JOB_ID_to_string (gnc_import_TransInfo_get_ref_id (trans_info));
764  GNC_AB_JOB *job = g_datalist_get_data (&data->tmp_job_list, jobname);
765 
766  if (imported)
767  {
768  AB_Transaction_List2_PushBack (data->job_list, job);
769  }
770  else
771  {
772  AB_Transaction_free (job);
773  }
774 
775  g_datalist_remove_data (&data->tmp_job_list, jobname);
776 }
777 
778 gchar *
779 gnc_AB_JOB_to_readable_string (const GNC_AB_JOB *job)
780 {
781  if (job)
782  {
783  return gnc_AB_JOB_ID_to_string (AB_Transaction_GetUniqueId (job));
784  }
785  else
786  {
787  return gnc_AB_JOB_ID_to_string (0);
788  }
789 }
790 gchar *
791 gnc_AB_JOB_ID_to_string (gulong job_id)
792 {
793  return g_strdup_printf ("job_%lu", job_id);
794 }
795 
796 
797 
798 static AB_IMEXPORTER_ACCOUNTINFO *
799 txn_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
800 {
801  GncABImExContextImport *data = user_data;
802  Account *gnc_acc;
803 
804  g_return_val_if_fail (element && data, NULL);
805 
806  if (data->awaiting & IGNORE_TRANSACTIONS)
807  /* Ignore them */
808  return NULL;
809 
810  if (!AB_ImExporterAccountInfo_GetFirstTransaction (element, AB_Transaction_TypeStatement, 0))
811 /* No transaction found */
812  return NULL;
813  else
814  data->awaiting |= FOUND_TRANSACTIONS;
815 
816  if (!(data->awaiting & AWAIT_TRANSACTIONS))
817  {
818  if (gnc_verify_dialog (GTK_WINDOW(data->parent), TRUE, "%s",
819  _("The bank has sent transaction information "
820  "in its response."
821  "\n"
822  "Do you want to import it?")))
823  {
824  data->awaiting |= AWAIT_TRANSACTIONS;
825  }
826  else
827  {
828  data->awaiting |= IGNORE_TRANSACTIONS;
829  return NULL;
830  }
831  }
832 
833  /* Lookup the corresponding gnucash account */
834  gnc_acc = gnc_ab_accinfo_to_gnc_acc (GTK_WIDGET(data->parent), element);
835  if (!gnc_acc) return NULL;
836  data->gnc_acc = gnc_acc;
837 
838  if (data->execute_txns)
839  {
840  /* Retrieve the aqbanking account that belongs to this gnucash
841  * account */
842  data->ab_acc = gnc_ab_get_ab_account (data->api, gnc_acc);
843  if (!data->ab_acc)
844  {
845  gnc_error_dialog (GTK_WINDOW(data->parent), "%s",
846  _("No Online Banking account found for this "
847  "gnucash account. These transactions will "
848  "not be executed by Online Banking."));
849  }
850  }
851  else
852  {
853  data->ab_acc = NULL;
854  }
855 
856  if (!data->generic_importer)
857  {
858  data->generic_importer = gnc_gen_trans_list_new (data->parent, NULL,
859  TRUE, 14, TRUE);
860  if (data->execute_txns)
861  {
862  gnc_gen_trans_list_add_tp_cb (data->generic_importer,
863  gnc_ab_trans_processed_cb, data);
864  }
865  }
866 
867  /* Iterate through all transactions */
868  {
869  AB_TRANSACTION_LIST *ab_trans_list = AB_ImExporterAccountInfo_GetTransactionList (element);
870  if (ab_trans_list)
871  AB_Transaction_List_ForEachByType (ab_trans_list,
872  txn_transaction_cb, data,
873  AB_Transaction_TypeStatement, 0);
874  }
875  return NULL;
876 }
877 
878 static AB_IMEXPORTER_ACCOUNTINFO *
879 bal_accountinfo_cb (AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
880 {
881  GncABImExContextImport *data = user_data;
882  Account *gnc_acc;
883  const AB_BALANCE *booked_bal, *noted_bal;
884  const AB_VALUE *booked_val = NULL, *noted_val = NULL;
885  gdouble booked_value, noted_value;
886  gnc_numeric value;
887  time64 booked_tt = 0;
888  GtkWidget *dialog;
889  gboolean show_recn_window = FALSE;
890 
891  g_return_val_if_fail (element && data, NULL);
892 
893  if (data->awaiting & IGNORE_BALANCES)
894  /* Ignore them */
895  return NULL;
896 
897  if (!AB_ImExporterAccountInfo_GetFirstBalance (element))
898  /* No balance found */
899  return NULL;
900  else
901  data->awaiting |= FOUND_BALANCES;
902 
903  /* Lookup the most recent BALANCE available */
904  booked_bal = AB_Balance_List_GetLatestByType (AB_ImExporterAccountInfo_GetBalanceList (element),
905  AB_Balance_TypeBooked);
906 
907  if (!(data->awaiting & AWAIT_BALANCES))
908  {
909  GtkWindow *parent = data->generic_importer ?
910  GTK_WINDOW(gnc_gen_trans_list_widget (data->generic_importer)) :
911  GTK_WINDOW(data->parent);
912  const char* balance_msg =
913  _("The bank has sent balance information in its response.\n"
914  "Do you want to import it?");
915  /* Ignore zero balances if we don't await a balance */
916  if (!booked_bal || AB_Value_IsZero (AB_Balance_GetValue (booked_bal)))
917  return NULL;
918 
919  /* Ask the user whether to import unawaited non-zero balance */
920  if (gnc_verify_dialog (parent, TRUE, "%s", balance_msg))
921  {
922  data->awaiting |= AWAIT_BALANCES;
923  }
924  else
925  {
926  data->awaiting |= IGNORE_BALANCES;
927  return NULL;
928  }
929  }
930 
931  /* Lookup the corresponding gnucash account */
932  gnc_acc = gnc_ab_accinfo_to_gnc_acc (GTK_WIDGET(data->parent), element);
933  if (!gnc_acc) return NULL;
934  data->gnc_acc = gnc_acc;
935 
936  /* Lookup booked balance and time */
937  if (booked_bal)
938  {
939  const GWEN_DATE *ti = AB_Balance_GetDate (booked_bal);
940  if (ti)
941  {
942  booked_tt = gnc_gwen_date_to_time64 (ti);
943  }
944  else
945  {
946  /* No time found? Use today because the HBCI query asked for today's
947  * balance. */
948  booked_tt = gnc_time64_get_day_neutral (gnc_time (NULL));
949  }
950  booked_val = AB_Balance_GetValue (booked_bal);
951  if (booked_val)
952  {
953  booked_value = AB_Value_GetValueAsDouble (booked_val);
954  }
955  else
956  {
957  g_warning ("bal_accountinfo_cb: booked_val == NULL. Assuming 0");
958  booked_value = 0.0;
959  }
960  }
961  else
962  {
963  g_warning ("bal_accountinfo_cb: booked_bal == NULL. Assuming 0");
964  booked_tt = 0;
965  booked_value = 0.0;
966  }
967 
968  /* Lookup noted balance */
969  noted_bal = AB_Balance_List_GetLatestByType (AB_ImExporterAccountInfo_GetBalanceList (element),
970  AB_Balance_TypeNoted);
971  if (noted_bal)
972  {
973  noted_val = AB_Balance_GetValue (noted_bal);
974  if (noted_val)
975  noted_value = AB_Value_GetValueAsDouble (noted_val);
976  else
977  {
978  g_warning ("bal_accountinfo_cb: noted_val == NULL. Assuming 0");
979  noted_value = 0.0;
980  }
981  }
982  else
983  {
984  g_warning ("bal_accountinfo_cb: noted_bal == NULL. Assuming 0");
985  noted_value = 0.0;
986  }
987 
988  value = double_to_gnc_numeric (booked_value,
989  xaccAccountGetCommoditySCU (gnc_acc),
991  if (noted_value == 0.0 && booked_value == 0.0)
992  {
993  dialog = gtk_message_dialog_new (
994  GTK_WINDOW(data->parent),
995  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
996  GTK_MESSAGE_INFO,
997  GTK_BUTTONS_OK,
998  "%s",
999  /* Translators: Strings from this file are needed only in
1000  countries that have one of aqbanking's Online Banking
1001  techniques available. This is 'OFX DirectConnect'
1002  (U.S. and others), 'HBCI' (in Germany), or 'YellowNet'
1003  (Switzerland). If none of these techniques are available
1004  in your country, you may safely ignore strings from the
1005  import-export/hbci subdirectory. */
1006  _("The downloaded Online Banking Balance was zero.\n\n"
1007  "Either this is the correct balance, or your bank does not "
1008  "support Balance download in this Online Banking version. "
1009  "In the latter case you should choose a different "
1010  "Online Banking version number in the Online Banking "
1011  "(AqBanking or HBCI) Setup. After that, try again to "
1012  "download the Online Banking Balance."));
1013  gtk_dialog_run (GTK_DIALOG(dialog));
1014  gtk_widget_destroy (dialog);
1015 
1016  }
1017  else
1018  {
1019  gnc_numeric reconc_balance = xaccAccountGetReconciledBalance (gnc_acc);
1020 
1021  gchar *booked_str = gnc_AB_VALUE_to_readable_string (booked_val);
1022  gchar *message1 = g_strdup_printf (
1023  _("Result of Online Banking job:\n"
1024  "Account booked balance is %s"),
1025  booked_str);
1026  gchar *message2 =
1027  (noted_value == 0.0) ?
1028  g_strdup ("") :
1029  g_strdup_printf (_("For your information: This account also "
1030  "has a noted balance of %s\n"),
1031  gnc_AB_VALUE_to_readable_string (noted_val));
1032 
1033  if (gnc_numeric_equal (value, reconc_balance))
1034  {
1035  const gchar *message3 =
1036  _("The booked balance is identical to the current "
1037  "reconciled balance of the account.");
1038  dialog = gtk_message_dialog_new (
1039  GTK_WINDOW(data->parent),
1040  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1041  GTK_MESSAGE_INFO,
1042  GTK_BUTTONS_OK,
1043  "%s\n%s\n%s",
1044  message1, message2, message3);
1045  gtk_dialog_run (GTK_DIALOG(dialog));
1046  gtk_widget_destroy (GTK_WIDGET(dialog));
1047 
1048  }
1049  else
1050  {
1051  const char *message3 = _("Reconcile account now?");
1052 
1053  show_recn_window = gnc_verify_dialog (GTK_WINDOW(data->parent), TRUE, "%s\n%s\n%s",
1054  message1, message2, message3);
1055  }
1056  g_free (booked_str);
1057  g_free (message1);
1058  g_free (message2);
1059  }
1060 
1061  /* Show reconciliation window */
1062  if (show_recn_window)
1063  recnWindowWithBalance (GTK_WIDGET(data->parent), gnc_acc, value, booked_tt);
1064 
1065  return NULL;
1066 }
1067 
1068 GncABImExContextImport *
1069 gnc_ab_import_context (AB_IMEXPORTER_CONTEXT *context,
1070  guint awaiting, gboolean execute_txns,
1071  AB_BANKING *api, GtkWidget *parent)
1072 {
1073  GncABImExContextImport *data = g_new (GncABImExContextImport, 1);
1074  AB_IMEXPORTER_ACCOUNTINFO_LIST *ab_ail;
1075  g_return_val_if_fail (context, NULL);
1076  /* Do not await and ignore at the same time */
1077  g_return_val_if_fail (!(awaiting & AWAIT_BALANCES)
1078  || !(awaiting & IGNORE_BALANCES),
1079  NULL);
1080  g_return_val_if_fail (!(awaiting & AWAIT_TRANSACTIONS)
1081  || !(awaiting & IGNORE_TRANSACTIONS),
1082  NULL);
1083  /* execute_txns must be FALSE if txns are not awaited */
1084  g_return_val_if_fail (awaiting & AWAIT_TRANSACTIONS || !execute_txns, NULL);
1085  /* An api is needed for the jobs */
1086  g_return_val_if_fail (!execute_txns || api, NULL);
1087 
1088  data->awaiting = awaiting;
1089  data->txn_found = FALSE;
1090  data->execute_txns = execute_txns;
1091  data->api = api;
1092  data->parent = parent;
1093  data->job_list = AB_Transaction_List2_new ();
1094  data->tmp_job_list = NULL;
1095  data->generic_importer = NULL;
1096 
1097  g_datalist_init (&data->tmp_job_list);
1098 
1099  /* Import transactions */
1100  ab_ail = AB_ImExporterContext_GetAccountInfoList (context);
1101  if (ab_ail && AB_ImExporterAccountInfo_List_GetCount (ab_ail))
1102  {
1103  if (!(awaiting & IGNORE_TRANSACTIONS))
1104  AB_ImExporterAccountInfo_List_ForEach (ab_ail,
1105  txn_accountinfo_cb,
1106  data);
1107 
1108  /* populate and display the matching window */
1109  if (data->generic_importer)
1110  gnc_gen_trans_list_show_all (data->generic_importer);
1111 
1112  /* Check balances */
1113  if (!(awaiting & IGNORE_BALANCES))
1114  AB_ImExporterAccountInfo_List_ForEach (ab_ail,
1115  bal_accountinfo_cb,
1116  data);
1117  }
1118 
1119  /* Check bank-messages */
1120  {
1121  AB_MESSAGE * bankmsg = AB_ImExporterContext_GetFirstMessage (context);
1122  while (bankmsg)
1123  {
1124  const char* subject = AB_Message_GetSubject (bankmsg);
1125  const char* text = AB_Message_GetText (bankmsg);
1126  gnc_info_dialog (GTK_WINDOW(data->parent), "%s\n%s %s\n%s",
1127  _("The bank has sent a message in its response."),
1128  _("Subject:"),
1129  subject,
1130  text);
1131 
1132  bankmsg = AB_Message_List_Next (bankmsg);
1133  }
1134  }
1135 
1136  return data;
1137 }
1138 
1139 guint
1140 gnc_ab_ieci_get_found (GncABImExContextImport *ieci)
1141 {
1142  g_return_val_if_fail (ieci, 0);
1143 
1144  return ieci->awaiting;
1145 }
1146 
1147 GNC_AB_JOB_LIST2 *
1148 gnc_ab_ieci_get_job_list (GncABImExContextImport *ieci)
1149 {
1150  g_return_val_if_fail (ieci, NULL);
1151 
1152  return ieci->job_list;
1153 }
1154 
1155 gboolean
1156 gnc_ab_ieci_run_matcher (GncABImExContextImport *ieci)
1157 {
1158  g_return_val_if_fail (ieci, FALSE);
1159 
1160  return gnc_gen_trans_list_run (ieci->generic_importer);
1161 }
1162 
1163 GWEN_DB_NODE *
1165 {
1166  int rv;
1167  GWEN_DB_NODE *perm_certs = NULL;
1168  AB_BANKING *banking = gnc_AB_BANKING_new ();
1169 
1170  g_return_val_if_fail (banking, NULL);
1171  rv = AB_Banking_LoadSharedConfig (banking, "certs", &perm_certs);
1172  gnc_AB_BANKING_fini (banking);
1173  g_return_val_if_fail (rv >= 0, NULL);
1174  return perm_certs;
1175 }
1176 
1177 #if (AQBANKING_VERSION_INT >= 60400)
1178 GList*
1179 gnc_ab_trans_templ_list_new_from_ref_accounts (GNC_AB_ACCOUNT_SPEC *ab_acc)
1180 {
1181  GList *retval = NULL;
1182  AB_REFERENCE_ACCOUNT *ra;
1183  AB_REFERENCE_ACCOUNT_LIST *ral;
1184  GWEN_BUFFER *accNameForTemplate = GWEN_Buffer_new (0,120,0,0);
1185  gnc_numeric zero = gnc_numeric_zero ();
1186 
1187  /* get the target account list */
1188  ral = AB_AccountSpec_GetRefAccountList (ab_acc);
1189  ra = AB_ReferenceAccount_List_First (ral);
1190 
1191  /* fill the template list with the target accounts */
1192  while (ra)
1193  {
1194  GncABTransTempl *new_templ = gnc_ab_trans_templ_new ();
1195  const char *iban = AB_ReferenceAccount_GetIban (ra);
1196  const char *accName = AB_ReferenceAccount_GetAccountName (ra);
1197  GWEN_Buffer_Reset (accNameForTemplate);
1198  if (accName)
1199  {
1200  GWEN_Buffer_AppendString (accNameForTemplate, accName);
1201  GWEN_Buffer_AppendString (accNameForTemplate, ": ");
1202  }
1203  GWEN_Buffer_AppendString (accNameForTemplate, iban);
1204  gnc_ab_trans_templ_set_name (new_templ, GWEN_Buffer_GetStart (accNameForTemplate));
1205  gnc_ab_trans_templ_set_recp_name (new_templ, AB_ReferenceAccount_GetOwnerName (ra));
1206  gnc_ab_trans_templ_set_recp_account (new_templ, AB_ReferenceAccount_GetIban (ra));
1207  gnc_ab_trans_templ_set_recp_bankcode (new_templ, AB_ReferenceAccount_GetBic (ra));
1208  gnc_ab_trans_templ_set_amount (new_templ, zero);
1209  retval = g_list_prepend (retval, new_templ);
1210  ra = AB_ReferenceAccount_List_Next (ra);
1211  }
1212  retval = g_list_reverse (retval);
1213 
1214  GWEN_Buffer_free (accNameForTemplate);
1215 
1216  return retval;
1217 }
1218 #endif
1219 static int
1220 ab_node_pair_compare (AB_Node_Pair* left, AB_Node_Pair* right)
1221 {
1222  return left ? (right ? g_strcmp0 (left->name, right->name) : -1) :
1223  (right ? 1 : 0);
1224 }
1225 
1226 GList*
1227 gnc_ab_imexporter_list (AB_BANKING* api)
1228 {
1229  GList* desc_list = NULL;
1230  GWEN_PLUGIN_DESCRIPTION_LIST2 *il =
1231  AB_Banking_GetImExporterDescrs (api);
1232  GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *ilit;
1233  g_return_val_if_fail (il, NULL);
1234  ilit = GWEN_PluginDescription_List2_First(il);
1235 
1236  for (GWEN_PLUGIN_DESCRIPTION *pd =
1237  GWEN_PluginDescription_List2Iterator_Data(ilit);
1238  pd;
1239  pd = GWEN_PluginDescription_List2Iterator_Next(ilit))
1240  {
1241  AB_Node_Pair *node = NULL;
1242 
1243  node = g_slice_new (AB_Node_Pair);
1244  node->name = g_strdup(GWEN_PluginDescription_GetName(pd));
1245  node->descr = g_strdup(GWEN_PluginDescription_GetShortDescr(pd));
1246  desc_list = g_list_prepend (desc_list, node);
1247  }
1248  GWEN_PluginDescription_List2_free(il);
1249  return g_list_sort (desc_list, (GCompareFunc)ab_node_pair_compare);
1250 }
1251 
1252 GList*
1253 gnc_ab_imexporter_profile_list (AB_BANKING* api, const char* importer_name)
1254 {
1255  GList* prof_list = NULL;
1256  GWEN_DB_NODE* db = AB_Banking_GetImExporterProfiles(api, importer_name);
1257  g_return_val_if_fail (db, NULL);
1258 
1259  for (GWEN_DB_NODE *profile = GWEN_DB_GetFirstGroup(db); profile;
1260  profile = GWEN_DB_GetNextGroup(profile))
1261  {
1262  AB_Node_Pair *node = g_slice_new(AB_Node_Pair);
1263  if (!profile) continue;
1264  node->name = g_strdup(GWEN_DB_GetCharValue(profile, "name", 0, NULL));
1265  node->descr = g_strdup(GWEN_DB_GetCharValue(profile, "shortDescr", 0, NULL));
1266  prof_list = g_list_prepend (prof_list, node);
1267  }
1268  return g_list_sort (prof_list, (GCompareFunc)ab_node_pair_compare);
1269 }
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:347
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:1321
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 in, 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:2696
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:367
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:791
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:437
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:422
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:495
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:779
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:3424
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:3351
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:261
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:1307