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 <gnome.h>
00029 #include <glib/gi18n.h>
00030 #include <libguile.h>
00031 #include "swig-runtime.h"
00032 
00033 #include "gncObject.h"
00034 #include "QueryCore.h"
00035 #include "QueryNew.h"
00036 
00037 #include "dialog-utils.h"
00038 #include "gnc-component-manager.h"
00039 #include "gnc-ui.h"
00040 #include "gnc-gconf-utils.h"
00041 #include "gnc-gui-query.h"
00042 #include "gnc-ui-util.h"
00043 #include "qof.h"
00044 #include "gnc-date-edit.h"
00045 #include "gnc-amount-edit.h"
00046 #include "gnucash-sheet.h"
00047 #include "window-report.h"
00048 #include "dialog-search.h"
00049 #include "search-param.h"
00050 #include "gnc-session.h"
00051 #include "gncInvoice.h"
00052 #include "gncInvoiceP.h"
00053 
00054 #include "gncEntryLedger.h"
00055 
00056 #include "gnc-plugin-page.h"
00057 #include "gnc-general-search.h"
00058 #include "dialog-date-close.h"
00059 #include "dialog-invoice.h"
00060 #include "dialog-job.h"
00061 #include "business-gnome-utils.h"
00062 #include "dialog-payment.h"
00063 #include "dialog-tax-table.h"
00064 #include "dialog-billterms.h"
00065 #include "dialog-account.h"
00066 #include "guile-mappings.h"
00067 
00068 #include "dialog-query-list.h"
00069 
00070 #include "gnc-plugin-business.h"
00071 #include "gnc-plugin-page-invoice.h"
00072 #include "gnc-main-window.h"
00073 
00074 /* Disable -Waddress.  GCC 4.2 warns (and fails to compile with -Werror) when
00075  * passing the address of a guid on the stack to QOF_BOOK_LOOKUP_ENTITY via
00076  * gncInvoiceLookup and friends.  When the macro gets inlined, the compiler
00077  * emits a warning that the guid null pointer test is always true.
00078  */
00079 #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 2)
00080 #    pragma GCC diagnostic ignored "-Waddress"
00081 #endif
00082 
00083 #define DIALOG_NEW_INVOICE_CM_CLASS "dialog-new-invoice"
00084 #define DIALOG_VIEW_INVOICE_CM_CLASS "dialog-view-invoice"
00085 
00086 #define GCONF_SECTION_SEARCH  "dialogs/business/invoice_search"
00087 
00088 #define LAST_POSTED_TO_ACCT "last-posted-to-acct"
00089 
00090 void gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data);
00091 void gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data);
00092 void gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data);
00093 void gnc_invoice_id_changed_cb (GtkWidget *widget, gpointer data);
00094 
00095 #define ENUM_INVOICE_TYPE(_) \
00096   _(NEW_INVOICE, )  \
00097   _(MOD_INVOICE, )  \
00098   _(EDIT_INVOICE, ) \
00099   _(VIEW_INVOICE, )
00100 
00101 DEFINE_ENUM(InvoiceDialogType, ENUM_INVOICE_TYPE)
00102 AS_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00103 FROM_STRING_DEC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00104 
00105 FROM_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00106 AS_STRING_FUNC(InvoiceDialogType, ENUM_INVOICE_TYPE)
00107 
00108 struct _invoice_select_window {
00109   GNCBook *     book;
00110   GncOwner *    owner;
00111   QueryNew *    q;
00112   GncOwner      owner_def;
00113 };
00114 
00115 
00121 struct _invoice_window {
00122   GladeXML *    xml;
00123 
00124   GtkWidget *   dialog;         /* Used by 'New Invoice Window' */
00125   GncPluginPage *page;          /* Used by 'Edit Invoice' Page */
00126 
00127   /* Summary Bar Widgets */
00128   GtkWidget *   total_label;
00129   GtkWidget *   total_cash_label;
00130   GtkWidget *   total_charge_label;
00131   GtkWidget *   total_subtotal_label;
00132   GtkWidget *   total_tax_label;
00133 
00134   /* Data Widgets */
00135   GtkWidget *   id_entry;
00136   GtkWidget *   notes_text;
00137   GtkWidget *   opened_date;
00138   GtkWidget *   posted_date_hbox;
00139   GtkWidget *   posted_date;
00140   GtkWidget *   active_check;
00141 
00142   GtkWidget *   owner_box;
00143   GtkWidget *   owner_label;
00144   GtkWidget *   owner_choice;
00145   GtkWidget *   job_label;
00146   GtkWidget *   job_box;
00147   GtkWidget *   job_choice;
00148   GtkWidget *   billing_id_entry;
00149   GtkWidget *   terms_menu;
00150 
00151   /* Project Widgets (used for Bills only) */
00152   GtkWidget *   proj_frame;
00153   GtkWidget *   proj_cust_box;
00154   GtkWidget *   proj_cust_choice;
00155   GtkWidget *   proj_job_box;
00156   GtkWidget *   proj_job_choice;
00157 
00158   /* Exp Voucher Widgets */
00159   GtkWidget *   to_charge_frame;
00160   GtkWidget *   to_charge_edit;
00161 
00162   gint          width;
00163 
00164   GncBillTerm * terms;
00165   GnucashRegister *     reg;
00166   GncEntryLedger *      ledger;
00167 
00168   invoice_sort_type_t   last_sort;
00169 
00170   InvoiceDialogType     dialog_type;
00171   GUID          invoice_guid;
00172   gint          component_id;
00173   GNCBook *     book;
00174   GncInvoice *  created_invoice;
00175   GncOwner      owner;
00176   GncOwner      job;
00177 
00178   GncOwner      proj_cust;
00179   GncOwner      proj_job;
00180 
00181   /* for Unposting */
00182   gboolean      reset_tax_tables;
00183 };
00184 
00185 /* Forward definitions for CB functions */
00186 void gnc_invoice_window_closeCB (GtkWidget *widget, gpointer data);
00187 void gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data);
00188 gboolean gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data);
00189 
00190 #define INV_WIDTH_PREFIX "invoice_reg"
00191 #define BILL_WIDTH_PREFIX "bill_reg"
00192 #define VOUCHER_WIDTH_PREFIX "voucher_reg"
00193 
00194 static void gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget);
00195 static InvoiceWindow * gnc_ui_invoice_modify (GncInvoice *invoice);
00196 
00197 /*******************************************************************************/
00198 /* FUNCTIONS FOR ACCESSING DATA STRUCTURE FIELDS */
00199 
00200 static GtkWidget *
00201 iw_get_window (InvoiceWindow *iw)
00202 {
00203   if (iw->page)
00204     return gnc_plugin_page_get_window(iw->page);
00205   return iw->dialog;
00206 }
00207 
00208 GtkWidget *
00209 gnc_invoice_get_register(InvoiceWindow *iw)
00210 {
00211   if (iw)
00212     return (GtkWidget *)iw->reg;
00213   return NULL;
00214 }
00215 
00216 /*******************************************************************************/
00217 /* FUNCTIONS FOR UNPOSTING */
00218 
00219 static gboolean
00220 iw_ask_unpost (InvoiceWindow *iw)
00221 {
00222   GtkWidget *dialog, *toggle, *pixmap;
00223   GladeXML *xml;
00224   gint response;
00225   char *s;
00226 
00227   xml = gnc_glade_xml_new ("invoice.glade", "Unpost Message Dialog");
00228   dialog = glade_xml_get_widget (xml, "Unpost Message Dialog");
00229   toggle = glade_xml_get_widget (xml, "yes_tt_reset");
00230   pixmap = glade_xml_get_widget (xml, "q_pixmap");
00231 
00232   gtk_window_set_transient_for (GTK_WINDOW(dialog),
00233                                 GTK_WINDOW(iw_get_window(iw)));
00234 
00235   iw->reset_tax_tables = FALSE;
00236 
00237   s = gnome_program_locate_file (NULL,
00238                                  GNOME_FILE_DOMAIN_PIXMAP,
00239                                  "gnome-question.png", TRUE, NULL);
00240   if (s) {
00241     pixmap = gtk_image_new_from_file(s);
00242     g_free(s);
00243   }
00244 
00245   gtk_widget_show_all(dialog);
00246 
00247   response = gtk_dialog_run(GTK_DIALOG(dialog));
00248   if (response == GTK_RESPONSE_OK)
00249     iw->reset_tax_tables =
00250       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
00251 
00252   gtk_widget_destroy(dialog);
00253   return (response == GTK_RESPONSE_OK);
00254 }
00255 
00256 /*******************************************************************************/
00257 /* INVOICE WINDOW */
00258 
00259 static GncInvoice *
00260 iw_get_invoice (InvoiceWindow *iw)
00261 {
00262   if (!iw)
00263     return NULL;
00264 
00265   return gncInvoiceLookup (iw->book, &iw->invoice_guid);
00266 }
00267 
00268 static void gnc_ui_to_invoice (InvoiceWindow *iw, GncInvoice *invoice)
00269 {
00270   GtkTextBuffer* text_buffer;
00271   GtkTextIter start, end;
00272   gchar *text;
00273   Timespec ts;
00274 
00275   if (iw->dialog_type == VIEW_INVOICE)
00276     return;
00277 
00278   gnc_suspend_gui_refresh ();
00279 
00280   gncInvoiceBeginEdit (invoice);
00281 
00282   if (iw->active_check)
00283     gncInvoiceSetActive (invoice, gtk_toggle_button_get_active
00284                          (GTK_TOGGLE_BUTTON (iw->active_check)));
00285 
00286   text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
00287   gtk_text_buffer_get_bounds (text_buffer, &start, &end);
00288   text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
00289   gncInvoiceSetNotes (invoice, text);
00290 
00291   if (iw->to_charge_edit)
00292     gncInvoiceSetToChargeAmount (invoice,
00293                                  gnc_amount_edit_get_amount
00294                                  (GNC_AMOUNT_EDIT (iw->to_charge_edit)));
00295 
00296   /* Only set these values for NEW/MOD INVOICE types */
00297   if (iw->dialog_type != EDIT_INVOICE) {
00298     gncInvoiceSetID (invoice, gtk_editable_get_chars
00299                      (GTK_EDITABLE (iw->id_entry), 0, -1));
00300     gncInvoiceSetBillingID (invoice, gtk_editable_get_chars
00301                             (GTK_EDITABLE (iw->billing_id_entry), 0, -1));
00302     gncInvoiceSetTerms (invoice, iw->terms);
00303 
00304     ts = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (iw->opened_date));
00305     gncInvoiceSetDateOpened (invoice, ts);
00306 
00307     gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
00308     if (iw->job_choice)
00309       gnc_owner_get_owner (iw->job_choice, &(iw->job));
00310 
00311     /* Only set the job if we've actually got one */
00312     if (gncOwnerGetJob (&(iw->job)))
00313       gncInvoiceSetOwner (invoice, &(iw->job));
00314     else
00315       gncInvoiceSetOwner (invoice, &(iw->owner));
00316 
00317     /* Set the invoice currency based on the owner */
00318     gncInvoiceSetCurrency (invoice, gncOwnerGetCurrency (&iw->owner));
00319 
00320     /* Only set the BillTo if we've actually got one */
00321     if (gncOwnerGetJob (&iw->proj_job))
00322       gncInvoiceSetBillTo (invoice, &iw->proj_job);
00323     else
00324       gncInvoiceSetBillTo (invoice, &iw->proj_cust);
00325   }
00326 
00327   gncInvoiceCommitEdit (invoice);
00328   gnc_resume_gui_refresh ();
00329 }
00330 
00331 static gboolean
00332 gnc_invoice_window_verify_ok (InvoiceWindow *iw)
00333 {
00334   const char *res;
00335   gchar *string;
00336 
00337   /* save the current entry in the ledger? */
00338   if (!gnc_entry_ledger_check_close (iw_get_window(iw), iw->ledger))
00339     return FALSE;
00340 
00341   /* Check the Owner */
00342   gnc_owner_get_owner (iw->owner_choice, &(iw->owner));
00343   res = gncOwnerGetName (&(iw->owner));
00344   if (res == NULL || safe_strcmp (res, "") == 0) {
00345     gnc_error_dialog (iw_get_window(iw),
00346                       /* Translators: In this context,
00347                        * 'Billing information' maps to the
00348                        * label in the frame and means
00349                        * e.g. customer i.e. the company being
00350                        * invoiced. */
00351                       _("You need to supply Billing Information."));
00352     return FALSE;
00353   }
00354 
00355   /* Check the ID; set one if necessary */
00356   res = gtk_entry_get_text (GTK_ENTRY (iw->id_entry));
00357   if (safe_strcmp (res, "") == 0) {
00358     /* Invoices and bills have separate counters.
00359        Therefore we pass the GncOwer to gncInvoiceNextID
00360        so it knows whether we are creating a bill
00361        or an invoice. */
00362     string = g_strdup_printf ("%.6" G_GINT64_FORMAT,
00363                               gncInvoiceNextID(iw->book, &(iw->owner)));
00364     gtk_entry_set_text (GTK_ENTRY (iw->id_entry), string);
00365     g_free(string);
00366   }
00367       
00368   return TRUE;
00369 }
00370 
00371 static gboolean
00372 gnc_invoice_window_ok_save (InvoiceWindow *iw)
00373 {
00374   if (!gnc_invoice_window_verify_ok (iw))
00375     return FALSE;
00376 
00377   {
00378     GncInvoice *invoice = iw_get_invoice (iw);
00379     if (invoice) {
00380       gnc_ui_to_invoice (iw, invoice);
00381     }
00382     /* Save the invoice to return it later. */
00383     iw->created_invoice = invoice;
00384   }
00385   return TRUE;
00386 }
00387 
00388 void
00389 gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data)
00390 {
00391   InvoiceWindow *iw = data;
00392 
00393   if (!gnc_invoice_window_ok_save (iw))
00394     return;
00395 
00396   /* Ok, we don't need this anymore */
00397   iw->invoice_guid = *xaccGUIDNULL ();
00398 
00399   /* if this is a NEW_INVOICE, and created_invoice is NON-NULL, the
00400    * open up a new window with the invoice.  This used to be done
00401    * in gnc_ui_invoice_new() but cannot be done anymore
00402    */
00403   if (iw->dialog_type == NEW_INVOICE && iw->created_invoice)
00404     gnc_ui_invoice_edit (iw->created_invoice);
00405 
00406   gnc_close_gui_component (iw->component_id);
00407 }
00408 
00409 void
00410 gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data)
00411 {
00412   InvoiceWindow *iw = data;
00413 
00414   gnc_close_gui_component (iw->component_id);
00415 }
00416 
00417 void
00418 gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data)
00419 {
00420   gnc_gnome_help(HF_HELP, HL_USAGE);
00421 }
00422 
00423 void
00424 gnc_invoice_window_destroy_cb (GtkWidget *widget, gpointer data)
00425 {
00426   InvoiceWindow *iw = data;
00427   GncInvoice *invoice = iw_get_invoice (iw);
00428 
00429   gnc_suspend_gui_refresh ();
00430 
00431   if (iw->dialog_type == NEW_INVOICE && invoice != NULL) {
00432     gncInvoiceBeginEdit (invoice);
00433     gncInvoiceDestroy (invoice);
00434     iw->invoice_guid = *xaccGUIDNULL ();
00435   }
00436 
00437   gnc_entry_ledger_destroy (iw->ledger);
00438   gnc_unregister_gui_component (iw->component_id);
00439   gtk_widget_destroy(widget);
00440   gnc_resume_gui_refresh ();
00441 
00442   g_free (iw);
00443 }
00444 
00445 void
00446 gnc_invoice_window_closeCB (GtkWidget *widget, gpointer data)
00447 {
00448   gnc_invoice_window_ok_cb (widget, data);
00449 }
00450 
00451 void
00452 gnc_invoice_window_editCB (GtkWidget *widget, gpointer data)
00453 {
00454   InvoiceWindow *iw = data;
00455   GncInvoice *invoice = iw_get_invoice (iw);
00456 
00457   if (invoice)
00458     gnc_ui_invoice_modify (invoice);
00459 }
00460 
00461 void
00462 gnc_invoice_window_recordCB (GtkWidget *widget, gpointer data)
00463 {
00464   InvoiceWindow *iw = data;
00465 
00466   if (!iw || !iw->ledger)
00467     return;
00468 
00469   if (!gnc_entry_ledger_commit_entry (iw->ledger))
00470     return;
00471 
00472   gnucash_register_goto_next_virt_row (iw->reg);
00473 }
00474 
00475 void
00476 gnc_invoice_window_cancelCB (GtkWidget *widget, gpointer data)
00477 {
00478   InvoiceWindow *iw = data;
00479 
00480   if (!iw || !iw->ledger)
00481     return;
00482 
00483   gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00484 }
00485 
00486 void
00487 gnc_invoice_window_deleteCB (GtkWidget *widget, gpointer data)
00488 {
00489   InvoiceWindow *iw = data;
00490   GncEntry *entry;
00491 
00492   if (!iw || !iw->ledger)
00493     return;
00494 
00495   /* get the current entry based on cursor position */
00496   entry = gnc_entry_ledger_get_current_entry (iw->ledger);
00497   if (!entry) {
00498     gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00499     return;
00500   }
00501 
00502   /* deleting the blank entry just cancels */
00503   if (entry == gnc_entry_ledger_get_blank_entry (iw->ledger)) {
00504     gnc_entry_ledger_cancel_cursor_changes (iw->ledger);
00505     return;
00506   }
00507 
00508   /* Verify that the user really wants to delete this entry */
00509   {
00510     const char *message = _("Are you sure you want to delete the "
00511                             "selected entry?");
00512     const char *order_warn = _("This entry is attached to an order and "
00513                                "will be deleted from that as well!");
00514     char *msg;
00515     gboolean result;
00516 
00517     if (gncEntryGetOrder (entry))
00518       msg = g_strconcat (message, "\n\n", order_warn, (char *)NULL);
00519     else
00520       msg = g_strdup (message);
00521 
00522     result = gnc_verify_dialog (iw_get_window(iw), FALSE, msg);
00523     g_free (msg);
00524 
00525     if (!result)
00526       return;
00527   }
00528 
00529   /* Yep, let's delete */
00530   gnc_entry_ledger_delete_current_entry (iw->ledger);
00531   return;
00532 }
00533 
00534 void
00535 gnc_invoice_window_duplicateCB (GtkWidget *widget, gpointer data)
00536 {
00537   InvoiceWindow *iw = data;
00538 
00539   if (!iw || !iw->ledger)
00540     return;
00541 
00542   gnc_entry_ledger_duplicate_current_entry (iw->ledger);
00543 }
00544 
00545 void
00546 gnc_invoice_window_blankCB (GtkWidget *widget, gpointer data)
00547 {
00548   InvoiceWindow *iw = data;
00549 
00550   if (!iw || !iw->ledger)
00551     return;
00552 
00553   if (!gnc_entry_ledger_commit_entry (iw->ledger))
00554     return;
00555 
00556   {
00557     VirtualCellLocation vcell_loc;
00558     GncEntry *blank;
00559 
00560     blank = gnc_entry_ledger_get_blank_entry (iw->ledger);
00561     if (blank == NULL)
00562       return;
00563 
00564     if (gnc_entry_ledger_get_entry_virt_loc (iw->ledger, blank, &vcell_loc))
00565       gnucash_register_goto_virt_cell (iw->reg, vcell_loc);
00566   }
00567 }
00568 
00569 void
00570 gnc_invoice_window_printCB (GtkWidget *widget, gpointer data)
00571 {
00572   InvoiceWindow *iw = data;
00573   GncInvoice *invoice = iw_get_invoice (iw);
00574   SCM func, arg;
00575   SCM args = SCM_EOL;
00576   int report_id;
00577 
00578   g_return_if_fail (invoice);
00579 
00580   func = scm_c_eval_string ("gnc:invoice-report-create");
00581   g_return_if_fail (SCM_PROCEDUREP (func));
00582 
00583   arg = SWIG_NewPointerObj(invoice, SWIG_TypeQuery("_p__gncInvoice"), 0);
00584   args = scm_cons (arg, args);
00585 
00586   /* scm_gc_protect_object(func); */
00587 
00588   arg = scm_apply (func, args, SCM_EOL);
00589   g_return_if_fail (SCM_EXACTP (arg));
00590   report_id = scm_num2int (arg, SCM_ARG1, __FUNCTION__);
00591 
00592   /* scm_gc_unprotect_object(func); */
00593   if (report_id >= 0)
00594     reportWindow (report_id);
00595 }
00596 
00597 void
00598 gnc_invoice_window_postCB (GtkWidget *widget, gpointer data)
00599 {
00600   InvoiceWindow *iw = data;
00601   GncInvoice *invoice;
00602   char *message, *memo, *ddue_label, *post_label, *acct_label, *question_label;
00603   Account *acc = NULL;
00604   GList * acct_types = NULL;
00605   Timespec ddue, postdate;
00606   gboolean accumulate;
00607   QofInstance *owner_inst;
00608   KvpFrame *kvpf;
00609   KvpValue *kvp_val;
00610 
00611   /* Make sure the invoice is ok */
00612   if (!gnc_invoice_window_verify_ok (iw))
00613       return;
00614 
00615   invoice = iw_get_invoice (iw);
00616   if (!invoice)
00617     return;
00618 
00619   /* Check that there is at least one Entry */
00620   invoice = iw_get_invoice (iw);
00621   if (gncInvoiceGetEntries (invoice) == NULL) {
00622     gnc_error_dialog (iw_get_window(iw),
00623                       _("The Invoice must have at least one Entry."));
00624     return;
00625   }
00626 
00627   /* Make sure that the invoice has a positive balance */
00628   if (gnc_numeric_negative_p(gncInvoiceGetTotal(invoice))) {
00629     gnc_error_dialog(iw_get_window(iw),
00630                      _("You may not post an invoice with a negative total value."));
00631     return;
00632   }
00633 
00634   if (iw->total_cash_label &&
00635       gnc_numeric_negative_p(gncInvoiceGetTotalOf(invoice, GNC_PAYMENT_CASH))) {
00636     gnc_error_dialog(iw_get_window(iw),
00637                      _("You may not post an expense voucher with a negative total cash value."));
00638     return;
00639   }
00640 
00641   /* Ok, we can post this invoice.  Ask for verification, set the due date,
00642    * post date, and posted account
00643    */
00644   message = _("Do you really want to post the invoice?");
00645   ddue_label = _("Due Date");
00646   post_label = _("Post Date");
00647   acct_label = _("Post to Account");
00648   question_label = _("Accumulate Splits?");
00649 
00650   /* Determine the type of account to post to */
00651   acct_types = gnc_business_account_types (&(iw->owner));
00652 
00653   /* Get the due date and posted account */
00654   timespecFromTime_t (&postdate, time(NULL));
00655   ddue = postdate;
00656   memo = NULL;
00657 
00658   owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
00659   kvpf = qof_instance_get_slots (owner_inst);
00660   acc = xaccAccountLookup (kvp_frame_get_guid (kvpf, LAST_POSTED_TO_ACCT),
00661                            iw->book);
00662 
00663   /* Get the default for the accumulate option */
00664   accumulate = gnc_gconf_get_bool(GCONF_SECTION_INVOICE, "accumulate_splits", NULL);
00665 
00666   if (!gnc_dialog_dates_acct_question_parented (iw_get_window(iw), message, ddue_label,
00667                                        post_label, acct_label, question_label, TRUE,
00668                                        acct_types, iw->book, iw->terms,
00669                                        &ddue, &postdate, &memo, &acc, &accumulate))
00670     return;
00671 
00672   /* Yep, we're posting.  So, save the invoice... 
00673    * Note that we can safely ignore the return value; we checked
00674    * the verify_ok earlier, so we know it's ok.
00675    */
00676   gnc_suspend_gui_refresh ();
00677   gncInvoiceBeginEdit (invoice);
00678   gnc_invoice_window_ok_save (iw);
00679 
00680   /* Save acc as last used account in the kvp frame of the invoice owner */
00681   kvp_val = kvp_value_new_guid (qof_instance_get_guid (QOF_INSTANCE (acc)));;
00682   qof_begin_edit (owner_inst);
00683   kvp_frame_set_slot_nc (kvpf, LAST_POSTED_TO_ACCT, kvp_val);
00684   qof_instance_set_dirty (owner_inst);
00685   qof_commit_edit (owner_inst);
00686   
00687   /* ... post it; post date is set to now ... */
00688   gncInvoicePostToAccount (invoice, acc, &postdate, &ddue, memo, accumulate);
00689   gncInvoiceCommitEdit (invoice);
00690   gnc_resume_gui_refresh ();
00691 
00692   if (memo)
00693     g_free (memo);
00694 
00695   /* Reset the type; change to read-only! */
00696   iw->dialog_type = VIEW_INVOICE;
00697   gnc_entry_ledger_set_readonly (iw->ledger, TRUE);
00698 
00699   /* ... and redisplay here. */
00700   gnc_invoice_update_window (iw, NULL);
00701   gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
00702 }
00703 
00704 void
00705 gnc_invoice_window_unpostCB (GtkWidget *widget, gpointer data)
00706 {
00707   InvoiceWindow *iw = data;
00708   GncInvoice *invoice;
00709   gboolean result;
00710 
00711   invoice = iw_get_invoice (iw);
00712   if (!invoice)
00713     return;
00714 
00715   /* make sure the user REALLY wants to do this! */
00716   result = iw_ask_unpost(iw);
00717   if (!result) return;
00718 
00719   /* Attempt to unpost the invoice */
00720   gnc_suspend_gui_refresh ();
00721   result = gncInvoiceUnpost (invoice, iw->reset_tax_tables);
00722   gnc_resume_gui_refresh ();
00723   if (!result) return;
00724 
00725   /* if we get here, we succeeded in unposting -- reset the ledger and redisplay */
00726   iw->dialog_type = EDIT_INVOICE;
00727   gnc_entry_ledger_set_readonly (iw->ledger, FALSE);
00728   gnc_invoice_update_window (iw, NULL);
00729   gnc_table_refresh_gui (gnc_entry_ledger_get_table (iw->ledger), FALSE);
00730 }
00731 
00732 void gnc_invoice_window_cut_cb (GtkWidget *widget, gpointer data)
00733 {
00734   InvoiceWindow *iw = data;
00735   gnucash_register_cut_clipboard (iw->reg);
00736 }
00737 
00738 void gnc_invoice_window_copy_cb (GtkWidget *widget, gpointer data)
00739 {
00740   InvoiceWindow *iw = data;
00741   gnucash_register_copy_clipboard (iw->reg);
00742 }
00743 
00744 void gnc_invoice_window_paste_cb (GtkWidget *widget, gpointer data)
00745 {
00746   InvoiceWindow *iw = data;
00747   gnucash_register_paste_clipboard (iw->reg);
00748 }
00749 
00750 void gnc_invoice_window_new_invoice_cb (GtkWidget *widget, gpointer data)
00751 {
00752   InvoiceWindow *iw = data;
00753   if (gncOwnerGetJob (&iw->job)) {
00754     gnc_ui_invoice_new (&iw->job, iw->book);
00755   } else {
00756     gnc_ui_invoice_new (&iw->owner, iw->book);
00757   }
00758 }
00759 
00760 void gnc_business_call_owner_report (GncOwner *owner, Account *acc)
00761 {
00762   int id;
00763   SCM args;
00764   SCM func;
00765   SCM arg;
00766 
00767   g_return_if_fail (owner);
00768 
00769   args = SCM_EOL;
00770 
00771   func = scm_c_eval_string ("gnc:owner-report-create");
00772   g_return_if_fail (SCM_PROCEDUREP (func));
00773 
00774   if (acc) {
00775     swig_type_info * qtype = SWIG_TypeQuery("_p_Account");
00776     g_return_if_fail (qtype);
00777 
00778     arg = SWIG_NewPointerObj(acc, qtype, 0);
00779     g_return_if_fail (arg != SCM_UNDEFINED);
00780     args = scm_cons (arg, args);
00781   } else {
00782     args = scm_cons (SCM_BOOL_F, args);
00783   }
00784 
00785   arg = SWIG_NewPointerObj(owner, SWIG_TypeQuery("_p__gncOwner"), 0);
00786   g_return_if_fail (arg != SCM_UNDEFINED);
00787   args = scm_cons (arg, args);
00788 
00789   /* Apply the function to the args */
00790   arg = scm_apply (func, args, SCM_EOL);
00791   g_return_if_fail (SCM_EXACTP (arg));
00792   id = scm_num2int (arg, SCM_ARG1, __FUNCTION__);
00793 
00794   if (id >= 0)
00795     reportWindow (id);
00796 }
00797 
00798 void gnc_invoice_window_report_owner_cb (GtkWidget *widget, gpointer data)
00799 {
00800   InvoiceWindow *iw = data;
00801   gnc_business_call_owner_report (&iw->owner, NULL);
00802 }
00803 
00804 void gnc_invoice_window_payment_cb (GtkWidget *widget, gpointer data)
00805 {
00806   InvoiceWindow *iw = data;
00807   GncInvoice *invoice = iw_get_invoice(iw);
00808 
00809   if (gncOwnerGetJob (&iw->job))
00810     gnc_ui_payment_new_with_invoice (&iw->job, iw->book, invoice);
00811   else
00812     gnc_ui_payment_new_with_invoice (&iw->owner, iw->book, invoice);
00813 }
00814 
00815 /* Sorting callbacks */
00816 
00817 void
00818 gnc_invoice_window_sort (InvoiceWindow *iw, invoice_sort_type_t sort_code)
00819 {
00820   QueryNew *query = gnc_entry_ledger_get_query (iw->ledger);
00821   GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
00822 
00823   if (iw->last_sort == sort_code)
00824     return;
00825 
00826   standard = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
00827 
00828   switch (sort_code)
00829   {
00830     case BY_STANDARD:
00831       p1 = standard;
00832       break;
00833     case BY_DATE:
00834       p1 = g_slist_prepend (p1, ENTRY_DATE);
00835       p2 = standard;
00836       break;
00837     case BY_DATE_ENTERED:
00838       p1 = g_slist_prepend (p1, ENTRY_DATE_ENTERED);
00839       p2 = standard;
00840       break;
00841     case BY_DESC:
00842       p1 = g_slist_prepend (p1, ENTRY_DESC);
00843       p2 = standard;
00844       break;
00845     case BY_QTY:
00846       p1 = g_slist_prepend (p1, ENTRY_QTY);
00847       p2 = standard;
00848       break;
00849     case BY_PRICE:
00850       p1 = g_slist_prepend (p1, ((iw->owner.type == GNC_OWNER_CUSTOMER) ?
00851                                  ENTRY_IPRICE : ENTRY_BPRICE));
00852       p2 = standard;
00853       break;
00854     default:
00855       g_slist_free (standard);
00856       g_return_if_fail (FALSE);
00857   }
00858 
00859   gncQuerySetSortOrder (query, p1, p2, p3);
00860   iw->last_sort = sort_code;
00861   gnc_entry_ledger_display_refresh (iw->ledger);
00862 }
00863 
00864 /* Window configuration callbacks */
00865 
00866 void
00867 gnc_invoice_window_active_toggled_cb (GtkWidget *widget, gpointer data)
00868 {
00869   InvoiceWindow *iw = data;
00870   GncInvoice *invoice = iw_get_invoice(iw);
00871 
00872   if (!invoice) return;
00873 
00874   gncInvoiceSetActive (invoice,
00875                        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
00876 }
00877 
00878 gboolean
00879 gnc_invoice_window_leave_notes_cb (GtkWidget *widget, GdkEventFocus *event,
00880                                    gpointer data)
00881 {
00882   InvoiceWindow *iw = data;
00883   GncInvoice *invoice = iw_get_invoice(iw);
00884   GtkTextBuffer* text_buffer;
00885   GtkTextIter start, end;
00886   gchar *text;
00887 
00888   if (!invoice) return FALSE;
00889 
00890   text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(iw->notes_text));
00891   gtk_text_buffer_get_bounds (text_buffer, &start, &end);
00892   text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
00893   gncInvoiceSetNotes (invoice, text);
00894   return FALSE;
00895 }
00896 
00897 static gboolean
00898 gnc_invoice_window_leave_to_charge_cb (GtkWidget *widget, GdkEventFocus *event,
00899                                        gpointer data)
00900 {
00901   gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (widget));
00902   return FALSE;
00903 }
00904 
00905 static void
00906 gnc_invoice_window_changed_to_charge_cb (GtkWidget *widget, gpointer data)
00907 {
00908   InvoiceWindow *iw = data;
00909   GncInvoice *invoice = iw_get_invoice(iw);
00910 
00911   if (!invoice) return;
00912 
00913   gncInvoiceSetToChargeAmount (invoice, gnc_amount_edit_get_amount
00914                                (GNC_AMOUNT_EDIT (widget)));
00915 }
00916 
00917 static GtkWidget *
00918 add_summary_label (GtkWidget *summarybar, const char *label_str)
00919 {
00920   GtkWidget *hbox;
00921   GtkWidget *label;
00922 
00923   hbox = gtk_hbox_new(FALSE, 2);
00924   gtk_box_pack_start (GTK_BOX(summarybar), hbox, FALSE, FALSE, 5);
00925 
00926   label = gtk_label_new (label_str);
00927   gtk_misc_set_alignment (GTK_MISC(label), 1.0, 0.5);
00928   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
00929 
00930   label = gtk_label_new ("");
00931   gtk_misc_set_alignment (GTK_MISC(label), 1.0, 0.5);
00932   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
00933 
00934   return label;
00935 }
00936 
00937 GtkWidget *
00938 gnc_invoice_window_create_summary_bar (InvoiceWindow *iw)
00939 {
00940   GtkWidget *summarybar;
00941 
00942   iw->total_label           = NULL;
00943   iw->total_cash_label      = NULL;
00944   iw->total_charge_label    = NULL;
00945   iw->total_subtotal_label  = NULL;
00946   iw->total_tax_label       = NULL;
00947 
00948   summarybar = gtk_hbox_new (FALSE, 4);
00949 
00950   iw->total_label           = add_summary_label (summarybar, _("Total:"));
00951 
00952   switch (gncOwnerGetType (&iw->owner)) {
00953   case GNC_OWNER_CUSTOMER:
00954   case GNC_OWNER_VENDOR:
00955     iw->total_subtotal_label= add_summary_label (summarybar, _("Subtotal:"));
00956     iw->total_tax_label     = add_summary_label (summarybar, _("Tax:"));
00957     break;
00958 
00959   case GNC_OWNER_EMPLOYEE:
00960     iw->total_cash_label    = add_summary_label (summarybar, _("Total Cash:"));
00961     iw->total_charge_label  = add_summary_label (summarybar, _("Total Charge:"));
00962     break;
00963 
00964   default:
00965     break;
00966   }
00967 
00968   gtk_widget_show_all(summarybar);
00969   return summarybar;
00970 }
00971 
00972 static int
00973 gnc_invoice_job_changed_cb (GtkWidget *widget, gpointer data)
00974 {
00975   InvoiceWindow *iw = data;
00976   GncInvoice *invoice;
00977   char const *msg = "";
00978   
00979   if (!iw)
00980     return FALSE;
00981 
00982   if (iw->dialog_type == VIEW_INVOICE)
00983     return FALSE;
00984 
00985   gnc_owner_get_owner (iw->job_choice, &(iw->job));
00986   invoice = iw_get_invoice (iw);
00987 
00988   if (iw->dialog_type == EDIT_INVOICE)
00989     return FALSE;
00990 
00991   msg = gncJobGetReference (gncOwnerGetJob (&(iw->job)));
00992   gtk_entry_set_text (GTK_ENTRY (iw->billing_id_entry), msg ? msg : "");
00993 
00994   return FALSE;
00995 
00996 }
00997 
00998 static GNCSearchWindow *
00999 gnc_invoice_select_job_cb (gpointer jobp, gpointer user_data)
01000 {
01001   GncJob *j = jobp;
01002   InvoiceWindow *iw = user_data;
01003   GncOwner owner, *ownerp;
01004 
01005   if (!iw) return NULL;
01006 
01007   if (j) {
01008     ownerp = gncJobGetOwner (j);
01009     gncOwnerCopy (ownerp, &owner);
01010   } else
01011     gncOwnerCopy (&(iw->owner), &owner);
01012 
01013   return gnc_job_search (j, &owner, iw->book);
01014 }
01015 
01016 static void
01017 gnc_invoice_update_job_choice (InvoiceWindow *iw)
01018 {
01019   if (iw->job_choice)
01020     gtk_container_remove (GTK_CONTAINER (iw->job_box), iw->job_choice);
01021 
01022   /* If we don't have a real owner, then we obviously can't have a job */
01023   if (iw->owner.owner.undefined == NULL) {
01024     iw->job_choice = NULL;
01025 
01026   } else
01027     switch (iw->dialog_type) {
01028     case VIEW_INVOICE:
01029     case EDIT_INVOICE:
01030       iw->job_choice =
01031         gnc_owner_edit_create (NULL, iw->job_box, iw->book, &(iw->job));
01032       break;
01033     case NEW_INVOICE:
01034     case MOD_INVOICE:
01035       iw->job_choice =
01036         gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
01037                                 gnc_invoice_select_job_cb, iw);
01038 
01039       gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
01040                                        gncOwnerGetJob (&iw->job));
01041       gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->job_choice),
01042                                       TRUE);
01043       gtk_box_pack_start (GTK_BOX (iw->job_box), iw->job_choice,
01044                           TRUE, TRUE, 0);
01045       
01046       g_signal_connect (G_OBJECT (iw->job_choice), "changed",
01047                         G_CALLBACK (gnc_invoice_job_changed_cb), iw);
01048       break;
01049     }
01050   
01051   if (iw->job_choice)
01052     gtk_widget_show_all (iw->job_choice);
01053 }
01054 
01055 static GNCSearchWindow *
01056 gnc_invoice_select_proj_job_cb (gpointer jobp, gpointer user_data)
01057 {
01058   GncJob *j = jobp;
01059   InvoiceWindow *iw = user_data;
01060   GncOwner owner, *ownerp;
01061 
01062   if (!iw) return NULL;
01063 
01064   if (j) {
01065     ownerp = gncJobGetOwner (j);
01066     gncOwnerCopy (ownerp, &owner);
01067   } else
01068     gncOwnerCopy (&(iw->proj_cust), &owner);
01069 
01070   return gnc_job_search (j, &owner, iw->book);
01071 }
01072 
01073 static int
01074 gnc_invoice_proj_job_changed_cb (GtkWidget *widget, gpointer data)
01075 {
01076   InvoiceWindow *iw = data;
01077   
01078   if (!iw)
01079     return FALSE;
01080 
01081   if (iw->dialog_type == VIEW_INVOICE)
01082     return FALSE;
01083 
01084   gnc_owner_get_owner (iw->proj_job_choice, &(iw->proj_job));
01085   return FALSE;
01086 }
01087 
01088 static void
01089 gnc_invoice_update_proj_job (InvoiceWindow *iw)
01090 {
01091   if (iw->proj_job_choice)
01092     gtk_container_remove (GTK_CONTAINER (iw->proj_job_box),
01093                           iw->proj_job_choice);
01094 
01095   switch (iw->dialog_type) {
01096   case VIEW_INVOICE:
01097   case EDIT_INVOICE:
01098       iw->proj_job_choice =
01099         gnc_owner_edit_create (NULL, iw->proj_job_box, iw->book, &(iw->job));
01100     break;
01101   case NEW_INVOICE:
01102   case MOD_INVOICE:
01103     if (iw->proj_cust.owner.undefined == NULL) {
01104       iw->proj_job_choice = NULL;
01105     } else {
01106       iw->proj_job_choice =
01107         gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
01108                                 gnc_invoice_select_proj_job_cb, iw);
01109 
01110       gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
01111                                        gncOwnerGetJob (&iw->proj_job));
01112       gnc_general_search_allow_clear (GNC_GENERAL_SEARCH (iw->proj_job_choice),
01113                                       TRUE);
01114       gtk_box_pack_start (GTK_BOX (iw->proj_job_box), iw->proj_job_choice,
01115                           TRUE, TRUE, 0);
01116       
01117       g_signal_connect (G_OBJECT (iw->proj_job_choice), "changed",
01118                         G_CALLBACK (gnc_invoice_proj_job_changed_cb), iw);
01119     }
01120     break;
01121   }
01122 
01123   if (iw->proj_job_choice)
01124     gtk_widget_show_all (iw->proj_job_choice);
01125 }
01126 
01127 static int
01128 gnc_invoice_owner_changed_cb (GtkWidget *widget, gpointer data)
01129 {
01130   InvoiceWindow *iw = data;
01131   GncBillTerm *term = NULL;
01132   GncOwner owner;
01133   
01134   if (!iw)
01135     return FALSE;
01136 
01137   if (iw->dialog_type == VIEW_INVOICE)
01138     return FALSE;
01139 
01140   gncOwnerCopy (&(iw->owner), &owner);
01141   gnc_owner_get_owner (iw->owner_choice, &owner);
01142 
01143   /* If this owner really changed, then reset ourselves */
01144   if (!gncOwnerEqual (&owner, &(iw->owner))) {
01145     GncInvoice *invoice;
01146 
01147     gncOwnerCopy (&owner, &(iw->owner));
01148     gncOwnerInitJob (&(iw->job), NULL);
01149     invoice = iw_get_invoice (iw);
01150     gnc_entry_ledger_reset_query (iw->ledger);
01151   }
01152 
01153   if (iw->dialog_type == EDIT_INVOICE)
01154     return FALSE;
01155 
01156   switch (gncOwnerGetType (&(iw->owner))) {
01157   case GNC_OWNER_CUSTOMER:
01158     term = gncCustomerGetTerms (gncOwnerGetCustomer (&(iw->owner)));
01159     break;
01160   case GNC_OWNER_VENDOR:
01161     term = gncVendorGetTerms (gncOwnerGetVendor (&(iw->owner)));
01162     break;
01163   case GNC_OWNER_EMPLOYEE:
01164     term = NULL;
01165     break;
01166   default:
01167     g_warning ("Unknown owner type: %d\n", gncOwnerGetType (&(iw->owner)));
01168     break;
01169   }
01170 
01171   /* XXX: I'm not sure -- should we change the terms if this happens? */
01172   iw->terms = term;
01173   gnc_ui_optionmenu_set_value (iw->terms_menu, iw->terms);
01174 
01175   gnc_invoice_update_job_choice (iw);
01176 
01177   return FALSE;
01178 }
01179 
01180 static int
01181 gnc_invoice_proj_cust_changed_cb (GtkWidget *widget, gpointer data)
01182 {
01183   InvoiceWindow *iw = data;
01184   GncOwner owner;
01185   
01186   if (!iw)
01187     return FALSE;
01188 
01189   if (iw->dialog_type == VIEW_INVOICE)
01190     return FALSE;
01191 
01192   gncOwnerCopy (&(iw->proj_cust), &owner);
01193   gnc_owner_get_owner (iw->proj_cust_choice, &owner);
01194 
01195   /* If this owner really changed, then reset ourselves */
01196   if (!gncOwnerEqual (&owner, &(iw->proj_cust))) {
01197     gncOwnerCopy (&owner, &(iw->proj_cust));
01198     gncOwnerInitJob (&(iw->proj_job), NULL);
01199   }
01200 
01201   if (iw->dialog_type == EDIT_INVOICE)
01202     return FALSE;
01203 
01204   gnc_invoice_update_proj_job (iw);
01205 
01206   return FALSE;
01207 }
01208 
01209 static void
01210 gnc_invoice_dialog_close_handler (gpointer user_data)
01211 {
01212   InvoiceWindow *iw = user_data;
01213 
01214   if (iw) {
01215     gtk_widget_destroy (iw->dialog);
01216   }
01217 }
01218 
01219 static void
01220 gnc_invoice_window_close_handler (gpointer user_data)
01221 {
01222   InvoiceWindow *iw = user_data;
01223 
01224   if (iw) {
01225     gnc_main_window_close_page(iw->page);
01226     iw->page = NULL;
01227   }
01228 }
01229 
01230 static void
01231 gnc_invoice_reset_total_label (GtkLabel *label, gnc_numeric amt, gnc_commodity *com)
01232 {
01233   char string[256];
01234 
01235   amt = gnc_numeric_convert (amt, gnc_commodity_get_fraction(com), GNC_RND_ROUND);
01236   xaccSPrintAmount (string, amt, gnc_default_print_info (TRUE));
01237   gtk_label_set_text (label, string);
01238 }
01239 
01240 static void
01241 gnc_invoice_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
01242 {
01243   InvoiceWindow *iw = data;
01244   GncInvoice * invoice;
01245   gnc_commodity * currency;
01246   gnc_numeric amount, to_charge_amt = gnc_numeric_zero();
01247 
01248   if (!iw)
01249     return;
01250 
01251   //  if (iw)
01252   //    gnc_invoice_update_window (iw, NULL);
01253 
01254   invoice = iw_get_invoice (iw);
01255   if (!invoice)
01256     return;
01257 
01258   currency = gncInvoiceGetCurrency (invoice);
01259 
01260   if (iw->total_label) {
01261     amount = gncInvoiceGetTotal (invoice);
01262     gnc_invoice_reset_total_label (GTK_LABEL (iw->total_label), amount, currency);
01263   }
01264 
01265   if (iw->total_subtotal_label) {
01266     amount = gncInvoiceGetTotalSubtotal (invoice);
01267     gnc_invoice_reset_total_label (GTK_LABEL (iw->total_subtotal_label), amount, currency);
01268   }
01269 
01270   if (iw->total_tax_label) {
01271     amount = gncInvoiceGetTotalTax (invoice);
01272     gnc_invoice_reset_total_label (GTK_LABEL (iw->total_tax_label), amount, currency);
01273   }
01274 
01275   /* Deal with extra items for the expense voucher */
01276 
01277   if (iw->to_charge_edit) {
01278     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (iw->to_charge_edit));
01279     to_charge_amt = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(iw->to_charge_edit));
01280   }
01281 
01282   if (iw->total_cash_label) {
01283     amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CASH);
01284     amount = gnc_numeric_sub (amount, to_charge_amt,
01285                               gnc_commodity_get_fraction (currency), GNC_RND_ROUND);
01286     gnc_invoice_reset_total_label (GTK_LABEL (iw->total_cash_label), amount, currency);
01287   }
01288 
01289   if (iw->total_charge_label) {
01290     amount = gncInvoiceGetTotalOf (invoice, GNC_PAYMENT_CARD);
01291     amount = gnc_numeric_add (amount, to_charge_amt, 
01292                               gnc_commodity_get_fraction (currency), GNC_RND_ROUND);
01293     gnc_invoice_reset_total_label (G