Line data Source code
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 :
42 : struct _gncEntry
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 :
102 : struct _gncEntryClass
103 : {
104 : QofInstanceClass parent_class;
105 : };
106 :
107 : static 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! */
112 : const char *
113 41 : gncEntryDiscountHowToString (GncDiscountHow how)
114 : {
115 41 : switch (how)
116 : {
117 16 : case (GNC_DISC_PRETAX):
118 16 : return "PRETAX";
119 15 : case (GNC_DISC_SAMETIME):
120 15 : return "SAMETIME";
121 10 : case (GNC_DISC_POSTTAX):
122 10 : return "POSTTAX";
123 0 : default:
124 0 : PWARN ("asked to translate unknown discount-how %d.\n", how);
125 0 : break;
126 : }
127 0 : 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! */
132 2 : gboolean gncEntryDiscountStringToHow (const char *str, GncDiscountHow *how)
133 : {
134 2 : if (g_strcmp0 ("PRETAX", str) == 0)
135 : {
136 2 : *how = GNC_DISC_PRETAX;
137 2 : return TRUE;
138 : }
139 0 : if (g_strcmp0 ("SAMETIME", str) == 0)
140 : {
141 0 : *how = GNC_DISC_SAMETIME;
142 0 : return TRUE;
143 : }
144 0 : if (g_strcmp0 ("POSTTAX", str) == 0)
145 : {
146 0 : *how = GNC_DISC_POSTTAX;
147 0 : return TRUE;
148 : }
149 0 : PWARN ("asked to translate unknown discount-how string %s.\n",
150 : str ? str : "(null)");
151 :
152 0 : 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! */
157 2 : const char * gncEntryPaymentTypeToString (GncEntryPaymentType type)
158 : {
159 2 : switch (type)
160 : {
161 2 : case (GNC_PAYMENT_CASH):
162 2 : return "CASH";
163 0 : case (GNC_PAYMENT_CARD):
164 0 : return "CARD";
165 0 : default:
166 0 : PWARN ("asked to translate unknown payment type %d.\n", type);
167 0 : break;
168 : }
169 0 : 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! */
174 3 : gboolean gncEntryPaymentStringToType (const char *str, GncEntryPaymentType *type)
175 : {
176 3 : if (g_strcmp0 ("CASH", str) == 0)
177 : {
178 3 : *type = GNC_PAYMENT_CASH;
179 3 : return TRUE;
180 : }
181 0 : if (g_strcmp0 ("CARD", str) == 0)
182 : {
183 0 : *type = GNC_PAYMENT_CARD;
184 0 : return TRUE;
185 : }
186 0 : PWARN ("asked to translate unknown discount-how string %s.\n",
187 : str ? str : "(null)");
188 :
189 0 : 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 :
200 : static inline void mark_entry (GncEntry *entry);
201 1158 : void mark_entry (GncEntry *entry)
202 : {
203 1158 : qof_instance_set_dirty(&entry->inst);
204 1158 : qof_event_gen (&entry->inst, QOF_EVENT_MODIFY, NULL);
205 1158 : }
206 :
207 : /* ================================================================ */
208 :
209 : enum
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 */
241 170 : G_DEFINE_TYPE(GncEntry, gnc_entry, QOF_TYPE_INSTANCE)
242 :
243 : static void
244 121 : gnc_entry_init(GncEntry* entry)
245 : {
246 121 : }
247 :
248 : static void
249 20 : gnc_entry_dispose(GObject *entryp)
250 : {
251 20 : G_OBJECT_CLASS(gnc_entry_parent_class)->dispose(entryp);
252 20 : }
253 :
254 : static void
255 20 : gnc_entry_finalize(GObject* entryp)
256 : {
257 20 : G_OBJECT_CLASS(gnc_entry_parent_class)->finalize(entryp);
258 20 : }
259 :
260 : static void
261 1 : gnc_entry_get_property (GObject *object,
262 : guint prop_id,
263 : GValue *value,
264 : GParamSpec *pspec)
265 : {
266 : GncEntry *entry;
267 :
268 1 : g_return_if_fail(GNC_IS_ENTRY(object));
269 :
270 1 : entry = GNC_ENTRY(object);
271 1 : switch (prop_id)
272 : {
273 1 : case PROP_DESCRIPTION:
274 1 : g_value_set_string(value, entry->desc);
275 1 : break;
276 0 : default:
277 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
278 0 : break;
279 : }
280 : }
281 :
282 : static void
283 1 : gnc_entry_set_property (GObject *object,
284 : guint prop_id,
285 : const GValue *value,
286 : GParamSpec *pspec)
287 : {
288 : GncEntry *entry;
289 :
290 1 : g_return_if_fail(GNC_IS_ENTRY(object));
291 :
292 1 : entry = GNC_ENTRY(object);
293 1 : g_assert (qof_instance_get_editlevel(entry));
294 :
295 1 : switch (prop_id)
296 : {
297 1 : case PROP_DESCRIPTION:
298 1 : gncEntrySetDescription(entry, g_value_get_string(value));
299 1 : break;
300 0 : default:
301 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
302 0 : break;
303 : }
304 : }
305 :
306 : /** Return displayable name */
307 : static gchar*
308 0 : impl_get_display_name(const QofInstance* inst)
309 : {
310 : GncEntry* entry;
311 : gchar* display_name;
312 : gchar* s;
313 :
314 0 : g_return_val_if_fail(inst != NULL, FALSE);
315 0 : g_return_val_if_fail(GNC_IS_ENTRY(inst), FALSE);
316 :
317 0 : entry = GNC_ENTRY(inst);
318 0 : if (entry->order != NULL)
319 : {
320 0 : display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->order));
321 0 : s = g_strdup_printf("Entry in %s", display_name);
322 0 : g_free(display_name);
323 0 : return s;
324 : }
325 0 : if (entry->invoice != NULL)
326 : {
327 0 : display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->invoice));
328 0 : s = g_strdup_printf("Entry in %s", display_name);
329 0 : g_free(display_name);
330 0 : return s;
331 : }
332 0 : if (entry->bill != NULL)
333 : {
334 0 : display_name = qof_instance_get_display_name(QOF_INSTANCE(entry->bill));
335 0 : s = g_strdup_printf("Entry in %s", display_name);
336 0 : g_free(display_name);
337 0 : return s;
338 : }
339 :
340 0 : return g_strdup_printf("Entry %p", inst);
341 : }
342 :
343 : /** Does this object refer to a specific object */
344 : static gboolean
345 0 : impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
346 : {
347 : GncEntry* entry;
348 :
349 0 : g_return_val_if_fail(inst != NULL, FALSE);
350 0 : g_return_val_if_fail(GNC_IS_ENTRY(inst), FALSE);
351 :
352 0 : entry = GNC_ENTRY(inst);
353 :
354 0 : if (GNC_IS_ACCOUNT(ref))
355 : {
356 0 : Account* acc = GNC_ACCOUNT(ref);
357 0 : return (entry->i_account == acc || entry->b_account == acc);
358 : }
359 0 : else if (GNC_IS_TAXTABLE(ref))
360 : {
361 0 : GncTaxTable* tt = GNC_TAXTABLE(ref);
362 0 : return (entry->i_tax_table == tt || entry->b_tax_table == tt);
363 : }
364 :
365 0 : return FALSE;
366 : }
367 :
368 : /** Returns a list of my type of object which refers to an object. For example, when called as
369 : qof_instance_get_typed_referring_object_list(taxtable, account);
370 : it will return the list of taxtables which refer to a specific account. The result should be the
371 : same regardless of which taxtable object is used. The list must be freed by the caller but the
372 : objects on the list must not.
373 : */
374 : static GList*
375 0 : impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
376 : {
377 0 : if (!GNC_IS_ACCOUNT(ref) && !GNC_IS_TAXTABLE(ref))
378 : {
379 0 : return NULL;
380 : }
381 :
382 0 : return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
383 : }
384 :
385 : static void
386 11 : gnc_entry_class_init (GncEntryClass *klass)
387 : {
388 11 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
389 11 : QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
390 :
391 11 : gobject_class->dispose = gnc_entry_dispose;
392 11 : gobject_class->finalize = gnc_entry_finalize;
393 11 : gobject_class->set_property = gnc_entry_set_property;
394 11 : gobject_class->get_property = gnc_entry_get_property;
395 :
396 11 : qof_class->get_display_name = impl_get_display_name;
397 11 : qof_class->refers_to_object = impl_refers_to_object;
398 11 : qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
399 :
400 11 : 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 11 : }
411 :
412 : /* Create/Destroy Functions */
413 121 : GncEntry *gncEntryCreate (QofBook *book)
414 : {
415 : GncEntry *entry;
416 121 : gnc_numeric zero = gnc_numeric_zero ();
417 :
418 121 : if (!book) return NULL;
419 :
420 121 : entry = g_object_new (GNC_TYPE_ENTRY, NULL);
421 121 : qof_instance_init_data (&entry->inst, _GNC_MOD_NAME, book);
422 :
423 121 : entry->desc = CACHE_INSERT ("");
424 121 : entry->action = CACHE_INSERT ("");
425 121 : entry->notes = CACHE_INSERT ("");
426 121 : entry->quantity = zero;
427 :
428 121 : entry->i_price = zero;
429 121 : entry->i_taxable = TRUE;
430 121 : entry->i_discount = zero;
431 121 : entry->i_disc_type = GNC_AMT_TYPE_PERCENT;
432 121 : entry->i_disc_how = GNC_DISC_PRETAX;
433 :
434 121 : entry->b_price = zero;
435 121 : entry->b_taxable = TRUE;
436 121 : entry->billto.type = GNC_OWNER_CUSTOMER;
437 121 : entry->b_payment = GNC_PAYMENT_CASH;
438 :
439 121 : entry->values_dirty = TRUE;
440 :
441 121 : qof_event_gen (&entry->inst, QOF_EVENT_CREATE, NULL);
442 :
443 121 : return entry;
444 : }
445 :
446 21 : void gncEntryDestroy (GncEntry *entry)
447 : {
448 21 : if (!entry) return;
449 21 : qof_instance_set_destroying(entry, TRUE);
450 21 : gncEntryCommitEdit(entry);
451 : }
452 :
453 20 : static void gncEntryFree (GncEntry *entry)
454 : {
455 20 : if (!entry) return;
456 :
457 20 : qof_event_gen (&entry->inst, QOF_EVENT_DESTROY, NULL);
458 :
459 20 : CACHE_REMOVE (entry->desc);
460 20 : CACHE_REMOVE (entry->action);
461 20 : CACHE_REMOVE (entry->notes);
462 20 : if (entry->i_tax_values)
463 0 : gncAccountValueDestroy (entry->i_tax_values);
464 20 : if (entry->b_tax_values)
465 0 : gncAccountValueDestroy (entry->b_tax_values);
466 :
467 20 : if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(entry))))
468 : {
469 6 : if (entry->i_tax_table)
470 0 : gncTaxTableDecRef (entry->i_tax_table);
471 6 : if (entry->b_tax_table)
472 0 : gncTaxTableDecRef (entry->b_tax_table);
473 : }
474 :
475 : /* qof_instance_release (&entry->inst); */
476 20 : g_object_unref (entry);
477 : }
478 :
479 : /* ================================================================ */
480 : /* Set Functions */
481 :
482 127 : void gncEntrySetDate (GncEntry *entry, time64 date)
483 : {
484 127 : gboolean first_date = FALSE;
485 127 : if (!entry) return;
486 127 : if (entry->date == date) return;
487 127 : if (!entry->date)
488 120 : first_date = TRUE;
489 127 : gncEntryBeginEdit (entry);
490 127 : entry->date = date;
491 127 : mark_entry (entry);
492 127 : gncEntryCommitEdit (entry);
493 :
494 : /* Don't re-sort the first time we set the date on this entry */
495 127 : if (!first_date)
496 : {
497 7 : if (entry->invoice)
498 0 : gncInvoiceSortEntries(entry->invoice);
499 7 : if (entry->bill)
500 0 : gncInvoiceSortEntries(entry->bill);
501 : }
502 : }
503 :
504 100 : void gncEntrySetDateGDate (GncEntry *entry, const GDate* date)
505 : {
506 100 : if (!entry || !date || !g_date_valid(date))
507 0 : 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.*/
514 100 : gncEntrySetDate(entry, time64CanonicalDayTime(gdate_to_time64(*date)));
515 : }
516 :
517 13 : void gncEntrySetDateEntered (GncEntry *entry, time64 date)
518 : {
519 13 : if (!entry) return;
520 13 : if (entry->date_entered == date) return;
521 13 : gncEntryBeginEdit (entry);
522 13 : entry->date_entered = date;
523 13 : mark_entry (entry);
524 13 : gncEntryCommitEdit (entry);
525 : }
526 :
527 119 : void gncEntrySetDescription (GncEntry *entry, const char *desc)
528 : {
529 119 : if (!entry || !desc) return;
530 119 : SET_STR (entry, entry->desc, desc);
531 118 : mark_entry (entry);
532 118 : gncEntryCommitEdit (entry);
533 : }
534 :
535 104 : void gncEntrySetAction (GncEntry *entry, const char *action)
536 : {
537 104 : if (!entry || !action) return;
538 104 : SET_STR (entry, entry->action, action);
539 103 : mark_entry (entry);
540 103 : gncEntryCommitEdit (entry);
541 : }
542 :
543 62 : void gncEntrySetNotes (GncEntry *entry, const char *notes)
544 : {
545 62 : if (!entry || !notes) return;
546 62 : SET_STR (entry, entry->notes, notes);
547 61 : mark_entry (entry);
548 61 : gncEntryCommitEdit (entry);
549 : }
550 :
551 16 : void gncEntrySetQuantity (GncEntry *entry, gnc_numeric quantity)
552 : {
553 16 : if (!entry) return;
554 16 : if (gnc_numeric_eq (entry->quantity, quantity)) return;
555 15 : gncEntryBeginEdit (entry);
556 15 : entry->quantity = quantity;
557 15 : entry->values_dirty = TRUE;
558 15 : mark_entry (entry);
559 15 : gncEntryCommitEdit (entry);
560 : }
561 :
562 109 : void gncEntrySetDocQuantity (GncEntry *entry, gnc_numeric quantity, gboolean is_cn)
563 : {
564 109 : if (!entry) return;
565 109 : if (gnc_numeric_eq (entry->quantity, (is_cn ? gnc_numeric_neg (quantity) : quantity))) return;
566 108 : gncEntryBeginEdit (entry);
567 108 : entry->quantity = (is_cn ? gnc_numeric_neg (quantity) : quantity);
568 108 : entry->values_dirty = TRUE;
569 108 : mark_entry (entry);
570 108 : gncEntryCommitEdit (entry);
571 : }
572 :
573 : /* Customer Invoices */
574 :
575 95 : void gncEntrySetInvAccount (GncEntry *entry, Account *acc)
576 : {
577 95 : if (!entry) return;
578 95 : if (entry->i_account == acc) return;
579 95 : gncEntryBeginEdit (entry);
580 95 : entry->i_account = acc;
581 95 : mark_entry (entry);
582 95 : gncEntryCommitEdit (entry);
583 : }
584 :
585 93 : void gncEntrySetInvPrice (GncEntry *entry, gnc_numeric price)
586 : {
587 93 : if (!entry) return;
588 93 : if (gnc_numeric_eq (entry->i_price, price)) return;
589 92 : gncEntryBeginEdit (entry);
590 92 : entry->i_price = price;
591 92 : entry->values_dirty = TRUE;
592 92 : mark_entry (entry);
593 92 : gncEntryCommitEdit (entry);
594 : }
595 :
596 43 : void gncEntrySetInvTaxable (GncEntry *entry, gboolean taxable)
597 : {
598 43 : if (!entry) return;
599 :
600 43 : ENTER ("%d", taxable);
601 43 : if (entry->i_taxable == taxable) {
602 27 : LEAVE ("Value already set");
603 27 : return;
604 : }
605 16 : gncEntryBeginEdit (entry);
606 16 : entry->i_taxable = taxable;
607 16 : entry->values_dirty = TRUE;
608 16 : mark_entry (entry);
609 16 : gncEntryCommitEdit (entry);
610 16 : LEAVE ("");
611 : }
612 :
613 50 : void gncEntrySetInvTaxIncluded (GncEntry *entry, gboolean taxincluded)
614 : {
615 50 : if (!entry) return;
616 :
617 50 : ENTER ("%d", taxincluded);
618 50 : if (entry->i_taxincluded == taxincluded) {
619 26 : LEAVE ("Value already set");
620 26 : return;
621 : }
622 24 : gncEntryBeginEdit (entry);
623 24 : entry->i_taxincluded = taxincluded;
624 24 : entry->values_dirty = TRUE;
625 24 : mark_entry (entry);
626 24 : gncEntryCommitEdit (entry);
627 24 : LEAVE ("");
628 : }
629 :
630 148 : void gncEntrySetInvTaxTable (GncEntry *entry, GncTaxTable *table)
631 : {
632 148 : if (!entry) return;
633 :
634 148 : ENTER ("%s", gncTaxTableGetName (table));
635 148 : if (entry->i_tax_table == table) {
636 55 : LEAVE ("Value already set");
637 55 : return;
638 : }
639 93 : gncEntryBeginEdit (entry);
640 93 : if (entry->i_tax_table)
641 46 : gncTaxTableDecRef (entry->i_tax_table);
642 93 : if (table)
643 87 : gncTaxTableIncRef (table);
644 93 : entry->i_tax_table = table;
645 93 : entry->values_dirty = TRUE;
646 93 : mark_entry (entry);
647 93 : gncEntryCommitEdit (entry);
648 93 : LEAVE ("");
649 : }
650 :
651 42 : void gncEntrySetInvDiscount (GncEntry *entry, gnc_numeric discount)
652 : {
653 42 : if (!entry) return;
654 42 : if (gnc_numeric_eq (entry->i_discount, discount)) return;
655 41 : gncEntryBeginEdit (entry);
656 41 : entry->i_discount = discount;
657 41 : entry->values_dirty = TRUE;
658 41 : mark_entry (entry);
659 41 : gncEntryCommitEdit (entry);
660 : }
661 :
662 41 : void gncEntrySetInvDiscountType (GncEntry *entry, GncAmountType type)
663 : {
664 41 : if (!entry) return;
665 41 : if (entry->i_disc_type == type) return;
666 :
667 20 : gncEntryBeginEdit (entry);
668 20 : entry->i_disc_type = type;
669 20 : entry->values_dirty = TRUE;
670 20 : mark_entry (entry);
671 20 : gncEntryCommitEdit (entry);
672 : }
673 :
674 41 : void gncEntrySetInvDiscountHow (GncEntry *entry, GncDiscountHow how)
675 : {
676 41 : if (!entry) return;
677 41 : if (entry->i_disc_how == how) return;
678 :
679 25 : gncEntryBeginEdit (entry);
680 25 : entry->i_disc_how = how;
681 25 : entry->values_dirty = TRUE;
682 25 : mark_entry (entry);
683 25 : gncEntryCommitEdit (entry);
684 : }
685 :
686 1 : void qofEntrySetInvDiscType (GncEntry *entry, const char *type_string)
687 : {
688 : GncAmountType type;
689 :
690 2 : if (!entry) return;
691 1 : gncAmountStringToType(type_string, &type);
692 1 : if (entry->i_disc_type == type) return;
693 0 : gncEntryBeginEdit (entry);
694 0 : entry->i_disc_type = type;
695 0 : entry->values_dirty = TRUE;
696 0 : mark_entry (entry);
697 0 : gncEntryCommitEdit (entry);
698 :
699 : }
700 :
701 1 : void qofEntrySetInvDiscHow (GncEntry *entry, const char *type)
702 : {
703 1 : GncDiscountHow how = GNC_DISC_PRETAX;
704 :
705 2 : if (!entry) return;
706 1 : gncEntryBeginEdit (entry);
707 1 : gncEntryDiscountStringToHow(type, &how);
708 1 : if (entry->i_disc_how == how) return;
709 0 : entry->i_disc_how = how;
710 0 : entry->values_dirty = TRUE;
711 0 : mark_entry (entry);
712 0 : gncEntryCommitEdit (entry);
713 : }
714 :
715 : /* Vendor Bills */
716 :
717 23 : void gncEntrySetBillAccount (GncEntry *entry, Account *acc)
718 : {
719 23 : if (!entry) return;
720 23 : if (entry->b_account == acc) return;
721 23 : gncEntryBeginEdit (entry);
722 23 : entry->b_account = acc;
723 23 : mark_entry (entry);
724 23 : gncEntryCommitEdit (entry);
725 : }
726 :
727 23 : void gncEntrySetBillPrice (GncEntry *entry, gnc_numeric price)
728 : {
729 23 : if (!entry) return;
730 23 : if (gnc_numeric_eq (entry->b_price, price)) return;
731 22 : gncEntryBeginEdit (entry);
732 22 : entry->b_price = price;
733 22 : entry->values_dirty = TRUE;
734 22 : mark_entry (entry);
735 22 : gncEntryCommitEdit (entry);
736 : }
737 :
738 4 : void gncEntrySetBillTaxable (GncEntry *entry, gboolean taxable)
739 : {
740 4 : if (!entry) return;
741 :
742 4 : ENTER ("%d", taxable);
743 4 : if (entry->b_taxable == taxable) {
744 2 : LEAVE ("Value already set");
745 2 : return;
746 : }
747 2 : gncEntryBeginEdit (entry);
748 2 : entry->b_taxable = taxable;
749 2 : entry->values_dirty = TRUE;
750 2 : mark_entry (entry);
751 2 : gncEntryCommitEdit (entry);
752 2 : LEAVE ("");
753 : }
754 :
755 4 : void gncEntrySetBillTaxIncluded (GncEntry *entry, gboolean taxincluded)
756 : {
757 4 : if (!entry) return;
758 :
759 4 : ENTER ("%d", taxincluded);
760 4 : if (entry->b_taxincluded == taxincluded) {
761 4 : LEAVE ("Value already set");
762 4 : return;
763 : }
764 0 : gncEntryBeginEdit (entry);
765 0 : entry->b_taxincluded = taxincluded;
766 0 : entry->values_dirty = TRUE;
767 0 : mark_entry (entry);
768 0 : gncEntryCommitEdit (entry);
769 0 : LEAVE ("");
770 : }
771 :
772 20 : void gncEntrySetBillTaxTable (GncEntry *entry, GncTaxTable *table)
773 : {
774 20 : if (!entry) return;
775 :
776 20 : ENTER ("%s", gncTaxTableGetName (table));
777 20 : if (entry->b_tax_table == table) {
778 20 : LEAVE ("Value already set");
779 20 : return;
780 : }
781 0 : gncEntryBeginEdit (entry);
782 0 : if (entry->b_tax_table)
783 0 : gncTaxTableDecRef (entry->b_tax_table);
784 0 : if (table)
785 0 : gncTaxTableIncRef (table);
786 0 : entry->b_tax_table = table;
787 0 : entry->values_dirty = TRUE;
788 0 : mark_entry (entry);
789 0 : gncEntryCommitEdit (entry);
790 0 : LEAVE ("");
791 : }
792 :
793 4 : void gncEntrySetBillable (GncEntry *entry, gboolean billable)
794 : {
795 4 : if (!entry) return;
796 4 : if (entry->billable == billable) return;
797 :
798 0 : gncEntryBeginEdit (entry);
799 0 : entry->billable = billable;
800 0 : mark_entry (entry);
801 0 : gncEntryCommitEdit (entry);
802 : }
803 :
804 0 : void gncEntrySetBillTo (GncEntry *entry, GncOwner *billto)
805 : {
806 0 : if (!entry || !billto) return;
807 0 : if (gncOwnerEqual (&entry->billto, billto)) return;
808 :
809 0 : gncEntryBeginEdit (entry);
810 0 : gncOwnerCopy (billto, &entry->billto);
811 0 : mark_entry (entry);
812 0 : gncEntryCommitEdit (entry);
813 : }
814 :
815 4 : void gncEntrySetBillPayment (GncEntry *entry, GncEntryPaymentType type)
816 : {
817 4 : if (!entry) return;
818 4 : if (entry->b_payment == type) return;
819 0 : gncEntryBeginEdit (entry);
820 0 : entry->b_payment = type;
821 0 : mark_entry (entry);
822 0 : gncEntryCommitEdit (entry);
823 : }
824 :
825 : /* Called from gncOrder when we're added to the Order */
826 40 : void gncEntrySetOrder (GncEntry *entry, GncOrder *order)
827 : {
828 40 : if (!entry) return;
829 40 : if (entry->order == order) return;
830 40 : gncEntryBeginEdit (entry);
831 40 : entry->order = order;
832 40 : mark_entry (entry);
833 40 : gncEntryCommitEdit (entry);
834 :
835 : }
836 :
837 : /* called from gncInvoice when we're added to the Invoice */
838 116 : void gncEntrySetInvoice (GncEntry *entry, GncInvoice *invoice)
839 : {
840 116 : if (!entry) return;
841 116 : if (entry->invoice == invoice) return;
842 115 : gncEntryBeginEdit (entry);
843 115 : entry->invoice = invoice;
844 115 : mark_entry (entry);
845 115 : gncEntryCommitEdit (entry);
846 : }
847 :
848 : /* called from gncInvoice when we're added to the Invoice/Bill */
849 5 : void gncEntrySetBill (GncEntry *entry, GncInvoice *bill)
850 : {
851 5 : if (!entry) return;
852 5 : if (entry->bill == bill) return;
853 5 : gncEntryBeginEdit (entry);
854 5 : entry->bill = bill;
855 5 : mark_entry (entry);
856 5 : gncEntryCommitEdit (entry);
857 : }
858 :
859 0 : void gncEntryCopy (const GncEntry *src, GncEntry *dest, gboolean add_entry)
860 : {
861 0 : if (!src || !dest) return;
862 :
863 0 : gncEntryBeginEdit (dest);
864 0 : dest->date = src->date;
865 0 : dest->date_entered = src->date_entered; /* ??? */
866 0 : gncEntrySetDescription (dest, src->desc);
867 0 : gncEntrySetAction (dest, src->action);
868 0 : gncEntrySetNotes (dest, src->notes);
869 0 : dest->quantity = src->quantity;
870 :
871 0 : dest->i_account = src->i_account;
872 0 : dest->i_price = src->i_price;
873 0 : dest->i_taxable = src->i_taxable;
874 0 : dest->i_taxincluded = src->i_taxincluded;
875 0 : dest->i_discount = src->i_discount;
876 0 : dest->i_disc_type = src->i_disc_type;
877 0 : dest->i_disc_how = src->i_disc_how;
878 :
879 : /* vendor bill data */
880 0 : dest->b_account = src->b_account;
881 0 : dest->b_price = src->b_price;
882 0 : dest->b_taxable = src->b_taxable;
883 0 : dest->b_taxincluded = src->b_taxincluded;
884 0 : dest->billable = src->billable;
885 0 : dest->billto = src->billto;
886 :
887 0 : if (src->i_tax_table)
888 0 : gncEntrySetInvTaxTable (dest, src->i_tax_table);
889 :
890 0 : if (src->b_tax_table)
891 0 : gncEntrySetBillTaxTable (dest, src->b_tax_table);
892 :
893 0 : if (add_entry)
894 : {
895 0 : if (src->order)
896 0 : gncOrderAddEntry (src->order, dest);
897 :
898 0 : if (src->invoice)
899 0 : gncInvoiceAddEntry (src->invoice, dest);
900 :
901 0 : if (src->bill)
902 0 : gncBillAddEntry (src->bill, dest);
903 : }
904 :
905 0 : dest->values_dirty = TRUE;
906 0 : mark_entry (dest);
907 0 : gncEntryCommitEdit (dest);
908 : }
909 :
910 : /* ================================================================ */
911 : /* Get Functions */
912 :
913 67 : time64 gncEntryGetDate (const GncEntry *entry)
914 : {
915 67 : return entry ? entry->date : 0;
916 : }
917 :
918 0 : GDate gncEntryGetDateGDate(const GncEntry *entry)
919 : {
920 0 : return time64_to_gdate(gncEntryGetDate(entry));
921 : }
922 :
923 4 : time64 gncEntryGetDateEntered (const GncEntry *entry)
924 : {
925 4 : return entry ? entry->date_entered : 0;
926 : }
927 :
928 66 : const char * gncEntryGetDescription (const GncEntry *entry)
929 : {
930 66 : if (!entry) return NULL;
931 66 : return entry->desc;
932 : }
933 :
934 67 : const char * gncEntryGetAction (const GncEntry *entry)
935 : {
936 67 : if (!entry) return NULL;
937 67 : return entry->action;
938 : }
939 :
940 19 : const char * gncEntryGetNotes (const GncEntry *entry)
941 : {
942 19 : if (!entry) return NULL;
943 19 : return entry->notes;
944 : }
945 :
946 71 : gnc_numeric gncEntryGetQuantity (const GncEntry *entry)
947 : {
948 71 : if (!entry) return gnc_numeric_zero();
949 71 : return entry->quantity;
950 : }
951 :
952 50 : gnc_numeric gncEntryGetDocQuantity (const GncEntry *entry, gboolean is_cn)
953 : {
954 50 : gnc_numeric value = gncEntryGetQuantity (entry);
955 50 : return (is_cn ? gnc_numeric_neg (value) : value);
956 : }
957 :
958 : /* Customer Invoice */
959 :
960 92 : Account * gncEntryGetInvAccount (const GncEntry *entry)
961 : {
962 92 : if (!entry) return NULL;
963 92 : return entry->i_account;
964 : }
965 :
966 39 : gnc_numeric gncEntryGetInvPrice (const GncEntry *entry)
967 : {
968 39 : if (!entry) return gnc_numeric_zero();
969 39 : return entry->i_price;
970 : }
971 :
972 39 : gnc_numeric gncEntryGetInvDiscount (const GncEntry *entry)
973 : {
974 39 : if (!entry) return gnc_numeric_zero();
975 39 : return entry->i_discount;
976 : }
977 :
978 36 : GncAmountType gncEntryGetInvDiscountType (const GncEntry *entry)
979 : {
980 36 : if (!entry) return 0;
981 36 : return entry->i_disc_type;
982 : }
983 :
984 0 : GncDiscountHow gncEntryGetInvDiscountHow (const GncEntry *entry)
985 : {
986 0 : if (!entry) return 0;
987 0 : return entry->i_disc_how;
988 : }
989 :
990 1 : char* qofEntryGetInvDiscType (const GncEntry *entry)
991 : {
992 : char *type_string;
993 :
994 1 : if (!entry) return 0;
995 1 : type_string = g_strdup(gncAmountTypeToString(entry->i_disc_type));
996 1 : return type_string;
997 : }
998 :
999 1 : char* qofEntryGetInvDiscHow (const GncEntry *entry)
1000 : {
1001 : char *type_string;
1002 :
1003 1 : if (!entry) return 0;
1004 1 : type_string = g_strdup(gncEntryDiscountHowToString(entry->i_disc_how));
1005 1 : return type_string;
1006 : }
1007 :
1008 37 : gboolean gncEntryGetInvTaxable (const GncEntry *entry)
1009 : {
1010 37 : if (!entry) return FALSE;
1011 37 : return entry->i_taxable;
1012 : }
1013 :
1014 1 : gboolean gncEntryGetInvTaxIncluded (const GncEntry *entry)
1015 : {
1016 1 : if (!entry) return FALSE;
1017 1 : return entry->i_taxincluded;
1018 : }
1019 :
1020 129 : GncTaxTable * gncEntryGetInvTaxTable (const GncEntry *entry)
1021 : {
1022 129 : if (!entry) return NULL;
1023 129 : return entry->i_tax_table;
1024 : }
1025 :
1026 : /* vendor bills */
1027 :
1028 23 : Account * gncEntryGetBillAccount (const GncEntry *entry)
1029 : {
1030 23 : if (!entry) return NULL;
1031 23 : return entry->b_account;
1032 : }
1033 :
1034 15 : gnc_numeric gncEntryGetBillPrice (const GncEntry *entry)
1035 : {
1036 15 : if (!entry) return gnc_numeric_zero();
1037 15 : return entry->b_price;
1038 : }
1039 :
1040 15 : gboolean gncEntryGetBillTaxable (const GncEntry *entry)
1041 : {
1042 15 : if (!entry) return FALSE;
1043 15 : return entry->b_taxable;
1044 : }
1045 :
1046 3 : gboolean gncEntryGetBillTaxIncluded (const GncEntry *entry)
1047 : {
1048 3 : if (!entry) return FALSE;
1049 3 : return entry->b_taxincluded;
1050 : }
1051 :
1052 39 : GncTaxTable * gncEntryGetBillTaxTable (const GncEntry *entry)
1053 : {
1054 39 : if (!entry) return NULL;
1055 39 : return entry->b_tax_table;
1056 : }
1057 :
1058 23 : gboolean gncEntryGetBillable (const GncEntry *entry)
1059 : {
1060 23 : if (!entry) return FALSE;
1061 23 : return entry->billable;
1062 : }
1063 :
1064 3 : GncOwner * gncEntryGetBillTo (GncEntry *entry)
1065 : {
1066 3 : if (!entry) return NULL;
1067 3 : return &entry->billto;
1068 : }
1069 :
1070 3 : GncEntryPaymentType gncEntryGetBillPayment (const GncEntry* entry)
1071 : {
1072 3 : if (!entry) return 0;
1073 3 : return entry->b_payment;
1074 : }
1075 :
1076 122 : GncInvoice * gncEntryGetInvoice (const GncEntry *entry)
1077 : {
1078 122 : if (!entry) return NULL;
1079 122 : return entry->invoice;
1080 : }
1081 :
1082 18 : GncInvoice * gncEntryGetBill (const GncEntry *entry)
1083 : {
1084 18 : if (!entry) return NULL;
1085 18 : return entry->bill;
1086 : }
1087 :
1088 97 : GncOrder * gncEntryGetOrder (const GncEntry *entry)
1089 : {
1090 97 : if (!entry) return NULL;
1091 97 : 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 : */
1131 316 : static 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 316 : gnc_numeric percent = gnc_numeric_create (100, 1);
1143 316 : gnc_numeric tpercent = gnc_numeric_zero ();
1144 316 : gnc_numeric tvalue = gnc_numeric_zero ();
1145 316 : gnc_numeric i_net_price = price;
1146 :
1147 316 : GList * entries = gncTaxTableGetEntries (tax_table);
1148 : GList * node;
1149 :
1150 316 : ENTER ("");
1151 : /* Step 1: compute the aggregate price */
1152 :
1153 316 : aggregate = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1154 :
1155 316 : 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 376 : for (node = entries; node; node = node->next)
1160 : {
1161 60 : GncTaxTableEntry *entry = node->data;
1162 60 : gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
1163 :
1164 60 : switch (gncTaxTableEntryGetType (entry))
1165 : {
1166 0 : case GNC_AMT_TYPE_VALUE:
1167 0 : tvalue = gnc_numeric_add (tvalue, amount, GNC_DENOM_AUTO,
1168 : GNC_HOW_DENOM_LCD);
1169 0 : break;
1170 60 : case GNC_AMT_TYPE_PERCENT:
1171 60 : tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO,
1172 : GNC_HOW_DENOM_LCD);
1173 60 : break;
1174 0 : default:
1175 0 : PWARN ("Unknown tax type: %d", gncTaxTableEntryGetType (entry));
1176 0 : break;
1177 : }
1178 : }
1179 : /* now we need to convert from 5% -> .05 */
1180 316 : tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO,
1181 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1182 316 : 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 316 : 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 24 : pretax = gnc_numeric_sub (aggregate, tvalue, GNC_DENOM_AUTO,
1193 : GNC_HOW_DENOM_LCD);
1194 24 : 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 24 : PINFO ("pretax %" PRId64 "/%" PRId64, pretax.num, pretax.denom);
1200 24 : if (!gnc_numeric_zero_p(qty))
1201 : {
1202 24 : i_net_price = gnc_numeric_div (pretax, qty, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1203 : }
1204 24 : PINFO("i_net_price %" PRId64 "/%" PRId64, i_net_price.num, i_net_price.denom);
1205 : }
1206 : else
1207 : {
1208 292 : PINFO ("Tax not included or no tax table, pretax is aggregate");
1209 292 : 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 316 : switch (discount_how)
1232 : {
1233 296 : case GNC_DISC_PRETAX:
1234 : case GNC_DISC_SAMETIME:
1235 : /* compute the discount from pretax */
1236 :
1237 296 : if (discount_type == GNC_AMT_TYPE_PERCENT)
1238 : {
1239 108 : discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
1240 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1241 108 : discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO,
1242 : GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1243 : }
1244 :
1245 296 : 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 296 : if (discount_how == GNC_DISC_PRETAX)
1249 266 : pretax = result;
1250 296 : break;
1251 :
1252 20 : case GNC_DISC_POSTTAX:
1253 : /* compute discount on pretax+taxes */
1254 :
1255 20 : if (discount_type == GNC_AMT_TYPE_PERCENT)
1256 : {
1257 : gnc_numeric after_tax;
1258 :
1259 10 : tax = gnc_numeric_mul (pretax, tpercent, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1260 10 : after_tax = gnc_numeric_add (pretax, tax, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
1261 10 : after_tax = gnc_numeric_add (after_tax, tvalue, GNC_DENOM_AUTO,
1262 : GNC_HOW_DENOM_LCD);
1263 10 : discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
1264 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1265 10 : discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO,
1266 : GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1267 : }
1268 :
1269 20 : result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
1270 20 : break;
1271 :
1272 0 : default:
1273 0 : PWARN ("unknown DiscountHow value: %d", discount_how);
1274 0 : 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 316 : if (discount_value != NULL)
1285 158 : *discount_value = discount;
1286 :
1287 316 : if (value != NULL)
1288 316 : *value = result;
1289 :
1290 : /* Now... Compute the list of tax values (if the caller wants it) */
1291 :
1292 316 : if (tax_value != NULL)
1293 : {
1294 316 : GList * taxes = NULL;
1295 :
1296 316 : PINFO("Computing tax value list");
1297 376 : for (node = entries; node; node = node->next)
1298 : {
1299 60 : GncTaxTableEntry *entry = node->data;
1300 60 : Account *acc = gncTaxTableEntryGetAccount (entry);
1301 60 : gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
1302 :
1303 60 : g_return_if_fail (acc);
1304 :
1305 60 : switch (gncTaxTableEntryGetType (entry))
1306 : {
1307 0 : case GNC_AMT_TYPE_VALUE:
1308 0 : taxes = gncAccountValueAdd (taxes, acc, amount);
1309 0 : break;
1310 60 : case GNC_AMT_TYPE_PERCENT:
1311 60 : amount = gnc_numeric_div (amount, percent, GNC_DENOM_AUTO,
1312 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
1313 60 : tax = gnc_numeric_mul (pretax, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
1314 60 : taxes = gncAccountValueAdd (taxes, acc, tax);
1315 60 : break;
1316 0 : default:
1317 0 : break;
1318 : }
1319 : }
1320 316 : *tax_value = taxes;
1321 : }
1322 :
1323 316 : if (net_price != NULL)
1324 0 : *net_price = i_net_price;
1325 :
1326 316 : LEAVE ("");
1327 316 : return;
1328 : }
1329 :
1330 316 : void 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 316 : gncEntryComputeValueInt (qty, price, tax_table, tax_included, discount, discount_type,
1338 : discount_how, value, discount_value, tax_value, NULL);
1339 316 : }
1340 :
1341 : static int
1342 158 : get_entry_commodity_denom (const GncEntry *entry)
1343 : {
1344 : gnc_commodity *c;
1345 158 : if (!entry)
1346 0 : return 0;
1347 158 : if (entry->invoice)
1348 : {
1349 152 : c = gncInvoiceGetCurrency (entry->invoice);
1350 152 : if (c)
1351 152 : return (gnc_commodity_get_fraction (c));
1352 : }
1353 6 : if (entry->bill)
1354 : {
1355 1 : c = gncInvoiceGetCurrency (entry->bill);
1356 1 : if (c)
1357 1 : return (gnc_commodity_get_fraction (c));
1358 : }
1359 5 : return 100000;
1360 : }
1361 :
1362 : static void
1363 1221 : gncEntryRecomputeValues (GncEntry *entry)
1364 : {
1365 : int denom;
1366 : GList *tv_iter;
1367 :
1368 1221 : ENTER ("");
1369 : /* See if either tax table changed since we last computed values */
1370 1221 : if (entry->i_tax_table)
1371 : {
1372 528 : time64 modtime = gncTaxTableLastModifiedSecs (entry->i_tax_table);
1373 528 : if (entry->i_taxtable_modtime != modtime)
1374 : {
1375 41 : PINFO ("Invoice tax table changed since last recompute.");
1376 41 : entry->values_dirty = TRUE;
1377 41 : entry->i_taxtable_modtime = modtime;
1378 : }
1379 : }
1380 1221 : if (entry->b_tax_table)
1381 : {
1382 0 : time64 modtime = gncTaxTableLastModifiedSecs (entry->b_tax_table);
1383 0 : if (entry->b_taxtable_modtime != modtime)
1384 : {
1385 0 : PINFO ("Bill tax table changed since last recompute.");
1386 0 : entry->values_dirty = TRUE;
1387 0 : entry->b_taxtable_modtime = modtime;
1388 : }
1389 : }
1390 :
1391 1221 : if (!entry->values_dirty) {
1392 1063 : LEAVE ("No changes");
1393 1063 : return;
1394 : }
1395 :
1396 : /* Clear the last-computed tax values */
1397 158 : if (entry->i_tax_values)
1398 : {
1399 34 : gncAccountValueDestroy (entry->i_tax_values);
1400 34 : entry->i_tax_values = NULL;
1401 : }
1402 158 : if (entry->b_tax_values)
1403 : {
1404 0 : gncAccountValueDestroy (entry->b_tax_values);
1405 0 : entry->b_tax_values = NULL;
1406 : }
1407 :
1408 : /* Determine the commodity denominator */
1409 158 : denom = get_entry_commodity_denom (entry);
1410 :
1411 : /* Compute the invoice values */
1412 158 : DEBUG("Compute Invoice Values.");
1413 158 : gncEntryComputeValue (entry->quantity, entry->i_price,
1414 158 : (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 158 : DEBUG("Compute BILL Values.");
1424 0 : gncEntryComputeValue (entry->quantity, entry->b_price,
1425 158 : (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 158 : entry->i_value_rounded = gnc_numeric_convert (entry->i_value, denom,
1432 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1433 158 : 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 158 : entry->i_tax_value = gncAccountValueTotal (entry->i_tax_values);
1436 158 : entry->i_tax_value_rounded = gnc_numeric_zero();
1437 218 : for (tv_iter = entry->i_tax_values; tv_iter; tv_iter=tv_iter->next)
1438 : {
1439 60 : GncAccountValue *acc_val = tv_iter->data;
1440 60 : 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 158 : entry->b_value_rounded = gnc_numeric_convert (entry->b_value, denom,
1445 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1446 158 : entry->b_tax_value = gncAccountValueTotal (entry->b_tax_values);
1447 158 : entry->b_tax_value_rounded = gnc_numeric_zero();
1448 158 : for (tv_iter = entry->b_tax_values; tv_iter; tv_iter=tv_iter->next)
1449 : {
1450 0 : GncAccountValue *acc_val = tv_iter->data;
1451 0 : 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 158 : entry->values_dirty = FALSE;
1455 158 : 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. */
1460 555 : static gnc_numeric gncEntryGetIntValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1461 : {
1462 555 : if (!entry) return gnc_numeric_zero();
1463 555 : gncEntryRecomputeValues (entry);
1464 555 : if (round)
1465 545 : return (is_cust_doc ? entry->i_value_rounded : entry->b_value_rounded);
1466 : else
1467 10 : return (is_cust_doc ? entry->i_value : entry->b_value);
1468 : }
1469 :
1470 176 : static gnc_numeric gncEntryGetIntTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1471 : {
1472 176 : if (!entry) return gnc_numeric_zero();
1473 176 : gncEntryRecomputeValues (entry);
1474 176 : if (round)
1475 166 : return (is_cust_doc ? entry->i_tax_value_rounded : entry->b_tax_value_rounded);
1476 : else
1477 10 : 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 */
1481 490 : static AccountValueList * gncEntryGetIntTaxValues (GncEntry *entry, gboolean is_cust_doc)
1482 : {
1483 490 : if (!entry) return NULL;
1484 490 : gncEntryRecomputeValues (entry);
1485 490 : return (is_cust_doc ? entry->i_tax_values : entry->b_tax_values);
1486 : }
1487 :
1488 0 : static gnc_numeric gncEntryGetIntDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1489 : {
1490 0 : if (!entry) return gnc_numeric_zero();
1491 0 : gncEntryRecomputeValues (entry);
1492 0 : if (round)
1493 0 : return (is_cust_doc ? entry->i_disc_value_rounded : gnc_numeric_zero());
1494 : else
1495 0 : 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) */
1502 0 : gnc_numeric gncEntryGetPrice (const GncEntry *entry, gboolean cust_doc, gboolean net)
1503 : {
1504 : gnc_numeric result;
1505 : int denom;
1506 :
1507 0 : if (!entry) return gnc_numeric_zero();
1508 0 : if (!net) return (cust_doc ? entry->i_price : entry->b_price);
1509 :
1510 :
1511 : /* Compute the net price */
1512 0 : if (cust_doc)
1513 0 : gncEntryComputeValueInt (entry->quantity, entry->i_price,
1514 0 : (entry->i_taxable ? entry->i_tax_table : NULL),
1515 0 : entry->i_taxincluded,
1516 0 : entry->i_discount, entry->i_disc_type,
1517 0 : entry->i_disc_how,
1518 : NULL, NULL, NULL, &result);
1519 : else
1520 0 : gncEntryComputeValueInt (entry->quantity, entry->b_price,
1521 0 : (entry->b_taxable ? entry->b_tax_table : NULL),
1522 0 : 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 0 : denom = get_entry_commodity_denom (entry);
1528 :
1529 0 : result = gnc_numeric_convert (result, denom,
1530 : GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1531 :
1532 0 : return result;
1533 : }
1534 :
1535 447 : gnc_numeric gncEntryGetDocValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1536 : {
1537 447 : gnc_numeric value = gncEntryGetIntValue (entry, round, is_cust_doc);
1538 447 : return (is_cn ? gnc_numeric_neg (value) : value);
1539 : }
1540 :
1541 68 : gnc_numeric gncEntryGetDocTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1542 : {
1543 68 : gnc_numeric value = gncEntryGetIntTaxValue (entry, round, is_cust_doc);
1544 68 : 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 */
1548 490 : AccountValueList * gncEntryGetDocTaxValues (GncEntry *entry, gboolean is_cust_doc, gboolean is_cn)
1549 : {
1550 490 : AccountValueList *int_values = gncEntryGetIntTaxValues (entry, is_cust_doc);
1551 490 : AccountValueList *values = NULL, *node;
1552 :
1553 : /* Make a copy of the list with negated values if necessary. */
1554 615 : for (node = int_values; node; node = node->next)
1555 : {
1556 125 : GncAccountValue *acct_val = node->data;
1557 125 : values = gncAccountValueAdd (values, acct_val->account,
1558 0 : (is_cn ? gnc_numeric_neg (acct_val->value)
1559 : : acct_val->value));
1560 : }
1561 :
1562 490 : return values;
1563 : }
1564 :
1565 0 : gnc_numeric gncEntryGetDocDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc, gboolean is_cn)
1566 : {
1567 0 : gnc_numeric value = gncEntryGetIntDiscountValue (entry, round, is_cust_doc);
1568 0 : return (is_cn ? gnc_numeric_neg (value) : value);
1569 : }
1570 :
1571 108 : gnc_numeric gncEntryGetBalValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1572 : {
1573 108 : gnc_numeric value = gncEntryGetIntValue (entry, round, is_cust_doc);
1574 108 : return (is_cust_doc ? gnc_numeric_neg (value) : value);
1575 : }
1576 :
1577 108 : gnc_numeric gncEntryGetBalTaxValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1578 : {
1579 108 : gnc_numeric value = gncEntryGetIntTaxValue (entry, round, is_cust_doc);
1580 108 : 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 */
1584 0 : AccountValueList * gncEntryGetBalTaxValues (GncEntry *entry, gboolean is_cust_doc)
1585 : {
1586 0 : AccountValueList *int_values = gncEntryGetIntTaxValues (entry, is_cust_doc);
1587 0 : AccountValueList *values = NULL, *node;
1588 :
1589 : /* Make a copy of the list with negated values if necessary. */
1590 0 : for (node = int_values; node; node = node->next)
1591 : {
1592 0 : GncAccountValue *acct_val = node->data;
1593 0 : values = gncAccountValueAdd (values, acct_val->account,
1594 0 : (is_cust_doc ? gnc_numeric_neg (acct_val->value)
1595 : : acct_val->value));
1596 : }
1597 :
1598 0 : return values;
1599 : }
1600 :
1601 0 : gnc_numeric gncEntryGetBalDiscountValue (GncEntry *entry, gboolean round, gboolean is_cust_doc)
1602 : {
1603 0 : gnc_numeric value = gncEntryGetIntDiscountValue (entry, round, is_cust_doc);
1604 0 : return (is_cust_doc ? gnc_numeric_neg (value) : value);
1605 : }
1606 :
1607 : /* XXX this existence of this routine is just wrong */
1608 0 : gboolean gncEntryIsOpen (const GncEntry *entry)
1609 : {
1610 0 : if (!entry) return FALSE;
1611 0 : return (qof_instance_get_editlevel(entry) > 0);
1612 : }
1613 :
1614 : /* ================================================================ */
1615 :
1616 1299 : void gncEntryBeginEdit (GncEntry *entry)
1617 : {
1618 1299 : qof_begin_edit(&entry->inst);
1619 1299 : }
1620 :
1621 0 : static void gncEntryOnError (QofInstance *entry, QofBackendError errcode)
1622 : {
1623 0 : PERR("Entry QofBackend Failure: %d", errcode);
1624 0 : gnc_engine_signal_commit_error( errcode );
1625 0 : }
1626 :
1627 1206 : static void gncEntryOnDone (QofInstance *inst) {}
1628 :
1629 20 : static void entry_free (QofInstance *inst)
1630 : {
1631 20 : GncEntry *entry = (GncEntry *)inst;
1632 20 : gncEntryFree (entry);
1633 20 : }
1634 :
1635 1298 : void gncEntryCommitEdit (GncEntry *entry)
1636 : {
1637 : /* GnuCash 2.6.3 and earlier didn't handle entry kvp's... */
1638 1298 : if (qof_instance_has_kvp(QOF_INSTANCE(entry)))
1639 0 : gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (entry)),
1640 : GNC_FEATURE_KVP_EXTRA_DATA);
1641 :
1642 1298 : if (!qof_commit_edit (QOF_INSTANCE(entry))) return;
1643 1226 : qof_commit_edit_part2 (&entry->inst, gncEntryOnError,
1644 : gncEntryOnDone, entry_free);
1645 : }
1646 :
1647 240 : int gncEntryCompare (const GncEntry *a, const GncEntry *b)
1648 : {
1649 : int compare;
1650 :
1651 240 : if (a == b) return 0;
1652 240 : if (!a && b) return -1;
1653 240 : if (a && !b) return 1;
1654 240 : g_assert (a && b); /* Silence a static analysis warning. */
1655 240 : if (a->date != b->date) return a->date - b->date;
1656 240 : if (a->date_entered != b->date_entered) return a->date_entered - b->date_entered;
1657 :
1658 240 : compare = g_strcmp0 (a->desc, b->desc);
1659 240 : if (compare) return compare;
1660 :
1661 0 : compare = g_strcmp0 (a->action, b->action);
1662 0 : if (compare) return compare;
1663 :
1664 0 : 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 :
1699 : static void
1700 15 : destroy_entry_on_book_close(QofInstance *ent, gpointer data)
1701 : {
1702 15 : GncEntry* entry = GNC_ENTRY(ent);
1703 :
1704 15 : gncEntryBeginEdit(entry);
1705 15 : gncEntryDestroy(entry);
1706 15 : }
1707 :
1708 : /** Handles book end - frees all entries from the book
1709 : *
1710 : * @param book Book being closed
1711 : */
1712 : static void
1713 179 : gnc_entry_book_end(QofBook* book)
1714 : {
1715 : QofCollection *col;
1716 :
1717 179 : col = qof_book_get_collection(book, GNC_ID_ENTRY);
1718 179 : qof_collection_foreach(col, destroy_entry_on_book_close, NULL);
1719 179 : }
1720 :
1721 : static 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 :
1736 83 : gboolean 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 83 : qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncEntryCompare, params);
1785 :
1786 83 : return qof_object_register (&gncEntryDesc);
1787 : }
|