GnuCash  5.6-150-g038405b370+
dialog-invoice.c
1 /*
2  * dialog-invoice.c -- Dialog for Invoice entry
3  * Copyright (C) 2001,2002,2006 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  *
6  * Copyright (c) 2005,2006 David Hampton <hampton@employees.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, contact:
20  *
21  * Free Software Foundation Voice: +1-617-542-5942
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
23  * Boston, MA 02110-1301, USA gnu@gnu.org
24  */
25 
26 #include <config.h>
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <libguile.h>
31 #include "swig-runtime.h"
32 
33 #include "qof.h"
34 
35 #include "dialog-utils.h"
36 #include "gnc-component-manager.h"
37 #include "gnc-ui.h"
38 #include "gnc-gui-query.h"
39 #include "gnc-prefs.h"
40 #include "gnc-ui-util.h"
41 #include "gnc-date.h"
42 #include "gnc-date-edit.h"
43 #include "gnc-amount-edit.h"
44 #include "gnucash-sheet.h"
45 #include "gnucash-register.h"
46 #include "window-report.h"
47 #include "dialog-search.h"
48 #include "search-param.h"
49 #include "gnc-session.h"
50 #include "gncOwner.h"
51 #include "gncInvoice.h"
52 #include "gncInvoiceP.h"
53 #include <gnc-glib-utils.h>
54 
55 #include "gncEntryLedger.h"
56 
57 #include "gnc-plugin-page.h"
58 #include "gnc-general-search.h"
59 #include "dialog-date-close.h"
60 #include "dialog-invoice.h"
61 #include "dialog-job.h"
62 #include "business-gnome-utils.h"
63 #include "dialog-payment.h"
64 #include "dialog-tax-table.h"
65 #include "dialog-billterms.h"
66 #include "dialog-account.h"
67 #include "guile-mappings.h"
68 #include "dialog-dup-trans.h"
69 
70 #include "dialog-query-view.h"
71 
72 #include "gnc-plugin-business.h"
74 #include "gnc-plugin-page-report.h"
75 #include "gnc-main-window.h"
76 #include "gnc-state.h"
77 
78 #include "dialog-doclink.h"
79 #include "dialog-doclink-utils.h"
80 #include "dialog-transfer.h"
81 #include "gnc-uri-utils.h"
82 #include "gnc-report-combo.h"
83 
84 #define DIALOG_NEW_INVOICE_CM_CLASS "dialog-new-invoice"
85 #define DIALOG_VIEW_INVOICE_CM_CLASS "dialog-view-invoice"
86 
87 #define GNC_PREFS_GROUP_CUSTOMER "dialogs.customer-due"
88 #define GNC_PREFS_GROUP_VENDOR "dialogs.vendor-due"
89 
90 #define GNC_PREFS_GROUP_SEARCH "dialogs.business.invoice-search"
91 #define GNC_PREF_NOTIFY_WHEN_DUE "notify-when-due"
92 #define GNC_PREF_ACCUM_SPLITS "accumulate-splits"
93 #define GNC_PREF_DAYS_IN_ADVANCE "days-in-advance"
94 
95 void gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data);
96 void gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data);
97 void gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data);
98 void gnc_invoice_type_toggled_cb (GtkWidget *widget, gpointer data);
99 void gnc_invoice_id_changed_cb (GtkWidget *widget, gpointer data);
100 void gnc_invoice_terms_changed_cb (GtkWidget *widget, gpointer data);
101 
102 #define ENUM_INVOICE_TYPE(_) \
103  _(NEW_INVOICE, ) \
104  _(MOD_INVOICE, ) \
105  _(DUP_INVOICE, ) \
106  _(EDIT_INVOICE, ) \
107  _(VIEW_INVOICE, )
108 
109 DEFINE_ENUM(InvoiceDialogType, ENUM_INVOICE_TYPE)
110 AS_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
111 FROM_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
112 
113 FROM_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
114 AS_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
115 
116 typedef enum
117 {
118  DUE_FOR_VENDOR, // show bills due
119  DUE_FOR_CUSTOMER, // show invoices due
120 } GncWhichDueType;
123 {
124  QofBook *book;
125  GncOwner *owner;
126  QofQuery *q;
127  GncOwner owner_def;
128 };
129 
130 #define UNUSED_VAR __attribute__ ((unused))
131 
132 static QofLogModule UNUSED_VAR log_module = G_LOG_DOMAIN; //G_LOG_BUSINESS;
133 
139 struct _invoice_window
140 {
141  GtkBuilder * builder;
142 
143  GtkWidget * dialog; /* Used by 'New Invoice Window' */
144  GncPluginPage *page; /* Used by 'Edit Invoice' Page */
145  const gchar * page_state_name; /* Used for loading open state information */
146 
147  /* Summary Bar Widgets */
148  GtkWidget * total_label;
149  GtkWidget * total_cash_label;
150  GtkWidget * total_charge_label;
151  GtkWidget * total_subtotal_label;
152  GtkWidget * total_tax_label;
153 
154  /* Data Widgets */
155  GtkWidget * info_label; /*Default in glade is "Invoice Information"*/
156  GtkWidget * id_label; /* Default in glade is Invoice ID */
157  GtkWidget * type_label;
158  GtkWidget * type_label_hbox;
159  GtkWidget * type_hbox;
160  GtkWidget * type_choice;
161  GtkWidget * id_entry;
162  GtkWidget * notes_text;
163  GtkWidget * opened_date;
164  GtkWidget * posted_date_hbox;
165  GtkWidget * posted_date;
166  GtkWidget * active_check;
167  GtkWidget * paid_label;
168 
169  GtkWidget * doclink_button;
170 
171  GtkWidget * owner_box;
172  GtkWidget * owner_label;
173  GtkWidget * owner_choice;
174  GtkWidget * job_label;
175  GtkWidget * job_box;
176  GtkWidget * job_choice;
177  GtkWidget * billing_id_entry;
178  GtkWidget * terms_menu;
179 
180  /* Project Widgets (used for Bills only) */
181  GtkWidget * proj_frame;
182  GtkWidget * proj_cust_box;
183  GtkWidget * proj_cust_choice;
184  GtkWidget * proj_job_box;
185  GtkWidget * proj_job_choice;
186 
187  /* Expense Voucher Widgets */
188  GtkWidget * to_charge_frame;
189  GtkWidget * to_charge_edit;
190 
191  gint width;
192 
193  GncBillTerm * terms;
194  GnucashRegister * reg;
195  GncEntryLedger * ledger;
196 
197  invoice_sort_type_t last_sort;
198 
199  InvoiceDialogType dialog_type;
200  GncGUID invoice_guid;
201  gboolean is_credit_note;
202  gint component_id;
203  QofBook * book;
204  GncInvoice * created_invoice;
205  GncOwner owner;
206  GncOwner job;
207 
208  GncOwner proj_cust;
209  GncOwner proj_job;
210 
211  /* the cached reportPage for this invoice. note this is not saved
212  into .gcm file therefore the invoice editor->report link is lost
213  upon restart. */
214  GncPluginPage *reportPage;
215 
216  /* for Unposting */
217  gboolean reset_tax_tables;
218 };
219 
220 /* Forward definitions for CB functions */
221 void gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data);
222 gboolean gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data);
223 DialogQueryView *gnc_invoice_show_docs_due (GtkWindow *parent, QofBook *book, double days_in_advance, GncWhichDueType duetype);
224 
225 #define INV_WIDTH_PREFIX "invoice_reg"
226 #define BILL_WIDTH_PREFIX "bill_reg"
227 #define VOUCHER_WIDTH_PREFIX "voucher_reg"
228 
229 static void gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget);
230 static InvoiceWindow * gnc_ui_invoice_modify (GtkWindow *parent, GncInvoice *invoice);
231 
232 /*******************************************************************************/
233 /* FUNCTIONS FOR ACCESSING DATA STRUCTURE FIELDS */
234 
235 static GtkWidget *
236 iw_get_window (InvoiceWindow *iw)
237 {
238  if (iw->page)
239  return gnc_plugin_page_get_window (iw->page);
240  return iw->dialog;
241 }
242 
243 GtkWidget *
244 gnc_invoice_get_register (InvoiceWindow *iw)
245 {
246  if (iw)
247  return (GtkWidget *)iw->reg;
248  return NULL;
249 }
250 
251 GtkWidget *
252 gnc_invoice_get_notes (InvoiceWindow *iw)
253 {
254  if (iw)
255  return (GtkWidget *)iw->notes_text;
256  return NULL;
257 }
258 
259 /*******************************************************************************/
260 /* FUNCTIONS FOR UNPOSTING */
261 
262 static gboolean
263 iw_ask_unpost (InvoiceWindow *iw)
264 {
265  GtkWidget *dialog;
266  GtkToggleButton *toggle;
267  GtkBuilder *builder;
268  gint response;
269  const gchar *style_label = NULL;
270  GncOwnerType owner_type = gncOwnerGetType (&iw->owner);
271 
272 
273  builder = gtk_builder_new();
274  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "unpost_message_dialog");
275  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "unpost_message_dialog"));
276  toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object (builder, "yes_tt_reset"));
277 
278  switch (owner_type)
279  {
280  case GNC_OWNER_VENDOR:
281  style_label = "gnc-class-vendors";
282  break;
283  case GNC_OWNER_EMPLOYEE:
284  style_label = "gnc-class-employees";
285  break;
286  default:
287  style_label = "gnc-class-customers";
288  break;
289  }
290  // Set a secondary style context for this page so it can be easily manipulated with css
291  gnc_widget_style_context_add_class (GTK_WIDGET(dialog), style_label);
292 
293  gtk_window_set_transient_for (GTK_WINDOW(dialog),
294  GTK_WINDOW(iw_get_window(iw)));
295 
296  iw->reset_tax_tables = FALSE;
297 
298  gtk_widget_show_all(dialog);
299 
300  response = gtk_dialog_run(GTK_DIALOG(dialog));
301  if (response == GTK_RESPONSE_OK)
302  iw->reset_tax_tables =
303  gtk_toggle_button_get_active(toggle);
304 
305  gtk_widget_destroy(dialog);
306  g_object_unref(G_OBJECT(builder));
307 
308  return (response == GTK_RESPONSE_OK);
309 }
310 
311 /*******************************************************************************/
312 /* INVOICE WINDOW */
313 
314 static GncInvoice *
315 iw_get_invoice (InvoiceWindow *iw)
316 {
317  if (!iw)
318  return NULL;
319 
320  return gncInvoiceLookup (iw->book, &iw->invoice_guid);
321 }
322 
323 GncInvoice *
324 gnc_invoice_window_get_invoice (InvoiceWindow *iw)
325 {
326  if (!iw)
327  return NULL;
328 
329  return iw_get_invoice (iw);
330 }
331 
332 GtkWidget *
333 gnc_invoice_window_get_doclink_button (InvoiceWindow *iw)
334 {
335  if (!iw)
336  return NULL;
337 
338  return iw->doclink_button;
339 }
340 
341 static void
342 set_gncEntry_switch_type (gpointer data, gpointer user_data)
343 {
344  GncEntry *entry = data;
345  //g_warning("Modifying date for entry with desc=\"%s\"", gncEntryGetDescription(entry));
346 
348 }
349 
350 static void
351 set_gncEntry_date(gpointer data, gpointer user_data)
352 {
353  GncEntry *entry = data;
354  time64 new_date = *(time64*) user_data;
355  //g_warning("Modifying date for entry with desc=\"%s\"", gncEntryGetDescription(entry));
356 
357  gncEntrySetDate(entry, gnc_time64_get_day_neutral (new_date));
358  /*gncEntrySetDateEntered(entry, *new_date); - don't modify this
359  * because apparently it defines the ordering of the entries,
360  * which we don't want to change. */
361 }
362 
363 static void gnc_ui_to_invoice (InvoiceWindow *iw, GncInvoice *invoice)
364 {
365  GtkTextBuffer* text_buffer;
366  GtkTextIter start, end;
367  gchar *text;
368  time64 time;
369  gboolean is_credit_note = gncInvoiceGetIsCreditNote (invoice);
370 
371  if (iw->dialog_type == VIEW_INVOICE)
372  return;
373 
374  gnc_suspend_gui_refresh ();
375 
376  gncInvoiceBeginEdit (invoice);
377 
378  if (iw->active_check)
379  gncInvoiceSetActive (invoice, gtk_toggle_button_get_active
380  (GTK_TOGGLE_BUTTON (iw->active_check)));
381 
382  text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
383  gtk_text_buffer_get_bounds (text_buffer, &start, &end);
384  text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
385  gncInvoiceSetNotes (invoice, text);
386 
387  if (iw->to_charge_edit)
388  gncInvoiceSetToChargeAmount (invoice,
389  gnc_amount_edit_get_amount
390  (GNC_AMOUNT_EDIT (iw->to_charge_edit)));
391 
392  time = gnc_date_edit_get_date (GNC_DATE_EDIT (iw->opened_date));
393 
394  /* Only set these values for NEW/MOD INVOICE types */
395  if (iw->dialog_type != EDIT_INVOICE)
396  {
397  gncInvoiceSetID (invoice, gtk_entry_get_text (GTK_ENTRY (iw->id_entry)));
398  gncInvoiceSetBillingID (invoice, gtk_entry_get_text (GTK_ENTRY (iw->billing_id_entry)));
399  gncInvoiceSetTerms (invoice, iw->terms);
400 
401  gncInvoiceSetDateOpened (invoice, time);
402 
403  gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
404  if (iw->job_choice)
405  gnc_owner_get_owner (iw->job_choice, &(iw->job));
406 
407  /* Only set the job if we've actually got one */
408  if (gncOwnerGetJob (&(iw->job)))
409  gncInvoiceSetOwner (invoice, &(iw->job));
410  else
411  gncInvoiceSetOwner (invoice, &(iw->owner));
412 
413  /* Set the invoice currency based on the owner */
414  gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (&iw->owner));
415 
416  /* Only set the BillTo if we've actually got one */
417  if (gncOwnerGetJob (&iw->proj_job))
418  gncInvoiceSetBillTo (invoice, &iw->proj_job);
419  else
420  gncInvoiceSetBillTo (invoice, &iw->proj_cust);
421  }
422 
423  /* Document type can only be modified for a new or duplicated invoice/credit note */
424  if (iw->dialog_type == NEW_INVOICE || iw->dialog_type == DUP_INVOICE)
425  {
426  /* Update the entry dates to match the invoice date. This only really
427  * should happen for a duplicate invoice. However as a new invoice has
428  * no entries we can run this unconditionally. */
429  g_list_foreach(gncInvoiceGetEntries(invoice),
430  &set_gncEntry_date, &time);
431 
432 
433  gncInvoiceSetIsCreditNote (invoice, iw->is_credit_note);
434  }
435 
436  /* If the document type changed on a duplicated invoice,
437  * its entries should be updated
438  */
439  if (iw->dialog_type == DUP_INVOICE && iw->is_credit_note != is_credit_note)
440  {
441  g_list_foreach(gncInvoiceGetEntries(invoice),
442  &set_gncEntry_switch_type, NULL);
443  }
444 
445  gncInvoiceCommitEdit (invoice);
446  gnc_resume_gui_refresh ();
447  g_free (text);
448 }
449 
450 static gboolean
451 gnc_invoice_window_verify_ok (InvoiceWindow *iw)
452 {
453  const char *res;
454  gchar *string;
455 
456  /* save the current entry in the ledger? */
457  if (!gnc_entry_ledger_check_close (iw_get_window(iw), iw->ledger))
458  return FALSE;
459 
460  /* Check the Owner */
461  gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
462  res = gncOwnerGetName (&(iw->owner));
463  if (res == NULL || g_strcmp0 (res, "") == 0)
464  {
465  gnc_error_dialog (GTK_WINDOW (iw_get_window(iw)), "%s",
466  /* Translators: In this context,
467  'Billing information' maps to the
468  label in the frame and means
469  e.g. customer i.e. the company being
470  invoiced. */
471  _("You need to supply Billing Information."));
472  return FALSE;
473  }
474 
475  /* Check the ID; set one if necessary */
476  res = gtk_entry_get_text (GTK_ENTRY (iw->id_entry));
477  if (g_strcmp0 (res, "") == 0)
478  {
479  /* Invoices and bills have separate counters.
480  Therefore we pass the GncOwer to gncInvoiceNextID
481  so it knows whether we are creating a bill
482  or an invoice. */
483  string = gncInvoiceNextID(iw->book, &(iw->owner));
484  gtk_entry_set_text (GTK_ENTRY (iw->id_entry), string);
485  g_free(string);
486  }
487 
488  return TRUE;
489 }
490 
491 static gboolean
492 gnc_invoice_window_ok_save (InvoiceWindow *iw)
493 {
494  if (!gnc_invoice_window_verify_ok (iw))
495  return FALSE;
496 
497  {
498  GncInvoice *invoice = iw_get_invoice (iw);
499  if (invoice)
500  {
501  gnc_ui_to_invoice (iw, invoice);
502  }
503  /* Save the invoice to return it later. */
504  iw->created_invoice = invoice;
505  }
506  return TRUE;
507 }
508 
509 void
510 gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data)
511 {
512  InvoiceWindow *iw = data;
513 
514  if (!gnc_invoice_window_ok_save (iw))
515  return;
516 
517  /* Ok, we don't need this anymore */
518  iw->invoice_guid = *guid_null ();
519 
520  /* if this is a new or duplicated invoice, and created_invoice is NON-NULL,
521  * then open up a new window with the invoice. This used to be done
522  * in gnc_ui_invoice_new() but cannot be done anymore
523  */
524  if ((iw->dialog_type == NEW_INVOICE || iw->dialog_type == DUP_INVOICE)
525  && iw->created_invoice)
526  gnc_ui_invoice_edit (gnc_ui_get_main_window (iw->dialog), iw->created_invoice);
527 
528  gnc_close_gui_component (iw->component_id);
529 }
530 
531 void
532 gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data)
533 {
534  InvoiceWindow *iw = data;
535 
536  gnc_close_gui_component (iw->component_id);
537 }
538 
539 void
540 gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data)
541 {
542  InvoiceWindow *iw = data;
543  GncOwnerType owner_type = gncOwnerGetType (&iw->owner);
544 
545  switch(owner_type)
546  {
547  case GNC_OWNER_CUSTOMER:
548  gnc_gnome_help (GTK_WINDOW(iw->dialog), DF_MANUAL, DL_USAGE_INVOICE);
549  break;
550  case GNC_OWNER_VENDOR:
551  gnc_gnome_help (GTK_WINDOW(iw->dialog), DF_MANUAL, DL_USAGE_BILL);
552  break;
553  default:
554  gnc_gnome_help (GTK_WINDOW(iw->dialog), DF_MANUAL, DL_USAGE_VOUCHER);
555  break;
556  }
557 }
558 
559 static const gchar *
560 gnc_invoice_window_get_state_group (InvoiceWindow *iw)
561 {
562  switch (gncOwnerGetType (gncOwnerGetEndOwner (&iw->owner)))
563  {
564  case GNC_OWNER_VENDOR:
565  return "Vendor documents";
566  break;
567  case GNC_OWNER_EMPLOYEE:
568  return "Employee documents";
569  break;
570  default:
571  return "Customer documents";
572  break;
573  }
574 }
575 
576 /* Save user state layout information for Invoice/Bill/Voucher
577  * documents so it can be used for the default user set layout
578  */
579 void
580 gnc_invoice_window_save_document_layout_to_user_state (InvoiceWindow *iw)
581 {
582  Table *table = gnc_entry_ledger_get_table (iw->ledger);
583  const gchar *group = gnc_invoice_window_get_state_group (iw);
584 
585  gnc_table_save_state (table, group);
586 }
587 
588 /* Removes the user state layout information for Invoice/Bill/Voucher
589  * documents and also resets the current layout to the built-in defaults
590  */
591 void
592 gnc_invoice_window_reset_document_layout_and_clear_user_state (InvoiceWindow *iw)
593 {
594  GnucashRegister *reg = iw->reg;
595  const gchar *group = gnc_invoice_window_get_state_group (iw);
596 
597  gnucash_register_reset_sheet_layout (reg);
599 }
600 
601 /* Checks to see if there is user state layout information for
602  * Invoice/Bill/Voucher documents so it can be used for the
603  * default user layout
604  */
605 gboolean
606 gnc_invoice_window_document_has_user_state (InvoiceWindow *iw)
607 {
608  GKeyFile *state_file = gnc_state_get_current ();
609  const gchar *group = gnc_invoice_window_get_state_group (iw);
610  return g_key_file_has_group (state_file, group);
611 }
612 
613 void
614 gnc_invoice_window_destroy_cb (GtkWidget *widget, gpointer data)
615 {
616  InvoiceWindow *iw = data;
617  GncInvoice *invoice = iw_get_invoice (iw);
618 
619  gnc_suspend_gui_refresh ();
620 
621  if ((iw->dialog_type == NEW_INVOICE || iw->dialog_type == DUP_INVOICE)
622  && invoice != NULL)
623  {
624  gncInvoiceRemoveEntries (invoice);
625  gncInvoiceBeginEdit (invoice);
626  gncInvoiceDestroy (invoice);
627  iw->invoice_guid = *guid_null ();
628  }
629 
630  gtk_widget_destroy(widget);
631  gnc_entry_ledger_destroy (iw->ledger);
632  gnc_unregister_gui_component (iw->component_id);
633  g_object_unref (G_OBJECT (iw->builder));
634  gnc_resume_gui_refresh ();
635 
636  g_free (iw);
637 }
638 
639 void
640 gnc_invoice_window_editCB (GtkWindow *parent, gpointer data)
641 {
642  InvoiceWindow *iw = data;
643  GncInvoice *invoice = iw_get_invoice (iw);
644 
645  if (invoice)
646  gnc_ui_invoice_modify (parent, invoice);
647 }
648 
649 void
650 gnc_invoice_window_duplicateInvoiceCB (GtkWindow *parent, gpointer data)
651 {
652  InvoiceWindow *iw = data;
653  GncInvoice *invoice = iw_get_invoice (iw);
654 
655  if (invoice)
656  gnc_ui_invoice_duplicate (parent, invoice, TRUE, NULL);
657 }
658 
659 void gnc_invoice_window_entryUpCB (GtkWidget *widget, gpointer data)
660 {
661  InvoiceWindow *iw = data;
662  if (!iw || !iw->ledger)
663  return;
664 
666 }
667 void gnc_invoice_window_entryDownCB (GtkWidget *widget, gpointer data)
668 {
669  InvoiceWindow *iw = data;
670  if (!iw || !iw->ledger)
671  return;
672 
674 }
675 
676 void
677 gnc_invoice_window_recordCB (GtkWidget *widget, gpointer data)
678 {
679  InvoiceWindow *iw = data;
680 
681  if (!iw || !iw->ledger)
682  return;
683 
684  if (!gnc_entry_ledger_commit_entry (iw->ledger))
685  return;
686 
687  gnucash_register_goto_next_virt_row (iw->reg);
688 }
689 
690 void
691 gnc_invoice_window_cancelCB (GtkWidget *widget, gpointer data)
692 {
693  InvoiceWindow *iw = data;
694 
695  if (!iw || !iw->ledger)
696  return;
697 
698  gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
699 }
700 
701 void
702 gnc_invoice_window_deleteCB (GtkWidget *widget, gpointer data)
703 {
704  InvoiceWindow *iw = data;
705  GncEntry *entry;
706 
707  if (!iw || !iw->ledger)
708  return;
709 
710  /* get the current entry based on cursor position */
711  entry = gnc_entry_ledger_get_current_entry (iw->ledger);
712  if (!entry)
713  {
714  gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
715  return;
716  }
717 
718  /* deleting the blank entry just cancels */
719  if (entry == gnc_entry_ledger_get_blank_entry (iw->ledger))
720  {
721  gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
722  return;
723  }
724 
725  /* Verify that the user really wants to delete this entry */
726  {
727  const char *message = _("Are you sure you want to delete the "
728  "selected entry?");
729  const char *order_warn = _("This entry is attached to an order and "
730  "will be deleted from that as well!");
731  char *msg;
732  gboolean result;
733 
734  if (gncEntryGetOrder (entry))
735  msg = g_strconcat (message, "\n\n", order_warn, (char *)NULL);
736  else
737  msg = g_strdup (message);
738 
739  result = gnc_verify_dialog (GTK_WINDOW (iw_get_window(iw)), FALSE, "%s", msg);
740  g_free (msg);
741 
742  if (!result)
743  return;
744  }
745 
746  /* Yep, let's delete */
747  gnc_entry_ledger_delete_current_entry (iw->ledger);
748  return;
749 }
750 
751 void
752 gnc_invoice_window_duplicateCB (GtkWidget *widget, gpointer data)
753 {
754  InvoiceWindow *iw = data;
755 
756  if (!iw || !iw->ledger)
757  return;
758 
759  gnc_entry_ledger_duplicate_current_entry (iw->ledger);
760 }
761 
762 void
763 gnc_invoice_window_blankCB (GtkWidget *widget, gpointer data)
764 {
765  InvoiceWindow *iw = data;
766 
767  if (!iw || !iw->ledger)
768  return;
769 
770  if (!gnc_entry_ledger_commit_entry (iw->ledger))
771  return;
772 
773  {
774  VirtualCellLocation vcell_loc;
775  GncEntry *blank;
776 
777  blank = gnc_entry_ledger_get_blank_entry (iw->ledger);
778  if (blank == NULL)
779  return;
780 
781  if (gnc_entry_ledger_get_entry_virt_loc (iw->ledger, blank, &vcell_loc))
782  gnucash_register_goto_virt_cell (iw->reg, vcell_loc);
783  }
784 }
786 typedef struct dialog_args
787 {
788  GtkProgressBar *pb;
789  GtkWidget *dialog;
790  gdouble timeout;
791 } dialog_args;
792 
793 static gboolean
794 update_progress_bar (gpointer user_data)
795 {
796  dialog_args *args = user_data;
797  GtkProgressBar *pb = args->pb;
798  gdouble frac = gtk_progress_bar_get_fraction (pb);
799  gdouble step = 0.1 / (args->timeout);
800 
801  frac -= step;
802 
803  if (frac < step)
804  {
805  gtk_dialog_response (GTK_DIALOG(args->dialog), GTK_RESPONSE_OK);
806  return FALSE;
807  }
808  gtk_progress_bar_set_fraction (pb, frac);
809  return TRUE;
810 }
811 
812 static void
813 combo_popped_cb (GObject *gobject,
814  GParamSpec *pspec,
815  gpointer user_data)
816 {
817  gboolean popup_shown;
818 
819  g_object_get (G_OBJECT(gobject), "popup-shown", &popup_shown, NULL);
820 
821  if (popup_shown)
822  g_source_remove_by_user_data (user_data);
823 }
824 
825 static gboolean
826 dialog_key_press_event_cb (GtkWidget *widget, GdkEventKey *event,
827  gpointer user_data)
828 {
829  g_source_remove_by_user_data (user_data);
830  return FALSE;
831 }
832 
833 static void
834 combo_changed_cb (GtkComboBox *widget, gpointer user_data)
835 {
836  g_source_remove_by_user_data (user_data);
837 }
838 
839 /* This function will return the selected invoice report guid if
840  * the countdown times out or a selection is made and OK pressed.
841  *
842  * If cancel is pressed then it will return NULL
843  */
844 static char*
845 use_default_report_template_or_change (GtkWindow *parent)
846 {
847  QofBook *book = gnc_get_current_book ();
848  GtkWidget *combo;
849  GtkBuilder *builder;
850  GtkWidget *dialog;
851  GtkWidget *ok_button;
852  GtkWidget *report_combo_hbox;
853  GtkWidget *progress_bar;
854  GtkWidget *label;
855  gchar *ret_guid = NULL;
856  gchar *rep_guid = NULL;
857  gchar *rep_name = NULL;
858  gboolean warning_visible = FALSE;
859  gint result;
860  gdouble timeout;
861  dialog_args *args;
862 
864 
865  combo = gnc_default_invoice_report_combo ("gnc:custom-report-invoice-template-guids");
866 
868  rep_guid = gnc_get_default_invoice_print_report ();
869 
870  gnc_report_combo_set_active (GNC_REPORT_COMBO(combo),
871  rep_guid,
872  rep_name);
873  g_free (rep_guid);
874  g_free (rep_name);
875 
876  warning_visible = gnc_report_combo_is_warning_visible_for_active (GNC_REPORT_COMBO(combo));
877 
878  // When timeout is 0, only return if warning not visible
879  if (timeout == 0 && !warning_visible)
880  return gnc_get_default_invoice_print_report ();
881 
882  builder = gtk_builder_new ();
883  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "invoice_print_dialog");
884 
885  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "invoice_print_dialog"));
886 
887  gtk_window_set_transient_for (GTK_WINDOW(dialog), parent);
888 
889  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
890 
891  ok_button = GTK_WIDGET(gtk_builder_get_object (builder, "ok_button"));
892  report_combo_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "report_combo_hbox"));
893  progress_bar = GTK_WIDGET(gtk_builder_get_object (builder, "progress_bar"));
894  label = GTK_WIDGET(gtk_builder_get_object (builder, "label"));
895 
896  gtk_box_pack_start (GTK_BOX(report_combo_hbox), GTK_WIDGET(combo), TRUE, TRUE, 0);
897 
898  gtk_widget_grab_focus (ok_button);
899 
900  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar), 1);
901 
902  args = g_malloc (sizeof(dialog_args));
903  args->dialog = dialog;
904  args->pb = GTK_PROGRESS_BAR(progress_bar);
905  args->timeout = timeout;
906 
907  gtk_widget_show_all (dialog);
908 
909  g_object_unref (G_OBJECT(builder));
910 
911  g_signal_connect (G_OBJECT(combo), "changed",
912  G_CALLBACK(combo_changed_cb), args);
913 
914  g_signal_connect (G_OBJECT(dialog), "key_press_event",
915  G_CALLBACK(dialog_key_press_event_cb), args);
916 
917  g_signal_connect (G_OBJECT(combo), "notify::popup-shown",
918  G_CALLBACK (combo_popped_cb), args);
919 
920  // if warning visible, do not add args timeout, wait for user
921  if (warning_visible)
922  {
923  gtk_label_set_text (GTK_LABEL(label),
924  N_("Choose a different report template or Printable Invoice will be used"));
925  gtk_widget_hide (GTK_WIDGET(progress_bar));
926  }
927  else
928  g_timeout_add (100, update_progress_bar, args);
929 
930  result = gtk_dialog_run (GTK_DIALOG(dialog));
931 
932  g_source_remove_by_user_data (args);
933 
934  if (result == GTK_RESPONSE_OK)
935  ret_guid = gnc_report_combo_get_active_guid (GNC_REPORT_COMBO(combo));
936 
937  gtk_widget_destroy (dialog);
938  g_free (args);
939 
940  return ret_guid;
941 }
942 
943 static GncPluginPage *
944 gnc_invoice_window_print_invoice (GtkWindow *parent, GncInvoice *invoice,
945  const gchar *report_guid)
946 {
947  SCM func, arg, arg2;
948  SCM args = SCM_EOL;
949  SCM is_invoice_guid;
950  SCM scm_guid;
951  int report_id;
952  const gchar *use_report_guid = NULL;
953  GncPluginPage *reportPage = NULL;
954 
955  g_return_val_if_fail (invoice, NULL);
956 
957  is_invoice_guid = scm_c_eval_string ("gnc:report-is-invoice-report?");
958  scm_guid = scm_from_utf8_string (report_guid);
959 
960  if (scm_is_false (scm_call_1 (is_invoice_guid, scm_guid)))
961  use_report_guid = gnc_get_builtin_default_invoice_print_report (); // fallback if the option lookup failed
962  else
963  use_report_guid = report_guid;
964 
965  func = scm_c_eval_string ("gnc:invoice-report-create");
966  g_return_val_if_fail (scm_is_procedure (func), NULL);
967 
968  arg = SWIG_NewPointerObj(invoice, SWIG_TypeQuery("_p__gncInvoice"), 0);
969  arg2 = scm_from_utf8_string (use_report_guid);
970  args = scm_cons2 (arg, arg2, args);
971 
972  /* scm_gc_protect_object(func); */
973 
974  arg = scm_apply (func, args, SCM_EOL);
975  g_return_val_if_fail (scm_is_exact (arg), NULL);
976  report_id = scm_to_int (arg);
977 
978  /* scm_gc_unprotect_object(func); */
979  if (report_id >= 0)
980  {
981  reportPage = gnc_plugin_page_report_new (report_id);
982  gnc_main_window_open_page (GNC_MAIN_WINDOW (parent), reportPage);
983  }
984  return reportPage;
985 }
986 
987 static gboolean
988 equal_fn (gpointer find_data, gpointer elt_data)
989 {
990  return (find_data && (find_data == elt_data));
991 }
992 
993 /* From the invoice editor, open the invoice report. This will reuse the
994  invoice report if generated from the current invoice editor. Note the
995  link is lost when GnuCash is restarted. This link may be restored
996  by: scan the current session tabs, identify reports, checking
997  whereby report's report-type matches an invoice report, and the
998  report's invoice option value matches the current invoice. */
999 void
1000 gnc_invoice_window_printCB (GtkWindow* parent, gpointer data)
1001 {
1002  InvoiceWindow *iw = data;
1003 
1004  if (gnc_find_first_gui_component (WINDOW_REPORT_CM_CLASS, equal_fn,
1005  iw->reportPage))
1006  gnc_plugin_page_report_reload (GNC_PLUGIN_PAGE_REPORT (iw->reportPage));
1007  else
1008  {
1009  gchar *report_guid = use_default_report_template_or_change (parent);
1010 
1011  if (!report_guid)
1012  return;
1013 
1014  iw->reportPage = gnc_invoice_window_print_invoice (parent,
1015  iw_get_invoice (iw),
1016  report_guid);
1017  g_free (report_guid);
1018  }
1019  gnc_main_window_open_page (GNC_MAIN_WINDOW (iw->dialog), iw->reportPage);
1020 }
1021 
1022 static gboolean
1023 gnc_dialog_post_invoice(InvoiceWindow *iw, char *message,
1024  time64 *ddue, time64 *postdate,
1025  char **memo, Account **acc, gboolean *accumulate)
1026 {
1027  GncInvoice *invoice;
1028  char *ddue_label, *post_label, *acct_label, *question_label;
1029  GList * acct_types = NULL;
1030  GList * acct_commodities = NULL;
1031  QofInstance *owner_inst;
1032  EntryList *entries, *entries_iter;
1033 
1034  invoice = iw_get_invoice (iw);
1035  if (!invoice)
1036  return FALSE;
1037 
1038  ddue_label = _("Due Date");
1039  post_label = _("Post Date");
1040  acct_label = _("Post to Account");
1041  question_label = _("Accumulate Splits?");
1042 
1043  /* Determine the type of account to post to */
1044  acct_types = gncOwnerGetAccountTypesList (&(iw->owner));
1045 
1046  /* Determine which commodity we're working with */
1047  acct_commodities = gncOwnerGetCommoditiesList(&(iw->owner));
1048 
1049  /* Get the invoice entries */
1050  entries = gncInvoiceGetEntries (invoice);
1051 
1052  /* Find the most suitable post date.
1053  * For Customer Invoices that would be today.
1054  * For Vendor Bills and Employee Vouchers
1055  * that would be the date of the most recent invoice entry.
1056  * Failing that, today is used as a fallback */
1057  *postdate = gnc_time(NULL);
1058 
1059  if (entries && ((gncInvoiceGetOwnerType (invoice) == GNC_OWNER_VENDOR) ||
1060  (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)))
1061  {
1062  *postdate = gncEntryGetDate ((GncEntry*)entries->data);
1063  for (entries_iter = entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
1064  {
1065  time64 entrydate = gncEntryGetDate ((GncEntry*)entries_iter->data);
1066  if (entrydate > *postdate)
1067  *postdate = entrydate;
1068  }
1069  }
1070 
1071  /* Get the due date and posted account */
1072  *ddue = *postdate;
1073  *memo = NULL;
1074  {
1075  GncGUID *guid = NULL;
1076  owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
1077  qof_instance_get (owner_inst,
1078  "invoice-last-posted-account", &guid,
1079  NULL);
1080  *acc = xaccAccountLookup (guid, iw->book);
1081  }
1082  /* Get the default for the accumulate option */
1083  *accumulate = gnc_prefs_get_bool(GNC_PREFS_GROUP_INVOICE, GNC_PREF_ACCUM_SPLITS);
1084 
1085  if (!gnc_dialog_dates_acct_question_parented (iw_get_window(iw), message, ddue_label,
1086  post_label, acct_label, question_label, TRUE, TRUE,
1087  acct_types, acct_commodities, iw->book, iw->terms,
1088  ddue, postdate, memo, acc, accumulate))
1089  return FALSE;
1090 
1091  return TRUE;
1092 }
1094 struct post_invoice_params
1095 {
1096  time64 ddue; /* Due date */
1097  time64 postdate; /* Date posted */
1098  char *memo; /* Memo for posting transaction */
1099  Account *acc; /* Account to post to */
1100  gboolean accumulate; /* Whether to accumulate splits */
1101  GtkWindow *parent;
1102 };
1103 
1104 static void
1105 gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
1106 {
1107  GncInvoice *invoice;
1108  char *message, *memo;
1109  Account *acc = NULL;
1110  time64 ddue, postdate;
1111  gboolean accumulate;
1112  QofInstance *owner_inst;
1113  const char *text;
1114  GHashTable *foreign_currs;
1115  GHashTableIter foreign_currs_iter;
1116  gpointer key,value;
1117  gboolean is_cust_doc, auto_pay;
1118  gboolean show_dialog = TRUE;
1119  gboolean post_ok = TRUE;
1120 
1121  /* Make sure the invoice is ok */
1122  if (!gnc_invoice_window_verify_ok (iw))
1123  return;
1124 
1125  invoice = iw_get_invoice (iw);
1126  if (!invoice)
1127  return;
1128 
1129  /* Check that there is at least one Entry */
1130  if (gncInvoiceGetEntries (invoice) == NULL)
1131  {
1132  gnc_error_dialog (GTK_WINDOW (iw_get_window(iw)), "%s",
1133  _("The Invoice must have at least one Entry."));
1134  return;
1135  }
1136 
1137  is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
1138 
1139  /* Ok, we can post this invoice. Ask for verification, set the due date,
1140  * post date, and posted account
1141  */
1142  if (post_params)
1143  {
1144  ddue = post_params->ddue;
1145  postdate = post_params->postdate;
1146  // Dup it since it will free it below
1147  memo = g_strdup (post_params->memo);
1148  acc = post_params->acc;
1149  accumulate = post_params->accumulate;
1150  }
1151  else
1152  {
1153  message = _("Do you really want to post the invoice?");
1154  if (!gnc_dialog_post_invoice(iw, message,
1155  &ddue, &postdate, &memo, &acc, &accumulate))
1156  return;
1157  }
1158 
1159  /* Yep, we're posting. So, save the invoice...
1160  * Note that we can safely ignore the return value; we checked
1161  * the verify_ok earlier, so we know it's ok.
1162  * Additionally make sure the invoice has the owner's currency
1163  * refer to https://bugs.gnucash.org/show_bug.cgi?id=728074
1164  */
1165  gnc_suspend_gui_refresh ();
1166  gncInvoiceBeginEdit (invoice);
1167  gnc_invoice_window_ok_save (iw);
1168  gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (gncInvoiceGetOwner (invoice)));
1169 
1170  /* Fill in the conversion prices with feedback from the user */
1171  text = _("One or more of the entries are for accounts different from the invoice/bill currency. You will be asked to enter a conversion rate for each.");
1172 
1173  /* Ask the user for conversion rates for all foreign currencies
1174  * (relative to the invoice currency) */
1175  foreign_currs = gncInvoiceGetForeignCurrencies (invoice);
1176  g_hash_table_iter_init (&foreign_currs_iter, foreign_currs);
1177  while (g_hash_table_iter_next (&foreign_currs_iter, &key, &value))
1178  {
1179  GNCPrice *convprice;
1180  gnc_commodity *account_currency = (gnc_commodity*)key;
1181  gnc_numeric *amount = (gnc_numeric*)value;
1182  XferDialog *xfer;
1183  gnc_numeric exch_rate;
1184 
1185 
1186  /* Explain to the user we're about to ask for an exchange rate.
1187  * Only show this dialog once, right before the first xfer dialog pops up.
1188  */
1189  if (show_dialog)
1190  {
1191  gnc_info_dialog(GTK_WINDOW (iw_get_window(iw)), "%s", text);
1192  show_dialog = FALSE;
1193  }
1194 
1195  /* Note some twisted logic here:
1196  * We ask the exchange rate
1197  * FROM invoice currency
1198  * TO other account currency
1199  * Because that's what happens logically.
1200  * But the internal posting logic works backwards:
1201  * It searches for an exchange rate
1202  * FROM other account currency
1203  * TO invoice currency
1204  * So we will store the inverted exchange rate
1205  */
1206 
1207  /* create the exchange-rate dialog */
1208  xfer = gnc_xfer_dialog (iw_get_window(iw), acc);
1209  gnc_xfer_dialog_is_exchange_dialog(xfer, &exch_rate);
1210  gnc_xfer_dialog_select_to_currency(xfer, account_currency);
1211  gnc_xfer_dialog_set_date (xfer, postdate);
1212  /* Even if amount is 0 ask for an exchange rate. It's required
1213  * for the transaction generating code. Use an amount of 1 in
1214  * that case as the dialog won't allow to specify an exchange
1215  * rate for 0. */
1216  gnc_xfer_dialog_set_amount(xfer, gnc_numeric_zero_p (*amount) ?
1217  (gnc_numeric){1, 1} : *amount);
1218  /* If we already had an exchange rate from a previous post operation,
1219  * set it here */
1220  convprice = gncInvoiceGetPrice (invoice, account_currency);
1221  if (convprice)
1222  {
1223  exch_rate = gnc_price_get_value (convprice);
1224  /* Invert the exchange rate as explained above */
1225  if (!gnc_numeric_zero_p (exch_rate))
1226  {
1227  exch_rate = gnc_numeric_div ((gnc_numeric){1, 1}, exch_rate,
1229  gnc_xfer_dialog_set_price_edit (xfer, exch_rate);
1230  }
1231  }
1232 
1233  /* All we want is the exchange rate so prevent the user from thinking
1234  it makes sense to mess with other stuff */
1235  gnc_xfer_dialog_set_from_show_button_active(xfer, FALSE);
1236  gnc_xfer_dialog_set_to_show_button_active(xfer, FALSE);
1237  gnc_xfer_dialog_hide_from_account_tree(xfer);
1238  gnc_xfer_dialog_hide_to_account_tree(xfer);
1239  if (gnc_xfer_dialog_run_until_done(xfer))
1240  {
1241  /* User finished the transfer dialog successfully */
1242 
1243  /* Invert the exchange rate as explained above */
1244  if (!gnc_numeric_zero_p (exch_rate))
1245  exch_rate = gnc_numeric_div ((gnc_numeric){1, 1}, exch_rate,
1247  convprice = gnc_price_create(iw->book);
1248  gnc_price_begin_edit (convprice);
1249  gnc_price_set_commodity (convprice, account_currency);
1250  gnc_price_set_currency (convprice, gncInvoiceGetCurrency (invoice));
1251  gnc_price_set_time64 (convprice, postdate);
1252  gnc_price_set_source (convprice, PRICE_SOURCE_TEMP);
1253  gnc_price_set_typestr (convprice, PRICE_TYPE_LAST);
1254  gnc_price_set_value (convprice, exch_rate);
1255  gncInvoiceAddPrice(invoice, convprice);
1256  gnc_price_commit_edit (convprice);
1257  }
1258  else
1259  {
1260  /* User canceled the transfer dialog, abort posting */
1261  post_ok = FALSE;
1262  goto cleanup;
1263  }
1264  }
1265 
1266 
1267  /* Save account as last used account in the owner's
1268  * invoice-last-posted-account property.
1269  */
1270  owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
1271  {
1272  const GncGUID *guid = qof_instance_get_guid (QOF_INSTANCE (acc));
1273  qof_begin_edit (owner_inst);
1274  qof_instance_set (owner_inst,
1275  "invoice-last-posted-account", guid,
1276  NULL);
1277  qof_commit_edit (owner_inst);
1278  }
1279 
1280  /* ... post it ... */
1281  if (is_cust_doc)
1282  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_INVOICE, GNC_PREF_AUTO_PAY);
1283  else
1284  auto_pay = gnc_prefs_get_bool (GNC_PREFS_GROUP_BILL, GNC_PREF_AUTO_PAY);
1285 
1286  gncInvoicePostToAccount (invoice, acc, postdate, ddue, memo, accumulate, auto_pay);
1287 
1288 cleanup:
1289  gncInvoiceCommitEdit (invoice);
1290  g_hash_table_unref (foreign_currs);
1291  gnc_resume_gui_refresh ();
1292 
1293  if (memo)
1294  g_free (memo);
1295 
1296  if (post_ok)
1297  {
1298  /* Reset the type; change to read-only! */
1299  iw->dialog_type = VIEW_INVOICE;
1300  gnc_entry_ledger_set_readonly (iw->ledger, TRUE);
1301  }
1302  else
1303  {
1304  text = _("The post action was canceled because not all exchange rates were given.");
1305  gnc_info_dialog(GTK_WINDOW (iw_get_window(iw)), "%s", text);
1306  }
1307 
1308  /* ... and redisplay here. */
1309  gnc_invoice_update_window (iw, NULL);
1310  gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
1311 }
1312 
1313 void
1314 gnc_invoice_window_postCB (GtkWidget *unused_widget, gpointer data)
1315 {
1316  InvoiceWindow *iw =data;
1317  gnc_invoice_post(iw, NULL);
1318 }
1319 
1320 void
1321 gnc_invoice_window_unpostCB (GtkWidget *widget, gpointer data)
1322 {
1323  InvoiceWindow *iw = data;
1324  GncInvoice *invoice;
1325  gboolean result;
1326 
1327  invoice = iw_get_invoice (iw);
1328  if (!invoice)
1329  return;
1330 
1331  /* make sure the user REALLY wants to do this! */
1332  result = iw_ask_unpost(iw);
1333  if (!result) return;
1334 
1335  /* Attempt to unpost the invoice */
1336  gnc_suspend_gui_refresh ();
1337  result = gncInvoiceUnpost (invoice, iw->reset_tax_tables);
1338  gnc_resume_gui_refresh ();
1339  if (!result) return;
1340 
1341  /* if we get here, we succeeded in unposting -- reset the ledger and redisplay */
1342  iw->dialog_type = EDIT_INVOICE;
1343  gnc_entry_ledger_set_readonly (iw->ledger, FALSE);
1344  gnc_invoice_update_window (iw, NULL);
1345  gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
1346 }
1347 
1348 void gnc_invoice_window_cut_cb (GtkWidget *widget, gpointer data)
1349 {
1350  InvoiceWindow *iw = data;
1351  gnucash_register_cut_clipboard (iw->reg);
1352 }
1353 
1354 void gnc_invoice_window_copy_cb (GtkWidget *widget, gpointer data)
1355 {
1356  InvoiceWindow *iw = data;
1357  gnucash_register_copy_clipboard (iw->reg);
1358 }
1359 
1360 void gnc_invoice_window_paste_cb (GtkWidget *widget, gpointer data)
1361 {
1362  InvoiceWindow *iw = data;
1363  gnucash_register_paste_clipboard (iw->reg);
1364 }
1365 
1366 void gnc_invoice_window_new_invoice_cb (GtkWindow *parent, gpointer data)
1367 {
1368  InvoiceWindow *iw = data;
1369  if (gncOwnerGetJob (&iw->job))
1370  {
1371  gnc_ui_invoice_new (parent, &iw->job, iw->book);
1372  }
1373  else
1374  {
1375  gnc_ui_invoice_new (parent, &iw->owner, iw->book);
1376  }
1377 }
1378 
1379 void gnc_business_call_owner_report (GtkWindow *parent, GncOwner *owner, Account *acc)
1380 {
1381  gnc_business_call_owner_report_with_enddate (parent, owner, acc, INT64_MAX);
1382 }
1383 
1384 void gnc_business_call_owner_report_with_enddate (GtkWindow *parent,
1385  GncOwner *owner,
1386  Account *acc,
1387  time64 enddate)
1388 {
1389  int id;
1390  SCM args;
1391  SCM func;
1392  SCM arg;
1393 
1394  g_return_if_fail (owner);
1395 
1396  args = SCM_EOL;
1397 
1398  func = scm_c_eval_string ("gnc:owner-report-create-with-enddate");
1399  g_return_if_fail (scm_is_procedure (func));
1400 
1401  /* set the enddate */
1402  arg = (enddate != INT64_MAX) ? scm_from_int64 (enddate) : SCM_BOOL_F;
1403  args = scm_cons (arg, args);
1404 
1405  if (acc)
1406  {
1407  swig_type_info * qtype = SWIG_TypeQuery("_p_Account");
1408  g_return_if_fail (qtype);
1409 
1410  arg = SWIG_NewPointerObj(acc, qtype, 0);
1411  g_return_if_fail (arg != SCM_UNDEFINED);
1412  args = scm_cons (arg, args);
1413  }
1414  else
1415  {
1416  args = scm_cons (SCM_BOOL_F, args);
1417  }
1418 
1419  arg = SWIG_NewPointerObj(owner, SWIG_TypeQuery("_p__gncOwner"), 0);
1420  g_return_if_fail (arg != SCM_UNDEFINED);
1421  args = scm_cons (arg, args);
1422 
1423  /* Apply the function to the args */
1424  arg = scm_apply (func, args, SCM_EOL);
1425  g_return_if_fail (scm_is_exact (arg));
1426  id = scm_to_int (arg);
1427 
1428  if (id >= 0)
1429  reportWindow (id, parent);
1430 }
1431 
1432 void gnc_invoice_window_report_owner_cb (GtkWindow *parent, gpointer data)
1433 {
1434  InvoiceWindow *iw = data;
1435  gnc_business_call_owner_report (parent, &iw->owner, NULL);
1436 }
1437 
1438 void gnc_invoice_window_payment_cb (GtkWindow *parent, gpointer data)
1439 {
1440  InvoiceWindow *iw = data;
1441  GncInvoice *invoice = iw_get_invoice(iw);
1442 
1443  if (gncOwnerGetJob (&iw->job))
1444  gnc_ui_payment_new_with_invoice (parent, &iw->job, iw->book, invoice);
1445  else
1446  gnc_ui_payment_new_with_invoice (parent, &iw->owner, iw->book, invoice);
1447 }
1448 
1449 /* Sorting callbacks */
1450 
1451 void
1452 gnc_invoice_window_sort (InvoiceWindow *iw, invoice_sort_type_t sort_code)
1453 {
1454  QofQuery *query = gnc_entry_ledger_get_query (iw->ledger);
1455  GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
1456 
1457  if (iw->last_sort == sort_code)
1458  return;
1459 
1460  standard = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
1461 
1462  switch (sort_code)
1463  {
1464  case INVSORT_BY_STANDARD:
1465  p1 = standard;
1466  break;
1467  case INVSORT_BY_DATE:
1468  p1 = g_slist_prepend (p1, ENTRY_DATE);
1469  p2 = standard;
1470  break;
1471  case INVSORT_BY_DATE_ENTERED:
1472  p1 = g_slist_prepend (p1, ENTRY_DATE_ENTERED);
1473  p2 = standard;
1474  break;
1475  case INVSORT_BY_DESC:
1476  p1 = g_slist_prepend (p1, ENTRY_DESC);
1477  p2 = standard;
1478  break;
1479  case INVSORT_BY_QTY:
1480  p1 = g_slist_prepend (p1, ENTRY_QTY);
1481  p2 = standard;
1482  break;
1483  case INVSORT_BY_PRICE:
1484  p1 = g_slist_prepend (p1, ((iw->owner.type == GNC_OWNER_CUSTOMER) ?
1485  ENTRY_IPRICE : ENTRY_BPRICE));
1486  p2 = standard;
1487  break;
1488  default:
1489  g_slist_free (standard);
1490  g_return_if_fail (FALSE);
1491  break;
1492  }
1493 
1494  qof_query_set_sort_order (query, p1, p2, p3);
1495  iw->last_sort = sort_code;
1496  gnc_entry_ledger_display_refresh (iw->ledger);
1497 }
1498 
1499 /* Window configuration callbacks */
1500 
1501 void
1502 gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data)
1503 {
1504  InvoiceWindow *iw = data;
1505  GncInvoice *invoice = iw_get_invoice(iw);
1506 
1507  if (!invoice) return;
1508 
1509  gncInvoiceSetActive (invoice,
1510  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
1511 }
1512 
1513 gboolean
1514 gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event,
1515  gpointer data)
1516 {
1517  InvoiceWindow *iw = data;
1518  GncInvoice *invoice = iw_get_invoice(iw);
1519  GtkTextBuffer* text_buffer;
1520  GtkTextIter start, end;
1521  gchar *text;
1522 
1523  if (!invoice) return FALSE;
1524 
1525  text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
1526  gtk_text_buffer_get_bounds (text_buffer, &start, &end);
1527  text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
1528  gncInvoiceSetNotes (invoice, text);
1529  g_free (text);
1530  return FALSE;
1531 }
1532 
1533 static gboolean
1534 gnc_invoice_window_leave_to_charge_cb (GtkWidget *widget, GdkEventFocus *event,
1535  gpointer data)
1536 {
1537  gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(data), NULL);
1538  return FALSE;
1539 }
1540 
1541 static void
1542 gnc_invoice_window_changed_to_charge_cb (GtkWidget *widget, gpointer data)
1543 {
1544  InvoiceWindow *iw = data;
1545  GncInvoice *invoice = iw_get_invoice(iw);
1546 
1547  if (!invoice) return;
1548 
1549  gncInvoiceSetToChargeAmount (invoice, gnc_amount_edit_get_amount
1550  (GNC_AMOUNT_EDIT (widget)));
1551 }
1552 
1553 static GtkWidget *
1554 add_summary_label (GtkWidget *summarybar, const char *label_str)
1555 {
1556  GtkWidget *hbox;
1557  GtkWidget *label;
1558 
1559  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1560  gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
1561  gtk_box_pack_start (GTK_BOX(summarybar), hbox, FALSE, FALSE, 5);
1562 
1563  label = gtk_label_new (label_str);
1564  gnc_label_set_alignment (label, 1.0, 0.5);
1565  gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1566 
1567  label = gtk_label_new ("");
1568  gnc_label_set_alignment (label, 1.0, 0.5);
1569  gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
1570 
1571  return label;
1572 }
1573 
1574 GtkWidget *
1575 gnc_invoice_window_create_summary_bar (InvoiceWindow *iw)
1576 {
1577  GtkWidget *summarybar;
1578 
1579  iw->total_label = NULL;
1580  iw->total_cash_label = NULL;
1581  iw->total_charge_label = NULL;
1582  iw->total_subtotal_label = NULL;
1583  iw->total_tax_label = NULL;
1584 
1585  summarybar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
1586  gtk_box_set_homogeneous (GTK_BOX (summarybar), FALSE);
1587  gtk_widget_set_name (summarybar, "gnc-id-summarybar");
1588 
1589  iw->total_label = add_summary_label (summarybar, _("Total:"));
1590 
1591  switch (gncOwnerGetType (&iw->owner))
1592  {
1593  case GNC_OWNER_CUSTOMER:
1594  case GNC_OWNER_VENDOR:
1595  iw->total_subtotal_label = add_summary_label (summarybar, _("Subtotal:"));
1596  iw->total_tax_label = add_summary_label (summarybar, _("Tax:"));
1597  break;
1598 
1599  case GNC_OWNER_EMPLOYEE:
1600  iw->total_cash_label = add_summary_label (summarybar, _("Total Cash:"));
1601  iw->total_charge_label = add_summary_label (summarybar, _("Total Charge:"));
1602  break;
1603 
1604  default:
1605  break;
1606  }
1607 
1608  gtk_widget_show_all(summarybar);
1609  return summarybar;
1610 }
1611 
1612 static int
1613 gnc_invoice_job_changed_cb (GtkWidget *widget, gpointer data)
1614 {
1615  InvoiceWindow *iw = data;
1616  char const *msg = "";
1617 
1618  if (!iw)
1619  return FALSE;
1620 
1621  if (iw->dialog_type == VIEW_INVOICE)
1622  return FALSE;
1623 
1624  gnc_owner_get_owner (iw->job_choice, &(iw->job));
1625 
1626  if (iw->dialog_type == EDIT_INVOICE)
1627  return FALSE;
1628 
1629  msg = gncJobGetReference (gncOwnerGetJob (&(iw->job)));
1630  gtk_entry_set_text (GTK_ENTRY (iw->billing_id_entry), msg ? msg : "");
1631 
1632  return FALSE;
1633 
1634 }
1635 
1636 static GNCSearchWindow *
1637 gnc_invoice_select_job_cb (GtkWindow *parent, gpointer jobp, gpointer user_data)
1638 {
1639  GncJob *j = jobp;
1640  InvoiceWindow *iw = user_data;
1641  GncOwner owner, *ownerp;
1642 
1643  if (!iw) return NULL;
1644 
1645  if (j)
1646  {
1647  ownerp = gncJobGetOwner (j);
1648  gncOwnerCopy (ownerp, &owner);
1649  }
1650  else
1651  gncOwnerCopy (&(iw->owner), &owner);
1652 
1653  return gnc_job_search (parent, j, &owner, iw->book);
1654 }
1655 
1656 static void
1657 gnc_invoice_update_job_choice (InvoiceWindow *iw)
1658 {
1659  if (iw->job_choice)
1660  gtk_container_remove (GTK_CONTAINER (iw->job_box), iw->job_choice);
1661 
1662  /* If we don't have a real owner, then we obviously can't have a job */
1663  if (iw->owner.owner.undefined == NULL)
1664  {
1665  iw->job_choice = NULL;
1666  }
1667  else
1668  switch (iw->dialog_type)
1669  {
1670  case VIEW_INVOICE:
1671  case EDIT_INVOICE:
1672  iw->job_choice =
1673  gnc_owner_edit_create (NULL, iw->job_box, iw->book, &(iw->job));
1674  break;
1675  case NEW_INVOICE:
1676  case MOD_INVOICE:
1677  case DUP_INVOICE:
1678  iw->job_choice =
1679  gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select…"), TRUE,
1680  gnc_invoice_select_job_cb, iw, iw->book);
1681 
1682  gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
1683  gncOwnerGetJob (&iw->job));
1684  gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->job_choice),
1685  TRUE);
1686  gtk_box_pack_start (GTK_BOX (iw->job_box), iw->job_choice,
1687  TRUE, TRUE, 0);
1688 
1689  g_signal_connect (G_OBJECT (iw->job_choice), "changed",
1690  G_CALLBACK (gnc_invoice_job_changed_cb), iw);
1691  break;
1692  }
1693 
1694  if (iw->job_choice)
1695  gtk_widget_show_all (iw->job_choice);
1696 }
1697 
1698 static GNCSearchWindow *
1699 gnc_invoice_select_proj_job_cb (GtkWindow *parent, gpointer jobp, gpointer user_data)
1700 {
1701  GncJob *j = jobp;
1702  InvoiceWindow *iw = user_data;
1703  GncOwner owner, *ownerp;
1704 
1705  if (!iw) return NULL;
1706 
1707  if (j)
1708  {
1709  ownerp = gncJobGetOwner (j);
1710  gncOwnerCopy (ownerp, &owner);
1711  }
1712  else
1713  gncOwnerCopy (&(iw->proj_cust), &owner);
1714 
1715  return gnc_job_search (parent, j, &owner, iw->book);
1716 }
1717 
1718 static int
1719 gnc_invoice_proj_job_changed_cb (GtkWidget *widget, gpointer data)
1720 {
1721  InvoiceWindow *iw = data;
1722 
1723  if (!iw)
1724  return FALSE;
1725 
1726  if (iw->dialog_type == VIEW_INVOICE)
1727  return FALSE;
1728 
1729  gnc_owner_get_owner (iw->proj_job_choice, &(iw->proj_job));
1730  return FALSE;
1731 }
1732 
1733 static void
1734 gnc_invoice_update_proj_job (InvoiceWindow *iw)
1735 {
1736  if (iw->proj_job_choice)
1737  gtk_container_remove (GTK_CONTAINER (iw->proj_job_box),
1738  iw->proj_job_choice);
1739 
1740  switch (iw->dialog_type)
1741  {
1742  case VIEW_INVOICE:
1743  case EDIT_INVOICE:
1744  iw->proj_job_choice =
1745  gnc_owner_edit_create (NULL, iw->proj_job_box, iw->book, &(iw->proj_job));
1746  break;
1747  case NEW_INVOICE:
1748  case MOD_INVOICE:
1749  case DUP_INVOICE:
1750  if (iw->proj_cust.owner.undefined == NULL)
1751  {
1752  iw->proj_job_choice = NULL;
1753  }
1754  else
1755  {
1756  iw->proj_job_choice =
1757  gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select…"), TRUE,
1758  gnc_invoice_select_proj_job_cb, iw, iw->book);
1759 
1760  gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
1761  gncOwnerGetJob (&iw->proj_job));
1762  gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->proj_job_choice),
1763  TRUE);
1764  gtk_box_pack_start (GTK_BOX (iw->proj_job_box), iw->proj_job_choice,
1765  TRUE, TRUE, 0);
1766 
1767  g_signal_connect (G_OBJECT (iw->proj_job_choice), "changed",
1768  G_CALLBACK (gnc_invoice_proj_job_changed_cb), iw);
1769  }
1770  break;
1771  }
1772 
1773  if (iw->proj_job_choice)
1774  gtk_widget_show_all (iw->proj_job_choice);
1775 }
1776 
1777 static int
1778 gnc_invoice_owner_changed_cb (GtkWidget *widget, gpointer data)
1779 {
1780  InvoiceWindow *iw = data;
1781  GncBillTerm *term = NULL;
1782  GncOwner owner;
1783 
1784  if (!iw)
1785  return FALSE;
1786 
1787  if (iw->dialog_type == VIEW_INVOICE)
1788  return FALSE;
1789 
1790  gncOwnerCopy (&(iw->owner), &owner);
1791  gnc_owner_get_owner (iw->owner_choice, &owner);
1792 
1793  /* If this owner really changed, then reset ourselves */
1794  if (!gncOwnerEqual (&owner, &(iw->owner)))
1795  {
1796  gncOwnerCopy (&owner, &(iw->owner));
1797  gncOwnerInitJob (&(iw->job), NULL);
1798  gnc_entry_ledger_reset_query (iw->ledger);
1799  }
1800 
1801  if (iw->dialog_type == EDIT_INVOICE)
1802  return FALSE;
1803 
1804  switch (gncOwnerGetType (&(iw->owner)))
1805  {
1806  case GNC_OWNER_CUSTOMER:
1807  term = gncCustomerGetTerms (gncOwnerGetCustomer (&(iw->owner)));
1808  break;
1809  case GNC_OWNER_VENDOR:
1810  term = gncVendorGetTerms (gncOwnerGetVendor (&(iw->owner)));
1811  break;
1812  case GNC_OWNER_EMPLOYEE:
1813  term = NULL;
1814  break;
1815  default:
1816  g_warning ("Unknown owner type: %d\n", gncOwnerGetType (&(iw->owner)));
1817  break;
1818  }
1819 
1820  /* XXX: I'm not sure -- should we change the terms if this happens? */
1821  iw->terms = term;
1822  gnc_simple_combo_set_value (GTK_COMBO_BOX(iw->terms_menu), iw->terms);
1823 
1824  gnc_invoice_update_job_choice (iw);
1825 
1826  return FALSE;
1827 }
1828 
1829 static int
1830 gnc_invoice_proj_cust_changed_cb (GtkWidget *widget, gpointer data)
1831 {
1832  InvoiceWindow *iw = data;
1833  GncOwner owner;
1834 
1835  if (!iw)
1836  return FALSE;
1837 
1838  if (iw->dialog_type == VIEW_INVOICE)
1839  return FALSE;
1840 
1841  gncOwnerCopy (&(iw->proj_cust), &owner);
1842  gnc_owner_get_owner (iw->proj_cust_choice, &owner);
1843 
1844  /* If this owner really changed, then reset ourselves */
1845  if (!gncOwnerEqual (&owner, &(iw->proj_cust)))
1846  {
1847  gncOwnerCopy (&owner, &(iw->proj_cust));
1848  gncOwnerInitJob (&(iw->proj_job), NULL);
1849  }
1850 
1851  if (iw->dialog_type == EDIT_INVOICE)
1852  return FALSE;
1853 
1854  gnc_invoice_update_proj_job (iw);
1855 
1856  return FALSE;
1857 }
1858 
1859 static void
1860 gnc_invoice_dialog_close_handler (gpointer user_data)
1861 {
1862  InvoiceWindow *iw = user_data;
1863 
1864  if (iw)
1865  {
1866  gtk_widget_destroy (iw->dialog);
1867  }
1868 }
1869 
1870 static void
1871 gnc_invoice_window_close_handler (gpointer user_data)
1872 {
1873  InvoiceWindow *iw = user_data;
1874 
1875  if (iw)
1876  {
1877  gnc_main_window_close_page(iw->page);
1878  iw->page = NULL;
1879  }
1880 }
1881 
1882 static void
1883 gnc_invoice_reset_total_label (GtkLabel *label, gnc_numeric amt, gnc_commodity *com)
1884 {
1885  char string[256];
1886  gchar *bidi_string;
1887 
1889  xaccSPrintAmount (string, amt, gnc_commodity_print_info (com, TRUE));
1890 
1891  bidi_string = gnc_wrap_text_with_bidi_ltr_isolate (string);
1892  gtk_label_set_text (label, bidi_string);
1893  g_free (bidi_string);
1894 }
1895 
1896 static void
1897 gnc_invoice_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
1898 {
1899  InvoiceWindow *iw = data;
1900  GncInvoice * invoice;
1901  gnc_commodity * currency;
1902  gnc_numeric amount, to_charge_amt = gnc_numeric_zero();
1903 
1904  if (!iw)
1905  return;
1906 
1907  // if (iw)
1908  // gnc_invoice_update_window (iw, NULL);
1909 
1910  invoice = iw_get_invoice (iw);
1911  if (!invoice)
1912  return;
1913 
1914  currency = gncInvoiceGetCurrency (invoice);
1915 
1916  if (iw->total_label)
1917  {
1918  amount = gncInvoiceGetTotal (invoice);
1919  gnc_invoice_reset_total_label (GTK_LABEL (iw->total_label), amount, currency);
1920  }
1921 
1922  if (iw->total_subtotal_label)
1923  {
1924  amount = gncInvoiceGetTotalSubtotal (invoice);
1925  gnc_invoice_reset_total_label (GTK_LABEL (iw->total_subtotal_label), amount, currency);
1926  }
1927 
1928  if (iw->total_tax_label)
1929  {
1930  amount = gncInvoiceGetTotalTax (invoice);
1931  gnc_invoice_reset_total_label (GTK_LABEL (iw->total_tax_label), amount, currency);
1932  }
1933 
1934  /* Deal with extra items for the expense voucher */
1935 
1936  if (iw->to_charge_edit)
1937  {
1938  gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (iw->to_charge_edit), NULL);
1939  to_charge_amt = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(iw->to_charge_edit));
1940  }
1941 
1942  if (iw->total_cash_label)
1943  {
1944  amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CASH);
1945  amount = gnc_numeric_sub (amount, to_charge_amt,
1947  gnc_invoice_reset_total_label (GTK_LABEL (iw->total_cash_label), amount, currency);
1948  }
1949 
1950  if (iw->total_charge_label)
1951  {
1952  amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CARD);
1953  amount = gnc_numeric_add (amount, to_charge_amt,
1955  gnc_invoice_reset_total_label (GTK_LABEL (iw->total_charge_label), amount, currency);
1956  }
1957 }
1958 
1959 void
1960 gnc_invoice_window_changed (InvoiceWindow *iw, GtkWidget *window)
1961 {
1962  gnc_entry_ledger_set_parent(iw->ledger, window);
1963 }
1964 
1965 gchar *
1966 gnc_invoice_get_help (InvoiceWindow *iw)
1967 {
1968  if (!iw)
1969  return NULL;
1970 
1971  return gnc_table_get_help (gnc_entry_ledger_get_table (iw->ledger));
1972 }
1973 
1974 static void
1975 gnc_invoice_window_refresh_handler (GHashTable *changes, gpointer user_data)
1976 {
1977  InvoiceWindow *iw = user_data;
1978  const EventInfo *info;
1979  GncInvoice *invoice = iw_get_invoice (iw);
1980  const GncOwner *owner;
1981 
1982  /* If there isn't an invoice behind us, close down */
1983  if (!invoice)
1984  {
1985  gnc_close_gui_component (iw->component_id);
1986  return;
1987  }
1988 
1989  /* Next, close if this is a destroy event */
1990  if (changes)
1991  {
1992  info = gnc_gui_get_entity_events (changes, &iw->invoice_guid);
1993  if (info && (info->event_mask & QOF_EVENT_DESTROY))
1994  {
1995  gnc_close_gui_component (iw->component_id);
1996  return;
1997  }
1998  }
1999 
2000  /* Check the owners, and see if they have changed */
2001  owner = gncInvoiceGetOwner (invoice);
2002 
2003  /* Copy the owner information into our window */
2004  gncOwnerCopy (gncOwnerGetEndOwner (owner), &(iw->owner));
2005  gncOwnerInitJob (&(iw->job), gncOwnerGetJob (owner));
2006 
2007  /* Copy the billto information into our window */
2008  owner = gncInvoiceGetBillTo (invoice);
2009  gncOwnerCopy (gncOwnerGetEndOwner (owner), &iw->proj_cust);
2010  gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (owner));
2011 
2012  /* Ok, NOW let's refresh ourselves */
2013  gnc_invoice_update_window (iw, NULL);
2014 }
2015 
2026 static void
2027 gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget)
2028 {
2029  GtkWidget *acct_entry;
2030  GncInvoice *invoice;
2031  gboolean is_posted = FALSE;
2032  gboolean can_unpost = FALSE;
2033 
2034  invoice = iw_get_invoice (iw);
2035 
2036  if (iw->owner_choice)
2037  gtk_container_remove (GTK_CONTAINER (iw->owner_box), iw->owner_choice);
2038 
2039  if (iw->proj_cust_choice)
2040  gtk_container_remove (GTK_CONTAINER (iw->proj_cust_box),
2041  iw->proj_cust_choice);
2042 
2043  switch (iw->dialog_type)
2044  {
2045  case VIEW_INVOICE:
2046  case EDIT_INVOICE:
2047  iw->owner_choice =
2048  gnc_owner_edit_create (iw->owner_label, iw->owner_box, iw->book,
2049  &(iw->owner));
2050  iw->proj_cust_choice =
2051  gnc_owner_edit_create (NULL, iw->proj_cust_box, iw->book,
2052  &(iw->proj_cust));
2053  break;
2054  case NEW_INVOICE:
2055  case MOD_INVOICE:
2056  case DUP_INVOICE:
2057  iw->owner_choice =
2058  gnc_owner_select_create (iw->owner_label, iw->owner_box, iw->book,
2059  &(iw->owner));
2060  iw->proj_cust_choice =
2061  gnc_owner_select_create (NULL, iw->proj_cust_box, iw->book,
2062  &(iw->proj_cust));
2063 
2064  g_signal_connect (G_OBJECT (iw->owner_choice), "changed",
2065  G_CALLBACK (gnc_invoice_owner_changed_cb), iw);
2066 
2067  g_signal_connect (G_OBJECT (iw->proj_cust_choice), "changed",
2068  G_CALLBACK (gnc_invoice_proj_cust_changed_cb), iw);
2069 
2070  break;
2071  }
2072 
2073  /* Set the type label */
2074  gtk_label_set_text (GTK_LABEL(iw->type_label), iw->is_credit_note ? _("Credit Note")
2075  : gtk_label_get_text (GTK_LABEL(iw->type_label)));
2076 
2077  if (iw->owner_choice)
2078  gtk_widget_show_all (iw->owner_choice);
2079  if (iw->proj_cust_choice)
2080  gtk_widget_show_all (iw->proj_cust_choice);
2081 
2082  gnc_invoice_update_job_choice (iw);
2083  gnc_invoice_update_proj_job (iw);
2084 
2085  /* Hide the project frame for customer invoices */
2086  if (iw->owner.type == GNC_OWNER_CUSTOMER)
2087  gtk_widget_hide (iw->proj_frame);
2088 
2089  /* Hide the "job" label and entry for employee invoices */
2090  if (iw->owner.type == GNC_OWNER_EMPLOYEE)
2091  {
2092  gtk_widget_hide (iw->job_label);
2093  gtk_widget_hide (iw->job_box);
2094  }
2095 
2096  acct_entry = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_entry"));
2097 
2098  /* We know that "invoice" (and "owner") exist now */
2099  {
2100  GtkTextBuffer* text_buffer;
2101  const char *string;
2102  gchar * tmp_string;
2103  time64 time;
2104 
2105  gtk_entry_set_text (GTK_ENTRY (iw->id_entry), gncInvoiceGetID (invoice));
2106 
2107  gtk_entry_set_text (GTK_ENTRY (iw->billing_id_entry),
2108  gncInvoiceGetBillingID (invoice));
2109 
2110  string = gncInvoiceGetNotes (invoice);
2111  text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
2112  gtk_text_buffer_set_text (text_buffer, string, -1);
2113 
2114  if (iw->active_check)
2115  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (iw->active_check),
2116  gncInvoiceGetActive (invoice));
2117 
2118  time = gncInvoiceGetDateOpened (invoice);
2119  if (time == INT64_MAX)
2120  {
2121  gnc_date_edit_set_time (GNC_DATE_EDIT (iw->opened_date),
2122  gnc_time (NULL));
2123  }
2124  else
2125  {
2126  gnc_date_edit_set_time (GNC_DATE_EDIT (iw->opened_date), time);
2127  }
2128 
2129  /* fill in the terms text */
2130  iw->terms = gncInvoiceGetTerms (invoice);
2131  //DEBUG("iw->dialog_type: %d",iw->dialog_type);
2132  switch (iw->dialog_type)
2133  {
2134  case NEW_INVOICE:
2135  case MOD_INVOICE:
2136  case DUP_INVOICE: //??
2137  gnc_simple_combo_set_value (GTK_COMBO_BOX(iw->terms_menu), iw->terms);
2138  break;
2139 
2140  case EDIT_INVOICE:
2141  case VIEW_INVOICE:
2142  // Fill in the invoice view version
2143  if(gncBillTermGetName (iw->terms) != NULL)
2144  gtk_entry_set_text (GTK_ENTRY (iw->terms_menu),gncBillTermGetName (iw->terms));
2145  else
2146  gtk_entry_set_text (GTK_ENTRY (iw->terms_menu),"None");
2147  break;
2148 
2149  default:
2150  break;
2151  }
2152 
2153  /*
2154  * Next, figure out if we've been posted, and if so set the appropriate
2155  * bits of information... Then work on hiding or showing as
2156  * necessary.
2157  */
2158  is_posted = gncInvoiceIsPosted (invoice);
2159  if (is_posted)
2160  {
2161  Account *acct = gncInvoiceGetPostedAcc (invoice);
2162 
2163  /* Can we unpost this invoice?
2164  * XXX: right now we always can, but there
2165  * may be times in the future when we cannot.
2166  */
2167  can_unpost = TRUE;
2168 
2169  time = gncInvoiceGetDatePosted (invoice);
2170  gnc_date_edit_set_time (GNC_DATE_EDIT (iw->posted_date), time);
2171 
2172  tmp_string = gnc_account_get_full_name (acct);
2173  gtk_entry_set_text (GTK_ENTRY (acct_entry), tmp_string);
2174  g_free(tmp_string);
2175  }
2176  }
2177 
2178  gnc_invoice_id_changed_cb(NULL, iw);
2179  if (iw->dialog_type == NEW_INVOICE ||
2180  iw->dialog_type == DUP_INVOICE ||
2181  iw->dialog_type == MOD_INVOICE)
2182  {
2183  if (widget)
2184  gtk_widget_show (widget);
2185  else
2186  gtk_widget_show (iw_get_window(iw));
2187  return;
2188  }
2189 
2190  /* Fill in the to_charge amount (only in VIEW/EDIT modes) */
2191  {
2192  gnc_numeric amount;
2193 
2194  amount = gncInvoiceGetToChargeAmount (invoice);
2195  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (iw->to_charge_edit), amount);
2196  }
2197 
2198  /* Hide/show the appropriate widgets based on our posted/paid state */
2199 
2200  {
2201  GtkWidget *hide, *show;
2202 
2203  if (is_posted)
2204  {
2205  show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "posted_label"));
2206  gtk_widget_show (show);
2207  gtk_widget_show (iw->posted_date_hbox);
2208  show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_label"));
2209  gtk_widget_show (show);
2210  gtk_widget_show (acct_entry);
2211  }
2212  else /* ! posted */
2213  {
2214  hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "posted_label"));
2215  gtk_widget_hide (hide);
2216  gtk_widget_hide (iw->posted_date_hbox);
2217 
2218  hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_label"));
2219  gtk_widget_hide (hide);
2220  gtk_widget_hide (acct_entry);
2221  }
2222  }
2223 
2224  /* Set the toolbar widgets sensitivity */
2225  if (iw->page)
2226  gnc_plugin_page_invoice_update_menus(iw->page, is_posted, can_unpost);
2227 
2228  /* Set the to_charge widget */
2229  gtk_widget_set_sensitive (iw->to_charge_edit, !is_posted);
2230 
2231  /* Hide the to_charge frame for all non-employee invoices,
2232  * or set insensitive if the employee does not have a charge card
2233  */
2234  if (iw->owner.type == GNC_OWNER_EMPLOYEE)
2235  {
2236  if (!gncEmployeeGetCCard (gncOwnerGetEmployee(&iw->owner)))
2237  gtk_widget_set_sensitive (iw->to_charge_edit, FALSE);
2238  }
2239  else
2240  {
2241  gtk_widget_hide (iw->to_charge_frame);
2242  }
2243 
2244  if (is_posted)
2245  {
2246  // GtkWidget *hide;
2247 
2248  /* Setup viewer for read-only access */
2249  gtk_widget_set_sensitive (acct_entry, FALSE);
2250  gtk_widget_set_sensitive (iw->id_entry, FALSE); /* XXX: why set FALSE and then TRUE? */
2251  gtk_widget_set_sensitive (iw->id_entry, TRUE);
2252  gtk_widget_set_sensitive (iw->terms_menu, FALSE);
2253  gtk_widget_set_sensitive (iw->owner_box, TRUE);
2254  gtk_widget_set_sensitive (iw->job_box, TRUE);
2255  gtk_widget_set_sensitive (iw->billing_id_entry, FALSE);
2256  gtk_widget_set_sensitive (iw->notes_text, TRUE);
2257  }
2258  else /* ! posted */
2259  {
2260  gtk_widget_set_sensitive (acct_entry, TRUE);
2261  gtk_widget_set_sensitive (iw->terms_menu, TRUE);
2262  gtk_widget_set_sensitive (iw->owner_box, TRUE);
2263  gtk_widget_set_sensitive (iw->job_box, TRUE);
2264  gtk_widget_set_sensitive (iw->billing_id_entry, TRUE);
2265  gtk_widget_set_sensitive (iw->notes_text, TRUE);
2266  }
2267 
2268  /* Translators: This is a label to show whether the invoice is paid or not. */
2269  if(gncInvoiceIsPaid (invoice))
2270  gtk_label_set_text(GTK_LABEL(iw->paid_label), _("PAID"));
2271  else
2272  gtk_label_set_text(GTK_LABEL(iw->paid_label), _("UNPAID"));
2273 
2274  if (widget)
2275  gtk_widget_show (widget);
2276  else
2277  gtk_widget_show (iw_get_window(iw));
2278 }
2279 
2280 GncInvoiceType
2281 gnc_invoice_get_type_from_window (InvoiceWindow *iw)
2282 {
2283  /* uses the same approach as gnc_invoice_get_title
2284  not called gnc_invoice_get_type because of name collisions
2285  */
2286  switch (gncOwnerGetType(&iw->owner))
2287  {
2288  case GNC_OWNER_CUSTOMER:
2289  return iw->is_credit_note ? GNC_INVOICE_CUST_CREDIT_NOTE
2290  : GNC_INVOICE_CUST_INVOICE;
2291  break;
2292  case GNC_OWNER_VENDOR:
2293  return iw->is_credit_note ? GNC_INVOICE_VEND_CREDIT_NOTE
2294  : GNC_INVOICE_VEND_INVOICE;
2295  break;
2296  case GNC_OWNER_EMPLOYEE:
2297  return iw->is_credit_note ? GNC_INVOICE_EMPL_CREDIT_NOTE
2298  : GNC_INVOICE_EMPL_INVOICE;
2299  break;
2300  default:
2301  return GNC_INVOICE_UNDEFINED;
2302  break;
2303  }
2304 }
2305 
2306 gchar *
2307 gnc_invoice_get_title (InvoiceWindow *iw)
2308 {
2309  char *wintitle = NULL;
2310  const char *id = NULL;
2311 
2312  if (!iw) return NULL;
2313 
2314  switch (gncOwnerGetType (&iw->owner))
2315  {
2316  case GNC_OWNER_CUSTOMER:
2317  switch (iw->dialog_type)
2318  {
2319  case NEW_INVOICE:
2320  wintitle = iw->is_credit_note ? _("New Credit Note")
2321  : _("New Invoice");
2322  break;
2323  case MOD_INVOICE:
2324  case DUP_INVOICE:
2325  case EDIT_INVOICE:
2326  wintitle = iw->is_credit_note ? _("Edit Credit Note")
2327  : _("Edit Invoice");
2328  break;
2329  case VIEW_INVOICE:
2330  wintitle = iw->is_credit_note ? _("View Credit Note")
2331  : _("View Invoice");
2332  break;
2333  }
2334  break;
2335  case GNC_OWNER_VENDOR:
2336  switch (iw->dialog_type)
2337  {
2338  case NEW_INVOICE:
2339  wintitle = iw->is_credit_note ? _("New Credit Note")
2340  : _("New Bill");
2341  break;
2342  case MOD_INVOICE:
2343  case DUP_INVOICE:
2344  case EDIT_INVOICE:
2345  wintitle = iw->is_credit_note ? _("Edit Credit Note")
2346  : _("Edit Bill");
2347  break;
2348  case VIEW_INVOICE:
2349  wintitle = iw->is_credit_note ? _("View Credit Note")
2350  : _("View Bill");
2351  break;
2352  }
2353  break;
2354  case GNC_OWNER_EMPLOYEE:
2355  switch (iw->dialog_type)
2356  {
2357  case NEW_INVOICE:
2358  wintitle = iw->is_credit_note ? _("New Credit Note")
2359  : _("New Expense Voucher");
2360  break;
2361  case MOD_INVOICE:
2362  case DUP_INVOICE:
2363  case EDIT_INVOICE:
2364  wintitle = iw->is_credit_note ? _("Edit Credit Note")
2365  : _("Edit Expense Voucher");
2366  break;
2367  case VIEW_INVOICE:
2368  wintitle = iw->is_credit_note ? _("View Credit Note")
2369  : _("View Expense Voucher");
2370  break;
2371  }
2372  break;
2373  default:
2374  break;
2375  }
2376 
2377  if (iw->id_entry)
2378  id = gtk_entry_get_text (GTK_ENTRY (iw->id_entry));
2379  if (id && *id)
2380  return g_strconcat (wintitle, " - ", id, (char *)NULL);
2381  return g_strdup (wintitle);
2382 }
2383 
2384 void
2385 gnc_invoice_type_toggled_cb (GtkWidget *widget, gpointer data)
2386 {
2387  InvoiceWindow *iw = data;
2388 
2389  if (!iw) return;
2390  iw->is_credit_note = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
2391 }
2392 
2393 void
2394 gnc_invoice_id_changed_cb (GtkWidget *unused, gpointer data)
2395 {
2396  InvoiceWindow *iw = data;
2397  gchar *title;
2398 
2399  if (!iw) return;
2400  if (iw->page)
2401  {
2403  }
2404  else
2405  {
2406  title = gnc_invoice_get_title (iw);
2407  gtk_window_set_title (GTK_WINDOW (iw->dialog), title);
2408  g_free (title);
2409  }
2410 }
2411 
2412 void
2413 gnc_invoice_terms_changed_cb (GtkWidget *widget, gpointer data)
2414 {
2415  GtkComboBox *cbox = GTK_COMBO_BOX (widget);
2416  InvoiceWindow *iw = data;
2417 
2418  if (!iw) return;
2419  if (!cbox) return;
2420 
2421  iw->terms = gnc_simple_combo_get_value (cbox);
2422 }
2423 
2424 
2425 static gboolean
2426 find_handler (gpointer find_data, gpointer user_data)
2427 {
2428  const GncGUID *invoice_guid = find_data;
2429  InvoiceWindow *iw = user_data;
2430 
2431  return(iw && guid_equal(&iw->invoice_guid, invoice_guid));
2432 }
2433 
2434 static InvoiceWindow *
2435 gnc_invoice_new_page (QofBook *bookp, InvoiceDialogType type,
2436  GncInvoice *invoice, const GncOwner *owner,
2437  GncMainWindow *window, const gchar *group_name)
2438 {
2439  InvoiceWindow *iw;
2440  GncOwner *billto;
2441  GncPluginPage *new_page;
2442 
2443  g_assert (type != NEW_INVOICE && type != MOD_INVOICE && type != DUP_INVOICE);
2444  g_assert (invoice != NULL);
2445 
2446  /*
2447  * Find an existing window for this invoice. If found, bring it to
2448  * the front.
2449  */
2450  if (invoice)
2451  {
2452  GncGUID invoice_guid;
2453 
2454  invoice_guid = *gncInvoiceGetGUID (invoice);
2455  iw = gnc_find_first_gui_component (DIALOG_VIEW_INVOICE_CM_CLASS,
2456  find_handler, &invoice_guid);
2457  if (iw)
2458  {
2459  gnc_main_window_display_page(iw->page);
2460  return(iw);
2461  }
2462  }
2463 
2464  /*
2465  * No existing invoice window found. Build a new one.
2466  */
2467  iw = g_new0 (InvoiceWindow, 1);
2468  iw->book = bookp;
2469  iw->dialog_type = type;
2470  iw->invoice_guid = *gncInvoiceGetGUID (invoice);
2471  iw->is_credit_note = gncInvoiceGetIsCreditNote (invoice);
2472  iw->width = -1;
2473  iw->page_state_name = group_name;
2474 
2475  /* Save this for later */
2476  gncOwnerCopy (gncOwnerGetEndOwner (owner), &(iw->owner));
2477  gncOwnerInitJob (&(iw->job), gncOwnerGetJob (owner));
2478 
2479  billto = gncInvoiceGetBillTo (invoice);
2480  gncOwnerCopy (gncOwnerGetEndOwner (billto), &(iw->proj_cust));
2481  gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (billto));
2482 
2483  /* Now create the plugin page for this invoice and display it. */
2484  new_page = gnc_plugin_page_invoice_new (iw);
2485 
2486  if (!window)
2487  window = gnc_plugin_business_get_window ();
2488 
2489  gnc_main_window_open_page (window, new_page);
2490 
2491  /* Initialize the summary bar */
2492  gnc_invoice_redraw_all_cb(iw->reg, iw);
2493 
2494  return iw;
2495 }
2496 
2497 #define KEY_INVOICE_TYPE "InvoiceType"
2498 #define KEY_INVOICE_GUID "InvoiceGUID"
2499 #define KEY_OWNER_TYPE "OwnerType"
2500 #define KEY_OWNER_GUID "OwnerGUID"
2501 
2502 GncPluginPage *
2503 gnc_invoice_recreate_page (GncMainWindow *window,
2504  GKeyFile *key_file,
2505  const gchar *group_name)
2506 {
2507  InvoiceWindow *iw;
2508  GError *error = NULL;
2509  char *tmp_string = NULL, *owner_type = NULL;
2510  InvoiceDialogType type;
2511  GncInvoice *invoice;
2512  GncGUID guid;
2513  QofBook *book;
2514  GncOwner owner = { 0 };
2515 
2516  /* Get Invoice Type */
2517  tmp_string = g_key_file_get_string(key_file, group_name,
2518  KEY_INVOICE_TYPE, &error);
2519  if (error)
2520  {
2521  g_warning("Error reading group %s key %s: %s.",
2522  group_name, KEY_INVOICE_TYPE, error->message);
2523  goto give_up;
2524  }
2525  type = InvoiceDialogTypefromString(tmp_string);
2526  g_free(tmp_string);
2527 
2528  /* Get Invoice GncGUID */
2529  tmp_string = g_key_file_get_string(key_file, group_name,
2530  KEY_INVOICE_GUID, &error);
2531  if (error)
2532  {
2533  g_warning("Error reading group %s key %s: %s.",
2534  group_name, KEY_INVOICE_GUID, error->message);
2535  goto give_up;
2536  }
2537  if (!string_to_guid(tmp_string, &guid))
2538  {
2539  g_warning("Invalid invoice guid: %s.", tmp_string);
2540  goto give_up;
2541  }
2542  book = gnc_get_current_book();
2543  invoice = gncInvoiceLookup(gnc_get_current_book(), &guid);
2544  if (invoice == NULL)
2545  {
2546  g_warning("Can't find invoice %s in current book.", tmp_string);
2547  goto give_up;
2548  }
2549  g_free(tmp_string);
2550  tmp_string = NULL;
2551 
2552  /* Get Owner Type */
2553  owner_type = g_key_file_get_string(key_file, group_name,
2554  KEY_OWNER_TYPE, &error);
2555  if (error)
2556  {
2557  g_warning("Error reading group %s key %s: %s.",
2558  group_name, KEY_OWNER_TYPE, error->message);
2559  goto give_up;
2560  }
2561 
2562  /* Get Owner GncGUID */
2563  tmp_string = g_key_file_get_string(key_file, group_name,
2564  KEY_OWNER_GUID, &error);
2565  if (error)
2566  {
2567  g_warning("Error reading group %s key %s: %s.",
2568  group_name, KEY_OWNER_GUID, error->message);
2569  goto give_up;
2570  }
2571  if (!string_to_guid(tmp_string, &guid))
2572  {
2573  g_warning("Invalid owner guid: %s.", tmp_string);
2574  goto give_up;
2575  }
2576 
2577  if (!gncOwnerGetOwnerFromTypeGuid(book, &owner, owner_type, &guid))
2578  {
2579  g_warning("Can't find owner %s in current book.", tmp_string);
2580  goto give_up;
2581  }
2582  g_free(tmp_string);
2583  g_free(owner_type);
2584 
2585  iw = gnc_invoice_new_page (book, type, invoice, &owner, window, group_name);
2586  return iw->page;
2587 
2588 give_up:
2589  g_warning("Giving up on restoring '%s'.", group_name);
2590  if (error)
2591  g_error_free(error);
2592  if (tmp_string)
2593  g_free(tmp_string);
2594  if (owner_type)
2595  g_free(owner_type);
2596  return NULL;
2597 }
2598 
2599 void
2600 gnc_invoice_save_page (InvoiceWindow *iw,
2601  GKeyFile *key_file,
2602  const gchar *group_name)
2603 {
2604  Table *table = gnc_entry_ledger_get_table (iw->ledger);
2605  gchar guidstr[GUID_ENCODING_LENGTH+1];
2606  guid_to_string_buff(&iw->invoice_guid, guidstr);
2607  g_key_file_set_string(key_file, group_name, KEY_INVOICE_TYPE,
2608  InvoiceDialogTypeasString(iw->dialog_type));
2609  g_key_file_set_string(key_file, group_name, KEY_INVOICE_GUID, guidstr);
2610 
2611  if (gncOwnerGetJob (&(iw->job)))
2612  {
2613  g_key_file_set_string(key_file, group_name, KEY_OWNER_TYPE,
2614  qofOwnerGetType(&iw->job));
2615  guid_to_string_buff(gncOwnerGetGUID(&iw->job), guidstr);
2616  g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID, guidstr);
2617  }
2618  else
2619  {
2620  g_key_file_set_string(key_file, group_name, KEY_OWNER_TYPE,
2621  qofOwnerGetType(&iw->owner));
2622  guid_to_string_buff(gncOwnerGetGUID(&iw->owner), guidstr);
2623  g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID, guidstr);
2624  }
2625  // save the open table layout
2626  gnc_table_save_state (table, group_name);
2627 }
2628 
2629 static gboolean
2630 doclink_button_cb (GtkLinkButton *button, InvoiceWindow *iw)
2631 {
2632  GncInvoice *invoice = gncInvoiceLookup (iw->book, &iw->invoice_guid);
2633  gnc_doclink_open_uri (GTK_WINDOW(iw->dialog), gncInvoiceGetDocLink (invoice));
2634 
2635  return TRUE;
2636 }
2637 
2638 GtkWidget *
2639 gnc_invoice_create_page (InvoiceWindow *iw, gpointer page)
2640 {
2641  GncInvoice *invoice;
2642  GtkBuilder *builder;
2643  GtkWidget *dialog, *hbox;
2644  GncEntryLedger *entry_ledger = NULL;
2645  GncOwnerType owner_type;
2646  GncEntryLedgerType ledger_type;
2647  const gchar *prefs_group = NULL;
2648  gboolean is_credit_note = FALSE;
2649  const gchar *style_label = NULL;
2650  const gchar *doclink_uri;
2651 
2652  invoice = gncInvoiceLookup (iw->book, &iw->invoice_guid);
2653  is_credit_note = gncInvoiceGetIsCreditNote (invoice);
2654 
2655  iw->page = page;
2656 
2657  /* Find the dialog */
2658  iw->builder = builder = gtk_builder_new();
2659  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "terms_store");
2660  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "invoice_entry_vbox");
2661  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "invoice_entry_vbox"));
2662 
2663  /* Autoconnect all the signals */
2664  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, iw);
2665 
2666  /* Grab the widgets */
2667  iw->id_label = GTK_WIDGET (gtk_builder_get_object (builder, "label3"));
2668  iw->type_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_type_label"));
2669  iw->info_label = GTK_WIDGET (gtk_builder_get_object (builder, "label25"));
2670  iw->id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "page_id_entry"));
2671  iw->billing_id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "page_billing_id_entry"));
2672  iw->terms_menu = GTK_WIDGET (gtk_builder_get_object (builder, "page_terms_menu"));
2673  iw->notes_text = GTK_WIDGET (gtk_builder_get_object (builder, "page_notes_text"));
2674  iw->active_check = GTK_WIDGET (gtk_builder_get_object (builder, "active_check"));
2675  iw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_owner_hbox"));
2676  iw->owner_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_owner_label"));
2677  iw->job_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_job_label"));
2678  iw->job_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_job_hbox"));
2679  iw->paid_label = GTK_WIDGET (gtk_builder_get_object (builder, "paid_label"));
2680 
2681  iw->doclink_button = GTK_WIDGET(gtk_builder_get_object (builder, "doclink_button"));
2682  g_signal_connect (G_OBJECT (iw->doclink_button), "activate-link",
2683  G_CALLBACK (doclink_button_cb), iw);
2684 
2685  /* invoice doclink */
2686  doclink_uri = gncInvoiceGetDocLink (invoice);
2687  if (doclink_uri)
2688  {
2689  gchar *display_uri = gnc_doclink_get_unescaped_just_uri (doclink_uri);
2690  gtk_button_set_label (GTK_BUTTON (iw->doclink_button),
2691  _("Open Linked Document:"));
2692  gtk_link_button_set_uri (GTK_LINK_BUTTON (iw->doclink_button),
2693  display_uri);
2694  gtk_widget_show (GTK_WIDGET (iw->doclink_button));
2695  g_free (display_uri);
2696  }
2697  else
2698  gtk_widget_hide (GTK_WIDGET (iw->doclink_button));
2699 
2700  // Add a style context for this label so it can be easily manipulated with css
2701  gnc_widget_style_context_add_class (GTK_WIDGET(iw->paid_label), "gnc-class-highlight");
2702 
2703  /* grab the project widgets */
2704  iw->proj_frame = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_frame"));
2705  iw->proj_cust_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_cust_hbox"));
2706  iw->proj_job_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_job_hbox"));
2707 
2708  /* grab the to_charge widgets */
2709  {
2710  GtkWidget *edit;
2711 
2712  gnc_commodity *currency = gncInvoiceGetCurrency (invoice);
2713  GNCPrintAmountInfo print_info;
2714 
2715  iw->to_charge_frame = GTK_WIDGET (gtk_builder_get_object (builder, "to_charge_frame"));
2716  edit = gnc_amount_edit_new();
2717  print_info = gnc_commodity_print_info (currency, FALSE);
2718  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
2719  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (edit), print_info);
2720  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (edit),
2721  gnc_commodity_get_fraction (currency));
2722  iw->to_charge_edit = edit;
2723  gtk_widget_show (edit);
2724  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "to_charge_box"));
2725  gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
2726 
2727  g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(edit))),
2728  "focus-out-event",
2729  G_CALLBACK(gnc_invoice_window_leave_to_charge_cb), edit);
2730  g_signal_connect(G_OBJECT(edit), "amount_changed",
2731  G_CALLBACK(gnc_invoice_window_changed_to_charge_cb), iw);
2732  }
2733 
2734  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "page_date_opened_hbox"));
2735  iw->opened_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
2736  gtk_widget_show(iw->opened_date);
2737  gtk_box_pack_start (GTK_BOX(hbox), iw->opened_date, TRUE, TRUE, 0);
2738 
2739  iw->posted_date_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "date_posted_hbox"));
2740  iw->posted_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
2741  gtk_widget_show(iw->posted_date);
2742  gtk_box_pack_start (GTK_BOX(iw->posted_date_hbox), iw->posted_date,
2743  TRUE, TRUE, 0);
2744 
2745  /* Make the opened and posted dates insensitive in this window */
2746  gtk_widget_set_sensitive (iw->opened_date, FALSE);
2747  gtk_widget_set_sensitive (iw->posted_date, FALSE);
2748  /* Also the invoice ID */
2749  gtk_widget_set_sensitive (iw->id_entry, FALSE);
2750 
2751  /* Build the ledger */
2752  ledger_type = GNCENTRY_INVOICE_VIEWER;
2753  owner_type = gncOwnerGetType (&iw->owner);
2754  switch (iw->dialog_type)
2755  {
2756  case EDIT_INVOICE:
2757  switch (owner_type)
2758  {
2759  case GNC_OWNER_CUSTOMER:
2760  ledger_type = is_credit_note ? GNCENTRY_CUST_CREDIT_NOTE_ENTRY
2761  : GNCENTRY_INVOICE_ENTRY;
2762  break;
2763  case GNC_OWNER_VENDOR:
2764  ledger_type = is_credit_note ? GNCENTRY_VEND_CREDIT_NOTE_ENTRY
2765  : GNCENTRY_BILL_ENTRY;
2766  break;
2767  case GNC_OWNER_EMPLOYEE:
2768  ledger_type = is_credit_note ? GNCENTRY_EMPL_CREDIT_NOTE_ENTRY
2769  : GNCENTRY_EXPVOUCHER_ENTRY;
2770  break;
2771  default:
2772  g_warning ("Invalid owner type");
2773  break;
2774  }
2775  break;
2776  case VIEW_INVOICE:
2777  default:
2778  switch (owner_type)
2779  {
2780  case GNC_OWNER_CUSTOMER:
2781  ledger_type = is_credit_note ? GNCENTRY_CUST_CREDIT_NOTE_VIEWER
2782  : GNCENTRY_INVOICE_VIEWER;
2783  prefs_group = GNC_PREFS_GROUP_INVOICE;
2784  break;
2785  case GNC_OWNER_VENDOR:
2786  ledger_type = is_credit_note ? GNCENTRY_VEND_CREDIT_NOTE_VIEWER
2787  : GNCENTRY_BILL_VIEWER;
2788  prefs_group = GNC_PREFS_GROUP_BILL;
2789  break;
2790  case GNC_OWNER_EMPLOYEE:
2791  ledger_type = is_credit_note ? GNCENTRY_EMPL_CREDIT_NOTE_VIEWER
2792  : GNCENTRY_EXPVOUCHER_VIEWER;
2793  prefs_group = GNC_PREFS_GROUP_BILL;
2794  break;
2795  default:
2796  g_warning ("Invalid owner type");
2797  break;
2798  }
2799  break;
2800  }
2801  /* Default labels are for invoices, change them if they are anything else. */
2802  switch (owner_type)
2803  {
2804  case GNC_OWNER_VENDOR:
2805  gtk_label_set_text (GTK_LABEL(iw->info_label), _("Bill Information"));
2806  gtk_label_set_text (GTK_LABEL(iw->type_label), _("Bill"));
2807  gtk_label_set_text (GTK_LABEL(iw->id_label), _("Bill ID"));
2808  style_label = "gnc-class-vendors";
2809  break;
2810  case GNC_OWNER_EMPLOYEE:
2811  gtk_label_set_text (GTK_LABEL(iw->info_label), _("Voucher Information"));
2812  gtk_label_set_text (GTK_LABEL(iw->type_label), _("Voucher"));
2813  gtk_label_set_text (GTK_LABEL(iw->id_label), _("Voucher ID"));
2814  style_label = "gnc-class-employees";
2815  break;
2816  default:
2817  style_label = "gnc-class-customers";
2818  break;
2819  }
2820  // Set a secondary style context for this page so it can be easily manipulated with css
2821  gnc_widget_style_context_add_class (GTK_WIDGET(dialog), style_label);
2822 
2823  entry_ledger = gnc_entry_ledger_new (iw->book, ledger_type);
2824 
2825  /* Save the ledger... */
2826  iw->ledger = entry_ledger;
2827  /* window will be updated in a callback */
2828 
2829  /* Set the entry_ledger's invoice */
2830  gnc_entry_ledger_set_default_invoice (entry_ledger, invoice);
2831 
2832  /* Set the preferences group */
2833  gnc_entry_ledger_set_prefs_group (entry_ledger, prefs_group);
2834 
2835  /* Setup initial values */
2836  iw->component_id =
2837  gnc_register_gui_component (DIALOG_VIEW_INVOICE_CM_CLASS,
2838  gnc_invoice_window_refresh_handler,
2839  gnc_invoice_window_close_handler,
2840  iw);
2841 
2842  gnc_gui_component_watch_entity_type (iw->component_id,
2843  GNC_INVOICE_MODULE_NAME,
2844  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
2845 
2846  /* Create the register */
2847  {
2848  GtkWidget *regWidget, *frame, *window;
2849  const gchar *default_group = gnc_invoice_window_get_state_group (iw);
2850  const gchar *group;
2851 
2852  // if this is from a page recreate, use those settings
2853  if (iw->page_state_name)
2854  group = iw->page_state_name;
2855  else
2856  group = default_group;
2857 
2858  /* Watch the order of operations, here... */
2860  (entry_ledger), group);
2861  gtk_widget_show(regWidget);
2862 
2863  frame = GTK_WIDGET (gtk_builder_get_object (builder, "ledger_frame"));
2864  gtk_container_add (GTK_CONTAINER (frame), regWidget);
2865 
2866  iw->reg = GNUCASH_REGISTER (regWidget);
2867  window = gnc_plugin_page_get_window(iw->page);
2868  gnucash_sheet_set_window (gnucash_register_get_sheet (iw->reg), window);
2869 
2870  g_signal_connect (G_OBJECT (regWidget), "activate_cursor",
2871  G_CALLBACK (gnc_invoice_window_recordCB), iw);
2872  g_signal_connect (G_OBJECT (regWidget), "redraw_all",
2873  G_CALLBACK (gnc_invoice_redraw_all_cb), iw);
2874  }
2875 
2876  gnc_table_realize_gui (gnc_entry_ledger_get_table (entry_ledger));
2877 
2878  /* Now fill in a lot of the pieces and display properly */
2879  gnc_invoice_update_window (iw, dialog);
2880 
2882 
2883  /* Show the dialog */
2884  // gtk_widget_show_all (dialog);
2885 
2886  return dialog;
2887 }
2888 
2889 void
2890 gnc_invoice_update_doclink_for_window (GncInvoice *invoice, const gchar *uri)
2891 {
2892  InvoiceWindow *iw = gnc_plugin_page_invoice_get_window (invoice);
2893 
2894  if (iw)
2895  {
2896  GtkWidget *doclink_button = gnc_invoice_window_get_doclink_button (iw);
2897 
2898  if (g_strcmp0 (uri, "") == 0) // deleted uri
2899  {
2900  GAction *uri_action;
2901 
2902  // update the menu actions
2903  uri_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(iw->page), "BusinessLinkOpenAction");
2904  g_simple_action_set_enabled (G_SIMPLE_ACTION(uri_action), FALSE);
2905 
2906  gtk_widget_hide (doclink_button);
2907  }
2908  else
2909  {
2910  gchar *display_uri = gnc_doclink_get_unescaped_just_uri (uri);
2911  gtk_link_button_set_uri (GTK_LINK_BUTTON (doclink_button),
2912  display_uri);
2913  gtk_widget_show (GTK_WIDGET (doclink_button));
2914  g_free (display_uri);
2915  }
2916  }
2917 }
2918 
2919 static InvoiceWindow *
2920 gnc_invoice_window_new_invoice (GtkWindow *parent, InvoiceDialogType dialog_type, QofBook *bookp,
2921  const GncOwner *owner, GncInvoice *invoice)
2922 {
2923  InvoiceWindow *iw;
2924  GtkBuilder *builder;
2925  GtkWidget *hbox;
2926  GtkWidget *invoice_radio;
2927  GncOwner *billto;
2928  const GncOwner *start_owner;
2929  GncBillTerm *owner_terms = NULL;
2930  GncOwnerType owner_type;
2931  const gchar *style_label = NULL;
2932 
2933  g_assert (dialog_type == NEW_INVOICE || dialog_type == MOD_INVOICE || dialog_type == DUP_INVOICE);
2934 
2935  if (invoice)
2936  {
2937  /*
2938  * Try to find an existing window for this invoice. If found,
2939  * bring it to the front.
2940  */
2941  GncGUID invoice_guid;
2942 
2943  invoice_guid = *gncInvoiceGetGUID (invoice);
2944  iw = gnc_find_first_gui_component (DIALOG_NEW_INVOICE_CM_CLASS,
2945  find_handler, &invoice_guid);
2946  if (iw)
2947  {
2948  gtk_window_set_transient_for (GTK_WINDOW(iw->dialog), parent);
2949  gtk_window_present (GTK_WINDOW(iw->dialog));
2950  return(iw);
2951  }
2952  }
2953 
2954  /*
2955  * No existing invoice window found. Build a new one.
2956  */
2957 
2958  iw = g_new0 (InvoiceWindow, 1);
2959  iw->dialog_type = dialog_type;
2960 
2961  switch (dialog_type)
2962  {
2963  case NEW_INVOICE:
2964  g_assert (bookp);
2965 
2966  invoice = gncInvoiceCreate (bookp);
2967  gncInvoiceSetCurrency (invoice, gnc_default_currency ());
2968  iw->book = bookp;
2969  start_owner = owner;
2970  switch (gncOwnerGetType (gncOwnerGetEndOwner (owner)))
2971  {
2972  case GNC_OWNER_CUSTOMER:
2973  owner_terms = gncCustomerGetTerms (gncOwnerGetCustomer (gncOwnerGetEndOwner (owner)));
2974  break;
2975  case GNC_OWNER_VENDOR:
2976  owner_terms = gncVendorGetTerms (gncOwnerGetVendor (gncOwnerGetEndOwner (owner)));
2977  break;
2978  default:
2979  break;
2980  }
2981  if (owner_terms)
2982  gncInvoiceSetTerms (invoice, owner_terms);
2983  break;
2984 
2985  case MOD_INVOICE:
2986  case DUP_INVOICE:
2987  start_owner = gncInvoiceGetOwner (invoice);
2988  iw->book = gncInvoiceGetBook (invoice);
2989  break;
2990  default:
2991  /* The assert at the beginning of this function should prevent this switch case ! */
2992  return NULL;
2993  }
2994 
2995  /* Save this for later */
2996  gncOwnerCopy (gncOwnerGetEndOwner(start_owner), &(iw->owner));
2997  gncOwnerInitJob (&(iw->job), gncOwnerGetJob (start_owner));
2998 
2999  billto = gncInvoiceGetBillTo (invoice);
3000  gncOwnerCopy (gncOwnerGetEndOwner (billto), &(iw->proj_cust));
3001  gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (billto));
3002 
3003  /* Find the glade page layout */
3004  iw->builder = builder = gtk_builder_new();
3005  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "terms_store");
3006  gnc_builder_add_from_file (builder, "dialog-invoice.glade", "new_invoice_dialog");
3007  iw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "new_invoice_dialog"));
3008  gtk_window_set_transient_for (GTK_WINDOW(iw->dialog), parent);
3009 
3010  // Set the name for this dialog so it can be easily manipulated with css
3011  gtk_widget_set_name (GTK_WIDGET(iw->dialog), "gnc-id-invoice");
3012 
3013  g_object_set_data (G_OBJECT (iw->dialog), "dialog_info", iw);
3014 
3015  /* Grab the widgets */
3016  iw->type_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_label"));
3017  iw->type_label_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_label_hbox"));
3018  iw->id_label = GTK_WIDGET (gtk_builder_get_object (builder, "label14"));
3019  iw->info_label = GTK_WIDGET (gtk_builder_get_object (builder, "label1"));
3020  invoice_radio = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_invoice_type"));
3021 
3022  iw->type_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_choice_hbox"));
3023  iw->type_choice = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_invoice"));
3024 
3025  /* The default GUI labels are for invoices, so change them if it isn't. */
3026  owner_type = gncOwnerGetType (&iw->owner);
3027  switch(owner_type)
3028  {
3029  case GNC_OWNER_VENDOR:
3030  gtk_label_set_text (GTK_LABEL(iw->info_label), _("Bill Information"));
3031  gtk_label_set_text (GTK_LABEL(iw->type_label), _("Bill"));
3032  gtk_button_set_label (GTK_BUTTON(invoice_radio), _("Bill"));
3033  gtk_label_set_text (GTK_LABEL(iw->id_label), _("Bill ID"));
3034  style_label = "gnc-class-vendors";
3035  break;
3036  case GNC_OWNER_EMPLOYEE:
3037  gtk_label_set_text (GTK_LABEL(iw->info_label), _("Voucher Information"));
3038  gtk_label_set_text (GTK_LABEL(iw->type_label), _("Voucher"));
3039  gtk_button_set_label (GTK_BUTTON(invoice_radio), _("Voucher"));
3040  gtk_label_set_text (GTK_LABEL(iw->id_label), _("Voucher ID"));
3041  style_label = "gnc-class-employees";
3042  break;
3043  default:
3044  style_label = "gnc-class-customers";
3045  break;
3046  }
3047  // Set a secondary style context for this page so it can be easily manipulated with css
3048  gnc_widget_style_context_add_class (GTK_WIDGET(iw->dialog), style_label);
3049 
3050  /* configure the type related widgets based on dialog type and invoice type */
3051  switch (dialog_type)
3052  {
3053  case NEW_INVOICE:
3054  case DUP_INVOICE:
3055  gtk_widget_show_all (iw->type_hbox);
3056  gtk_widget_hide (iw->type_label_hbox);
3057  gtk_widget_hide (iw->type_label);
3058  break;
3059  case MOD_INVOICE:
3060  gtk_widget_hide (iw->type_hbox);
3061  gtk_widget_show (iw->type_label_hbox);
3062  gtk_widget_show (iw->type_label);
3063  break;
3064  default:
3065  break;
3066  }
3067 
3068  if (dialog_type == DUP_INVOICE)
3069  {
3070  GtkWidget *cn_radio = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_creditnote_type"));
3071 
3072  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(cn_radio), gncInvoiceGetIsCreditNote (invoice));
3073  }
3074 
3075  iw->id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_id_entry"));
3076  iw->billing_id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_billing_id_entry"));
3077  iw->terms_menu = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_terms_menu"));
3078  iw->notes_text = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_notes_text"));
3079  iw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_owner_hbox"));
3080  iw->owner_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_owner_label"));
3081  iw->job_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_job_label"));
3082  iw->job_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_job_hbox"));
3083 
3084  /* Grab the project widgets */
3085  iw->proj_frame = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_frame"));
3086  iw->proj_cust_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_cust_hbox"));
3087  iw->proj_job_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_job_hbox"));
3088 
3089  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_date_opened_hbox"));
3090  iw->opened_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
3091  gtk_widget_show(iw->opened_date);
3092  gtk_box_pack_start (GTK_BOX(hbox), iw->opened_date, TRUE, TRUE, 0);
3093 
3094  /* If this is a New Invoice, reset the Notes file to read/write */
3095  gtk_widget_set_sensitive (iw->notes_text,
3096  (iw->dialog_type == NEW_INVOICE) ||
3097  (iw->dialog_type == DUP_INVOICE));
3098 
3099  /* Setup signals */
3100  gtk_builder_connect_signals_full( builder,
3101  gnc_builder_connect_full_func,
3102  iw);
3103 
3104  /* Setup initial values */
3105  iw->reportPage = NULL;
3106  iw->invoice_guid = *gncInvoiceGetGUID (invoice);
3107  iw->is_credit_note = gncInvoiceGetIsCreditNote (invoice);
3108 
3109  iw->component_id =
3110  gnc_register_gui_component (DIALOG_NEW_INVOICE_CM_CLASS,
3111  gnc_invoice_window_refresh_handler,
3112  gnc_invoice_dialog_close_handler,
3113  iw);
3114 
3115  gnc_gui_component_watch_entity_type (iw->component_id,
3116  GNC_INVOICE_MODULE_NAME,
3117  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
3118 
3119  /* Now fill in a lot of the pieces and display properly */
3120  switch(dialog_type)
3121  {
3122  case NEW_INVOICE:
3123  case MOD_INVOICE:
3124  case DUP_INVOICE:
3125  gnc_billterms_combo (GTK_COMBO_BOX(iw->terms_menu), iw->book, TRUE, iw->terms);
3126  break;
3127  case EDIT_INVOICE:
3128  case VIEW_INVOICE:
3129  // Fill in the invoice view version
3130  if(gncBillTermGetName (iw->terms) != NULL)
3131  gtk_entry_set_text (GTK_ENTRY (iw->terms_menu),gncBillTermGetName (iw->terms));
3132  else
3133  gtk_entry_set_text (GTK_ENTRY (iw->terms_menu),"None");
3134  break;
3135  }
3136 
3137  gnc_invoice_update_window (iw, iw->dialog);
3139 
3140  // The customer choice widget should have keyboard focus
3141  if (GNC_IS_GENERAL_SEARCH(iw->owner_choice))
3142  {
3143  gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(iw->owner_choice));
3144  }
3145 
3146  return iw;
3147 }
3148 
3149 InvoiceWindow *
3150 gnc_ui_invoice_edit (GtkWindow *parent, GncInvoice *invoice)
3151 {
3152  InvoiceWindow *iw;
3153  InvoiceDialogType type;
3154 
3155  if (!invoice) return NULL;
3156 
3157  /* Immutable once we've been posted */
3158  if (gncInvoiceGetPostedAcc (invoice))
3159  type = VIEW_INVOICE;
3160  else
3161  type = EDIT_INVOICE;
3162 
3163  iw = gnc_invoice_new_page (gncInvoiceGetBook(invoice), type,
3164  invoice, gncInvoiceGetOwner (invoice),
3165  GNC_MAIN_WINDOW(gnc_ui_get_main_window (GTK_WIDGET (parent))), NULL);
3166 
3167  return iw;
3168 }
3169 
3170 static InvoiceWindow *
3171 gnc_ui_invoice_modify (GtkWindow *parent, GncInvoice *invoice)
3172 {
3173  InvoiceWindow *iw;
3174  if (!invoice) return NULL;
3175 
3176  iw = gnc_invoice_window_new_invoice (parent, MOD_INVOICE, NULL, NULL, invoice);
3177  return iw;
3178 }
3179 
3180 
3181 InvoiceWindow * gnc_ui_invoice_duplicate (GtkWindow *parent, GncInvoice *old_invoice, gboolean open_properties, const GDate *new_date)
3182 {
3183  InvoiceWindow *iw = NULL;
3184  GncInvoice *new_invoice = NULL;
3185  time64 entry_date;
3186 
3187  g_assert(old_invoice);
3188 
3189  // Create a deep copy of the old invoice
3190  new_invoice = gncInvoiceCopy(old_invoice);
3191 
3192  // The new invoice is for sure active
3193  gncInvoiceSetActive(new_invoice, TRUE);
3194 
3195  // and unposted
3196  if (gncInvoiceIsPosted (new_invoice))
3197  {
3198  gboolean result = gncInvoiceUnpost(new_invoice, TRUE);
3199  if (!result)
3200  {
3201  g_warning("Oops, error when unposting the copied invoice; ignoring.");
3202  }
3203  }
3204 
3205  // Unset the invoice ID, let it get allocated later
3206  gncInvoiceSetID(new_invoice, "");
3207 
3208  // Modify the date to today
3209  if (new_date)
3210  entry_date = gnc_time64_get_day_neutral (gdate_to_time64 (*new_date));
3211  else
3212  entry_date = gnc_time64_get_day_neutral (gnc_time (NULL));
3213  gncInvoiceSetDateOpened(new_invoice, entry_date);
3214 
3215  // Also modify the date of all entries to today
3216  //g_warning("We have %d entries", g_list_length(gncInvoiceGetEntries(new_invoice)));
3217  g_list_foreach(gncInvoiceGetEntries(new_invoice),
3218  &set_gncEntry_date, &entry_date);
3219 
3220 
3221  if (open_properties)
3222  {
3223  // Open the "properties" pop-up for the invoice...
3224  iw = gnc_invoice_window_new_invoice (parent, DUP_INVOICE, NULL, NULL, new_invoice);
3225  }
3226  else
3227  {
3228  // Open the newly created invoice in the "edit" window
3229  iw = gnc_ui_invoice_edit (parent, new_invoice);
3230  // Check the ID; set one if necessary
3231  if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (iw->id_entry)), "") == 0)
3232  {
3233  gncInvoiceSetID (new_invoice, gncInvoiceNextID(iw->book, &(iw->owner)));
3234  }
3235  }
3236  return iw;
3237 }
3238 
3239 InvoiceWindow *
3240 gnc_ui_invoice_new (GtkWindow *parent, GncOwner *owner, QofBook *book)
3241 {
3242  InvoiceWindow *iw;
3243  GncOwner inv_owner;
3244 
3245  if (owner)
3246  {
3247  gncOwnerCopy (owner, &inv_owner);
3248  }
3249  else
3250  gncOwnerInitCustomer (&inv_owner, NULL); /* XXX: pass in the owner type? */
3251 
3252  /* Make sure required options exist */
3253  if (!book) return NULL;
3254 
3255  iw = gnc_invoice_window_new_invoice (parent, NEW_INVOICE, book, &inv_owner, NULL);
3256 
3257  return iw;
3258 }
3259 
3260 /* Functions for invoice selection widgets */
3261 
3262 static void
3263 edit_invoice_direct (GtkWindow *dialog, gpointer invoice, gpointer user_data)
3264 {
3265  g_return_if_fail (invoice);
3266  gnc_ui_invoice_edit (gnc_ui_get_main_window (GTK_WIDGET (dialog)), invoice);
3267 }
3268 
3269 static void
3270 edit_invoice_cb (GtkWindow *dialog, gpointer inv, gpointer user_data)
3271 {
3272  GncInvoice *invoice = inv;
3273  g_return_if_fail (invoice && user_data);
3274  edit_invoice_direct (dialog, invoice, user_data);
3275 }
3276 
3279 {
3280  gpointer user_data;
3281  GtkWindow *parent;
3282  gchar *report_guid;
3283 };
3284 
3285 static void
3286 multi_edit_invoice_one (gpointer inv, gpointer user_data)
3287 {
3288  struct multi_edit_invoice_data *meid = user_data;
3289  edit_invoice_cb (meid->parent, inv, meid->user_data);
3290 }
3291 
3292 static void
3293 multi_edit_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_data)
3294 {
3295  struct multi_edit_invoice_data meid;
3296 
3297  meid.user_data = user_data;
3298  meid.parent = dialog;
3299  g_list_foreach (invoice_list, multi_edit_invoice_one, &meid);
3300 }
3301 
3302 static void
3303 pay_invoice_direct (GtkWindow *dialog, gpointer inv, gpointer user_data)
3304 {
3305  GncInvoice *invoice = inv;
3306 
3307  g_return_if_fail (invoice);
3308  gnc_ui_payment_new_with_invoice (dialog, gncInvoiceGetOwner (invoice),
3309  gncInvoiceGetBook (invoice), invoice);
3310 }
3311 
3312 static void
3313 pay_invoice_cb (GtkWindow *dialog, gpointer *invoice_p, gpointer user_data)
3314 {
3315  g_return_if_fail (invoice_p && user_data);
3316  if (! *invoice_p)
3317  return;
3318  pay_invoice_direct (dialog, *invoice_p, user_data);
3319 }
3322 {
3323  GDate date;
3324  GtkWindow *parent;
3325 };
3326 
3327 static void multi_duplicate_invoice_one(gpointer data, gpointer user_data)
3328 {
3329  GncInvoice *old_invoice = data;
3330  struct multi_duplicate_invoice_data *dup_user_data = user_data;
3331 
3332  g_assert(dup_user_data);
3333  if (old_invoice)
3334  {
3335  GncInvoice *new_invoice;
3336  // In this simplest form, we just use the existing duplication
3337  // algorithm, only without opening the "edit invoice" window for editing
3338  // the number etc. for each of the invoices.
3339  InvoiceWindow *iw = gnc_ui_invoice_duplicate(dup_user_data->parent, old_invoice, FALSE, &dup_user_data->date);
3340  // FIXME: Now we could use this invoice and manipulate further data.
3341  g_assert(iw);
3342  new_invoice = iw_get_invoice(iw);
3343  g_assert(new_invoice);
3344  }
3345 }
3346 
3347 static void
3348 multi_duplicate_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_data)
3349 {
3350  g_return_if_fail (invoice_list);
3351  switch (g_list_length(invoice_list))
3352  {
3353  case 0:
3354  return;
3355  case 1:
3356  {
3357  // Duplicate exactly one invoice
3358  GncInvoice *old_invoice = invoice_list->data;
3359  gnc_ui_invoice_duplicate(dialog, old_invoice, TRUE, NULL);
3360  return;
3361  }
3362  default:
3363  {
3364  // Duplicate multiple invoices. We ask for a date first.
3365  struct multi_duplicate_invoice_data dup_user_data;
3366  gboolean dialog_ok;
3367 
3368  // Default date: Today
3369  gnc_gdate_set_time64(&dup_user_data.date, gnc_time (NULL));
3370  dup_user_data.parent = dialog;
3371  dialog_ok = gnc_dup_date_dialog (GTK_WIDGET(dialog), _("Date of duplicated entries"), &dup_user_data.date);
3372  if (!dialog_ok)
3373  {
3374  // User pressed cancel, so don't duplicate anything here.
3375  return;
3376  }
3377 
3378  // Note: If we want to have a more sophisticated duplication, we might want
3379  // to ask for particular data right here, then insert this data upon
3380  // duplication.
3381  g_list_foreach(invoice_list, multi_duplicate_invoice_one, &dup_user_data);
3382  return;
3383  }
3384  }
3385 }
3386 
3387 static void post_one_invoice_cb(gpointer data, gpointer user_data)
3388 {
3389  GncInvoice *invoice = data;
3390  struct post_invoice_params *post_params = user_data;
3391  InvoiceWindow *iw = gnc_ui_invoice_edit(post_params->parent, invoice);
3392  gnc_invoice_post(iw, post_params);
3393 }
3394 
3395 static void gnc_invoice_is_posted(gpointer inv, gpointer test_value)
3396 {
3397  GncInvoice *invoice = inv;
3398  gboolean *test = (gboolean*)test_value;
3399 
3400  if (gncInvoiceIsPosted (invoice))
3401  {
3402  *test = TRUE;
3403  }
3404 }
3405 
3406 
3407 static void
3408 multi_post_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_data)
3409 {
3410  struct post_invoice_params post_params;
3411  gboolean test;
3412  InvoiceWindow *iw;
3413 
3414  if (!gnc_list_length_cmp (invoice_list, 0))
3415  return;
3416  // Get the posting parameters for these invoices
3417  iw = gnc_ui_invoice_edit(dialog, invoice_list->data);
3418  test = FALSE;
3419  gnc_suspend_gui_refresh (); // Turn off GUI refresh for the duration.
3420  // Check if any of the selected invoices have already been posted.
3421  g_list_foreach(invoice_list, gnc_invoice_is_posted, &test);
3422  gnc_resume_gui_refresh ();
3423  if (test)
3424  {
3425  gnc_error_dialog (GTK_WINDOW (iw_get_window(iw)), "%s",
3426  _("One or more selected invoices have already been posted.\nRe-check your selection."));
3427  return;
3428  }
3429 
3430  if (!gnc_dialog_post_invoice(iw, _("Do you really want to post these invoices?"),
3431  &post_params.ddue, &post_params.postdate,
3432  &post_params.memo, &post_params.acc,
3433  &post_params.accumulate))
3434  return;
3435  post_params.parent = dialog;
3436 
3437  // Turn off GUI refresh for the duration. This is more than just an
3438  // optimization. If the search that got us here is based on the "posted"
3439  // status of an invoice, the updating the GUI will change the list we're
3440  // working on which leads to bad things happening.
3441  gnc_suspend_gui_refresh ();
3442  g_list_foreach(invoice_list, post_one_invoice_cb, &post_params);
3443  gnc_resume_gui_refresh ();
3444 }
3445 
3446 static void print_one_invoice_cb(GtkWindow *dialog, gpointer data, gpointer user_data)
3447 {
3448  GncInvoice *invoice = data;
3449  struct multi_edit_invoice_data *meid = user_data;
3450  gnc_invoice_window_print_invoice (dialog, invoice, meid->report_guid);
3451 }
3452 
3453 static void
3454 multi_print_invoice_one (gpointer data, gpointer user_data)
3455 {
3456  struct multi_edit_invoice_data *meid = user_data;
3457  print_one_invoice_cb (gnc_ui_get_main_window (GTK_WIDGET(meid->parent)), data, meid);
3458 }
3459 
3460 static void
3461 multi_print_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_data)
3462 {
3463  gchar *report_guid = NULL;
3464  struct multi_edit_invoice_data meid;
3465 
3466  if (!gnc_list_length_cmp (invoice_list, 0))
3467  return;
3468 
3469  report_guid = use_default_report_template_or_change (dialog);
3470 
3471  if (!report_guid)
3472  return;
3473 
3474  meid.user_data = user_data;
3475  meid.parent = dialog;
3476  meid.report_guid = report_guid;
3477 
3478  g_list_foreach (invoice_list, multi_print_invoice_one, &meid);
3479  g_free (report_guid);
3480 }
3481 
3482 static gpointer
3483 new_invoice_cb (GtkWindow *dialog, gpointer user_data)
3484 {
3485  struct _invoice_select_window *sw = user_data;
3486  InvoiceWindow *iw;
3487 
3488  g_return_val_if_fail (user_data, NULL);
3489 
3490  iw = gnc_ui_invoice_new (dialog, sw->owner, sw->book);
3491  return iw_get_invoice (iw);
3492 }
3493 
3494 static void
3495 free_invoice_cb (gpointer user_data)
3496 {
3497  struct _invoice_select_window *sw = user_data;
3498 
3499  g_return_if_fail (sw);
3500 
3501  qof_query_destroy (sw->q);
3502  g_free (sw);
3503 }
3504 
3505 GNCSearchWindow *
3506 gnc_invoice_search (GtkWindow *parent, GncInvoice *start, GncOwner *owner, QofBook *book)
3507 {
3508  QofIdType type = GNC_INVOICE_MODULE_NAME;
3509  struct _invoice_select_window *sw;
3510  QofQuery *q, *q2 = NULL;
3511  GncOwnerType owner_type = GNC_OWNER_CUSTOMER;
3512  static GList *inv_params = NULL, *bill_params = NULL, *emp_params = NULL, *params;
3513  static GList *columns = NULL;
3514  const gchar *title, *label, *style_class;
3515  static GNCSearchCallbackButton *buttons;
3516  static GNCSearchCallbackButton inv_buttons[] =
3517  {
3518  { N_("View/Edit Invoice"), NULL, multi_edit_invoice_cb, TRUE},
3519  { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
3520  { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
3521  { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
3522  { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
3523  { NULL },
3524  };
3525  static GNCSearchCallbackButton bill_buttons[] =
3526  {
3527  { N_("View/Edit Bill"), NULL, multi_edit_invoice_cb, TRUE},
3528  { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
3529  { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
3530  { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
3531  { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
3532  { NULL },
3533  };
3534  static GNCSearchCallbackButton emp_buttons[] =
3535  {
3536  /* Translators: The terms 'Voucher' and 'Expense Voucher' are used
3537  interchangeably in gnucash and mean the same thing. */
3538  { N_("View/Edit Voucher"), NULL, multi_edit_invoice_cb, TRUE},
3539  { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
3540  { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
3541  { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
3542  { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
3543  { NULL },
3544  };
3545 
3546  g_return_val_if_fail (book, NULL);
3547 
3548  /* Build parameter list in reverse order */
3549  if (inv_params == NULL)
3550  {
3551  inv_params = gnc_search_param_prepend (inv_params,
3552  _("Invoice Owner"), NULL, type,
3553  INVOICE_OWNER, NULL);
3554  inv_params = gnc_search_param_prepend (inv_params,
3555  _("Invoice Notes"), NULL, type,
3556  INVOICE_NOTES, NULL);
3557  inv_params = gnc_search_param_prepend (inv_params,
3558  _("Billing ID"), NULL, type,
3559  INVOICE_BILLINGID, NULL);
3560  inv_params = gnc_search_param_prepend (inv_params,
3561  _("Is Paid?"), NULL, type,
3562  INVOICE_IS_PAID, NULL);
3563  inv_params = gnc_search_param_prepend (inv_params,
3564  _("Date Posted"), NULL, type,
3565  INVOICE_POSTED, NULL);
3566  inv_params = gnc_search_param_prepend (inv_params,
3567  _("Is Posted?"), NULL, type,
3568  INVOICE_IS_POSTED, NULL);
3569  inv_params = gnc_search_param_prepend (inv_params,
3570  _("Date Opened"), NULL, type,
3571  INVOICE_OPENED, NULL);
3572  inv_params = gnc_search_param_prepend (inv_params,
3573  _("Due Date"), NULL, type,
3574  INVOICE_DUE, NULL);
3575  inv_params = gnc_search_param_prepend (inv_params,
3576  _("Company Name"), NULL, type,
3577  INVOICE_OWNER, OWNER_PARENT,
3578  OWNER_NAME, NULL);
3579  inv_params = gnc_search_param_prepend (inv_params,
3580  _("Invoice ID"), NULL, type,
3581  INVOICE_ID, NULL);
3582  }
3583  if (bill_params == NULL)
3584  {
3585  bill_params = gnc_search_param_prepend (bill_params,
3586  _("Bill Owner"), NULL, type,
3587  INVOICE_OWNER, NULL);
3588  bill_params = gnc_search_param_prepend (bill_params,
3589  _("Bill Notes"), NULL, type,
3590  INVOICE_NOTES, NULL);
3591  bill_params = gnc_search_param_prepend (bill_params,
3592  _("Billing ID"), NULL, type,
3593  INVOICE_BILLINGID, NULL);
3594  bill_params = gnc_search_param_prepend (bill_params,
3595  _("Is Paid?"), NULL, type,
3596  INVOICE_IS_PAID, NULL);
3597  bill_params = gnc_search_param_prepend (bill_params,
3598  _("Date Posted"), NULL, type,
3599  INVOICE_POSTED, NULL);
3600  bill_params = gnc_search_param_prepend (bill_params,
3601  _("Is Posted?"), NULL, type,
3602  INVOICE_IS_POSTED, NULL);
3603  bill_params = gnc_search_param_prepend (bill_params,
3604  _("Date Opened"), NULL, type,
3605  INVOICE_OPENED, NULL);
3606  bill_params = gnc_search_param_prepend (bill_params,
3607  _("Due Date"), NULL, type,
3608  INVOICE_DUE, NULL);
3609  bill_params = gnc_search_param_prepend (bill_params,
3610  _("Company Name"), NULL, type,
3611  INVOICE_OWNER, OWNER_PARENT,
3612  OWNER_NAME, NULL);
3613  bill_params = gnc_search_param_prepend (bill_params,
3614  _("Bill ID"), NULL, type,
3615  INVOICE_ID, NULL);
3616  }
3617  if (emp_params == NULL)
3618  {
3619  emp_params = gnc_search_param_prepend (emp_params,
3620  _("Voucher Owner"), NULL, type,
3621  INVOICE_OWNER, NULL);
3622  emp_params = gnc_search_param_prepend (emp_params,
3623  _("Voucher Notes"), NULL, type,
3624  INVOICE_NOTES, NULL);
3625  emp_params = gnc_search_param_prepend (emp_params,
3626  _("Billing ID"), NULL, type,
3627  INVOICE_BILLINGID, NULL);
3628  emp_params = gnc_search_param_prepend (emp_params,
3629  _("Is Paid?"), NULL, type,
3630  INVOICE_IS_PAID, NULL);
3631  emp_params = gnc_search_param_prepend (emp_params,
3632  _("Date Posted"), NULL, type,
3633  INVOICE_POSTED, NULL);
3634  emp_params = gnc_search_param_prepend (emp_params,
3635  _("Is Posted?"), NULL, type,
3636  INVOICE_IS_POSTED, NULL);
3637  emp_params = gnc_search_param_prepend (emp_params,
3638  _("Date Opened"), NULL, type,
3639  INVOICE_OPENED, NULL);
3640  emp_params = gnc_search_param_prepend (emp_params,
3641  _("Due Date"), NULL, type,
3642  INVOICE_DUE, NULL);
3643  emp_params = gnc_search_param_prepend (emp_params,
3644  _("Employee Name"), NULL, type,
3645  INVOICE_OWNER, OWNER_PARENT,
3646  OWNER_NAME, NULL);
3647  emp_params = gnc_search_param_prepend (emp_params,
3648  _("Voucher ID"), NULL, type,
3649  INVOICE_ID, NULL);
3650  }
3651 
3652  /* Build the column list in reverse order */
3653  if (columns == NULL)
3654  {
3655  columns = gnc_search_param_prepend (columns, _("Billing ID"), NULL, type,
3656  INVOICE_BILLINGID, NULL);
3657  columns = gnc_search_param_prepend (columns, _("Type"), NULL, type,
3658  INVOICE_TYPE_STRING, NULL);
3659  columns = gnc_search_param_prepend_with_justify (columns, _("Paid"),
3660  GTK_JUSTIFY_CENTER, NULL, type,
3661  INVOICE_IS_PAID, NULL);
3662  columns = gnc_search_param_prepend (columns, _("Posted"), NULL, type,
3663  INVOICE_POSTED, NULL);
3664  columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,
3665  INVOICE_OWNER, OWNER_PARENT,
3666  OWNER_NAME, NULL);
3667  columns = gnc_search_param_prepend (columns, _("Due"), NULL, type,
3668  INVOICE_DUE, NULL);
3669  columns = gnc_search_param_prepend (columns, _("Opened"), NULL, type,
3670  INVOICE_OPENED, NULL);
3671  columns = gnc_search_param_prepend (columns, _("Num"), NULL, type,
3672  INVOICE_ID, NULL);
3673  }
3674 
3675  /* Build the queries */
3676  q = qof_query_create_for (type);
3677  qof_query_set_book (q, book);
3678 
3679  /* If owner is supplied, limit all searches to invoices who's owner
3680  * or end-owner is the supplied owner! Show all invoices by this
3681  * owner. If a Job is supplied, search for all invoices for that
3682  * job, but if a Customer is supplied, search for all invoices owned
3683  * by that Customer or any of that Customer's Jobs. In other words,
3684  * match on <supplied-owner's guid> == Invoice->Owner->GncGUID or
3685  * Invoice->owner->parentGUID.
3686  */
3687  if (owner)
3688  {
3689  /* First, figure out the type of owner here.. */
3690  owner_type = gncOwnerGetType (gncOwnerGetEndOwner (owner));
3691 
3692  /* Then if there's an actual owner add it to the query
3693  * and limit the search to this owner
3694  * If there's only a type, limit the search to this type.
3695  */
3696  if (gncOwnerGetGUID (owner))
3697  {
3698  q2 = qof_query_create ();
3699  qof_query_add_guid_match (q2, g_slist_prepend
3700  (g_slist_prepend (NULL, QOF_PARAM_GUID),
3701  INVOICE_OWNER),
3702  gncOwnerGetGUID (owner), QOF_QUERY_OR);
3703 
3704  qof_query_add_guid_match (q2, g_slist_prepend
3705  (g_slist_prepend (NULL, OWNER_PARENTG),
3706  INVOICE_OWNER),
3707  gncOwnerGetGUID (owner), QOF_QUERY_OR);
3708  qof_query_merge_in_place (q, q2, QOF_QUERY_AND);
3709  qof_query_destroy (q2);
3710 
3711  /* Use this base query as pre-fill query.
3712  * This will pre-fill the search dialog with the query results
3713  */
3714  q2 = qof_query_copy (q);
3715 
3716  }
3717  else
3718  {
3719  QofQuery *q3 = qof_query_create ();
3720  QofQueryPredData *inv_type_pred = NULL;
3721  GList *type_list = NULL, *node = NULL;
3722 
3723  type_list = gncInvoiceGetTypeListForOwnerType(owner_type);
3724  for (node = type_list; node; node = node->next)
3725  {
3726  inv_type_pred = qof_query_int32_predicate(QOF_COMPARE_EQUAL,
3727  GPOINTER_TO_INT(node->data));
3728  qof_query_add_term (q3, g_slist_prepend (NULL, INVOICE_TYPE), inv_type_pred, QOF_QUERY_OR);
3729  }
3730  qof_query_merge_in_place (q, q3, QOF_QUERY_AND);
3731  qof_query_destroy (q3);
3732 
3733  /* Don't set a pre-fill query in this case, the result set would be too long */
3734  q2 = NULL;
3735  }
3736  }
3737 
3738  /* Launch select dialog and return the result */
3739  sw = g_new0 (struct _invoice_select_window, 1);
3740 
3741  if (owner)
3742  {
3743  gncOwnerCopy (owner, &(sw->owner_def));
3744  sw->owner = &(sw->owner_def);
3745  }
3746  sw->book = book;
3747  sw->q = q;
3748 
3749  switch (owner_type)
3750  {
3751  case GNC_OWNER_VENDOR:
3752  title = _("Find Bill");
3753  label = _("Bill");
3754  style_class = "gnc-class-bills";
3755  params = bill_params;
3756  buttons = bill_buttons;
3757  break;
3758  case GNC_OWNER_EMPLOYEE:
3759  title = _("Find Expense Voucher");
3760  label = _("Expense Voucher");
3761  style_class = "gnc-class-vouchers";
3762  params = emp_params;
3763  buttons = emp_buttons;
3764  break;
3765  default:
3766  title = _("Find Invoice");
3767  label = _("Invoice");
3768  style_class = "gnc-class-invoices";
3769  params = inv_params;
3770  buttons = inv_buttons;
3771  break;
3772  }
3773  return gnc_search_dialog_create (parent, type, title, params, columns, q, q2,
3774  buttons, NULL, new_invoice_cb,
3775  sw, free_invoice_cb, GNC_PREFS_GROUP_SEARCH,
3776  label, style_class);
3777 }
3778 
3779 DialogQueryView *
3780 gnc_invoice_show_docs_due (GtkWindow *parent, QofBook *book, double days_in_advance, GncWhichDueType duetype)
3781 {
3782  QofIdType type = GNC_INVOICE_MODULE_NAME;
3783  Query *q;
3784  QofQueryPredData* pred_data;
3785  time64 end_date;
3786  GList *res;
3787  gchar *message, *title;
3788  gchar *prefs_group;
3789  DialogQueryView *dialog;
3790  gint len;
3791  static GList *param_list = NULL;
3792  static GNCDisplayViewButton vendorbuttons[] =
3793  {
3794  { N_("View/Edit Bill"), edit_invoice_direct },
3795  { N_("Process Payment"), pay_invoice_direct },
3796  { NULL },
3797  };
3798  static GNCDisplayViewButton customerbuttons[] =
3799  {
3800  { N_("View/Edit Invoice"), edit_invoice_direct },
3801  { N_("Process Payment"), pay_invoice_direct },
3802  { NULL },
3803  };
3804 
3805  if (!book)
3806  {
3807  PERR("No book, no due invoices.");
3808  return NULL;
3809  }
3810 
3811  /* Create the param list (in reverse order) */
3812  if (param_list == NULL)
3813  {
3814  param_list = gnc_search_param_prepend_with_justify (param_list, _("Amount"),
3815  GTK_JUSTIFY_RIGHT, NULL, type,
3816  INVOICE_POST_LOT, LOT_BALANCE, NULL);
3817  param_list = gnc_search_param_prepend (param_list, _("Type"), NULL, type,
3818  INVOICE_TYPE_STRING, NULL);
3819  param_list = gnc_search_param_prepend (param_list, _("Company"), NULL, type,
3820  INVOICE_OWNER, OWNER_PARENT, OWNER_NAME, NULL);
3821  param_list = gnc_search_param_prepend (param_list, _("Due"), NULL, type,
3822  INVOICE_DUE, NULL);
3823  }
3824 
3825  /* Create the query to search for invoices; set the book */
3826  q = qof_query_create();
3827  qof_query_search_for(q, GNC_INVOICE_MODULE_NAME);
3828  qof_query_set_book (q, book);
3829 
3830  /* For vendor bills we want to find all invoices where:
3831  * invoice -> is_posted == TRUE
3832  * AND invoice -> lot -> is_closed? == FALSE
3833  * AND invoice -> type != customer invoice
3834  * AND invoice -> type != customer credit note
3835  * AND invoice -> due <= (today + days_in_advance)
3836  */
3837 
3838  /* For customer invoices we want to find all invoices where:
3839  * invoice -> is_posted == TRUE
3840  * AND invoice -> lot -> is_closed? == FALSE
3841  * AND invoice -> type != vendor bill
3842  * AND invoice -> type != vendor credit note
3843  * AND invoice -> type != employee voucher
3844  * AND invoice -> type != employee credit note
3845  * AND invoice -> due <= (today + days_in_advance)
3846  * This could probably also be done by searching for customer invoices OR customer credit notes
3847  * but that would make a more complicated query to compose.
3848  */
3849 
3850  qof_query_add_boolean_match (q, g_slist_prepend(NULL, INVOICE_IS_POSTED), TRUE,
3851  QOF_QUERY_AND);
3852 
3853  qof_query_add_boolean_match (q, g_slist_prepend(g_slist_prepend(NULL, LOT_IS_CLOSED),
3854  INVOICE_POST_LOT), FALSE, QOF_QUERY_AND);
3855 
3856 
3857  if (duetype == DUE_FOR_VENDOR)
3858  {
3859  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_CUST_INVOICE);
3860  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3861 
3862  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_CUST_CREDIT_NOTE);
3863  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3864  }
3865  else
3866  {
3867  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_VEND_INVOICE);
3868  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3869 
3870  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_VEND_CREDIT_NOTE);
3871  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3872 
3873  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_EMPL_INVOICE);
3874  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3875 
3876  pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_EMPL_CREDIT_NOTE);
3877  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
3878  }
3879 
3880  end_date = gnc_time (NULL);
3881  if (days_in_advance < 0)
3882  days_in_advance = 0;
3883  end_date += days_in_advance * 60 * 60 * 24;
3884 
3885  pred_data = qof_query_date_predicate (QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, end_date);
3886  qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_DUE), pred_data, QOF_QUERY_AND);
3887 
3888  res = qof_query_run(q);
3889  len = g_list_length (res);
3890  if (!res || len <= 0)
3891  {
3892  qof_query_destroy(q);
3893  return NULL;
3894  }
3895 
3896  if (duetype == DUE_FOR_VENDOR)
3897  {
3898  prefs_group = GNC_PREFS_GROUP_VENDOR;
3899  message = g_strdup_printf
3900  (/* Translators: %d is the number of bills/credit notes due. This is a
3901  ngettext(3) message. */
3902  ngettext("The following vendor document is due:",
3903  "The following %d vendor documents are due:",
3904  len),
3905  len);
3906  title = _("Due Bills Reminder");
3907  }
3908  else
3909  {
3910  prefs_group = GNC_PREFS_GROUP_CUSTOMER;
3911  message = g_strdup_printf
3912  (/* Translators: %d is the number of invoices/credit notes due. This is a
3913  ngettext(3) message. */
3914  ngettext("The following customer document is due:",
3915  "The following %d customer documents are due:",
3916  len),
3917  len);
3918  title = _("Due Invoices Reminder");
3919  }
3920 
3921  dialog = gnc_dialog_query_view_create(parent, param_list, q,
3922  title,
3923  message,
3924  TRUE, FALSE,
3925  1, GTK_SORT_ASCENDING,
3926  1, // columns start from 0
3927  duetype == DUE_FOR_VENDOR ?
3928  vendorbuttons :
3929  customerbuttons,
3930  prefs_group, NULL);
3931 
3932  g_free(message);
3933  qof_query_destroy(q);
3934  return dialog;
3935 }
3936 
3937 void
3938 gnc_invoice_remind_bills_due (GtkWindow *parent)
3939 {
3940  QofBook *book;
3941  gint days;
3942 
3943  if (!gnc_current_session_exist()) return;
3944  book = qof_session_get_book(gnc_get_current_session());
3945  days = gnc_prefs_get_float(GNC_PREFS_GROUP_BILL, GNC_PREF_DAYS_IN_ADVANCE);
3946 
3947  gnc_invoice_show_docs_due (parent, book, days, DUE_FOR_VENDOR);
3948 }
3949 
3950 void
3951 gnc_invoice_remind_invoices_due (GtkWindow *parent)
3952 {
3953  QofBook *book;
3954  gint days;
3955 
3956  if (!gnc_current_session_exist()) return;
3957  book = qof_session_get_book(gnc_get_current_session());
3958  days = gnc_prefs_get_float(GNC_PREFS_GROUP_INVOICE, GNC_PREF_DAYS_IN_ADVANCE);
3959 
3960  gnc_invoice_show_docs_due (parent, book, days, DUE_FOR_CUSTOMER);
3961 }
3962 
3963 void
3964 gnc_invoice_remind_bills_due_cb (void)
3965 {
3966  if (!gnc_prefs_get_bool(GNC_PREFS_GROUP_BILL, GNC_PREF_NOTIFY_WHEN_DUE))
3967  return;
3968 
3969  gnc_invoice_remind_bills_due (GTK_WINDOW(gnc_ui_get_main_window (NULL)));
3970 }
3971 
3972 void
3973 gnc_invoice_remind_invoices_due_cb (void)
3974 {
3975  if (!gnc_prefs_get_bool(GNC_PREFS_GROUP_INVOICE, GNC_PREF_NOTIFY_WHEN_DUE))
3976  return;
3977 
3978  gnc_invoice_remind_invoices_due (GTK_WINDOW(gnc_ui_get_main_window (NULL)));
3979 }
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Returns a GList of currencies associated with the owner.
Definition: gncOwner.c:1462
GNCPrice * gnc_price_create(QofBook *book)
gnc_price_create - returns a newly allocated and initialized price with a reference count of 1...
utility functions for the GnuCash UI
Functions to load, save and get gui state.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Get the GncGUID of the immediate owner.
Definition: gncOwner.c:518
void qof_query_add_term(QofQuery *q, QofQueryParamList *param_list, QofQueryPredData *pred_data, QofQueryOp op)
This is the general function that adds a new Query Term to a query.
Definition: qofquery.cpp:681
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Business Interface: Object OWNERs.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
The instance data structure for a content plugin.
void gncEntrySetQuantity(GncEntry *entry, gnc_numeric quantity)
Set the internal quantity without any conversion.
Definition: gncEntry.c:551
Date and Time handling routines.
This file contains the functions to present a gui to the user for creating a new account or editing a...
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Returns a GList of account-types based on the owner type.
Definition: gncOwner.c:1444
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1249
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.
gdouble qof_book_get_default_invoice_report_timeout(const QofBook *book)
Get the length of time available to change the used Invoice Report when printing Invoices.
Definition: qofbook.cpp:1132
gint gnc_state_drop_sections_for(const gchar *partial_name)
Drop all sections from the state file whose name contains partial_name.
Definition: gnc-state.c:260
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
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 * gnc_wrap_text_with_bidi_ltr_isolate(const char *text)
This function helps with GTK&#39;s use of &#39;Unicode Bidirectional Text Algorithm&#39;.
void gnc_entry_ledger_move_current_entry_updown(GncEntryLedger *ledger, gboolean move_up)
This implements the command of moving the current entry (where the cursor is currently located) one r...
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.
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
Definition: qofquery.cpp:1018
void gncInvoiceRemoveEntries(GncInvoice *invoice)
Remove all entries from an invoice.
Definition: gncInvoice.c:760
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
GncEntryLedger * gnc_entry_ledger_new(QofBook *book, GncEntryLedgerType type)
Create and return a new GncEntry Ledger.
Transaction * gncInvoicePostToAccount(GncInvoice *invoice, Account *acc, time64 post_date, time64 due_date, const char *memo, gboolean accumulatesplits, gboolean autopay)
Post this invoice to an account.
Definition: gncInvoice.c:1496
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:173
GHashTable * gncInvoiceGetForeignCurrencies(const GncInvoice *invoice)
Return an overview of amounts on this invoice that will be posted to accounts in currencies that are ...
Definition: gncInvoice.c:1362
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
GtkWidget * gnucash_register_new(Table *table, const gchar *state_section)
this already has scrollbars attached
gnc_numeric gncInvoiceGetTotal(GncInvoice *invoice)
Return the "total" amount of the invoice as seen on the document (and shown to the user in the report...
Definition: gncInvoice.c:1008
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
void gnc_plugin_page_invoice_update_menus(GncPluginPage *page, gboolean is_posted, gboolean can_unpost)
Update the menu items associated with this invoice page.
void gnc_main_window_display_page(GncPluginPage *page)
Bring the window containing the specified page to the top of the window stack, then switch the notebo...
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
Functions for adding content to a window.
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:275
time64 gncEntryGetDate(const GncEntry *entry)
DEPRECATED - use gncEntryGetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:913
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:80
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:574
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
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
GncEntry * gnc_entry_ledger_get_current_entry(GncEntryLedger *ledger)
Returns the Entry where the cursor is currently located.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition: guid.cpp:204
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
GncPluginPage * gnc_plugin_page_invoice_new(InvoiceWindow *iw)
Create a new "invoice" plugin page, given a pointer to an InvoiceWindow data structure.
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
return the type for the collection.
Definition: gncOwner.c:230
Functions for adding plugins to a GnuCash window.
#define gncInvoiceGetGUID(x)
deprecated functions
Definition: gncInvoice.h:315
gboolean gnc_entry_ledger_check_close(GtkWidget *parent, GncEntryLedger *ledger)
This will ask the user if they really want to make a change.
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1253
Public declarations of GnucashRegister class.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
This data structure does double duty.
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
GncPluginPage * gnc_plugin_page_report_new(int reportId)
void qof_query_add_guid_match(QofQuery *q, QofQueryParamList *param_list, const GncGUID *guid, QofQueryOp op)
DOCUMENT ME !!
Definition: qofquery.cpp:1310
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
Business Invoice Interface.
GncJob * gncOwnerGetJob(const GncOwner *owner)
If the given owner is of type GNC_OWNER_JOB, returns the pointer to the job object.
Definition: gncOwner.c:376
gboolean gncInvoiceUnpost(GncInvoice *invoice, gboolean reset_tax_tables)
Unpost this invoice.
Definition: gncInvoice.c:1790
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
void gnc_entry_ledger_destroy(GncEntryLedger *ledger)
Destroy the GncEntry Ledger.
gchar * qof_book_get_default_invoice_report_name(const QofBook *book)
Get the name of the Invoice Report to be used as the default for printing Invoices.
Definition: qofbook.cpp:1101
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1244
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
gnc_numeric gncEntryGetQuantity(const GncEntry *entry)
Get the quantity as stored internally.
Definition: gncEntry.c:946
void gnc_entry_ledger_set_default_invoice(GncEntryLedger *ledger, GncInvoice *invoice)
Set the default invoice for this ledger.
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition: qofquery.h:105
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
If the given owner is of type GNC_OWNER_VENDOR, returns the pointer to the vendor object...
Definition: gncOwner.c:383
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
If the given owner is of type GNC_OWNER_CUSTOMER, returns the pointer to the customer object...
Definition: gncOwner.c:369
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
Table * gnc_entry_ledger_get_table(GncEntryLedger *ledger)
Get the Table.
Utility functions for convert uri in separate components and back.
void gnc_table_save_state(Table *table, const gchar *state_section)
Implementation.
Definition: table-gnome.c:71
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void gncEntrySetDate(GncEntry *entry, time64 date)
DEPRECATED - use gncEntrySetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:482
FROM_STRING_DEC(CheckItemType, ENUM_CHECK_ITEM_TYPE)
void qof_query_add_boolean_match(QofQuery *q, QofQueryParamList *param_list, gboolean value, QofQueryOp op)
Handy-dandy convenience routines, avoids having to create a separate predicate for boolean matches...
Definition: qofquery.cpp:1347
GncEmployee * gncOwnerGetEmployee(const GncOwner *owner)
If the given owner is of type GNC_OWNER_EMPLOYEE, returns the pointer to the employee object...
Definition: gncOwner.c:390
gboolean gnc_entry_ledger_get_entry_virt_loc(GncEntryLedger *ledger, const GncEntry *entry, VirtualCellLocation *vcell_loc)
Looks up the cell location of the given "entry" and writes the location into the variable pointed to ...
gint gnc_list_length_cmp(const GList *list, size_t len)
Scans the GList elements the minimum number of iterations required to test it against a specified siz...
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
The type used to store guids in C.
Definition: guid.h:75
GncInvoice * gncInvoiceCopy(const GncInvoice *from)
Create a new GncInvoice object as a deep copy of the given other invoice.
Definition: gncInvoice.c:336
QofQuery * qof_query_create(void)
Create a new query.
Definition: qofquery.cpp:918
A Query.
Definition: qofquery.cpp:74
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
GncEntry * gnc_entry_ledger_get_blank_entry(GncEntryLedger *ledger)
Exported Functions.
void qof_query_search_for(QofQuery *q, QofIdTypeConst obj_type)
Set the object type to be searched for.
Definition: qofquery.cpp:926
InvoiceWindow * gnc_plugin_page_invoice_get_window(GncInvoice *invoice)
Find the Invoice Window amongst the plugin pages for an Invoice, if not present return NULL...
void gnc_plugin_page_invoice_update_title(GncPluginPage *plugin_page)
Update the title associated with this invoice page.
gboolean gnc_entry_ledger_commit_entry(GncEntryLedger *ledger)
This will act just like hitting &#39;return&#39; to record an entry.
time64 gnc_time64_get_day_neutral(time64 time_val)
The gnc_time64_get_day_neutral() routine will take the given time in seconds and adjust it to 10:59:0...
Definition: gnc-date.cpp:1307
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Get an float value from the preferences backend.
void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Like qof_query_merge, but this will merge a copy of q2 into q1.
Definition: qofquery.cpp:1236
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2032