GnuCash  5.6-150-g038405b370+
gncEntryLedger.c
1 /*
2  * gncEntryLedger.c -- a Ledger widget for entering GncEntry objects
3  * Copyright (C) 2001, 2002, 2003 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA gnu@gnu.org
22  */
23 
24 #include <config.h>
25 
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 
29 #include "Account.h"
30 #include "dialog-account.h"
31 #include "dialog-utils.h"
32 #include "gnc-ui-util.h"
33 #include "combocell.h"
34 #include "pricecell.h"
35 #include "recncell.h"
36 #include "checkboxcell.h"
37 
38 #include "gnc-component-manager.h"
39 #include "gnc-ui.h"
40 #include "gnc-warnings.h"
41 
42 #include "gncEntry.h"
43 #include "gncEntryLedger.h"
44 #include "gncEntryLedgerP.h"
45 #include "gncEntryLedgerLayout.h"
46 #include "gncEntryLedgerModel.h"
47 #include "gncEntryLedgerControl.h"
48 
49 static QofLogModule log_module = "Business Entry Ledger";
50 
53 static void
54 gnc_entry_ledger_clear_blank_entry (GncEntryLedger *ledger)
55 {
56  GncEntry *entry;
57 
58  if (!ledger) return;
59 
60  entry = gnc_entry_ledger_get_blank_entry (ledger);
61  if (entry)
62  {
63  if (!gncEntryIsOpen (entry))
64  gncEntryBeginEdit (entry);
65  gncEntryDestroy (entry);
66  }
67 
68  ledger->blank_entry_guid = *guid_null ();
69  ledger->blank_entry_edited = FALSE;
70 }
71 
74 GncEntry *
75 gnc_entry_ledger_get_blank_entry (GncEntryLedger *ledger)
76 {
77  if (!ledger) return NULL;
78  return gncEntryLookup (ledger->book, &(ledger->blank_entry_guid));
79 }
80 
81 Account *
82 gnc_entry_ledger_get_account_by_name (GncEntryLedger *ledger, BasicCell * bcell,
83  const char *name, gboolean *isnew)
84 {
85  const char *placeholder = _("The account %s does not allow transactions.");
86  const char *missing = _("The account %s does not exist. "
87  "Would you like to create it?");
88  char *account_name;
89  ComboCell *cell = (ComboCell *) bcell;
90  Account *account;
91  GList *account_types = NULL;
92 
93  /* Find the account */
94  account = gnc_account_lookup_for_register (gnc_get_current_root_account (), name);
95  if (!account)
96  account = gnc_account_lookup_by_code (gnc_get_current_root_account(), name);
97 
98  if (!account)
99  {
100  /* Ask if they want to create a new one. */
101  if (!gnc_verify_dialog (GTK_WINDOW (ledger->parent), TRUE, missing, name))
102  return NULL;
103 
104  /* No changes, as yet. */
105  *isnew = FALSE;
106 
107  /* User said yes, they want to create a new account. */
108  account_types = g_list_prepend (account_types, (gpointer)ACCT_TYPE_CREDIT);
109  account_types = g_list_prepend (account_types, (gpointer)ACCT_TYPE_ASSET);
110  account_types = g_list_prepend (account_types, (gpointer)ACCT_TYPE_LIABILITY);
111  if ( ledger->is_cust_doc )
112  account_types = g_list_prepend (account_types, (gpointer)ACCT_TYPE_INCOME);
113  else
114  account_types = g_list_prepend (account_types, (gpointer)ACCT_TYPE_EXPENSE);
115 
116  account = gnc_ui_new_accounts_from_name_with_defaults (GTK_WINDOW (ledger->parent), name, account_types,
117  NULL, NULL);
118  g_list_free ( account_types );
119  if (!account)
120  return NULL;
121  *isnew = TRUE;
122  }
123 
124  /* Now have a new account. Update the cell with the name as created. */
125  account_name = gnc_get_account_name_for_register (account);
126  if (g_strcmp0(account_name, gnc_basic_cell_get_value(bcell)))
127  {
128  gnc_combo_cell_set_value (cell, account_name);
129  gnc_basic_cell_set_changed (&cell->cell, TRUE);
130  }
131  g_free (account_name);
132 
133  /* See if the account (either old or new) is a placeholder. */
134  if (xaccAccountGetPlaceholder (account))
135  {
136  gnc_error_dialog (GTK_WINDOW (ledger->parent), placeholder, name);
137  }
138 
139  /* Be seeing you. */
140  return account;
141 }
142 
143 Account * gnc_entry_ledger_get_account (GncEntryLedger *ledger,
144  const char * cell_name)
145 {
146  BasicCell *cell;
147  const char * name;
148  gboolean dummy;
149 
150  cell = gnc_table_layout_get_cell (ledger->table->layout, cell_name);
151  if (!cell)
152  return NULL;
153  name = gnc_basic_cell_get_value (cell);
154  return gnc_entry_ledger_get_account_by_name (ledger, cell, name, &dummy);
155 }
156 
157 GncTaxTable * gnc_entry_ledger_get_taxtable (GncEntryLedger *ledger,
158  const char *cell_name)
159 {
160  GncEntry *entry;
161  const char * name;
162 
163  /* If the cursor has changed, then pull in the current table */
164  if (gnc_table_layout_get_cell_changed (ledger->table->layout,
165  cell_name, TRUE))
166  {
167  name = gnc_table_layout_get_cell_value (ledger->table->layout, cell_name);
168  return gncTaxTableLookupByName (ledger->book, name);
169  }
170 
171  /* If it has not changed, pull in the table from the entry */
172  entry = gnc_entry_ledger_get_current_entry (ledger);
173  if (ledger->is_cust_doc)
174  return gncEntryGetInvTaxTable (entry);
175  else
176  return gncEntryGetBillTaxTable (entry);
177 }
178 
179 gboolean gnc_entry_ledger_get_checkmark (GncEntryLedger *ledger,
180  const char * cell_name)
181 {
182  CheckboxCell *cell =
183  (CheckboxCell *) gnc_table_layout_get_cell (ledger->table->layout, cell_name);
184 
185  if (!cell)
186  return FALSE;
187 
188  return cell->flag;
189 }
190 
191 gint gnc_entry_ledger_get_type (GncEntryLedger *ledger, const char * cell_name)
192 {
193  RecnCell *cell =
194  (RecnCell *) gnc_table_layout_get_cell (ledger->table->layout, cell_name);
195 
196  if (!cell)
197  return -1;
198 
199  return (gnc_recn_cell_get_flag (cell) - '0');
200 }
201 
202 /* Return TRUE if value is valid, return FALSE if invalid */
203 gboolean gnc_entry_ledger_get_numeric (GncEntryLedger *ledger,
204  const char *cell_name,
205  gnc_numeric *value)
206 {
207  PriceCell *cell =
208  (PriceCell *) gnc_table_layout_get_cell (ledger->table->layout, cell_name);
209 
210  if (!value || !cell)
211  return FALSE;
212 
213  *value = gnc_price_cell_get_value (cell);
214  return TRUE;
215 }
216 
217 
218 GncEntry * gnc_entry_ledger_get_entry (GncEntryLedger *ledger,
219  VirtualCellLocation vcell_loc)
220 {
221  GncGUID *guid;
222 
223  if (!ledger) return NULL;
224 
225  guid = gnc_table_get_vcell_data (ledger->table, vcell_loc);
226  if (!guid) return NULL;
227 
228  return gncEntryLookup (ledger->book, guid);
229 }
230 
231 /* Returns the Entry where the cursor is currently located. */
232 GncEntry * gnc_entry_ledger_get_current_entry (GncEntryLedger *ledger)
233 {
234  if (!ledger) return NULL;
235 
236  return
238  ledger->table->current_cursor_loc.vcell_loc);
239 }
240 
241 static void gnc_entry_ledger_config_action (GncEntryLedger *ledger)
242 {
243  ComboCell *cell;
244 
245  cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
246  ENTRY_ACTN_CELL);
247  if (!cell) return;
248 
249  /* XXX: change this based on the ledger type */
250 
251  gnc_combo_cell_add_menu_item (cell, _("Hours"));
252  gnc_combo_cell_add_menu_item (cell, _("Project"));
253  gnc_combo_cell_add_menu_item (cell, _("Material"));
254 }
255 
256 static void
257 gnc_entry_ledger_config_cells (GncEntryLedger *ledger)
258 {
259  /* the action cell */
261  ((ComboCell *)
262  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_ACTN_CELL), TRUE);
263 
264  /* The action cell should also accept strings not in the list */
266  ((ComboCell *)
267  gnc_table_layout_get_cell (ledger->table->layout, ENTRY_ACTN_CELL), FALSE);
268 
269  /* add menu items for the action and payment cells */
270  gnc_entry_ledger_config_action (ledger);
271 }
272 
273 /* Create and return a new GncEntry Ledger */
274 GncEntryLedger * gnc_entry_ledger_new (QofBook *book, GncEntryLedgerType type)
275 {
276  GncEntryLedger *ledger;
277 
278  if (!book) return NULL;
279  if (type < 0 || type >= GNCENTRY_NUM_REGISTER_TYPES) return NULL;
280 
281  ledger = g_new0 (GncEntryLedger, 1);
282  ledger->type = type;
283  ledger->book = book;
284  ledger->traverse_to_new = TRUE;
285  ledger->prefs_group = NULL;
286 
287  /* Orders and Invoices are "invoices" for lookups */
288  switch (type)
289  {
290  case GNCENTRY_ORDER_ENTRY:
291  case GNCENTRY_ORDER_VIEWER:
292  case GNCENTRY_INVOICE_ENTRY:
293  case GNCENTRY_INVOICE_VIEWER:
294  ledger->is_cust_doc = TRUE;
295  ledger->is_credit_note = FALSE;
296  break;
297  case GNCENTRY_BILL_ENTRY:
298  case GNCENTRY_BILL_VIEWER:
299  case GNCENTRY_EXPVOUCHER_ENTRY:
300  case GNCENTRY_EXPVOUCHER_VIEWER:
301  case GNCENTRY_NUM_REGISTER_TYPES:
302  ledger->is_cust_doc = FALSE;
303  ledger->is_credit_note = FALSE;
304  break;
305  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
306  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
307  ledger->is_cust_doc = TRUE;
308  ledger->is_credit_note = TRUE;
309  break;
310  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
311  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
312  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
313  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
314  ledger->is_cust_doc = FALSE;
315  ledger->is_credit_note = TRUE;
316  break;
317  default:
318  PWARN ("Bad GncEntryLedgerType");
319  g_free (ledger);
320  return NULL;
321  break;
322  }
323 
324  ledger->blank_entry_guid = *guid_null();
325  ledger->blank_entry_edited = FALSE;
326 
327  {
328  GDate *today = gnc_g_date_new_today();
329  ledger->last_date_entered = *today;
330  g_date_free(today);
331  }
332 
333  {
334  TableLayout *layout = gnc_entry_ledger_layout_new (ledger);
335  TableModel *model = gnc_entry_ledger_model_new (type);
336  TableControl *control = gnc_entry_ledger_control_new ();
337  model->handler_user_data = ledger;
338  control->user_data = ledger;
339 
340  ledger->table = gnc_table_new (layout, model, control);
341  }
342 
343  gnc_entry_ledger_config_cells (ledger);
344 
345  /* set up header */
346  {
347  VirtualCellLocation vcell_loc = { 0, 0 };
348  CellBlock *header;
349 
350  header = gnc_table_layout_get_cursor (ledger->table->layout, CURSOR_HEADER);
351 
352  gnc_table_set_vcell (ledger->table, header, NULL, TRUE, TRUE, vcell_loc);
353  }
354 
355  /* set up first initial row */
356  {
357  VirtualLocation vloc;
358  CellBlock *cursor;
359 
360  vloc.vcell_loc.virt_row = 1;
361  vloc.vcell_loc.virt_col = 0;
362  vloc.phys_row_offset = 0;
363  vloc.phys_col_offset = 0;
364 
365  cursor = gnc_table_layout_get_cursor (ledger->table->layout, "cursor");
366 
367  gnc_table_set_vcell (ledger->table, cursor, NULL, TRUE, TRUE, vloc.vcell_loc);
368 
369  if (gnc_table_find_close_valid_cell (ledger->table, &vloc, FALSE))
370  gnc_table_move_cursor (ledger->table, vloc);
371  else
372  {
373  g_warning ("Can't find valid initial location");
374  }
375  }
376 
377  /* Initialize Display */
378  gnc_entry_ledger_display_init (ledger);
379  if (qof_book_is_readonly(ledger->book))
380  {
381  gnc_entry_ledger_set_readonly(ledger, TRUE);
382  }
383  return ledger;
384 }
385 
386 /* Destroy the GncEntry Ledger */
387 void gnc_entry_ledger_destroy (GncEntryLedger *ledger)
388 {
389  if (!ledger) return;
390 
391  /* Destroy blank entry, etc. */
392  gnc_entry_ledger_clear_blank_entry (ledger);
393  gnc_entry_ledger_display_fini (ledger);
394  gnc_table_destroy (ledger->table);
395  qof_query_destroy (ledger->query);
396  g_free (ledger);
397 }
398 
399 Table * gnc_entry_ledger_get_table (GncEntryLedger *ledger)
400 {
401  if (!ledger) return NULL;
402  return ledger->table;
403 }
404 
405 void gnc_entry_ledger_set_default_order (GncEntryLedger *ledger,
406  GncOrder *order)
407 {
408  if (!ledger) return;
409  ledger->order = order;
410 
411  if (!ledger->query && order)
412  {
413  ledger->query = qof_query_create_for (GNC_ENTRY_MODULE_NAME);
414  qof_query_set_book (ledger->query, gncOrderGetBook (order));
415  qof_query_add_guid_match (ledger->query,
416  g_slist_prepend (g_slist_prepend (NULL,
417  QOF_PARAM_GUID),
418  ENTRY_ORDER),
419  gncOrderGetGUID (order), QOF_QUERY_AND);
420  }
421  gnc_entry_ledger_display_refresh (ledger);
422 }
423 
424 static void create_invoice_query (GncEntryLedger *ledger)
425 {
426  QofQuery *q, *q1;
427  char * type = NULL;
428 
429  if (!ledger->invoice)
430  return;
431 
432  if (ledger->query)
433  qof_query_destroy (ledger->query);
434 
435  /* Match: (where I-TYPE == Invoice or Bill)
436  *
437  * 1. book AND
438  * 2. ( Entry->I-TYPE == ledger->invoice
439  * #if I-TYPE == Invoice/Cust Credit Note (entry only)
440  * OR
441  * 3. ( Entry->Invoice == NULL AND
442  * ( Entry->Billable == TRUE AND
443  * Entry->Bill->Is-Posted? == TRUE AND
444  * ( Entry->BillTo == Invoice->parent OR
445  * ( Entry->BillTo == NULL AND Entry->Bill->BillTo == Invoice->parent ) ) )
446  * OR
447  * ( Entry->Order->real-parent == Invoice->parent ) )
448  * #endif
449  * )
450  *
451  * Note that term 3 is only for Editable invoices.
452  */
453 
454  /* Term 1 */
455  ledger->query = qof_query_create_for (GNC_ENTRY_MODULE_NAME);
456  qof_query_set_book (ledger->query, gncInvoiceGetBook (ledger->invoice));
457 
458  /* Term 2 */
459  switch (ledger->type)
460  {
461  case GNCENTRY_INVOICE_ENTRY:
462  case GNCENTRY_INVOICE_VIEWER:
463  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
464  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
465  type = ENTRY_INVOICE;
466  break;
467  case GNCENTRY_BILL_ENTRY:
468  case GNCENTRY_BILL_VIEWER:
469  case GNCENTRY_EXPVOUCHER_ENTRY:
470  case GNCENTRY_EXPVOUCHER_VIEWER:
471  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
472  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
473  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
474  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
475  type = ENTRY_BILL;
476  break;
477  default:
478  g_warning ("Invalid Ledger type");
479  type = ENTRY_INVOICE;
480  break;
481  }
482 
483  q = qof_query_create_for (GNC_ENTRY_MODULE_NAME);
484  qof_query_add_guid_match (q, qof_query_build_param_list (type, QOF_PARAM_GUID, NULL),
485  gncInvoiceGetGUID (ledger->invoice), QOF_QUERY_OR);
486 
487  /* Term 3 */
488  if ((ledger->type == GNCENTRY_INVOICE_ENTRY ||
489  ledger->type == GNCENTRY_CUST_CREDIT_NOTE_ENTRY) &&
490  gncOwnerGetEndGUID (gncInvoiceGetOwner (ledger->invoice)) != NULL)
491  {
492 
493  const GncGUID *invoice_parent =
494  gncOwnerGetGUID (gncInvoiceGetOwner (ledger->invoice));
495  QofQuery *q2 = qof_query_create_for (GNC_ENTRY_MODULE_NAME);
496 
497  /*
498  * Entry->BillTo == Invoice->parent OR
499  * ( Entry->BillTo == NULL AND Entry->Bill->BillTo == Invoice->parent )
500  */
501 
502  qof_query_add_guid_match (q2, qof_query_build_param_list (ENTRY_BILLTO,
503  QOF_PARAM_GUID, NULL),
504  NULL, QOF_QUERY_AND);
505  qof_query_add_guid_match (q2, qof_query_build_param_list (ENTRY_BILL, INVOICE_BILLTO,
506  QOF_PARAM_GUID, NULL),
507  invoice_parent, QOF_QUERY_AND);
508  qof_query_add_guid_match (q2, qof_query_build_param_list (ENTRY_BILLTO,
509  QOF_PARAM_GUID, NULL),
510  invoice_parent, QOF_QUERY_OR);
511 
512  /* Entry->Billable == TRUE AND Entry->Bill->Is-Posted? == TRUE */
513  qof_query_add_boolean_match (q2, qof_query_build_param_list (ENTRY_BILLABLE, NULL),
514  TRUE, QOF_QUERY_AND);
515  qof_query_add_boolean_match (q2, qof_query_build_param_list (ENTRY_BILL,
516  INVOICE_IS_POSTED, NULL),
517  TRUE, QOF_QUERY_AND);
518 
519  /* Entry->Order->real-parent == Invoice->parent */
520  qof_query_add_guid_match (q2, qof_query_build_param_list (ENTRY_ORDER, ORDER_OWNER,
521  OWNER_PARENTG, NULL),
522  invoice_parent, QOF_QUERY_OR);
523 
524  /* Entry->Invoice == NULL */
525  qof_query_add_guid_match (q2, qof_query_build_param_list (ENTRY_INVOICE,
526  QOF_PARAM_GUID, NULL),
527  NULL, QOF_QUERY_AND);
528 
529 
530  /* Combine terms 2 and 3 */
531  q1 = qof_query_merge (q, q2, QOF_QUERY_OR);
532  qof_query_destroy (q);
533  qof_query_destroy (q2);
534  q = q1;
535  }
536 
537  /* Combine terms 1 and 2 */
538  q1 = qof_query_merge (ledger->query, q, QOF_QUERY_AND);
539  qof_query_destroy (q);
540  qof_query_destroy (ledger->query);
541  ledger->query = q1;
542 }
543 
544 void gnc_entry_ledger_set_default_invoice (GncEntryLedger *ledger,
545  GncInvoice *invoice)
546 {
547  if (!ledger) return;
548  ledger->invoice = invoice;
549 
550  /* For bills only, set the default date for new entries
551  * to the bill's opened date. This saves a lot of typing when
552  * adding bills on a day different from the bill's own date.
553  * Note this is for bills only, because for (customer's) invoices
554  * it makes more sense to use the current date.
555  * Consult https://bugs.gnucash.org/show_bug.cgi?id=646541
556  * to understand why.
557  */
558  if (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_VENDOR)
559  ledger->last_date_entered = time64_to_gdate(gncInvoiceGetDateOpened (invoice));
560 
561  if (!ledger->query && invoice)
562  create_invoice_query (ledger);
563 
564  gnc_entry_ledger_display_refresh (ledger);
565 }
566 
567 void gnc_entry_ledger_reset_query (GncEntryLedger *ledger)
568 {
569  if (!ledger) return;
570  if (!ledger->invoice) return;
571 
572  create_invoice_query (ledger);
573  gnc_entry_ledger_display_refresh (ledger);
574 }
575 
576 void gnc_entry_ledger_set_parent (GncEntryLedger *ledger, GtkWidget *parent)
577 {
578  if (!ledger) return;
579  ledger->parent = parent;
580 }
581 
582 gboolean gnc_entry_ledger_find_entry (GncEntryLedger *ledger, GncEntry *entry,
583  VirtualCellLocation *vcell_loc)
584 {
585  Table *table = ledger->table;
586  int v_row;
587  GncEntry *e;
588 
589  for (v_row = 1; v_row < table->num_virt_rows; v_row++)
590  {
591  VirtualCellLocation vc_loc = { v_row, 0 };
592 
593  e = gnc_entry_ledger_get_entry (ledger, vc_loc);
594 
595  if (e == entry)
596  {
597  if (vcell_loc != NULL)
598  *vcell_loc = vc_loc;
599  return TRUE;
600  }
601  }
602  return FALSE;
603 }
604 
605 void gnc_entry_ledger_set_readonly (GncEntryLedger *ledger, gboolean readonly)
606 {
607  if (!ledger) return;
608  if (!readonly && qof_book_is_readonly(ledger->book)) return;
609 
610  /* reset the ledger type appropriately */
611  if (readonly)
612  {
613  switch (ledger->type)
614  {
615  case GNCENTRY_ORDER_ENTRY:
616  ledger->type = GNCENTRY_ORDER_VIEWER;
617  break;
618  case GNCENTRY_INVOICE_ENTRY:
619  ledger->type = GNCENTRY_INVOICE_VIEWER;
620  create_invoice_query (ledger);
621  break;
622  case GNCENTRY_BILL_ENTRY:
623  ledger->type = GNCENTRY_BILL_VIEWER;
624  create_invoice_query (ledger);
625  break;
626  case GNCENTRY_EXPVOUCHER_ENTRY:
627  ledger->type = GNCENTRY_EXPVOUCHER_VIEWER;
628  create_invoice_query (ledger);
629  break;
630  case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
631  ledger->type = GNCENTRY_CUST_CREDIT_NOTE_VIEWER;
632  create_invoice_query (ledger);
633  break;
634  case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
635  ledger->type = GNCENTRY_VEND_CREDIT_NOTE_VIEWER;
636  create_invoice_query (ledger);
637  break;
638  case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
639  ledger->type = GNCENTRY_EMPL_CREDIT_NOTE_VIEWER;
640  create_invoice_query (ledger);
641  break;
642  default:
643  return; /* Nothing to do */
644  }
645  }
646  else
647  {
648  switch (ledger->type)
649  {
650  case GNCENTRY_ORDER_VIEWER:
651  ledger->type = GNCENTRY_ORDER_ENTRY;
652  break;
653  case GNCENTRY_INVOICE_VIEWER:
654  ledger->type = GNCENTRY_INVOICE_ENTRY;
655  create_invoice_query (ledger);
656  break;
657  case GNCENTRY_BILL_VIEWER:
658  ledger->type = GNCENTRY_BILL_ENTRY;
659  create_invoice_query (ledger);
660  break;
661  case GNCENTRY_EXPVOUCHER_VIEWER:
662  ledger->type = GNCENTRY_EXPVOUCHER_ENTRY;
663  create_invoice_query (ledger);
664  break;
665  case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
666  ledger->type = GNCENTRY_CUST_CREDIT_NOTE_ENTRY;
667  create_invoice_query (ledger);
668  break;
669  case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
670  ledger->type = GNCENTRY_VEND_CREDIT_NOTE_ENTRY;
671  create_invoice_query (ledger);
672  break;
673  case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
674  ledger->type = GNCENTRY_EMPL_CREDIT_NOTE_ENTRY;
675  create_invoice_query (ledger);
676  break;
677  default:
678  return; /* Nothing to do */
679  }
680  }
681 
682  /* reset the model */
683  gnc_table_model_set_read_only (ledger->table->model, readonly);
684 
685  /* if readonly is TRUE, get rid of the blank entry. */
686  if (readonly)
687  gnc_entry_ledger_clear_blank_entry (ledger);
688 
689  /* and refresh the display */
690  gnc_entry_ledger_display_refresh (ledger);
691 }
692 
693 gboolean
694 gnc_entry_ledger_changed (GncEntryLedger *ledger)
695 {
696  if (!ledger)
697  return FALSE;
698 
699  if (gnc_table_current_cursor_changed (ledger->table, FALSE))
700  return TRUE;
701 
702  return FALSE;
703 }
704 
705 void
706 gnc_entry_ledger_compute_value (GncEntryLedger *ledger,
707  gnc_numeric *value, gnc_numeric *tax_value)
708 {
709  gnc_numeric qty = gnc_numeric_zero(), price = gnc_numeric_zero(), discount = gnc_numeric_zero();
710  gint disc_type, disc_how;
711  gboolean taxable, taxincluded;
713  GList *taxes = NULL;
714  int denom = 100;
715  gnc_numeric value_unrounded, taxes_unrounded;
716 
717  gnc_entry_ledger_get_numeric (ledger, ENTRY_QTY_CELL, &qty);
718  gnc_entry_ledger_get_numeric (ledger, ENTRY_PRIC_CELL, &price);
719  gnc_entry_ledger_get_numeric (ledger, ENTRY_DISC_CELL, &discount);
720 
721  disc_type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);
722  disc_how = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);
723 
724  /* Some ledger types (see full list in gnc_entry_ledger_set_cells)
725  don't have discounts */
726  if (ledger->type == GNCENTRY_BILL_ENTRY ||
727  ledger->type == GNCENTRY_BILL_VIEWER ||
728  ledger->type == GNCENTRY_VEND_CREDIT_NOTE_ENTRY ||
729  ledger->type == GNCENTRY_VEND_CREDIT_NOTE_VIEWER ||
730  ledger->type == GNCENTRY_EXPVOUCHER_ENTRY ||
731  ledger->type == GNCENTRY_EXPVOUCHER_VIEWER ||
732  ledger->type == GNCENTRY_EMPL_CREDIT_NOTE_ENTRY ||
733  ledger->type == GNCENTRY_EMPL_CREDIT_NOTE_VIEWER)
734  {
735  g_assert (gnc_numeric_zero_p (discount));
736  disc_type = GNC_AMT_TYPE_VALUE;
737  disc_how = GNC_DISC_PRETAX;
738  }
739 
740 
741  /* If we're so early in the process that we don't have info, stop now */
742  if (disc_type < 0 || disc_how < 0)
743  {
744  if (value)
745  *value = gnc_numeric_zero ();
746  if (tax_value)
747  *tax_value = gnc_numeric_zero ();
748  return;
749  }
750 
751  taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
752  taxincluded = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXINCLUDED_CELL);
753  table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
754 
755  /* Expense vouchers don't have taxable, taxincluded, or taxtable cells, either */
756  if (ledger->type == GNCENTRY_EXPVOUCHER_ENTRY ||
757  ledger->type == GNCENTRY_EXPVOUCHER_VIEWER)
758  {
759  taxable = FALSE;
760  taxincluded = FALSE;
761  table = NULL;
762  }
763 
764  if (ledger->invoice)
765  {
766  gnc_commodity *currency = gncInvoiceGetCurrency(ledger->invoice);
767  if (currency)
768  denom = gnc_commodity_get_fraction(currency);
769  }
770 
771  gncEntryComputeValue (qty, price, (taxable ? table : NULL), taxincluded,
772  discount, disc_type, disc_how, 0,
773  &value_unrounded, NULL, &taxes);
774 
775  if (value)
776  *value = gnc_numeric_convert (value_unrounded, denom,
778 
779  /* return the tax value */
780  taxes_unrounded = gncAccountValueTotal (taxes);
781  gncAccountValueDestroy (taxes);
782  if (tax_value)
783  *tax_value = gnc_numeric_convert (taxes_unrounded, denom,
785 }
786 
787 gboolean
788 gnc_entry_ledger_get_entry_virt_loc (GncEntryLedger *ledger, const GncEntry *entry,
789  VirtualCellLocation *vcell_loc)
790 {
791  Table *table;
792  int v_row;
793  int v_col;
794 
795  if ((ledger == NULL) || (entry == NULL))
796  return FALSE;
797  g_assert(vcell_loc);
798 
799  table = ledger->table;
800 
801  /* go backwards because typically you search for entries at the end */
802 
803  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
804  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
805  {
806  VirtualCellLocation vc_loc = { v_row, v_col };
807  VirtualCell *vcell;
808  GncEntry *e;
809 
810  vcell = gnc_table_get_virtual_cell (table, vc_loc);
811  if (vcell == NULL)
812  continue;
813 
814  if (!vcell->visible)
815  continue;
816 
817  e = gncEntryLookup (ledger->book, vcell->vcell_data);
818 
819  if (e == entry)
820  {
821  if (vcell_loc)
822  *vcell_loc = vc_loc;
823 
824  return TRUE;
825  }
826  }
827 
828  return FALSE;
829 }
830 
831 void
832 gnc_entry_ledger_delete_current_entry (GncEntryLedger *ledger)
833 {
834  GncEntry *entry;
835 
836  if (!ledger)
837  return;
838 
839  /* If there is no entry, just return */
840  entry = gnc_entry_ledger_get_current_entry (ledger);
841  if (!entry)
842  return;
843 
844  /* If this is the blank entry, just cancel the changes */
845  if (entry == gnc_entry_ledger_get_blank_entry (ledger))
846  {
847  gnc_entry_ledger_cancel_cursor_changes (ledger);
848  return;
849  }
850 
851  /* Ok, let's delete this entry */
852  gnc_suspend_gui_refresh ();
853  if (!gncEntryIsOpen (entry))
854  gncEntryBeginEdit (entry);
855 
856  {
857  GncOrder *order;
858  GncInvoice *invoice;
859 
860  order = gncEntryGetOrder (entry);
861  if (order)
862  gncOrderRemoveEntry (order, entry);
863 
864  invoice = gncEntryGetInvoice (entry);
865  if (invoice)
866  gncInvoiceRemoveEntry (invoice, entry);
867 
868  invoice = gncEntryGetBill (entry);
869  if (invoice)
870  gncBillRemoveEntry (invoice, entry);
871 
872  gncEntryDestroy (entry);
873  }
874  gnc_resume_gui_refresh ();
875 }
876 
877 void
878 gnc_entry_ledger_duplicate_current_entry (GncEntryLedger *ledger)
879 {
880  GncEntry *entry;
881  gboolean changed;
882 
883  if (!ledger)
884  return;
885 
886  /* Be paranoid */
887  entry = gnc_entry_ledger_get_current_entry (ledger);
888  if (!entry)
889  return;
890 
891  changed = gnc_table_current_cursor_changed (ledger->table, FALSE);
892 
893  /* See if we're asked to duplicate an unchanged blank entry --
894  * there is no point in doing that.
895  */
896  if (!changed && entry == gnc_entry_ledger_get_blank_entry (ledger))
897  return;
898 
899  gnc_suspend_gui_refresh ();
900 
901  /* If the cursor has been edited, we are going to have to commit
902  * it before we can duplicate. Make sure the user wants to do that. */
903  if (changed)
904  {
905  const char *title = _("Save the current entry?");
906  const char *message =
907  _("The current transaction has been changed. Would you like to "
908  "record the changes before duplicating this entry, or "
909  "cancel the duplication?");
910  GtkWidget *dialog;
911  gint response;
912 
913  dialog = gtk_message_dialog_new(GTK_WINDOW(ledger->parent),
914  GTK_DIALOG_DESTROY_WITH_PARENT,
915  GTK_MESSAGE_QUESTION,
916  GTK_BUTTONS_NONE,
917  "%s", title);
918  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
919  "%s", message);
920  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
921  _("_Cancel"), GTK_RESPONSE_CANCEL,
922  _("_Record"), GTK_RESPONSE_ACCEPT,
923  NULL);
924  response = gnc_dialog_run(GTK_DIALOG(dialog), GNC_PREF_WARN_INV_ENTRY_DUP);
925  gtk_widget_destroy(dialog);
926 
927  if (response != GTK_RESPONSE_ACCEPT)
928  {
929  gnc_resume_gui_refresh ();
930  return;
931  }
932 
933  if (!gnc_entry_ledger_commit_entry (ledger))
934  {
935  gnc_resume_gui_refresh ();
936  return;
937  }
938  }
939 
940  /* Ok, we're ready to make the copy */
941  {
942  GncEntry * new_entry;
943 
944  new_entry = gncEntryCreate (ledger->book);
945  gncEntryCopy (entry, new_entry, TRUE);
946  gncEntrySetDateGDate (new_entry, &ledger->last_date_entered);
947 
948  /* We also must set a new DateEntered on the new entry
949  * because otherwise the ordering is not deterministic */
950  gncEntrySetDateEntered (new_entry, gnc_time (NULL));
951 
952  /* Set the hint for where to display on the refresh */
953  ledger->hint_entry = new_entry;
954  }
955 
956  gnc_resume_gui_refresh ();
957  return;
958 }
959 
960 QofQuery *
961 gnc_entry_ledger_get_query (GncEntryLedger *ledger)
962 {
963  if (!ledger)
964  return NULL;
965 
966  return ledger->query;
967 }
968 
969 void
970 gnc_entry_ledger_set_prefs_group (GncEntryLedger *ledger, const gchar *string)
971 {
972  if (!ledger)
973  return;
974 
975  ledger->prefs_group = string;
976 }
977 
978 void gnc_entry_ledger_move_current_entry_updown (GncEntryLedger *ledger,
979  gboolean move_up)
980 {
981  GncEntry *blank, *current, *target;
982  VirtualCellLocation vcell_loc;
983 
984  g_assert(ledger);
985 
986  blank = gnc_entry_ledger_get_blank_entry(ledger);
987  if (!blank)
988  return;
989 
990  /* Ensure we have a valid current GncEntry and it isn't the blank
991  * entry */
992  current = gnc_entry_ledger_get_current_entry(ledger);
993  if (!current || current == blank)
994  return;
995 
996  /* Obtain the GncEntry at the up or down virtual table location */
997  vcell_loc = ledger->table->current_cursor_loc.vcell_loc;
998  if (move_up)
999  {
1000  if (vcell_loc.virt_row == 0)
1001  return;
1002  vcell_loc.virt_row--;
1003  }
1004  else
1005  {
1006  vcell_loc.virt_row++;
1007  }
1008 
1009  /* Ensure we have a valid other GncEntry and it isn't the blank
1010  * entry */
1011  target = gnc_entry_ledger_get_entry(ledger, vcell_loc);
1012  if (!target || target == blank)
1013  return;
1014 
1015  /* Also, only continue if both have the same date, because the
1016  * "standard ordering" is tied to the date anyway. Note: This
1017  * unfortunately prevents the user from changing the ordering if
1018  * he has chosen a different sort order and the sort key happens
1019  * to be equal among the two entries. But I don't know how to look
1020  * up the current sort ordering from here, so I cowardly refuse to
1021  * tweak the EntryDate in this case. */
1022  {
1023  time64 t1, t2;
1024  GDate d1 = gncEntryGetDateGDate(current),
1025  d2 = gncEntryGetDateGDate(target);
1026  if (g_date_compare(&d1, &d2) != 0)
1027  return;
1028 
1029  /* Special treatment if the equality doesn't hold if we access the
1030  dates as time64. See the comment in gncEntrySetDateGDate() for the
1031  reason: Some code used the time64 at noon for the EntryDate, other
1032  code used the time64 at the start of day. */
1033  t1 = gncEntryGetDate(current);
1034  t2 = gncEntryGetDate(target);
1035  if (t1 != t2)
1036  {
1037  /* times are not equal, even though the GDates were equal? Then
1038  we set the GDates again. This will force the times to be equal
1039  as well. */
1040  gncEntrySetDateGDate(current, &d1);
1041  gncEntrySetDateGDate(target, &d2);
1042  }
1043  }
1044 
1045  /*g_warning("Ok, current desc='%s' target desc='%s'",
1046  gncEntryGetDescription(current),
1047  gncEntryGetDescription(target));*/
1048 
1049  gnc_suspend_gui_refresh ();
1050 
1051  /* Swap the date-entered of both entries. That's already
1052  * sufficient! */
1053  {
1054  time64 time_current = gncEntryGetDateEntered(current);
1055  time64 time_target = gncEntryGetDateEntered(target);
1056 
1057  /* Special treatment for identical times (potentially caused
1058  * by the "duplicate entry" command) */
1059  if (time_current == time_target)
1060  {
1061  /*g_warning("Surprise - both DateEntered are equal.");*/
1062  /* We just increment the DateEntered of the previously
1063  * lower of the two by one second. This might still cause
1064  * issues if multiple entries had this problem, but
1065  * whatever. */
1066  if (move_up)
1067  ++time_current;
1068  else
1069  ++time_target;
1070  }
1071 
1072  /* Write the new DateEntered. */
1073  gncEntrySetDateEntered(current, time_target);
1074  gncEntrySetDateEntered(target, time_current);
1075 
1076  /* And finally let the GncInvoice sort its entries
1077  * accordingly, so that the invoice reports will give the same
1078  * ordering as the register window. */
1079  gncInvoiceSortEntries(ledger->invoice);
1080  }
1081 
1082  gnc_resume_gui_refresh ();
1083 }
The RecnCell object implements a cell handler that will cycle through a series of single-character va...
Definition: recncell.h:47
gpointer vcell_data
Array of physical cells.
Definition: table-allgui.h:135
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Get the GncGUID of the immediate owner.
Definition: gncOwner.c:518
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
This file contains the functions to present a gui to the user for creating a new account or editing a...
utility functions for the GnuCash UI
Expense accounts are used to denote expenses.
Definition: Account.h:143
gpointer gnc_table_get_vcell_data(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell data associated with a cursor located at the given virtual coords...
Definition: table-allgui.c:932
STRUCTS.
holds information about each virtual cell.
Definition: table-allgui.h:132
TableModel * gnc_entry_ledger_model_new(GncEntryLedgerType type)
Public Interface.
GncEntry * gnc_entry_ledger_get_entry(GncEntryLedger *ledger, VirtualCellLocation vcell_loc)
Returns the GncEntry at the given location, or NULL if the location is not valid. ...
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
void gnc_entry_ledger_move_current_entry_updown(GncEntryLedger *ledger, gboolean move_up)
This implements the command of moving the current entry (where the cursor is currently located) one r...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
GDate time64_to_gdate(time64 t)
Returns the GDate in which the time64 occurs.
Definition: gnc-date.cpp:1211
GncEntryLedger * gnc_entry_ledger_new(QofBook *book, GncEntryLedgerType type)
Create and return a new GncEntry Ledger.
gnc_numeric gncAccountValueTotal(GList *list)
return the total for this list
Definition: gncTaxTable.c:984
void gncInvoiceSortEntries(GncInvoice *invoice)
Call this function when an Entry is changed and you want to re-sort the list of entries.
Definition: gncInvoice.c:751
time64 gncEntryGetDate(const GncEntry *entry)
DEPRECATED - use gncEntryGetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:913
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
tax is a number
Definition: gncTaxTable.h:80
char * gnc_get_account_name_for_register(const Account *account)
Get either the full name of the account or the simple name, depending on the configuration parameter ...
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
Definition: combocell.h:52
GncEntry * gnc_entry_ledger_get_current_entry(GncEntryLedger *ledger)
Returns the Entry where the cursor is currently located.
void gncEntryComputeValue(gnc_numeric qty, gnc_numeric price, const GncTaxTable *tax_table, gboolean tax_included, gnc_numeric discount, GncAmountType discount_type, GncDiscountHow discount_how, int SCU, gnc_numeric *value, gnc_numeric *discount_value, GList **tax_values)
Compute the Entry value, tax_value, and discount_value, based on the quantity, price, discount, tax_-table, and types.
Income accounts are used to denote income.
Definition: Account.h:140
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
The gnc_account_lookup_by_code() subroutine works like gnc_account_lookup_by_name, but uses the account code.
Definition: Account.cpp:3051
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:54
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
Add a menu item to the list.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
void gnc_entry_ledger_set_default_order(GncEntryLedger *ledger, GncOrder *order)
Set the default order for this ledger.
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
void gnc_combo_cell_set_strict(ComboCell *cell, gboolean strict)
Determines whether the cell will accept strings not in the menu.
#define gncInvoiceGetGUID(x)
deprecated functions
Definition: gncInvoice.h:315
GDate gncEntryGetDateGDate(const GncEntry *entry)
Returns the day of this entry.
Definition: gncEntry.c:918
void gnc_table_set_vcell(Table *table, CellBlock *cursor, gconstpointer vcell_data, gboolean visible, gboolean start_primary_color, VirtualCellLocation vcell_loc)
Indicate what handler should be used for a given virtual block.
Definition: table-allgui.c:664
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Combine two queries together using the Boolean set (logical) operator &#39;op&#39;.
Definition: qofquery.cpp:1129
void gncEntrySetDateGDate(GncEntry *entry, const GDate *date)
Set the date of this entry.
Definition: gncEntry.c:504
void gncAccountValueDestroy(GList *list)
Destroy a list of accountvalues.
Definition: gncTaxTable.c:997
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:116
void qof_query_add_guid_match(QofQuery *q, QofQueryParamList *param_list, const GncGUID *guid, QofQueryOp op)
DOCUMENT ME !!
Definition: qofquery.cpp:1310
Account * gnc_account_lookup_for_register(const Account *base_account, const char *name)
Retrieve the account matching the given name starting from the descendants of base_account.
unsigned int visible
Used by higher-level code.
Definition: table-allgui.h:138
void gnc_entry_ledger_destroy(GncEntryLedger *ledger)
Destroy the GncEntry Ledger.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
liability (and asset) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:119
Account * gnc_ui_new_accounts_from_name_with_defaults(GtkWindow *parent, const char *name, GList *valid_types, const gnc_commodity *default_commodity, Account *parent_acct)
Display a modal window for creating a new account.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4179
void gnc_entry_ledger_set_default_invoice(GncEntryLedger *ledger, GncInvoice *invoice)
Set the default invoice for this ledger.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
The CheckboxCell object implements a cell handler that will toggle between yes and no values when cli...
Definition: checkboxcell.h:40
Table * gnc_entry_ledger_get_table(GncEntryLedger *ledger)
Get the Table.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void qof_query_add_boolean_match(QofQuery *q, QofQueryParamList *param_list, gboolean value, QofQueryOp op)
Handy-dandy convenience routines, avoids having to create a separate predicate for boolean matches...
Definition: qofquery.cpp:1347
Business Entry Interface.
gboolean gnc_entry_ledger_get_entry_virt_loc(GncEntryLedger *ledger, const GncEntry *entry, VirtualCellLocation *vcell_loc)
Looks up the cell location of the given "entry" and writes the location into the variable pointed to ...
The type used to store guids in C.
Definition: guid.h:75
A Query.
Definition: qofquery.cpp:74
GncEntry * gnc_entry_ledger_get_blank_entry(GncEntryLedger *ledger)
Exported Functions.
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition: pricecell.c:208
void gnc_table_move_cursor(Table *table, VirtualLocation new_virt_loc)
will move the cursor (but not the cursor GUI) to the indicated location.
Definition: table-allgui.c:878
gboolean gnc_entry_ledger_commit_entry(GncEntryLedger *ledger)
This will act just like hitting &#39;return&#39; to record an entry.
modtime is the internal date of the last modtime See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following Code that handles refcount, parent, child, invisible and children is identical to that in ::GncBillTerm
void gnc_combo_cell_set_autosize(ComboCell *cell, gboolean autosize)
Determines whether the popup list autosizes itself or uses all available space.
The Credit card account is used to denote credit (e.g.
Definition: Account.h:113
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).
Definition: gnc-date.cpp:1225