LCOV - code coverage report
Current view: top level - libgnucash/engine - gncCustomer.c (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 75.1 % 422 317
Test Date: 2026-11-02 18:19:43 Functions: 83.6 % 61 51
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************\
       2              :  * gncCustomer.c -- the Core Customer 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              :  * 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 <string.h>
      33              : #include <qofinstance-p.h>
      34              : 
      35              : #include "gnc-commodity.h"
      36              : 
      37              : #include "gncAddressP.h"
      38              : #include "gncBillTermP.h"
      39              : #include "gncInvoice.h"
      40              : #include "gncBusiness.h"
      41              : 
      42              : #include "gncCustomer.h"
      43              : #include "gncCustomerP.h"
      44              : #include "gncJobP.h"
      45              : #include "gncTaxTableP.h"
      46              : 
      47              : static gint cust_qof_event_handler_id = 0;
      48              : static void cust_handle_qof_events (QofInstance *entity, QofEventId event_type,
      49              :                                     gpointer user_data, gpointer event_data);
      50              : 
      51              : struct _gncCustomer
      52              : {
      53              :     QofInstance     inst;
      54              : 
      55              :     /* The following fields are identical to 'vendor' */
      56              :     const char *    id;
      57              :     const char *    name;
      58              :     const char *    notes;
      59              :     GncBillTerm *   terms;
      60              :     GncAddress *    addr;
      61              :     gnc_commodity * currency;
      62              :     GncTaxTable*    taxtable;
      63              :     gboolean        taxtable_override;
      64              :     GncTaxIncluded  taxincluded;
      65              :     gboolean        active;
      66              :     GList *         jobs;
      67              :     gnc_numeric *   balance; /* cached customer balance, will not be stored */
      68              : 
      69              :     /* The following fields are unique to 'customer' */
      70              :     gnc_numeric     credit;
      71              :     gnc_numeric     discount;
      72              :     GncAddress *    shipaddr;
      73              : };
      74              : 
      75              : struct _gncCustomerClass
      76              : {
      77              :     QofInstanceClass parent_class;
      78              : };
      79              : 
      80              : static QofLogModule log_module = GNC_MOD_BUSINESS;
      81              : 
      82              : #define _GNC_MOD_NAME        GNC_ID_CUSTOMER
      83              : 
      84              : /* ============================================================== */
      85              : /* misc inline funcs */
      86              : 
      87              : static inline void mark_customer (GncCustomer *customer);
      88           96 : void mark_customer (GncCustomer *customer)
      89              : {
      90           96 :     qof_instance_set_dirty(&customer->inst);
      91           96 :     qof_event_gen (&customer->inst, QOF_EVENT_MODIFY, NULL);
      92           96 : }
      93              : 
      94              : /* ============================================================== */
      95              : 
      96              : enum
      97              : {
      98              :     PROP_0,
      99              :     PROP_NAME,
     100              :     PROP_PDF_DIRNAME,
     101              :     PROP_LAST_POSTED,
     102              :     PROP_PAYMENT_LAST_ACCT,
     103              : };
     104              : 
     105              : /* GObject Initialization */
     106          141 : G_DEFINE_TYPE(GncCustomer, gnc_customer, QOF_TYPE_INSTANCE)
     107              : 
     108              : static void
     109           37 : gnc_customer_init(GncCustomer* cust)
     110              : {
     111           37 : }
     112              : 
     113              : static void
     114           22 : gnc_customer_dispose(GObject *custp)
     115              : {
     116           22 :     G_OBJECT_CLASS(gnc_customer_parent_class)->dispose(custp);
     117           22 : }
     118              : 
     119              : static void
     120           22 : gnc_customer_finalize(GObject* custp)
     121              : {
     122           22 :     G_OBJECT_CLASS(gnc_customer_parent_class)->finalize(custp);
     123           22 : }
     124              : 
     125              : static void
     126            4 : gnc_customer_get_property (GObject         *object,
     127              :                            guint            prop_id,
     128              :                            GValue          *value,
     129              :                            GParamSpec      *pspec)
     130              : {
     131              :     GncCustomer *cust;
     132            4 :     g_return_if_fail(GNC_IS_CUSTOMER(object));
     133              : 
     134            4 :     cust = GNC_CUSTOMER(object);
     135            4 :     switch (prop_id)
     136              :     {
     137            1 :     case PROP_NAME:
     138            1 :         g_value_set_string(value, cust->name);
     139            1 :         break;
     140            1 :     case PROP_PDF_DIRNAME:
     141            1 :         qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
     142            1 :         break;
     143            1 :     case PROP_LAST_POSTED:
     144            1 :         qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
     145            1 :         break;
     146            1 :     case PROP_PAYMENT_LAST_ACCT:
     147            1 :         qof_instance_get_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
     148            1 :         break;
     149            0 :     default:
     150            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     151            0 :         break;
     152              :     }
     153              : }
     154              : 
     155              : static void
     156            4 : gnc_customer_set_property (GObject         *object,
     157              :                            guint            prop_id,
     158              :                            const GValue    *value,
     159              :                            GParamSpec      *pspec)
     160              : {
     161              :     GncCustomer *cust;
     162              : 
     163            4 :     g_return_if_fail(GNC_IS_CUSTOMER(object));
     164              : 
     165            4 :     cust = GNC_CUSTOMER(object);
     166            4 :     g_assert (qof_instance_get_editlevel(cust));
     167              : 
     168            4 :     switch (prop_id)
     169              :     {
     170            1 :     case PROP_NAME:
     171            1 :         gncCustomerSetName(cust, g_value_get_string(value));
     172            1 :         break;
     173            1 :     case PROP_PDF_DIRNAME:
     174            1 :         qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
     175            1 :         break;
     176            1 :     case PROP_LAST_POSTED:
     177            1 :         qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
     178            1 :         break;
     179            1 :     case PROP_PAYMENT_LAST_ACCT:
     180            1 :         qof_instance_set_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
     181            1 :         break;
     182            0 :     default:
     183            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     184            0 :         break;
     185              :     }
     186              : }
     187              : 
     188              : /** Return display name for this object */
     189              : static gchar*
     190            0 : impl_get_display_name(const QofInstance* inst)
     191              : {
     192              :     GncCustomer* cust;
     193              : 
     194            0 :     g_return_val_if_fail(inst != NULL, FALSE);
     195            0 :     g_return_val_if_fail(GNC_IS_CUSTOMER(inst), FALSE);
     196              : 
     197            0 :     cust = GNC_CUSTOMER(inst);
     198              :     /* XXX internationalization of "Customer" */
     199            0 :     return g_strdup_printf("Customer %s", cust->name);
     200              : }
     201              : 
     202              : /** Does this object refer to a specific object */
     203              : static gboolean
     204            0 : impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
     205              : {
     206              :     GncCustomer* cust;
     207              : 
     208            0 :     g_return_val_if_fail(inst != NULL, FALSE);
     209            0 :     g_return_val_if_fail(GNC_IS_CUSTOMER(inst), FALSE);
     210              : 
     211            0 :     cust = GNC_CUSTOMER(inst);
     212              : 
     213            0 :     if (GNC_IS_BILLTERM(ref))
     214              :     {
     215            0 :         return (cust->terms == GNC_BILLTERM(ref));
     216              :     }
     217            0 :     else if (GNC_IS_TAXTABLE(ref))
     218              :     {
     219            0 :         return (cust->taxtable == GNC_TAXTABLE(ref));
     220              :     }
     221              : 
     222            0 :     return FALSE;
     223              : }
     224              : 
     225              : /** Returns a list of my type of object which refers to an object.  For example, when called as
     226              :         qof_instance_get_typed_referring_object_list(taxtable, account);
     227              :     it will return the list of taxtables which refer to a specific account.  The result should be the
     228              :     same regardless of which taxtable object is used.  The list must be freed by the caller but the
     229              :     objects on the list must not.
     230              :  */
     231              : static GList*
     232            0 : impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
     233              : {
     234            0 :     if (!GNC_IS_BILLTERM(ref) && !GNC_IS_TAXTABLE(ref))
     235              :     {
     236            0 :         return NULL;
     237              :     }
     238              : 
     239            0 :     return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
     240              : }
     241              : 
     242              : static void
     243           13 : gnc_customer_class_init (GncCustomerClass *klass)
     244              : {
     245           13 :     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     246           13 :     QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
     247              : 
     248           13 :     gobject_class->dispose = gnc_customer_dispose;
     249           13 :     gobject_class->finalize = gnc_customer_finalize;
     250           13 :     gobject_class->set_property = gnc_customer_set_property;
     251           13 :     gobject_class->get_property = gnc_customer_get_property;
     252              : 
     253           13 :     qof_class->get_display_name = impl_get_display_name;
     254           13 :     qof_class->refers_to_object = impl_refers_to_object;
     255           13 :     qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
     256              : 
     257           13 :     g_object_class_install_property
     258              :     (gobject_class,
     259              :      PROP_NAME,
     260              :      g_param_spec_string ("name",
     261              :                           "Customer Name",
     262              :                           "The customer is an arbitrary string "
     263              :                           "assigned by the user which provides the "
     264              :                           "customer name.",
     265              :                           NULL,
     266              :                           G_PARAM_READWRITE));
     267              : 
     268           13 :     g_object_class_install_property
     269              :     (gobject_class,
     270              :      PROP_PDF_DIRNAME,
     271              :      g_param_spec_string ("export-pdf-dir",
     272              :                           "Export PDF Directory Name",
     273              :                           "A subdirectory for exporting PDF reports which is "
     274              :                           "appended to the target directory when writing them "
     275              :                           "out. It is retrieved from preferences and stored on "
     276              :                           "each 'Owner' object which prints items after "
     277              :                           "printing.",
     278              :                           NULL,
     279              :                           G_PARAM_READWRITE));
     280              : 
     281           13 :     g_object_class_install_property(
     282              :        gobject_class,
     283              :        PROP_LAST_POSTED,
     284              :        g_param_spec_boxed("invoice-last-posted-account",
     285              :                           "Invoice Last Posted Account",
     286              :                           "The last account to which an invoice belonging to "
     287              :                           "this owner was posted.",
     288              :                           GNC_TYPE_GUID,
     289              :                           G_PARAM_READWRITE));
     290              : 
     291           13 :     g_object_class_install_property(
     292              :        gobject_class,
     293              :        PROP_PAYMENT_LAST_ACCT,
     294              :        g_param_spec_boxed("payment-last-account",
     295              :                           "Payment Last Account",
     296              :                           "The last account to which an payment belonging to "
     297              :                           "this owner was posted.",
     298              :                           GNC_TYPE_GUID,
     299              :                           G_PARAM_READWRITE));
     300           13 : }
     301              : 
     302              : /* Create/Destroy Functions */
     303           38 : GncCustomer *gncCustomerCreate (QofBook *book)
     304              : {
     305              :     GncCustomer *cust;
     306              : 
     307           38 :     if (!book) return NULL;
     308              : 
     309           37 :     cust = g_object_new (GNC_TYPE_CUSTOMER, NULL);
     310           37 :     qof_instance_init_data (&cust->inst, _GNC_MOD_NAME, book);
     311              : 
     312           37 :     cust->id = CACHE_INSERT ("");
     313           37 :     cust->name = CACHE_INSERT ("");
     314           37 :     cust->notes = CACHE_INSERT ("");
     315           37 :     cust->addr = gncAddressCreate (book, &cust->inst);
     316           37 :     cust->taxincluded = GNC_TAXINCLUDED_USEGLOBAL;
     317           37 :     cust->active = TRUE;
     318           37 :     cust->jobs = NULL;
     319           37 :     cust->balance = NULL;
     320              : 
     321           37 :     cust->discount = gnc_numeric_zero();
     322           37 :     cust->credit = gnc_numeric_zero();
     323           37 :     cust->shipaddr = gncAddressCreate (book, &cust->inst);
     324              : 
     325           37 :     if (cust_qof_event_handler_id == 0)
     326           13 :         cust_qof_event_handler_id = qof_event_register_handler (cust_handle_qof_events, NULL);
     327              : 
     328           37 :     qof_event_gen (&cust->inst, QOF_EVENT_CREATE, NULL);
     329              : 
     330           37 :     return cust;
     331              : }
     332              : 
     333           21 : void gncCustomerDestroy (GncCustomer *cust)
     334              : {
     335           21 :     if (!cust) return;
     336           21 :     qof_instance_set_destroying(cust, TRUE);
     337           21 :     qof_instance_set_dirty (&cust->inst);
     338           21 :     gncCustomerCommitEdit (cust);
     339              : }
     340              : 
     341           21 : static void gncCustomerFree (GncCustomer *cust)
     342              : {
     343           21 :     if (!cust) return;
     344              : 
     345           21 :     qof_event_gen (&cust->inst, QOF_EVENT_DESTROY, NULL);
     346              : 
     347           21 :     CACHE_REMOVE (cust->id);
     348           21 :     CACHE_REMOVE (cust->name);
     349           21 :     CACHE_REMOVE (cust->notes);
     350           21 :     gncAddressBeginEdit (cust->addr);
     351           21 :     gncAddressDestroy (cust->addr);
     352           21 :     gncAddressBeginEdit (cust->shipaddr);
     353           21 :     gncAddressDestroy (cust->shipaddr);
     354              : 
     355           21 :     gncJobFreeList (cust->jobs);
     356           21 :     g_list_free (cust->jobs);
     357           21 :     g_free (cust->balance);
     358              : 
     359           21 :     if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(cust))))
     360              :     {
     361            9 :         if (cust->terms)
     362            0 :             gncBillTermDecRef (cust->terms);
     363            9 :         if (cust->taxtable)
     364            0 :             gncTaxTableDecRef (cust->taxtable);
     365              :     }
     366              : 
     367              :     /* qof_instance_release (&cust->inst); */
     368           21 :     g_object_unref (cust);
     369              : }
     370              : 
     371              : /* ============================================================== */
     372              : /* Set Functions */
     373              : 
     374              : #define SET_STR(obj, member, str) { \
     375              :         if (!g_strcmp0 (member, str)) return; \
     376              :         gncCustomerBeginEdit (obj); \
     377              :         CACHE_REPLACE(member, str); \
     378              :         }
     379              : 
     380           19 : void gncCustomerSetID (GncCustomer *cust, const char *id)
     381              : {
     382           19 :     if (!cust) return;
     383           19 :     if (!id) return;
     384           19 :     SET_STR(cust, cust->id, id);
     385           19 :     mark_customer (cust);
     386           19 :     gncCustomerCommitEdit (cust);
     387              : }
     388              : 
     389           13 : void gncCustomerSetName (GncCustomer *cust, const char *name)
     390              : {
     391           13 :     if (!cust) return;
     392           13 :     if (!name) return;
     393           13 :     SET_STR(cust, cust->name, name);
     394           13 :     mark_customer (cust);
     395           13 :     gncCustomerCommitEdit (cust);
     396              : }
     397              : 
     398           12 : void gncCustomerSetNotes (GncCustomer *cust, const char *notes)
     399              : {
     400           12 :     if (!cust) return;
     401           12 :     if (!notes) return;
     402           12 :     SET_STR(cust, cust->notes, notes);
     403           12 :     mark_customer (cust);
     404           12 :     gncCustomerCommitEdit (cust);
     405              : }
     406              : 
     407            0 : void gncCustomerSetTerms (GncCustomer *cust, GncBillTerm *terms)
     408              : {
     409            0 :     if (!cust) return;
     410            0 :     if (cust->terms == terms) return;
     411              : 
     412            0 :     gncCustomerBeginEdit (cust);
     413            0 :     if (cust->terms)
     414            0 :         gncBillTermDecRef (cust->terms);
     415            0 :     cust->terms = terms;
     416            0 :     if (cust->terms)
     417            0 :         gncBillTermIncRef (cust->terms);
     418            0 :     mark_customer (cust);
     419            0 :     gncCustomerCommitEdit (cust);
     420              : }
     421              : 
     422           10 : void gncCustomerSetTaxIncluded (GncCustomer *cust, GncTaxIncluded taxincl)
     423              : {
     424           10 :     if (!cust) return;
     425           10 :     if (taxincl == cust->taxincluded) return;
     426            8 :     gncCustomerBeginEdit (cust);
     427            8 :     cust->taxincluded = taxincl;
     428            8 :     mark_customer (cust);
     429            8 :     gncCustomerCommitEdit (cust);
     430              : }
     431              : 
     432           11 : void gncCustomerSetActive (GncCustomer *cust, gboolean active)
     433              : {
     434           11 :     if (!cust) return;
     435           11 :     if (active == cust->active) return;
     436            8 :     gncCustomerBeginEdit (cust);
     437            8 :     cust->active = active;
     438            8 :     mark_customer (cust);
     439            8 :     gncCustomerCommitEdit (cust);
     440              : }
     441              : 
     442            3 : void gncCustomerSetDiscount (GncCustomer *cust, gnc_numeric discount)
     443              : {
     444            3 :     if (!cust) return;
     445            3 :     if (gnc_numeric_equal (discount, cust->discount)) return;
     446            1 :     gncCustomerBeginEdit (cust);
     447            1 :     cust->discount = discount;
     448            1 :     mark_customer (cust);
     449            1 :     gncCustomerCommitEdit (cust);
     450              : }
     451              : 
     452            3 : void gncCustomerSetCredit (GncCustomer *cust, gnc_numeric credit)
     453              : {
     454            3 :     if (!cust) return;
     455            3 :     if (gnc_numeric_equal (credit, cust->credit)) return;
     456            1 :     gncCustomerBeginEdit (cust);
     457            1 :     cust->credit = credit;
     458            1 :     mark_customer (cust);
     459            1 :     gncCustomerCommitEdit (cust);
     460              : }
     461              : 
     462           18 : void gncCustomerSetCurrency (GncCustomer *cust, gnc_commodity *currency)
     463              : {
     464           18 :     if (!cust || !currency) return;
     465           18 :     if (cust->currency && gnc_commodity_equal (cust->currency, currency)) return;
     466           18 :     gncCustomerBeginEdit (cust);
     467           18 :     cust->currency = currency;
     468           18 :     mark_customer (cust);
     469           18 :     gncCustomerCommitEdit (cust);
     470              : }
     471              : 
     472            2 : void gncCustomerSetTaxTableOverride (GncCustomer *customer, gboolean override)
     473              : {
     474            2 :     if (!customer) return;
     475            2 :     if (customer->taxtable_override == override) return;
     476            0 :     gncCustomerBeginEdit (customer);
     477            0 :     customer->taxtable_override = override;
     478            0 :     mark_customer (customer);
     479            0 :     gncCustomerCommitEdit (customer);
     480              : }
     481              : 
     482            0 : void gncCustomerSetTaxTable (GncCustomer *customer, GncTaxTable *table)
     483              : {
     484            0 :     if (!customer) return;
     485            0 :     if (customer->taxtable == table) return;
     486              : 
     487            0 :     gncCustomerBeginEdit (customer);
     488            0 :     if (customer->taxtable)
     489            0 :         gncTaxTableDecRef (customer->taxtable);
     490            0 :     if (table)
     491            0 :         gncTaxTableIncRef (table);
     492            0 :     customer->taxtable = table;
     493            0 :     mark_customer (customer);
     494            0 :     gncCustomerCommitEdit (customer);
     495              : }
     496              : 
     497              : /* Note that JobList changes do not affect the "dirtiness" of the customer */
     498           15 : void gncCustomerAddJob (GncCustomer *cust, GncJob *job)
     499              : {
     500           15 :     if (!cust) return;
     501           15 :     if (!job) return;
     502              : 
     503           15 :     if (g_list_index(cust->jobs, job) == -1)
     504           15 :         cust->jobs = g_list_insert_sorted (cust->jobs, job,
     505              :                                            (GCompareFunc)gncJobCompare);
     506              : 
     507           15 :     qof_event_gen (&cust->inst, QOF_EVENT_MODIFY, NULL);
     508              : }
     509              : 
     510            2 : void gncCustomerRemoveJob (GncCustomer *cust, GncJob *job)
     511              : {
     512              :     GList *node;
     513              : 
     514            2 :     if (!cust) return;
     515            2 :     if (!job) return;
     516              : 
     517            2 :     node = g_list_find (cust->jobs, job);
     518            2 :     if (!node)
     519              :     {
     520              :         /*    PERR ("split not in account"); */
     521              :     }
     522              :     else
     523              :     {
     524            2 :         cust->jobs = g_list_remove_link (cust->jobs, node);
     525            2 :         g_list_free_1 (node);
     526              :     }
     527            2 :     qof_event_gen (&cust->inst, QOF_EVENT_MODIFY, NULL);
     528              : }
     529              : 
     530          134 : void gncCustomerBeginEdit (GncCustomer *cust)
     531              : {
     532          134 :     qof_begin_edit (&cust->inst);
     533          134 : }
     534              : 
     535            0 : static void gncCustomerOnError (QofInstance *inst, QofBackendError errcode)
     536              : {
     537            0 :     PERR("Customer QofBackend Failure: %d", errcode);
     538            0 :     gnc_engine_signal_commit_error( errcode );
     539            0 : }
     540              : 
     541           78 : static void gncCustomerOnDone (QofInstance *inst)
     542              : {
     543           78 :     GncCustomer *cust = (GncCustomer *) inst;
     544           78 :     gncAddressClearDirty (cust->addr);
     545           78 :     gncAddressClearDirty (cust->shipaddr);
     546           78 : }
     547              : 
     548           21 : static void cust_free (QofInstance *inst)
     549              : {
     550           21 :     GncCustomer *cust = (GncCustomer *) inst;
     551           21 :     gncCustomerFree (cust);
     552           21 : }
     553              : 
     554          134 : void gncCustomerCommitEdit (GncCustomer *cust)
     555              : {
     556          134 :     if (!qof_commit_edit (QOF_INSTANCE(cust))) return;
     557           99 :     qof_commit_edit_part2 (&cust->inst, gncCustomerOnError,
     558              :                            gncCustomerOnDone, cust_free);
     559              : }
     560              : 
     561              : /* ============================================================== */
     562              : /* Get Functions */
     563              : 
     564            4 : const char * gncCustomerGetID (const GncCustomer *cust)
     565              : {
     566            4 :     if (!cust) return NULL;
     567            4 :     return cust->id;
     568              : }
     569              : 
     570          122 : const char * gncCustomerGetName (const GncCustomer *cust)
     571              : {
     572          122 :     if (!cust) return NULL;
     573          122 :     return cust->name;
     574              : }
     575              : 
     576           25 : GncAddress * gncCustomerGetAddr (const GncCustomer *cust)
     577              : {
     578           25 :     if (!cust) return NULL;
     579           25 :     return cust->addr;
     580              : }
     581              : 
     582              : static void
     583            1 : qofCustomerSetAddr (GncCustomer *cust, QofInstance *addr_ent)
     584              : {
     585              :     GncAddress *addr;
     586              : 
     587            1 :     if (!cust || !addr_ent)
     588              :     {
     589            0 :         return;
     590              :     }
     591            1 :     addr = (GncAddress*)addr_ent;
     592            1 :     if (addr == cust->addr)
     593              :     {
     594            0 :         return;
     595              :     }
     596            1 :     if (cust->addr != NULL)
     597              :     {
     598            1 :         gncAddressBeginEdit(cust->addr);
     599            1 :         gncAddressDestroy(cust->addr);
     600              :     }
     601            1 :     gncCustomerBeginEdit(cust);
     602            1 :     cust->addr = addr;
     603            1 :     gncCustomerCommitEdit(cust);
     604              : }
     605              : 
     606              : static void
     607            1 : qofCustomerSetShipAddr (GncCustomer *cust, QofInstance *ship_addr_ent)
     608              : {
     609              :     GncAddress *ship_addr;
     610              : 
     611            1 :     if (!cust || !ship_addr_ent)
     612              :     {
     613            0 :         return;
     614              :     }
     615            1 :     ship_addr = (GncAddress*)ship_addr_ent;
     616            1 :     if (ship_addr == cust->shipaddr)
     617              :     {
     618            0 :         return;
     619              :     }
     620            1 :     if (cust->shipaddr != NULL)
     621              :     {
     622            1 :         gncAddressBeginEdit(cust->shipaddr);
     623            1 :         gncAddressDestroy(cust->shipaddr);
     624              :     }
     625            1 :     gncCustomerBeginEdit(cust);
     626            1 :     cust->shipaddr = ship_addr;
     627            1 :     gncCustomerCommitEdit(cust);
     628              : }
     629              : 
     630            4 : GncAddress * gncCustomerGetShipAddr (const GncCustomer *cust)
     631              : {
     632            4 :     if (!cust) return NULL;
     633            4 :     return cust->shipaddr;
     634              : }
     635              : 
     636            2 : const char * gncCustomerGetNotes (const GncCustomer *cust)
     637              : {
     638            2 :     if (!cust) return NULL;
     639            2 :     return cust->notes;
     640              : }
     641              : 
     642            2 : GncBillTerm * gncCustomerGetTerms (const GncCustomer *cust)
     643              : {
     644            2 :     if (!cust) return NULL;
     645            2 :     return cust->terms;
     646              : }
     647              : 
     648            1 : GncTaxIncluded gncCustomerGetTaxIncluded (const GncCustomer *cust)
     649              : {
     650            1 :     if (!cust) return GNC_TAXINCLUDED_USEGLOBAL;
     651            1 :     return cust->taxincluded;
     652              : }
     653              : 
     654            3 : gnc_commodity * gncCustomerGetCurrency (const GncCustomer *cust)
     655              : {
     656            3 :     if (!cust) return NULL;
     657            3 :     return cust->currency;
     658              : }
     659              : 
     660           15 : gboolean gncCustomerGetActive (const GncCustomer *cust)
     661              : {
     662           15 :     if (!cust) return FALSE;
     663           15 :     return cust->active;
     664              : }
     665              : 
     666            2 : gnc_numeric gncCustomerGetDiscount (const GncCustomer *cust)
     667              : {
     668            2 :     if (!cust) return gnc_numeric_zero();
     669            2 :     return cust->discount;
     670              : }
     671              : 
     672            2 : gnc_numeric gncCustomerGetCredit (const GncCustomer *cust)
     673              : {
     674            2 :     if (!cust) return gnc_numeric_zero();
     675            2 :     return cust->credit;
     676              : }
     677              : 
     678            1 : gboolean gncCustomerGetTaxTableOverride (const GncCustomer *customer)
     679              : {
     680            1 :     if (!customer) return FALSE;
     681            1 :     return customer->taxtable_override;
     682              : }
     683              : 
     684            2 : GncTaxTable* gncCustomerGetTaxTable (const GncCustomer *customer)
     685              : {
     686            2 :     if (!customer) return NULL;
     687            2 :     return customer->taxtable;
     688              : }
     689              : 
     690            6 : GList * gncCustomerGetJoblist (const GncCustomer *cust, gboolean show_all)
     691              : {
     692            6 :     if (!cust) return NULL;
     693              : 
     694            6 :     if (show_all)
     695              :     {
     696            4 :         return (g_list_copy (cust->jobs));
     697              :     }
     698              :     else
     699              :     {
     700            2 :         GList *list = NULL, *iterator;
     701            4 :         for (iterator = cust->jobs; iterator; iterator = iterator->next)
     702              :         {
     703            2 :             GncJob *j = iterator->data;
     704            2 :             if (gncJobGetActive (j))
     705            1 :                 list = g_list_prepend (list, j);
     706              :         }
     707            2 :         return g_list_reverse (list);
     708              :     }
     709              : }
     710              : 
     711           12 : gboolean gncCustomerIsDirty (GncCustomer *cust)
     712              : {
     713           12 :     if (!cust) return FALSE;
     714           18 :     return (qof_instance_is_dirty(&cust->inst) ||
     715           18 :             gncAddressIsDirty (cust->addr) ||
     716            6 :             gncAddressIsDirty (cust->shipaddr));
     717              : }
     718              : 
     719              : /* Other functions */
     720              : 
     721            0 : int gncCustomerCompare (const GncCustomer *a, const GncCustomer *b)
     722              : {
     723            0 :     if (!a && !b) return 0;
     724            0 :     if (!a && b) return 1;
     725            0 :     if (a && !b) return -1;
     726              : 
     727            0 :     return(strcmp(a->name, b->name));
     728              : }
     729              : 
     730              : gboolean
     731            4 : gncCustomerEqual(const GncCustomer *a, const GncCustomer *b)
     732              : {
     733            4 :     if (a == NULL && b == NULL) return TRUE;
     734            4 :     if (a == NULL || b == NULL) return FALSE;
     735              : 
     736            4 :     g_return_val_if_fail(GNC_IS_CUSTOMER(a), FALSE);
     737            4 :     g_return_val_if_fail(GNC_IS_CUSTOMER(b), FALSE);
     738              : 
     739            4 :     if (g_strcmp0(a->id, b->id) != 0)
     740              :     {
     741            0 :         PWARN("IDs differ: %s vs %s", a->id, b->id);
     742            0 :         return FALSE;
     743              :     }
     744              : 
     745            4 :     if (g_strcmp0(a->name, b->name) != 0)
     746              :     {
     747            0 :         PWARN("Names differ: %s vs %s", a->name, b->name);
     748            0 :         return FALSE;
     749              :     }
     750              : 
     751            4 :     if (g_strcmp0(a->notes, b->notes) != 0)
     752              :     {
     753            0 :         PWARN("Notes differ: %s vs %s", a->notes, b->notes);
     754            0 :         return FALSE;
     755              :     }
     756              : 
     757            4 :     if (!gncBillTermEqual(a->terms, b->terms))
     758              :     {
     759            0 :         PWARN("Bill terms differ");
     760            0 :         return FALSE;
     761              :     }
     762              : 
     763            4 :     if (!gnc_commodity_equal(a->currency, b->currency))
     764              :     {
     765            0 :         PWARN("currencies differ");
     766            0 :         return FALSE;
     767              :     }
     768              : 
     769            4 :     if (!gncTaxTableEqual(a->taxtable, b->taxtable))
     770              :     {
     771            0 :         PWARN("tax tables differ");
     772            0 :         return FALSE;
     773              :     }
     774              : 
     775            4 :     if (a->taxtable_override != b->taxtable_override)
     776              :     {
     777            0 :         PWARN("Tax table override flags differ");
     778            0 :         return FALSE;
     779              :     }
     780              : 
     781            4 :     if (a->taxincluded != b->taxincluded)
     782              :     {
     783            0 :         PWARN("Tax included flags differ");
     784            0 :         return FALSE;
     785              :     }
     786              : 
     787            4 :     if (a->active != b->active)
     788              :     {
     789            0 :         PWARN("Active flags differ");
     790            0 :         return FALSE;
     791              :     }
     792              : 
     793            4 :     if (!gncAddressEqual(a->addr, b->addr))
     794              :     {
     795            0 :         PWARN("addresses differ");
     796            0 :         return FALSE;
     797              :     }
     798            4 :     if (!gncAddressEqual(a->shipaddr, b->shipaddr))
     799              :     {
     800            0 :         PWARN("addresses differ");
     801            0 :         return FALSE;
     802              :     }
     803              : 
     804            4 :     if (!gnc_numeric_equal(a->credit, b->credit))
     805              :     {
     806            0 :         PWARN("Credit amounts differ");
     807            0 :         return FALSE;
     808              :     }
     809              : 
     810            4 :     if (!gnc_numeric_equal(a->discount, b->discount))
     811              :     {
     812            0 :         PWARN("Discount amounts differ");
     813            0 :         return FALSE;
     814              :     }
     815              : 
     816              :     /* FIXME: Need to check jobs list
     817              :     GList *         jobs;
     818              :     */
     819              : 
     820            4 :     return TRUE;
     821              : }
     822              : 
     823              : /**
     824              :  * Listen for qof events.
     825              :  *
     826              :  * - If the address of a customer has changed, mark the customer as dirty.
     827              :  * - If a lot related to a customer has changed, clear the customer's
     828              :  *   cached balance as it likely has become invalid.
     829              :  *
     830              :  * @param entity Entity for the event
     831              :  * @param event_type Event type
     832              :  * @param user_data User data registered with the handler
     833              :  * @param event_data Event data passed with the event.
     834              :  */
     835              : static void
     836       147674 : cust_handle_qof_events (QofInstance *entity, QofEventId event_type,
     837              :                         gpointer user_data, gpointer event_data)
     838              : {
     839              :     /* Handle address change events */
     840       147674 :     if ((GNC_IS_ADDRESS (entity) &&
     841           68 :         (event_type & QOF_EVENT_MODIFY) != 0))
     842              :     {
     843           21 :         if (GNC_IS_CUSTOMER (event_data))
     844              :         {
     845           16 :             GncCustomer* cust = GNC_CUSTOMER (event_data);
     846           16 :             gncCustomerBeginEdit (cust);
     847           16 :             mark_customer (cust);
     848           16 :             gncCustomerCommitEdit (cust);
     849              :         }
     850           21 :         return;
     851              :     }
     852              : 
     853              :     /* Handle lot change events */
     854       147653 :     if (GNC_IS_LOT (entity))
     855              :     {
     856          769 :         GNCLot *lot = GNC_LOT (entity);
     857              :         GncOwner lot_owner;
     858          769 :         const GncOwner *end_owner = NULL;
     859          769 :         GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
     860              : 
     861              :         /* Determine the owner associated with the lot */
     862          769 :         if (invoice)
     863              :             /* Invoice lots */
     864          408 :             end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
     865          361 :         else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
     866              :             /* Pre-payment lots */
     867          109 :             end_owner = gncOwnerGetEndOwner (&lot_owner);
     868              : 
     869          769 :         if (gncOwnerGetType (end_owner) == GNC_OWNER_CUSTOMER)
     870              :         {
     871              :             /* Clear the cached balance */
     872          437 :             GncCustomer* cust = gncOwnerGetCustomer (end_owner);
     873          437 :             g_free (cust->balance);
     874          437 :             cust->balance = NULL;
     875              :         }
     876          769 :         return;
     877              :     }
     878              : }
     879              : 
     880              : /* ============================================================== */
     881              : /* Package-Private functions */
     882           86 : static const char * _gncCustomerPrintable (gpointer item)
     883              : {
     884              : //  GncCustomer *c = item;
     885           86 :     if (!item) return "failed";
     886            0 :     return gncCustomerGetName((GncCustomer*)item);
     887              : }
     888              : 
     889              : static void
     890           12 : destroy_customer_on_book_close(QofInstance *ent, gpointer data)
     891              : {
     892           12 :     GncCustomer* c = GNC_CUSTOMER(ent);
     893              : 
     894           12 :     gncCustomerBeginEdit(c);
     895           12 :     gncCustomerDestroy(c);
     896           12 : }
     897              : 
     898              : /** Handles book end - frees all customers from the book
     899              :  *
     900              :  * @param book Book being closed
     901              :  */
     902              : static void
     903          182 : gnc_customer_book_end(QofBook* book)
     904              : {
     905              :     QofCollection *col;
     906              : 
     907          182 :     col = qof_book_get_collection(book, GNC_ID_CUSTOMER);
     908          182 :     qof_collection_foreach(col, destroy_customer_on_book_close, NULL);
     909          182 : }
     910              : 
     911              : static QofObject gncCustomerDesc =
     912              : {
     913              :     DI(.interface_version = ) QOF_OBJECT_VERSION,
     914              :     DI(.e_type            = ) _GNC_MOD_NAME,
     915              :     DI(.type_label        = ) "Customer",
     916              :     DI(.create            = ) (gpointer)gncCustomerCreate,
     917              :     DI(.book_begin        = ) NULL,
     918              :     DI(.book_end          = ) gnc_customer_book_end,
     919              :     DI(.is_dirty          = ) qof_collection_is_dirty,
     920              :     DI(.mark_clean        = ) qof_collection_mark_clean,
     921              :     DI(.foreach           = ) qof_collection_foreach,
     922              :     DI(.printable         = ) (const char * (*)(gpointer))gncCustomerGetName,
     923              :     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
     924              : };
     925              : 
     926           86 : gboolean gncCustomerRegister (void)
     927              : {
     928              :     static QofParam params[] =
     929              :     {
     930              :         { CUSTOMER_ID, QOF_TYPE_NATURAL, (QofAccessFunc)gncCustomerGetID, (QofSetterFunc)gncCustomerSetID },
     931              :         { CUSTOMER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetName, (QofSetterFunc)gncCustomerSetName },
     932              :         { CUSTOMER_NOTES, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetNotes, (QofSetterFunc)gncCustomerSetNotes },
     933              :         {
     934              :             CUSTOMER_DISCOUNT, QOF_TYPE_NUMERIC, (QofAccessFunc)gncCustomerGetDiscount,
     935              :             (QofSetterFunc)gncCustomerSetDiscount
     936              :         },
     937              :         {
     938              :             CUSTOMER_CREDIT, QOF_TYPE_NUMERIC, (QofAccessFunc)gncCustomerGetCredit,
     939              :             (QofSetterFunc)gncCustomerSetCredit
     940              :         },
     941              :         { CUSTOMER_ADDR, GNC_ID_ADDRESS, (QofAccessFunc)gncCustomerGetAddr, (QofSetterFunc)qofCustomerSetAddr },
     942              :         { CUSTOMER_SHIPADDR, GNC_ID_ADDRESS, (QofAccessFunc)gncCustomerGetShipAddr, (QofSetterFunc)qofCustomerSetShipAddr },
     943              :         {
     944              :             CUSTOMER_TT_OVER, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetTaxTableOverride,
     945              :             (QofSetterFunc)gncCustomerSetTaxTableOverride
     946              :         },
     947              :         { CUSTOMER_TERMS, GNC_ID_BILLTERM, (QofAccessFunc)gncCustomerGetTerms, (QofSetterFunc)gncCustomerSetTerms },
     948              :         { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetActive, (QofSetterFunc)gncCustomerSetActive },
     949              :         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
     950              :         { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
     951              :         { NULL },
     952              :     };
     953              : 
     954           86 :     qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncCustomerCompare, params);
     955              :     /* temp */
     956           86 :     _gncCustomerPrintable(NULL);
     957           86 :     return qof_object_register (&gncCustomerDesc);
     958              : }
     959              : 
     960            0 : gchar *gncCustomerNextID (QofBook *book)
     961              : {
     962            0 :     return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
     963              : }
     964              : 
     965              : const gnc_numeric*
     966            0 : gncCustomerGetCachedBalance (GncCustomer *cust)
     967              : {
     968            0 :     return cust->balance;
     969              : }
     970              : 
     971            0 : void gncCustomerSetCachedBalance (GncCustomer *cust, const gnc_numeric *new_bal)
     972              : {
     973            0 :     if (!new_bal)
     974              :     {
     975            0 :         if (cust->balance)
     976              :         {
     977            0 :             g_free (cust->balance);
     978            0 :             cust->balance = NULL;
     979              :         }
     980            0 :         return;
     981              :     }
     982              : 
     983            0 :     if (!cust->balance)
     984            0 :         cust->balance = g_new0 (gnc_numeric, 1);
     985              : 
     986            0 :     *cust->balance = *new_bal;
     987              : }
        

Generated by: LCOV version 2.0-1