GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gncBillTerm.c
1 /********************************************************************\
2  * gncBillTerm.c -- the Gnucash Billing Terms 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) 2002 Derek Atkins
25  * Copyright (C) 2003 Linas Vepstas <[email protected]>
26  * Author: Derek Atkins <[email protected]>
27  */
28 
29 #include <config.h>
30 
31 #include <glib.h>
32 #include <qofinstance-p.h>
33 
34 #include "gnc-engine.h"
35 #include "gncBillTermP.h"
36 
38 {
39  QofInstance inst;
40 
41  /* 'visible' data fields directly manipulated by user */
42  char * name;
43  char * desc;
44  GncBillTermType type;
45  gint due_days;
46  gint disc_days;
47  gnc_numeric discount;
48  gint cutoff;
49 
50  /* Internal management fields */
51  /* See src/doc/business.txt for an explanation of the following */
52  /* Code that handles this is *identical* to that in gncTaxTable */
53  gint64 refcount;
54  GncBillTerm * parent; /* if non-null, we are an immutable child */
55  GncBillTerm * child; /* if non-null, we have not changed */
56  gboolean invisible;
57  GList * children; /* list of children for disconnection */
58 };
59 
61 {
62  QofInstanceClass parent_class;
63 };
64 
65 struct _book_info
66 {
67  GList * terms; /* visible terms */
68 };
69 
70 static QofLogModule log_module = GNC_MOD_BUSINESS;
71 
72 #define _GNC_MOD_NAME GNC_ID_BILLTERM
73 
74 #define SET_STR(obj, member, str) { \
75  char * tmp; \
76  \
77  if (!g_strcmp0 (member, str)) return; \
78  gncBillTermBeginEdit (obj); \
79  tmp = CACHE_INSERT (str); \
80  CACHE_REMOVE (member); \
81  member = tmp; \
82  }
83 
84 AS_STRING_DEC(GncBillTermType, ENUM_TERMS_TYPE)
85 FROM_STRING_DEC(GncBillTermType, ENUM_TERMS_TYPE)
86 
87 /* ============================================================== */
88 /* Misc inline utilities */
89 
90 static inline void
91 mark_term (GncBillTerm *term)
92 {
93  qof_instance_set_dirty(&term->inst);
94  qof_event_gen (&term->inst, QOF_EVENT_MODIFY, NULL);
95 }
96 
97 static inline void maybe_resort_list (GncBillTerm *term)
98 {
99  struct _book_info *bi;
100 
101  if (term->parent || term->invisible) return;
102  bi = qof_book_get_data (qof_instance_get_book(term), _GNC_MOD_NAME);
103  bi->terms = g_list_sort (bi->terms, (GCompareFunc)gncBillTermCompare);
104 }
105 
106 static inline void addObj (GncBillTerm *term)
107 {
108  struct _book_info *bi;
109  bi = qof_book_get_data (qof_instance_get_book(term), _GNC_MOD_NAME);
110  bi->terms = g_list_insert_sorted (bi->terms, term,
111  (GCompareFunc)gncBillTermCompare);
112 }
113 
114 static inline void remObj (GncBillTerm *term)
115 {
116  struct _book_info *bi;
117  bi = qof_book_get_data (qof_instance_get_book(term), _GNC_MOD_NAME);
118  bi->terms = g_list_remove (bi->terms, term);
119 }
120 
121 static inline void
122 gncBillTermAddChild (GncBillTerm *table, GncBillTerm *child)
123 {
124  g_return_if_fail(qof_instance_get_destroying(table) == FALSE);
125  table->children = g_list_prepend(table->children, child);
126 }
127 
128 static inline void
129 gncBillTermRemoveChild (GncBillTerm *table, GncBillTerm *child)
130 {
131  if (qof_instance_get_destroying(table)) return;
132  table->children = g_list_remove(table->children, child);
133 }
134 
135 /* ============================================================== */
136 
137 enum
138 {
139  PROP_0,
140  PROP_NAME
141 };
142 
143 /* GObject Initialization */
144 G_DEFINE_TYPE(GncBillTerm, gnc_billterm, QOF_TYPE_INSTANCE);
145 
146 static void
147 gnc_billterm_init(GncBillTerm* bt)
148 {
149 }
150 
151 static void
152 gnc_billterm_dispose(GObject *btp)
153 {
154  G_OBJECT_CLASS(gnc_billterm_parent_class)->dispose(btp);
155 }
156 
157 static void
158 gnc_billterm_finalize(GObject* btp)
159 {
160  G_OBJECT_CLASS(gnc_billterm_parent_class)->finalize(btp);
161 }
162 
163 static void
164 gnc_billterm_get_property (GObject *object,
165  guint prop_id,
166  GValue *value,
167  GParamSpec *pspec)
168 {
169  GncBillTerm *bt;
170 
171  g_return_if_fail(GNC_IS_BILLTERM(object));
172 
173  bt = GNC_BILLTERM(object);
174  switch (prop_id)
175  {
176  case PROP_NAME:
177  g_value_set_string(value, bt->name);
178  break;
179  default:
180  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
181  break;
182  }
183 }
184 
185 static void
186 gnc_billterm_set_property (GObject *object,
187  guint prop_id,
188  const GValue *value,
189  GParamSpec *pspec)
190 {
191  GncBillTerm *bt;
192 
193  g_return_if_fail(GNC_IS_BILLTERM(object));
194 
195  bt = GNC_BILLTERM(object);
196  g_assert (qof_instance_get_editlevel(bt));
197 
198  switch (prop_id)
199  {
200  case PROP_NAME:
201  gncBillTermSetName(bt, g_value_get_string(value));
202  break;
203  default:
204  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
205  break;
206  }
207 }
208 
215 static GList*
216 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
217 {
218  /* Bill term doesn't refer to anything except other billterms */
219  return NULL;
220 }
221 
222 static void
223 gnc_billterm_class_init (GncBillTermClass *klass)
224 {
225  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
226  QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
227 
228  gobject_class->dispose = gnc_billterm_dispose;
229  gobject_class->finalize = gnc_billterm_finalize;
230  gobject_class->set_property = gnc_billterm_set_property;
231  gobject_class->get_property = gnc_billterm_get_property;
232 
233  qof_class->get_display_name = NULL;
234  qof_class->refers_to_object = NULL;
235  qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
236 
237  g_object_class_install_property
238  (gobject_class,
239  PROP_NAME,
240  g_param_spec_string ("name",
241  "BillTerm Name",
242  "The bill term name is an arbitrary string "
243  "assigned by the user. It is intended to "
244  "a short, 10 to 30 character long string "
245  "that is displayed by the GUI as the "
246  "billterm mnemonic.",
247  NULL,
248  G_PARAM_READWRITE));
249 }
250 
251 /* Create/Destroy Functions */
252 GncBillTerm * gncBillTermCreate (QofBook *book)
253 {
254  GncBillTerm *term;
255  if (!book) return NULL;
256 
257  term = g_object_new (GNC_TYPE_BILLTERM, NULL);
258  qof_instance_init_data(&term->inst, _GNC_MOD_NAME, book);
259  term->name = CACHE_INSERT ("");
260  term->desc = CACHE_INSERT ("");
261  term->discount = gnc_numeric_zero ();
262  addObj (term);
263  qof_event_gen (&term->inst, QOF_EVENT_CREATE, NULL);
264  return term;
265 }
266 
267 void gncBillTermDestroy (GncBillTerm *term)
268 {
269  gchar guidstr[GUID_ENCODING_LENGTH+1];
270  if (!term) return;
271  guid_to_string_buff(qof_instance_get_guid(&term->inst),guidstr);
272  DEBUG("destroying bill term %s (%p)", guidstr, term);
273  qof_instance_set_destroying(term, TRUE);
274  qof_instance_set_dirty (&term->inst);
275  gncBillTermCommitEdit (term);
276 }
277 
278 static void gncBillTermFree (GncBillTerm *term)
279 {
280  GncBillTerm *child;
281  GList *list;
282 
283  if (!term) return;
284 
285  qof_event_gen (&term->inst, QOF_EVENT_DESTROY, NULL);
286  CACHE_REMOVE (term->name);
287  CACHE_REMOVE (term->desc);
288  remObj (term);
289 
290  if (!qof_instance_get_destroying(term))
291  PERR("free a billterm without do_free set!");
292 
293  /* disconnect from parent */
294  if (term->parent)
295  gncBillTermRemoveChild(term->parent, term);
296 
297  /* disconnect from the children */
298  for (list = term->children; list; list = list->next)
299  {
300  child = list->data;
301  gncBillTermSetParent(child, NULL);
302  }
303  g_list_free(term->children);
304 
305  /* qof_instance_release(&term->inst); */
306  g_object_unref (term);
307 }
308 
309 /* ============================================================== */
310 /* Set Functions */
311 
312 void gncBillTermSetName (GncBillTerm *term, const char *name)
313 {
314  if (!term || !name) return;
315  SET_STR (term, term->name, name);
316  mark_term (term);
317  maybe_resort_list (term);
318  gncBillTermCommitEdit (term);
319 }
320 
321 void gncBillTermSetDescription (GncBillTerm *term, const char *desc)
322 {
323  if (!term || !desc) return;
324  SET_STR (term, term->desc, desc);
325  mark_term (term);
326  maybe_resort_list (term);
327  gncBillTermCommitEdit (term);
328 }
329 
330 void gncBillTermSetType (GncBillTerm *term, GncBillTermType type)
331 {
332  if (!term) return;
333  if (term->type == type) return;
334  gncBillTermBeginEdit (term);
335  term->type = type;
336  mark_term (term);
337  gncBillTermCommitEdit (term);
338 }
339 
341 FROM_STRING_FUNC(GncBillTermType, ENUM_TERMS_TYPE)
342 
343 static
344 void qofBillTermSetType (GncBillTerm *term, const char *type_label)
345 {
346  GncBillTermType type;
347 
348  type = GncBillTermTypefromString(type_label);
349  gncBillTermSetType(term, type);
350 }
351 
352 void gncBillTermSetDueDays (GncBillTerm *term, gint days)
353 {
354  if (!term) return;
355  if (term->due_days == days) return;
356  gncBillTermBeginEdit (term);
357  term->due_days = days;
358  mark_term (term);
359  gncBillTermCommitEdit (term);
360 }
361 
362 void gncBillTermSetDiscountDays (GncBillTerm *term, gint days)
363 {
364  if (!term) return;
365  if (term->disc_days == days) return;
366  gncBillTermBeginEdit (term);
367  term->disc_days = days;
368  mark_term (term);
369  gncBillTermCommitEdit (term);
370 }
371 
372 void gncBillTermSetDiscount (GncBillTerm *term, gnc_numeric discount)
373 {
374  if (!term) return;
375  if (gnc_numeric_eq (term->discount, discount)) return;
376  gncBillTermBeginEdit (term);
377  term->discount = discount;
378  mark_term (term);
379  gncBillTermCommitEdit (term);
380 }
381 
382 void gncBillTermSetCutoff (GncBillTerm *term, gint cutoff)
383 {
384  if (!term) return;
385  if (term->cutoff == cutoff) return;
386  gncBillTermBeginEdit (term);
387  term->cutoff = cutoff;
388  mark_term (term);
389  gncBillTermCommitEdit (term);
390 }
391 
392 /* XXX this doesn't seem right. If the parent/child relationship
393  * is a doubly-linked list, then there shouldn't be separate set-parent,
394  * set-child routines, else misuse of the routines will goof up
395  * relationships. These ops should be atomic, I think.
396  */
397 void gncBillTermSetParent (GncBillTerm *term, GncBillTerm *parent)
398 {
399  if (!term) return;
400  gncBillTermBeginEdit (term);
401  if (term->parent)
402  gncBillTermRemoveChild(term->parent, term);
403  term->parent = parent;
404  if (parent)
405  gncBillTermAddChild(parent, term);
406  term->refcount = 0;
407  if ( parent != NULL )
408  {
409  gncBillTermMakeInvisible (term);
410  }
411  mark_term (term);
412  gncBillTermCommitEdit (term);
413 }
414 
415 void gncBillTermSetChild (GncBillTerm *term, GncBillTerm *child)
416 {
417  if (!term) return;
418  gncBillTermBeginEdit (term);
419  term->child = child;
420  mark_term (term);
421  gncBillTermCommitEdit (term);
422 }
423 
424 void gncBillTermIncRef (GncBillTerm *term)
425 {
426  if (!term) return;
427  if (term->parent || term->invisible) return; /* children dont need refcounts */
428  gncBillTermBeginEdit (term);
429  term->refcount++;
430  mark_term (term);
431  gncBillTermCommitEdit (term);
432 }
433 
434 void gncBillTermDecRef (GncBillTerm *term)
435 {
436  if (!term) return;
437  if (term->parent || term->invisible) return; /* children dont need refcounts */
438  g_return_if_fail (term->refcount >= 1);
439  gncBillTermBeginEdit (term);
440  term->refcount--;
441  mark_term (term);
442  gncBillTermCommitEdit (term);
443 }
444 
445 void gncBillTermSetRefcount (GncBillTerm *term, gint64 refcount)
446 {
447  if (!term) return;
448  gncBillTermBeginEdit (term);
449  term->refcount = refcount;
450  mark_term (term);
451  gncBillTermCommitEdit (term);
452 }
453 
454 void gncBillTermMakeInvisible (GncBillTerm *term)
455 {
456  if (!term) return;
457  gncBillTermBeginEdit (term);
458  term->invisible = TRUE;
459  remObj (term);
460  mark_term (term);
461  gncBillTermCommitEdit (term);
462 }
463 
464 void gncBillTermChanged (GncBillTerm *term)
465 {
466  if (!term) return;
467  term->child = NULL;
468 }
469 
470 void gncBillTermBeginEdit (GncBillTerm *term)
471 {
472  qof_begin_edit(&term->inst);
473 }
474 
475 static void gncBillTermOnError (QofInstance *inst, QofBackendError errcode)
476 {
477  PERR("BillTerm QofBackend Failure: %d", errcode);
478  gnc_engine_signal_commit_error( errcode );
479 }
480 
481 static void bill_free (QofInstance *inst)
482 {
483  GncBillTerm *term = (GncBillTerm *) inst;
484  gncBillTermFree(term);
485 }
486 
487 static void on_done (QofInstance *inst) {}
488 
489 void gncBillTermCommitEdit (GncBillTerm *term)
490 {
491  if (!qof_commit_edit (QOF_INSTANCE(term))) return;
492  qof_commit_edit_part2 (&term->inst, gncBillTermOnError,
493  on_done, bill_free);
494 }
495 
496 /* Get Functions */
497 
498 GncBillTerm *gncBillTermLookupByName (QofBook *book, const char *name)
499 {
500  GList *list = gncBillTermGetTerms (book);
501 
502  for ( ; list; list = list->next)
503  {
504  GncBillTerm *term = list->data;
505  if (!g_strcmp0 (term->name, name))
506  return list->data;
507  }
508  return NULL;
509 }
510 
511 GList * gncBillTermGetTerms (QofBook *book)
512 {
513  struct _book_info *bi;
514  if (!book) return NULL;
515 
516  bi = qof_book_get_data (book, _GNC_MOD_NAME);
517  return bi->terms;
518 }
519 
520 const char *gncBillTermGetName (const GncBillTerm *term)
521 {
522  if (!term) return NULL;
523  return term->name;
524 }
525 
526 const char *gncBillTermGetDescription (const GncBillTerm *term)
527 {
528  if (!term) return NULL;
529  return term->desc;
530 }
531 
532 GncBillTermType gncBillTermGetType (const GncBillTerm *term)
533 {
534  if (!term) return 0;
535  return term->type;
536 }
537 
539 AS_STRING_FUNC(GncBillTermType, ENUM_TERMS_TYPE)
540 
541 static
542 const char* qofBillTermGetType (const GncBillTerm *term)
543 {
544  if (!term)
545  {
546  return NULL;
547  }
548  return GncBillTermTypeasString(term->type);
549 }
550 
551 gint gncBillTermGetDueDays (const GncBillTerm *term)
552 {
553  if (!term) return 0;
554  return term->due_days;
555 }
556 
557 gint gncBillTermGetDiscountDays (const GncBillTerm *term)
558 {
559  if (!term) return 0;
560  return term->disc_days;
561 }
562 
563 gnc_numeric gncBillTermGetDiscount (const GncBillTerm *term)
564 {
565  if (!term) return gnc_numeric_zero ();
566  return term->discount;
567 }
568 
569 gint gncBillTermGetCutoff (const GncBillTerm *term)
570 {
571  if (!term) return 0;
572  return term->cutoff;
573 }
574 
575 static GncBillTerm *gncBillTermCopy (const GncBillTerm *term)
576 {
577  GncBillTerm *t;
578 
579  if (!term) return NULL;
580  t = gncBillTermCreate (qof_instance_get_book(term));
581 
582  gncBillTermBeginEdit(t);
583 
584  gncBillTermSetName (t, term->name);
585  gncBillTermSetDescription (t, term->desc);
586 
587  t->type = term->type;
588  t->due_days = term->due_days;
589  t->disc_days = term->disc_days;
590  t->discount = term->discount;
591  t->cutoff = term->cutoff;
592 
593  mark_term (t);
594  gncBillTermCommitEdit(t);
595 
596  return t;
597 }
598 
599 GncBillTerm *gncBillTermReturnChild (GncBillTerm *term, gboolean make_new)
600 {
601  GncBillTerm *child = NULL;
602 
603  if (!term) return NULL;
604  if (term->child) return term->child;
605  if (term->parent || term->invisible) return term;
606  if (make_new)
607  {
608  child = gncBillTermCopy (term);
609  gncBillTermSetChild (term, child);
610  gncBillTermSetParent (child, term);
611  }
612  return child;
613 }
614 
615 GncBillTerm *gncBillTermGetParent (const GncBillTerm *term)
616 {
617  if (!term) return NULL;
618  return term->parent;
619 }
620 
621 gint64 gncBillTermGetRefcount (const GncBillTerm *term)
622 {
623  if (!term) return 0;
624  return term->refcount;
625 }
626 
627 gboolean gncBillTermGetInvisible (const GncBillTerm *term)
628 {
629  if (!term) return FALSE;
630  return term->invisible;
631 }
632 
634 {
635  int ret;
636 
637  if (!a && !b) return 0;
638  if (!a) return -1;
639  if (!b) return 1;
640 
641  ret = g_strcmp0 (a->name, b->name);
642  if (ret) return ret;
643 
644  return g_strcmp0 (a->desc, b->desc);
645 }
646 
647 gboolean gncBillTermEqual(const GncBillTerm *a, const GncBillTerm *b)
648 {
649  if (a == NULL && b == NULL) return TRUE;
650  if (a == NULL || b == NULL) return FALSE;
651 
652  g_return_val_if_fail(GNC_IS_BILLTERM(a), FALSE);
653  g_return_val_if_fail(GNC_IS_BILLTERM(b), FALSE);
654 
655  if (g_strcmp0(a->name, b->name) != 0)
656  {
657  PWARN("Names differ: %s vs %s", a->name, b->name);
658  return FALSE;
659  }
660 
661  if (g_strcmp0(a->desc, b->desc) != 0)
662  {
663  PWARN("Descriptions differ: %s vs %s", a->desc, b->desc);
664  return FALSE;
665  }
666 
667  if (a->type != b->type)
668  {
669  PWARN("Types differ");
670  return FALSE;
671  }
672 
673  if (a->due_days != b->due_days)
674  {
675  PWARN("Due days differ: %d vs %d", a->due_days, b->due_days);
676  return FALSE;
677  }
678 
679  if (a->disc_days != b->disc_days)
680  {
681  PWARN("Discount days differ: %d vs %d", a->disc_days, b->disc_days);
682  return FALSE;
683  }
684 
685  if (!gnc_numeric_equal(a->discount, b->discount))
686  {
687  PWARN("Discounts differ");
688  return FALSE;
689  }
690 
691  if (a->cutoff != b->cutoff)
692  {
693  PWARN("Cutoffs differ: %d vs %d", a->cutoff, b->cutoff);
694  return FALSE;
695  }
696 
697  if (a->invisible != b->invisible)
698  {
699  PWARN("Invisible flags differ");
700  return FALSE;
701  }
702 
703 // gint64 refcount;
704 // GncBillTerm * parent; /* if non-null, we are an immutable child */
705 // GncBillTerm * child; /* if non-null, we have not changed */
706 // GList * children; /* list of children for disconnection */
707 
708  return TRUE;
709 }
710 
711 gboolean gncBillTermIsFamily (const GncBillTerm *a, const GncBillTerm *b)
712 {
713  if (!gncBillTermCompare (a, b))
714  return TRUE;
715  else
716  return FALSE;
717 }
718 
719 gboolean gncBillTermIsDirty (const GncBillTerm *term)
720 {
721  if (!term) return FALSE;
722  return qof_instance_get_dirty_flag(term);
723 }
724 
725 /********************************************************/
726 /* functions to compute dates from Bill Terms */
727 
728 #define SECS_PER_DAY 86400
729 
730 /* Based on the post date and a proximo type, compute the month and
731  * year this is due. The actual day is filled in below.
732  *
733  * A proximo billing term has multiple parameters:
734  * * due day: day of the month the invoice/bill will be due
735  * * cutoff: day of the month used to decide if the due date will be
736  * in the next month or in the month thereafter. This can be
737  * a negative number in which case the cutoff date is relative
738  * to the end of the month and counting backwards.
739  * Eg: cutoff = -3 would mean 25 in February or 28 in June
740  *
741  * How does it work:
742  * Assume cutoff = 19 and due day = 20
743  *
744  * * Example 1 post date = 14-06-2010 (European date format)
745  * 14 is less than the cutoff of 19, so the due date will be in the next
746  * month. Since the due day is set to 20, the due date will be
747  * 20-07-2010
748  *
749  * * Example 2 post date = 22-06-2010 (European date format)
750  * 22 is more than the cutoff of 19, so the due date will be in the month
751  * after next month. Since the due day is set to 20, the due date will be
752  * 20-02-2010
753  *
754  */
755 static void
756 compute_monthyear (const GncBillTerm *term, Timespec post_date,
757  int *month, int *year)
758 {
759  int iday, imonth, iyear;
760  int cutoff = term->cutoff;
761 
762  g_return_if_fail (term->type == GNC_TERM_TYPE_PROXIMO);
763 
764  gnc_timespec2dmy (post_date, &iday, &imonth, &iyear);
765 
766  if (cutoff <= 0)
767  cutoff += gnc_date_get_last_mday (imonth, iyear);
768 
769  if (iday <= cutoff)
770  {
771  /* We apply this to next month */
772  imonth++;
773  }
774  else
775  {
776  /* We apply to the following month */
777  imonth += 2;
778  }
779 
780  if (imonth > 12)
781  {
782  iyear++;
783  imonth -= 12;
784  }
785 
786  if (month) *month = imonth;
787  if (year) *year = iyear;
788 }
789 
790 /* There are two types of billing terms:
791  *
792  * Type DAYS defines a due date to be a fixed number of days passed the post
793  * date. This is a straightforward calculation.
794  *
795  * The other type PROXIMO defines the due date as a fixed day of the month
796  * (like always the 15th of the month). The proximo algorithm determines which
797  * month based on the cutoff day and the post date. See above for a more
798  * detailed explanation of proximo.
799  */
800 
801 static Timespec
802 compute_time (const GncBillTerm *term, Timespec post_date, int days)
803 {
804  Timespec res = post_date;
805  int day, month, year;
806 
807  switch (term->type)
808  {
809  case GNC_TERM_TYPE_DAYS:
810  res.tv_sec += (SECS_PER_DAY * days);
811  break;
812  case GNC_TERM_TYPE_PROXIMO:
813  compute_monthyear (term, post_date, &month, &year);
814  day = gnc_date_get_last_mday (month, year);
815  if (days < day)
816  day = days;
817  res = gnc_dmy2timespec (day, month, year);
818  break;
819  }
820  return res;
821 }
822 
823 Timespec
824 gncBillTermComputeDueDate (const GncBillTerm *term, Timespec post_date)
825 {
826  Timespec res = post_date;
827  if (!term) return res;
828 
829  return compute_time (term, post_date, term->due_days);
830 }
831 /* Package-Private functions */
832 
833 static void _gncBillTermCreate (QofBook *book)
834 {
835  struct _book_info *bi;
836 
837  if (!book) return;
838 
839  bi = g_new0 (struct _book_info, 1);
840  qof_book_set_data (book, _GNC_MOD_NAME, bi);
841 }
842 
843 static void _gncBillTermDestroy (QofBook *book)
844 {
845  struct _book_info *bi;
846 
847  if (!book) return;
848 
849  bi = qof_book_get_data (book, _GNC_MOD_NAME);
850 
851  g_list_free (bi->terms);
852  g_free (bi);
853 }
854 
855 static QofObject gncBillTermDesc =
856 {
857  DI(.interface_version = ) QOF_OBJECT_VERSION,
858  DI(.e_type = ) _GNC_MOD_NAME,
859  DI(.type_label = ) "Billing Term",
860  DI(.create = ) (gpointer)gncBillTermCreate,
861  DI(.book_begin = ) _gncBillTermCreate,
862  DI(.book_end = ) _gncBillTermDestroy,
863  DI(.is_dirty = ) qof_collection_is_dirty,
864  DI(.mark_clean = ) qof_collection_mark_clean,
865  DI(.foreach = ) qof_collection_foreach,
866  DI(.printable = ) NULL,
867  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
868 };
869 
870 gboolean gncBillTermRegister (void)
871 {
872  static QofParam params[] =
873  {
874  { GNC_BILLTERM_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncBillTermGetName, (QofSetterFunc)gncBillTermSetName },
875  { GNC_BILLTERM_DESC, QOF_TYPE_STRING, (QofAccessFunc)gncBillTermGetDescription, (QofSetterFunc)gncBillTermSetDescription },
876  { GNC_BILLTERM_TYPE, QOF_TYPE_STRING, (QofAccessFunc)qofBillTermGetType, (QofSetterFunc)qofBillTermSetType },
877  { GNC_BILLTERM_DUEDAYS, QOF_TYPE_INT32, (QofAccessFunc)gncBillTermGetDueDays, (QofSetterFunc)gncBillTermSetDueDays },
878  { GNC_BILLTERM_DISCDAYS, QOF_TYPE_INT32, (QofAccessFunc)gncBillTermGetDiscountDays, (QofSetterFunc)gncBillTermSetDiscountDays },
879  { GNC_BILLTERM_DISCOUNT, QOF_TYPE_NUMERIC, (QofAccessFunc)gncBillTermGetDiscount, (QofSetterFunc)gncBillTermSetDiscount },
880  { GNC_BILLTERM_CUTOFF, QOF_TYPE_INT32, (QofAccessFunc)gncBillTermGetCutoff, (QofSetterFunc)gncBillTermSetCutoff },
881  { GNC_BILLTERM_REFCOUNT, QOF_TYPE_INT64, (QofAccessFunc)gncBillTermGetRefcount, NULL },
882  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
883  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
884  { NULL },
885  };
886 
887  qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncBillTermCompare, params);
888 
889  return qof_object_register (&gncBillTermDesc);
890 }
int gncBillTermCompare(const GncBillTerm *a, const GncBillTerm *b)
Definition: gncBillTerm.c:633
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
const GncGUID * qof_instance_get_guid(gconstpointer)
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
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean qof_instance_get_destroying(gconstpointer ptr)
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_fcn, const QofParam *params)
#define ENUM_TERMS_TYPE(_)
Definition: gncBillTerm.h:76
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
Definition: qofclass.h:177
#define QOF_OBJECT_VERSION
Definition: qofobject.h:64
gboolean qof_commit_edit(QofInstance *inst)
Timespec gnc_dmy2timespec(gint day, gint month, gint year)
#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)
gboolean gncBillTermEqual(const GncBillTerm *a, const GncBillTerm *b)
Definition: gncBillTerm.c:647
#define PWARN(format, args...)
Definition: qoflog.h:243
gboolean gncBillTermIsFamily(const GncBillTerm *a, const GncBillTerm *b)
Definition: gncBillTerm.c:711
void qof_instance_init_data(QofInstance *, QofIdType, QofBook *)
gboolean qof_begin_edit(QofInstance *inst)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
gboolean qof_instance_get_dirty_flag(gconstpointer ptr)
int(* QofSortFunc)(gconstpointer, gconstpointer)
Definition: qofclass.h:222
int gnc_date_get_last_mday(int month, int year)
void qof_book_set_data(QofBook *book, const gchar *key, gpointer data)
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
void qof_collection_mark_clean(QofCollection *)
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
All type declarations for the whole Gnucash engine.
void(* QofSetterFunc)(gpointer, gpointer)
Definition: qofclass.h:184
gboolean qof_object_register(const QofObject *object)
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
void gnc_timespec2dmy(Timespec ts, gint *day, gint *month, gint *year)
const gchar * QofLogModule
Definition: qofid.h:89