GnuCash  5.6-150-g038405b370+
dialog-payment.c
1 /*
2  * dialog-payment.c -- Dialog for payment entry
3  * Copyright (C) 2002,2006 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  * Copyright (c) 2006 David Hampton <hampton@employees.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, contact:
19  *
20  * Free Software Foundation Voice: +1-617-542-5942
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22  * Boston, MA 02110-1301, USA gnu@gnu.org
23  */
24 
25 #include <config.h>
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 
30 #include "dialog-utils.h"
31 #include "gnc-component-manager.h"
32 #include "gnc-ui.h"
33 #include "gnc-gui-query.h"
34 #include "gnc-ui-util.h"
35 #include <gnc-glib-utils.h>
36 #include "qof.h"
37 #include "gnc-date.h"
38 #include "gnc-date-edit.h"
39 #include "gnc-amount-edit.h"
40 #include "gnc-gtk-utils.h"
41 #include "gnc-prefs.h"
42 #include "gnc-tree-view-account.h"
43 #include "tree-view-utils.h"
44 #include "Transaction.h"
45 #include "Account.h"
46 #include "gncOwner.h"
47 #include "engine-helpers.h"
48 
49 #include "gncInvoice.h"
50 
51 #include "dialog-payment.h"
52 #include "business-gnome-utils.h"
53 
54 #include "dialog-transfer.h"
55 #include "dialog-print-check.h"
56 #include "gnc-general-search.h"
57 #include <qoflog.h>
58 
59 static const QofLogModule log_module = G_LOG_DOMAIN;
60 
61 #define DIALOG_PAYMENT_CM_CLASS "payment-dialog"
62 #define GNC_PREFS_GROUP "dialogs.process-payment"
63 
64 typedef enum
65 {
66  COL_OWNER_TYPE_NAME ,
67  COL_OWNER_TYPE_NUM ,
68 } OwnerTypeCols;
69 
70 typedef struct
71 {
72  GNCLot * lot;
73  gnc_numeric amount;
75 
76 typedef struct
77 {
78  GncOwner owner;
79  Transaction * txn;
80  Account * post_acct;
81  GList * lots;
83 
85 {
86  GtkWidget * dialog;
87 
88  GtkWidget * payment_warning;
89  GtkWidget * conflict_message;
90  GtkWidget * ok_button;
91  GtkWidget * num_entry;
92  GtkWidget * memo_entry;
93  GtkWidget * post_combo;
94  GtkWidget * owner_box;
95  GtkWidget * owner_type_combo;
96  GtkWidget * owner_choice;
97  GtkWidget * amount_debit_edit;
98  GtkWidget * amount_credit_edit;
99  GtkWidget * amount_payment_box;
100  GtkWidget * amount_refund_box;
101  GtkWidget * date_edit;
102  GtkWidget * acct_tree;
103  GtkWidget * docs_list_tree_view;
104  GtkWidget * commodity_label;
105  GtkWidget * print_check;
106 
107  gint component_id;
108  QofBook * book;
109  GncOwner owner;
110  GncOwnerType owner_type;
111  Account * post_acct;
112  Account * xfer_acct;
113  gnc_numeric amount_tot;
114  GList * acct_types;
115  GList * acct_commodities;
116 
117  InitialPaymentInfo *tx_info;
118  gboolean print_check_state;
119 };
120 
121 void gnc_ui_payment_window_set_num (PaymentWindow *pw, const char* num)
122 {
123  g_assert(pw);
124  gtk_entry_set_text(GTK_ENTRY (pw->num_entry), num);
125 }
126 void gnc_ui_payment_window_set_memo (PaymentWindow *pw, const char* memo)
127 {
128  g_assert(pw);
129  gtk_entry_set_text(GTK_ENTRY (pw->memo_entry), memo);
130 }
131 void gnc_ui_payment_window_set_date (PaymentWindow *pw, const GDate *date)
132 {
133  g_assert(pw);
134  g_assert(date);
135  gnc_date_edit_set_gdate (GNC_DATE_EDIT (pw->date_edit), date);
136 }
137 void gnc_ui_payment_window_set_amount (PaymentWindow *pw, gnc_numeric amount)
138 {
139  g_assert(pw);
140 
141  /* Debits are negative, credits are positive */
142  if (gnc_numeric_positive_p (amount))
143  {
144  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_credit_edit),
145  amount);
146  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_debit_edit),
147  gnc_numeric_zero ());
148  }
149  else
150  {
151  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_debit_edit),
152  gnc_numeric_neg (amount));
153  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_credit_edit),
154  gnc_numeric_zero ());
155  }
156 
157 }
158 
159 static void gnc_ui_payment_window_set_commodity (PaymentWindow *pw, const Account* account)
160 {
161  gchar *comm_string;
162  gnc_commodity *comm;
163 
164  g_assert(pw);
165  g_assert(account);
166 
167  comm = xaccAccountGetCommodity (account);
168  comm_string = g_strconcat ("(", gnc_commodity_get_nice_symbol (comm), ")", NULL);
169  gtk_label_set_text (GTK_LABEL(pw->commodity_label), comm_string);
170  g_free (comm_string);
171 }
172 
173 void gnc_ui_payment_window_set_postaccount (PaymentWindow *pw, const Account* account)
174 {
175  g_assert(pw);
176  g_assert(account);
177  {
178  gchar *acct_string = gnc_account_get_full_name (account);
179  gnc_cbwe_set_by_string(GTK_COMBO_BOX(pw->post_combo), acct_string);
180  g_free(acct_string);
181  }
182 
183  gnc_ui_payment_window_set_commodity (pw, account);
184 }
185 
186 void gnc_ui_payment_window_set_xferaccount (PaymentWindow *pw, const Account* account)
187 {
188  g_assert(pw);
189  g_assert(account);
190  gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
191  (Account*)account);
192 }
193 
194 static gboolean gnc_payment_dialog_has_pre_existing_txn(const PaymentWindow* pw)
195 {
196  return pw->tx_info->txn != NULL;
197 }
198 int gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data);
199 int gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data);
200 void gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data);
201 void gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data);
202 void gnc_payment_ok_cb (GtkWidget *widget, gpointer data);
203 void gnc_payment_cancel_cb (GtkWidget *widget, gpointer data);
204 void gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data);
205 void gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
206  GtkTreeViewColumn *column, PaymentWindow *pw);
207 void gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
208  PaymentWindow *pw);
209 void gnc_payment_activate_amount_cb (GtkWidget *widget, PaymentWindow *pw);
210 void gnc_payment_window_fill_docs_list (PaymentWindow *pw);
211 
212 
213 static void
214 gnc_payment_window_refresh_handler (G_GNUC_UNUSED GHashTable *changes, gpointer data)
215 {
216  PaymentWindow *pw = data;
217 
218  gnc_payment_window_fill_docs_list (pw);
219  pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, NULL);
220 }
221 
222 static gboolean
223 gnc_payment_window_check_payment (PaymentWindow *pw)
224 {
225  const char *conflict_msg = NULL;
226  gnc_numeric amount_deb, amount_cred;
227  gboolean enable_xfer_acct = TRUE;
228  gboolean allow_payment = TRUE;
229  GtkTreeSelection *selection;
230  gint c_result, d_result;
231 
232  if (!pw)
233  return FALSE;
234 
235  /* Verify the "post" account */
236  if (!pw->post_acct)
237  {
238  conflict_msg = _("You must enter a valid account name for posting.");
239  allow_payment = FALSE;
240  goto update_cleanup;
241  }
242 
243  /* Verify the user has selected an owner */
244  gnc_owner_get_owner (pw->owner_choice, &(pw->owner));
245  if (!gncOwnerIsValid(&pw->owner))
246  {
247  conflict_msg = _("You must select a company for payment processing.");
248  allow_payment = FALSE;
249  goto update_cleanup;
250  }
251 
252  /* Verify the credit / debit amounts are valid */
253  d_result = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(pw->amount_debit_edit),
254  &amount_deb, FALSE, NULL);
255 
256  c_result = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(pw->amount_credit_edit),
257  &amount_cred, FALSE, NULL);
258 
259  if ((d_result == 1) || (c_result == 1))
260  {
261  conflict_msg = _("There is a problem with the Payment or Refund amount.");
262  allow_payment = FALSE;
263  goto update_cleanup;
264  }
265 
266  /* Test the total amount */
267  pw->amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
269  xaccAccountGetCommodity (pw->post_acct)),
271 
272  if (gnc_numeric_check (pw->amount_tot) || gnc_numeric_zero_p (pw->amount_tot))
273  {
274  enable_xfer_acct = FALSE;
275  }
276  else
277  {
278  /* Verify the user has selected a transfer account */
279  pw->xfer_acct = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(pw->acct_tree));
280  if (!pw->xfer_acct)
281  {
282  conflict_msg = _("You must select a transfer account from the account tree.");
283  allow_payment = FALSE;
284  goto update_cleanup;
285  }
286  }
287 
288  /* this last test checks whether documents were selected. if none,
289  emit warning but still allow as an unattached payment. */
290  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
291  if (gtk_tree_selection_count_selected_rows (selection) == 0)
292  {
293  conflict_msg = _("No documents were selected to assign this payment to. This may create an unattached payment.");
294  allow_payment = TRUE;
295  }
296 
297 
298 update_cleanup:
299  gtk_widget_set_sensitive (pw->acct_tree, enable_xfer_acct);
300 
301  /* Disable "Print Check" widget if amount is zero but save current
302  state to restore when the widget is re-enabled */
303  if (gtk_widget_is_sensitive (pw->print_check))
304  pw->print_check_state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(pw->print_check));
305  if (!enable_xfer_acct)
306  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(pw->print_check), FALSE);
307  gtk_widget_set_sensitive (pw->print_check, enable_xfer_acct);
308  if (gtk_widget_is_sensitive (pw->print_check))
309  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(pw->print_check), pw->print_check_state);
310 
311  /* Check if there are issues preventing a successful payment */
312  gtk_label_set_text (GTK_LABEL(pw->conflict_message), conflict_msg);
313  gtk_widget_set_sensitive (pw->ok_button, allow_payment);
314  if (conflict_msg)
315  {
316  gtk_widget_show (pw->payment_warning);
317  }
318  else
319  {
320  gtk_widget_hide (pw->payment_warning);
321  }
322 
323  return allow_payment;
324 }
325 
326 static void
327 gnc_payment_window_close_handler (gpointer data)
328 {
329  PaymentWindow *pw = data;
330 
331  if (!pw) return;
332  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(pw->dialog));
333  gtk_widget_destroy (pw->dialog);
334 }
335 
336 static void
337 calculate_selected_total_helper (GtkTreeModel *model,
338  G_GNUC_UNUSED GtkTreePath *path,
339  GtkTreeIter *iter,
340  gpointer data)
341 {
342  gnc_numeric *subtotal = (gnc_numeric*) data;
343  gnc_numeric cur_val;
344  GNCLot *lot;
345  Account *acct;
346  gnc_commodity *currency;
347 
348  gtk_tree_model_get (model, iter, 5, &lot, -1);
349 
350  /* Find the amount's currency to determine the required precision */
351  acct = gnc_lot_get_account (lot);
352  currency = xaccAccountGetCommodity (acct);
353 
354  cur_val = gnc_lot_get_balance (lot);
355  *subtotal = gnc_numeric_add (*subtotal, cur_val,
357 }
358 
359 static gnc_numeric
360 gnc_payment_dialog_calculate_selected_total (PaymentWindow *pw)
361 {
362  GtkTreeSelection *selection;
363  gnc_numeric val = gnc_numeric_zero();
364 
365  if (!pw->docs_list_tree_view || !GTK_IS_TREE_VIEW(pw->docs_list_tree_view))
366  return gnc_numeric_zero();
367 
368  /* Figure out if anything is set in the current list */
369  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
370 
371  gtk_tree_selection_selected_foreach (selection,
372  calculate_selected_total_helper,
373  (gpointer) &val);
374 
375  return val;
376 }
377 
378 static void
379 gnc_payment_dialog_document_selection_changed (PaymentWindow *pw)
380 {
381  gnc_numeric val;
382 
383  /* Don't change the amount based on the selected documents
384  * in case this payment is from a pre-existing txn
385  */
386  if (gnc_payment_dialog_has_pre_existing_txn (pw))
387  return;
388 
389  /* Set the payment amount in the dialog */
390  val = gnc_payment_dialog_calculate_selected_total (pw);
391  gnc_ui_payment_window_set_amount(pw, val);
392 }
393 
394 static gint
395 _gnc_lotinfo_find_by_lot(PreExistLotInfo *lotinfo_inst, GNCLot *lot_to_find)
396 {
397  if (lotinfo_inst->lot == lot_to_find)
398  return 0;
399  return -1;
400 }
401 
402 static void
403 gnc_payment_dialog_highlight_documents (PaymentWindow *pw)
404 {
405  gboolean selection_changed = FALSE;
406  GtkTreeIter iter;
407  GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view));
408  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
409  gtk_tree_selection_unselect_all (selection);
410 
411  if (gtk_tree_model_get_iter_first (model, &iter))
412  {
413  do
414  {
415  GNCLot *lot;
416  GList *li_node;
417 
418  gtk_tree_model_get (model, &iter, 5, &lot, -1);
419 
420  if (!lot)
421  continue; /* Lot has been deleted behind our back... */
422 
423  li_node = g_list_find_custom (pw->tx_info->lots, lot,
424  (GCompareFunc)_gnc_lotinfo_find_by_lot);
425  if (li_node)
426  {
427  gtk_tree_selection_select_iter (selection, &iter);
428  selection_changed = TRUE;
429  }
430  }
431  while (gtk_tree_model_iter_next (model, &iter));
432  }
433 
434  if (selection_changed)
435  gnc_payment_dialog_document_selection_changed (pw);
436 }
437 
438 
439 void
440 gnc_payment_window_fill_docs_list (PaymentWindow *pw)
441 {
442  GtkListStore *store;
443  GtkTreeSelection *selection;
444  GList *list = NULL, *node;
445 
446  g_return_if_fail (pw->docs_list_tree_view && GTK_IS_TREE_VIEW(pw->docs_list_tree_view));
447 
448  /* Get a list of open lots for this owner and post account */
449  if (pw->owner.owner.undefined && pw->post_acct)
450  list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc,
451  &pw->owner, NULL);
452 
453  /* If pre-existing transaction's post account equals the selected post account
454  * and we have lots for this transaction then compensate the document list for those.
455  * The presence of such lots indicates the pre-existing transaction is an existing payment that
456  * we are about to replace. So we should make sure this existing payment info can be reselected
457  * by the user (within the practical limits of the payment window*) to redo the same
458  * payment again.
459  * If the txn's lots are closed they are ignored by default so we should explicitly readd
460  * them here.
461  * And for all lots in the pre-existing transaction we need to readd the split amount
462  * for that lot or the existing payment values would not be taken into account.
463  * This will happen further below though.
464  *
465  * Finally all this is only relevant if the lot belongs to the same owner...
466  *
467  * * The practical limits are
468  * - The payment dialog can handle only one transfer split. If the pre-existing
469  * transaction has more possible candidates, all but the first will be used
470  * - The payment dialog can't handle AR/AP splits that aren't linked to a lot
471  * in the current post account. Such splits will be ignored as well.
472  * In both cases the user will have been informed before and given the option to abort.
473  */
474  if (pw->tx_info->post_acct == pw->post_acct)
475  for (node = pw->tx_info->lots; node; node = node->next)
476  {
477  PreExistLotInfo *lot_info = node->data;
478  if (gnc_numeric_zero_p (gnc_lot_get_balance (lot_info->lot)))
479  /* The not-zero case will be handled below when the lot is processed as part of the open lots */
480  {
481  GncOwner lotowner;
482  gncOwnerInitUndefined(&lotowner, NULL);
483  if (!gncOwnerGetOwnerFromLot(lot_info->lot, &lotowner))
484  {
485  const GncOwner *owner;
486  const GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot_info->lot);
487  if (invoice)
488  {
489  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
490  gncOwnerCopy (owner, &lotowner);
491  }
492  }
493  if (gncOwnerEqual(&pw->owner, &lotowner))
494  list = g_list_prepend (list, lot_info->lot);
495  }
496  }
497 
498  /* Clear the existing list */
499  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
500  gtk_tree_selection_unselect_all (selection);
501  store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view)));
502  gtk_list_store_clear(store);
503 
504  /* Add the documents and overpayments to the tree view */
505  for (node = list; node; node = node->next)
506  {
507  GNCLot *lot = node->data;
508  GList *li_node;
509  time64 doc_date_time = 0;
510  const gchar *doc_type_str = NULL;
511  const gchar *doc_id_str = NULL;
512  const gchar *doc_deb_str = NULL;
513  const gchar *doc_cred_str = NULL;
514  GtkTreeIter iter;
515  GncInvoice *document;
516  gnc_numeric value;
517  gnc_numeric debit = gnc_numeric_zero();
518  gnc_numeric credit = gnc_numeric_zero();
519 
520  /* Find the lot's document if it exists,
521  * it could also be a prepayment lot. */
522  document = gncInvoiceGetInvoiceFromLot (lot);
523 
524  /* Find the document's date or pre-payment date */
525  if (document)
526  doc_date_time = gncInvoiceGetDatePosted (document);
527  else
528  {
529  /* Calculate the payment date based on the lot splits */
530  Transaction *trans = xaccSplitGetParent (gnc_lot_get_latest_split (lot));
531  if (trans)
532  doc_date_time = xaccTransRetDatePosted (trans);
533  else
534  continue; /* No valid split in this lot, skip it */
535  }
536 
537  /* Find the document type. No type means pre-payment in this case */
538  if (document)
539  {
540  doc_type_str = gncInvoiceGetTypeString (document);
541  }
542  else
543  doc_type_str = _("Pre-Payment");
544 
545  /* Find the document id. Empty for pre-payments. */
546  if (document)
547  {
548  doc_id_str = gncInvoiceGetID (document);
549  }
550 
551  /* Find the debit/credit amount.
552  * Invoices/vendor credit notes are debit (increasing the balance)
553  * Customer credit notes/bills are credit (decreasing the balance)
554  * Pre-payments are debit or credit depending on their sign
555  */
556  value = gnc_lot_get_balance (lot);
557 
558  /* If this lot is linked to the pre-existing transaction, compensate
559  * its amount so the same pre-existing transaction can be reselected bye the user
560  * (within applicable limits)
561  */
562  li_node = g_list_find_custom (pw->tx_info->lots, lot,
563  (GCompareFunc)_gnc_lotinfo_find_by_lot);
564  if (li_node)
565  {
566  PreExistLotInfo *lot_info = li_node->data;
567  value = gnc_numeric_sub(value, lot_info->amount,
570  }
571 
572  if (gnc_numeric_zero_p (value))
573  /* If the lot's balance is 0 after the above compensation, skip this lot */
574  continue;
575  else if (gnc_numeric_positive_p (value))
576  debit = value;
577  else
578  credit = gnc_numeric_neg (value);
579 
580 
581  /* Only display non-zero debits/credits */
582  if (!gnc_numeric_zero_p (debit))
583  doc_deb_str = xaccPrintAmount (debit, gnc_default_print_info (FALSE));
584  if (!gnc_numeric_zero_p (credit))
585  doc_cred_str = xaccPrintAmount (credit, gnc_default_print_info (FALSE));
586 
587  gtk_list_store_append (store, &iter);
588  gtk_list_store_set (store, &iter,
589  0, doc_date_time,
590  1, doc_id_str,
591  2, doc_type_str,
592  3, doc_deb_str,
593  4, doc_cred_str,
594  5, (gpointer)lot,
595  -1);
596 
597  }
598 
599  g_list_free (list);
600 
601  /* Highlight the preset invoice if it's in the new list */
602  gnc_payment_dialog_highlight_documents (pw);
603 }
604 
605 static void
606 gnc_payment_dialog_post_to_changed (PaymentWindow *pw)
607 {
608  gnc_payment_window_fill_docs_list (pw);
609 }
610 
611 static void
612 gnc_payment_dialog_owner_changed (PaymentWindow *pw)
613 {
614  GncOwner *owner = &pw->owner;
615 
616  /* refresh the post and acc available accounts, but cleanup first */
617  if (pw->acct_types)
618  {
619  g_list_free(pw->acct_types);
620  pw->acct_types = NULL;
621  }
622 
623  if (pw->acct_commodities)
624  {
625  g_list_free(pw->acct_commodities);
626  pw->acct_commodities = NULL;
627  }
628 
629  pw->acct_types = gncOwnerGetAccountTypesList(owner);
630  if (gncOwnerIsValid(owner))
631  pw->acct_commodities = gncOwnerGetCommoditiesList (owner);
632 
633  pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, NULL);
634  if (gncOwnerEqual(&pw->owner, &pw->tx_info->owner) && pw->tx_info->post_acct)
635  {
636  pw->post_acct = pw->tx_info->post_acct;
637  gnc_ui_payment_window_set_postaccount (pw, pw->post_acct);
638  }
639  gnc_payment_dialog_post_to_changed (pw);
640 
641  if (pw->post_acct)
642  gnc_ui_payment_window_set_commodity (pw, pw->post_acct);
643 
644  /* Set the last-used transfer account, but only if we didn't
645  * create this dialog from a pre-existing transaction. */
646  if (!gnc_payment_dialog_has_pre_existing_txn(pw))
647  {
648  GncGUID *guid = NULL;
649  Account *last_acct = NULL;
650 
651  if (gncOwnerIsValid(owner))
653  "payment-last-account", &guid,
654  NULL);
655  last_acct = xaccAccountLookup(guid, pw->book);
656  guid_free (guid);
657  if (last_acct)
658  gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
659  last_acct);
660  }
661 }
662 
663 
664 static void
665 gnc_payment_dialog_owner_type_changed (PaymentWindow *pw)
666 {
667  GtkWidget *debit_box, *credit_box;
668 
669  /* Some terminology:
670  * Invoices are paid, credit notes are refunded.
671  * A customer payment is a credit action, paying a vendor is debit
672  *
673  * So depending on the owner the payment amount should be considered
674  * credit (customer) or debit (vendor/employee) and refunds should be
675  * considered debit (customer) or credit (vendor/employee).
676  * For visual consistency, the dialog box will always show a payment and
677  * a refund field. Internally they are treated as credit or debit depending
678  * on the owner type.
679  */
680  if (pw->owner_type == GNC_OWNER_CUSTOMER)
681  {
682  debit_box = pw->amount_refund_box;
683  credit_box = pw->amount_payment_box;
684  }
685  else
686  {
687  debit_box = pw->amount_payment_box;
688  credit_box = pw->amount_refund_box;
689  }
690 
691  g_object_ref (G_OBJECT (pw->amount_debit_edit));
692  g_object_ref (G_OBJECT (pw->amount_credit_edit));
693 
694  if (gtk_widget_is_ancestor(pw->amount_debit_edit, credit_box))
695  gtk_container_remove (GTK_CONTAINER (credit_box), pw->amount_debit_edit);
696  if (gtk_widget_is_ancestor(pw->amount_credit_edit, debit_box))
697  gtk_container_remove (GTK_CONTAINER (debit_box), pw->amount_credit_edit);
698 
699  if (!gtk_widget_is_ancestor(pw->amount_debit_edit, debit_box))
700  gtk_box_pack_start (GTK_BOX (debit_box), pw->amount_debit_edit, TRUE, TRUE, 0);
701  if (!gtk_widget_is_ancestor(pw->amount_credit_edit, credit_box))
702  gtk_box_pack_start (GTK_BOX (credit_box), pw->amount_credit_edit, TRUE, TRUE, 0);
703 
704  g_object_unref (G_OBJECT (pw->amount_debit_edit));
705  g_object_unref (G_OBJECT (pw->amount_credit_edit));
706 
707  /* Redo the owner_choice widget */
708  if (pw->owner_choice)
709  gtk_widget_destroy(pw->owner_choice);
710  pw->owner_choice = gnc_owner_select_create (NULL, pw->owner_box, pw->book, &pw->owner);
711  gtk_widget_show (pw->owner_choice);
712  gnc_payment_dialog_owner_changed (pw);
713 
714  g_signal_connect (G_OBJECT (pw->owner_choice), "changed",
715  G_CALLBACK (gnc_payment_dialog_owner_changed_cb), pw);
716 }
717 
718 static void
719 gnc_payment_dialog_remember_account (PaymentWindow *pw, Account *acc)
720 {
721  QofInstance *owner = qofOwnerGetOwner (&pw->owner);
722  const GncGUID *guid;
723 
724  if (!acc) return;
725 
726  guid = xaccAccountGetGUID(acc);
727  qof_begin_edit (owner);
728  qof_instance_set (owner,
729  "payment-last-account", guid,
730  NULL);
731  qof_commit_edit (owner);
732 }
733 
734 
735 static void
736 gnc_payment_update_style_classes (PaymentWindow *pw)
737 {
738  GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(pw->dialog));
739  const gchar *style_label = NULL;
740 
741  if (gtk_style_context_has_class (stylectxt, "gnc-class-customers"))
742  gtk_style_context_remove_class (stylectxt, "gnc-class-customers");
743 
744  if (gtk_style_context_has_class (stylectxt, "gnc-class-vendors"))
745  gtk_style_context_remove_class (stylectxt, "gnc-class-vendors");
746 
747  if (gtk_style_context_has_class (stylectxt, "gnc-class-employees"))
748  gtk_style_context_remove_class (stylectxt, "gnc-class-employees");
749 
750  switch (pw->owner_type)
751  {
752  case GNC_OWNER_CUSTOMER:
753  style_label = "gnc-class-customers";
754  break;
755  case GNC_OWNER_VENDOR:
756  style_label = "gnc-class-vendors";
757  break;
758  case GNC_OWNER_EMPLOYEE:
759  style_label = "gnc-class-employees";
760  break;
761  default:
762  style_label = "gnc-class-unknown";
763  break;
764  }
765  // Set a secondary style context for this page so it can be easily manipulated with css
766  gtk_style_context_add_class (stylectxt, style_label);
767 }
768 
769 static void
770 gnc_payment_set_owner_type (PaymentWindow *pw, GncOwnerType owner_type)
771 {
772  gboolean valid;
773  GtkTreeModel *store;
774  GtkTreeIter iter;
775 
776  switch (owner_type)
777  {
778  case GNC_OWNER_CUSTOMER:
779  case GNC_OWNER_EMPLOYEE:
780  case GNC_OWNER_VENDOR:
781  pw->owner_type = owner_type;
782  break;
783  default:
784  pw->owner_type = GNC_OWNER_CUSTOMER;
785  }
786 
787  store = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
788  valid = gtk_tree_model_get_iter_first (store, &iter);
789  while (valid)
790  {
791  GncOwnerType owner_type;
792  gtk_tree_model_get (store, &iter, COL_OWNER_TYPE_NUM, &owner_type, -1);
793  if (owner_type == pw->owner_type)
794  {
795  gtk_combo_box_set_active_iter (GTK_COMBO_BOX(pw->owner_type_combo), &iter);
796  break;
797  }
798  valid = gtk_tree_model_iter_next (store, &iter);
799  }
800  gnc_payment_update_style_classes (pw);
801 
802  gnc_payment_dialog_owner_type_changed (pw);
803 }
804 
805 int
806 gnc_payment_dialog_owner_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
807 {
808  PaymentWindow *pw = data;
809  GncOwner owner;
810 
811  if (!pw) return FALSE;
812 
813  gncOwnerCopy (&(pw->owner), &owner);
814  gnc_owner_get_owner (pw->owner_choice, &owner);
815 
816  /* If this owner really changed, then reset ourselves */
817  if (!gncOwnerEqual (&owner, &(pw->owner)))
818  {
819  gncOwnerCopy (&owner, &(pw->owner));
820  gnc_payment_dialog_owner_changed(pw);
821  }
822 
823  /* Reflect if the payment could complete now */
824  gnc_payment_window_check_payment (pw);
825 
826  return FALSE;
827 }
828 
829 static int
830 gnc_payment_dialog_owner_type_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
831 {
832  PaymentWindow *pw = data;
833  GtkTreeIter iter;
834  GtkTreeModel *model;
835  GncOwnerType owner_type;
836 
837  if (!pw) return FALSE;
838 
839  gtk_combo_box_get_active_iter (GTK_COMBO_BOX(pw->owner_type_combo), &iter);
840  model = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
841  gtk_tree_model_get (model, &iter, COL_OWNER_TYPE_NUM, &owner_type, -1);
842 
843  if (owner_type != pw->owner_type)
844  {
845  pw->owner_type = owner_type;
846 
847  /* If type changed, the currently selected owner can't be valid any more
848  * If the initial owner is of the new owner_type, we propose that one
849  * otherwise we just reset the owner
850  */
851  if (gncOwnerGetType (&pw->tx_info->owner) == pw->owner_type)
852  gncOwnerCopy (&pw->tx_info->owner, &pw->owner);
853  else
854  {
855  switch (pw->owner_type)
856  {
857  case GNC_OWNER_VENDOR:
858  gncOwnerInitVendor (&pw->owner, NULL);
859  break;
860  case GNC_OWNER_EMPLOYEE:
861  gncOwnerInitEmployee (&pw->owner, NULL);
862  break;
863  default:
864  gncOwnerInitCustomer (&pw->owner, NULL);
865  }
866 
867  }
868 
869  gnc_payment_dialog_owner_type_changed (pw);
870  }
871 
872  /* Reflect if the payment could complete now */
873  gnc_payment_window_check_payment (pw);
874 
875  return FALSE;
876 }
877 
878 void
879 gnc_payment_dialog_document_selection_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
880 {
881  PaymentWindow *pw = data;
882 
883  if (!pw) return;
884 
885  gnc_payment_dialog_document_selection_changed (pw);
886 
887  /* Reflect if the payment could complete now */
888  gnc_payment_window_check_payment (pw);
889 }
890 
891 void
892 gnc_payment_dialog_xfer_acct_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
893 {
894  PaymentWindow *pw = data;
895 
896  if (!pw) return;
897 
898  /* Reflect if the payment could complete now */
899  gnc_payment_window_check_payment (pw);
900 }
901 
902 int
903 gnc_payment_dialog_post_to_changed_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
904 {
905  PaymentWindow *pw = data;
906  Account *post_acct;
907 
908  if (!pw) return FALSE;
909 
910  post_acct = gnc_account_select_combo_get_active (pw->post_combo);
911 
912  /* If this post account really changed, then reset ourselves */
913  if (post_acct != pw->post_acct)
914  {
915  pw->post_acct = post_acct;
916  gnc_payment_dialog_post_to_changed(pw);
917  }
918  else
919  gnc_payment_dialog_highlight_documents (pw);
920 
921  /* Reflect if the payment could complete now */
922  gnc_payment_window_check_payment (pw);
923 
924  return FALSE;
925 }
926 
927 /*
928  * This helper function is called once for each row in the tree view
929  * that is currently selected. Its task is to add the corresponding
930  * lot to the end of a glist.
931  */
932 static void
933 get_selected_lots (GtkTreeModel *model,
934  G_GNUC_UNUSED GtkTreePath *path,
935  GtkTreeIter *iter,
936  gpointer data)
937 {
938  GList **return_list = data;
939  GNCLot *lot;
940 
941  gtk_tree_model_get (model, iter, 5, &lot, -1);
942 
943  if (lot)
944  *return_list = g_list_insert_sorted (*return_list, lot, (GCompareFunc)gncOwnerLotsSortFunc);
945 }
946 
947 void
948 gnc_payment_ok_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
949 {
950  PaymentWindow *pw = data;
951  const char *text = NULL;
952 
953  if (!pw)
954  return;
955 
956  /* The gnc_payment_window_check_payment function
957  * ensures we have valid owner, post account, transfer account
958  * and amount so we can proceed with the payment.
959  * Note: make sure it's called before all entry points to this function !
960  */
961 
962  /* We're on our way out, stop watching for object changes that could
963  * trigger a gui refresh. Without this the gui suspend/resume
964  * pair could still trigger a gui update on the payment dialog
965  * before we close it. This is undesired because the lots may be in
966  * an inconsistent state until after all events are handled. So
967  * the gui refresh may result in a crash.
968  * See https://bugs.gnucash.org/show_bug.cgi?id=740471
969  */
970  gnc_gui_component_clear_watches (pw->component_id);
971 
972  gnc_suspend_gui_refresh ();
973  {
974  const char *memo, *num;
975  GDate date;
976  time64 t;
977  gnc_numeric exch = gnc_numeric_create(1, 1); //default to "one to one" rate
978  GList *selected_lots = NULL;
979  GtkTreeSelection *selection;
980  gboolean auto_pay;
981 
982  /* Obtain all our ancillary information */
983  memo = gtk_entry_get_text (GTK_ENTRY (pw->memo_entry));
984  num = gtk_entry_get_text (GTK_ENTRY (pw->num_entry));
985  g_date_clear (&date, 1);
986  gnc_date_edit_get_gdate (GNC_DATE_EDIT (pw->date_edit), &date);
987  t = gdate_to_time64 (date);
988 
989  /* Obtain the list of selected lots (documents/payments) from the dialog */
990  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
991  gtk_tree_selection_selected_foreach (selection, get_selected_lots, &selected_lots);
992 
993  /* When the payment amount is 0, the selected documents cancel each other out
994  * so no money is actually transferred.
995  * For non-zero payments money will be transferred between the post account
996  * and the transfer account. In that case if these two accounts don't have
997  * the same currency the user is asked to enter the exchange rate.
998  */
999  if (!gnc_numeric_zero_p (pw->amount_tot) &&
1000  !gnc_commodity_equal(xaccAccountGetCommodity(pw->xfer_acct), xaccAccountGetCommodity(pw->post_acct)))
1001  {
1002  XferDialog* xfer;
1003 
1004  text = _("The transfer and post accounts are associated with different currencies. Please specify the conversion rate.");
1005 
1006  xfer = gnc_xfer_dialog(pw->dialog, pw->post_acct);
1007  gnc_info_dialog (GTK_WINDOW (pw->dialog), "%s", text);
1008 
1009  gnc_xfer_dialog_select_to_account(xfer, pw->xfer_acct);
1010  gnc_xfer_dialog_set_amount(xfer, pw->amount_tot);
1011  gnc_xfer_dialog_set_date (xfer, t);
1012 
1013  /* All we want is the exchange rate so prevent the user from thinking
1014  it makes sense to mess with other stuff */
1015  gnc_xfer_dialog_set_from_show_button_active(xfer, FALSE);
1016  gnc_xfer_dialog_set_to_show_button_active(xfer, FALSE);
1017  gnc_xfer_dialog_hide_from_account_tree(xfer);
1018  gnc_xfer_dialog_hide_to_account_tree(xfer);
1019  gnc_xfer_dialog_is_exchange_dialog(xfer, &exch);
1020 
1021  if (!gnc_xfer_dialog_run_until_done(xfer))
1022  return; /* If the user cancels, return to the payment dialog without changes */
1023  }
1024 
1025  /* Perform the payment */
1026  if (gncOwnerGetType (&(pw->owner)) == GNC_OWNER_CUSTOMER)
1027  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_INVOICE, GNC_PREF_AUTO_PAY);
1028  else
1029  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
1030 
1031  gncOwnerApplyPaymentSecs (&pw->owner, &(pw->tx_info->txn), selected_lots,
1032  pw->post_acct, pw->xfer_acct, pw->amount_tot,
1033  exch, t, memo, num, auto_pay);
1034  }
1035  gnc_resume_gui_refresh ();
1036 
1037  /* Save the transfer account, xfer_acct */
1038  gnc_payment_dialog_remember_account(pw, pw->xfer_acct);
1039 
1040  if (gtk_widget_is_sensitive (pw->print_check) &&
1041  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(pw->print_check)))
1042  {
1043  Split *split = xaccTransFindSplitByAccount (pw->tx_info->txn, pw->xfer_acct);
1044  GList *splits = NULL;
1045  splits = g_list_append(splits, split);
1046  gnc_ui_print_check_dialog_create(NULL, splits, NULL);
1047  g_list_free (splits);
1048  }
1049 
1050  gnc_ui_payment_window_destroy (pw);
1051 }
1052 
1053 void
1054 gnc_payment_cancel_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
1055 {
1056  PaymentWindow *pw = data;
1057  gnc_ui_payment_window_destroy (pw);
1058 }
1059 
1060 void
1061 gnc_payment_window_destroy_cb (G_GNUC_UNUSED GtkWidget *widget, gpointer data)
1062 {
1063  PaymentWindow *pw = data;
1064 
1065  if (!pw) return;
1066 
1067  gnc_unregister_gui_component (pw->component_id);
1068 
1069  g_list_free (pw->acct_types);
1070  g_list_free (pw->acct_commodities);
1071  if (pw->tx_info->lots)
1072  g_list_free_full (pw->tx_info->lots, g_free);
1073  g_free (pw);
1074 }
1075 
1076 void
1077 gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
1078  G_GNUC_UNUSED GtkTreeViewColumn *column, PaymentWindow *pw)
1079 {
1080  GtkTreeView *view;
1081  GtkTreeModel *model;
1082  GtkTreeIter iter;
1083 
1084  g_return_if_fail(widget);
1085  view = GTK_TREE_VIEW(widget);
1086 
1087  model = gtk_tree_view_get_model(view);
1088  if (gtk_tree_model_get_iter(model, &iter, path))
1089  {
1090  if (gtk_tree_model_iter_has_child(model, &iter))
1091  {
1092  /* There are children,
1093  * just expand or collapse the row. */
1094  if (gtk_tree_view_row_expanded(view, path))
1095  gtk_tree_view_collapse_row(view, path);
1096  else
1097  gtk_tree_view_expand_row(view, path, FALSE);
1098  }
1099  else if (gnc_payment_window_check_payment (pw))
1100  /* It's an account without any children
1101  * If all conditions for a valid payment are met click the Ok button. */
1102  gnc_payment_ok_cb(widget, pw);
1103  }
1104 }
1105 
1106 void
1107 gnc_payment_leave_amount_cb (G_GNUC_UNUSED GtkWidget *widget,
1108  G_GNUC_UNUSED GdkEventFocus *event,
1109  PaymentWindow *pw)
1110 {
1111  gboolean d_payment_ok = FALSE;
1112  gboolean c_payment_ok = FALSE;
1113 
1114  if (! pw->amount_credit_edit || ! pw->amount_debit_edit)
1115  return;
1116 
1117  c_payment_ok = gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(pw->amount_credit_edit), NULL);
1118  d_payment_ok = gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(pw->amount_debit_edit), NULL);
1119 
1120  if (c_payment_ok && d_payment_ok)
1121  {
1122  gnc_numeric amount_deb, amount_cred, amount_tot;
1123 
1124  /* If both credit and debit amount are entered, simplify it to either one */
1125  amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit));
1126  amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit));
1127  amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
1129  xaccAccountGetCommodity (pw->post_acct)),
1131 
1132  gnc_ui_payment_window_set_amount (pw, amount_tot);
1133  }
1134  /* Reflect if the payment could complete now */
1135  gnc_payment_window_check_payment (pw);
1136 }
1137 
1138 void
1139 gnc_payment_activate_amount_cb (G_GNUC_UNUSED GtkWidget *widget,
1140  PaymentWindow *pw)
1141 {
1142  gnc_payment_leave_amount_cb (NULL, NULL, pw);
1143 }
1144 
1145 /* Select the list of accounts to show in the tree */
1146 static void
1147 gnc_payment_set_account_types (GncTreeViewAccount *tree)
1148 {
1149  AccountViewInfo avi;
1150  int i;
1151 
1153 
1154  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
1155  avi.include_type[i] = !xaccAccountIsAPARType (i);
1156 
1158 }
1159 
1160 static gboolean
1161 find_handler (G_GNUC_UNUSED gpointer find_data, gpointer user_data)
1162 {
1163  PaymentWindow *pw = user_data;
1164 
1165  return (pw != NULL);
1166 }
1167 
1168 static void print_date (G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
1169  GtkCellRenderer *cell,
1170  GtkTreeModel *tree_model,
1171  GtkTreeIter *iter,
1172  G_GNUC_UNUSED gpointer data)
1173 {
1174  time64 doc_date_time;
1175  gchar *doc_date_str;
1176 
1177  g_return_if_fail (cell && iter && tree_model);
1178 
1179 
1180  gtk_tree_model_get (tree_model, iter, 0, &doc_date_time, -1);
1181  doc_date_str = qof_print_date (doc_date_time);
1182  g_object_set (G_OBJECT (cell), "text", doc_date_str, NULL);
1183  g_free (doc_date_str);
1184 }
1185 
1186 static gint
1187 doc_sort_func (GtkTreeModel *model,
1188  GtkTreeIter *a,
1189  GtkTreeIter *b,
1190  gpointer user_data)
1191 {
1192  time64 a_date, b_date;
1193  gchar *a_id = NULL, *b_id = NULL;
1194  int ret;
1195 
1196  gtk_tree_model_get (model, a, 0, &a_date, 1, &a_id, -1);
1197  gtk_tree_model_get (model, b, 0, &b_date, 1, &b_id, -1);
1198 
1199  if (a_date < b_date) ret = -1;
1200  else if (a_date > b_date) ret = 1;
1201  else ret = g_strcmp0 (a_id, b_id);
1202 
1203  g_free (a_id);
1204  g_free (b_id);
1205  return ret;
1206 }
1207 
1208 static gboolean
1209 payment_dialog_delete_event_cb (GtkWidget *widget,
1210  GdkEvent *event,
1211  gpointer user_data)
1212 {
1213  PaymentWindow *pw = user_data;
1214 
1215  // this cb allows the window size to be saved on closing with the X
1216  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(pw->dialog));
1217 
1218  return FALSE;
1219 }
1220 
1221 static PaymentWindow *
1222 new_payment_window (GtkWindow *parent, QofBook *book, InitialPaymentInfo *tx_info)
1223 {
1224  PaymentWindow *pw;
1225  GtkBuilder *builder;
1226  GtkWidget *box;
1227  GtkTreeSelection *selection;
1228  GtkTreeViewColumn *column;
1229  GtkCellRenderer *renderer;
1230  GtkTreeModel *store;
1231  GtkTreeIter iter;
1232 
1233  /* Ensure we always have a properly initialized PreExistTxnInfo struct to work with */
1234  if (!tx_info)
1235  {
1236  tx_info = g_new0 (InitialPaymentInfo, 1);
1237  gncOwnerInitCustomer (&tx_info->owner, NULL);
1238  }
1239 
1240  /*
1241  * Find an existing payment window. If found, bring it to
1242  * the front. If we have an actual owner, then set it in
1243  * the window. And update the PreExistTxnInfo (tx_info) for this window.
1244  */
1245 
1246  pw = gnc_find_first_gui_component (DIALOG_PAYMENT_CM_CLASS, find_handler, NULL);
1247  if (pw)
1248  {
1249 
1250  // Reset the current
1251  if (pw->tx_info->lots)
1252  g_list_free_full (pw->tx_info->lots, g_free);
1253  g_free (pw->tx_info);
1254  pw->tx_info = tx_info;
1255 
1256  gncOwnerCopy (&pw->tx_info->owner, &(pw->owner));
1257  gnc_payment_set_owner_type (pw, gncOwnerGetType(&pw->tx_info->owner));
1258 
1259  gtk_window_set_transient_for (GTK_WINDOW(pw->dialog), parent);
1260  gtk_window_present (GTK_WINDOW(pw->dialog));
1261  return(pw);
1262  }
1263 
1264  /* Ok, we need a new window */
1265 
1266  pw = g_new0 (PaymentWindow, 1);
1267  pw->book = book;
1268  pw->tx_info = tx_info;
1269 
1270  /* Open and read the Glade File */
1271  builder = gtk_builder_new();
1272  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_hor_adj");
1273  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_vert_adj");
1274  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_model");
1275  gnc_builder_add_from_file (builder, "dialog-payment.glade", "post_combo_model");
1276  gnc_builder_add_from_file (builder, "dialog-payment.glade", "owner_type_combo_model");
1277  gnc_builder_add_from_file (builder, "dialog-payment.glade", "payment_dialog");
1278  pw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "payment_dialog"));
1279  gtk_window_set_transient_for (GTK_WINDOW(pw->dialog), parent);
1280 
1281  // Set the name for this dialog so it can be easily manipulated with css
1282  gtk_widget_set_name (GTK_WIDGET(pw->dialog), "gnc-id-payment");
1283 
1284  /* Grab the widgets and build the dialog */
1285  pw->payment_warning = GTK_WIDGET (gtk_builder_get_object (builder, "payment_warning"));
1286  pw->conflict_message = GTK_WIDGET (gtk_builder_get_object (builder, "conflict_message"));
1287  pw->ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "okbutton"));
1288  pw->num_entry = GTK_WIDGET (gtk_builder_get_object (builder, "num_entry"));
1289  pw->memo_entry = GTK_WIDGET (gtk_builder_get_object (builder, "memo_entry"));
1290  pw->commodity_label = GTK_WIDGET (gtk_builder_get_object (builder, "commodity_label"));
1291  pw->post_combo = GTK_WIDGET (gtk_builder_get_object (builder, "post_combo"));
1292  gtk_combo_box_set_entry_text_column( GTK_COMBO_BOX( pw->post_combo ), 0 );
1293  gnc_cbwe_require_list_item(GTK_COMBO_BOX(pw->post_combo));
1294 
1295  pw->owner_type_combo = GTK_WIDGET (gtk_builder_get_object (builder, "owner_type_combo"));
1296  /* Add the respective GNC_OWNER_TYPEs to the combo box model
1297  * ATTENTION: the order here should match the order of the
1298  * store's entries as set in the glade file !
1299  */
1300  store = gtk_combo_box_get_model (GTK_COMBO_BOX(pw->owner_type_combo));
1301  gtk_tree_model_get_iter_first (store, &iter);
1302  gtk_list_store_set (GTK_LIST_STORE(store), &iter,
1303  COL_OWNER_TYPE_NAME, _("Customer"),
1304  COL_OWNER_TYPE_NUM, GNC_OWNER_CUSTOMER, -1);
1305  gtk_tree_model_iter_next (store, &iter);
1306  gtk_list_store_set (GTK_LIST_STORE(store), &iter,
1307  COL_OWNER_TYPE_NAME, _("Vendor"),
1308  COL_OWNER_TYPE_NUM, GNC_OWNER_VENDOR, -1);
1309  gtk_tree_model_iter_next (store, &iter);
1310  gtk_list_store_set (GTK_LIST_STORE(store), &iter,
1311  COL_OWNER_TYPE_NAME, _("Employee"),
1312  COL_OWNER_TYPE_NUM, GNC_OWNER_EMPLOYEE, -1);
1313 
1314  pw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "owner_box"));
1315 
1316  pw->amount_refund_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
1317  pw->amount_payment_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
1318 
1319  pw->amount_debit_edit = gnc_amount_edit_new ();
1320  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_debit_edit),
1321  TRUE);
1322  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit), gnc_numeric_zero());
1323  g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(pw->amount_debit_edit))),
1324  "focus-out-event",
1325  G_CALLBACK(gnc_payment_leave_amount_cb), pw);
1326 
1327  g_signal_connect(G_OBJECT(pw->amount_debit_edit),
1328  "activate",
1329  G_CALLBACK(gnc_payment_activate_amount_cb), pw);
1330 
1331  pw->amount_credit_edit = gnc_amount_edit_new ();
1332  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_credit_edit),
1333  TRUE);
1334  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit), gnc_numeric_zero());
1335  g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(pw->amount_credit_edit))),
1336  "focus-out-event",
1337  G_CALLBACK(gnc_payment_leave_amount_cb), pw);
1338 
1339  g_signal_connect(G_OBJECT(pw->amount_credit_edit),
1340  "activate",
1341  G_CALLBACK(gnc_payment_activate_amount_cb), pw);
1342 
1343  box = GTK_WIDGET (gtk_builder_get_object (builder, "date_box"));
1344  pw->date_edit = gnc_date_edit_new (time(NULL), FALSE, FALSE);
1345  gtk_box_pack_start (GTK_BOX (box), pw->date_edit, TRUE, TRUE, 0);
1346  pw->print_check = GTK_WIDGET (gtk_builder_get_object (builder, "print_check"));
1347 
1348  pw->docs_list_tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "docs_list_tree_view"));
1349  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
1350  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1351 
1352  // Set grid lines option to preference
1353  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(pw->docs_list_tree_view), gnc_tree_view_get_grid_lines_pref ());
1354 
1355  /* Configure date column */
1356  renderer = gtk_cell_renderer_text_new ();
1357  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 0);
1358  gtk_tree_view_column_pack_start (column, renderer, TRUE);
1359  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
1360  column, "31-12-2013");
1361  gtk_tree_view_column_set_cell_data_func (column, renderer,
1362  (GtkTreeCellDataFunc) print_date,
1363  NULL, NULL);
1364 
1365  /* Configure document number column */
1366  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 1);
1367  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
1368  column, _("Pre-Payment"));
1369 
1370  /* Configure document type column */
1371  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 2);
1372  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
1373  column, _("Credit Note"));
1374 
1375  /* Configure debit column */
1376  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 3);
1377  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
1378  column, "9,999,999.00");
1379 
1380  /* Configure credit column */
1381  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 4);
1382  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
1383  column, "9,999,999.00");
1384 
1385  gtk_tree_sortable_set_default_sort_func
1386  (GTK_TREE_SORTABLE (gtk_tree_view_get_model
1387  (GTK_TREE_VIEW (pw->docs_list_tree_view))),
1388  doc_sort_func, NULL, NULL);
1389 
1390  gtk_tree_sortable_set_sort_column_id
1391  (GTK_TREE_SORTABLE (gtk_tree_view_get_model
1392  (GTK_TREE_VIEW (pw->docs_list_tree_view))),
1393  GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1394  GTK_SORT_ASCENDING);
1395 
1396  box = GTK_WIDGET (gtk_builder_get_object (builder, "acct_window"));
1397  pw->acct_tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
1398  gtk_container_add (GTK_CONTAINER (box), pw->acct_tree);
1399  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(pw->acct_tree), FALSE);
1400  gnc_payment_set_account_types (GNC_TREE_VIEW_ACCOUNT (pw->acct_tree));
1401 
1402  /* Set the dialog for the 'new' owner and owner type.
1403  * Note that this also sets the post account tree. */
1404  gncOwnerCopy (&pw->tx_info->owner, &(pw->owner));
1405  gnc_payment_set_owner_type (pw, gncOwnerGetType (&pw->tx_info->owner));
1406 
1407  /* Setup signals */
1408  gtk_builder_connect_signals_full( builder,
1409  gnc_builder_connect_full_func,
1410  pw);
1411 
1412  g_signal_connect (G_OBJECT (pw->acct_tree), "row-activated",
1413  G_CALLBACK (gnc_payment_acct_tree_row_activated_cb), pw);
1414 
1415  g_signal_connect (G_OBJECT (pw->owner_type_combo), "changed",
1416  G_CALLBACK (gnc_payment_dialog_owner_type_changed_cb), pw);
1417 
1418  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->acct_tree));
1419  g_signal_connect (G_OBJECT (selection), "changed",
1420  G_CALLBACK (gnc_payment_dialog_xfer_acct_changed_cb), pw);
1421 
1422  g_signal_connect (G_OBJECT(pw->dialog), "delete-event",
1423  G_CALLBACK(payment_dialog_delete_event_cb), pw);
1424 
1425  /* Register with the component manager */
1426  pw->component_id =
1427  gnc_register_gui_component (DIALOG_PAYMENT_CM_CLASS,
1428  gnc_payment_window_refresh_handler,
1429  gnc_payment_window_close_handler,
1430  pw);
1431 
1432  /* Watch for any new or changed accounts */
1433  gnc_gui_component_watch_entity_type (pw->component_id,
1434  GNC_ID_ACCOUNT,
1435  QOF_EVENT_CREATE | QOF_EVENT_MODIFY |
1436  QOF_EVENT_DESTROY);
1437 
1438  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(pw->dialog), GTK_WINDOW(parent));
1439 
1440  /* Show it all */
1441  gtk_widget_show_all (pw->dialog);
1442  g_object_unref(G_OBJECT(builder));
1443 
1444  // The customer choice widget should have keyboard focus
1445  if (GNC_IS_GENERAL_SEARCH(pw->owner_choice))
1446  {
1447  gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(pw->owner_choice));
1448  }
1449 
1450  /* Reflect if the payment could complete now */
1451  gnc_payment_window_check_payment (pw);
1452 
1453  /* Warn the user if they have no valid post-to accounts */
1454  {
1455  const gchar *text;
1456  const char *acct_type;
1457 
1458  text = gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (GTK_COMBO_BOX(pw->post_combo)))));
1459 
1460  if (!text || g_strcmp0 (text, "") == 0)
1461  {
1462 
1463  /* The code below assumes there will only be one account type.
1464  * Let's assert this to protect from potential future changes. */
1465  g_assert (g_list_length (pw->acct_types) == 1);
1466  acct_type = xaccAccountGetTypeStr(GPOINTER_TO_INT(pw->acct_types->data));
1467  gnc_warning_dialog(GTK_WINDOW (pw->dialog),
1468  _("You have no valid \"Post To\" accounts. "
1469  "Please create an account of type \"%s\" "
1470  "before you continue to process this payment. "
1471  "Perhaps you want to create an Invoice or "
1472  "Bill first?"),
1473  acct_type);
1474  }
1475  }
1476 
1477  return pw;
1478 }
1479 
1480 
1481 void
1482 gnc_ui_payment_window_destroy (PaymentWindow *pw)
1483 {
1484  if (!pw) return;
1485 
1486  gnc_close_gui_component (pw->component_id);
1487 }
1488 
1489 PaymentWindow *
1490 gnc_ui_payment_new_with_invoice (GtkWindow *parent, const GncOwner *owner,
1491  QofBook *book, GncInvoice *invoice)
1492 {
1493  GNCLot *postlot;
1494  InitialPaymentInfo *tx_info;
1495 
1496  if (!book) return NULL;
1497 
1498 
1499  tx_info = g_new0 (InitialPaymentInfo, 1);
1500 
1501  if (owner)
1502  {
1503  /* Figure out the company */
1504  gncOwnerCopy (gncOwnerGetEndOwner (owner), &tx_info->owner);
1505  }
1506  else
1507  {
1508  gncOwnerInitCustomer (&tx_info->owner, NULL);
1509  }
1510 
1511  tx_info->post_acct = gncInvoiceGetPostedAcc (invoice);
1512 
1513  postlot = gncInvoiceGetPostedLot (invoice);
1514  if (postlot)
1515  {
1516  PreExistLotInfo *lot_info = g_new0 (PreExistLotInfo, 1);
1517  lot_info->lot = postlot;
1518  lot_info->amount = gnc_numeric_zero ();
1519  tx_info->lots = g_list_prepend (tx_info->lots, lot_info);
1520  }
1521  return new_payment_window (parent, book, tx_info);
1522 }
1523 
1524 PaymentWindow *
1525 gnc_ui_payment_new (GtkWindow *parent, GncOwner *owner, QofBook *book)
1526 {
1527  return gnc_ui_payment_new_with_invoice (parent, owner, book, NULL);
1528 }
1529 
1530 // ///////////////
1531 
1532 gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
1533 {
1534  gboolean result = TRUE;
1535  Split *assetaccount_split, *aparaccount_split;
1536  gnc_numeric amount;
1537 
1538  if (!txn)
1539  return result;
1540 
1541  if (!xaccTransGetSplitList(txn))
1542  return result;
1543 
1544  /* First test if one split is in an A/R or A/P account.
1545  * That will give us the best Customer vs Vendor/Employee distinction */
1546  // Prefer true business split (one that's linked to a lot)
1547  aparaccount_split = xaccTransGetFirstAPARAcctSplit(txn, TRUE);
1548  if (!aparaccount_split)
1549  // No true business split found, try again but this time more relaxed
1550  aparaccount_split = xaccTransGetFirstAPARAcctSplit(txn, FALSE);
1551  if (aparaccount_split)
1552  {
1553  if (xaccAccountGetType (xaccSplitGetAccount (aparaccount_split)) == ACCT_TYPE_RECEIVABLE)
1554  return TRUE; // Type is Customer
1555  else if (xaccAccountGetType (xaccSplitGetAccount (aparaccount_split)) == ACCT_TYPE_PAYABLE)
1556  return FALSE; // Type is Vendor/Employee, there's not enough information to refine more
1557  }
1558 
1559  /* For the lack of an A/R or A/P account we'll assume positive changes to an
1560  * Asset/Liability or Equity account are Customer payments the others will be
1561  * considered Vendor payments */
1562  assetaccount_split = xaccTransGetFirstPaymentAcctSplit(txn);
1563  if (!assetaccount_split)
1564  {
1565  /* Transaction isn't valid for a payment, just return the default
1566  * Calling code will have to handle this situation properly */
1567  PINFO("No asset splits in txn \"%s\"; cannot use this for assigning a payment.",
1569  return result;
1570  }
1571 
1572  assetaccount_split = xaccTransGetFirstPaymentAcctSplit(txn);
1573  amount = xaccSplitGetValue(assetaccount_split);
1574  result = gnc_numeric_positive_p(amount); // positive amounts == customer
1575  //PINFO("Amount=%s", gnc_numeric_to_string(amount));
1576  return result;
1577 }
1578 
1579 // ///////////////
1580 static char *gen_split_desc (Transaction *txn, Split *split)
1581 {
1582  gnc_numeric value = xaccSplitGetAmount(split);
1583  Account *xfer_acct = xaccSplitGetAccount(split);
1584  char *acct_name = gnc_account_get_full_name (xfer_acct);
1585  const char *action = gnc_get_action_num (txn, split);
1586  const char *memo = xaccSplitGetMemo (split);
1587  char rec_state = xaccSplitGetReconcile (split);
1588  const char *print_amt = xaccPrintAmount(value, gnc_account_print_info (xfer_acct, TRUE));
1589  char *split_str = NULL;
1590  char *rec_str = NULL;
1591 
1592  if (rec_state == CREC)
1593  rec_str = g_strdup_printf("[%s] ", _("Cleared"));
1594  else if (rec_state == YREC)
1595  rec_str = g_strdup_printf("[%s] ", _("Reconciled"));
1596  else
1597  rec_str = g_strdup("");
1598 
1599  if (action && *action && memo && *memo)
1600  split_str = g_strdup_printf ("%s%s: %s (%s, %s)", rec_str, acct_name, print_amt,
1601  action, memo);
1602  else if((action && *action) || (memo && *memo))
1603  split_str = g_strdup_printf ("%s%s: %s (%s)", rec_str, acct_name, print_amt,
1604  action ? action : memo);
1605  else
1606  split_str = g_strdup_printf ("%s%s: %s", rec_str, acct_name, print_amt);
1607 
1608  g_free (acct_name);
1609  g_free (rec_str);
1610 
1611  return split_str;
1612 }
1613 
1614 static Split *select_payment_split (GtkWindow *parent, Transaction *txn)
1615 {
1616  /* We require the txn to have one split in an Asset account.
1617  * The only exception would be a lot link transaction
1618  */
1619  GList *payment_splits = xaccTransGetPaymentAcctSplitList (txn);
1620  Split *selected_split = NULL;
1621  if (!payment_splits)
1622  {
1623  GtkWidget *dialog;
1624 
1625  if (xaccTransGetTxnType(txn) == TXN_TYPE_LINK)
1626  return NULL;
1627 
1628  dialog = gtk_message_dialog_new (parent,
1629  GTK_DIALOG_DESTROY_WITH_PARENT,
1630  GTK_MESSAGE_INFO,
1631  GTK_BUTTONS_CLOSE,
1632  "%s",
1633  _("The selected transaction doesn't have splits that can be assigned as a payment"));
1634  gtk_dialog_run (GTK_DIALOG(dialog));
1635  gtk_widget_destroy (dialog);
1636  PINFO("No asset splits in txn \"%s\"; cannot use this for assigning a payment.",
1638  return NULL;
1639  }
1640 
1641  if (g_list_length(payment_splits) > 1)
1642  {
1643  GtkWidget *first_rb = NULL;
1644  int answer = GTK_BUTTONS_OK;
1645  const char *message = _("While this transaction has multiple splits that can be considered\n"
1646  "as 'the payment split', GnuCash only knows how to handle one.\n"
1647  "Please select one, the others will be discarded.\n\n");
1648  GtkDialog *dialog = GTK_DIALOG(
1649  gtk_dialog_new_with_buttons (_("Warning"),
1650  parent,
1651  GTK_DIALOG_DESTROY_WITH_PARENT,
1652  _("Continue"), GTK_BUTTONS_OK,
1653  _("Cancel"), GTK_BUTTONS_CANCEL,
1654  NULL));
1655  GtkWidget *content = gtk_dialog_get_content_area(dialog);
1656  GtkWidget *label = gtk_label_new (message);
1657  gtk_box_pack_start (GTK_BOX(content), label, FALSE, TRUE, 0);
1658 
1659  /* Add splits as selectable options to the dialog */
1660  for (GList *node = payment_splits; node; node = node->next)
1661  {
1662  GtkWidget *rbutton;
1663  Split *split = node->data;
1664  char *split_str = gen_split_desc (txn, split);
1665 
1666  if (node == payment_splits)
1667  {
1668  first_rb = gtk_radio_button_new_with_label (NULL, split_str);
1669  rbutton = first_rb;
1670  }
1671  else
1672  rbutton = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_rb), split_str);
1673 
1674  g_object_set_data(G_OBJECT(rbutton), "split", split);
1675  gtk_box_pack_start (GTK_BOX(content), rbutton, FALSE, FALSE, 0);
1676 
1677  g_free (split_str);
1678  }
1679 
1680  gtk_dialog_set_default_response (dialog, GTK_BUTTONS_CANCEL);
1681  gtk_widget_show_all (GTK_WIDGET(dialog));
1682  answer = gtk_dialog_run (dialog);
1683 
1684  if (answer == GTK_BUTTONS_OK)
1685  {
1686  GSList *rbgroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(first_rb));
1687  GSList *rbnode;
1688  for (rbnode = rbgroup; rbnode; rbnode = rbnode->next)
1689  {
1690  GtkWidget *rbutton = rbnode->data;
1691  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutton)))
1692  {
1693  selected_split = g_object_get_data(G_OBJECT(rbutton), "split");
1694  break;
1695  }
1696  }
1697  }
1698 
1699  gtk_widget_destroy (GTK_WIDGET(dialog));
1700  }
1701  else
1702  selected_split = payment_splits->data;
1703 
1704  g_list_free (payment_splits);
1705  return selected_split;
1706 }
1707 
1708 static GList *select_txn_lots (GtkWindow *parent, Transaction *txn, Account **post_acct, gboolean *abort)
1709 {
1710  SplitList *apar_splits = NULL; /* all spits in txn that are APAR type */
1711  SplitList *apar_splits_no_lot = NULL; /* all splits in txn that are APAR type, but not tied to a lot */
1712  SplitList *iter;
1713  GList *txn_lots = NULL;
1714  GList *unique_apar_accts = NULL;
1715 
1716  /* There's no use in continuing if I can't set the post_acct or abort variables */
1717  if (!post_acct || !abort)
1718  return NULL;
1719 
1720  *abort = FALSE;
1721  *post_acct = NULL;
1722 
1723  /* Start by filtering out all APAR splits that have lots. Those are the ones we can
1724  display as invoices and pre-payments in the payment window. */
1725  apar_splits = xaccTransGetAPARAcctSplitList (txn, FALSE);
1726  for (iter = apar_splits; iter; iter = iter->next)
1727  {
1728  GNCLot *postlot = NULL;
1729  Split *post_split = iter->data;
1730  Account *apar_acct = xaccSplitGetAccount (post_split);
1731 
1732  /* Store found apar_acct in our list of unique_apar_accts
1733  * for later processing */
1734  if (!g_list_find (unique_apar_accts, apar_acct))
1735  unique_apar_accts = g_list_prepend (unique_apar_accts, apar_acct);
1736 
1737  postlot = xaccSplitGetLot (post_split);
1738  if (postlot)
1739  {
1740  PreExistLotInfo *lot_info = g_new0 (PreExistLotInfo, 1);
1741  lot_info->lot = postlot;
1742  lot_info->amount = xaccSplitGetValue (post_split);
1743  txn_lots = g_list_prepend (txn_lots, lot_info);
1744  *post_acct = apar_acct;
1745  }
1746  else
1747  apar_splits_no_lot = g_list_prepend (apar_splits_no_lot, post_split);
1748  }
1749 
1750  /* If no post_acct was selected from the postlots, fall back to the first apar split's
1751  * account if there is one. */
1752  if (!*post_acct && apar_splits_no_lot)
1753  *post_acct = xaccSplitGetAccount (apar_splits_no_lot->data);
1754 
1755  /* Abort if the txn has splits in more than one APAR account
1756  * GnuCash can only handle one post account per payment transaction.
1757  */
1758  if (g_list_length (unique_apar_accts) > 1)
1759  {
1760  GtkWidget *dialog;
1761  char *split_str = g_strdup ("");
1762 
1763  for (iter = unique_apar_accts; iter; iter = iter->next)
1764  {
1765  Account *acct = iter->data;
1766  char *acct_name = gnc_account_get_full_name (acct);
1767  char *tmp_str = g_strconcat(split_str, "• ", acct_name, "\n", NULL);
1768  g_free (acct_name);
1769  g_free (split_str);
1770  split_str = tmp_str;
1771  }
1772 
1773  dialog = gtk_message_dialog_new (parent,
1774  GTK_DIALOG_DESTROY_WITH_PARENT,
1775  GTK_MESSAGE_INFO,
1776  GTK_BUTTONS_CLOSE,
1777  _("This transaction has splits in multiple business accounts:\n\n%s\n"
1778  "GnuCash can only handle transactions that post to a single account.\n\n"
1779  "Please correct this manually by editing the transaction directly and then try again."),
1780  split_str);
1781  gtk_dialog_run (GTK_DIALOG(dialog));
1782  gtk_widget_destroy (dialog);
1783  PINFO("Multiple asset accounts in splits of txn \"%s\"; cannot use this for assigning a payment.",
1785  g_free (split_str);
1786 
1787  *abort = TRUE;
1788  g_list_free_full (txn_lots, g_free);
1789  txn_lots = NULL;
1790  }
1791 
1792  g_list_free (apar_splits);
1793  g_list_free (apar_splits_no_lot);
1794  g_list_free (unique_apar_accts);
1795  return txn_lots;
1796 }
1797 
1798 PaymentWindow * gnc_ui_payment_new_with_txn (GtkWindow* parent, GncOwner *owner, Transaction *txn)
1799 {
1800  Split *payment_split = NULL;
1801  Account *post_acct = NULL;
1802  InitialPaymentInfo *tx_info = NULL;
1803  GList *txn_lots = NULL;
1804  gboolean abort = FALSE;
1805  PaymentWindow *pw;
1806 
1807  if (!txn)
1808  return NULL;
1809 
1810  if (!xaccTransGetSplitList(txn))
1811  return NULL;
1812 
1813  /* We require the txn to have one split in an Asset account.
1814  * The only exception would be a lot link transaction
1815  */
1816  payment_split = select_payment_split (parent, txn);
1817  if (!payment_split && (xaccTransGetTxnType(txn) != TXN_TYPE_LINK))
1818  return NULL;
1819 
1820  /* Get all APAR related lots. Watch out: there might be none */
1821  txn_lots = select_txn_lots (parent, txn, &post_acct, &abort);
1822  if (abort)
1823  return NULL;
1824 
1825  // Fill in the values from the given txn
1826  tx_info = g_new0(InitialPaymentInfo, 1);
1827  tx_info->txn = txn;
1828  tx_info->post_acct = post_acct;
1829  tx_info->lots = txn_lots;
1830  gncOwnerCopy (owner, &tx_info->owner);
1831 
1832  pw = new_payment_window (parent,
1833  qof_instance_get_book(QOF_INSTANCE(txn)),
1834  tx_info);
1835 
1836  gnc_ui_payment_window_set_num(pw, gnc_get_num_action (txn, payment_split));
1837  gnc_ui_payment_window_set_memo(pw, xaccTransGetDescription(txn));
1838  {
1839  GDate txn_date = xaccTransGetDatePostedGDate (txn);
1840  gnc_ui_payment_window_set_date(pw, &txn_date);
1841  }
1842 
1843  gnc_numeric amount = xaccSplitGetAmount (payment_split);
1844  /* Note: at this point post account selected in newly created payment dialog
1845  * may differ from what we got from select_txn_lots above.
1846  * Use the dialog's post account commodity to optionally convert the amount
1847  * to to display to the user */
1848  if (pw->post_acct)
1849  amount = xaccSplitConvertAmount (payment_split, pw->post_acct);
1850  gnc_ui_payment_window_set_amount(pw, amount);
1851  if (payment_split)
1852  gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(payment_split));
1853  return pw;
1854 }
void gnc_cbwe_set_by_string(GtkComboBox *cbwe, const gchar *text)
Find an entry in the GtkComboBox by its text value, and set the widget to that value.
Definition: gnc-gtk-utils.c:41
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Returns a GList of currencies associated with the owner.
Definition: gncOwner.c:1462
void gnc_tree_view_account_get_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will copy the current con...
void tree_view_column_set_default_width(GtkTreeView *view, GtkTreeViewColumn *column, const gchar *sizing_text)
Set default width for a treeview column.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Business Interface: Object OWNERs.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
Date and Time handling routines.
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Returns a GList of account-types based on the owner type.
Definition: gncOwner.c:1444
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
utility functions for the GnuCash UI
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits...
#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
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3217
gtk helper routines.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:404
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
stop here; the following types just aren&#39;t ready for prime time
Definition: Account.h:161
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void gnc_tree_view_account_set_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will applies the settings...
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
Split * xaccTransGetFirstPaymentAcctSplit(const Transaction *trans)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
gboolean gncOwnerIsValid(const GncOwner *owner)
Returns TRUE if the given owner is one of the valid objects.
Definition: gncOwner.c:699
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:275
Split * gnc_lot_get_latest_split(GNCLot *lot)
Convenience routineto identify the date this lot was closed.
Definition: gnc-lot.cpp:685
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
#define xaccAccountGetGUID(X)
Definition: Account.h:248
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:609
void gncOwnerApplyPaymentSecs(const GncOwner *owner, Transaction **preset_txn, GList *lots, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, time64 date, const char *memo, const char *num, gboolean auto_pay)
A convenience function to apply a payment to the owner.
Definition: gncOwner.c:1405
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3255
Account handling public routines.
GtkTreeView implementation for gnucash account tree.
#define YREC
The Split has been reconciled.
Definition: Split.h:74
gint gncOwnerLotsSortFunc(GNCLot *lotA, GNCLot *lotB)
Helper function used to sort lots by date.
Definition: gncOwner.c:728
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1253
gboolean gncOwnerGetOwnerFromLot(GNCLot *lot, GncOwner *owner)
Get the owner from the lot.
Definition: gncOwner.c:636
A/P account type.
Definition: Account.h:151
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
Retrieve a symbol for the specified commodity, suitable for display to the user.
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4462
#define TXN_TYPE_LINK
Transaction is a link between (invoice and payment) lots.
Definition: Transaction.h:128
SplitList * xaccTransGetAPARAcctSplitList(const Transaction *trans, gboolean strict)
The xaccTransGetAPARSplitList() method returns a GList of the splits in a transaction that belong to ...
#define CREC
The Split has been cleared.
Definition: Split.h:73
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
GLib helper routines.
Generic api to store and retrieve preferences.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:200
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Get the "parent" Owner or GncGUID thereof.
Definition: gncOwner.c:572
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1288
Business Invoice Interface.
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
This function selects an account in the account tree view.
Split * xaccTransGetFirstAPARAcctSplit(const Transaction *trans, gboolean strict)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
gboolean gncOwnerLotMatchOwnerFunc(GNCLot *lot, gpointer user_data)
Helper function used to filter a list of lots by owner.
Definition: gncOwner.c:706
SplitList * xaccTransGetPaymentAcctSplitList(const Transaction *trans)
The xaccTransGetPaymentAcctSplitList() method returns a GList of the splits in a transaction that bel...
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
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.
A/R account type.
Definition: Account.h:149
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
This function returns the account associated with the selected item in the account tree view...
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
LotList * xaccAccountFindOpenLots(const Account *acc, gboolean(*match_func)(GNCLot *lot, gpointer user_data), gpointer user_data, GCompareFunc sort_func)
Find a list of open lots that match the match_func.
Definition: Account.cpp:3917
const char * xaccAccountGetTypeStr(GNCAccountType type)
The xaccAccountGetTypeStr() routine returns a string suitable for use in the GUI/Interface.
Definition: Account.cpp:4292
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition: gnc-lot.cpp:502
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.cpp:1886
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2032