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