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