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