LCOV - code coverage report
Current view: top level - libgnucash/engine - gncBillTerm.c (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 43.6 % 383 167
Test Date: 2026-11-02 18:19:43 Functions: 46.3 % 67 31
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1