GnuCash  4.8a-132-gcdaeb421d+
gncEntry.c
1 /********************************************************************\
2  * gncEntry.c -- the Core Business Entry Interface *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20  * *
21 \********************************************************************/
22 
23 /*
24  * Copyright (C) 2001,2002 Derek Atkins
25  * Author: Derek Atkins <warlord@MIT.EDU>
26  */
27 
28 #include <config.h>
29 
30 #include <glib.h>
31 #include <qofinstance-p.h>
32 
33 #include "gnc-commodity.h"
34 
35 #include "gncEntry.h"
36 #include "gncEntryP.h"
37 #include "gnc-features.h"
38 #include "gncInvoice.h"
39 #include "gncOrder.h"
40 
41 struct _gncEntry
42 {
43  QofInstance inst;
44 
45  time64 date;
46  time64 date_entered;
47  const char * desc;
48  const char * action;
49  const char * notes;
50  gnc_numeric quantity;
51 
52  /* customer invoice data */
53  Account * i_account;
54  gnc_numeric i_price;
55  gboolean i_taxable;
56  gboolean i_taxincluded;
57  GncTaxTable * i_tax_table;
58  gnc_numeric i_discount;
59  GncAmountType i_disc_type;
60  GncDiscountHow i_disc_how;
61 
62  /* vendor bill data */
63  Account * b_account;
64  gnc_numeric b_price;
65  gboolean b_taxable;
66  gboolean b_taxincluded;
67  GncTaxTable * b_tax_table;
68  gboolean billable;
69  GncOwner billto;
70 
71  /* employee bill data */
72  GncEntryPaymentType b_payment;
73 
74  /* my parent(s) */
75  GncOrder * order;
76  GncInvoice * invoice;
77  GncInvoice * bill;
78 
79  /* CACHED VALUES */
80  gboolean values_dirty;
81 
82  /* customer invoice */
83  gnc_numeric i_value;
84  gnc_numeric i_value_rounded;
85  GList * i_tax_values;
86  gnc_numeric i_tax_value;
87  gnc_numeric i_tax_value_rounded;
88  gnc_numeric i_disc_value;
89  gnc_numeric i_disc_value_rounded;
90  time64 i_taxtable_modtime;
91 
92  /* vendor bill */
93  gnc_numeric b_value;
94  gnc_numeric b_value_rounded;
95  GList * b_tax_values;
96  gnc_numeric b_tax_value;
97  gnc_numeric b_tax_value_rounded;
98  time64 b_taxtable_modtime;
99 };
100 
102 {
103  QofInstanceClass parent_class;
104 };
105 
106 static QofLogModule log_module = GNC_MOD_BUSINESS;
107 
108 
109 /* You must edit the functions in this block in tandem.
110  * KEEP THIS FUNCTION IN SYNC with the one below! */
111 const char *
112 gncEntryDiscountHowToString (GncDiscountHow how)
113 {
114  switch (how)
115  {
116  case (GNC_DISC_PRETAX):
117  return "PRETAX";
118  case (GNC_DISC_SAMETIME):
119  return "SAMETIME";
120  case (GNC_DISC_POSTTAX):
121  return "POSTTAX";
122  default:
123  g_warning ("asked to translate unknown discount-how %d.\n", how);
124  break;
125  }
126  return NULL;
127 }
128 
129 /* You must edit the functions in this block in tandem.
130  * KEEP THIS FUNCTION IN SYNC with the one above! */
131 gboolean gncEntryDiscountStringToHow (const char *str, GncDiscountHow *how)
132 {
133  if (g_strcmp0 ("PRETAX", str) == 0)
134  {
135  *how = GNC_DISC_PRETAX;
136  return TRUE;
137  }
138  if (g_strcmp0 ("SAMETIME", str) == 0)
139  {
140  *how = GNC_DISC_SAMETIME;
141  return TRUE;
142  }
143  if (g_strcmp0 ("POSTTAX", str) == 0)
144  {
145  *how = GNC_DISC_POSTTAX;
146  return TRUE;
147  }
148  g_warning ("asked to translate unknown discount-how string %s.\n",
149  str ? str : "(null)");
150 
151  return FALSE;
152 }
153 
154 /* You must edit the functions in this block in tandem.
155  * KEEP THIS FUNCTION IN SYNC with the one below! */
156 const char * gncEntryPaymentTypeToString (GncEntryPaymentType type)
157 {
158  switch (type)
159  {
160  case (GNC_PAYMENT_CASH):
161  return "CASH";
162  case (GNC_PAYMENT_CARD):
163  return "CARD";
164  default:
165  g_warning ("asked to translate unknown payment type %d.\n", type);
166  break;
167  }
168  return NULL ;
169 }
170 
171 /* You must edit the functions in this block in tandem.
172  * KEEP THIS FUNCTION IN SYNC with the one above! */
173 gboolean gncEntryPaymentStringToType (const char *str, GncEntryPaymentType *type)
174 {
175  if (g_strcmp0 ("CASH", str) == 0)
176  {
177  *type = GNC_PAYMENT_CASH;
178  return TRUE;
179  }
180  if (g_strcmp0 ("CARD", str) == 0)
181  {
182  *type = GNC_PAYMENT_CARD;
183  return TRUE;
184  }
185  g_warning ("asked to translate unknown discount-how string %s.\n",
186  str ? str : "(null)");
187 
188  return FALSE;
189 }
190 
191 #define _GNC_MOD_NAME GNC_ID_ENTRY
192 
193 #define SET_STR(obj, member, str) { \
194  if (!g_strcmp0 (member, str)) return; \
195  gncEntryBeginEdit (obj); \
196  CACHE_REPLACE (member, str); \
197  }
198 
199 static inline void mark_entry (GncEntry *entry);
200 void mark_entry (GncEntry *entry)
201 {
202  qof_instance_set_dirty(&entry->inst);
203  qof_event_gen (&entry->inst, QOF_EVENT_MODIFY, NULL);
204 }
205 
206 /* ================================================================ */
207 
208 enum
209 {
210  PROP_0,
211 // PROP_DATE, /* Table */
212 // PROP_DATE_ENTERED, /* Table */
213  PROP_DESCRIPTION, /* Table */
214 // PROP_ACTION, /* Table */
215 // PROP_NOTES, /* Table */
216 // PROP_QUANTITY, /* Table (numeric) */
217 // PROP_I_ACCT, /* Table */
218 // PROP_I_PRICE, /* Table (numeric) */
219 // PROP_I_DISCOUNT, /* Table (numeric) */
220 // PROP_INVOICE, /* Table */
221 // PROP_I_DISC_TYPE, /* Table */
222 // PROP_I_DISC_HOW, /* Table */
223 // PROP_I_TAXABLE, /* Table */
224 // PROP_I_TAX_INCL, /* Table */
225 // PROP_I_TAXTABLE, /* Table */
226 // PROP_B_ACCT, /* Table */
227 // PROP_B_PRICE, /* Table (numeric) */
228 // PROP_BILL, /* Table */
229 // PROP_B_TAXTABLE_1, /* Table */
230 // PROP_B_TAX_INCL, /* Table */
231 // PROP_B_TAXTABLE, /* Table */
232 // PROP_B_PAYTYPE, /* Table */
233 // PROP_BILLABLE, /* Table */
234 // PROP_BILLTO_TYPE, /* Table */
235 // PROP_BILLTO, /* Table */
236 // PROP_ORDER, /* Table */
237 };
238 
239 /* GObject Initialization */
240 G_DEFINE_TYPE(GncEntry, gnc_entry, QOF_TYPE_INSTANCE);
241 
242 static void
243 gnc_entry_init(GncEntry* entry)
244 {
245 }
246 
247 static void
248 gnc_entry_dispose(GObject *entryp)
249 {
250  G_OBJECT_CLASS(gnc_entry_parent_class)->dispose(entryp);
251 }
252 
253 static void
254 gnc_entry_finalize(GObject* entryp)
255 {
256  G_OBJECT_CLASS(gnc_entry_parent_class)->finalize(entryp);
257 }
258 
259 static void
260 gnc_entry_get_property (GObject *object,
261  guint prop_id,
262  GValue *value,
263  GParamSpec *pspec)
264 {
265  GncEntry *entry;
266 
267  g_return_if_fail(GNC_IS_ENTRY(object));
268 
269  entry = GNC_ENTRY(object);
270  switch (prop_id)
271  {
272  case PROP_DESCRIPTION:
273  g_value_set_string(value, entry->desc);
274  break;
275  default:
276  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
277  break;
278  }
279 }
280 
281 static void
282 gnc_entry_set_property (GObject *object,
283  guint prop_id,
284  const GValue *value,
285  GParamSpec *pspec)
286 {
287  GncEntry *entry;
288 
289  g_return_if_fail(GNC_IS_ENTRY(object));
290 
291  entry = GNC_ENTRY(object);
292  g_assert (qof_instance_get_editlevel(entry));
293 
294  switch (prop_id)
295  {
296  case PROP_DESCRIPTION:
297  gncEntrySetDescription(entry, g_value_get_string(value));
298  break;
299  default:
300  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
301  break;
302  }
303 }
304 
306 static gchar*
307 impl_get_display_name(const QofInstance* inst)
308 {
309  GncEntry* entry;
310  gchar* display_name;
311  gchar* s;
312 
313  g_return_val_if_fail(inst != NULL, FALSE);
314  g_return_val_if_fail(GNC_IS_ENTRY(inst), FALSE);
315 
316  entry = GNC_ENTRY(inst);
317  if (entry->order != NULL)
318  {
319  display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->order));
320  s = g_strdup_printf("Entry in %s", display_name);
321  g_free(display_name);
322  return s;
323  }
324  if (entry->invoice != NULL)
325  {
326  display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->invoice));
327  s = g_strdup_printf("Entry in %s", display_name);
328  g_free(display_name);
329  return s;
330  }
331  if (entry->bill != NULL)
332  {
333  display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->bill));
334  s = g_strdup_printf("Entry in %s", display_name);
335  g_free(display_name);
336  return s;
337  }
338 
339  return g_strdup_printf("Entry %p", inst);
340 }
341 
343 static gboolean
344 impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
345 {
346  GncEntry* entry;
347 
348  g_return_val_if_fail(inst != NULL, FALSE);
349  g_return_val_if_fail(GNC_IS_ENTRY(inst), FALSE);
350 
351  entry = GNC_ENTRY(inst);
352 
353  if (GNC_IS_ACCOUNT(ref))
354  {
355  Account* acc = GNC_ACCOUNT(ref);
356  return (entry->i_account == acc || entry->b_account == acc);
357  }
358  else if (GNC_IS_TAXTABLE(ref))
359  {
360  GncTaxTable* tt = GNC_TAXTABLE(ref);
361  return (entry->i_tax_table == tt || entry->b_tax_table == tt);
362  }
363 
364  return FALSE;
365 }
366 
373 static GList*
374 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
375 {
376  if (!GNC_IS_ACCOUNT(ref) && !GNC_IS_TAXTABLE(ref))
377  {
378  return NULL;
379  }
380 
382 }
383 
384 static void
385 gnc_entry_class_init (GncEntryClass *klass)
386 {
387  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
388  QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
389 
390  gobject_class->dispose = gnc_entry_dispose;
391  gobject_class->finalize = gnc_entry_finalize;
392  gobject_class->set_property = gnc_entry_set_property;
393  gobject_class->get_property = gnc_entry_get_property;
394 
395  qof_class->get_display_name = impl_get_display_name;
396  qof_class->refers_to_object = impl_refers_to_object;
397  qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
398 
399  g_object_class_install_property
400  (gobject_class,
401  PROP_DESCRIPTION,
402  g_param_spec_string ("description",
403  "Entry Description",
404  "The description is an arbitrary string "
405  "assigned by the user. It provides identification "
406  "for this entry.",
407  NULL,
408  G_PARAM_READWRITE));
409 }
410 
411 /* Create/Destroy Functions */
412 GncEntry *gncEntryCreate (QofBook *book)
413 {
414  GncEntry *entry;
415  gnc_numeric zero = gnc_numeric_zero ();
416 
417  if (!book) return NULL;
418 
419  entry = g_object_new (GNC_TYPE_ENTRY, NULL);
420  qof_instance_init_data (&entry->inst, _GNC_MOD_NAME, book);
421 
422  entry->desc = CACHE_INSERT ("");
423  entry->action = CACHE_INSERT ("");
424  entry->notes = CACHE_INSERT ("");
425  entry->quantity = zero;
426 
427  entry->i_price = zero;
428  entry->i_taxable = TRUE;
429  entry->i_discount = zero;
430  entry->i_disc_type = GNC_AMT_TYPE_PERCENT;
431  entry->i_disc_how = GNC_DISC_PRETAX;
432 
433  entry->b_price = zero;
434  entry->b_taxable = TRUE;
435  entry->billto.type = GNC_OWNER_CUSTOMER;
436  entry->b_payment = GNC_PAYMENT_CASH;
437 
438  entry->values_dirty = TRUE;
439 
440  qof_event_gen (&entry->inst, QOF_EVENT_CREATE, NULL);
441 
442  return entry;
443 }
444 
445 void gncEntryDestroy (GncEntry *entry)
446 {
447  if (!entry) return;
448  qof_instance_set_destroying(entry, TRUE);
449  gncEntryCommitEdit(entry);
450 }
451 
452 static void gncEntryFree (GncEntry *entry)
453 {
454  if (!entry) return;
455 
456  qof_event_gen (&entry->inst, QOF_EVENT_DESTROY, NULL);
457 
458  CACHE_REMOVE (entry->desc);
459  CACHE_REMOVE (entry->action);
460  CACHE_REMOVE (entry->notes);
461  if (entry->i_tax_values)
462  gncAccountValueDestroy (entry->i_tax_values);
463  if (entry->b_tax_values)
464  gncAccountValueDestroy (entry->b_tax_values);
465  if (entry->i_tax_table)
466  gncTaxTableDecRef (entry->i_tax_table);
467  if (entry->b_tax_table)
468  gncTaxTableDecRef (entry->b_tax_table);
469 
470  /* qof_instance_release (&entry->inst); */
471  g_object_unref (entry);
472 }
473 
474 /* ================================================================ */
475 /* Set Functions */
476 
477 void gncEntrySetDate (GncEntry *entry, time64 date)
478 {
479  gboolean first_date = FALSE;
480  if (!entry) return;
481  if (entry->date == date) return;
482  if (!entry->date)
483  first_date = TRUE;
484  gncEntryBeginEdit (entry);
485  entry->date = date;
486  mark_entry (entry);
487  gncEntryCommitEdit (entry);
488 
489  /* Don't re-sort the first time we set the date on this entry */
490  if (!first_date)
491  {
492  if (entry->invoice)
493  gncInvoiceSortEntries(entry->invoice);
494  if (entry->bill)
495  gncInvoiceSortEntries(entry->bill);
496  }
497 }
498 
499 void gncEntrySetDateGDate (GncEntry *entry, const GDate* date)
500 {
501  if (!entry || !date || !g_date_valid(date))
502  return;
503 
504  /* Watch out: Here we are deviating from the initial convention that a
505  GDate always converts to the start time of the day. Instead, the GDate is
506  converted to "noon" on the respective date. This is not nice, but this
507  convention was used for the time64 of GncEntry all the time, so we better
508  stick to it.*/
510 }
511 
512 void gncEntrySetDateEntered (GncEntry *entry, time64 date)
513 {
514  if (!entry) return;
515  if (entry->date_entered == date) return;
516  gncEntryBeginEdit (entry);
517  entry->date_entered = date;
518  mark_entry (entry);
519  gncEntryCommitEdit (entry);
520 }
521 
522 void gncEntrySetDescription (GncEntry *entry, const char *desc)
523 {
524  if (!entry || !desc) return;
525  SET_STR (entry, entry->desc, desc);
526  mark_entry (entry);
527  gncEntryCommitEdit (entry);
528 }
529 
530 void gncEntrySetAction (GncEntry *entry, const char *action)
531 {
532  if (!entry || !action) return;
533  SET_STR (entry, entry->action, action);
534  mark_entry (entry);
535  gncEntryCommitEdit (entry);
536 }
537 
538 void gncEntrySetNotes (GncEntry *entry, const char *notes)
539 {
540  if (!entry || !notes) return;
541  SET_STR (entry, entry->notes, notes);
542  mark_entry (entry);
543  gncEntryCommitEdit (entry);
544 }
545 
546 void gncEntrySetQuantity (GncEntry *entry, gnc_numeric quantity)
547 {
548  if (!entry) return;
549  if (gnc_numeric_eq (entry->quantity, quantity)) return;
550  gncEntryBeginEdit (entry);
551  entry->quantity = quantity;
552  entry->values_dirty = TRUE;
553  mark_entry (entry);
554  gncEntryCommitEdit (entry);
555 }
556 
557 void gncEntrySetDocQuantity (GncEntry *entry, gnc_numeric quantity, gboolean is_cn)
558 {
559  if (!entry) return;
560  if (gnc_numeric_eq (entry->quantity, (is_cn ? gnc_numeric_neg (quantity) : quantity))) return;
561  gncEntryBeginEdit (entry);
562  entry->quantity = (is_cn ? gnc_numeric_neg (quantity) : quantity);
563  entry->values_dirty = TRUE;
564  mark_entry (entry);
565  gncEntryCommitEdit (entry);
566 }
567 
568 /* Customer Invoices */
569 
570 void gncEntrySetInvAccount (GncEntry *entry, Account *acc)
571 {
572  if (!entry) return;
573  if (entry->i_account == acc) return;
574  gncEntryBeginEdit (entry);
575  entry->i_account = acc;
576  mark_entry (entry);
577  gncEntryCommitEdit (entry);
578 }
579 
580 void gncEntrySetInvPrice (GncEntry *entry, gnc_numeric price)
581 {
582  if (!entry) return;
583  if (gnc_numeric_eq (entry->i_price, price)) return;
584  gncEntryBeginEdit (entry);
585  entry->i_price = price;
586  entry->values_dirty = TRUE;
587  mark_entry (entry);
588  gncEntryCommitEdit (entry);
589 }
590 
591 void gncEntrySetInvTaxable (GncEntry *entry, gboolean taxable)
592 {
593  if (!entry) return;
594  if (entry->i_taxable == taxable) return;
595  gncEntryBeginEdit (entry);
596  entry->i_taxable = taxable;
597  entry->values_dirty = TRUE;
598  mark_entry (entry);
599  gncEntryCommitEdit (entry);
600 }
601 
602 void gncEntrySetInvTaxIncluded (GncEntry *entry, gboolean taxincluded)
603 {
604  if (!entry) return;
605  if (entry->i_taxincluded == taxincluded) return;
606  gncEntryBeginEdit (entry);
607  entry->i_taxincluded = taxincluded;
608  entry->values_dirty = TRUE;
609  mark_entry (entry);
610  gncEntryCommitEdit (entry);
611 }
612 
613 void gncEntrySetInvTaxTable (GncEntry *entry, GncTaxTable *table)
614 {
615  if (!entry) return;
616  if (entry->i_tax_table == table) return;
617  gncEntryBeginEdit (entry);
618  if (entry->i_tax_table)
619  gncTaxTableDecRef (entry->i_tax_table);
620  if (table)
621  gncTaxTableIncRef (table);
622  entry->i_tax_table = table;
623  entry->values_dirty = TRUE;
624  mark_entry (entry);
625  gncEntryCommitEdit (entry);
626 }
627 
628 void gncEntrySetInvDiscount (GncEntry *entry, gnc_numeric discount)
629 {
630  if (!entry) return;
631  if (gnc_numeric_eq (entry->i_discount, discount)) return;
632  gncEntryBeginEdit (entry);
633  entry->i_discount = discount;
634  entry->values_dirty = TRUE;
635  mark_entry (entry);
636  gncEntryCommitEdit (entry);
637 }
638 
639 void gncEntrySetInvDiscountType (GncEntry *entry, GncAmountType type)
640 {
641  if (!entry) return;
642  if (entry->i_disc_type == type) return;
643 
644  gncEntryBeginEdit (entry);
645  entry->i_disc_type = type;
646  entry->values_dirty = TRUE;
647  mark_entry (entry);
648  gncEntryCommitEdit (entry);
649 }
650 
651 void gncEntrySetInvDiscountHow (GncEntry *entry, GncDiscountHow how)
652 {
653  if (!entry) return;
654  if (entry->i_disc_how == how) return;
655 
656  gncEntryBeginEdit (entry);
657  entry->i_disc_how = how;
658  entry->values_dirty = TRUE;
659  mark_entry (entry);
660  gncEntryCommitEdit (entry);
661 }
662 
663 void qofEntrySetInvDiscType (GncEntry *entry, const char *type_string)
664 {
665  GncAmountType type;
666 
667  if (!entry) return;
668  gncAmountStringToType(type_string, &type);
669  if (entry->i_disc_type == type) return;
670  gncEntryBeginEdit (entry);
671  entry->i_disc_type = type;
672  entry->values_dirty = TRUE;
673  mark_entry (entry);
674  gncEntryCommitEdit (entry);
675 
676 }
677 
678 void qofEntrySetInvDiscHow (GncEntry *entry, const char *type)
679 {
680  GncDiscountHow how = GNC_DISC_PRETAX;
681 
682  if (!entry) return;
683  gncEntryBeginEdit (entry);
684  gncEntryDiscountStringToHow(type, &how);
685  if (entry->i_disc_how == how) return;
686  entry->i_disc_how = how;
687  entry->values_dirty = TRUE;
688  mark_entry (entry);
689  gncEntryCommitEdit (entry);
690 }
691 
692 /* Vendor Bills */
693 
694 void gncEntrySetBillAccount (GncEntry *entry, Account *acc)
695 {
696  if (!entry) return;
697  if (entry->b_account == acc) return;
698  gncEntryBeginEdit (entry);
699  entry->b_account = acc;
700  mark_entry (entry);
701  gncEntryCommitEdit (entry);
702 }
703 
704 void gncEntrySetBillPrice (GncEntry *entry, gnc_numeric price)
705 {
706  if (!entry) return;
707  if (gnc_numeric_eq (entry->b_price, price)) return;
708  gncEntryBeginEdit (entry);
709  entry->b_price = price;
710  entry->values_dirty = TRUE;
711  mark_entry (entry);
712  gncEntryCommitEdit (entry);
713 }
714 
715 void gncEntrySetBillTaxable (GncEntry *entry, gboolean taxable)
716 {
717  if (!entry) return;
718  if (entry->b_taxable == taxable) return;
719  gncEntryBeginEdit (entry);
720  entry->b_taxable = taxable;
721  entry->values_dirty = TRUE;
722  mark_entry (entry);
723  gncEntryCommitEdit (entry);
724 }
725 
726 void gncEntrySetBillTaxIncluded (GncEntry *entry, gboolean taxincluded)
727 {
728  if (!entry) return;
729  if (entry->b_taxincluded == taxincluded) return;
730  gncEntryBeginEdit (entry);
731  entry->b_taxincluded = taxincluded;
732  entry->values_dirty = TRUE;
733  mark_entry (entry);
734  gncEntryCommitEdit (entry);
735 }
736 
737 void gncEntrySetBillTaxTable (GncEntry *entry, GncTaxTable *table)
738 {
739  if (!entry) return;
740  if (entry->b_tax_table == table) return;
741  gncEntryBeginEdit (entry);
742  if (entry->b_tax_table)
743  gncTaxTableDecRef (entry->b_tax_table);
744  if (table)
745  gncTaxTableIncRef (table);
746  entry->b_tax_table = table;
747  entry->values_dirty = TRUE;
748  mark_entry (entry);
749  gncEntryCommitEdit (entry);
750 }
751 
752 void gncEntrySetBillable (GncEntry *entry, gboolean billable)
753 {
754  if (!entry) return;
755  if (entry->billable == billable) return;
756 
757  gncEntryBeginEdit (entry);
758  entry->billable = billable;
759  mark_entry (entry);
760  gncEntryCommitEdit (entry);
761 }
762 
763 void gncEntrySetBillTo (GncEntry *entry, GncOwner *billto)
764 {
765  if (!entry || !billto) return;
766  if (gncOwnerEqual (&entry->billto, billto)) return;
767 
768  gncEntryBeginEdit (entry);
769  gncOwnerCopy (billto, &entry->billto);
770  mark_entry (entry);
771  gncEntryCommitEdit (entry);
772 }
773 
774 void gncEntrySetBillPayment (GncEntry *entry, GncEntryPaymentType type)
775 {
776  if (!entry) return;
777  if (entry->b_payment == type) return;
778  gncEntryBeginEdit (entry);
779  entry->b_payment = type;
780  mark_entry (entry);
781  gncEntryCommitEdit (entry);
782 }
783 
784 /* Called from gncOrder when we're added to the Order */
785 void gncEntrySetOrder (GncEntry *entry, GncOrder *order)
786 {
787  if (!entry) return;
788  if (entry->order == order) return;
789  gncEntryBeginEdit (entry);
790  entry->order = order;
791  mark_entry (entry);
792  gncEntryCommitEdit (entry);
793 
794 }
795 
796 /* called from gncInvoice when we're added to the Invoice */
797 void gncEntrySetInvoice (GncEntry *entry, GncInvoice *invoice)
798 {
799  if (!entry) return;
800  if (entry->invoice == invoice) return;
801  gncEntryBeginEdit (entry);
802  entry->invoice = invoice;
803  mark_entry (entry);
804  gncEntryCommitEdit (entry);
805 }
806 
807 /* called from gncInvoice when we're added to the Invoice/Bill */
808 void gncEntrySetBill (GncEntry *entry, GncInvoice *bill)
809 {
810  if (!entry) return;
811  if (entry->bill == bill) return;
812  gncEntryBeginEdit (entry);
813  entry->bill = bill;
814  mark_entry (entry);
815  gncEntryCommitEdit (entry);
816 }
817 
818 void gncEntryCopy (const GncEntry *src, GncEntry *dest, gboolean add_entry)
819 {
820  if (!src || !dest) return;
821 
822  gncEntryBeginEdit (dest);
823  dest->date = src->date;
824  dest->date_entered = src->date_entered; /* ??? */
825  gncEntrySetDescription (dest, src->desc);
826  gncEntrySetAction (dest, src->action);
827  gncEntrySetNotes (dest, src->notes);
828  dest->quantity = src->quantity;
829 
830  dest->i_account = src->i_account;
831  dest->i_price = src->i_price;
832  dest->i_taxable = src->i_taxable;
833  dest->i_taxincluded = src->i_taxincluded;
834  dest->i_discount = src->i_discount;
835  dest->i_disc_type = src->i_disc_type;
836  dest->i_disc_how = src->i_disc_how;
837 
838  /* vendor bill data */
839  dest->b_account = src->b_account;
840  dest->b_price = src->b_price;
841  dest->b_taxable = src->b_taxable;
842  dest->b_taxincluded = src->b_taxincluded;
843  dest->billable = src->billable;
844  dest->billto = src->billto;
845 
846  if (src->i_tax_table)
847  gncEntrySetInvTaxTable (dest, src->i_tax_table);
848 
849  if (src->b_tax_table)
850  gncEntrySetBillTaxTable (dest, src->b_tax_table);
851 
852  if (add_entry)
853  {
854  if (src->order)
855  gncOrderAddEntry (src->order, dest);
856 
857  if (src->invoice)
858  gncInvoiceAddEntry (src->invoice, dest);
859 
860  if (src->bill)
861  gncBillAddEntry (src->bill, dest);
862  }
863 
864  dest->values_dirty = TRUE;
865  mark_entry (dest);
866  gncEntryCommitEdit (dest);
867 }
868 
869 /* ================================================================ */
870 /* Get Functions */
871 
872 time64 gncEntryGetDate (const GncEntry *entry)
873 {
874  return entry ? entry->date : 0;
875 }
876 
877 GDate gncEntryGetDateGDate(const GncEntry *entry)
878 {
879  return time64_to_gdate(gncEntryGetDate(entry));
880 }
881 
882 time64 gncEntryGetDateEntered (const GncEntry *entry)
883 {
884  return entry ? entry->date_entered : 0;
885 }
886 
887 const char * gncEntryGetDescription (const GncEntry *entry)
888 {
889  if (!entry) return NULL;
890  return entry->desc;
891 }
892 
893 const char * gncEntryGetAction (const GncEntry *entry)
894 {
895  if (!entry) return NULL;
896  return entry->action;
897 }
898 
899 const char * gncEntryGetNotes (const GncEntry *entry)
900 {
901  if (!entry) return NULL;
902  return entry->notes;
903 }
904 
905 gnc_numeric gncEntryGetQuantity (const GncEntry *entry)
906 {
907  if (!entry) return gnc_numeric_zero();
908  return entry->quantity;
909 }
910 
911 gnc_numeric gncEntryGetDocQuantity (const GncEntry *entry, gboolean is_cn)
912 {
913  gnc_numeric value = gncEntryGetQuantity (entry);
914  return (is_cn ? gnc_numeric_neg (value) : value);
915 }
916 
917 /* Customer Invoice */
918 
919 Account * gncEntryGetInvAccount (const GncEntry *entry)
920 {
921  if (!entry) return NULL;
922  return entry->i_account;
923 }
924 
925 gnc_numeric gncEntryGetInvPrice (const GncEntry *entry)
926 {
927  if (!entry) return gnc_numeric_zero();
928  return entry->i_price;
929 }
930 
931 gnc_numeric gncEntryGetInvDiscount (const GncEntry *entry)
932 {
933  if (!entry) return gnc_numeric_zero();
934  return entry->i_discount;
935 }
936 
937 GncAmountType gncEntryGetInvDiscountType (const GncEntry *entry)
938 {
939  if (!entry) return 0;
940  return entry->i_disc_type;
941 }
942 
943 GncDiscountHow gncEntryGetInvDiscountHow (const GncEntry *entry)
944 {
945  if (!entry) return 0;
946  return entry->i_disc_how;
947 }
948 
949 char* qofEntryGetInvDiscType (const GncEntry *entry)
950 {
951  char *type_string;
952 
953  if (!entry) return 0;
954  type_string = g_strdup(gncAmountTypeToString(entry->i_disc_type));
955  return type_string;
956 }
957 
958 char* qofEntryGetInvDiscHow (const GncEntry *entry)
959 {
960  char *type_string;
961 
962  if (!entry) return 0;
963  type_string = g_strdup(gncEntryDiscountHowToString(entry->i_disc_how));
964  return type_string;
965 }
966 
967 gboolean gncEntryGetInvTaxable (const GncEntry *entry)
968 {
969  if (!entry) return FALSE;
970  return entry->i_taxable;
971 }
972 
973 gboolean gncEntryGetInvTaxIncluded (const GncEntry *entry)
974 {
975  if (!entry) return FALSE;
976  return entry->i_taxincluded;
977 }
978 
979 GncTaxTable * gncEntryGetInvTaxTable (const GncEntry *entry)
980 {
981  if (!entry) return NULL;
982  return entry->i_tax_table;
983 }
984 
985 /* vendor bills */
986 
987 Account * gncEntryGetBillAccount (const GncEntry *entry)
988 {
989  if (!entry) return NULL;
990  return entry->b_account;
991 }
992 
993 gnc_numeric gncEntryGetBillPrice (const GncEntry *entry)
994 {
995  if (!entry) return gnc_numeric_zero();
996  return entry->b_price;
997 }
998 
999 gboolean gncEntryGetBillTaxable (const GncEntry *entry)
1000 {
1001  if (!entry) return FALSE;
1002  return entry->b_taxable;
1003 }
1004 
1005 gboolean gncEntryGetBillTaxIncluded (const GncEntry *entry)
1006 {
1007  if (!entry) return FALSE;
1008  return entry->b_taxincluded;
1009 }
1010 
1011 GncTaxTable * gncEntryGetBillTaxTable (const GncEntry *entry)
1012 {
1013  if (!entry) return NULL;
1014  return entry->b_tax_table;
1015 }
1016 
1017 gboolean gncEntryGetBillable (const GncEntry *entry)
1018 {
1019  if (!entry) return FALSE;
1020  return entry->billable;
1021 }
1022 
1023 GncOwner * gncEntryGetBillTo (GncEntry *entry)
1024 {
1025  if (!entry) return NULL;
1026  return &entry->billto;
1027 }
1028 
1029 GncEntryPaymentType gncEntryGetBillPayment (const GncEntry* entry)
1030 {
1031  if (!entry) return 0;
1032  return entry->b_payment;
1033 }
1034 
1035 GncInvoice * gncEntryGetInvoice (const GncEntry *entry)
1036 {
1037  if (!entry) return NULL;
1038  return entry->invoice;
1039 }
1040 
1041 GncInvoice * gncEntryGetBill (const GncEntry *entry)
1042 {
1043  if (!entry) return NULL;
1044  return entry->bill;
1045 }
1046 
1047 GncOrder * gncEntryGetOrder (const GncEntry *entry)
1048 {
1049  if (!entry) return NULL;
1050  return entry->order;
1051 }
1052 
1053 /* ================================================================ */
1054 /*
1055  * This is the logic of computing the total for an Entry, so you know
1056  * what values to put into various Splits or to display in the ledger.
1057  * In other words, we combine the quantity, unit-price, discount and
1058  * taxes together, depending on various flags.
1059  *
1060  * There are four potential ways to combine these numbers:
1061  * Discount: Pre-Tax Post-Tax
1062  * Tax : Included Not-Included
1063  *
1064  * The process is relatively simple:
1065  *
1066  * 1) compute the aggregate price (price*qty)
1067  * 2) if taxincluded, then back-compute the aggregate pre-tax price
1068  * 3) apply discount and taxes in the appropriate order
1069  * 4) return the requested results.
1070  *
1071  * Step 2 can be done with aggregate taxes; no need to compute them all
1072  * unless the caller asked for the tax_value.
1073  *
1074  * Note that the returned "value" is such that
1075  * value + tax == "total to pay"
1076  * which means in the case of tax-included that the returned
1077  * "value" may be less than the aggregate price, even without a
1078  * discount. If you want to display the tax-included value, you need
1079  * to add the value and taxes together. In other words, the value is
1080  * the amount the merchant gets; the taxes are the amount the gov't
1081  * gets, and the customer pays the sum or value + taxes.
1082  *
1083  * The discount return value is just for entertainment -- you may want
1084  * to let a consumer know how much they saved.
1085  *
1086  * Note this function will not do any rounding unless forced to prevent overflow.
1087  * It's the caller's responsibility to round to the proper commodity
1088  * denominator if needed.
1089  */
1090 static void gncEntryComputeValueInt (gnc_numeric qty, gnc_numeric price,
1091  const GncTaxTable *tax_table, gboolean tax_included,
1092  gnc_numeric discount, GncAmountType discount_type,
1093  GncDiscountHow discount_how,
1094  gnc_numeric *value, gnc_numeric *discount_value,
1095  GList **tax_value, gnc_numeric *net_price)
1096 {
1097  gnc_numeric aggregate;
1098  gnc_numeric pretax;
1099  gnc_numeric result;
1100  gnc_numeric tax;
1101  gnc_numeric percent = gnc_numeric_create (100, 1);
1102  gnc_numeric tpercent = gnc_numeric_zero ();
1103  gnc_numeric tvalue = gnc_numeric_zero ();
1104  gnc_numeric i_net_price = price;
1105 
1106  GList * entries = gncTaxTableGetEntries (tax_table);
1107  GList * node;
1108 
1109  /* Step 1: compute the aggregate price */
1110 
1112 
1113  /* Step 2: compute the pre-tax aggregate */
1114 
1115  /* First, compute the aggregate tpercent and tvalue numbers */
1116  for (node = entries; node; node = node->next)
1117  {
1118  GncTaxTableEntry *entry = node->data;
1119  gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
1120 
1121  switch (gncTaxTableEntryGetType (entry))
1122  {
1123  case GNC_AMT_TYPE_VALUE:
1124  tvalue = gnc_numeric_add (tvalue, amount, GNC_DENOM_AUTO,
1126  break;
1127  case GNC_AMT_TYPE_PERCENT:
1128  tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO,
1130  break;
1131  default:
1132  g_warning ("Unknown tax type: %d", gncTaxTableEntryGetType (entry));
1133  break;
1134  }
1135  }
1136  /* now we need to convert from 5% -> .05 */
1137  tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO,
1139 
1140  /* Next, actually compute the pre-tax aggregate value based on the
1141  * taxincluded flag.
1142  */
1143  if (tax_table && tax_included)
1144  {
1145  /* Back-compute the pre-tax aggregate value.
1146  * We know that aggregate = pretax + pretax*tpercent + tvalue, so
1147  * pretax = (aggregate-tvalue)/(1+tpercent)
1148  */
1149  pretax = gnc_numeric_sub (aggregate, tvalue, GNC_DENOM_AUTO,
1151  pretax = gnc_numeric_div (pretax,
1152  gnc_numeric_add (tpercent,
1153  gnc_numeric_create (1, 1),
1156  if (!gnc_numeric_zero_p(qty))
1157  {
1158  i_net_price = gnc_numeric_div (pretax, qty, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1159  }
1160  }
1161  else
1162  {
1163  pretax = aggregate;
1164  }
1165 
1166  /* Step 3: apply discount and taxes in the appropriate order */
1167 
1168  /*
1169  * There are two ways to apply discounts and taxes. In one way, you
1170  * always compute the discount off the pretax number, and compute
1171  * the taxes off of either the pretax value or "pretax-discount"
1172  * value. In the other way, you always compute the tax on "pretax",
1173  * and compute the discount on either "pretax" or "pretax+taxes".
1174  *
1175  * I don't know which is the "correct" way.
1176  */
1177 
1178  /*
1179  * Type: discount tax
1180  * PRETAX pretax pretax-discount
1181  * SAMETIME pretax pretax
1182  * POSTTAX pretax+tax pretax
1183  */
1184 
1185  switch (discount_how)
1186  {
1187  case GNC_DISC_PRETAX:
1188  case GNC_DISC_SAMETIME:
1189  /* compute the discount from pretax */
1190 
1191  if (discount_type == GNC_AMT_TYPE_PERCENT)
1192  {
1193  discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
1195  discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO,
1197  }
1198 
1199  result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
1200 
1201  /* Figure out when to apply the tax, pretax or pretax-discount */
1202  if (discount_how == GNC_DISC_PRETAX)
1203  pretax = result;
1204  break;
1205 
1206  case GNC_DISC_POSTTAX:
1207  /* compute discount on pretax+taxes */
1208 
1209  if (discount_type == GNC_AMT_TYPE_PERCENT)
1210  {
1211  gnc_numeric after_tax;
1212 
1214  after_tax = gnc_numeric_add (pretax, tax, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
1215  after_tax = gnc_numeric_add (after_tax, tvalue, GNC_DENOM_AUTO,
1217  discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
1219  discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO,
1221  }
1222 
1223  result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
1224  break;
1225 
1226  default:
1227  g_warning ("unknown DiscountHow value: %d", discount_how);
1228  break;
1229  }
1230 
1231  /* Step 4: return the requested results. */
1232 
1233  /* result == amount merchant gets
1234  * discount == amount of discount
1235  * need to compute taxes (based on 'pretax') if the caller wants it.
1236  */
1237 
1238  if (discount_value != NULL)
1239  *discount_value = discount;
1240 
1241  if (value != NULL)
1242  *value = result;
1243 
1244  /* Now... Compute the list of tax values (if the caller wants it) */
1245 
1246  if (tax_value != NULL)
1247  {
1248  GList * taxes = NULL;
1249 
1250  for (node = entries; node; node = node->next)
1251  {
1252  GncTaxTableEntry *entry = node->data;
1253  Account *acc = gncTaxTableEntryGetAccount (entry);
1254  gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
1255 
1256  g_return_if_fail (acc);
1257 
1258  switch (gncTaxTableEntryGetType (entry))
1259  {
1260  case GNC_AMT_TYPE_VALUE:
1261  taxes = gncAccountValueAdd (taxes, acc, amount);
1262  break;
1263  case GNC_AMT_TYPE_PERCENT:
1264  amount = gnc_numeric_div (amount, percent, GNC_DENOM_AUTO,
1267  taxes = gncAccountValueAdd (taxes, acc, tax);
1268  break;
1269  default:
1270  break;
1271  }
1272  }
1273  *tax_value = taxes;
1274  }
1275 
1276  if (net_price != NULL)
1277  *net_price = i_net_price;
1278 
1279  return;
1280 }
1281 
1282 void gncEntryComputeValue (gnc_numeric qty, gnc_numeric price,
1283  const GncTaxTable *tax_table, gboolean tax_included,
1284  gnc_numeric discount, GncAmountType discount_type,
1285  GncDiscountHow discount_how, G_GNUC_UNUSED int SCU,
1286  gnc_numeric *value, gnc_numeric *discount_value,
1287  GList **tax_value)
1288 {
1289  gncEntryComputeValueInt (qty, price, tax_table, tax_included, discount, discount_type,
1290  discount_how, value, discount_value, tax_value, NULL);
1291 }
1292 
1293 static int
1294 get_entry_commodity_denom (const GncEntry *entry)
1295 {
1296  gnc_commodity *c;
1297  if (!entry)
1298  return 0;
1299  if (entry->invoice)
1300  {
1301  c = gncInvoiceGetCurrency (entry->invoice);
1302  if (c)
1303  return (gnc_commodity_get_fraction (c));
1304  }
1305  if (entry->bill)
1306  {
1307  c = gncInvoiceGetCurrency (entry->bill);
1308  if (c)
1309  return (gnc_commodity_get_fraction (c));
1310  }
1311  return 100000;
1312 }
1313 
1314 static void
1315 gncEntryRecomputeValues (GncEntry *entry)
1316 {
1317  int denom;
1318  GList *tv_iter;
1319 
1320  /* See if either tax table changed since we last computed values */
1321  if (entry->i_tax_table)
1322  {
1323  time64 modtime = gncTaxTableLastModifiedSecs (entry->i_tax_table);
1324  if (entry->i_taxtable_modtime != modtime)
1325  {
1326  entry->values_dirty = TRUE;
1327  entry->i_taxtable_modtime = modtime;
1328  }
1329  }
1330  if (entry->b_tax_table)
1331  {
1332  time64 modtime = gncTaxTableLastModifiedSecs (entry->b_tax_table);
1333  if (entry->b_taxtable_modtime != modtime)
1334  {
1335  entry->values_dirty = TRUE;
1336  entry->b_taxtable_modtime = modtime;
1337  }
1338  }
1339 
1340  if (!entry->values_dirty)
1341  return;
1342 
1343  /* Clear the last-computed tax values */
1344  if (entry->i_tax_values)
1345  {
1346  gncAccountValueDestroy (entry->i_tax_values);
1347  entry->i_tax_values = NULL;
1348  }
1349  if (entry->b_tax_values)
1350  {
1351  gncAccountValueDestroy (entry->b_tax_values);
1352  entry->b_tax_values = NULL;
1353  }
1354 
1355  /* Determine the commodity denominator */
1356  denom = get_entry_commodity_denom (entry);
1357 
1358  /* Compute the invoice values */
1359  gncEntryComputeValue (entry->quantity, entry->i_price,
1360  (entry->i_taxable ? entry->i_tax_table : NULL),
1361  entry->i_taxincluded,
1362  entry->i_discount, entry->i_disc_type,
1363  entry->i_disc_how,
1364  denom,
1365  &(entry->i_value), &(entry->i_disc_value),
1366  &(entry->i_tax_values));
1367 
1368  /* Compute the bill values */
1369  gncEntryComputeValue (entry->quantity, entry->b_price,
1370  (entry->b_taxable ? entry->b_tax_table : NULL),
1371  entry->b_taxincluded,
1372  gnc_numeric_zero(), GNC_AMT_TYPE_VALUE, GNC_DISC_PRETAX,
1373  denom,
1374  &(entry->b_value), NULL, &(entry->b_tax_values));
1375 
1376  entry->i_value_rounded = gnc_numeric_convert (entry->i_value, denom,
1378  entry->i_disc_value_rounded = gnc_numeric_convert (entry->i_disc_value, denom,
1380  entry->i_tax_value = gncAccountValueTotal (entry->i_tax_values);
1381  entry->i_tax_value_rounded = gnc_numeric_zero();
1382  for (tv_iter = entry->i_tax_values; tv_iter; tv_iter=tv_iter->next)
1383  {
1384  GncAccountValue *acc_val = tv_iter->data;
1385  entry->i_tax_value_rounded = gnc_numeric_add (entry->i_tax_value_rounded, acc_val->value,
1387  }
1388 
1389  entry->b_value_rounded = gnc_numeric_convert (entry->b_value, denom,
1391  entry->b_tax_value = gncAccountValueTotal (entry->b_tax_values);
1392  entry->b_tax_value_rounded = gnc_numeric_zero();
1393  for (tv_iter = entry->b_tax_values; tv_iter; tv_iter=tv_iter->next)
1394  {
1395  GncAccountValue *acc_val = tv_iter->data;
1396  entry->b_tax_value_rounded = gnc_numeric_add (entry->b_tax_value_rounded, acc_val->value,
1398  }
1399  entry->values_dirty = FALSE;
1400 }
1401 
1402 /* The "Int" functions below are for internal use only.
1403  * Outside this file, use the "Doc" or "Bal" variants found below instead. */
1404 static gnc_numeric gncEntryGetIntValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1405 {
1406  if (!entry) return gnc_numeric_zero();
1407  gncEntryRecomputeValues (entry);
1408  if (round)
1409  return (is_cust_doc ? entry->i_value_rounded : entry->b_value_rounded);
1410  else
1411  return (is_cust_doc ? entry->i_value : entry->b_value);
1412 }
1413 
1414 static gnc_numeric gncEntryGetIntTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1415 {
1416  if (!entry) return gnc_numeric_zero();
1417  gncEntryRecomputeValues (entry);
1418  if (round)
1419  return (is_cust_doc ? entry->i_tax_value_rounded : entry->b_tax_value_rounded);
1420  else
1421  return (is_cust_doc ? entry->i_tax_value : entry->b_tax_value);
1422 }
1423 
1424 /* Careful: the returned list is managed by the entry, and will only be valid for a short time */
1425 static AccountValueList * gncEntryGetIntTaxValues (GncEntry *entry, gboolean is_cust_doc)
1426 {
1427  if (!entry) return NULL;
1428  gncEntryRecomputeValues (entry);
1429  return (is_cust_doc ? entry->i_tax_values : entry->b_tax_values);
1430 }
1431 
1432 static gnc_numeric gncEntryGetIntDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1433 {
1434  if (!entry) return gnc_numeric_zero();
1435  gncEntryRecomputeValues (entry);
1436  if (round)
1437  return (is_cust_doc ? entry->i_disc_value_rounded : gnc_numeric_zero());
1438  else
1439  return (is_cust_doc ? entry->i_disc_value : gnc_numeric_zero());
1440 }
1441 
1442 /* Note contrary to the GetDoc*Value and GetBal*Value functions below
1443  * this function will always round the net price to the entry's
1444  * currency denominator (being the invoice/bill denom or 100000 if not
1445  * included in a bill or invoice) */
1446 gnc_numeric gncEntryGetPrice (const GncEntry *entry, gboolean cust_doc, gboolean net)
1447 {
1448  gnc_numeric result;
1449  int denom;
1450 
1451  if (!entry) return gnc_numeric_zero();
1452  if (!net) return (cust_doc ? entry->i_price : entry->b_price);
1453 
1454 
1455  /* Compute the net price */
1456  if (cust_doc)
1457  gncEntryComputeValueInt (entry->quantity, entry->i_price,
1458  (entry->i_taxable ? entry->i_tax_table : NULL),
1459  entry->i_taxincluded,
1460  entry->i_discount, entry->i_disc_type,
1461  entry->i_disc_how,
1462  NULL, NULL, NULL, &result);
1463  else
1464  gncEntryComputeValueInt (entry->quantity, entry->b_price,
1465  (entry->b_taxable ? entry->b_tax_table : NULL),
1466  entry->b_taxincluded,
1467  gnc_numeric_zero(), GNC_AMT_TYPE_VALUE, GNC_DISC_PRETAX,
1468  NULL, NULL, NULL, &result);
1469 
1470  /* Determine the commodity denominator */
1471  denom = get_entry_commodity_denom (entry);
1472 
1473  result = gnc_numeric_convert (result, denom,
1475 
1476  return result;
1477 }
1478 
1479 gnc_numeric gncEntryGetDocValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1480 {
1481  gnc_numeric value = gncEntryGetIntValue (entry, round, is_cust_doc);
1482  return (is_cn ? gnc_numeric_neg (value) : value);
1483 }
1484 
1485 gnc_numeric gncEntryGetDocTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1486 {
1487  gnc_numeric value = gncEntryGetIntTaxValue (entry, round, is_cust_doc);
1488  return (is_cn ? gnc_numeric_neg (value) : value);
1489 }
1490 
1491 /* Careful: the returned list is NOT owned by the entry and should be freed by the caller */
1492 AccountValueList * gncEntryGetDocTaxValues (GncEntry *entry, gboolean is_cust_doc, gboolean is_cn)
1493 {
1494  AccountValueList *int_values = gncEntryGetIntTaxValues (entry, is_cust_doc);
1495  AccountValueList *values = NULL, *node;
1496 
1497  /* Make a copy of the list with negated values if necessary. */
1498  for (node = int_values; node; node = node->next)
1499  {
1500  GncAccountValue *acct_val = node->data;
1501  values = gncAccountValueAdd (values, acct_val->account,
1502  (is_cn ? gnc_numeric_neg (acct_val->value)
1503  : acct_val->value));
1504  }
1505 
1506  return values;
1507 }
1508 
1509 gnc_numeric gncEntryGetDocDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1510 {
1511  gnc_numeric value = gncEntryGetIntDiscountValue (entry, round, is_cust_doc);
1512  return (is_cn ? gnc_numeric_neg (value) : value);
1513 }
1514 
1515 gnc_numeric gncEntryGetBalValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1516 {
1517  gnc_numeric value = gncEntryGetIntValue (entry, round, is_cust_doc);
1518  return (is_cust_doc ? gnc_numeric_neg (value) : value);
1519 }
1520 
1521 gnc_numeric gncEntryGetBalTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1522 {
1523  gnc_numeric value = gncEntryGetIntTaxValue (entry, round, is_cust_doc);
1524  return (is_cust_doc ? gnc_numeric_neg (value) : value);
1525 }
1526 
1527 /* Careful: the returned list is NOT owned by the entry and should be freed by the caller */
1528 AccountValueList * gncEntryGetBalTaxValues (GncEntry *entry, gboolean is_cust_doc)
1529 {
1530  AccountValueList *int_values = gncEntryGetIntTaxValues (entry, is_cust_doc);
1531  AccountValueList *values = NULL, *node;
1532 
1533  /* Make a copy of the list with negated values if necessary. */
1534  for (node = int_values; node; node = node->next)
1535  {
1536  GncAccountValue *acct_val = node->data;
1537  values = gncAccountValueAdd (values, acct_val->account,
1538  (is_cust_doc ? gnc_numeric_neg (acct_val->value)
1539  : acct_val->value));
1540  }
1541 
1542  return values;
1543 }
1544 
1545 gnc_numeric gncEntryGetBalDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1546 {
1547  gnc_numeric value = gncEntryGetIntDiscountValue (entry, round, is_cust_doc);
1548  return (is_cust_doc ? gnc_numeric_neg (value) : value);
1549 }
1550 
1551 /* XXX this existence of this routine is just wrong */
1552 gboolean gncEntryIsOpen (const GncEntry *entry)
1553 {
1554  if (!entry) return FALSE;
1555  return (qof_instance_get_editlevel(entry) > 0);
1556 }
1557 
1558 /* ================================================================ */
1559 
1560 void gncEntryBeginEdit (GncEntry *entry)
1561 {
1562  qof_begin_edit(&entry->inst);
1563 }
1564 
1565 static void gncEntryOnError (QofInstance *entry, QofBackendError errcode)
1566 {
1567  PERR("Entry QofBackend Failure: %d", errcode);
1568  gnc_engine_signal_commit_error( errcode );
1569 }
1570 
1571 static void gncEntryOnDone (QofInstance *inst) {}
1572 
1573 static void entry_free (QofInstance *inst)
1574 {
1575  GncEntry *entry = (GncEntry *)inst;
1576  gncEntryFree (entry);
1577 }
1578 
1579 void gncEntryCommitEdit (GncEntry *entry)
1580 {
1581  /* GnuCash 2.6.3 and earlier didn't handle entry kvp's... */
1582  if (qof_instance_has_kvp(QOF_INSTANCE(entry)))
1583  gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (entry)),
1584  GNC_FEATURE_KVP_EXTRA_DATA);
1585 
1586  if (!qof_commit_edit (QOF_INSTANCE(entry))) return;
1587  qof_commit_edit_part2 (&entry->inst, gncEntryOnError,
1588  gncEntryOnDone, entry_free);
1589 }
1590 
1591 int gncEntryCompare (const GncEntry *a, const GncEntry *b)
1592 {
1593  int compare;
1594 
1595  if (a == b) return 0;
1596  if (!a && b) return -1;
1597  if (a && !b) return 1;
1598  g_assert (a && b); /* Silence a static analysis warning. */
1599  if (a->date != b->date) return a->date - b->date;
1600  if (a->date_entered != b->date_entered) return a->date_entered - b->date_entered;
1601 
1602  compare = g_strcmp0 (a->desc, b->desc);
1603  if (compare) return compare;
1604 
1605  compare = g_strcmp0 (a->action, b->action);
1606  if (compare) return compare;
1607 
1608  return qof_instance_guid_compare(a, b);
1609 }
1610 
1611 #define CHECK_STRING(X, Y, FIELD) \
1612  if (g_strcmp0((X)->FIELD, (Y)->FIELD) != 0) \
1613  { \
1614  PWARN("%s differ: %s vs %s", #FIELD, (X)->FIELD, (Y)->FIELD); \
1615  return FALSE; \
1616  }
1617 
1618 #define CHECK_ACCOUNT(X, Y, FIELD) \
1619  if (!xaccAccountEqual((X)->FIELD, (Y)->FIELD, TRUE)) \
1620  { \
1621  PWARN("%s differ", #FIELD); \
1622  return FALSE; \
1623  }
1624 
1625 #define CHECK_NUMERIC(X, Y, FIELD) \
1626  if (!gnc_numeric_equal((X)->FIELD, (Y)->FIELD)) \
1627  { \
1628  PWARN("%s differ", #FIELD); \
1629  return FALSE; \
1630  }
1631 
1632 #define CHECK_VALUE(X, Y, FIELD) \
1633  if ((X)->FIELD != (Y)->FIELD) \
1634  { \
1635  PWARN("%s differ", #FIELD); \
1636  return FALSE; \
1637  }
1638 
1639 
1640 /* ============================================================= */
1641 /* Object declaration */
1642 
1643 static void
1644 destroy_entry_on_book_close(QofInstance *ent, gpointer data)
1645 {
1646  GncEntry* entry = GNC_ENTRY(ent);
1647 
1648  gncEntryBeginEdit(entry);
1649  gncEntryDestroy(entry);
1650 }
1651 
1656 static void
1657 gnc_entry_book_end(QofBook* book)
1658 {
1659  QofCollection *col;
1660 
1661  col = qof_book_get_collection(book, GNC_ID_ENTRY);
1662  qof_collection_foreach(col, destroy_entry_on_book_close, NULL);
1663 }
1664 
1665 static QofObject gncEntryDesc =
1666 {
1667  DI(.interface_version = ) QOF_OBJECT_VERSION,
1668  DI(.e_type = ) _GNC_MOD_NAME,
1669  DI(.type_label = ) "Order/Invoice/Bill Entry",
1670  DI(.create = ) (gpointer)gncEntryCreate,
1671  DI(.book_begin = ) NULL,
1672  DI(.book_end = ) gnc_entry_book_end,
1673  DI(.is_dirty = ) qof_collection_is_dirty,
1674  DI(.mark_clean = ) qof_collection_mark_clean,
1675  DI(.foreach = ) qof_collection_foreach,
1676  DI(.printable = ) NULL,
1677  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
1678 };
1679 
1680 gboolean gncEntryRegister (void)
1681 {
1682  static QofParam params[] =
1683  {
1684  { ENTRY_DATE, QOF_TYPE_DATE, (QofAccessFunc)gncEntryGetDate, (QofSetterFunc)gncEntrySetDate },
1685  { ENTRY_DATE_ENTERED, QOF_TYPE_DATE, (QofAccessFunc)gncEntryGetDateEntered, (QofSetterFunc)gncEntrySetDateEntered },
1686  { ENTRY_DESC, QOF_TYPE_STRING, (QofAccessFunc)gncEntryGetDescription, (QofSetterFunc)gncEntrySetDescription },
1687  { ENTRY_ACTION, QOF_TYPE_STRING, (QofAccessFunc)gncEntryGetAction, (QofSetterFunc)gncEntrySetAction },
1688  { ENTRY_NOTES, QOF_TYPE_STRING, (QofAccessFunc)gncEntryGetNotes, (QofSetterFunc)gncEntrySetNotes },
1689  { ENTRY_QTY, QOF_TYPE_NUMERIC, (QofAccessFunc)gncEntryGetQuantity, (QofSetterFunc)gncEntrySetQuantity },
1690  { ENTRY_IPRICE, QOF_TYPE_NUMERIC, (QofAccessFunc)gncEntryGetInvPrice, (QofSetterFunc)gncEntrySetInvPrice },
1691  { ENTRY_BPRICE, QOF_TYPE_NUMERIC, (QofAccessFunc)gncEntryGetBillPrice, (QofSetterFunc)gncEntrySetBillPrice },
1692  { ENTRY_INVOICE, GNC_ID_INVOICE, (QofAccessFunc)gncEntryGetInvoice, NULL },
1693  { ENTRY_IACCT, GNC_ID_ACCOUNT, (QofAccessFunc)gncEntryGetInvAccount, (QofSetterFunc)gncEntrySetInvAccount },
1694  { ENTRY_BACCT, GNC_ID_ACCOUNT, (QofAccessFunc)gncEntryGetBillAccount, (QofSetterFunc)gncEntrySetBillAccount },
1695  { ENTRY_BILL, GNC_ID_INVOICE, (QofAccessFunc)gncEntryGetBill, NULL },
1696  {
1697  ENTRY_INV_DISC_TYPE, QOF_TYPE_STRING, (QofAccessFunc)qofEntryGetInvDiscType,
1698  (QofSetterFunc)qofEntrySetInvDiscType
1699  },
1700  {
1701  ENTRY_INV_DISC_HOW, QOF_TYPE_STRING, (QofAccessFunc)qofEntryGetInvDiscHow,
1702  (QofSetterFunc)qofEntrySetInvDiscHow
1703  },
1704  {
1705  ENTRY_INV_TAXABLE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetInvTaxable,
1706  (QofSetterFunc)gncEntrySetInvTaxable
1707  },
1708  {
1709  ENTRY_INV_TAX_INC, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetInvTaxIncluded,
1710  (QofSetterFunc)gncEntrySetInvTaxIncluded
1711  },
1712  {
1713  ENTRY_BILL_TAXABLE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetBillTaxable,
1714  (QofSetterFunc)gncEntrySetBillTaxable
1715  },
1716  {
1717  ENTRY_BILL_TAX_INC, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetBillTaxIncluded,
1718  (QofSetterFunc)gncEntrySetBillTaxIncluded
1719  },
1720  { ENTRY_BILLABLE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEntryGetBillable, (QofSetterFunc)gncEntrySetBillable },
1721  { ENTRY_BILLTO, GNC_ID_OWNER, (QofAccessFunc)gncEntryGetBillTo, (QofSetterFunc)gncEntrySetBillTo },
1722  { ENTRY_ORDER, GNC_ID_ORDER, (QofAccessFunc)gncEntryGetOrder, NULL },
1723  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
1724  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
1725  { NULL },
1726  };
1727 
1728  qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncEntryCompare, params);
1729 
1730  return qof_object_register (&gncEntryDesc);
1731 }
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:196
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void gncEntrySetQuantity(GncEntry *entry, gnc_numeric quantity)
Set the internal quantity without any conversion.
Definition: gncEntry.c:546
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:257
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
GList * qof_instance_get_referring_object_list_from_collection(const QofCollection *coll, const QofInstance *ref)
Returns a list of objects from the collection which refer to the specific object. ...
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
Definition: gnc-features.c:135
AccountValueList * gncEntryGetDocTaxValues(GncEntry *entry, gboolean is_cust_doc, gboolean is_cn)
Careful: the returned list is NOT owned by the entry and should be freed by the caller.
Definition: gncEntry.c:1492
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:405
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
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:1215
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
gnc_numeric gncAccountValueTotal(GList *list)
return the total for this list
Definition: gncTaxTable.c:984
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
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:765
void gncEntrySetDocQuantity(GncEntry *entry, gnc_numeric quantity, gboolean is_cn)
Set the internal quantity converting from the quantity as visible on the physical document...
Definition: gncEntry.c:557
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:64
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
Definition: qofid.cpp:323
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:184
time64 gncEntryGetDate(const GncEntry *entry)
DEPRECATED - use gncEntryGetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:872
tax is a number
Definition: gncTaxTable.h:69
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
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;...
AccountValueList * gncEntryGetBalTaxValues(GncEntry *entry, gboolean is_cust_doc)
Careful: the returned list is NOT owned by the entry and should be freed by the caller.
Definition: gncEntry.c:1528
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.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void gncBillAddEntry(GncInvoice *bill, GncEntry *entry)
Call this function when adding an entry to a bill instead of an invoice.
Definition: gncInvoice.c:734
GDate gncEntryGetDateGDate(const GncEntry *entry)
Returns the day of this entry.
Definition: gncEntry.c:877
tax is a percentage
Definition: gncTaxTable.h:70
Use unbiased ("banker&#39;s") rounding.
Definition: gnc-numeric.h:173
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1256
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
void gncEntrySetDateGDate(GncEntry *entry, const GDate *date)
Set the date of this entry.
Definition: gncEntry.c:499
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:263
Find the least common multiple of the arguments&#39; denominators and use that as the denominator of the ...
Definition: gnc-numeric.h:201
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
void gncAccountValueDestroy(GList *list)
Destroy a list of accountvalues.
Definition: gncTaxTable.c:997
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
Never round at all, and signal an error if there is a fractional result in a computation.
Definition: gnc-numeric.h:178
const char * gncEntryDiscountHowToString(GncDiscountHow how)
How to apply the discount and taxes.
Definition: gncEntry.c:112
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
Business Invoice Interface.
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
gnc_numeric gncEntryGetQuantity(const GncEntry *entry)
Get the quantity as stored internally.
Definition: gncEntry.c:905
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:604
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
void gncEntrySetDate(GncEntry *entry, time64 date)
DEPRECATED - use gncEntrySetDateGDate() instead! (Because the time-of-day is a misleading extra infor...
Definition: gncEntry.c:477
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:317
GList * gncAccountValueAdd(GList *list, Account *acc, gnc_numeric value)
This will add value to the account-value for acc, creating a new list object if necessary.
Definition: gncTaxTable.c:942
Business Entry Interface.
time64 time64CanonicalDayTime(time64 t)
convert a time64 on a certain day (localtime) to the time64 representing midday on that day...
Definition: gnc-date.cpp:413
gboolean qof_instance_has_kvp(QofInstance *inst)
Report whether a QofInstance has anything stored in KVP.
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
GncAmountType
How to interpret the amount.
Definition: gncTaxTable.h:67
gnc_numeric gncEntryGetDocQuantity(const GncEntry *entry, gboolean is_cn)
Get the quantity as on the physical document.
Definition: gncEntry.c:911
Commodity handling public routines.
modtime is the internal date of the last modtime See src/doc/business.txt for an explanation of the f...
gchar * qof_instance_get_display_name(const QofInstance *inst)
Returns a displayable name for this object.
Utility functions for file access.