GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-payment.c
1 /*
2  * dialog-payment.c -- Dialog for payment entry
3  * Copyright (C) 2002,2006 Derek Atkins
4  * Author: Derek Atkins <[email protected]>
5  * Copyright (c) 2006 David Hampton <[email protected]>
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 [email protected]
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 "qof.h"
36 #include "gnc-date.h"
37 #include "gnc-date-edit.h"
38 #include "gnc-amount-edit.h"
39 #include "gnc-gtk-utils.h"
40 #include "gnc-prefs.h"
41 #include "gnc-tree-view-account.h"
42 #include "tree-view-utils.h"
43 #include "Transaction.h"
44 #include "Account.h"
45 #include "gncOwner.h"
46 #include "engine-helpers.h"
47 
48 #include "gncInvoice.h"
49 
50 #include "dialog-payment.h"
51 #include "business-gnome-utils.h"
52 
53 #include "dialog-transfer.h"
54 #include "gnome-search/gnc-general-search.h"
55 
56 #define DIALOG_PAYMENT_CUSTOMER_CM_CLASS "customer-payment-dialog"
57 #define DIALOG_PAYMENT_VENDOR_CM_CLASS "vendor-payment-dialog"
58 
60 {
61  GtkWidget * dialog;
62 
63  GtkWidget * payment_warning;
64  GtkWidget * ok_button;
65  GtkWidget * num_entry;
66  GtkWidget * memo_entry;
67  GtkWidget * post_combo;
68  GtkWidget * owner_choice;
69  GtkWidget * amount_debit_edit;
70  GtkWidget * amount_credit_edit;
71  GtkWidget * date_edit;
72  GtkWidget * acct_tree;
73  GtkWidget * docs_list_tree_view;
74 
75  gint component_id;
76  QofBook * book;
77  GncOwner owner;
78  GncInvoice * invoice;
79  Account * post_acct;
80  Account * xfer_acct;
81  gnc_numeric amount_tot;
82  GList * acct_types;
83  GList * acct_commodities;
84 
85  Transaction * pre_existing_txn;
86 };
87 
88 void gnc_ui_payment_window_set_num (PaymentWindow *pw, const char* num)
89 {
90  g_assert(pw);
91  gtk_entry_set_text(GTK_ENTRY (pw->num_entry), num);
92 }
93 void gnc_ui_payment_window_set_memo (PaymentWindow *pw, const char* memo)
94 {
95  g_assert(pw);
96  gtk_entry_set_text(GTK_ENTRY (pw->memo_entry), memo);
97 }
98 void gnc_ui_payment_window_set_date (PaymentWindow *pw, const GDate *date)
99 {
100  g_assert(pw);
101  g_assert(date);
102  gnc_date_edit_set_gdate (GNC_DATE_EDIT (pw->date_edit), date);
103 }
104 void gnc_ui_payment_window_set_amount (PaymentWindow *pw, gnc_numeric amount)
105 {
106  g_assert(pw);
107 
108  /* Debits are negative, credits are positive */
109  if (gnc_numeric_positive_p (amount))
110  {
111  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_credit_edit),
112  amount);
113  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_debit_edit),
114  gnc_numeric_zero ());
115  }
116  else
117  {
118  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_debit_edit),
119  gnc_numeric_neg (amount));
120  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(pw->amount_credit_edit),
121  gnc_numeric_zero ());
122  }
123 
124 }
125 void gnc_ui_payment_window_set_postaccount (PaymentWindow *pw, const Account* account)
126 {
127  g_assert(pw);
128  g_assert(account);
129  {
130  gchar *acct_string = gnc_account_get_full_name (account);
131  gnc_cbwe_set_by_string(GTK_COMBO_BOX(pw->post_combo), acct_string);
132  g_free(acct_string);
133  }
134 }
135 void gnc_ui_payment_window_set_xferaccount (PaymentWindow *pw, const Account* account)
136 {
137  g_assert(pw);
138  g_assert(account);
139  gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
140  (Account*)account);
141 }
142 
143 static gboolean gnc_payment_dialog_has_pre_existing_txn(const PaymentWindow* pw)
144 {
145  return pw->pre_existing_txn != NULL;
146 }
147 int gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data);
148 void gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data);
149 void gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data);
150 void gnc_payment_ok_cb (GtkWidget *widget, gpointer data);
151 void gnc_payment_cancel_cb (GtkWidget *widget, gpointer data);
152 void gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data);
153 void gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
154  GtkTreeViewColumn *column, PaymentWindow *pw);
155 void gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
156  PaymentWindow *pw);
157 void gnc_payment_window_fill_docs_list (PaymentWindow *pw);
158 
159 
160 static void
161 gnc_payment_window_refresh_handler (GHashTable *changes, gpointer data)
162 {
163  PaymentWindow *pw = data;
164 
165  gnc_payment_window_fill_docs_list (pw);
166  pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
167 }
168 
169 static gboolean
170 gnc_payment_window_check_payment (PaymentWindow *pw)
171 {
172  const char *conflict_msg = NULL;
173  Account *post, *acc;
174  gnc_numeric amount_deb, amount_cred;
175  gboolean enable_xfer_acct = TRUE;
176  GtkTreeSelection *selection;
177 
178  if (!pw)
179  return FALSE;
180 
181  /* Verify the "post" account */
182  if (!pw->post_acct)
183  {
184  conflict_msg = _("You must enter a valid account name for posting.");
185  goto update_cleanup;
186  }
187 
188  /* Verify the user has selected an owner */
189  gnc_owner_get_owner (pw->owner_choice, &(pw->owner));
190  if (!gncOwnerIsValid(&pw->owner))
191  {
192  conflict_msg = _("You must select a company for payment processing.");
193  goto update_cleanup;
194  }
195 
196  /* Test the total amount */
197  amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit));
198  amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit));
199  pw->amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
202 
203  if (gnc_numeric_check (pw->amount_tot) || gnc_numeric_zero_p (pw->amount_tot))
204  {
205  enable_xfer_acct = FALSE;
206  }
207  else
208  {
209  /* Verify the user has selected a transfer account */
210  pw->xfer_acct = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(pw->acct_tree));
211  if (!pw->xfer_acct)
212  {
213  conflict_msg = _("You must select a transfer account from the account tree.");
214  }
215  }
216 
217 update_cleanup:
218  gtk_widget_set_sensitive (pw->acct_tree, enable_xfer_acct);
219 
220  /* Check if there are issues preventing a successful payment */
221  gtk_widget_set_tooltip_text (pw->payment_warning, conflict_msg);
222  if (conflict_msg)
223  {
224  gtk_widget_show (pw->payment_warning);
225  gtk_widget_set_sensitive (pw->ok_button, FALSE);
226  return FALSE;
227  }
228  else
229  {
230  gtk_widget_hide (pw->payment_warning);
231  gtk_widget_set_sensitive (pw->ok_button, TRUE);
232  }
233 
234  return TRUE;
235 }
236 
237 static void
238 gnc_payment_window_close_handler (gpointer data)
239 {
240  PaymentWindow *pw = data;
241 
242  if (pw)
243  gtk_widget_destroy (pw->dialog);
244 }
245 
246 static void
247 calculate_selected_total_helper (GtkTreeModel *model,
248  GtkTreePath *path,
249  GtkTreeIter *iter,
250  gpointer data)
251 {
252  gnc_numeric *subtotal = (gnc_numeric*) data;
253  gnc_numeric cur_val;
254  GValue value = { 0 };
255  GNCLot *lot;
256  Account *acct;
257  gnc_commodity *currency;
258 
259  gtk_tree_model_get_value (model, iter, 5, &value);
260  lot = (GNCLot *) g_value_get_pointer (&value);
261  g_value_unset (&value);
262 
263  /* Find the amount's currency to determine the required precision */
264  acct = gnc_lot_get_account (lot);
265  currency = xaccAccountGetCommodity (acct);
266 
267  cur_val = gnc_lot_get_balance (lot);
268  *subtotal = gnc_numeric_add (*subtotal, cur_val,
270 }
271 
272 static gnc_numeric
273 gnc_payment_dialog_calculate_selected_total (PaymentWindow *pw)
274 {
275  GtkTreeSelection *selection;
276  gnc_numeric val = gnc_numeric_zero();
277 
278  if (!pw->docs_list_tree_view || !GTK_IS_TREE_VIEW(pw->docs_list_tree_view))
279  return gnc_numeric_zero();
280 
281  /* Figure out if anything is set in the current list */
282  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
283 
284  gtk_tree_selection_selected_foreach (selection,
285  calculate_selected_total_helper,
286  (gpointer) &val);
287 
288  return val;
289 }
290 
291 static void
292 gnc_payment_dialog_document_selection_changed (PaymentWindow *pw)
293 {
294  gnc_numeric val;
295 
296  /* Don't change the amount based on the selected documents
297  * in case this payment is from a pre-existing txn
298  */
299  if (gnc_payment_dialog_has_pre_existing_txn (pw))
300  return;
301 
302  /* Set the payment amount in the dialog */
303  val = gnc_payment_dialog_calculate_selected_total (pw);
304  gnc_ui_payment_window_set_amount(pw, val);
305 }
306 
307 static void
308 gnc_payment_dialog_highlight_document (PaymentWindow *pw)
309 {
310  if (pw->invoice)
311  {
312  GtkTreeIter iter;
313  GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view));
314  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
315  gtk_tree_selection_unselect_all (selection);
316 
317  if (gtk_tree_model_get_iter_first (model, &iter))
318  {
319  do
320  {
321  GValue value = { 0 };
322  GNCLot *lot;
323  GncInvoice *invoice;
324 
325  gtk_tree_model_get_value (model, &iter, 5, &value);
326  lot = (GNCLot *) g_value_get_pointer (&value);
327  g_value_unset (&value);
328 
329  if (!lot)
330  continue; /* Lot has been deleted behind our back... */
331 
332  invoice = gncInvoiceGetInvoiceFromLot (lot);
333  if (!invoice)
334  continue;
335 
336  if (pw->invoice == invoice)
337  {
338  gtk_tree_selection_select_iter (selection, &iter);
339  gnc_payment_dialog_document_selection_changed (pw);
340  }
341  }
342  while (gtk_tree_model_iter_next (model, &iter));
343  }
344  }
345 }
346 
347 void
348 gnc_payment_window_fill_docs_list (PaymentWindow *pw)
349 {
350  GtkListStore *store;
351  GtkTreeSelection *selection;
352  GList *list = NULL, *node;
353 
354  g_return_if_fail (pw->docs_list_tree_view && GTK_IS_TREE_VIEW(pw->docs_list_tree_view));
355 
356  /* Get a list of open lots for this owner and post account */
357  if (pw->owner.owner.undefined)
358  list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc,
359  &pw->owner, NULL);
360 
361  /* Clear the existing list */
362  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
363  gtk_tree_selection_unselect_all (selection);
364  store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pw->docs_list_tree_view)));
365  gtk_list_store_clear(store);
366 
367  /* Add the documents and overpayments to the tree view */
368  for (node = list; node; node = node->next)
369  {
370  GNCLot *lot = node->data;
371  time64 doc_date_time = 0;
372  const gchar *doc_type_str = NULL;
373  const gchar *doc_id_str = NULL;
374  const gchar *doc_deb_str = NULL;
375  const gchar *doc_cred_str = NULL;
376  GtkTreeIter iter;
377  Timespec doc_date;
378  GncInvoice *document;
379  gnc_numeric value = gnc_numeric_zero();
380  gnc_numeric debit = gnc_numeric_zero();
381  gnc_numeric credit = gnc_numeric_zero();
382 
383  /* Find the lot's document if it exists,
384  * it could also be a prepayment lot. */
385  document = gncInvoiceGetInvoiceFromLot (lot);
386 
387  /* Find the document's date or pre-payment date */
388  if (document)
389  doc_date = gncInvoiceGetDatePosted (document);
390  else
391  {
392  /* Calculate the payment date based on the lot splits */
394  if (trans)
395  doc_date = xaccTransRetDatePostedTS (trans);
396  else
397  continue; /* No valid split in this lot, skip it */
398  }
399  doc_date_time = timespecToTime64 (doc_date);
400 
401  /* Find the document type. No type means pre-payment in this case */
402  if (document)
403  {
404  doc_type_str = gncInvoiceGetTypeString (document);
405  }
406  else
407  doc_type_str = _("Pre-Payment");
408 
409  /* Find the document id. Empty for pre-payments. */
410  if (document)
411  {
412  doc_id_str = gncInvoiceGetID (document);
413  }
414 
415  /* Find the debit/credit amount.
416  * Invoices/vendor credit notes are debit (increasing the balance)
417  * Customer credit notes/bills are credit (decreasing the balance)
418  * Pre-payments are debit or credit depending on their sign
419  */
420  value = gnc_lot_get_balance (lot);
421 
422  if (gnc_numeric_positive_p (value))
423  debit = value;
424  else
425  credit = gnc_numeric_neg (value);
426 
427  /* Only display non-zero debits/credits */
428  if (!gnc_numeric_zero_p (debit))
429  doc_deb_str = xaccPrintAmount (debit, gnc_default_print_info (FALSE));
430  if (!gnc_numeric_zero_p (credit))
431  doc_cred_str = xaccPrintAmount (credit, gnc_default_print_info (FALSE));
432 
433  gtk_list_store_append (store, &iter);
434  gtk_list_store_set (store, &iter,
435  0, doc_date_time,
436  1, doc_id_str,
437  2, doc_type_str,
438  3, doc_deb_str,
439  4, doc_cred_str,
440  5, (gpointer)lot,
441  -1);
442 
443  }
444 
445  g_list_free (list);
446 
447  /* Highlight the preset invoice if it's in the new list */
448  gnc_payment_dialog_highlight_document (pw);
449 }
450 
451 static void
452 gnc_payment_dialog_owner_changed (PaymentWindow *pw)
453 {
454  Account *last_acct = NULL;
455  GncGUID *guid = NULL;
456  GncOwner *owner = &pw->owner;
457 
458  /* If the owner changed, the initial invoice is no longer valid */
459  pw->invoice = NULL;
460 
461  /* Now handle the account tree */
463  "payment-last-account", &guid,
464  NULL);
465 
466  /* refresh the post and acc available accounts, but cleanup first */
467  if (pw->acct_types)
468  {
469  g_list_free(pw->acct_types);
470  pw->acct_types = NULL;
471  }
472 
473  if (pw->acct_commodities)
474  {
475  g_list_free(pw->acct_commodities);
476  pw->acct_commodities = NULL;
477  }
478 
479  pw->acct_types = gncOwnerGetAccountTypesList(owner);
480  if (gncOwnerIsValid(owner))
481  pw->acct_commodities = gncOwnerGetCommoditiesList (owner);
482  pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
483 
484  /* Update list of documents and pre-payments */
485  gnc_payment_window_fill_docs_list (pw);
486 
487  if (guid)
488  {
489  last_acct = xaccAccountLookup(guid, pw->book);
490  }
491 
492  /* Set the last-used transfer account, but only if we didn't
493  * create this dialog from a pre-existing transaction. */
494  if (last_acct && !gnc_payment_dialog_has_pre_existing_txn(pw))
495  {
496  gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(pw->acct_tree),
497  last_acct);
498  }
499 }
500 
501 static void
502 gnc_payment_dialog_post_to_changed (PaymentWindow *pw)
503 {
504  gnc_payment_window_fill_docs_list (pw);
505 }
506 
507 static void
508 gnc_payment_dialog_remember_account (PaymentWindow *pw, Account *acc)
509 {
510  QofInstance *owner = qofOwnerGetOwner (&pw->owner);
511  const GncGUID *guid;
512 
513  if (!acc) return;
514 
515  guid = xaccAccountGetGUID(acc);
516  qof_begin_edit (owner);
517  qof_instance_set (owner,
518  "payment-last-account", guid,
519  NULL);
520  qof_commit_edit (owner);
521 }
522 
523 
524 static void
525 gnc_payment_set_owner (PaymentWindow *pw, GncOwner *owner)
526 {
527  gnc_owner_set_owner (pw->owner_choice, owner);
528  gnc_payment_dialog_owner_changed(pw);
529 }
530 
531 static int
532 gnc_payment_dialog_owner_changed_cb (GtkWidget *widget, gpointer data)
533 {
534  PaymentWindow *pw = data;
535  GncOwner owner;
536 
537  if (!pw) return FALSE;
538 
539  gncOwnerCopy (&(pw->owner), &owner);
540  gnc_owner_get_owner (pw->owner_choice, &owner);
541 
542  /* If this owner really changed, then reset ourselves */
543  if (!gncOwnerEqual (&owner, &(pw->owner)))
544  {
545  gncOwnerCopy (&owner, &(pw->owner));
546  gnc_payment_dialog_owner_changed(pw);
547  }
548 
549  /* Reflect if the payment could complete now */
550  gnc_payment_window_check_payment (pw);
551 
552  return FALSE;
553 }
554 
555 void
556 gnc_payment_dialog_document_selection_changed_cb (GtkWidget *widget, gpointer data)
557 {
558  PaymentWindow *pw = data;
559 
560  if (!pw) return;
561 
562  gnc_payment_dialog_document_selection_changed (pw);
563 
564  /* Reflect if the payment could complete now */
565  gnc_payment_window_check_payment (pw);
566 }
567 
568 void
569 gnc_payment_dialog_xfer_acct_changed_cb (GtkWidget *widget, gpointer data)
570 {
571  PaymentWindow *pw = data;
572 
573  if (!pw) return;
574 
575  /* Reflect if the payment could complete now */
576  gnc_payment_window_check_payment (pw);
577 }
578 
579 int
580 gnc_payment_dialog_post_to_changed_cb (GtkWidget *widget, gpointer data)
581 {
582  PaymentWindow *pw = data;
583  Account *post_acct;
584 
585  if (!pw) return FALSE;
586 
587  post_acct = gnc_account_select_combo_get_active (pw->post_combo);
588 
589  /* If this invoice really changed, then reset ourselves */
590  if (post_acct != pw->post_acct)
591  {
592  pw->post_acct = post_acct;
593  gnc_payment_dialog_post_to_changed(pw);
594  }
595  else
596  gnc_payment_dialog_highlight_document (pw);
597 
598  /* Reflect if the payment could complete now */
599  gnc_payment_window_check_payment (pw);
600 
601  return FALSE;
602 }
603 
604 /*
605  * This helper function is called once for each row in the tree view
606  * that is currently selected. Its task is to add the corresponding
607  * lot to the end of a glist.
608  */
609 static void
610 get_selected_lots (GtkTreeModel *model,
611  GtkTreePath *path,
612  GtkTreeIter *iter,
613  gpointer data)
614 {
615  GList **return_list = data;
616  GNCLot *lot;
617  GValue value = { 0 };
618 
619  gtk_tree_model_get_value (model, iter, 5, &value);
620  lot = (GNCLot *) g_value_get_pointer (&value);
621  g_value_unset (&value);
622 
623  if (lot)
624  *return_list = g_list_insert_sorted (*return_list, lot, (GCompareFunc)gncOwnerLotsSortFunc);
625 }
626 
627 void
628 gnc_payment_ok_cb (GtkWidget *widget, gpointer data)
629 {
630  PaymentWindow *pw = data;
631  const char *text = NULL;
632 
633  if (!pw)
634  return;
635 
636  /* The gnc_payment_window_check_payment function
637  * ensures we have valid owner, post account, transfer account
638  * and amount so we can proceed with the payment.
639  * Note: make sure it's called before all entry points to this function !
640  */
641 
642  /* We're on our way out, stop watching for object changes that could
643  * trigger a gui refresh. Without this the gui suspend/resume
644  * pair could still trigger a gui update on the payment dialog
645  * before we close it. This is undesired because the lots may be in
646  * an inconsistent state until after all events are handled. So
647  * the gui refresh may result in a crash.
648  * See https://bugzilla.gnome.org/show_bug.cgi?id=740471
649  */
650  gnc_gui_component_clear_watches (pw->component_id);
651 
652  gnc_suspend_gui_refresh ();
653  {
654  const char *memo, *num;
655  Timespec date;
656  gnc_numeric exch = gnc_numeric_create(1, 1); //default to "one to one" rate
657  GList *selected_lots = NULL;
658  GtkTreeSelection *selection;
659  gboolean auto_pay;
660 
661  /* Obtain all our ancillary information */
662  memo = gtk_entry_get_text (GTK_ENTRY (pw->memo_entry));
663  num = gtk_entry_get_text (GTK_ENTRY (pw->num_entry));
664  date = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (pw->date_edit));
665 
666  /* Obtain the list of selected lots (documents/payments) from the dialog */
667  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
668  gtk_tree_selection_selected_foreach (selection, get_selected_lots, &selected_lots);
669 
670  /* When the payment amount is 0, the selected documents cancel each other out
671  * so no money is actually transferred.
672  * For non-zero payments money will be transferred between the post account
673  * and the transfer account. In that case if these two accounts don't have
674  * the same currency the user is asked to enter the exchange rate.
675  */
676  if (!gnc_numeric_zero_p (pw->amount_tot) &&
678  {
679  XferDialog* xfer;
680 
681  text = _("The transfer and post accounts are associated with different currencies. Please specify the conversion rate.");
682 
683  xfer = gnc_xfer_dialog(pw->dialog, pw->xfer_acct);
684  gnc_info_dialog(pw->dialog, "%s", text);
685 
686  gnc_xfer_dialog_select_to_account(xfer, pw->post_acct);
687  gnc_xfer_dialog_set_amount(xfer, pw->amount_tot);
688 
689  /* All we want is the exchange rate so prevent the user from thinking
690  it makes sense to mess with other stuff */
691  gnc_xfer_dialog_set_from_show_button_active(xfer, FALSE);
692  gnc_xfer_dialog_set_to_show_button_active(xfer, FALSE);
693  gnc_xfer_dialog_hide_from_account_tree(xfer);
694  gnc_xfer_dialog_hide_to_account_tree(xfer);
695  gnc_xfer_dialog_is_exchange_dialog(xfer, &exch);
696  gnc_xfer_dialog_run_until_done(xfer);
697  }
698 
699  /* Perform the payment */
700  if (gncOwnerGetType (&(pw->owner)) == GNC_OWNER_CUSTOMER)
701  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_INVOICE, GNC_PREF_AUTO_PAY);
702  else
703  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
704 
705  gncOwnerApplyPayment (&pw->owner, pw->pre_existing_txn, selected_lots,
706  pw->post_acct, pw->xfer_acct, pw->amount_tot,
707  exch, date, memo, num, auto_pay);
708  }
709  gnc_resume_gui_refresh ();
710 
711  /* Save the transfer account, xfer_acct */
712  gnc_payment_dialog_remember_account(pw, pw->xfer_acct);
713 
714  gnc_ui_payment_window_destroy (pw);
715 }
716 
717 void
718 gnc_payment_cancel_cb (GtkWidget *widget, gpointer data)
719 {
720  PaymentWindow *pw = data;
721  gnc_ui_payment_window_destroy (pw);
722 }
723 
724 void
725 gnc_payment_window_destroy_cb (GtkWidget *widget, gpointer data)
726 {
727  PaymentWindow *pw = data;
728 
729  if (!pw) return;
730 
731  gnc_unregister_gui_component (pw->component_id);
732 
733  g_list_free (pw->acct_types);
734  g_list_free (pw->acct_commodities);
735  g_free (pw);
736 }
737 
738 void
739 gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *path,
740  GtkTreeViewColumn *column, PaymentWindow *pw)
741 {
742  GtkTreeView *view;
743  GtkTreeModel *model;
744  GtkTreeIter iter;
745 
746  g_return_if_fail(widget);
747  view = GTK_TREE_VIEW(widget);
748 
749  model = gtk_tree_view_get_model(view);
750  if (gtk_tree_model_get_iter(model, &iter, path))
751  {
752  if (gtk_tree_model_iter_has_child(model, &iter))
753  {
754  /* There are children,
755  * just expand or collapse the row. */
756  if (gtk_tree_view_row_expanded(view, path))
757  gtk_tree_view_collapse_row(view, path);
758  else
759  gtk_tree_view_expand_row(view, path, FALSE);
760  }
761  else if (gnc_payment_window_check_payment (pw))
762  /* It's an account without any children
763  * If all conditions for a valid payment are met click the Ok button. */
764  gnc_payment_ok_cb(widget, pw);
765  }
766 }
767 
768 void
769 gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
770  PaymentWindow *pw)
771 {
772  gnc_numeric amount_deb, amount_cred, amount_tot;
773 
774  if (! pw->amount_credit_edit || ! pw->amount_debit_edit)
775  return;
776 
777  /* If both credit and debit amount are entered, simplify it to either one */
778  amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit));
779  amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit));
780  amount_tot = gnc_numeric_sub (amount_cred, amount_deb,
783 
784  gnc_ui_payment_window_set_amount (pw, amount_tot);
785 
786  /* Reflect if the payment could complete now */
787  gnc_payment_window_check_payment (pw);
788 }
789 
790 static gboolean AccountTypeOkForPayments (GNCAccountType type)
791 {
792  if (xaccAccountIsAssetLiabType(type) ||
794  return TRUE;
795  else
796  return FALSE;
797 }
798 
799 /* Select the list of accounts to show in the tree */
800 static void
801 gnc_payment_set_account_types (GncTreeViewAccount *tree)
802 {
803  AccountViewInfo avi;
804  int i;
805 
807 
808  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
809  avi.include_type[i] = AccountTypeOkForPayments (i);
810 
812 }
813 
814 static gboolean
815 find_handler (gpointer find_data, gpointer user_data)
816 {
817  PaymentWindow *pw = user_data;
818 
819  return (pw != NULL);
820 }
821 
822 static void print_date (GtkTreeViewColumn *tree_column,
823  GtkCellRenderer *cell,
824  GtkTreeModel *tree_model,
825  GtkTreeIter *iter,
826  gpointer data)
827 {
828  GValue value = { 0 };
829  time64 doc_date_time;
830  gchar *doc_date_str;
831 
832  g_return_if_fail (cell && iter && tree_model);
833 
834 
835  gtk_tree_model_get_value (tree_model, iter, 0, &value);
836  doc_date_time = (time64) g_value_get_int64 (&value);
837  g_value_unset (&value);
838  doc_date_str = qof_print_date (doc_date_time);
839  g_object_set (G_OBJECT (cell), "text", doc_date_str, NULL);
840  g_free (doc_date_str);
841 }
842 
843 static PaymentWindow *
844 new_payment_window (GncOwner *owner, QofBook *book, GncInvoice *invoice)
845 {
846  PaymentWindow *pw;
847  GtkBuilder *builder;
848  GtkWidget *box, *label, *credit_box, *debit_box;
849  GtkTreeSelection *selection;
850  GtkTreeViewColumn *column;
851  GtkCellRenderer *renderer;
852  char * cm_class = (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER ?
853  DIALOG_PAYMENT_CUSTOMER_CM_CLASS :
854  DIALOG_PAYMENT_VENDOR_CM_CLASS);
855 
856  /*
857  * Find an existing payment window. If found, bring it to
858  * the front. If we have an actual owner, then set it in
859  * the window.
860  */
861 
862  pw = gnc_find_first_gui_component (cm_class, find_handler, NULL);
863  if (pw)
864  {
865  if (gncOwnerIsValid(owner))
866  gnc_payment_set_owner (pw, owner);
867 
868  // Reset the setting about the pre-existing TXN
869  pw->pre_existing_txn = NULL;
870 
871  gtk_window_present (GTK_WINDOW(pw->dialog));
872  return(pw);
873  }
874 
875  /* Ok, we need a new window */
876 
877  pw = g_new0 (PaymentWindow, 1);
878  pw->book = book;
879  gncOwnerCopy (owner, &(pw->owner));
880 
881  /* Compute the post-to account types */
882  pw->acct_types = gncOwnerGetAccountTypesList (owner);
883 
884  if (gncOwnerIsValid(owner))
885  pw->acct_commodities = gncOwnerGetCommoditiesList (owner);
886 
887  /* Open and read the Glade File */
888  builder = gtk_builder_new();
889  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_hor_adj");
890  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_vert_adj");
891  gnc_builder_add_from_file (builder, "dialog-payment.glade", "docs_list_model");
892  gnc_builder_add_from_file (builder, "dialog-payment.glade", "post_combo_model");
893  gnc_builder_add_from_file (builder, "dialog-payment.glade", "Payment Dialog");
894  pw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "Payment Dialog"));
895 
896  /* Grab the widgets and build the dialog */
897  pw->payment_warning = GTK_WIDGET (gtk_builder_get_object (builder, "payment_warning"));
898  pw->ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "okbutton"));
899  pw->num_entry = GTK_WIDGET (gtk_builder_get_object (builder, "num_entry"));
900  pw->memo_entry = GTK_WIDGET (gtk_builder_get_object (builder, "memo_entry"));
901  pw->post_combo = GTK_WIDGET (gtk_builder_get_object (builder, "post_combo"));
902  gtk_combo_box_set_entry_text_column( GTK_COMBO_BOX( pw->post_combo ), 0 );
903  gnc_cbwe_require_list_item(GTK_COMBO_BOX(pw->post_combo));
904 
905  label = GTK_WIDGET (gtk_builder_get_object (builder, "owner_label"));
906  box = GTK_WIDGET (gtk_builder_get_object (builder, "owner_box"));
907  pw->owner_choice = gnc_owner_select_create (label, box, book, owner);
908 
909  /* Some terminology:
910  * Invoices are paid, credit notes are refunded.
911  * A customer payment is a credit action, paying a vendor is debit
912  *
913  * So depending on the owner the payment amount should be considered
914  * credit (customer) or debit (vendor/employee) and refunds should be
915  * considered debit (customer) or credit (vendor/employee).
916  * For visual consistency, the dialog box will always show a payment and
917  * a refund field. Internally they are treated as credit or debit depending
918  * on the owner type.
919  */
920  if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
921  {
922  debit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
923  credit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
924  }
925  else
926  {
927  debit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_payment_box"));
928  credit_box = GTK_WIDGET (gtk_builder_get_object (builder, "amount_refund_box"));
929  }
930 
931  pw->amount_debit_edit = gnc_amount_edit_new ();
932  gtk_box_pack_start (GTK_BOX (debit_box), pw->amount_debit_edit, TRUE, TRUE, 0);
933  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_debit_edit),
934  TRUE);
935  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit), gnc_numeric_zero());
936  g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(pw->amount_debit_edit))),
937  "focus-out-event",
938  G_CALLBACK(gnc_payment_leave_amount_cb), pw);
939 
940  pw->amount_credit_edit = gnc_amount_edit_new ();
941  gtk_box_pack_start (GTK_BOX (credit_box), pw->amount_credit_edit, TRUE, TRUE, 0);
942  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (pw->amount_credit_edit),
943  TRUE);
944  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit), gnc_numeric_zero());
945  g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(pw->amount_credit_edit))),
946  "focus-out-event",
947  G_CALLBACK(gnc_payment_leave_amount_cb), pw);
948 
949  box = GTK_WIDGET (gtk_builder_get_object (builder, "date_box"));
950  pw->date_edit = gnc_date_edit_new (time(NULL), FALSE, FALSE);
951  gtk_box_pack_start (GTK_BOX (box), pw->date_edit, TRUE, TRUE, 0);
952 
953  pw->docs_list_tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "docs_list_tree_view"));
954  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->docs_list_tree_view));
955  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
956 
957  /* Configure date column */
958  renderer = gtk_cell_renderer_text_new ();
959  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 0);
960  gtk_tree_view_column_pack_start (column, renderer, TRUE);
961  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
962  column, "31-12-2013");
963  gtk_tree_view_column_set_cell_data_func (column, renderer,
964  (GtkTreeCellDataFunc) print_date,
965  NULL, NULL);
966 
967  /* Configure document number column */
968  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 1);
969  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
970  column, "INV2013-016");
971 
972  /* Configure document type column */
973  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 2);
974  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
975  column, _("Credit Note"));
976 
977  /* Configure debit column */
978  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 3);
979  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
980  column, "11,999.00");
981 
982  /* Configure credit column */
983  column = gtk_tree_view_get_column (GTK_TREE_VIEW (pw->docs_list_tree_view), 4);
984  tree_view_column_set_default_width (GTK_TREE_VIEW (pw->docs_list_tree_view),
985  column, "11,999.00");
986 
987  gtk_tree_sortable_set_sort_column_id (
988  GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (pw->docs_list_tree_view))),
989  0, GTK_SORT_ASCENDING);
990 
991 
992  box = GTK_WIDGET (gtk_builder_get_object (builder, "acct_window"));
993  pw->acct_tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
994  gtk_container_add (GTK_CONTAINER (box), pw->acct_tree);
995  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(pw->acct_tree), FALSE);
996  gnc_payment_set_account_types (GNC_TREE_VIEW_ACCOUNT (pw->acct_tree));
997 
998  /* Set the dialog for the 'new' owner.
999  * Note that this also sets the post account tree. */
1000  gnc_payment_dialog_owner_changed(pw);
1001 
1002  /* Set the dialog for the 'new' invoice */
1003  pw->invoice = invoice;
1004  if (invoice)
1005  {
1006  Account *postacct = gncInvoiceGetPostedAcc (invoice);
1007  if (postacct)
1008  {
1009  gchar *acct_string = gnc_account_get_full_name (postacct);
1010  gnc_cbwe_set_by_string(GTK_COMBO_BOX(pw->post_combo), acct_string);
1011  gnc_payment_dialog_post_to_changed_cb (pw->post_combo, pw);
1012  g_free(acct_string);
1013  }
1014  }
1015 
1016  /* Setup signals */
1017  gtk_builder_connect_signals_full( builder,
1018  gnc_builder_connect_full_func,
1019  pw);
1020 
1021  g_signal_connect (G_OBJECT (pw->owner_choice), "changed",
1022  G_CALLBACK (gnc_payment_dialog_owner_changed_cb), pw);
1023 
1024  g_signal_connect (G_OBJECT (pw->acct_tree), "row-activated",
1025  G_CALLBACK (gnc_payment_acct_tree_row_activated_cb), pw);
1026 
1027  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pw->acct_tree));
1028  g_signal_connect (G_OBJECT (selection), "changed",
1029  G_CALLBACK (gnc_payment_dialog_xfer_acct_changed_cb), pw);
1030 
1031 
1032  /* Register with the component manager */
1033  pw->component_id =
1034  gnc_register_gui_component (cm_class,
1035  gnc_payment_window_refresh_handler,
1036  gnc_payment_window_close_handler,
1037  pw);
1038 
1039  /* Watch for any new or changed accounts */
1040  gnc_gui_component_watch_entity_type (pw->component_id,
1041  GNC_ID_ACCOUNT,
1042  QOF_EVENT_CREATE | QOF_EVENT_MODIFY |
1043  QOF_EVENT_DESTROY);
1044 
1045  /* Show it all */
1046  gtk_widget_show_all (pw->dialog);
1047  g_object_unref(G_OBJECT(builder));
1048 
1049  // The customer choice widget should have keyboard focus
1050  if (GNC_IS_GENERAL_SEARCH(pw->owner_choice))
1051  {
1052  gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(pw->owner_choice));
1053  }
1054 
1055  /* Reflect if the payment could complete now */
1056  gnc_payment_window_check_payment (pw);
1057 
1058  /* Warn the user if they have no valid post-to accounts */
1059  {
1060  const gchar *text;
1061  const char *acct_type;
1062 
1063  text = gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (GTK_COMBO_BOX(pw->post_combo)))));
1064 
1065  if (!text || g_strcmp0 (text, "") == 0)
1066  {
1067 
1068  /* The code below assumes there will only be one account type.
1069  * Let's assert this to protect from potential future changes. */
1070  g_assert (g_list_length (pw->acct_types) == 1);
1071  acct_type = xaccAccountGetTypeStr(GPOINTER_TO_INT(pw->acct_types->data));
1072  gnc_warning_dialog(pw->dialog,
1073  _("You have no valid \"Post To\" accounts. "
1074  "Please create an account of type \"%s\" "
1075  "before you continue to process this payment. "
1076  "Perhaps you want to create an Invoice or "
1077  "Bill first?"),
1078  acct_type);
1079  }
1080  }
1081 
1082  return pw;
1083 }
1084 
1085 
1086 void
1087 gnc_ui_payment_window_destroy (PaymentWindow *pw)
1088 {
1089  if (!pw) return;
1090  gnc_close_gui_component (pw->component_id);
1091 }
1092 
1093 PaymentWindow *
1094 gnc_ui_payment_new_with_invoice (const GncOwner *owner, QofBook *book,
1095  GncInvoice *invoice)
1096 {
1097  GncOwner owner_def;
1098 
1099  if (!book) return NULL;
1100  if (owner)
1101  {
1102  /* Figure out the company */
1103  gncOwnerCopy (gncOwnerGetEndOwner (owner), &owner_def);
1104  }
1105  else
1106  {
1107  gncOwnerInitCustomer (&owner_def, NULL);
1108  }
1109 
1110  return new_payment_window (&owner_def, book, invoice);
1111 }
1112 
1113 PaymentWindow *
1114 gnc_ui_payment_new (GncOwner *owner, QofBook *book)
1115 {
1116  return gnc_ui_payment_new_with_invoice (owner, book, NULL);
1117 }
1118 
1119 // ////////////////////////////////////////////////////////////
1120 static void increment_if_asset_account (gpointer data,
1121  gpointer user_data)
1122 {
1123  int *r = user_data;
1124  const Split *split = data;
1125  const Account *account = xaccSplitGetAccount(split);
1126  if (AccountTypeOkForPayments(xaccAccountGetType (account)))
1127  ++(*r);
1128 }
1129 static int countAssetAccounts(SplitList* slist)
1130 {
1131  int result = 0;
1132  g_list_foreach(slist, &increment_if_asset_account, &result);
1133  return result;
1134 }
1135 
1136 static gint predicate_is_asset_account(gconstpointer a,
1137  gconstpointer user_data)
1138 {
1139  const Split *split = a;
1140  const Account *account = xaccSplitGetAccount(split);
1141  if (AccountTypeOkForPayments(xaccAccountGetType(account)))
1142  return 0;
1143  else
1144  return -1;
1145 }
1146 static gint predicate_is_apar_account(gconstpointer a,
1147  gconstpointer user_data)
1148 {
1149  const Split *split = a;
1150  const Account *account = xaccSplitGetAccount(split);
1152  return 0;
1153  else
1154  return -1;
1155 }
1156 static Split *getFirstAssetAccountSplit(SplitList* slist)
1157 {
1158  GList *r = g_list_find_custom(slist, NULL, &predicate_is_asset_account);
1159  if (r)
1160  return r->data;
1161  else
1162  return NULL;
1163 }
1164 static Split *getFirstAPARAccountSplit(SplitList* slist)
1165 {
1166  GList *r = g_list_find_custom(slist, NULL, &predicate_is_apar_account);
1167  if (r)
1168  return r->data;
1169  else
1170  return NULL;
1171 }
1172 
1173 // ///////////////
1174 
1175 gboolean gnc_ui_payment_is_customer_payment(const Transaction *txn)
1176 {
1177  SplitList *slist;
1178  gboolean result = TRUE;
1179 
1180  Split *assetaccount_split;
1181  gnc_numeric amount;
1182 
1183  if (!txn)
1184  return result;
1185 
1186  // We require the txn to have one split in an A/R or A/P account.
1187 
1188  slist = xaccTransGetSplitList(txn);
1189  if (!slist)
1190  return result;
1191  if (countAssetAccounts(slist) == 0)
1192  {
1193  g_message("No asset splits in txn \"%s\"; cannot use this for assigning a payment.",
1195  return result;
1196  }
1197 
1198  assetaccount_split = getFirstAssetAccountSplit(slist);
1199  amount = xaccSplitGetValue(assetaccount_split);
1200  result = gnc_numeric_positive_p(amount); // positive amounts == customer
1201  //g_message("Amount=%s", gnc_numeric_to_string(amount));
1202  return result;
1203 }
1204 
1205 // ///////////////
1206 
1207 PaymentWindow * gnc_ui_payment_new_with_txn (GncOwner *owner, Transaction *txn)
1208 {
1209  SplitList *slist;
1210 
1211  Split *assetaccount_split;
1212  Split *postaccount_split;
1213  gnc_numeric amount;
1214  PaymentWindow *pw;
1215 
1216  if (!txn)
1217  return NULL;
1218 
1219  // We require the txn to have one split in an Asset account.
1220 
1221  slist = xaccTransGetSplitList(txn);
1222  if (!slist)
1223  return NULL;
1224  if (countAssetAccounts(slist) == 0)
1225  {
1226  g_message("No asset splits in txn \"%s\"; cannot use this for assigning a payment.",
1228  return NULL;
1229  }
1230 
1231  assetaccount_split = getFirstAssetAccountSplit(slist);
1232  postaccount_split = getFirstAPARAccountSplit(slist); // watch out: Might be NULL
1233  amount = xaccSplitGetValue(assetaccount_split);
1234 
1235  pw = gnc_ui_payment_new(owner,
1236  qof_instance_get_book(QOF_INSTANCE(txn)));
1237  g_assert(assetaccount_split); // we can rely on this because of the countAssetAccounts() check above
1238  g_debug("Amount=%s", gnc_numeric_to_string(amount));
1239 
1240  // Fill in the values from the given txn
1241  pw->pre_existing_txn = txn;
1242  gnc_ui_payment_window_set_num(pw, gnc_get_num_action(txn, assetaccount_split));
1243  gnc_ui_payment_window_set_memo(pw, xaccTransGetDescription(txn));
1244  {
1245  GDate txn_date = xaccTransGetDatePostedGDate (txn);
1246  gnc_ui_payment_window_set_date(pw, &txn_date);
1247  }
1248  gnc_ui_payment_window_set_amount(pw, amount);
1249  gnc_ui_payment_window_set_xferaccount(pw, xaccSplitGetAccount(assetaccount_split));
1250  if (postaccount_split)
1251  gnc_ui_payment_window_set_postaccount(pw, xaccSplitGetAccount(postaccount_split));
1252 
1253  return pw;
1254 }
void gnc_cbwe_set_by_string(GtkComboBox *cbwe, const gchar *text)
Definition: gnc-gtk-utils.c:41
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Definition: gncOwner.c:1401
void gnc_tree_view_account_get_view_info(GncTreeViewAccount *account_view, AccountViewInfo *avi)
void tree_view_column_set_default_width(GtkTreeView *view, GtkTreeViewColumn *column, const gchar *sizing_text)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
time64 timespecToTime64(Timespec ts)
Business Interface: Object OWNERs.
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
Date and Time handling routines.
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Definition: gncOwner.c:1383
QofBook * qof_instance_get_book(gconstpointer)
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
gtk helper routines.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
void qof_instance_set(QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Definition: gncOwner.c:382
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
void gnc_tree_view_account_set_view_info(GncTreeViewAccount *account_view, AccountViewInfo *avi)
gchar * gnc_numeric_to_string(gnc_numeric n)
gboolean qof_commit_edit(QofInstance *inst)
gboolean gncOwnerIsValid(const GncOwner *owner)
Definition: gncOwner.c:650
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
Definition: gncOwner.c:253
Definition: guid.h:65
Split * gnc_lot_get_latest_split(GNCLot *lot)
Definition: gnc-lot.c:660
char * qof_print_date(time64 secs)
gboolean qof_begin_edit(QofInstance *inst)
#define xaccAccountGetGUID(X)
Definition: Account.h:239
gboolean xaccAccountIsAssetLiabType(GNCAccountType t)
Definition: Account.c:4212
GList SplitList
Definition: gnc-engine.h:203
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
Account handling public routines.
void gncOwnerApplyPayment(const GncOwner *owner, Transaction *txn, GList *lots, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, Timespec date, const char *memo, const char *num, gboolean auto_pay)
Definition: gncOwner.c:1348
GtkTreeView implementation for gnucash account tree.
gint gncOwnerLotsSortFunc(GNCLot *lotA, GNCLot *lotB)
Definition: gncOwner.c:679
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
gboolean xaccAccountIsAPARType(GNCAccountType t)
Definition: Account.c:4225
GNCAccountType
Definition: Account.h:96
gboolean gnc_numeric_positive_p(gnc_numeric a)
Generic api to store and retrieve preferences.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:201
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Definition: gncOwner.c:550
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Definition: gncInvoice.c:1174
Business Invoice Interface.
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
gboolean gncOwnerLotMatchOwnerFunc(GNCLot *lot, gpointer user_data)
Definition: gncOwner.c:657
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
Timespec xaccTransRetDatePostedTS(const Transaction *trans)
Definition: Transaction.c:2243
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
gint64 time64
Definition: gnc-date.h:83
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
LotList * xaccAccountFindOpenLots(const Account *acc, gboolean(*match_func)(GNCLot *lot, gpointer user_data), gpointer user_data, GCompareFunc sort_func)
Definition: Account.c:3751
const char * xaccAccountGetTypeStr(GNCAccountType type)
Definition: Account.c:4137
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Definition: Transaction.c:2250
API for Transactions and Splits (journal entries)
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
gboolean xaccAccountIsEquityType(GNCAccountType t)
Definition: Account.c:4237
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
Definition: Account.c:1827