1 /*
2  * gnc-ab-transfer.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 
22 /**
23  * @internal
24  * @file gnc-ab-utils.c
25  * @brief AqBanking transfer functions
26  * @author Copyright (C) 2002 Christian Stimming <stimming@tuhh.de>
27  * @author Copyright (C) 2004 Bernd Wagner
28  * @author Copyright (C) 2006 David Hampton <hampton@employees.org>
29  * @author Copyright (C) 2008 Andreas Koehler <andi5.py@gmx.net>
30  */
31 
32 #include <config.h>
33 
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include <aqbanking/banking.h>
37 
38 #include <gnc-aqbanking-templates.h>
39 #include <Transaction.h>
40 #include "dialog-transfer.h"
41 #include "gnc-ab-transfer.h"
42 #include "gnc-ab-kvp.h"
43 #include "gnc-ab-utils.h"
44 #include "gnc-gwen-gui.h"
45 #include "gnc-ui.h"
46 
47 /* This static indicates the debugging module that this .o belongs to.  */
48 G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
49 
50 static void save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates,
51                            gboolean dont_ask);
52 static void txn_created_cb(Transaction *trans, gpointer user_data);
53 
54 static void
save_templates(GtkWidget * parent,Account * gnc_acc,GList * templates,gboolean dont_ask)55 save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates,
56                gboolean dont_ask)
57 {
58     g_return_if_fail(gnc_acc);
59     if (dont_ask || gnc_verify_dialog (
60                 GTK_WINDOW (parent), FALSE, "%s",
61                 _("You have changed the list of online transfer templates, "
62                   "but you cancelled the transfer dialog. "
63                   "Do you nevertheless want to store the changes?")))
64     {
65         gnc_ab_set_book_template_list(gnc_account_get_book(gnc_acc), templates);
66     }
67 }
68 
69 static void
txn_created_cb(Transaction * trans,gpointer user_data)70 txn_created_cb(Transaction *trans, gpointer user_data)
71 {
72     Transaction **trans_loc = user_data;
73 
74     if (!trans) return;
75     g_return_if_fail(trans_loc);
76     *trans_loc = trans;
77 }
78 
79 void
gnc_ab_maketrans(GtkWidget * parent,Account * gnc_acc,GncABTransType trans_type)80 gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc,
81                  GncABTransType trans_type)
82 {
83     AB_BANKING *api;
84     gboolean online = FALSE;
85     GNC_AB_ACCOUNT_SPEC *ab_acc;
86     GList *templates = NULL;
87     GncABTransDialog *td = NULL;
88     gboolean successful = FALSE;
89     gboolean aborted = FALSE;
90 
91     g_return_if_fail(parent && gnc_acc);
92 
93     /* Get the API */
94     api = gnc_AB_BANKING_new();
95     if (!api)
96     {
97         g_warning("gnc_ab_maketrans: Couldn't get AqBanking API");
98         return;
99     }
100 #ifndef AQBANKING6
101     if (AB_Banking_OnlineInit(api) != 0)
102     {
103         g_warning("gnc_ab_maketrans: Couldn't initialize AqBanking API");
104         goto cleanup;
105     }
106     online = TRUE;
107 #endif
108     /* Get the AqBanking Account */
109     ab_acc = gnc_ab_get_ab_account(api, gnc_acc);
110     if (!ab_acc)
111     {
112         g_warning("gnc_ab_gettrans: No AqBanking account found");
113         gnc_error_dialog (GTK_WINDOW (parent), _("No valid online banking account assigned."));
114         goto cleanup;
115     }
116 
117 #if (AQBANKING_VERSION_INT >= 60400)
118     if (trans_type == SEPA_INTERNAL_TRANSFER)
119     {
120         /* Generate list of template transactions from the reference accounts*/
121         templates = gnc_ab_trans_templ_list_new_from_ref_accounts (ab_acc);
122         if (templates == NULL)
123         {
124             g_warning ("gnc_ab_gettrans: No reference accounts found");
125             gnc_error_dialog (GTK_WINDOW (parent), _("No reference accounts found."));
126             goto cleanup;
127         }
128     }
129     else
130 #endif
131     {
132     /* Get list of template transactions */
133         templates = gnc_ab_trans_templ_list_new_from_book(
134              gnc_account_get_book(gnc_acc));
135     }
136 
137     /* Create new ABTransDialog */
138     td = gnc_ab_trans_dialog_new(parent, ab_acc,
139                                  xaccAccountGetCommoditySCU(gnc_acc),
140                                  trans_type, templates);
141     templates = NULL;
142 
143     /* Repeat until AqBanking action was successful or user pressed cancel */
144     do
145     {
146         GncGWENGui *gui = NULL;
147         gint result;
148         gboolean changed;
149         const AB_TRANSACTION *ab_trans;
150         GNC_AB_JOB *job = NULL;
151         GNC_AB_JOB_LIST2 *job_list = NULL;
152         XferDialog *xfer_dialog = NULL;
153         gnc_numeric amount;
154         gchar *description;
155         gchar *memo;
156         Transaction *gnc_trans = NULL;
157         AB_IMEXPORTER_CONTEXT *context = NULL;
158         GNC_AB_JOB_STATUS job_status;
159         GncABImExContextImport *ieci = NULL;
160 
161 #ifndef AQBANKING6
162         /* Get a GUI object */
163         gui = gnc_GWEN_Gui_get(parent);
164         if (!gui)
165         {
166             g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI");
167             aborted = TRUE;
168             goto repeat;
169         }
170 #endif
171 
172         /* Let the user enter the values */
173         result = gnc_ab_trans_dialog_run_until_ok(td);
174 
175         templates = gnc_ab_trans_dialog_get_templ(td, &changed);
176 #if (AQBANKING_VERSION_INT >= 60400)
177         if (trans_type != SEPA_INTERNAL_TRANSFER && changed)
178 #else
179 	if (changed)
180 #endif
181         {
182            /* Save the templates */
183             save_templates(parent, gnc_acc, templates,
184                            (result == GNC_RESPONSE_NOW));
185         }
186         g_list_free(templates);
187         templates = NULL;
188 
189         if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER)
190         {
191             aborted = TRUE;
192             goto repeat;
193         }
194 
195         /* Get a job and enqueue it */
196         ab_trans = gnc_ab_trans_dialog_get_ab_trans(td);
197         job = gnc_ab_trans_dialog_get_job(td);
198 #ifdef AQBANKING6
199         if (!job || AB_AccountSpec_GetTransactionLimitsForCommand(ab_acc, AB_Transaction_GetCommand(job))==NULL)
200 #else
201         if (!job || AB_Job_CheckAvailability(job))
202 #endif
203         {
204             if (!gnc_verify_dialog (
205                         GTK_WINDOW (parent), FALSE, "%s",
206                         _("The backend found an error during the preparation "
207                           "of the job. It is not possible to execute this job.\n"
208                           "\n"
209                           "Most probable the bank does not support your chosen "
210                           "job or your Online Banking account does not have the permission "
211                           "to execute this job. More error messages might be "
212                           "visible on your console log.\n"
213                           "\n"
214                           "Do you want to enter the job again?")))
215                 aborted = TRUE;
216             goto repeat;
217         }
218 #ifdef AQBANKING6
219         job_list = AB_Transaction_List2_new();
220         AB_Transaction_List2_PushBack(job_list, job);
221 #else
222         job_list = AB_Job_List2_new();
223         AB_Job_List2_PushBack(job_list, job);
224 #endif
225         /* Setup a Transfer Dialog for the GnuCash transaction */
226         xfer_dialog = gnc_xfer_dialog(gnc_ab_trans_dialog_get_parent(td),
227                                       gnc_acc);
228         switch (trans_type)
229         {
230         case SINGLE_DEBITNOTE:
231             gnc_xfer_dialog_set_title(
232                 xfer_dialog, _("Online Banking Direct Debit Note"));
233             gnc_xfer_dialog_lock_to_account_tree(xfer_dialog);
234             break;
235         case SINGLE_INTERNAL_TRANSFER:
236             gnc_xfer_dialog_set_title(
237                 xfer_dialog, _("Online Banking Bank-Internal Transfer"));
238             gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
239             break;
240         case SEPA_TRANSFER:
241             gnc_xfer_dialog_set_title(
242                 xfer_dialog, _("Online Banking European (SEPA) Transfer"));
243             gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
244             break;
245 #if (AQBANKING_VERSION_INT >= 60400)
246         case SEPA_INTERNAL_TRANSFER:
247             gnc_xfer_dialog_set_title (
248                 xfer_dialog, _("Online Banking European (SEPA) Internal Transfer"));
249             gnc_xfer_dialog_lock_from_account_tree (xfer_dialog);
250             break;
251 #endif
252         case SEPA_DEBITNOTE:
253             gnc_xfer_dialog_set_title(
254                 xfer_dialog, _("Online Banking European (SEPA) Debit Note"));
255             gnc_xfer_dialog_lock_to_account_tree(xfer_dialog);
256             break;
257         case SINGLE_TRANSFER:
258         default:
259             gnc_xfer_dialog_set_title(
260                 xfer_dialog, _("Online Banking Transaction"));
261             gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
262         }
263         gnc_xfer_dialog_set_to_show_button_active(xfer_dialog, TRUE);
264 
265         amount = double_to_gnc_numeric(
266                      AB_Value_GetValueAsDouble(AB_Transaction_GetValue(ab_trans)),
267                      xaccAccountGetCommoditySCU(gnc_acc),
268                      GNC_HOW_RND_ROUND_HALF_UP);
269         gnc_xfer_dialog_set_amount(xfer_dialog, amount);
270         gnc_xfer_dialog_set_amount_sensitive(xfer_dialog, FALSE);
271         gnc_xfer_dialog_set_date_sensitive(xfer_dialog, FALSE);
272 
273         /* OFX doesn't do transfers. */
274         description = gnc_ab_description_to_gnc(ab_trans, FALSE);
275         gnc_xfer_dialog_set_description(xfer_dialog, description);
276         g_free(description);
277 
278         memo = gnc_ab_memo_to_gnc(ab_trans);
279         gnc_xfer_dialog_set_memo(xfer_dialog, memo);
280         g_free(memo);
281 
282         gnc_xfer_dialog_set_txn_cb(xfer_dialog, txn_created_cb, &gnc_trans);
283 
284         /* And run it */
285         successful = gnc_xfer_dialog_run_until_done(xfer_dialog);
286 
287         /* On cancel, go back to the AB transaction dialog */
288         if (!successful || !gnc_trans)
289         {
290             successful = FALSE;
291             goto repeat;
292         }
293 
294         if (result == GNC_RESPONSE_NOW)
295         {
296             /* Create a context to store possible results */
297             context = AB_ImExporterContext_new();
298 
299             gui = gnc_GWEN_Gui_get(parent);
300             if (!gui)
301             {
302                 g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI");
303                 aborted = TRUE;
304                 goto repeat;
305             }
306 
307             /* Finally, execute the job */
308 #ifdef AQBANKING6
309             AB_Banking_SendCommands(api, job_list, context);
310 #else
311             AB_Banking_ExecuteJobs(api, job_list, context);
312 #endif
313             /* Ignore the return value of AB_Banking_ExecuteJobs(), as the job's
314              * status always describes better whether the job was actually
315              * transferred to and accepted by the bank.  See also
316              * https://lists.gnucash.org/pipermail/gnucash-de/2008-September/006389.html
317              */
318 #ifdef AQBANKING6
319             job_status = AB_Transaction_GetStatus(job);
320             if (job_status != AB_Transaction_StatusAccepted
321                 && job_status != AB_Transaction_StatusPending)
322 #else
323             job_status = AB_Job_GetStatus(job);
324             if (job_status != AB_Job_StatusFinished
325                     && job_status != AB_Job_StatusPending)
326 #endif
327             {
328                 successful = FALSE;
329                 if (!gnc_verify_dialog (
330                             GTK_WINDOW (parent), FALSE, "%s",
331                             _("An error occurred while executing the job. Please check "
332                               "the log window for the exact error message.\n"
333                               "\n"
334                               "Do you want to enter the job again?")))
335                 {
336                     aborted = TRUE;
337                 }
338             }
339             else
340             {
341                 successful = TRUE;
342             }
343 
344             if (successful)
345             {
346                 /* Import the results, awaiting nothing */
347                 ieci = gnc_ab_import_context(context, 0, FALSE, NULL, parent);
348             }
349         }
350         /* Simply ignore any other case */
351 
352 repeat:
353         /* Clean up */
354         if (gnc_trans && !successful)
355         {
356             xaccTransBeginEdit(gnc_trans);
357             xaccTransDestroy(gnc_trans);
358             xaccTransCommitEdit(gnc_trans);
359             gnc_trans = NULL;
360         }
361         if (ieci)
362             g_free(ieci);
363         if (context)
364             AB_ImExporterContext_free(context);
365         if (job_list)
366         {
367 #ifdef AQBANKING6
368             AB_Transaction_List2_free(job_list);
369 #else
370             AB_Job_List2_free(job_list);
371 #endif
372             job_list = NULL;
373         }
374         if (job)
375         {
376 #ifdef AQBANKING6
377             AB_Transaction_free(job);
378 #else
379             AB_Job_free(job);
380 #endif
381             job = NULL;
382         }
383         if (gui)
384         {
385             gnc_GWEN_Gui_release(gui);
386             gui = NULL;
387         }
388 
389     }
390     while (!successful && !aborted);
391 
392 cleanup:
393     if (td)
394         gnc_ab_trans_dialog_free(td);
395 #ifndef AQBANKING6
396     if (online)
397         AB_Banking_OnlineFini(api);
398 #endif
399     gnc_AB_BANKING_fini(api);
400 }
401