|
GnuCash 2.4.99
|
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
1.7.4