GnuCash 2.4.99
dialog-invoice.c
00001 /*
00002  * dialog-invoice.c -- Dialog for Invoice entry
00003  * Copyright (C) 2001,2002,2006 Derek Atkins
00004  * Author: Derek Atkins <warlord@MIT.EDU>
00005  *
00006  * Copyright (c) 2005,2006 David Hampton <hampton@employees.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, contact:
00020  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00024  */
00025 
00026 #include "config.h"
00027 
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 #include <libguile.h>
00031 #include "swig-runtime.h"
00032 
00033 #include "qof.h"
00034 
00035 #include "dialog-utils.h"
00036 #include "gnc-component-manager.h"
00037 #include "gnc-ui.h"
00038 #include "gnc-gconf-utils.h"
00039 #include "gnc-gui-query.h"
00040 #include "gnc-ui-util.h"
00041 #include "gnc-date-edit.h"
00042 #include "gnc-amount-edit.h"
00043 #include "gnucash-sheet.h"
00044 #include "window-report.h"
00045 #include "dialog-search.h"
00046 #include "search-param.h"
00047 #include "gnc-session.h"
00048 #include "gncOwner.h"
00049 #include "gncInvoice.h"
00050 #include "gncInvoiceP.h"
00051 
00052 #include "gncEntryLedger.h"
00053 
00054 #include "gnc-plugin-page.h"
00055 #include "gnc-general-search.h"
00056 #include "dialog-date-close.h"
00057 #include "dialog-invoice.h"
00058 #include "dialog-job.h"
00059 #include "business-gnome-utils.h"
00060 #include "dialog-payment.h"
00061 #include "dialog-tax-table.h"
00062 #include "dialog-billterms.h"
00063 #include "dialog-account.h"
00064 #include "guile-mappings.h"
00065 #include "dialog-dup-trans.h"
00066 
00067 #include "dialog-query-list.h"
00068 
00069 #include "gnc-plugin-business.h"
00070 #include "gnc-plugin-page-invoice.h"
00071 #include "gnc-main-window.h"
00072 
00073 #include "dialog-transfer.h"
00074 
00075 /* Disable -Waddress.  GCC 4.2 warns (and fails to compile with -Werror) when
00076  * passing the address of a guid on the stack to QOF_BOOK_LOOKUP_ENTITY via
00077  * gncInvoiceLookup and friends.  When the macro gets inlined, the compiler
00078  * emits a warning that the guid null pointer test is always true.
00079  */
00080 #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 2)
00081 #    pragma GCC diagnostic warning "-Waddress"
00082 #endif
00083 
00084 #define DIALOG_NEW_INVOICE_CM_CLASS "dialog-new-invoice"
00085 #define DIALOG_VIEW_INVOICE_CM_CLASS "dialog-view-invoice"
00086 
00087 #define GCONF_SECTION_SEARCH  "dialogs/business/invoice_search"
00088 
00089 #define LAST_POSTED_TO_ACCT "last-posted-to-acct"
00090 
00091 void gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data);
00092 void gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data);
00093 void gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data);
00094 void gnc_invoice_type_toggled_cb (GtkWidget *widget, gpointer data);
00095 void gnc_invoice_id_changed_cb (GtkWidget *widget, gpointer data);
00096 void gnc_invoice_terms_changed_cb (GtkWidget *widget, gpointer data);
00097 
00098 #define ENUM_INVOICE_TYPE(_) \
00099   _(NEW_INVOICE, )  \
00100   _(MOD_INVOICE, )  \
00101   _(DUP_INVOICE, )  \
00102   _(EDIT_INVOICE, ) \
00103   _(VIEW_INVOICE, )
00104 
00105 DEFINE_ENUM(InvoiceDialogType, ENUM_INVOICE_TYPE)
00106 AS_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00107 FROM_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00108 
00109 FROM_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00110 AS_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00111 
00112 struct _invoice_select_window
00113 {
00114     QofBook *   book;
00115     GncOwner *  owner;
00116     QofQuery *  q;
00117     GncOwner    owner_def;
00118 };
00119 
00120 
00126 struct _invoice_window
00127 {
00128     GtkBuilder   * builder;
00129 
00130     GtkWidget  * dialog;         /* Used by 'New Invoice Window' */
00131     GncPluginPage *page;        /* Used by 'Edit Invoice' Page */
00132 
00133     /* Summary Bar Widgets */
00134     GtkWidget  * total_label;
00135     GtkWidget  * total_cash_label;
00136     GtkWidget  * total_charge_label;
00137     GtkWidget  * total_subtotal_label;
00138     GtkWidget  * total_tax_label;
00139 
00140     /* Data Widgets */
00141     GtkWidget  * type_label;
00142     GtkWidget  * type_hbox;
00143     GtkWidget  * type_choice;
00144     GtkWidget  * id_entry;
00145     GtkWidget  * notes_text;
00146     GtkWidget  * opened_date;
00147     GtkWidget  * posted_date_hbox;
00148     GtkWidget  * posted_date;
00149     GtkWidget  * active_check;
00150 
00151     GtkWidget  * owner_box;
00152     GtkWidget  * owner_label;
00153     GtkWidget  * owner_choice;
00154     GtkWidget  * job_label;
00155     GtkWidget  * job_box;
00156     GtkWidget  * job_choice;
00157     GtkWidget  * billing_id_entry;
00158     GtkWidget  * terms_menu;
00159 
00160     /* Project Widgets (used for Bills only) */
00161     GtkWidget  * proj_frame;
00162     GtkWidget  * proj_cust_box;
00163     GtkWidget  * proj_cust_choice;
00164     GtkWidget  * proj_job_box;
00165     GtkWidget  * proj_job_choice;
00166 
00167     /* Expense Voucher Widgets */
00168     GtkWidget  * to_charge_frame;
00169     GtkWidget  * to_charge_edit;
00170 
00171     gint         width;
00172 
00173     GncBillTerm     * terms;
00174     GnucashRegister * reg;
00175     GncEntryLedger  * ledger;
00176 
00177     invoice_sort_type_t last_sort;
00178 
00179     InvoiceDialogType   dialog_type;
00180     GncGUID      invoice_guid;
00181     gboolean     is_credit_note;
00182     gint         component_id;
00183     QofBook    * book;
00184     GncInvoice * created_invoice;
00185     GncOwner     owner;
00186     GncOwner     job;
00187 
00188     GncOwner     proj_cust;
00189     GncOwner     proj_job;
00190 
00191     /* for Unposting */
00192     gboolean     reset_tax_tables;
00193 };
00194 
00195 /* Forward definitions for CB functions */
00196 void gnc_invoice_window_closeCB (GtkWidget *widget, gpointer data);
00197 void gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data);
00198 gboolean gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data);
00199 
00200 #define INV_WIDTH_PREFIX "invoice_reg"
00201 #define BILL_WIDTH_PREFIX "bill_reg"
00202 #define VOUCHER_WIDTH_PREFIX "voucher_reg"
00203 
00204 static void gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget);
00205 static InvoiceWindow * gnc_ui_invoice_modify (GncInvoice *invoice);
00206 
00207 /*******************************************************************************/
00208 /* FUNCTIONS FOR ACCESSING DATA STRUCTURE FIELDS */
00209 
00210 static GtkWidget *
00211 iw_get_window (InvoiceWindow *iw)
00212 {
00213     if (iw->page)
00214         return gnc_plugin_page_get_window(iw->page);
00215     return iw->dialog;
00216 }
00217 
00218 GtkWidget *
00219 gnc_invoice_get_register(InvoiceWindow *iw)
00220 {
00221     if (iw)
00222         return (GtkWidget *)iw->reg;
00223     return NULL;
00224 }
00225 
00226 /*******************************************************************************/
00227 /* FUNCTIONS FOR UNPOSTING */
00228 
00229 static gboolean
00230 iw_ask_unpost (InvoiceWindow *iw)
00231 {
00232     GtkWidget *dialog;
00233     GtkToggleButton *toggle;
00234     GtkBuilder *builder;
00235     gint response;
00236     char *s;
00237 
00238     builder = gtk_builder_new();
00239     gnc_builder_add_from_file (builder, "dialog-invoice.glade", "Unpost Message Dialog");
00240     dialog = GTK_WIDGET (gtk_builder_get_object (builder, "Unpost Message Dialog"));
00241     toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object (builder, "yes_tt_reset"));
00242 
00243     gtk_window_set_transient_for (GTK_WINDOW(dialog),
00244                                   GTK_WINDOW(iw_get_window(iw)));
00245 
00246     iw->reset_tax_tables = FALSE;
00247 
00248     gtk_widget_show_all(dialog);
00249 
00250     response = gtk_dialog_run(GTK_DIALOG(dialog));
00251     if (response == GTK_RESPONSE_OK)
00252         iw->reset_tax_tables =
00253             gtk_toggle_button_get_active(toggle);
00254 
00255     gtk_widget_destroy(dialog);
00256     g_object_unref(G_OBJECT(builder));
00257 
00258     return (response == GTK_RESPONSE_OK);
00259 }
00260 
00261 /*******************************************************************************/
00262 /* INVOICE WINDOW */
00263 
00264 static GncInvoice *
00265 iw_get_invoice (InvoiceWindow *iw)
00266 {
00267     if (!iw)
00268         return NULL;
00269 
00270     return gncInvoiceLookup (iw->book, &iw->invoice_guid);
00271 }
00272 
00273 static void
00274 set_gncEntry_switch_type (gpointer data, gpointer user_data)
00275 {
00276     GncEntry *entry = data;
00277     //g_warning("Modifying date for entry with desc=\"%s\"", gncEntryGetDescription(entry));
00278 
00279     gncEntrySetQuantity (entry, gnc_numeric_neg (gncEntryGetQuantity (entry)));
00280 }
00281 
00282 static void gnc_ui_to_invoice (InvoiceWindow *iw, GncInvoice *invoice)
00283 {
00284     GtkTextBuffer* text_buffer;
00285     GtkTextIter start, end;
00286     gchar *text;
00287     Timespec ts;
00288     gboolean is_credit_note = gncInvoiceGetIsCreditNote (invoice);
00289 
00290     if (iw->dialog_type == VIEW_INVOICE)
00291         return;
00292 
00293     gnc_suspend_gui_refresh ();
00294 
00295     gncInvoiceBeginEdit (invoice);
00296 
00297     if (iw->active_check)
00298         gncInvoiceSetActive (invoice, gtk_toggle_button_get_active
00299                              (GTK_TOGGLE_BUTTON (iw->active_check)));
00300 
00301     text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
00302     gtk_text_buffer_get_bounds (text_buffer, &start, &end);
00303     text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
00304     gncInvoiceSetNotes (invoice, text);
00305 
00306     if (iw->to_charge_edit)
00307         gncInvoiceSetToChargeAmount (invoice,
00308                                      gnc_amount_edit_get_amount
00309                                      (GNC_AMOUNT_EDIT (iw->to_charge_edit)));
00310 
00311     /* Only set these values for NEW/MOD INVOICE types */
00312     if (iw->dialog_type != EDIT_INVOICE)
00313     {
00314         gncInvoiceSetID (invoice, gtk_editable_get_chars
00315                          (GTK_EDITABLE (iw->id_entry), 0, -1));
00316         gncInvoiceSetBillingID (invoice, gtk_editable_get_chars
00317                                 (GTK_EDITABLE (iw->billing_id_entry), 0, -1));
00318         gncInvoiceSetTerms (invoice, iw->terms);
00319 
00320         ts = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (iw->opened_date));
00321         gncInvoiceSetDateOpened (invoice, ts);
00322 
00323         gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
00324         if (iw->job_choice)
00325             gnc_owner_get_owner (iw->job_choice, &(iw->job));
00326 
00327         /* Only set the job if we've actually got one */
00328         if (gncOwnerGetJob (&(iw->job)))
00329             gncInvoiceSetOwner (invoice, &(iw->job));
00330         else
00331             gncInvoiceSetOwner (invoice, &(iw->owner));
00332 
00333         /* Set the invoice currency based on the owner */
00334         gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (&iw->owner));
00335 
00336         /* Only set the BillTo if we've actually got one */
00337         if (gncOwnerGetJob (&iw->proj_job))
00338             gncInvoiceSetBillTo (invoice, &iw->proj_job);
00339         else
00340             gncInvoiceSetBillTo (invoice, &iw->proj_cust);
00341     }
00342 
00343     /* Document type can only be modified for a new or duplicated invoice/credit note */
00344     if (iw->dialog_type == NEW_INVOICE || iw->dialog_type == DUP_INVOICE)
00345         gncInvoiceSetIsCreditNote (invoice, iw->is_credit_note);
00346 
00347     /* If the document type changed on a duplicated invoice,
00348      * its entries should be updated
00349      */
00350     if (iw->dialog_type == DUP_INVOICE && iw->is_credit_note != is_credit_note)
00351     {
00352         g_list_foreach(gncInvoiceGetEntries(invoice),
00353                        &set_gncEntry_switch_type, NULL);
00354     }
00355 
00356     gncInvoiceCommitEdit (invoice);
00357     gnc_resume_gui_refresh ();
00358 }
00359 
00360 static gboolean
00361 gnc_invoice_window_verify_ok (InvoiceWindow *iw)
00362 {
00363     const char *res;
00364     gchar *string;
00365 
00366     /* save the current entry in the ledger? */
00367     if (!gnc_entry_ledger_check_close (iw_get_window(iw), iw->ledger))
00368         return FALSE;
00369 
00370     /* Check the Owner */
00371     gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
00372     res = gncOwnerGetName (&(iw->owner));
00373     if (res == NULL || safe_strcmp (res, "") == 0)
00374     {
00375         gnc_error_dialog (iw_get_window(iw), "%s",
00376                           /* Translators: In this context,
00377                            * 'Billing information' maps to the
00378                            * label in the frame and means
00379                            * e.g. customer i.e. the company being
00380                            * invoiced. */
00381                           _("You need to supply Billing Information."));
00382         return FALSE;
00383     }
00384 
00385     /* Check the ID; set one if necessary */
00386     res = gtk_entry_get_text (GTK_ENTRY (iw->id_entry));
00387     if (safe_strcmp (res, "") == 0)
00388     {
00389         /* Invoices and bills have separate counters.
00390            Therefore we pass the GncOwer to gncInvoiceNextID
00391            so it knows whether we are creating a bill
00392            or an invoice. */
00393         string = gncInvoiceNextID(iw->book, &(iw->owner));
00394         gtk_entry_set_text (GTK_ENTRY (iw->id_entry), string);
00395         g_free(string);
00396     }
00397 
00398     return TRUE;
00399 }
00400 
00401 static gboolean
00402 gnc_invoice_window_ok_save (InvoiceWindow *iw)
00403 {
00404     if (!gnc_invoice_window_verify_ok (iw))
00405         return FALSE;
00406 
00407     {
00408         GncInvoice *invoice = iw_get_invoice (iw);
00409         if (invoice)
00410         {
00411             gnc_ui_to_invoice (iw, invoice);
00412         }
00413         /* Save the invoice to return it later. */
00414         iw->created_invoice = invoice;
00415     }
00416     return TRUE;
00417 }
00418 
00419 void
00420 gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data)
00421 {
00422     InvoiceWindow *iw = data;
00423 
00424     if (!gnc_invoice_window_ok_save (iw))
00425         return;
00426 
00427     /* Ok, we don't need this anymore */
00428     iw->invoice_guid = *guid_null ();
00429 
00430     /* if this is a new or duplicated invoice, and created_invoice is NON-NULL,
00431      * then open up a new window with the invoice.  This used to be done
00432      * in gnc_ui_invoice_new() but cannot be done anymore
00433      */
00434     if ((iw->dialog_type == NEW_INVOICE || iw->dialog_type == DUP_INVOICE)
00435             && iw->created_invoice)
00436         gnc_ui_invoice_edit (iw->created_invoice);
00437 
00438     gnc_close_gui_component (iw->component_id);
00439 }
00440 
00441 void
00442 gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data)
00443 {
00444     InvoiceWindow *iw = data;
00445 
00446     gnc_close_gui_component (iw->component_id);
00447 }
00448 
00449 void
00450 gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data)
00451 {
00452     gnc_gnome_help(HF_HELP, HL_USAGE);
00453 }
00454 
00455 void
00456 gnc_invoice_window_destroy_cb (GtkWidget *widget, gpointer data)
00457 {
00458     InvoiceWindow *iw = data;
00459     GncInvoice *invoice = iw_get_invoice (iw);
00460 
00461     gnc_suspend_gui_refresh ();
00462 
00463     if (iw->dialog_type == NEW_INVOICE && invoice != NULL)
00464     {
00465         gncInvoiceBeginEdit (invoice);
00466         gncInvoiceDestroy (invoice);
00467         iw->invoice_guid = *guid_null ();
00468     }
00469 
00470     gnc_entry_ledger_destroy (iw->ledger);
00471     gnc_unregister_gui_component (iw->component_id);
00472     gtk_widget_destroy(widget);
00473     gnc_resume_gui_refresh ();
00474 
00475     g_free (iw);
00476 }
00477 
00478 void
00479 gnc_invoice_window_closeCB (GtkWidget *widget, gpointer data)
00480 {
00481     gnc_invoice_window_ok_cb (widget, data);
00482 }
00483 
00484 void
00485 gnc_invoice_window_editCB (GtkWidget *widget, gpointer data)
00486 {
00487     InvoiceWindow *iw = data;
00488     GncInvoice *invoice = iw_get_invoice (iw);
00489 
00490     if (invoice)
00491         gnc_ui_invoice_modify (invoice);
00492 }
00493 
00494 void
00495 gnc_invoice_window_duplicateInvoiceCB (GtkWidget *widget, gpointer data)
00496 {
00497     InvoiceWindow *iw = data;
00498     GncInvoice *invoice = iw_get_invoice (iw);
00499 
00500     if (invoice)
00501         gnc_ui_invoice_duplicate (invoice, TRUE, NULL);
00502 }
00503 
00504 void gnc_invoice_window_entryUpCB (GtkWidget *widget, gpointer data)
00505 {
00506     InvoiceWindow *iw = data;
00507     if (!iw || !iw->ledger)
00508         return;
00509 
00510     gnc_entry_ledger_move_current_entry_updown(iw->ledger, TRUE);
00511 }
00512 void gnc_invoice_window_entryDownCB (GtkWidget *widget, gpointer data)
00513 {
00514     InvoiceWindow *iw = data;
00515     if (!iw || !iw->ledger)
00516         return;
00517 
00518     gnc_entry_ledger_move_current_entry_updown(iw->ledger, FALSE);
00519 }
00520 
00521 void
00522 gnc_invoice_window_recordCB (GtkWidget *widget, gpointer data)
00523 {
00524     InvoiceWindow *iw = data;
00525 
00526     if (!iw || !iw->ledger)
00527         return;
00528 
00529     if (!gnc_entry_ledger_commit_entry (iw->ledger))
00530         return;
00531 
00532     gnucash_register_goto_next_virt_row (iw->reg);
00533 }
00534 
00535 void
00536 gnc_invoice_window_cancelCB (GtkWidget *widget, gpointer data)
00537 {
00538     InvoiceWindow *iw = data;
00539 
00540     if (!iw || !iw->ledger)
00541         return;
00542 
00543     gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00544 }
00545 
00546 void
00547 gnc_invoice_window_deleteCB (GtkWidget *widget, gpointer data)
00548 {
00549     InvoiceWindow *iw = data;
00550     GncEntry *entry;
00551 
00552     if (!iw || !iw->ledger)
00553         return;
00554 
00555     /* get the current entry based on cursor position */
00556     entry = gnc_entry_ledger_get_current_entry (iw->ledger);
00557     if (!entry)
00558     {
00559         gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00560         return;
00561     }
00562 
00563     /* deleting the blank entry just cancels */
00564     if (entry == gnc_entry_ledger_get_blank_entry (iw->ledger))
00565     {
00566         gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00567         return;
00568     }
00569 
00570     /* Verify that the user really wants to delete this entry */
00571     {
00572         const char *message = _("Are you sure you want to delete the "
00573                                 "selected entry?");
00574         const char *order_warn = _("This entry is attached to an order and "
00575                                    "will be deleted from that as well!");
00576         char *msg;
00577         gboolean result;
00578 
00579         if (gncEntryGetOrder (entry))
00580             msg = g_strconcat (message, "\n\n", order_warn, (char *)NULL);
00581         else
00582             msg = g_strdup (message);
00583 
00584         result = gnc_verify_dialog (iw_get_window(iw), FALSE, "%s", msg);
00585         g_free (msg);
00586 
00587         if (!result)
00588             return;
00589     }
00590 
00591     /* Yep, let's delete */
00592     gnc_entry_ledger_delete_current_entry (iw->ledger);
00593     return;
00594 }
00595 
00596 void
00597 gnc_invoice_window_duplicateCB (GtkWidget *widget, gpointer data)
00598 {
00599     InvoiceWindow *iw = data;
00600 
00601     if (!iw || !iw->ledger)
00602         return;
00603 
00604     gnc_entry_ledger_duplicate_current_entry (iw->ledger);
00605 }
00606 
00607 void
00608 gnc_invoice_window_blankCB (GtkWidget *widget, gpointer data)
00609 {
00610     InvoiceWindow *iw = data;
00611 
00612     if (!iw || !iw->ledger)
00613         return;
00614 
00615     if (!gnc_entry_ledger_commit_entry (iw->ledger))
00616         return;
00617 
00618     {
00619         VirtualCellLocation vcell_loc;
00620         GncEntry *blank;
00621 
00622         blank = gnc_entry_ledger_get_blank_entry (iw->ledger);
00623         if (blank == NULL)
00624             return;
00625 
00626         if (gnc_entry_ledger_get_entry_virt_loc (iw->ledger, blank, &vcell_loc))
00627             gnucash_register_goto_virt_cell (iw->reg, vcell_loc);
00628     }
00629 }
00630 
00631 static void
00632 gnc_invoice_window_print_invoice(GncInvoice *invoice)
00633 {
00634     SCM func, arg, arg2;
00635     SCM args = SCM_EOL;
00636     int report_id;
00637     const char *reportname = gnc_plugin_business_get_invoice_printreport();
00638 
00639     g_return_if_fail (invoice);
00640     if (!reportname)
00641         reportname = "Printable Invoice"; // fallback if the option lookup failed
00642 
00643     func = scm_c_eval_string ("gnc:invoice-report-create-withname");
00644     g_return_if_fail (scm_is_procedure (func));
00645 
00646     arg = SWIG_NewPointerObj(invoice, SWIG_TypeQuery("_p__gncInvoice"), 0);
00647     arg2 = scm_from_locale_string(reportname);
00648     args = scm_cons2 (arg, arg2, args);
00649 
00650     /* scm_gc_protect_object(func); */
00651 
00652     arg = scm_apply (func, args, SCM_EOL);
00653     g_return_if_fail (scm_is_exact (arg));
00654     report_id = scm_num2int (arg, SCM_ARG1, G_STRFUNC);
00655 
00656     /* scm_gc_unprotect_object(func); */
00657     if (report_id >= 0)
00658         reportWindow (report_id);
00659 }
00660 void
00661 gnc_invoice_window_printCB (GtkWidget *unused_widget, gpointer data)
00662 {
00663     InvoiceWindow *iw = data;
00664     gnc_invoice_window_print_invoice(iw_get_invoice (iw));
00665 }
00666 
00667 void
00668 gnc_invoice_window_postCB (GtkWidget *unused_widget, gpointer data)
00669 {
00670     InvoiceWindow *iw = data;
00671     GncInvoice *invoice;
00672     char *message, *memo, *ddue_label, *post_label, *acct_label, *question_label;
00673     Account *acc = NULL;
00674     GList * acct_types = NULL;
00675     GList * acct_commodities = NULL;
00676     Timespec ddue, postdate;
00677     gboolean accumulate;
00678     QofInstance *owner_inst;
00679     KvpFrame *kvpf;
00680     KvpValue *kvp_val;
00681     const char *text;
00682     EntryList *entries, *entries_iter;
00683     GncEntry* entry;
00684     gboolean is_cust_doc;
00685     gboolean is_cn;
00686     gboolean show_dialog = TRUE;
00687     gboolean post_ok = TRUE;
00688 
00689     /* Make sure the invoice is ok */
00690     if (!gnc_invoice_window_verify_ok (iw))
00691         return;
00692 
00693     invoice = iw_get_invoice (iw);
00694     if (!invoice)
00695         return;
00696 
00697     /* Check that there is at least one Entry */
00698     if (gncInvoiceGetEntries (invoice) == NULL)
00699     {
00700         gnc_error_dialog (iw_get_window(iw), "%s",
00701                           _("The Invoice must have at least one Entry."));
00702         return;
00703     }
00704 
00705     is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
00706     is_cn = gncInvoiceGetIsCreditNote (invoice);
00707 
00708     /* Ok, we can post this invoice.  Ask for verification, set the due date,
00709      * post date, and posted account
00710      */
00711     message = _("Do you really want to post the invoice?");
00712     ddue_label = _("Due Date");
00713     post_label = _("Post Date");
00714     acct_label = _("Post to Account");
00715     question_label = _("Accumulate Splits?");
00716 
00717     /* Determine the type of account to post to */
00718     acct_types = gncOwnerGetAccountTypesList (&(iw->owner));
00719 
00720     /* Determine which commodity we're working with */
00721     acct_commodities = gncOwnerGetCommoditiesList(&(iw->owner));
00722 
00723     /* Get the invoice entries */
00724     entries = gncInvoiceGetEntries (invoice);
00725 
00726     /* Find the most suitable post date.
00727      * For Customer Invoices that would be today.
00728      * For Vendor Bills and Employee Vouchers
00729      * that would be the date of the most recent invoice entry.
00730      * Failing that, today is used as a fallback */
00731     postdate = timespec_now();
00732 
00733     if (entries && ((gncInvoiceGetOwnerType (invoice) == GNC_OWNER_VENDOR) ||
00734                     (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)))
00735     {
00736         postdate = gncEntryGetDate ((GncEntry*)entries->data);
00737         for (entries_iter = entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
00738         {
00739             Timespec entrydate;
00740 
00741             entrydate = gncEntryGetDate ((GncEntry*)entries_iter->data);
00742             if (timespec_cmp(&entrydate, &postdate) > 0)
00743                 postdate = entrydate;
00744         }
00745     }
00746 
00747     /* Get the due date and posted account */
00748     ddue = postdate;
00749     memo = NULL;
00750 
00751     owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
00752     kvpf = qof_instance_get_slots (owner_inst);
00753     acc = xaccAccountLookup (kvp_frame_get_guid (kvpf, LAST_POSTED_TO_ACCT),
00754                              iw->book);
00755 
00756     /* Get the default for the accumulate option */
00757     accumulate = gnc_gconf_get_bool(GCONF_SECTION_INVOICE, "accumulate_splits", NULL);
00758 
00759     if (!gnc_dialog_dates_acct_question_parented (iw_get_window(iw), message, ddue_label,
00760             post_label, acct_label, question_label, TRUE, TRUE,
00761             acct_types, acct_commodities, iw->book, iw->terms,
00762             &ddue, &postdate, &memo, &acc, &accumulate))
00763         return;
00764 
00765     /* Yep, we're posting.  So, save the invoice...
00766      * Note that we can safely ignore the return value; we checked
00767      * the verify_ok earlier, so we know it's ok.
00768      */
00769     gnc_suspend_gui_refresh ();
00770     gncInvoiceBeginEdit (invoice);
00771     gnc_invoice_window_ok_save (iw);
00772 
00773     /* Fill in the conversion prices with feedback from the user */
00774     text = _("One or more of the entries are for accounts different from the invoice/bill currency.  You will be asked a conversion rate for each.");
00775 
00776     for (entries_iter = entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
00777     {
00778         Account *this_acc;
00779         gnc_commodity *account_currency;
00780 
00781         entry = (GncEntry*)entries_iter->data;
00782         this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
00783                     gncEntryGetBillAccount (entry));
00784         account_currency = xaccAccountGetCommodity (this_acc);
00785 
00786         if (this_acc &&
00787                 !gnc_commodity_equal (gncInvoiceGetCurrency (invoice), account_currency))
00788         {
00789             GNCPrice *convprice;
00790 
00791             if (show_dialog)
00792             {
00793                 gnc_info_dialog(iw_get_window(iw), "%s", text);
00794                 show_dialog = FALSE;
00795             }
00796 
00797             convprice = gncInvoiceGetPrice(invoice, account_currency);
00798             if (convprice == NULL)
00799             {
00800                 XferDialog *xfer;
00801                 gnc_numeric exch_rate;
00802                 Timespec date;
00803                 gnc_numeric amount = gnc_numeric_create(1, 1);
00804                 gnc_numeric value;
00805                 gnc_numeric tax;
00806 
00807                 /* Note some twisted logic here:
00808                  * We ask the exchange rate
00809                  *  FROM invoice currency
00810                  *  TO other account currency
00811                  *  Because that's what happens logically.
00812                  *  But the internal posting logic works backwards:
00813                  *  It searches for an exchange rate
00814                  *  FROM other account currency
00815                  *  TO invoice currency
00816                  *  So we will store the inverted exchange rate
00817                  */
00818 
00819                 /* Obtain the Entry's total value (net + tax) */
00820                 value = gncEntryGetDocValue (entry, FALSE, is_cust_doc, is_cn);
00821                 tax   = gncEntryGetDocTaxValue (entry, FALSE, is_cust_doc, is_cn);
00822                 amount = gnc_numeric_add (value, tax,
00823                                           gnc_commodity_get_fraction (account_currency),
00824                                           GNC_HOW_RND_ROUND_HALF_UP );
00825 
00826                 /* create the exchange-rate dialog */
00827                 xfer = gnc_xfer_dialog (iw_get_window(iw), acc);
00828                 gnc_xfer_dialog_select_to_account(xfer, this_acc);
00829                 gnc_xfer_dialog_set_amount(xfer, amount);
00830 
00831                 /* All we want is the exchange rate so prevent the user from thinking
00832                    it makes sense to mess with other stuff */
00833                 gnc_xfer_dialog_set_from_show_button_active(xfer, FALSE);
00834                 gnc_xfer_dialog_set_to_show_button_active(xfer, FALSE);
00835                 gnc_xfer_dialog_hide_from_account_tree(xfer);
00836                 gnc_xfer_dialog_hide_to_account_tree(xfer);
00837                 gnc_xfer_dialog_is_exchange_dialog(xfer, &exch_rate);
00838                 if (gnc_xfer_dialog_run_until_done(xfer))
00839                 {
00840                     /* User finished the transfer dialog successfully */
00841 
00842                     /* Invert the exchange rate as explained above */
00843                     if (!gnc_numeric_zero_p (exch_rate))
00844                         exch_rate = gnc_numeric_div ((gnc_numeric)
00845                     {
00846                         1, 1
00847                     }, exch_rate,
00848                     GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
00849                     convprice = gnc_price_create(iw->book);
00850                     gnc_price_begin_edit (convprice);
00851                     gnc_price_set_commodity (convprice, account_currency);
00852                     gnc_price_set_currency (convprice, gncInvoiceGetCurrency (invoice));
00853                     date.tv_sec = time (NULL);
00854                     date.tv_nsec = 0;
00855                     gnc_price_set_time (convprice, date);
00856                     gnc_price_set_source (convprice, "user:invoice-post");
00857 
00858                     /* Yes, magic strings are evil but I can't find any defined constants
00859                        for this..*/
00860                     gnc_price_set_typestr (convprice, "last");
00861                     gnc_price_set_value (convprice, exch_rate);
00862                     gncInvoiceAddPrice(invoice, convprice);
00863                     gnc_price_commit_edit (convprice);
00864                 }
00865                 else
00866                 {
00867                     /* User canceled the transfer dialog, abort posting */
00868                     post_ok = FALSE;
00869                     goto cleanup;
00870                 }
00871             }
00872         }
00873     }
00874 
00875 
00876     /* Save account as last used account in the kvp frame of the invoice owner */
00877     kvp_val = kvp_value_new_guid (qof_instance_get_guid (QOF_INSTANCE (acc)));;
00878     qof_begin_edit (owner_inst);
00879     kvp_frame_set_slot_nc (kvpf, LAST_POSTED_TO_ACCT, kvp_val);
00880     qof_instance_set_dirty (owner_inst);
00881     qof_commit_edit (owner_inst);
00882 
00883     /* ... post it ... */
00884     gncInvoicePostToAccount (invoice, acc, &postdate, &ddue, memo, accumulate);
00885 
00886 cleanup:
00887     gncInvoiceCommitEdit (invoice);
00888     gnc_resume_gui_refresh ();
00889 
00890     if (memo)
00891         g_free (memo);
00892 
00893     if (post_ok)
00894     {
00895         /* Reset the type; change to read-only! */
00896         iw->dialog_type = VIEW_INVOICE;
00897         gnc_entry_ledger_set_readonly (iw->ledger, TRUE);
00898     }
00899     else
00900     {
00901         text = _("The post action was canceled because not all exchange rates were given.");
00902         gnc_info_dialog(iw_get_window(iw), "%s", text);
00903     }
00904 
00905     /* ... and redisplay here. */
00906     gnc_invoice_update_window (iw, NULL);
00907     gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
00908 }
00909 
00910 void
00911 gnc_invoice_window_unpostCB (GtkWidget *widget, gpointer data)
00912 {
00913     InvoiceWindow *iw = data;
00914     GncInvoice *invoice;
00915     gboolean result;
00916 
00917     invoice = iw_get_invoice (iw);
00918     if (!invoice)
00919         return;
00920 
00921     /* make sure the user REALLY wants to do this! */
00922     result = iw_ask_unpost(iw);
00923     if (!result) return;
00924 
00925     /* Attempt to unpost the invoice */
00926     gnc_suspend_gui_refresh ();
00927     result = gncInvoiceUnpost (invoice, iw->reset_tax_tables);
00928     gnc_resume_gui_refresh ();
00929     if (!result) return;
00930 
00931     /* if we get here, we succeeded in unposting -- reset the ledger and redisplay */
00932     iw->dialog_type = EDIT_INVOICE;
00933     gnc_entry_ledger_set_readonly (iw->ledger, FALSE);
00934     gnc_invoice_update_window (iw, NULL);
00935     gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
00936 }
00937 
00938 void gnc_invoice_window_cut_cb (GtkWidget *widget, gpointer data)
00939 {
00940     InvoiceWindow *iw = data;
00941     gnucash_register_cut_clipboard (iw->reg);
00942 }
00943 
00944 void gnc_invoice_window_copy_cb (GtkWidget *widget, gpointer data)
00945 {
00946     InvoiceWindow *iw = data;
00947     gnucash_register_copy_clipboard (iw->reg);
00948 }
00949 
00950 void gnc_invoice_window_paste_cb (GtkWidget *widget, gpointer data)
00951 {
00952     InvoiceWindow *iw = data;
00953     gnucash_register_paste_clipboard (iw->reg);
00954 }
00955 
00956 void gnc_invoice_window_new_invoice_cb (GtkWidget *widget, gpointer data)
00957 {
00958     InvoiceWindow *iw = data;
00959     if (gncOwnerGetJob (&iw->job))
00960     {
00961         gnc_ui_invoice_new (&iw->job, iw->book);
00962     }
00963     else
00964     {
00965         gnc_ui_invoice_new (&iw->owner, iw->book);
00966     }
00967 }
00968 
00969 void gnc_business_call_owner_report (GncOwner *owner, Account *acc)
00970 {
00971     int id;
00972     SCM args;
00973     SCM func;
00974     SCM arg;
00975 
00976     g_return_if_fail (owner);
00977 
00978     args = SCM_EOL;
00979 
00980     func = scm_c_eval_string ("gnc:owner-report-create");
00981     g_return_if_fail (scm_is_procedure (func));
00982 
00983     if (acc)
00984     {
00985         swig_type_info * qtype = SWIG_TypeQuery("_p_Account");
00986         g_return_if_fail (qtype);
00987 
00988         arg = SWIG_NewPointerObj(acc, qtype, 0);
00989         g_return_if_fail (arg != SCM_UNDEFINED);
00990         args = scm_cons (arg, args);
00991     }
00992     else
00993     {
00994         args = scm_cons (SCM_BOOL_F, args);
00995     }
00996 
00997     arg = SWIG_NewPointerObj(owner, SWIG_TypeQuery("_p__gncOwner"), 0);
00998     g_return_if_fail (arg != SCM_UNDEFINED);
00999     args = scm_cons (arg, args);
01000 
01001     /* Apply the function to the args */
01002     arg = scm_apply (func, args, SCM_EOL);
01003     g_return_if_fail (scm_is_exact (arg));
01004     id = scm_num2int (arg, SCM_ARG1, G_STRFUNC);
01005 
01006     if (id >= 0)
01007         reportWindow (id);
01008 }
01009 
01010 void gnc_invoice_window_report_owner_cb (GtkWidget *widget, gpointer data)
01011 {
01012     InvoiceWindow *iw = data;
01013     gnc_business_call_owner_report (&iw->owner, NULL);
01014 }
01015 
01016 void gnc_invoice_window_payment_cb (GtkWidget *widget, gpointer data)
01017 {
01018     InvoiceWindow *iw = data;
01019     GncInvoice *invoice = iw_get_invoice(iw);
01020 
01021     if (gncOwnerGetJob (&iw->job))
01022         gnc_ui_payment_new_with_invoice (&iw->job, iw->book, invoice);
01023     else
01024         gnc_ui_payment_new_with_invoice (&iw->owner, iw->book, invoice);
01025 }
01026 
01027 /* Sorting callbacks */
01028 
01029 void
01030 gnc_invoice_window_sort (InvoiceWindow *iw, invoice_sort_type_t sort_code)
01031 {
01032     QofQuery *query = gnc_entry_ledger_get_query (iw->ledger);
01033     GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
01034 
01035     if (iw->last_sort == sort_code)
01036         return;
01037 
01038     standard = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
01039 
01040     switch (sort_code)
01041     {
01042     case INVSORT_BY_STANDARD:
01043         p1 = standard;
01044         break;
01045     case INVSORT_BY_DATE:
01046         p1 = g_slist_prepend (p1, ENTRY_DATE);
01047         p2 = standard;
01048         break;
01049     case INVSORT_BY_DATE_ENTERED:
01050         p1 = g_slist_prepend (p1, ENTRY_DATE_ENTERED);
01051         p2 = standard;
01052         break;
01053     case INVSORT_BY_DESC:
01054         p1 = g_slist_prepend (p1, ENTRY_DESC);
01055         p2 = standard;
01056         break;
01057     case INVSORT_BY_QTY:
01058         p1 = g_slist_prepend (p1, ENTRY_QTY);
01059         p2 = standard;
01060         break;
01061     case INVSORT_BY_PRICE:
01062         p1 = g_slist_prepend (p1, ((iw->owner.type == GNC_OWNER_CUSTOMER) ?
01063                                    ENTRY_IPRICE : ENTRY_BPRICE));
01064         p2 = standard;
01065         break;
01066     default:
01067         g_slist_free (standard);
01068         g_return_if_fail (FALSE);
01069         break;
01070     }
01071 
01072     qof_query_set_sort_order (query, p1, p2, p3);
01073     iw->last_sort = sort_code;
01074     gnc_entry_ledger_display_refresh (iw->ledger);
01075 }
01076 
01077 /* Window configuration callbacks */
01078 
01079 void
01080 gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data)
01081 {
01082     InvoiceWindow *iw = data;
01083     GncInvoice *invoice = iw_get_invoice(iw);
01084 
01085     if (!invoice) return;
01086 
01087     gncInvoiceSetActive (invoice,
01088                          gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
01089 }
01090 
01091 gboolean
01092 gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event,
01093                                    gpointer data)
01094 {
01095     InvoiceWindow *iw = data;
01096     GncInvoice *invoice = iw_get_invoice(iw);
01097     GtkTextBuffer* text_buffer;
01098     GtkTextIter start, end;
01099     gchar *text;
01100 
01101     if (!invoice) return FALSE;
01102 
01103     text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
01104     gtk_text_buffer_get_bounds (text_buffer, &start, &end);
01105     text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
01106     gncInvoiceSetNotes (invoice, text);
01107     return FALSE;
01108 }
01109 
01110 static gboolean
01111 gnc_invoice_window_leave_to_charge_cb (GtkWidget *widget, GdkEventFocus *event,
01112                                        gpointer data)
01113 {
01114     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (widget));
01115     return FALSE;
01116 }
01117 
01118 static void
01119 gnc_invoice_window_changed_to_charge_cb (GtkWidget *widget, gpointer data)
01120 {
01121     InvoiceWindow *iw = data;
01122     GncInvoice *invoice = iw_get_invoice(iw);
01123 
01124     if (!invoice) return;
01125 
01126     gncInvoiceSetToChargeAmount (invoice, gnc_amount_edit_get_amount
01127                                  (GNC_AMOUNT_EDIT (widget)));
01128 }
01129 
01130 static GtkWidget *
01131 add_summary_label (GtkWidget *summarybar, const char *label_str)
01132 {
01133     GtkWidget *hbox;
01134     GtkWidget *label;
01135 
01136     hbox = gtk_hbox_new(FALSE, 2);
01137     gtk_box_pack_start (GTK_BOX(summarybar), hbox, FALSE, FALSE, 5);
01138 
01139     label = gtk_label_new (label_str);
01140     gtk_misc_set_alignment (GTK_MISC(label), 1.0, 0.5);
01141     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
01142 
01143     label = gtk_label_new ("");
01144     gtk_misc_set_alignment (GTK_MISC(label), 1.0, 0.5);
01145     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
01146 
01147     return label;
01148 }
01149 
01150 GtkWidget *
01151 gnc_invoice_window_create_summary_bar (InvoiceWindow *iw)
01152 {
01153     GtkWidget *summarybar;
01154 
01155     iw->total_label           = NULL;
01156     iw->total_cash_label      = NULL;
01157     iw->total_charge_label    = NULL;
01158     iw->total_subtotal_label  = NULL;
01159     iw->total_tax_label       = NULL;
01160 
01161     summarybar = gtk_hbox_new (FALSE, 4);
01162 
01163     iw->total_label           = add_summary_label (summarybar, _("Total:"));
01164 
01165     switch (gncOwnerGetType (&iw->owner))
01166     {
01167     case GNC_OWNER_CUSTOMER:
01168     case GNC_OWNER_VENDOR:
01169         iw->total_subtotal_label = add_summary_label (summarybar, _("Subtotal:"));
01170         iw->total_tax_label     = add_summary_label (summarybar, _("Tax:"));
01171         break;
01172 
01173     case GNC_OWNER_EMPLOYEE:
01174         iw->total_cash_label    = add_summary_label (summarybar, _("Total Cash:"));
01175         iw->total_charge_label  = add_summary_label (summarybar, _("Total Charge:"));
01176         break;
01177 
01178     default:
01179         break;
01180     }
01181 
01182     gtk_widget_show_all(summarybar);
01183     return summarybar;
01184 }
01185 
01186 static int
01187 gnc_invoice_job_changed_cb (GtkWidget *widget, gpointer data)
01188 {
01189     InvoiceWindow *iw = data;
01190     char const *msg = "";
01191 
01192     if (!iw)
01193         return FALSE;
01194 
01195     if (iw->dialog_type == VIEW_INVOICE)
01196         return FALSE;
01197 
01198     gnc_owner_get_owner (iw->job_choice, &(iw->job));
01199 
01200     if (iw->dialog_type == EDIT_INVOICE)
01201         return FALSE;
01202 
01203     msg = gncJobGetReference (gncOwnerGetJob (&(iw->job)));
01204     gtk_entry_set_text (GTK_ENTRY (iw->billing_id_entry), msg ? msg : "");
01205 
01206     return FALSE;
01207 
01208 }
01209 
01210 static GNCSearchWindow *
01211 gnc_invoice_select_job_cb (gpointer jobp, gpointer user_data)
01212 {
01213     GncJob *j = jobp;
01214     InvoiceWindow *iw = user_data;
01215     GncOwner owner, *ownerp;
01216 
01217     if (!iw) return NULL;
01218 
01219     if (j)
01220     {
01221         ownerp = gncJobGetOwner (j);
01222         gncOwnerCopy (ownerp, &owner);
01223     }
01224     else
01225         gncOwnerCopy (&(iw->owner), &owner);
01226 
01227     return gnc_job_search (j, &owner, iw->book);
01228 }
01229 
01230 static void
01231 gnc_invoice_update_job_choice (InvoiceWindow *iw)
01232 {
01233     if (iw->job_choice)
01234         gtk_container_remove (GTK_CONTAINER (iw->job_box), iw->job_choice);
01235 
01236     /* If we don't have a real owner, then we obviously can't have a job */
01237     if (iw->owner.owner.undefined == NULL)
01238     {
01239         iw->job_choice = NULL;
01240     }
01241     else
01242         switch (iw->dialog_type)
01243         {
01244         case VIEW_INVOICE:
01245         case EDIT_INVOICE:
01246             iw->job_choice =
01247                 gnc_owner_edit_create (NULL, iw->job_box, iw->book, &(iw->job));
01248             break;
01249         case NEW_INVOICE:
01250         case MOD_INVOICE:
01251         case DUP_INVOICE:
01252             iw->job_choice =
01253                 gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
01254                                         gnc_invoice_select_job_cb, iw, iw->book);
01255 
01256             gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
01257                                              gncOwnerGetJob (&iw->job));
01258             gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->job_choice),
01259                                             TRUE);
01260             gtk_box_pack_start (GTK_BOX (iw->job_box), iw->job_choice,
01261                                 TRUE, TRUE, 0);
01262 
01263             g_signal_connect (G_OBJECT (iw->job_choice), "changed",
01264                               G_CALLBACK (gnc_invoice_job_changed_cb), iw);
01265             break;
01266         }
01267 
01268     if (iw->job_choice)
01269         gtk_widget_show_all (iw->job_choice);
01270 }
01271 
01272 static GNCSearchWindow *
01273 gnc_invoice_select_proj_job_cb (gpointer jobp, gpointer user_data)
01274 {
01275     GncJob *j = jobp;
01276     InvoiceWindow *iw = user_data;
01277     GncOwner owner, *ownerp;
01278 
01279     if (!iw) return NULL;
01280 
01281     if (j)
01282     {
01283         ownerp = gncJobGetOwner (j);
01284         gncOwnerCopy (ownerp, &owner);
01285     }
01286     else
01287         gncOwnerCopy (&(iw->proj_cust), &owner);
01288 
01289     return gnc_job_search (j, &owner, iw->book);
01290 }
01291 
01292 static int
01293 gnc_invoice_proj_job_changed_cb (GtkWidget *widget, gpointer data)
01294 {
01295     InvoiceWindow *iw = data;
01296 
01297     if (!iw)
01298         return FALSE;
01299 
01300     if (iw->dialog_type == VIEW_INVOICE)
01301         return FALSE;
01302 
01303     gnc_owner_get_owner (iw->proj_job_choice, &(iw->proj_job));
01304     return FALSE;
01305 }
01306 
01307 static void
01308 gnc_invoice_update_proj_job (InvoiceWindow *iw)
01309 {
01310     if (iw->proj_job_choice)
01311         gtk_container_remove (GTK_CONTAINER (iw->proj_job_box),
01312                               iw->proj_job_choice);
01313 
01314     switch (iw->dialog_type)
01315     {
01316     case VIEW_INVOICE:
01317     case EDIT_INVOICE:
01318         iw->proj_job_choice =
01319             gnc_owner_edit_create (NULL, iw->proj_job_box, iw->book, &(iw->proj_job));
01320         break;
01321     case NEW_INVOICE:
01322     case MOD_INVOICE:
01323     case DUP_INVOICE:
01324         if (iw->proj_cust.owner.undefined == NULL)
01325         {
01326             iw->proj_job_choice = NULL;
01327         }
01328         else
01329         {
01330             iw->proj_job_choice =
01331                 gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
01332                                         gnc_invoice_select_proj_job_cb, iw, iw->book);
01333 
01334             gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
01335                                              gncOwnerGetJob (&iw->proj_job));
01336             gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->proj_job_choice),
01337                                             TRUE);
01338             gtk_box_pack_start (GTK_BOX (iw->proj_job_box), iw->proj_job_choice,
01339                                 TRUE, TRUE, 0);
01340 
01341             g_signal_connect (G_OBJECT (iw->proj_job_choice), "changed",
01342                               G_CALLBACK (gnc_invoice_proj_job_changed_cb), iw);
01343         }
01344         break;
01345     }
01346 
01347     if (iw->proj_job_choice)
01348         gtk_widget_show_all (iw->proj_job_choice);
01349 }
01350 
01351 static int
01352 gnc_invoice_owner_changed_cb (GtkWidget *widget, gpointer data)
01353 {
01354     InvoiceWindow *iw = data;
01355     GncBillTerm *term = NULL;
01356     GncOwner owner;
01357 
01358     if (!iw)
01359         return FALSE;
01360 
01361     if (iw->dialog_type == VIEW_INVOICE)
01362         return FALSE;
01363 
01364     gncOwnerCopy (&(iw->owner), &owner);
01365     gnc_owner_get_owner (iw->owner_choice, &owner);
01366 
01367     /* If this owner really changed, then reset ourselves */
01368     if (!gncOwnerEqual (&owner, &(iw->owner)))
01369     {
01370         GncInvoice *invoice;
01371 
01372         gncOwnerCopy (&owner, &(iw->owner));
01373         gncOwnerInitJob (&(iw->job), NULL);
01374         invoice = iw_get_invoice (iw);
01375         gnc_entry_ledger_reset_query (iw->ledger);
01376     }
01377 
01378     if (iw->dialog_type == EDIT_INVOICE)
01379         return FALSE;
01380 
01381     switch (gncOwnerGetType (&(iw->owner)))
01382     {
01383     case GNC_OWNER_CUSTOMER:
01384         term = gncCustomerGetTerms (gncOwnerGetCustomer (&(iw->owner)));
01385         break;
01386     case GNC_OWNER_VENDOR:
01387         term = gncVendorGetTerms (gncOwnerGetVendor (&(iw->owner)));
01388         break;
01389     case GNC_OWNER_EMPLOYEE:
01390         term = NULL;
01391         break;
01392     default:
01393         g_warning ("Unknown owner type: %d\n", gncOwnerGetType (&(iw->owner)));
01394         break;
01395     }
01396 
01397     /* XXX: I'm not sure -- should we change the terms if this happens? */
01398     iw->terms = term;
01399     gnc_simple_combo_set_value (GTK_COMBO_BOX(iw->terms_menu), iw->terms);
01400 
01401     gnc_invoice_update_job_choice (iw);
01402 
01403     return FALSE;
01404 }
01405 
01406 static int
01407 gnc_invoice_proj_cust_changed_cb (GtkWidget *widget, gpointer data)
01408 {
01409     InvoiceWindow *iw = data;
01410     GncOwner owner;
01411 
01412     if (!iw)
01413         return FALSE;
01414 
01415     if (iw->dialog_type == VIEW_INVOICE)
01416         return FALSE;
01417 
01418     gncOwnerCopy (&(iw->proj_cust), &owner);
01419     gnc_owner_get_owner (iw->proj_cust_choice, &owner);
01420 
01421     /* If this owner really changed, then reset ourselves */
01422     if (!gncOwnerEqual (&owner, &(iw->proj_cust)))
01423     {
01424         gncOwnerCopy (&owner, &(iw->proj_cust));
01425         gncOwnerInitJob (&(iw->proj_job), NULL);
01426     }
01427 
01428     if (iw->dialog_type == EDIT_INVOICE)
01429         return FALSE;
01430 
01431     gnc_invoice_update_proj_job (iw);
01432 
01433     return FALSE;
01434 }
01435 
01436 static void
01437 gnc_invoice_dialog_close_handler (gpointer user_data)
01438 {
01439     InvoiceWindow *iw = user_data;
01440 
01441     if (iw)
01442     {
01443         gtk_widget_destroy (iw->dialog);
01444     }
01445 }
01446 
01447 static void
01448 gnc_invoice_window_close_handler (gpointer user_data)
01449 {
01450     InvoiceWindow *iw = user_data;
01451 
01452     if (iw)
01453     {
01454         gnc_main_window_close_page(iw->page);
01455         iw->page = NULL;
01456     }
01457 }
01458 
01459 static void
01460 gnc_invoice_reset_total_label (GtkLabel *label, gnc_numeric amt, gnc_commodity *com)
01461 {
01462     char string[256];
01463 
01464     amt = gnc_numeric_convert (amt, gnc_commodity_get_fraction(com), GNC_HOW_RND_ROUND_HALF_UP);
01465     xaccSPrintAmount (string, amt, gnc_commodity_print_info (com, TRUE));
01466     gtk_label_set_text (label, string);
01467 }
01468 
01469 static void
01470 gnc_invoice_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
01471 {
01472     InvoiceWindow *iw = data;
01473     GncInvoice * invoice;
01474     gnc_commodity * currency;
01475     gnc_numeric amount, to_charge_amt = gnc_numeric_zero();
01476 
01477     if (!iw)
01478         return;
01479 
01480     //  if (iw)
01481     //    gnc_invoice_update_window (iw, NULL);
01482 
01483     invoice = iw_get_invoice (iw);
01484     if (!invoice)
01485         return;
01486 
01487     currency = gncInvoiceGetCurrency (invoice);
01488 
01489     if (iw->total_label)
01490     {
01491         amount = gncInvoiceGetTotal (invoice);
01492         gnc_invoice_reset_total_label (GTK_LABEL (iw->total_label), amount, currency);
01493     }
01494 
01495     if (iw->total_subtotal_label)
01496     {
01497         amount = gncInvoiceGetTotalSubtotal (invoice);
01498         gnc_invoice_reset_total_label (GTK_LABEL (iw->total_subtotal_label), amount, currency);
01499     }
01500 
01501     if (iw->total_tax_label)
01502     {
01503         amount = gncInvoiceGetTotalTax (invoice);
01504         gnc_invoice_reset_total_label (GTK_LABEL (iw->total_tax_label), amount, currency);
01505     }
01506 
01507     /* Deal with extra items for the expense voucher */
01508 
01509     if (iw->to_charge_edit)
01510     {
01511         gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (iw->to_charge_edit));
01512         to_charge_amt = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(iw->to_charge_edit));
01513     }
01514 
01515     if (iw->total_cash_label)
01516     {
01517         amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CASH);
01518         amount = gnc_numeric_sub (amount, to_charge_amt,
01519                                   gnc_commodity_get_fraction (currency), GNC_HOW_RND_ROUND_HALF_UP);
01520         gnc_invoice_reset_total_label (GTK_LABEL (iw->total_cash_label), amount, currency);
01521     }
01522 
01523     if (iw->total_charge_label)
01524     {
01525         amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CARD);
01526         amount = gnc_numeric_add (amount, to_charge_amt,
01527                                   gnc_commodity_get_fraction (currency), GNC_HOW_RND_ROUND_HALF_UP);
01528         gnc_invoice_reset_total_label (GTK_LABEL (iw->total_charge_label), amount, currency);
01529     }
01530 }
01531 
01532 void
01533 gnc_invoice_window_changed (InvoiceWindow *iw, GtkWidget *window)
01534 {
01535     gnc_entry_ledger_set_parent(iw->ledger, window);
01536 }
01537 
01538 gchar *
01539 gnc_invoice_get_help (InvoiceWindow *iw)
01540 {
01541     if (!iw)
01542         return NULL;
01543 
01544     return gnc_table_get_help (gnc_entry_ledger_get_table (iw->ledger));
01545 }
01546 
01547 static void
01548 gnc_invoice_window_refresh_handler (GHashTable *changes, gpointer user_data)
01549 {
01550     InvoiceWindow *iw = user_data;
01551     const EventInfo *info;
01552     GncInvoice *invoice = iw_get_invoice (iw);
01553     const GncOwner *owner;
01554 
01555     /* If there isn't an invoice behind us, close down */
01556     if (!invoice)
01557     {
01558         gnc_close_gui_component (iw->component_id);
01559         return;
01560     }
01561 
01562     /* Next, close if this is a destroy event */
01563     if (changes)
01564     {
01565         info = gnc_gui_get_entity_events (changes, &iw->invoice_guid);
01566         if (info && (info->event_mask & QOF_EVENT_DESTROY))
01567         {
01568             gnc_close_gui_component (iw->component_id);
01569             return;
01570         }
01571     }
01572 
01573     /* Check the owners, and see if they have changed */
01574     owner = gncInvoiceGetOwner (invoice);
01575 
01576     /* Copy the owner information into our window */
01577     gncOwnerCopy (gncOwnerGetEndOwner (owner), &(iw->owner));
01578     gncOwnerInitJob (&(iw->job), gncOwnerGetJob (owner));
01579 
01580     /* Copy the billto information into our window */
01581     owner = gncInvoiceGetBillTo (invoice);
01582     gncOwnerCopy (gncOwnerGetEndOwner (owner), &iw->proj_cust);
01583     gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (owner));
01584 
01585     /* Ok, NOW let's refresh ourselves */
01586     gnc_invoice_update_window (iw, NULL);
01587 }
01588 
01599 static void
01600 gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget)
01601 {
01602     GtkWidget *acct_entry;
01603     GncInvoice *invoice;
01604     gboolean is_posted = FALSE;
01605     gboolean can_unpost = FALSE;
01606 
01607     invoice = iw_get_invoice (iw);
01608 
01609     if (iw->owner_choice)
01610         gtk_container_remove (GTK_CONTAINER (iw->owner_box), iw->owner_choice);
01611 
01612     if (iw->proj_cust_choice)
01613         gtk_container_remove (GTK_CONTAINER (iw->proj_cust_box),
01614                               iw->proj_cust_choice);
01615 
01616     switch (iw->dialog_type)
01617     {
01618     case VIEW_INVOICE:
01619     case EDIT_INVOICE:
01620         iw->owner_choice =
01621             gnc_owner_edit_create (iw->owner_label, iw->owner_box, iw->book,
01622                                    &(iw->owner));
01623         iw->proj_cust_choice =
01624             gnc_owner_edit_create (NULL, iw->proj_cust_box, iw->book,
01625                                    &(iw->proj_cust));
01626         break;
01627     case NEW_INVOICE:
01628     case MOD_INVOICE:
01629     case DUP_INVOICE:
01630         iw->owner_choice =
01631             gnc_owner_select_create (iw->owner_label, iw->owner_box, iw->book,
01632                                      &(iw->owner));
01633         iw->proj_cust_choice =
01634             gnc_owner_select_create (NULL, iw->proj_cust_box, iw->book,
01635                                      &(iw->proj_cust));
01636 
01637         g_signal_connect (G_OBJECT (iw->owner_choice), "changed",
01638                           G_CALLBACK (gnc_invoice_owner_changed_cb), iw);
01639 
01640         g_signal_connect (G_OBJECT (iw->proj_cust_choice), "changed",
01641                           G_CALLBACK (gnc_invoice_proj_cust_changed_cb), iw);
01642 
01643         break;
01644     }
01645 
01646     /* Set the type label */
01647     gtk_label_set_text (GTK_LABEL(iw->type_label), iw->is_credit_note ? _("Credit note") : _("Invoice"));
01648 
01649     if (iw->owner_choice)
01650         gtk_widget_show_all (iw->owner_choice);
01651     if (iw->proj_cust_choice)
01652         gtk_widget_show_all (iw->proj_cust_choice);
01653 
01654     gnc_invoice_update_job_choice (iw);
01655     gnc_invoice_update_proj_job (iw);
01656 
01657     /* Hide the project frame for customer invoices */
01658     if (iw->owner.type == GNC_OWNER_CUSTOMER)
01659         gtk_widget_hide_all (iw->proj_frame);
01660 
01661     /* Hide the "job" label and entry for employee invoices */
01662     if (iw->owner.type == GNC_OWNER_EMPLOYEE)
01663     {
01664         gtk_widget_hide_all (iw->job_label);
01665         gtk_widget_hide_all (iw->job_box);
01666     }
01667 
01668     acct_entry = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_entry"));
01669 
01670     /* We know that "invoice" (and "owner") exist now */
01671     {
01672         GtkTextBuffer* text_buffer;
01673         const char *string;
01674         gchar * tmp_string;
01675         Timespec ts, ts_zero = {0, 0};
01676         Account *acct;
01677 
01678         gtk_entry_set_text (GTK_ENTRY (iw->id_entry), gncInvoiceGetID (invoice));
01679 
01680         gtk_entry_set_text (GTK_ENTRY (iw->billing_id_entry),
01681                             gncInvoiceGetBillingID (invoice));
01682 
01683         string = gncInvoiceGetNotes (invoice);
01684         text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
01685         gtk_text_buffer_set_text (text_buffer, string, -1);
01686 
01687         if (iw->active_check)
01688             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (iw->active_check),
01689                                           gncInvoiceGetActive (invoice));
01690 
01691         ts = gncInvoiceGetDateOpened (invoice);
01692         if (timespec_equal (&ts, &ts_zero))
01693         {
01694             gnc_date_edit_set_time (GNC_DATE_EDIT (iw->opened_date), time(NULL));
01695         }
01696         else
01697         {
01698             gnc_date_edit_set_time_ts (GNC_DATE_EDIT (iw->opened_date), ts);
01699         }
01700 
01701         /* fill in the terms menu */
01702         iw->terms = gncInvoiceGetTerms (invoice);
01703         gnc_simple_combo_set_value (GTK_COMBO_BOX(iw->terms_menu), iw->terms);
01704 
01705         /*
01706          * Next, figure out if we've been posted, and if so set the
01707          * appropriate bits of information.. Then work on hiding or
01708          * showing as necessary.
01709          */
01710 
01711         acct = gncInvoiceGetPostedAcc (invoice);
01712         if (acct)
01713         {
01714             /* Ok, it's definitely posted. Setup the 'posted-invoice' fields now */
01715             is_posted = TRUE;
01716 
01717             /* Can we unpost this invoice?
01718              * XXX: right now we always can, but there
01719              * may be times in the future when we cannot.
01720              */
01721             can_unpost = TRUE;
01722 
01723             ts = gncInvoiceGetDatePosted (invoice);
01724             gnc_date_edit_set_time_ts (GNC_DATE_EDIT (iw->posted_date), ts);
01725 
01726             tmp_string = gnc_account_get_full_name (acct);
01727             gtk_entry_set_text (GTK_ENTRY (acct_entry), tmp_string);
01728             g_free(tmp_string);
01729         }
01730     }
01731 
01732     gnc_invoice_id_changed_cb(NULL, iw);
01733     if (iw->dialog_type == NEW_INVOICE ||
01734         iw->dialog_type == DUP_INVOICE ||
01735         iw->dialog_type == MOD_INVOICE)
01736     {
01737         if (widget)
01738             gtk_widget_show (widget);
01739         else
01740             gtk_widget_show (iw_get_window(iw));
01741         return;
01742     }
01743 
01744     /* Fill in the to_charge amount (only in VIEW/EDIT modes) */
01745     {
01746         gnc_numeric amount;
01747 
01748         amount = gncInvoiceGetToChargeAmount (invoice);
01749         gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (iw->to_charge_edit), amount);
01750     }
01751 
01752     /* Hide/show the appropriate widgets based on our posted/paid state */
01753 
01754     {
01755         GtkWidget *hide;
01756 
01757         if (is_posted == TRUE)
01758         {
01759             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide3"));
01760             gtk_widget_hide_all (hide);
01761             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide4"));
01762             gtk_widget_hide_all (hide);
01763 
01764         }
01765         else           /* ! posted */
01766         {
01767             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "posted_label"));
01768             gtk_widget_hide_all (hide);
01769             gtk_widget_hide_all (iw->posted_date_hbox);
01770 
01771             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_label"));
01772             gtk_widget_hide_all (hide);
01773             gtk_widget_hide_all (acct_entry);
01774 
01775             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide1"));
01776             gtk_widget_hide_all (hide);
01777             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide2"));
01778             gtk_widget_hide_all (hide);
01779         }
01780     }
01781 
01782     /* Set the toolbar widgets sensitivity */
01783     if (iw->page)
01784         gnc_plugin_page_invoice_update_menus(iw->page, is_posted, can_unpost);
01785 
01786     /* Set the to_charge widget */
01787     gtk_widget_set_sensitive (iw->to_charge_edit, !is_posted);
01788 
01789     /* Hide the to_charge frame for all non-employee invoices,
01790      * or set insensitive if the employee does not have a charge card
01791      */
01792     if (iw->owner.type == GNC_OWNER_EMPLOYEE)
01793     {
01794         if (!gncEmployeeGetCCard (gncOwnerGetEmployee(&iw->owner)))
01795             gtk_widget_set_sensitive (iw->to_charge_edit, FALSE);
01796     }
01797     else
01798     {
01799         gtk_widget_hide_all (iw->to_charge_frame);
01800     }
01801 
01802     if (is_posted)
01803     {
01804         //    GtkWidget *hide;
01805 
01806         /* Setup viewer for read-only access */
01807         /*
01808         gtk_widget_set_sensitive (iw->id_entry, FALSE);
01809         gtk_widget_set_sensitive (iw->terms_menu, FALSE);
01810         gtk_widget_set_sensitive (iw->notes_text, FALSE); *//* XXX: should notes remain writable? */
01811     }
01812 
01813     if (widget)
01814         gtk_widget_show (widget);
01815     else
01816         gtk_widget_show (iw_get_window(iw));
01817 }
01818 
01819 gchar *
01820 gnc_invoice_get_title (InvoiceWindow *iw)
01821 {
01822     char *wintitle = NULL;
01823     const char *id = NULL;
01824 
01825     if (!iw) return NULL;
01826 
01827     switch (gncOwnerGetType (&iw->owner))
01828     {
01829     case GNC_OWNER_CUSTOMER:
01830         switch (iw->dialog_type)
01831         {
01832         case NEW_INVOICE:
01833             wintitle = iw->is_credit_note ? _("New Credit Note")
01834                        : _("New Invoice");
01835             break;
01836         case MOD_INVOICE:
01837         case DUP_INVOICE:
01838         case EDIT_INVOICE:
01839             wintitle = iw->is_credit_note ? _("Edit Credit Note")
01840                        : _("Edit Invoice");
01841             break;
01842         case VIEW_INVOICE:
01843             wintitle = iw->is_credit_note ? _("View Credit Note")
01844                        : _("View Invoice");
01845             break;
01846         }
01847         break;
01848     case GNC_OWNER_VENDOR:
01849         switch (iw->dialog_type)
01850         {
01851         case NEW_INVOICE:
01852             wintitle = iw->is_credit_note ? _("New Credit Note")
01853                        : _("New Bill");
01854             break;
01855         case MOD_INVOICE:
01856         case DUP_INVOICE:
01857         case EDIT_INVOICE:
01858             wintitle = iw->is_credit_note ? _("Edit Credit Note")
01859                        : _("Edit Bill");
01860             break;
01861         case VIEW_INVOICE:
01862             wintitle = iw->is_credit_note ? _("View Credit Note")
01863                        : _("View Bill");
01864             break;
01865         }
01866         break;
01867     case GNC_OWNER_EMPLOYEE:
01868         switch (iw->dialog_type)
01869         {
01870         case NEW_INVOICE:
01871             wintitle = iw->is_credit_note ? _("New Credit Note")
01872                        : _("New Expense Voucher");
01873             break;
01874         case MOD_INVOICE:
01875         case DUP_INVOICE:
01876         case EDIT_INVOICE:
01877             wintitle = iw->is_credit_note ? _("Edit Credit Note")
01878                        : _("Edit Expense Voucher");
01879             break;
01880         case VIEW_INVOICE:
01881             wintitle = iw->is_credit_note ? _("View Credit Note")
01882                        : _("View Expense Voucher");
01883             break;
01884         }
01885         break;
01886     default:
01887         break;
01888     }
01889 
01890     if (iw->id_entry)
01891         id = gtk_entry_get_text (GTK_ENTRY (iw->id_entry));
01892     if (id && *id)
01893         return g_strconcat (wintitle, " - ", id, (char *)NULL);
01894     return g_strdup (wintitle);
01895 }
01896 
01897 void
01898 gnc_invoice_type_toggled_cb (GtkWidget *widget, gpointer data)
01899 {
01900     InvoiceWindow *iw = data;
01901 
01902     if (!iw) return;
01903     iw->is_credit_note = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
01904 }
01905 
01906 void
01907 gnc_invoice_id_changed_cb (GtkWidget *unused, gpointer data)
01908 {
01909     InvoiceWindow *iw = data;
01910     gchar *title;
01911 
01912     if (!iw) return;
01913     if (iw->page)
01914     {
01915         gnc_plugin_page_invoice_update_title (iw->page);
01916     }
01917     else
01918     {
01919         title = gnc_invoice_get_title (iw);
01920         gtk_window_set_title (GTK_WINDOW (iw->dialog), title);
01921         g_free (title);
01922     }
01923 }
01924 
01925 void
01926 gnc_invoice_terms_changed_cb (GtkWidget *widget, gpointer data)
01927 {
01928     GtkComboBox *cbox = GTK_COMBO_BOX (widget);
01929     InvoiceWindow *iw = data;
01930     gchar *title;
01931 
01932     if (!iw) return;
01933     if (!cbox) return;
01934 
01935     iw->terms = gnc_simple_combo_get_value (cbox);
01936 }
01937 
01938 
01939 static gboolean
01940 find_handler (gpointer find_data, gpointer user_data)
01941 {
01942     const GncGUID *invoice_guid = find_data;
01943     InvoiceWindow *iw = user_data;
01944 
01945     return(iw && guid_equal(&iw->invoice_guid, invoice_guid));
01946 }
01947 
01948 static InvoiceWindow *
01949 gnc_invoice_new_page (QofBook *bookp, InvoiceDialogType type,
01950                       GncInvoice *invoice, const GncOwner *owner,
01951                       GncMainWindow *window)
01952 {
01953     InvoiceWindow *iw;
01954     GncOwner *billto;
01955     GncPluginPage *new_page;
01956 
01957     g_assert (type != NEW_INVOICE && type != MOD_INVOICE && type != DUP_INVOICE);
01958     g_assert (invoice != NULL);
01959 
01960     /*
01961      * Find an existing window for this invoice.  If found, bring it to
01962      * the front.
01963      */
01964     if (invoice)
01965     {
01966         GncGUID invoice_guid;
01967 
01968         invoice_guid = *gncInvoiceGetGUID (invoice);
01969         iw = gnc_find_first_gui_component (DIALOG_VIEW_INVOICE_CM_CLASS,
01970                                            find_handler, &invoice_guid);
01971         if (iw)
01972         {
01973             gnc_main_window_display_page(iw->page);
01974             return(iw);
01975         }
01976     }
01977 
01978     /*
01979      * No existing invoice window found.  Build a new one.
01980      */
01981     iw = g_new0 (InvoiceWindow, 1);
01982     iw->book = bookp;
01983     iw->dialog_type = type;
01984     iw->invoice_guid = *gncInvoiceGetGUID (invoice);
01985     iw->is_credit_note = gncInvoiceGetIsCreditNote (invoice);
01986     iw->width = -1;
01987 
01988     /* Save this for later */
01989     gncOwnerCopy (gncOwnerGetEndOwner (owner), &(iw->owner));
01990     gncOwnerInitJob (&(iw->job), gncOwnerGetJob (owner));
01991 
01992     billto = gncInvoiceGetBillTo (invoice);
01993     gncOwnerCopy (gncOwnerGetEndOwner (billto), &(iw->proj_cust));
01994     gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (billto));
01995 
01996     /* Now create the plugin page for this invoice and display it. */
01997     new_page = gnc_plugin_page_invoice_new (iw);
01998     if (window)
01999         gnc_plugin_page_set_use_new_window (new_page, FALSE);
02000     else
02001         window = gnc_plugin_business_get_window ();
02002 
02003     gnc_main_window_open_page (window, new_page);
02004 
02005     /* Initialize the summary bar */
02006     gnc_invoice_redraw_all_cb(iw->reg, iw);
02007 
02008     return iw;
02009 }
02010 
02011 #define KEY_INVOICE_TYPE        "InvoiceType"
02012 #define KEY_INVOICE_GUID        "InvoiceGUID"
02013 #define KEY_OWNER_TYPE          "OwnerType"
02014 #define KEY_OWNER_GUID          "OwnerGUID"
02015 
02016 GncPluginPage *
02017 gnc_invoice_recreate_page (GncMainWindow *window,
02018                            GKeyFile *key_file,
02019                            const gchar *group_name)
02020 {
02021     InvoiceWindow *iw;
02022     GError *error = NULL;
02023     char *tmp_string = NULL, *owner_type = NULL;
02024     InvoiceDialogType type;
02025     GncInvoice *invoice;
02026     GncGUID guid;
02027     QofBook *book;
02028     GncOwner owner = { 0 };
02029 
02030     /* Get Invoice Type */
02031     tmp_string = g_key_file_get_string(key_file, group_name,
02032                                        KEY_INVOICE_TYPE, &error);
02033     if (error)
02034     {
02035         g_warning("Error reading group %s key %s: %s.",
02036                   group_name, KEY_INVOICE_TYPE, error->message);
02037         goto give_up;
02038     }
02039     type = InvoiceDialogTypefromString(tmp_string);
02040     g_free(tmp_string);
02041 
02042     /* Get Invoice GncGUID */
02043     tmp_string = g_key_file_get_string(key_file, group_name,
02044                                        KEY_INVOICE_GUID, &error);
02045     if (error)
02046     {
02047         g_warning("Error reading group %s key %s: %s.",
02048                   group_name, KEY_INVOICE_GUID, error->message);
02049         goto give_up;
02050     }
02051     if (!string_to_guid(tmp_string, &guid))
02052     {
02053         g_warning("Invalid invoice guid: %s.", tmp_string);
02054         goto give_up;
02055     }
02056     book = gnc_get_current_book();
02057     invoice = gncInvoiceLookup(gnc_get_current_book(), &guid);
02058     if (invoice == NULL)
02059     {
02060         g_warning("Can't find invoice %s in current book.", tmp_string);
02061         goto give_up;
02062     }
02063     g_free(tmp_string);
02064 
02065     /* Get Owner Type */
02066     owner_type = g_key_file_get_string(key_file, group_name,
02067                                        KEY_OWNER_TYPE, &error);
02068     if (error)
02069     {
02070         g_warning("Error reading group %s key %s: %s.",
02071                   group_name, KEY_OWNER_TYPE, error->message);
02072         goto give_up;
02073     }
02074 
02075     /* Get Owner GncGUID */
02076     tmp_string = g_key_file_get_string(key_file, group_name,
02077                                        KEY_OWNER_GUID, &error);
02078     if (error)
02079     {
02080         g_warning("Error reading group %s key %s: %s.",
02081                   group_name, KEY_OWNER_GUID, error->message);
02082         goto give_up;
02083     }
02084     if (!string_to_guid(tmp_string, &guid))
02085     {
02086         g_warning("Invalid owner guid: %s.", tmp_string);
02087         goto give_up;
02088     }
02089 
02090     if (!gncOwnerGetOwnerFromTypeGuid(book, &owner, owner_type, &guid))
02091     {
02092         g_warning("Can't find owner %s in current book.", tmp_string);
02093         goto give_up;
02094     }
02095     g_free(tmp_string);
02096     g_free(owner_type);
02097 
02098     iw = gnc_invoice_new_page (book, type, invoice, &owner, window);
02099     return iw->page;
02100 
02101 give_up:
02102     g_warning("Giving up on restoring '%s'.", group_name);
02103     if (error)
02104         g_error_free(error);
02105     if (tmp_string)
02106         g_free(tmp_string);
02107     if (owner_type)
02108         g_free(owner_type);
02109     return NULL;
02110 }
02111 
02112 void
02113 gnc_invoice_save_page (InvoiceWindow *iw,
02114                        GKeyFile *key_file,
02115                        const gchar *group_name)
02116 {
02117     g_key_file_set_string(key_file, group_name, KEY_INVOICE_TYPE,
02118                           InvoiceDialogTypeasString(iw->dialog_type));
02119     g_key_file_set_string(key_file, group_name, KEY_INVOICE_GUID,
02120                           guid_to_string(&iw->invoice_guid));
02121 
02122     g_key_file_set_string(key_file, group_name, KEY_OWNER_TYPE,
02123                           qofOwnerGetType(&iw->owner));
02124     g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID,
02125                           guid_to_string(gncOwnerGetGUID(&iw->owner)));
02126 }
02127 
02128 GtkWidget *
02129 gnc_invoice_create_page (InvoiceWindow *iw, gpointer page)
02130 {
02131     GncInvoice *invoice;
02132     GtkBuilder *builder;
02133     GtkWidget *dialog, *hbox;
02134     GncEntryLedger *entry_ledger = NULL;
02135     GncOwnerType owner_type;
02136     GncEntryLedgerType ledger_type;
02137     const gchar *gconf_section = NULL;
02138     gboolean is_credit_note = FALSE;
02139 
02140     invoice = gncInvoiceLookup (iw->book, &iw->invoice_guid);
02141     is_credit_note = gncInvoiceGetIsCreditNote (invoice);
02142 
02143     iw->page = page;
02144 
02145     /* Find the dialog */
02146     iw->builder = builder = gtk_builder_new();
02147     gnc_builder_add_from_file (builder, "dialog-invoice.glade", "terms_store");
02148     gnc_builder_add_from_file (builder, "dialog-invoice.glade", "invoice_entry_vbox");
02149     dialog = GTK_WIDGET (gtk_builder_get_object (builder, "invoice_entry_vbox"));
02150 
02151     /* Autoconnect all the signals */
02152     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, iw);
02153 
02154     /* Grab the widgets */
02155     iw->type_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_type_label"));
02156     iw->id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "page_id_entry"));
02157     iw->billing_id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "page_billing_id_entry"));
02158     iw->terms_menu = GTK_WIDGET (gtk_builder_get_object (builder, "page_terms_menu"));
02159     iw->notes_text = GTK_WIDGET (gtk_builder_get_object (builder, "page_notes_text"));
02160     iw->active_check = GTK_WIDGET (gtk_builder_get_object (builder, "active_check"));
02161     iw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_owner_hbox"));
02162     iw->owner_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_owner_label"));
02163     iw->job_label = GTK_WIDGET (gtk_builder_get_object (builder, "page_job_label"));
02164     iw->job_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_job_hbox"));
02165 
02166     /* grab the project widgets */
02167     iw->proj_frame = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_frame"));
02168     iw->proj_cust_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_cust_hbox"));
02169     iw->proj_job_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_proj_job_hbox"));
02170 
02171     /* grab the to_charge widgets */
02172     {
02173         GtkWidget *edit;
02174 
02175         gnc_commodity *currency = gncInvoiceGetCurrency (invoice);
02176         GNCPrintAmountInfo print_info;
02177 
02178         iw->to_charge_frame = GTK_WIDGET (gtk_builder_get_object (builder, "to_charge_frame"));
02179         edit = gnc_amount_edit_new();
02180         print_info = gnc_commodity_print_info (currency, FALSE);
02181         gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
02182         gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (edit), print_info);
02183         gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (edit),
02184                                       gnc_commodity_get_fraction (currency));
02185         iw->to_charge_edit = edit;
02186         gtk_widget_show (edit);
02187         hbox = GTK_WIDGET (gtk_builder_get_object (builder, "to_charge_box"));
02188         gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);
02189 
02190         g_signal_connect(G_OBJECT(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(edit))),
02191                          "focus-out-event",
02192                          G_CALLBACK(gnc_invoice_window_leave_to_charge_cb), iw);
02193         g_signal_connect(G_OBJECT(edit), "amount_changed",
02194                          G_CALLBACK(gnc_invoice_window_changed_to_charge_cb), iw);
02195     }
02196 
02197     hbox = GTK_WIDGET (gtk_builder_get_object (builder, "page_date_opened_hbox"));
02198     iw->opened_date = gnc_date_edit_new (time(NULL), FALSE, FALSE);
02199     gtk_widget_show(iw->opened_date);
02200     gtk_box_pack_start (GTK_BOX(hbox), iw->opened_date, TRUE, TRUE, 0);
02201 
02202     iw->posted_date_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "date_posted_hbox"));
02203     iw->posted_date = gnc_date_edit_new (time(NULL), FALSE, FALSE);
02204     gtk_widget_show(iw->posted_date);
02205     gtk_box_pack_start (GTK_BOX(iw->posted_date_hbox), iw->posted_date,
02206                         TRUE, TRUE, 0);
02207 
02208     /* Make the opened and posted dates insensitive in this window */
02209     gtk_widget_set_sensitive (iw->opened_date, FALSE);
02210     gtk_widget_set_sensitive (iw->posted_date, FALSE);
02211 
02212     /* Build the ledger */
02213     ledger_type = GNCENTRY_INVOICE_VIEWER;
02214     owner_type = gncOwnerGetType (&iw->owner);
02215     switch (iw->dialog_type)
02216     {
02217     case EDIT_INVOICE:
02218         switch (owner_type)
02219         {
02220         case GNC_OWNER_CUSTOMER:
02221             ledger_type = is_credit_note ? GNCENTRY_CUST_CREDIT_NOTE_ENTRY
02222                           : GNCENTRY_INVOICE_ENTRY;
02223             break;
02224         case GNC_OWNER_VENDOR:
02225             ledger_type = is_credit_note ? GNCENTRY_VEND_CREDIT_NOTE_ENTRY
02226                           : GNCENTRY_BILL_ENTRY;
02227             break;
02228         case GNC_OWNER_EMPLOYEE:
02229             ledger_type = is_credit_note ? GNCENTRY_EMPL_CREDIT_NOTE_ENTRY
02230                           : GNCENTRY_EXPVOUCHER_ENTRY;
02231             break;
02232         default:
02233             g_warning ("Invalid owner type");
02234             break;
02235         }
02236         break;
02237     case VIEW_INVOICE:
02238     default:
02239         switch (owner_type)
02240         {
02241         case GNC_OWNER_CUSTOMER:
02242             ledger_type = is_credit_note ? GNCENTRY_CUST_CREDIT_NOTE_VIEWER
02243                           : GNCENTRY_INVOICE_VIEWER;
02244             gconf_section = GCONF_SECTION_INVOICE;
02245             break;
02246         case GNC_OWNER_VENDOR:
02247             ledger_type = is_credit_note ? GNCENTRY_VEND_CREDIT_NOTE_VIEWER
02248                           : GNCENTRY_BILL_VIEWER;
02249             gconf_section = GCONF_SECTION_BILL;
02250             break;
02251         case GNC_OWNER_EMPLOYEE:
02252             ledger_type = is_credit_note ? GNCENTRY_EMPL_CREDIT_NOTE_VIEWER
02253                           : GNCENTRY_EXPVOUCHER_VIEWER;
02254             gconf_section = GCONF_SECTION_BILL;
02255             break;
02256         default:
02257             g_warning ("Invalid owner type");
02258             break;
02259         }
02260         break;
02261     }
02262     entry_ledger = gnc_entry_ledger_new (iw->book, ledger_type);
02263 
02264     /* Save the ledger... */
02265     iw->ledger = entry_ledger;
02266     /* window will be updated in a callback */
02267 
02268     /* Set the entry_ledger's invoice */
02269     gnc_entry_ledger_set_default_invoice (entry_ledger, invoice);
02270 
02271     /* Set the gconf section */
02272     gnc_entry_ledger_set_gconf_section (entry_ledger, gconf_section);
02273 
02274     /* Setup initial values */
02275     iw->component_id =
02276         gnc_register_gui_component (DIALOG_VIEW_INVOICE_CM_CLASS,
02277                                     gnc_invoice_window_refresh_handler,
02278                                     gnc_invoice_window_close_handler,
02279                                     iw);
02280 
02281     gnc_gui_component_watch_entity_type (iw->component_id,
02282                                          GNC_INVOICE_MODULE_NAME,
02283                                          QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
02284 
02285     /* Create the register */
02286     {
02287         GtkWidget *regWidget, *frame, *window;
02288 
02289         /* Watch the order of operations, here... */
02290         regWidget = gnucash_register_new (gnc_entry_ledger_get_table
02291                                           (entry_ledger));
02292         gtk_widget_show(regWidget);
02293         gnc_table_init_gui( regWidget, entry_ledger );
02294 
02295         frame = GTK_WIDGET (gtk_builder_get_object (builder, "ledger_frame"));
02296         gtk_container_add (GTK_CONTAINER (frame), regWidget);
02297 
02298         iw->reg = GNUCASH_REGISTER (regWidget);
02299         window = gnc_plugin_page_get_window(iw->page);
02300         GNUCASH_SHEET (iw->reg->sheet)->window = window;
02301 
02302         g_signal_connect (G_OBJECT (regWidget), "activate_cursor",
02303                           G_CALLBACK (gnc_invoice_window_recordCB), iw);
02304         g_signal_connect (G_OBJECT (regWidget), "redraw_all",
02305                           G_CALLBACK (gnc_invoice_redraw_all_cb), iw);
02306     }
02307 
02308     gnc_table_realize_gui (gnc_entry_ledger_get_table (entry_ledger));
02309 
02310     /* Now fill in a lot of the pieces and display properly */
02311     gnc_billterms_combo (GTK_COMBO_BOX(iw->terms_menu), iw->book, TRUE, iw->terms);
02312     gnc_invoice_update_window (iw, dialog);
02313 
02314     gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), TRUE);
02315 
02316     /* Show the dialog */
02317     //  gtk_widget_show_all (dialog);
02318 
02319     return dialog;
02320 }
02321 
02322 static InvoiceWindow *
02323 gnc_invoice_window_new_invoice (InvoiceDialogType dialog_type, QofBook *bookp,
02324                                 const GncOwner *owner, GncInvoice *invoice)
02325 {
02326     InvoiceWindow *iw;
02327     GtkBuilder *builder;
02328     GtkWidget *hbox;
02329     GncOwner *billto;
02330     const GncOwner *start_owner;
02331     GncBillTerm *owner_terms = NULL;
02332 
02333     g_assert (dialog_type == NEW_INVOICE || dialog_type == MOD_INVOICE || dialog_type == DUP_INVOICE);
02334 
02335     if (invoice)
02336     {
02337         /*
02338          * Try to find an existing window for this invoice.  If found,
02339          * bring it to the front.
02340          */
02341         GncGUID invoice_guid;
02342 
02343         invoice_guid = *gncInvoiceGetGUID (invoice);
02344         iw = gnc_find_first_gui_component (DIALOG_NEW_INVOICE_CM_CLASS,
02345                                            find_handler, &invoice_guid);
02346         if (iw)
02347         {
02348             gtk_window_present (GTK_WINDOW(iw->dialog));
02349             return(iw);
02350         }
02351     }
02352 
02353     /*
02354      * No existing invoice window found.  Build a new one.
02355      */
02356 
02357     iw = g_new0 (InvoiceWindow, 1);
02358     iw->dialog_type = dialog_type;
02359 
02360     switch (dialog_type)
02361     {
02362     case NEW_INVOICE:
02363         g_assert (bookp);
02364 
02365         invoice = gncInvoiceCreate (bookp);
02366         gncInvoiceSetCurrency (invoice, gnc_default_currency ());
02367         iw->book = bookp;
02368         start_owner = owner;
02369         switch (gncOwnerGetType (gncOwnerGetEndOwner (owner)))
02370         {
02371         case GNC_OWNER_CUSTOMER:
02372             owner_terms = gncCustomerGetTerms (gncOwnerGetCustomer (gncOwnerGetEndOwner (owner)));
02373             break;
02374         case GNC_OWNER_VENDOR:
02375             owner_terms = gncVendorGetTerms (gncOwnerGetVendor (gncOwnerGetEndOwner (owner)));
02376             break;
02377         default:
02378             break;
02379         }
02380         if (owner_terms)
02381             gncInvoiceSetTerms (invoice, owner_terms);
02382         break;
02383 
02384     case MOD_INVOICE:
02385     case DUP_INVOICE:
02386         start_owner = gncInvoiceGetOwner (invoice);
02387         iw->book = gncInvoiceGetBook (invoice);
02388         break;
02389     default:
02390         /* The assert at the beginning of this function should prevent this switch case ! */
02391         return NULL;
02392     }
02393 
02394     /* Save this for later */
02395     gncOwnerCopy (gncOwnerGetEndOwner(start_owner), &(iw->owner));
02396     gncOwnerInitJob (&(iw->job), gncOwnerGetJob (start_owner));
02397 
02398     billto = gncInvoiceGetBillTo (invoice);
02399     gncOwnerCopy (gncOwnerGetEndOwner (billto), &(iw->proj_cust));
02400     gncOwnerInitJob (&iw->proj_job, gncOwnerGetJob (billto));
02401 
02402     /* Find the glade page layout */
02403     iw->builder = builder = gtk_builder_new();
02404     gnc_builder_add_from_file (builder, "dialog-invoice.glade", "terms_store");
02405     gnc_builder_add_from_file (builder, "dialog-invoice.glade", "New Invoice Dialog");
02406     iw->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "New Invoice Dialog"));
02407 
02408     g_object_set_data (G_OBJECT (iw->dialog), "dialog_info", iw);
02409 
02410     /* Grab the widgets */
02411     iw->type_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_label"));
02412     iw->type_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_choice_hbox"));
02413     iw->type_choice = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_invoice"));
02414     /* configure the type related widgets based on dialog type and invoice type */
02415     switch (dialog_type)
02416     {
02417     case NEW_INVOICE:
02418     case DUP_INVOICE:
02419         gtk_widget_show_all (iw->type_hbox);
02420         gtk_widget_hide (iw->type_label);
02421         break;
02422     case MOD_INVOICE:
02423         gtk_widget_hide_all (iw->type_hbox);
02424         gtk_widget_show (iw->type_label);
02425         break;
02426     default:
02427         break;
02428     }
02429 
02430     iw->id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_id_entry"));
02431     iw->billing_id_entry = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_billing_id_entry"));
02432     iw->terms_menu = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_terms_menu"));
02433     iw->notes_text = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_notes_text"));
02434     iw->owner_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_owner_hbox"));
02435     iw->owner_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_owner_label"));
02436     iw->job_label = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_job_label"));
02437     iw->job_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_job_hbox"));
02438 
02439     /* Grab the project widgets */
02440     iw->proj_frame = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_frame"));
02441     iw->proj_cust_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_cust_hbox"));
02442     iw->proj_job_box = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_proj_job_hbox"));
02443 
02444     hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_date_opened_hbox"));
02445     iw->opened_date = gnc_date_edit_new (time(NULL), FALSE, FALSE);
02446     gtk_widget_show(iw->opened_date);
02447     gtk_box_pack_start (GTK_BOX(hbox), iw->opened_date, TRUE, TRUE, 0);
02448 
02449     /* If this is a New Invoice, reset the Notes file to read/write */
02450     gtk_widget_set_sensitive (iw->notes_text, (iw->dialog_type == NEW_INVOICE));
02451 
02452     /* Setup signals */
02453     gtk_builder_connect_signals_full( builder,
02454                                       gnc_builder_connect_full_func,
02455                                       iw);
02456 
02457     /* Setup initial values */
02458     iw->invoice_guid = *gncInvoiceGetGUID (invoice);
02459     iw->is_credit_note = gncInvoiceGetIsCreditNote (invoice);
02460 
02461     iw->component_id =
02462         gnc_register_gui_component (DIALOG_NEW_INVOICE_CM_CLASS,
02463                                     gnc_invoice_window_refresh_handler,
02464                                     gnc_invoice_dialog_close_handler,
02465                                     iw);
02466 
02467     gnc_gui_component_watch_entity_type (iw->component_id,
02468                                          GNC_INVOICE_MODULE_NAME,
02469                                          QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
02470 
02471     /* Now fill in a lot of the pieces and display properly */
02472     gnc_billterms_combo (GTK_COMBO_BOX(iw->terms_menu), iw->book, TRUE, iw->terms);
02473     gnc_invoice_update_window (iw, iw->dialog);
02474     gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), TRUE);
02475 
02476     // The customer choice widget should have keyboard focus
02477     if (GNC_IS_GENERAL_SEARCH(iw->owner_choice))
02478     {
02479         gnc_general_search_grab_focus(GNC_GENERAL_SEARCH(iw->owner_choice));
02480     }
02481 
02482     return iw;
02483 }
02484 
02485 InvoiceWindow *
02486 gnc_ui_invoice_edit (GncInvoice *invoice)
02487 {
02488     InvoiceWindow *iw;
02489     InvoiceDialogType type;
02490 
02491     if (!invoice) return NULL;
02492 
02493     /* Immutable once we've been posted */
02494     if (gncInvoiceGetPostedAcc (invoice))
02495         type = VIEW_INVOICE;
02496     else
02497         type = EDIT_INVOICE;
02498 
02499     iw = gnc_invoice_new_page (gncInvoiceGetBook(invoice), type,
02500                                invoice, gncInvoiceGetOwner (invoice), NULL);
02501 
02502     return iw;
02503 }
02504 
02505 static InvoiceWindow *
02506 gnc_ui_invoice_modify (GncInvoice *invoice)
02507 {
02508     InvoiceWindow *iw;
02509     if (!invoice) return NULL;
02510 
02511     iw = gnc_invoice_window_new_invoice (MOD_INVOICE, NULL, NULL, invoice);
02512     return iw;
02513 }
02514 
02515 static void
02516 set_gncEntry_date(gpointer data, gpointer user_data)
02517 {
02518     GncEntry *entry = data;
02519     const GDate* new_date = user_data;
02520     //g_warning("Modifying date for entry with desc=\"%s\"", gncEntryGetDescription(entry));
02521 
02522     gncEntrySetDateGDate(entry, new_date);
02523     /*gncEntrySetDateEntered(entry, *new_date); - don't modify this
02524      * because apparently it defines the ordering of the entries,
02525      * which we don't want to change. */
02526 }
02527 
02528 
02529 InvoiceWindow * gnc_ui_invoice_duplicate (GncInvoice *old_invoice, gboolean open_properties, const GDate *new_date)
02530 {
02531     InvoiceWindow *iw;
02532     GncInvoice *new_invoice = NULL;
02533     gchar *new_id;
02534     GList *node;
02535     GDate new_date_gdate;
02536 
02537     g_assert(old_invoice);
02538 
02539     // Create a deep copy of the old invoice
02540     new_invoice = gncInvoiceCopy(old_invoice);
02541 
02542     // The new invoice is for sure active
02543     gncInvoiceSetActive(new_invoice, TRUE);
02544 
02545     // and unposted
02546     if (gncInvoiceIsPosted (new_invoice))
02547     {
02548         gboolean result = gncInvoiceUnpost(new_invoice, TRUE);
02549         if (!result)
02550         {
02551             g_warning("Oops, error when unposting the copied invoice; ignoring.");
02552         }
02553     }
02554 
02555     // Set a new id from the respective counter
02556     new_id = gncInvoiceNextID(gnc_get_current_book(),
02557                               gncInvoiceGetOwner(new_invoice));
02558     gncInvoiceSetID(new_invoice, new_id);
02559     g_free(new_id);
02560 
02561     // Modify the date to today
02562     if (new_date)
02563     {
02564         new_date_gdate = *new_date;
02565     }
02566     else
02567     {
02568         GDate *tmp = gnc_g_date_new_today();
02569         new_date_gdate = *tmp;
02570         g_date_free(tmp);
02571     }
02572     gncInvoiceSetDateOpenedGDate(new_invoice, &new_date_gdate);
02573 
02574     // Also modify the date of all entries to today
02575     //g_warning("We have %d entries", g_list_length(gncInvoiceGetEntries(new_invoice)));
02576     g_list_foreach(gncInvoiceGetEntries(new_invoice),
02577                    &set_gncEntry_date, &new_date_gdate);
02578 
02579 
02580     if (open_properties)
02581     {
02582         // Open the "properties" pop-up for the invoice...
02583         iw = gnc_invoice_window_new_invoice (DUP_INVOICE, NULL, NULL, new_invoice);
02584     }
02585     else
02586     {
02587         // Open the newly created invoice in the "edit" window
02588         iw = gnc_ui_invoice_edit (new_invoice);
02589     }
02590 
02591     return iw;
02592 }
02593 
02594 InvoiceWindow *
02595 gnc_ui_invoice_new (GncOwner *ownerp, QofBook *bookp)
02596 {
02597     InvoiceWindow *iw;
02598     GncOwner owner;
02599 
02600     if (ownerp)
02601     {
02602         gncOwnerCopy (ownerp, &owner);
02603     }
02604     else
02605         gncOwnerInitCustomer (&owner, NULL); /* XXX: pass in the owner type? */
02606 
02607     /* Make sure required options exist */
02608     if (!bookp) return NULL;
02609 
02610     iw = gnc_invoice_window_new_invoice (NEW_INVOICE, bookp, &owner, NULL);
02611 
02612     return iw;
02613 }
02614 
02615 /* Functions for invoice selection widgets */
02616 
02617 static void
02618 edit_invoice_direct (gpointer invoice, gpointer user_data)
02619 {
02620     g_return_if_fail (invoice);
02621     gnc_ui_invoice_edit (invoice);
02622 }
02623 
02624 static void
02625 edit_invoice_cb (gpointer *invoice_p, gpointer user_data)
02626 {
02627     g_return_if_fail (invoice_p && user_data);
02628     if (! *invoice_p)
02629         return;
02630     edit_invoice_direct (*invoice_p, user_data);
02631 }
02632 
02633 static void
02634 pay_invoice_direct (gpointer inv, gpointer user_data)
02635 {
02636     GncInvoice *invoice = inv;
02637 
02638     g_return_if_fail (invoice);
02639     gnc_ui_payment_new_with_invoice (gncInvoiceGetOwner (invoice),
02640                                      gncInvoiceGetBook (invoice), invoice);
02641 }
02642 
02643 static void
02644 pay_invoice_cb (gpointer *invoice_p, gpointer user_data)
02645 {
02646     g_return_if_fail (invoice_p && user_data);
02647     if (! *invoice_p)
02648         return;
02649     pay_invoice_direct (*invoice_p, user_data);
02650 }
02651 struct multi_duplicate_invoice_data
02652 {
02653     GDate date;
02654 };
02655 
02656 static void multi_duplicate_invoice_one(gpointer data, gpointer user_data)
02657 {
02658     GncInvoice *old_invoice = data;
02659     struct multi_duplicate_invoice_data *dup_user_data = user_data;
02660 
02661     g_assert(dup_user_data);
02662     if (old_invoice)
02663     {
02664         GncInvoice *new_invoice;
02665         // In this simplest form, we just use the existing duplication
02666         // algorithm, only without opening the "edit invoice" window for editing
02667         // the number etc. for each of the invoices.
02668         InvoiceWindow *iw = gnc_ui_invoice_duplicate(old_invoice, FALSE, &dup_user_data->date);
02669         // FIXME: Now we could use this invoice and manipulate further data.
02670         g_assert(iw);
02671         new_invoice = iw->created_invoice;
02672         g_assert(new_invoice); // FIXME: This is NULL?!?
02673     }
02674 }
02675 
02676 static void
02677 multi_duplicate_invoice_cb (GList *invoice_list, gpointer user_data)
02678 {
02679     struct _invoice_select_window *sw = user_data; // unused, though
02680     g_return_if_fail (invoice_list);
02681     switch (g_list_length(invoice_list))
02682     {
02683     case 0:
02684         return;
02685     case 1:
02686     {
02687         // Duplicate exactly one invoice
02688         GncInvoice *old_invoice = invoice_list->data;
02689         gnc_ui_invoice_duplicate(old_invoice, TRUE, NULL);
02690         return;
02691     }
02692     default:
02693     {
02694         // Duplicate multiple invoices. We ask for a date first.
02695         struct multi_duplicate_invoice_data dup_user_data;
02696         gboolean dialog_ok;
02697 
02698         // Default date: Today
02699         g_date_set_time_t(&dup_user_data.date, time(NULL));
02700         dialog_ok = gnc_dup_date_dialog (NULL, _("Date of duplicated entries"), &dup_user_data.date);
02701         if (!dialog_ok)
02702         {
02703             // User pressed cancel, so don't duplicate anything here.
02704             return;
02705         }
02706 
02707         // Note: If we want to have a more sophisticated duplication, we might want
02708         // to ask for particular data right here, then insert this data upon
02709         // duplication.
02710         g_list_foreach(invoice_list, multi_duplicate_invoice_one, &dup_user_data);
02711         return;
02712     }
02713     }
02714 }
02715 
02716 static void post_one_invoice_cb(gpointer data, gpointer user_data)
02717 {
02718     GncInvoice *invoice = data;
02719     InvoiceWindow *iw = gnc_ui_invoice_edit(invoice);
02720     gnc_invoice_window_ok_save (iw);
02721     gnc_invoice_window_postCB(NULL, iw);
02722 }
02723 
02724 static void
02725 multi_post_invoice_cb (GList *invoice_list, gpointer user_data)
02726 {
02727     if (g_list_length(invoice_list) == 0)
02728         return;
02729 
02730     g_list_foreach(invoice_list, post_one_invoice_cb, user_data);
02731 }
02732 
02733 static void print_one_invoice_cb(gpointer data, gpointer user_data)
02734 {
02735     GncInvoice *invoice = data;
02736     gnc_invoice_window_print_invoice(invoice); // that's all!
02737 }
02738 
02739 static void
02740 multi_print_invoice_cb (GList *invoice_list, gpointer user_data)
02741 {
02742     if (g_list_length(invoice_list) == 0)
02743         return;
02744 
02745     g_list_foreach(invoice_list, print_one_invoice_cb, user_data);
02746 }
02747 
02748 static gpointer
02749 new_invoice_cb (gpointer user_data)
02750 {
02751     struct _invoice_select_window *sw = user_data;
02752     InvoiceWindow *iw;
02753 
02754     g_return_val_if_fail (user_data, NULL);
02755 
02756     iw = gnc_ui_invoice_new (sw->owner, sw->book);
02757     return iw_get_invoice (iw);
02758 }
02759 
02760 static void
02761 free_invoice_cb (gpointer user_data)
02762 {
02763     struct _invoice_select_window *sw = user_data;
02764 
02765     g_return_if_fail (sw);
02766 
02767     qof_query_destroy (sw->q);
02768     g_free (sw);
02769 }
02770 
02771 GNCSearchWindow *
02772 gnc_invoice_search (GncInvoice *start, GncOwner *owner, QofBook *book)
02773 {
02774     QofIdType type = GNC_INVOICE_MODULE_NAME;
02775     struct _invoice_select_window *sw;
02776     QofQuery *q, *q2 = NULL;
02777     GncOwnerType owner_type = GNC_OWNER_CUSTOMER;
02778     static GList *inv_params = NULL, *bill_params = NULL, *emp_params = NULL, *params;
02779     static GList *columns = NULL;
02780     const gchar *title, *label;
02781     static GNCSearchCallbackButton *buttons;
02782     static GNCSearchCallbackButton inv_buttons[] =
02783     {
02784         { N_("View/Edit Invoice"), edit_invoice_cb, NULL, TRUE},
02785         { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
02786         { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
02787         { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
02788         { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
02789         { NULL },
02790     };
02791     static GNCSearchCallbackButton bill_buttons[] =
02792     {
02793         { N_("View/Edit Bill"), edit_invoice_cb, NULL, TRUE},
02794         { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
02795         { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
02796         { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
02797         { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
02798         { NULL },
02799     };
02800     static GNCSearchCallbackButton emp_buttons[] =
02801     {
02802         /* Translators: The terms 'Voucher' and 'Expense Voucher' are used
02803            interchangeably in gnucash and mean the same thing. */
02804         { N_("View/Edit Voucher"), edit_invoice_cb, NULL, TRUE},
02805         { N_("Process Payment"), pay_invoice_cb, NULL, FALSE},
02806         { N_("Duplicate"), NULL, multi_duplicate_invoice_cb, FALSE},
02807         { N_("Post"), NULL, multi_post_invoice_cb, FALSE},
02808         { N_("Printable Report"), NULL, multi_print_invoice_cb, TRUE},
02809         { NULL },
02810     };
02811 
02812     g_return_val_if_fail (book, NULL);
02813 
02814     /* Build parameter list in reverse order */
02815     if (inv_params == NULL)
02816     {
02817         inv_params = gnc_search_param_prepend (inv_params,
02818                                                _("Invoice Owner"), NULL, type,
02819                                                INVOICE_OWNER, NULL);
02820         inv_params = gnc_search_param_prepend (inv_params,
02821                                                _("Invoice Notes"), NULL, type,
02822                                                INVOICE_NOTES, NULL);
02823         inv_params = gnc_search_param_prepend (inv_params,
02824                                                _("Billing ID"), NULL, type,
02825                                                INVOICE_BILLINGID, NULL);
02826         inv_params = gnc_search_param_prepend (inv_params,
02827                                                _("Is Paid?"), NULL, type,
02828                                                INVOICE_IS_PAID, NULL);
02829         inv_params = gnc_search_param_prepend (inv_params,
02830                                                _("Date Posted"), NULL, type,
02831                                                INVOICE_POSTED, NULL);
02832         inv_params = gnc_search_param_prepend (inv_params,
02833                                                _("Is Posted?"), NULL, type,
02834                                                INVOICE_IS_POSTED, NULL);
02835         inv_params = gnc_search_param_prepend (inv_params,
02836                                                _("Date Opened"), NULL, type,
02837                                                INVOICE_OPENED, NULL);
02838         inv_params = gnc_search_param_prepend (inv_params,
02839                                                _("Due Date"), NULL, type,
02840                                                INVOICE_DUE, NULL);
02841         inv_params = gnc_search_param_prepend (inv_params,
02842                                                _("Company Name "), NULL, type,
02843                                                INVOICE_OWNER, OWNER_PARENT,
02844                                                OWNER_NAME, NULL);
02845         inv_params = gnc_search_param_prepend (inv_params,
02846                                                _("Invoice ID"), NULL, type,
02847                                                INVOICE_ID, NULL);
02848     }
02849     if (bill_params == NULL)
02850     {
02851         bill_params = gnc_search_param_prepend (bill_params,
02852                                                 _("Bill Owner"), NULL, type,
02853                                                 INVOICE_OWNER, NULL);
02854         bill_params = gnc_search_param_prepend (bill_params,
02855                                                 _("Bill Notes"), NULL, type,
02856                                                 INVOICE_NOTES, NULL);
02857         bill_params = gnc_search_param_prepend (bill_params,
02858                                                 _("Billing ID"), NULL, type,
02859                                                 INVOICE_BILLINGID, NULL);
02860         bill_params = gnc_search_param_prepend (bill_params,
02861                                                 _("Is Paid?"), NULL, type,
02862                                                 INVOICE_IS_PAID, NULL);
02863         bill_params = gnc_search_param_prepend (bill_params,
02864                                                 _("Date Posted"), NULL, type,
02865                                                 INVOICE_POSTED, NULL);
02866         bill_params = gnc_search_param_prepend (bill_params,
02867                                                 _("Is Posted?"), NULL, type,
02868                                                 INVOICE_IS_POSTED, NULL);
02869         bill_params = gnc_search_param_prepend (bill_params,
02870                                                 _("Date Opened"), NULL, type,
02871                                                 INVOICE_OPENED, NULL);
02872         bill_params = gnc_search_param_prepend (bill_params,
02873                                                 _("Due Date"), NULL, type,
02874                                                 INVOICE_DUE, NULL);
02875         bill_params = gnc_search_param_prepend (bill_params,
02876                                                 _("Company Name "), NULL, type,
02877                                                 INVOICE_OWNER, OWNER_PARENT,
02878                                                 OWNER_NAME, NULL);
02879         bill_params = gnc_search_param_prepend (bill_params,
02880                                                 _("Bill ID"), NULL, type,
02881                                                 INVOICE_ID, NULL);
02882     }
02883     if (emp_params == NULL)
02884     {
02885         emp_params = gnc_search_param_prepend (emp_params,
02886                                                _("Voucher Owner"), NULL, type,
02887                                                INVOICE_OWNER, NULL);
02888         emp_params = gnc_search_param_prepend (emp_params,
02889                                                _("Voucher Notes"), NULL, type,
02890                                                INVOICE_NOTES, NULL);
02891         emp_params = gnc_search_param_prepend (emp_params,
02892                                                _("Billing ID"), NULL, type,
02893                                                INVOICE_BILLINGID, NULL);
02894         emp_params = gnc_search_param_prepend (emp_params,
02895                                                _("Is Paid?"), NULL, type,
02896                                                INVOICE_IS_PAID, NULL);
02897         emp_params = gnc_search_param_prepend (emp_params,
02898                                                _("Date Posted"), NULL, type,
02899                                                INVOICE_POSTED, NULL);
02900         emp_params = gnc_search_param_prepend (emp_params,
02901                                                _("Is Posted?"), NULL, type,
02902                                                INVOICE_IS_POSTED, NULL);
02903         emp_params = gnc_search_param_prepend (emp_params,
02904                                                _("Date Opened"), NULL, type,
02905                                                INVOICE_OPENED, NULL);
02906         emp_params = gnc_search_param_prepend (emp_params,
02907                                                _("Due Date"), NULL, type,
02908                                                INVOICE_DUE, NULL);
02909         emp_params = gnc_search_param_prepend (emp_params,
02910                                                _("Employee Name"), NULL, type,
02911                                                INVOICE_OWNER, OWNER_PARENT,
02912                                                OWNER_NAME, NULL);
02913         emp_params = gnc_search_param_prepend (emp_params,
02914                                                _("Voucher ID"), NULL, type,
02915                                                INVOICE_ID, NULL);
02916     }
02917 
02918     /* Build the column list in reverse order */
02919     if (columns == NULL)
02920     {
02921         columns = gnc_search_param_prepend (columns, _("Billing ID"), NULL, type,
02922                                             INVOICE_BILLINGID, NULL);
02923         columns = gnc_search_param_prepend (columns, _("Type"), NULL, type,
02924                                             INVOICE_TYPE_STRING, NULL);
02925         columns = gnc_search_param_prepend_with_justify (columns, _("Paid"),
02926                   GTK_JUSTIFY_CENTER, NULL, type,
02927                   INVOICE_IS_PAID, NULL);
02928         columns = gnc_search_param_prepend (columns, _("Posted"), NULL, type,
02929                                             INVOICE_POSTED, NULL);
02930         columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,
02931                                             INVOICE_OWNER, OWNER_PARENT,
02932                                             OWNER_NAME, NULL);
02933         columns = gnc_search_param_prepend (columns, _("Due"), NULL, type,
02934                                             INVOICE_DUE, NULL);
02935         columns = gnc_search_param_prepend (columns, _("Opened"), NULL, type,
02936                                             INVOICE_OPENED, NULL);
02937         columns = gnc_search_param_prepend (columns, _("Num"), NULL, type,
02938                                             INVOICE_ID, NULL);
02939     }
02940 
02941     /* Build the queries */
02942     q = qof_query_create_for (type);
02943     qof_query_set_book (q, book);
02944 
02945     /* If owner is supplied, limit all searches to invoices who's owner
02946      * or end-owner is the supplied owner!  Show all invoices by this
02947      * owner.  If a Job is supplied, search for all invoices for that
02948      * job, but if a Customer is supplied, search for all invoices owned
02949      * by that Customer or any of that Customer's Jobs.  In other words,
02950      * match on <supplied-owner's guid> == Invoice->Owner->GncGUID or
02951      * Invoice->owner->parentGUID.
02952      */
02953     if (owner)
02954     {
02955         /* First, figure out the type of owner here.. */
02956         owner_type = gncOwnerGetType (gncOwnerGetEndOwner (owner));
02957 
02958         /* Then if there's an actual owner add it to the query
02959          * and limit the search to this owner
02960          * If there's only a type, limit the search to this type.
02961          */
02962         if (gncOwnerGetGUID (owner))
02963         {
02964             q2 = qof_query_create ();
02965             qof_query_add_guid_match (q2, g_slist_prepend
02966                                       (g_slist_prepend (NULL, QOF_PARAM_GUID),
02967                                        INVOICE_OWNER),
02968                                       gncOwnerGetGUID (owner), QOF_QUERY_OR);
02969 
02970             qof_query_add_guid_match (q2, g_slist_prepend
02971                                       (g_slist_prepend (NULL, OWNER_PARENTG),
02972                                        INVOICE_OWNER),
02973                                       gncOwnerGetGUID (owner), QOF_QUERY_OR);
02974             qof_query_merge_in_place (q, q2, QOF_QUERY_AND);
02975             qof_query_destroy (q2);
02976 
02977             /* Use this base query as pre-fill query.
02978              * This will pre-fill the search dialog with the query results
02979              */
02980             q2 = qof_query_copy (q);
02981 
02982         }
02983         else
02984         {
02985             QofQuery *q3 = qof_query_create ();
02986             QofQueryPredData *inv_type_pred = NULL;
02987             GList *type_list = NULL, *node = NULL;
02988 
02989             type_list = gncInvoiceGetTypeListForOwnerType(owner_type);
02990             for (node = type_list; node; node = node->next)
02991             {
02992                 inv_type_pred = qof_query_int32_predicate(QOF_COMPARE_EQUAL,
02993                                 GPOINTER_TO_INT(node->data));
02994                 qof_query_add_term (q3, g_slist_prepend (NULL, INVOICE_TYPE), inv_type_pred, QOF_QUERY_OR);
02995             }
02996             qof_query_merge_in_place (q, q3, QOF_QUERY_AND);
02997             qof_query_destroy (q3);
02998 
02999             /* Don't set a pre-fill query in this case, the result set would be too long */
03000             q2 = NULL;
03001         }
03002     }
03003 
03004     /* Launch select dialog and return the result */
03005     sw = g_new0 (struct _invoice_select_window, 1);
03006 
03007     if (owner)
03008     {
03009         gncOwnerCopy (owner, &(sw->owner_def));
03010         sw->owner = &(sw->owner_def);
03011     }
03012     sw->book = book;
03013     sw->q = q;
03014 
03015     switch (owner_type)
03016     {
03017     case GNC_OWNER_VENDOR:
03018         title = _("Find Bill");
03019         label = _("Bill");
03020         params = bill_params;
03021         buttons = bill_buttons;
03022         break;
03023     case GNC_OWNER_EMPLOYEE:
03024         title = _("Find Expense Voucher");
03025         label = _("Expense Voucher");
03026         params = emp_params;
03027         buttons = emp_buttons;
03028         break;
03029     default:
03030         title = _("Find Invoice");
03031         label = _("Invoice");
03032         params = inv_params;
03033         buttons = inv_buttons;
03034         break;
03035     }
03036     return gnc_search_dialog_create (type, title, params, columns, q, q2,
03037                                      buttons, NULL, new_invoice_cb,
03038                                      sw, free_invoice_cb, GCONF_SECTION_SEARCH,
03039                                      label);
03040 }
03041 
03042 DialogQueryList *
03043 gnc_invoice_show_bills_due (QofBook *book, double days_in_advance)
03044 {
03045     QofIdType type = GNC_INVOICE_MODULE_NAME;
03046     Query *q;
03047     QofQueryPredData* pred_data;
03048     time_t end_date;
03049     GList *res;
03050     gchar *message;
03051     DialogQueryList *dialog;
03052     gint len;
03053     Timespec ts;
03054     static GList *param_list = NULL;
03055     static GNCDisplayListButton buttons[] =
03056     {
03057         { N_("View/Edit Bill"), edit_invoice_direct },
03058         { N_("Process Payment"), pay_invoice_direct },
03059         { NULL },
03060     };
03061 
03062     /* Create the param list (in reverse order) */
03063     if (param_list == NULL)
03064     {
03065         param_list = gnc_search_param_prepend (param_list, _("Amount"), NULL, type,
03066                                                INVOICE_POST_LOT, LOT_BALANCE, NULL);
03067         param_list = gnc_search_param_prepend (param_list, _("Company"), NULL, type,
03068                                                INVOICE_OWNER, OWNER_NAME, NULL);
03069         param_list = gnc_search_param_prepend (param_list, _("Due"), NULL, type,
03070                                                INVOICE_DUE, NULL);
03071     }
03072 
03073     /* Create the query to search for invoices; set the book */
03074     q = qof_query_create();
03075     qof_query_search_for(q, GNC_INVOICE_MODULE_NAME);
03076     qof_query_set_book (q, book);
03077 
03078     /* We want to find all invoices where:
03079      *      invoice -> is_posted == TRUE
03080      * AND  invoice -> lot -> is_closed? == FALSE
03081      * AND  invoice -> type != customer invoice
03082      * AND  invoice -> type != customer credit note
03083      * AND  invoice -> due >= (today - days_in_advance)
03084      */
03085 
03086     qof_query_add_boolean_match (q, g_slist_prepend(NULL, INVOICE_IS_POSTED), TRUE,
03087                                  QOF_QUERY_AND);
03088 
03089     qof_query_add_boolean_match (q, g_slist_prepend(g_slist_prepend(NULL, LOT_IS_CLOSED),
03090                                  INVOICE_POST_LOT), FALSE, QOF_QUERY_AND);
03091 
03092     pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_CUST_INVOICE);
03093     qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
03094 
03095     pred_data = qof_query_int32_predicate (QOF_COMPARE_NEQ, GNC_INVOICE_CUST_CREDIT_NOTE);
03096     qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_TYPE), pred_data, QOF_QUERY_AND);
03097 
03098     end_date = time(NULL);
03099     if (days_in_advance < 0)
03100         days_in_advance = 0;
03101     end_date += days_in_advance * 60 * 60 * 24;
03102 
03103     ts.tv_sec = (gint64) end_date;
03104     ts.tv_nsec = 0;
03105     pred_data = qof_query_date_predicate (QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, ts);
03106     qof_query_add_term (q, g_slist_prepend(NULL, INVOICE_DUE), pred_data, QOF_QUERY_AND);
03107 
03108     res = qof_query_run(q);
03109     len = g_list_length (res);
03110     if (!res || len <= 0)
03111     {
03112         qof_query_destroy(q);
03113         return NULL;
03114     }
03115 
03116     message = g_strdup_printf
03117               (/* Translators: %d is the number of bills due. This is a
03118                      ngettext(3) message. */
03119                   ngettext("The following %d bill is due:",
03120                            "The following %d bills are due:",
03121                            len),
03122                   len);
03123     dialog = gnc_dialog_query_list_create(param_list, q,
03124                                           _("Due Bills Reminder"),
03125                                           message,
03126                                           TRUE, FALSE,
03127                                           buttons, NULL);
03128     g_free(message);
03129     qof_query_destroy(q);
03130     return dialog;
03131 
03132 }
03133 
03134 void
03135 gnc_invoice_remind_bills_due (void)
03136 {
03137     QofBook *book;
03138     gint days;
03139 
03140     if (!gnc_current_session_exist()) return;
03141     book = qof_session_get_book(gnc_get_current_session());
03142     days = gnc_gconf_get_float(GCONF_SECTION_BILL, "days_in_advance", NULL);
03143 
03144     gnc_invoice_show_bills_due(book, days);
03145 }
03146 
03147 void
03148 gnc_invoice_remind_bills_due_cb (void)
03149 {
03150     if (!gnc_gconf_get_bool(GCONF_SECTION_BILL, "notify_when_due", NULL))
03151         return;
03152 
03153     gnc_invoice_remind_bills_due();
03154 }
03155 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines