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 
101 struct _gncEntryClass
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 *
gncEntryDiscountHowToString(GncDiscountHow how)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! */
gncEntryDiscountStringToHow(const char * str,GncDiscountHow * how)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! */
gncEntryPaymentTypeToString(GncEntryPaymentType type)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! */
gncEntryPaymentStringToType(const char * str,GncEntryPaymentType * type)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);
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
gnc_entry_init(GncEntry * entry)243 gnc_entry_init(GncEntry* entry)
244 {
245 }
246 
247 static void
gnc_entry_dispose(GObject * entryp)248 gnc_entry_dispose(GObject *entryp)
249 {
250     G_OBJECT_CLASS(gnc_entry_parent_class)->dispose(entryp);
251 }
252 
253 static void
gnc_entry_finalize(GObject * entryp)254 gnc_entry_finalize(GObject* entryp)
255 {
256     G_OBJECT_CLASS(gnc_entry_parent_class)->finalize(entryp);
257 }
258 
259 static void
gnc_entry_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
gnc_entry_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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 
305 /** Return displayable name */
306 static gchar*
impl_get_display_name(const QofInstance * inst)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 
342 /** Does this object refer to a specific object */
343 static gboolean
impl_refers_to_object(const QofInstance * inst,const QofInstance * ref)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 
367 /** Returns a list of my type of object which refers to an object.  For example, when called as
368         qof_instance_get_typed_referring_object_list(taxtable, account);
369     it will return the list of taxtables which refer to a specific account.  The result should be the
370     same regardless of which taxtable object is used.  The list must be freed by the caller but the
371     objects on the list must not.
372  */
373 static GList*
impl_get_typed_referring_object_list(const QofInstance * inst,const QofInstance * ref)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 
381     return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
382 }
383 
384 static void
gnc_entry_class_init(GncEntryClass * klass)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 */
gncEntryCreate(QofBook * book)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 
gncEntryDestroy(GncEntry * entry)445 void gncEntryDestroy (GncEntry *entry)
446 {
447     if (!entry) return;
448     qof_instance_set_destroying(entry, TRUE);
449     gncEntryCommitEdit(entry);
450 }
451 
gncEntryFree(GncEntry * entry)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 
gncEntrySetDate(GncEntry * entry,time64 date)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 
gncEntrySetDateGDate(GncEntry * entry,const GDate * date)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.*/
509     gncEntrySetDate(entry, time64CanonicalDayTime(gdate_to_time64(*date)));
510 }
511 
gncEntrySetDateEntered(GncEntry * entry,time64 date)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 
gncEntrySetDescription(GncEntry * entry,const char * desc)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 
gncEntrySetAction(GncEntry * entry,const char * action)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 
gncEntrySetNotes(GncEntry * entry,const char * notes)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 
gncEntrySetQuantity(GncEntry * entry,gnc_numeric quantity)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 
gncEntrySetDocQuantity(GncEntry * entry,gnc_numeric quantity,gboolean is_cn)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 
gncEntrySetInvAccount(GncEntry * entry,Account * acc)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 
gncEntrySetInvPrice(GncEntry * entry,gnc_numeric price)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 
gncEntrySetInvTaxable(GncEntry * entry,gboolean taxable)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 
gncEntrySetInvTaxIncluded(GncEntry * entry,gboolean taxincluded)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 
gncEntrySetInvTaxTable(GncEntry * entry,GncTaxTable * table)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 
gncEntrySetInvDiscount(GncEntry * entry,gnc_numeric discount)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 
gncEntrySetInvDiscountType(GncEntry * entry,GncAmountType type)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 
gncEntrySetInvDiscountHow(GncEntry * entry,GncDiscountHow how)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 
qofEntrySetInvDiscType(GncEntry * entry,const char * type_string)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 
qofEntrySetInvDiscHow(GncEntry * entry,const char * type)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 
gncEntrySetBillAccount(GncEntry * entry,Account * acc)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 
gncEntrySetBillPrice(GncEntry * entry,gnc_numeric price)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 
gncEntrySetBillTaxable(GncEntry * entry,gboolean taxable)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 
gncEntrySetBillTaxIncluded(GncEntry * entry,gboolean taxincluded)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 
gncEntrySetBillTaxTable(GncEntry * entry,GncTaxTable * table)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 
gncEntrySetBillable(GncEntry * entry,gboolean billable)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 
gncEntrySetBillTo(GncEntry * entry,GncOwner * billto)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 
gncEntrySetBillPayment(GncEntry * entry,GncEntryPaymentType type)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 */
gncEntrySetOrder(GncEntry * entry,GncOrder * 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 */
gncEntrySetInvoice(GncEntry * entry,GncInvoice * 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 */
gncEntrySetBill(GncEntry * entry,GncInvoice * 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 
gncEntryCopy(const GncEntry * src,GncEntry * dest,gboolean add_entry)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 
gncEntryGetDate(const GncEntry * entry)872 time64 gncEntryGetDate (const GncEntry *entry)
873 {
874     return entry ? entry->date : 0;
875 }
876 
gncEntryGetDateGDate(const GncEntry * entry)877 GDate gncEntryGetDateGDate(const GncEntry *entry)
878 {
879     return time64_to_gdate(gncEntryGetDate(entry));
880 }
881 
gncEntryGetDateEntered(const GncEntry * entry)882 time64 gncEntryGetDateEntered (const GncEntry *entry)
883 {
884     return entry ? entry->date_entered : 0;
885 }
886 
gncEntryGetDescription(const GncEntry * entry)887 const char * gncEntryGetDescription (const GncEntry *entry)
888 {
889     if (!entry) return NULL;
890     return entry->desc;
891 }
892 
gncEntryGetAction(const GncEntry * entry)893 const char * gncEntryGetAction (const GncEntry *entry)
894 {
895     if (!entry) return NULL;
896     return entry->action;
897 }
898 
gncEntryGetNotes(const GncEntry * entry)899 const char * gncEntryGetNotes (const GncEntry *entry)
900 {
901     if (!entry) return NULL;
902     return entry->notes;
903 }
904 
gncEntryGetQuantity(const GncEntry * entry)905 gnc_numeric gncEntryGetQuantity (const GncEntry *entry)
906 {
907     if (!entry) return gnc_numeric_zero();
908     return entry->quantity;
909 }
910 
gncEntryGetDocQuantity(const GncEntry * entry,gboolean is_cn)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 
gncEntryGetInvAccount(const GncEntry * entry)919 Account * gncEntryGetInvAccount (const GncEntry *entry)
920 {
921     if (!entry) return NULL;
922     return entry->i_account;
923 }
924 
gncEntryGetInvPrice(const GncEntry * entry)925 gnc_numeric gncEntryGetInvPrice (const GncEntry *entry)
926 {
927     if (!entry) return gnc_numeric_zero();
928     return entry->i_price;
929 }
930 
gncEntryGetInvDiscount(const GncEntry * entry)931 gnc_numeric gncEntryGetInvDiscount (const GncEntry *entry)
932 {
933     if (!entry) return gnc_numeric_zero();
934     return entry->i_discount;
935 }
936 
gncEntryGetInvDiscountType(const GncEntry * entry)937 GncAmountType gncEntryGetInvDiscountType (const GncEntry *entry)
938 {
939     if (!entry) return 0;
940     return entry->i_disc_type;
941 }
942 
gncEntryGetInvDiscountHow(const GncEntry * entry)943 GncDiscountHow gncEntryGetInvDiscountHow (const GncEntry *entry)
944 {
945     if (!entry) return 0;
946     return entry->i_disc_how;
947 }
948 
qofEntryGetInvDiscType(const GncEntry * entry)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 
qofEntryGetInvDiscHow(const GncEntry * entry)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 
gncEntryGetInvTaxable(const GncEntry * entry)967 gboolean gncEntryGetInvTaxable (const GncEntry *entry)
968 {
969     if (!entry) return FALSE;
970     return entry->i_taxable;
971 }
972 
gncEntryGetInvTaxIncluded(const GncEntry * entry)973 gboolean gncEntryGetInvTaxIncluded (const GncEntry *entry)
974 {
975     if (!entry) return FALSE;
976     return entry->i_taxincluded;
977 }
978 
gncEntryGetInvTaxTable(const GncEntry * entry)979 GncTaxTable * gncEntryGetInvTaxTable (const GncEntry *entry)
980 {
981     if (!entry) return NULL;
982     return entry->i_tax_table;
983 }
984 
985 /* vendor bills */
986 
gncEntryGetBillAccount(const GncEntry * entry)987 Account * gncEntryGetBillAccount (const GncEntry *entry)
988 {
989     if (!entry) return NULL;
990     return entry->b_account;
991 }
992 
gncEntryGetBillPrice(const GncEntry * entry)993 gnc_numeric gncEntryGetBillPrice (const GncEntry *entry)
994 {
995     if (!entry) return gnc_numeric_zero();
996     return entry->b_price;
997 }
998 
gncEntryGetBillTaxable(const GncEntry * entry)999 gboolean gncEntryGetBillTaxable (const GncEntry *entry)
1000 {
1001     if (!entry) return FALSE;
1002     return entry->b_taxable;
1003 }
1004 
gncEntryGetBillTaxIncluded(const GncEntry * entry)1005 gboolean gncEntryGetBillTaxIncluded (const GncEntry *entry)
1006 {
1007     if (!entry) return FALSE;
1008     return entry->b_taxincluded;
1009 }
1010 
gncEntryGetBillTaxTable(const GncEntry * entry)1011 GncTaxTable * gncEntryGetBillTaxTable (const GncEntry *entry)
1012 {
1013     if (!entry) return NULL;
1014     return entry->b_tax_table;
1015 }
1016 
gncEntryGetBillable(const GncEntry * entry)1017 gboolean gncEntryGetBillable (const GncEntry *entry)
1018 {
1019     if (!entry) return FALSE;
1020     return entry->billable;
1021 }
1022 
gncEntryGetBillTo(GncEntry * entry)1023 GncOwner * gncEntryGetBillTo (GncEntry *entry)
1024 {
1025     if (!entry) return NULL;
1026     return &entry->billto;
1027 }
1028 
gncEntryGetBillPayment(const GncEntry * entry)1029 GncEntryPaymentType gncEntryGetBillPayment (const GncEntry* entry)
1030 {
1031     if (!entry) return 0;
1032     return entry->b_payment;
1033 }
1034 
gncEntryGetInvoice(const GncEntry * entry)1035 GncInvoice * gncEntryGetInvoice (const GncEntry *entry)
1036 {
1037     if (!entry) return NULL;
1038     return entry->invoice;
1039 }
1040 
gncEntryGetBill(const GncEntry * entry)1041 GncInvoice * gncEntryGetBill (const GncEntry *entry)
1042 {
1043     if (!entry) return NULL;
1044     return entry->bill;
1045 }
1046 
gncEntryGetOrder(const GncEntry * entry)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  */
gncEntryComputeValueInt(gnc_numeric qty,gnc_numeric price,const GncTaxTable * tax_table,gboolean tax_included,gnc_numeric discount,GncAmountType discount_type,GncDiscountHow discount_how,gnc_numeric * value,gnc_numeric * discount_value,GList ** tax_value,gnc_numeric * net_price)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 
1111     aggregate = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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,
1125                                       GNC_HOW_DENOM_LCD);
1126             break;
1127         case GNC_AMT_TYPE_PERCENT:
1128             tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO,
1129                                         GNC_HOW_DENOM_LCD);
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,
1138                                 GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
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,
1150                                   GNC_HOW_DENOM_LCD);
1151         pretax = gnc_numeric_div (pretax,
1152                                   gnc_numeric_add (tpercent,
1153                                           gnc_numeric_create (1, 1),
1154                                           GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
1155                                   GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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,
1194                                         GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1195             discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO,
1196                                         GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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 
1213             tax = gnc_numeric_mul (pretax, tpercent, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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,
1216                                          GNC_HOW_DENOM_LCD);
1217             discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
1218                                         GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1219             discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO,
1220                                         GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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,
1265                                           GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1266                 tax = gnc_numeric_mul (pretax, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
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 
gncEntryComputeValue(gnc_numeric qty,gnc_numeric price,const GncTaxTable * tax_table,gboolean tax_included,gnc_numeric discount,GncAmountType discount_type,GncDiscountHow discount_how,G_GNUC_UNUSED int SCU,gnc_numeric * value,gnc_numeric * discount_value,GList ** tax_value)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
get_entry_commodity_denom(const GncEntry * entry)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
gncEntryRecomputeValues(GncEntry * entry)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,
1377                              GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1378     entry->i_disc_value_rounded = gnc_numeric_convert (entry->i_disc_value, denom,
1379                                   GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
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,
1386                                      denom, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1387     }
1388 
1389     entry->b_value_rounded = gnc_numeric_convert (entry->b_value, denom,
1390                              GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
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,
1397                                                       denom, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
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. */
gncEntryGetIntValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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 
gncEntryGetIntTaxValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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 */
gncEntryGetIntTaxValues(GncEntry * entry,gboolean is_cust_doc)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 
gncEntryGetIntDiscountValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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) */
gncEntryGetPrice(const GncEntry * entry,gboolean cust_doc,gboolean net)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,
1474                                   GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1475 
1476     return result;
1477 }
1478 
gncEntryGetDocValue(GncEntry * entry,gboolean round,gboolean is_cust_doc,gboolean is_cn)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 
gncEntryGetDocTaxValue(GncEntry * entry,gboolean round,gboolean is_cust_doc,gboolean is_cn)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 */
gncEntryGetDocTaxValues(GncEntry * entry,gboolean is_cust_doc,gboolean is_cn)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 
gncEntryGetDocDiscountValue(GncEntry * entry,gboolean round,gboolean is_cust_doc,gboolean is_cn)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 
gncEntryGetBalValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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 
gncEntryGetBalTaxValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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 */
gncEntryGetBalTaxValues(GncEntry * entry,gboolean is_cust_doc)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 
gncEntryGetBalDiscountValue(GncEntry * entry,gboolean round,gboolean is_cust_doc)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 */
gncEntryIsOpen(const GncEntry * entry)1552 gboolean gncEntryIsOpen (const GncEntry *entry)
1553 {
1554     if (!entry) return FALSE;
1555     return (qof_instance_get_editlevel(entry) > 0);
1556 }
1557 
1558 /* ================================================================ */
1559 
gncEntryBeginEdit(GncEntry * entry)1560 void gncEntryBeginEdit (GncEntry *entry)
1561 {
1562     qof_begin_edit(&entry->inst);
1563 }
1564 
gncEntryOnError(QofInstance * entry,QofBackendError errcode)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 
gncEntryOnDone(QofInstance * inst)1571 static void gncEntryOnDone (QofInstance *inst) {}
1572 
entry_free(QofInstance * inst)1573 static void entry_free (QofInstance *inst)
1574 {
1575     GncEntry *entry = (GncEntry *)inst;
1576     gncEntryFree (entry);
1577 }
1578 
gncEntryCommitEdit(GncEntry * entry)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 
gncEntryCompare(const GncEntry * a,const GncEntry * b)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
destroy_entry_on_book_close(QofInstance * ent,gpointer data)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 
1652 /** Handles book end - frees all entries from the book
1653  *
1654  * @param book Book being closed
1655  */
1656 static void
gnc_entry_book_end(QofBook * book)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 
gncEntryRegister(void)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 }
1732