GnuCash  5.6-150-g038405b370+
gnc-ab-transfer.c
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 
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 txn_created_cb(Transaction *trans, gpointer user_data);
51 
52 #if (AQBANKING_VERSION_INT >= 60400)
53 static void
54 save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates,
55  gboolean dont_ask)
56 {
57  g_return_if_fail(gnc_acc);
58  if (dont_ask || gnc_verify_dialog (
59  GTK_WINDOW (parent), FALSE, "%s",
60  _("You have changed the list of online transfer templates, "
61  "but you cancelled the transfer dialog. "
62  "Do you nevertheless want to store the changes?")))
63  {
64  gnc_ab_set_book_template_list(gnc_account_get_book(gnc_acc), templates);
65  }
66 }
67 #endif
68 
69 static void
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
80 gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc,
81  GncABTransType trans_type)
82 {
83  AB_BANKING *api;
84  GNC_AB_ACCOUNT_SPEC *ab_acc;
85  GList *templates = NULL;
86  GncABTransDialog *td = NULL;
87  gboolean successful = FALSE;
88  gboolean aborted = FALSE;
89 
90  g_return_if_fail(parent && gnc_acc);
91 
92  /* Get the API */
93  api = gnc_AB_BANKING_new();
94  if (!api)
95  {
96  g_warning("gnc_ab_maketrans: Couldn't get AqBanking API");
97  return;
98  }
99  /* Get the AqBanking Account */
100  ab_acc = gnc_ab_get_ab_account(api, gnc_acc);
101  if (!ab_acc)
102  {
103  g_warning("gnc_ab_gettrans: No AqBanking account found");
104  gnc_error_dialog (GTK_WINDOW (parent), _("No valid online banking account assigned."));
105  goto cleanup;
106  }
107 
108 #if (AQBANKING_VERSION_INT >= 60400)
109  if (trans_type == SEPA_INTERNAL_TRANSFER)
110  {
111  /* Generate list of template transactions from the reference accounts*/
112  templates = gnc_ab_trans_templ_list_new_from_ref_accounts (ab_acc);
113  if (templates == NULL)
114  {
115  g_warning ("gnc_ab_gettrans: No reference accounts found");
116  gnc_error_dialog (GTK_WINDOW (parent), _("No reference accounts found."));
117  goto cleanup;
118  }
119  }
120  else
121 #endif
122  {
123  /* Get list of template transactions */
125  gnc_account_get_book(gnc_acc));
126  }
127 
128  /* Create new ABTransDialog */
129  td = gnc_ab_trans_dialog_new(parent, ab_acc,
131  trans_type, templates);
132  templates = NULL;
133 
134  /* Repeat until AqBanking action was successful or user pressed cancel */
135  do
136  {
137  GncGWENGui *gui = NULL;
138  gint result;
139  const AB_TRANSACTION *ab_trans;
140  GNC_AB_JOB *job = NULL;
141  GNC_AB_JOB_LIST2 *job_list = NULL;
142  XferDialog *xfer_dialog = NULL;
143  gnc_numeric amount;
144  gchar *description;
145  gchar *memo;
146  Transaction *gnc_trans = NULL;
147  AB_IMEXPORTER_CONTEXT *context = NULL;
148  GNC_AB_JOB_STATUS job_status;
149  GncABImExContextImport *ieci = NULL;
150 
151 
152  /* Let the user enter the values */
154 
155 #if (AQBANKING_VERSION_INT >= 60400)
156  gboolean changed;
157  templates = gnc_ab_trans_dialog_get_templ(td, &changed);
158  if (trans_type != SEPA_INTERNAL_TRANSFER && changed)
159  {
160  /* Save the templates */
161  save_templates(parent, gnc_acc, templates,
162  (result == GNC_RESPONSE_NOW));
163  }
164  g_list_free(templates);
165  templates = NULL;
166 #endif
167 
168  if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER)
169  {
170  aborted = TRUE;
171  goto repeat;
172  }
173 
174  /* Get a job and enqueue it */
175  ab_trans = gnc_ab_trans_dialog_get_ab_trans(td);
176  job = gnc_ab_trans_dialog_get_job(td);
177  if (!job || AB_AccountSpec_GetTransactionLimitsForCommand(ab_acc, AB_Transaction_GetCommand(job))==NULL)
178  {
179  if (!gnc_verify_dialog (
180  GTK_WINDOW (parent), FALSE, "%s",
181  _("The backend found an error during the preparation "
182  "of the job. It is not possible to execute this job.\n"
183  "\n"
184  "Most probable the bank does not support your chosen "
185  "job or your Online Banking account does not have the permission "
186  "to execute this job. More error messages might be "
187  "visible on your console log.\n"
188  "\n"
189  "Do you want to enter the job again?")))
190  aborted = TRUE;
191  goto repeat;
192  }
193  job_list = AB_Transaction_List2_new();
194  AB_Transaction_List2_PushBack(job_list, job);
195  /* Setup a Transfer Dialog for the GnuCash transaction */
196  xfer_dialog = gnc_xfer_dialog(gnc_ab_trans_dialog_get_parent(td),
197  gnc_acc);
198  switch (trans_type)
199  {
200  case SINGLE_DEBITNOTE:
201  gnc_xfer_dialog_set_title(
202  xfer_dialog, _("Online Banking Direct Debit Note"));
203  gnc_xfer_dialog_lock_to_account_tree(xfer_dialog);
204  break;
205  case SINGLE_INTERNAL_TRANSFER:
206  gnc_xfer_dialog_set_title(
207  xfer_dialog, _("Online Banking Bank-Internal Transfer"));
208  gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
209  break;
210  case SEPA_TRANSFER:
211  gnc_xfer_dialog_set_title(
212  xfer_dialog, _("Online Banking European (SEPA) Transfer"));
213  gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
214  break;
215 #if (AQBANKING_VERSION_INT >= 60400)
216  case SEPA_INTERNAL_TRANSFER:
217  gnc_xfer_dialog_set_title (
218  xfer_dialog, _("Online Banking European (SEPA) Internal Transfer"));
219  gnc_xfer_dialog_lock_from_account_tree (xfer_dialog);
220  break;
221 #endif
222  case SEPA_DEBITNOTE:
223  gnc_xfer_dialog_set_title(
224  xfer_dialog, _("Online Banking European (SEPA) Debit Note"));
225  gnc_xfer_dialog_lock_to_account_tree(xfer_dialog);
226  break;
227  case SINGLE_TRANSFER:
228  default:
229  gnc_xfer_dialog_set_title(
230  xfer_dialog, _("Online Banking Transaction"));
231  gnc_xfer_dialog_lock_from_account_tree(xfer_dialog);
232  }
233  gnc_xfer_dialog_set_to_show_button_active(xfer_dialog, TRUE);
234 
235  amount = double_to_gnc_numeric(
236  AB_Value_GetValueAsDouble(AB_Transaction_GetValue(ab_trans)),
239  gnc_xfer_dialog_set_amount(xfer_dialog, amount);
240  gnc_xfer_dialog_set_amount_sensitive(xfer_dialog, FALSE);
241  gnc_xfer_dialog_set_date_sensitive(xfer_dialog, FALSE);
242 
243  /* OFX doesn't do transfers. */
244  description = gnc_ab_description_to_gnc(ab_trans, FALSE);
245  gnc_xfer_dialog_set_description(xfer_dialog, description);
246  g_free(description);
247 
248  memo = gnc_ab_memo_to_gnc(ab_trans);
249  gnc_xfer_dialog_set_memo(xfer_dialog, memo);
250  g_free(memo);
251 
252  gnc_xfer_dialog_set_txn_cb(xfer_dialog, txn_created_cb, &gnc_trans);
253 
254  /* And run it */
255  successful = gnc_xfer_dialog_run_until_done(xfer_dialog);
256 
257  /* On cancel, go back to the AB transaction dialog */
258  if (!successful || !gnc_trans)
259  {
260  successful = FALSE;
261  goto repeat;
262  }
263 
264  if (result == GNC_RESPONSE_NOW)
265  {
266  /* Create a context to store possible results */
267  context = AB_ImExporterContext_new();
268 
269  gui = gnc_GWEN_Gui_get(parent);
270  if (!gui)
271  {
272  g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI");
273  aborted = TRUE;
274  goto repeat;
275  }
276 
277  /* Finally, execute the job */
278  AB_Banking_SendCommands(api, job_list, context);
279  /* Ignore the return value of AB_Banking_ExecuteJobs(), as the job's
280  * status always describes better whether the job was actually
281  * transferred to and accepted by the bank. See also
282  * https://lists.gnucash.org/pipermail/gnucash-de/2008-September/006389.html
283  */
284  job_status = AB_Transaction_GetStatus(job);
285  if (job_status != AB_Transaction_StatusAccepted
286  && job_status != AB_Transaction_StatusPending)
287  {
288  successful = FALSE;
289  if (!gnc_verify_dialog (
290  GTK_WINDOW (parent), FALSE, "%s",
291  _("An error occurred while executing the job. Please check "
292  "the log window for the exact error message.\n"
293  "\n"
294  "Do you want to enter the job again?")))
295  {
296  aborted = TRUE;
297  }
298  }
299  else
300  {
301  successful = TRUE;
302  }
303 
304  if (successful)
305  {
306  /* Import the results, awaiting nothing */
307  ieci = gnc_ab_import_context(context, 0, FALSE, NULL, parent);
308  }
309  }
310  /* Simply ignore any other case */
311 
312 repeat:
313  /* Clean up */
314  if (gnc_trans && !successful)
315  {
316  xaccTransBeginEdit(gnc_trans);
317  xaccTransDestroy(gnc_trans);
318  xaccTransCommitEdit(gnc_trans);
319  gnc_trans = NULL;
320  }
321  if (ieci)
322  g_free(ieci);
323  if (context)
324  AB_ImExporterContext_free(context);
325  if (job_list)
326  {
327  AB_Transaction_List2_free(job_list);
328  job_list = NULL;
329  }
330  if (job)
331  {
332  AB_Transaction_free(job);
333  job = NULL;
334  }
335  if (gui)
336  {
338  gui = NULL;
339  }
340 
341  }
342  while (!successful && !aborted);
343 
344 cleanup:
345  if (td)
347  gnc_AB_BANKING_fini(api);
348 }
gnc_numeric double_to_gnc_numeric(double in, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2696
STRUCTS.
GncABTransDialog * gnc_ab_trans_dialog_new(GtkWidget *parent, GNC_AB_ACCOUNT_SPEC *ab_acc, gint commodity_scu, GncABTransType trans_type, GList *templates)
Create a new AqBanking transfer dialog.
GNC_AB_JOB * gnc_ab_trans_dialog_get_job(const GncABTransDialog *td)
Receive the Aqbanking job filled by the dialog.
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
GncGWENGui * gnc_GWEN_Gui_get(GtkWidget *parent)
When called for the first time, create a unique GncGWENGui object featuring a GWEN_GUI with all neces...
Definition: gnc-gwen-gui.c:245
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
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
Dialog for AqBanking transaction data.
void gnc_GWEN_Gui_release(GncGWENGui *gui)
Currently a no-op.
Definition: gnc-gwen-gui.c:280
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 xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
void gnc_ab_set_book_template_list(QofBook *b, GList *template_list)
Set the GList of kvp_frames of template transactions in the Book b to template_list.
gint gnc_AB_BANKING_fini(AB_BANKING *api)
Finish the AB_BANKING api.
Definition: gnc-ab-utils.c:226
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.
void gnc_ab_trans_dialog_free(GncABTransDialog *td)
Free a Aqbanking transfer dialog.
GList * gnc_ab_trans_templ_list_new_from_book(QofBook *b)
Obtain the list of QofTemplates saved in a Book.
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
const AB_TRANSACTION * gnc_ab_trans_dialog_get_ab_trans(const GncABTransDialog *td)
Receive the Aqbanking Transaction filled by the dialog.
GtkWidget * gnc_ab_trans_dialog_get_parent(const GncABTransDialog *td)
Retrieve the widget used as parent.
AqBanking KVP handling.
GUI callbacks for AqBanking.
API for Transactions and Splits (journal entries)
gint gnc_ab_trans_dialog_run_until_ok(GncABTransDialog *td)
Run the Aqbanking transfer dialog until correct values where entered or the user cancelled the dialog...
AqBanking utility functions.
void gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc, GncABTransType trans_type)
Create SEPA transfers.