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