mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 02:40:43 -06:00
1002 lines
27 KiB
C
1002 lines
27 KiB
C
/********************************************************************\
|
|
* gncCustomer.c -- the Core Customer Interface *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, contact: *
|
|
* *
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
* *
|
|
\********************************************************************/
|
|
|
|
/*
|
|
* Copyright (C) 2001,2002 Derek Atkins
|
|
* Copyright (C) 2003 Linas Vepstas <linas@linas.org>
|
|
* Author: Derek Atkins <warlord@MIT.EDU>
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <glib.h>
|
|
#include <string.h>
|
|
#include <qofinstance-p.h>
|
|
|
|
#include "gnc-commodity.h"
|
|
|
|
#include "gncAddressP.h"
|
|
#include "gncBillTermP.h"
|
|
#include "gncInvoice.h"
|
|
#include "gncBusiness.h"
|
|
|
|
#include "gncCustomer.h"
|
|
#include "gncCustomerP.h"
|
|
#include "gncJobP.h"
|
|
#include "gncTaxTableP.h"
|
|
|
|
static gint cust_qof_event_handler_id = 0;
|
|
static void cust_handle_qof_events (QofInstance *entity, QofEventId event_type,
|
|
gpointer user_data, gpointer event_data);
|
|
|
|
struct _gncCustomer
|
|
{
|
|
QofInstance inst;
|
|
|
|
/* The following fields are identical to 'vendor' */
|
|
const char * id;
|
|
const char * name;
|
|
const char * notes;
|
|
GncBillTerm * terms;
|
|
GncAddress * addr;
|
|
gnc_commodity * currency;
|
|
GncTaxTable* taxtable;
|
|
gboolean taxtable_override;
|
|
GncTaxIncluded taxincluded;
|
|
gboolean active;
|
|
GList * jobs;
|
|
gnc_numeric * balance; /* cached customer balance, will not be stored */
|
|
|
|
/* The following fields are unique to 'customer' */
|
|
gnc_numeric credit;
|
|
gnc_numeric discount;
|
|
GncAddress * shipaddr;
|
|
};
|
|
|
|
struct _gncCustomerClass
|
|
{
|
|
QofInstanceClass parent_class;
|
|
};
|
|
|
|
static QofLogModule log_module = GNC_MOD_BUSINESS;
|
|
|
|
#define _GNC_MOD_NAME GNC_ID_CUSTOMER
|
|
|
|
/* ============================================================== */
|
|
/* misc inline funcs */
|
|
|
|
static inline void mark_customer (GncCustomer *customer);
|
|
void mark_customer (GncCustomer *customer)
|
|
{
|
|
qof_instance_set_dirty(&customer->inst);
|
|
qof_event_gen (&customer->inst, QOF_EVENT_MODIFY, NULL);
|
|
}
|
|
|
|
/* ============================================================== */
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_NAME,
|
|
PROP_PDF_DIRNAME,
|
|
PROP_LAST_POSTED,
|
|
PROP_PAYMENT_LAST_ACCT,
|
|
};
|
|
|
|
/* GObject Initialization */
|
|
G_DEFINE_TYPE(GncCustomer, gnc_customer, QOF_TYPE_INSTANCE)
|
|
|
|
static void
|
|
gnc_customer_init(GncCustomer* cust)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gnc_customer_dispose(GObject *custp)
|
|
{
|
|
G_OBJECT_CLASS(gnc_customer_parent_class)->dispose(custp);
|
|
}
|
|
|
|
static void
|
|
gnc_customer_finalize(GObject* custp)
|
|
{
|
|
G_OBJECT_CLASS(gnc_customer_parent_class)->finalize(custp);
|
|
}
|
|
|
|
static void
|
|
gnc_customer_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GncCustomer *cust;
|
|
gchar *key;
|
|
g_return_if_fail(GNC_IS_CUSTOMER(object));
|
|
|
|
cust = GNC_CUSTOMER(object);
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
g_value_set_string(value, cust->name);
|
|
break;
|
|
case PROP_PDF_DIRNAME:
|
|
qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
|
|
break;
|
|
case PROP_LAST_POSTED:
|
|
qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
|
|
break;
|
|
case PROP_PAYMENT_LAST_ACCT:
|
|
qof_instance_get_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gnc_customer_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GncCustomer *cust;
|
|
gchar *key;
|
|
|
|
g_return_if_fail(GNC_IS_CUSTOMER(object));
|
|
|
|
cust = GNC_CUSTOMER(object);
|
|
g_assert (qof_instance_get_editlevel(cust));
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
gncCustomerSetName(cust, g_value_get_string(value));
|
|
break;
|
|
case PROP_PDF_DIRNAME:
|
|
qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
|
|
break;
|
|
case PROP_LAST_POSTED:
|
|
qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
|
|
break;
|
|
case PROP_PAYMENT_LAST_ACCT:
|
|
qof_instance_set_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/** Return display name for this object */
|
|
static gchar*
|
|
impl_get_display_name(const QofInstance* inst)
|
|
{
|
|
GncCustomer* cust;
|
|
|
|
g_return_val_if_fail(inst != NULL, FALSE);
|
|
g_return_val_if_fail(GNC_IS_CUSTOMER(inst), FALSE);
|
|
|
|
cust = GNC_CUSTOMER(inst);
|
|
/* XXX internationalization of "Customer" */
|
|
return g_strdup_printf("Customer %s", cust->name);
|
|
}
|
|
|
|
/** Does this object refer to a specific object */
|
|
static gboolean
|
|
impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
|
|
{
|
|
GncCustomer* cust;
|
|
|
|
g_return_val_if_fail(inst != NULL, FALSE);
|
|
g_return_val_if_fail(GNC_IS_CUSTOMER(inst), FALSE);
|
|
|
|
cust = GNC_CUSTOMER(inst);
|
|
|
|
if (GNC_IS_BILLTERM(ref))
|
|
{
|
|
return (cust->terms == GNC_BILLTERM(ref));
|
|
}
|
|
else if (GNC_IS_TAXTABLE(ref))
|
|
{
|
|
return (cust->taxtable == GNC_TAXTABLE(ref));
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/** Returns a list of my type of object which refers to an object. For example, when called as
|
|
qof_instance_get_typed_referring_object_list(taxtable, account);
|
|
it will return the list of taxtables which refer to a specific account. The result should be the
|
|
same regardless of which taxtable object is used. The list must be freed by the caller but the
|
|
objects on the list must not.
|
|
*/
|
|
static GList*
|
|
impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
|
|
{
|
|
if (!GNC_IS_BILLTERM(ref) && !GNC_IS_TAXTABLE(ref))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
|
|
}
|
|
|
|
static void
|
|
gnc_customer_class_init (GncCustomerClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
|
|
|
|
gobject_class->dispose = gnc_customer_dispose;
|
|
gobject_class->finalize = gnc_customer_finalize;
|
|
gobject_class->set_property = gnc_customer_set_property;
|
|
gobject_class->get_property = gnc_customer_get_property;
|
|
|
|
qof_class->get_display_name = impl_get_display_name;
|
|
qof_class->refers_to_object = impl_refers_to_object;
|
|
qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
|
|
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_NAME,
|
|
g_param_spec_string ("name",
|
|
"Customer Name",
|
|
"The customer is an arbitrary string "
|
|
"assigned by the user which provides the "
|
|
"customer name.",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_PDF_DIRNAME,
|
|
g_param_spec_string ("export-pdf-dir",
|
|
"Export PDF Directory Name",
|
|
"A subdirectory for exporting PDF reports which is "
|
|
"appended to the target directory when writing them "
|
|
"out. It is retrieved from preferences and stored on "
|
|
"each 'Owner' object which prints items after "
|
|
"printing.",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property(
|
|
gobject_class,
|
|
PROP_LAST_POSTED,
|
|
g_param_spec_boxed("invoice-last-posted-account",
|
|
"Invoice Last Posted Account",
|
|
"The last account to which an invoice belonging to "
|
|
"this owner was posted.",
|
|
GNC_TYPE_GUID,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property(
|
|
gobject_class,
|
|
PROP_PAYMENT_LAST_ACCT,
|
|
g_param_spec_boxed("payment-last-account",
|
|
"Payment Last Account",
|
|
"The last account to which an payment belonging to "
|
|
"this owner was posted.",
|
|
GNC_TYPE_GUID,
|
|
G_PARAM_READWRITE));
|
|
}
|
|
|
|
/* Create/Destroy Functions */
|
|
GncCustomer *gncCustomerCreate (QofBook *book)
|
|
{
|
|
GncCustomer *cust;
|
|
|
|
if (!book) return NULL;
|
|
|
|
cust = g_object_new (GNC_TYPE_CUSTOMER, NULL);
|
|
qof_instance_init_data (&cust->inst, _GNC_MOD_NAME, book);
|
|
|
|
cust->id = CACHE_INSERT ("");
|
|
cust->name = CACHE_INSERT ("");
|
|
cust->notes = CACHE_INSERT ("");
|
|
cust->addr = gncAddressCreate (book, &cust->inst);
|
|
cust->taxincluded = GNC_TAXINCLUDED_USEGLOBAL;
|
|
cust->active = TRUE;
|
|
cust->jobs = NULL;
|
|
cust->balance = NULL;
|
|
|
|
cust->discount = gnc_numeric_zero();
|
|
cust->credit = gnc_numeric_zero();
|
|
cust->shipaddr = gncAddressCreate (book, &cust->inst);
|
|
|
|
if (cust_qof_event_handler_id == 0)
|
|
cust_qof_event_handler_id = qof_event_register_handler (cust_handle_qof_events, NULL);
|
|
|
|
qof_event_gen (&cust->inst, QOF_EVENT_CREATE, NULL);
|
|
|
|
return cust;
|
|
}
|
|
|
|
void gncCustomerDestroy (GncCustomer *cust)
|
|
{
|
|
if (!cust) return;
|
|
qof_instance_set_destroying(cust, TRUE);
|
|
qof_instance_set_dirty (&cust->inst);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
static void gncCustomerFree (GncCustomer *cust)
|
|
{
|
|
if (!cust) return;
|
|
|
|
qof_event_gen (&cust->inst, QOF_EVENT_DESTROY, NULL);
|
|
|
|
CACHE_REMOVE (cust->id);
|
|
CACHE_REMOVE (cust->name);
|
|
CACHE_REMOVE (cust->notes);
|
|
gncAddressBeginEdit (cust->addr);
|
|
gncAddressDestroy (cust->addr);
|
|
gncAddressBeginEdit (cust->shipaddr);
|
|
gncAddressDestroy (cust->shipaddr);
|
|
|
|
gncJobFreeList (cust->jobs);
|
|
g_list_free (cust->jobs);
|
|
g_free (cust->balance);
|
|
|
|
if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(cust))))
|
|
{
|
|
if (cust->terms)
|
|
gncBillTermDecRef (cust->terms);
|
|
if (cust->taxtable)
|
|
gncTaxTableDecRef (cust->taxtable);
|
|
}
|
|
|
|
/* qof_instance_release (&cust->inst); */
|
|
g_object_unref (cust);
|
|
}
|
|
|
|
/* ============================================================== */
|
|
/* Set Functions */
|
|
|
|
#define SET_STR(obj, member, str) { \
|
|
if (!g_strcmp0 (member, str)) return; \
|
|
gncCustomerBeginEdit (obj); \
|
|
CACHE_REPLACE(member, str); \
|
|
}
|
|
|
|
void gncCustomerSetID (GncCustomer *cust, const char *id)
|
|
{
|
|
if (!cust) return;
|
|
if (!id) return;
|
|
SET_STR(cust, cust->id, id);
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetName (GncCustomer *cust, const char *name)
|
|
{
|
|
if (!cust) return;
|
|
if (!name) return;
|
|
SET_STR(cust, cust->name, name);
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetNotes (GncCustomer *cust, const char *notes)
|
|
{
|
|
if (!cust) return;
|
|
if (!notes) return;
|
|
SET_STR(cust, cust->notes, notes);
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetTerms (GncCustomer *cust, GncBillTerm *terms)
|
|
{
|
|
if (!cust) return;
|
|
if (cust->terms == terms) return;
|
|
|
|
gncCustomerBeginEdit (cust);
|
|
if (cust->terms)
|
|
gncBillTermDecRef (cust->terms);
|
|
cust->terms = terms;
|
|
if (cust->terms)
|
|
gncBillTermIncRef (cust->terms);
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetTaxIncluded (GncCustomer *cust, GncTaxIncluded taxincl)
|
|
{
|
|
if (!cust) return;
|
|
if (taxincl == cust->taxincluded) return;
|
|
gncCustomerBeginEdit (cust);
|
|
cust->taxincluded = taxincl;
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetActive (GncCustomer *cust, gboolean active)
|
|
{
|
|
if (!cust) return;
|
|
if (active == cust->active) return;
|
|
gncCustomerBeginEdit (cust);
|
|
cust->active = active;
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetDiscount (GncCustomer *cust, gnc_numeric discount)
|
|
{
|
|
if (!cust) return;
|
|
if (gnc_numeric_equal (discount, cust->discount)) return;
|
|
gncCustomerBeginEdit (cust);
|
|
cust->discount = discount;
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetCredit (GncCustomer *cust, gnc_numeric credit)
|
|
{
|
|
if (!cust) return;
|
|
if (gnc_numeric_equal (credit, cust->credit)) return;
|
|
gncCustomerBeginEdit (cust);
|
|
cust->credit = credit;
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetCurrency (GncCustomer *cust, gnc_commodity *currency)
|
|
{
|
|
if (!cust || !currency) return;
|
|
if (cust->currency && gnc_commodity_equal (cust->currency, currency)) return;
|
|
gncCustomerBeginEdit (cust);
|
|
cust->currency = currency;
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
|
|
void gncCustomerSetTaxTableOverride (GncCustomer *customer, gboolean override)
|
|
{
|
|
if (!customer) return;
|
|
if (customer->taxtable_override == override) return;
|
|
gncCustomerBeginEdit (customer);
|
|
customer->taxtable_override = override;
|
|
mark_customer (customer);
|
|
gncCustomerCommitEdit (customer);
|
|
}
|
|
|
|
void gncCustomerSetTaxTable (GncCustomer *customer, GncTaxTable *table)
|
|
{
|
|
if (!customer) return;
|
|
if (customer->taxtable == table) return;
|
|
|
|
gncCustomerBeginEdit (customer);
|
|
if (customer->taxtable)
|
|
gncTaxTableDecRef (customer->taxtable);
|
|
if (table)
|
|
gncTaxTableIncRef (table);
|
|
customer->taxtable = table;
|
|
mark_customer (customer);
|
|
gncCustomerCommitEdit (customer);
|
|
}
|
|
|
|
/* Note that JobList changes do not affect the "dirtiness" of the customer */
|
|
void gncCustomerAddJob (GncCustomer *cust, GncJob *job)
|
|
{
|
|
if (!cust) return;
|
|
if (!job) return;
|
|
|
|
if (g_list_index(cust->jobs, job) == -1)
|
|
cust->jobs = g_list_insert_sorted (cust->jobs, job,
|
|
(GCompareFunc)gncJobCompare);
|
|
|
|
qof_event_gen (&cust->inst, QOF_EVENT_MODIFY, NULL);
|
|
}
|
|
|
|
void gncCustomerRemoveJob (GncCustomer *cust, GncJob *job)
|
|
{
|
|
GList *node;
|
|
|
|
if (!cust) return;
|
|
if (!job) return;
|
|
|
|
node = g_list_find (cust->jobs, job);
|
|
if (!node)
|
|
{
|
|
/* PERR ("split not in account"); */
|
|
}
|
|
else
|
|
{
|
|
cust->jobs = g_list_remove_link (cust->jobs, node);
|
|
g_list_free_1 (node);
|
|
}
|
|
qof_event_gen (&cust->inst, QOF_EVENT_MODIFY, NULL);
|
|
}
|
|
|
|
void gncCustomerBeginEdit (GncCustomer *cust)
|
|
{
|
|
qof_begin_edit (&cust->inst);
|
|
}
|
|
|
|
static void gncCustomerOnError (QofInstance *inst, QofBackendError errcode)
|
|
{
|
|
PERR("Customer QofBackend Failure: %d", errcode);
|
|
gnc_engine_signal_commit_error( errcode );
|
|
}
|
|
|
|
static void gncCustomerOnDone (QofInstance *inst)
|
|
{
|
|
GncCustomer *cust = (GncCustomer *) inst;
|
|
gncAddressClearDirty (cust->addr);
|
|
gncAddressClearDirty (cust->shipaddr);
|
|
}
|
|
|
|
static void cust_free (QofInstance *inst)
|
|
{
|
|
GncCustomer *cust = (GncCustomer *) inst;
|
|
gncCustomerFree (cust);
|
|
}
|
|
|
|
void gncCustomerCommitEdit (GncCustomer *cust)
|
|
{
|
|
if (!qof_commit_edit (QOF_INSTANCE(cust))) return;
|
|
qof_commit_edit_part2 (&cust->inst, gncCustomerOnError,
|
|
gncCustomerOnDone, cust_free);
|
|
}
|
|
|
|
/* ============================================================== */
|
|
/* Get Functions */
|
|
|
|
const char * gncCustomerGetID (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->id;
|
|
}
|
|
|
|
const char * gncCustomerGetName (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->name;
|
|
}
|
|
|
|
GncAddress * gncCustomerGetAddr (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->addr;
|
|
}
|
|
|
|
static void
|
|
qofCustomerSetAddr (GncCustomer *cust, QofInstance *addr_ent)
|
|
{
|
|
GncAddress *addr;
|
|
|
|
if (!cust || !addr_ent)
|
|
{
|
|
return;
|
|
}
|
|
addr = (GncAddress*)addr_ent;
|
|
if (addr == cust->addr)
|
|
{
|
|
return;
|
|
}
|
|
if (cust->addr != NULL)
|
|
{
|
|
gncAddressBeginEdit(cust->addr);
|
|
gncAddressDestroy(cust->addr);
|
|
}
|
|
gncCustomerBeginEdit(cust);
|
|
cust->addr = addr;
|
|
gncCustomerCommitEdit(cust);
|
|
}
|
|
|
|
static void
|
|
qofCustomerSetShipAddr (GncCustomer *cust, QofInstance *ship_addr_ent)
|
|
{
|
|
GncAddress *ship_addr;
|
|
|
|
if (!cust || !ship_addr_ent)
|
|
{
|
|
return;
|
|
}
|
|
ship_addr = (GncAddress*)ship_addr_ent;
|
|
if (ship_addr == cust->shipaddr)
|
|
{
|
|
return;
|
|
}
|
|
if (cust->shipaddr != NULL)
|
|
{
|
|
gncAddressBeginEdit(cust->shipaddr);
|
|
gncAddressDestroy(cust->shipaddr);
|
|
}
|
|
gncCustomerBeginEdit(cust);
|
|
cust->shipaddr = ship_addr;
|
|
gncCustomerCommitEdit(cust);
|
|
}
|
|
|
|
GncAddress * gncCustomerGetShipAddr (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->shipaddr;
|
|
}
|
|
|
|
const char * gncCustomerGetNotes (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->notes;
|
|
}
|
|
|
|
GncBillTerm * gncCustomerGetTerms (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->terms;
|
|
}
|
|
|
|
GncTaxIncluded gncCustomerGetTaxIncluded (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return GNC_TAXINCLUDED_USEGLOBAL;
|
|
return cust->taxincluded;
|
|
}
|
|
|
|
gnc_commodity * gncCustomerGetCurrency (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return NULL;
|
|
return cust->currency;
|
|
}
|
|
|
|
gboolean gncCustomerGetActive (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return FALSE;
|
|
return cust->active;
|
|
}
|
|
|
|
gnc_numeric gncCustomerGetDiscount (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return gnc_numeric_zero();
|
|
return cust->discount;
|
|
}
|
|
|
|
gnc_numeric gncCustomerGetCredit (const GncCustomer *cust)
|
|
{
|
|
if (!cust) return gnc_numeric_zero();
|
|
return cust->credit;
|
|
}
|
|
|
|
gboolean gncCustomerGetTaxTableOverride (const GncCustomer *customer)
|
|
{
|
|
if (!customer) return FALSE;
|
|
return customer->taxtable_override;
|
|
}
|
|
|
|
GncTaxTable* gncCustomerGetTaxTable (const GncCustomer *customer)
|
|
{
|
|
if (!customer) return NULL;
|
|
return customer->taxtable;
|
|
}
|
|
|
|
GList * gncCustomerGetJoblist (const GncCustomer *cust, gboolean show_all)
|
|
{
|
|
if (!cust) return NULL;
|
|
|
|
if (show_all)
|
|
{
|
|
return (g_list_copy (cust->jobs));
|
|
}
|
|
else
|
|
{
|
|
GList *list = NULL, *iterator;
|
|
for (iterator = cust->jobs; iterator; iterator = iterator->next)
|
|
{
|
|
GncJob *j = iterator->data;
|
|
if (gncJobGetActive (j))
|
|
list = g_list_prepend (list, j);
|
|
}
|
|
return g_list_reverse (list);
|
|
}
|
|
}
|
|
|
|
gboolean gncCustomerIsDirty (GncCustomer *cust)
|
|
{
|
|
if (!cust) return FALSE;
|
|
return (qof_instance_is_dirty(&cust->inst) ||
|
|
gncAddressIsDirty (cust->addr) ||
|
|
gncAddressIsDirty (cust->shipaddr));
|
|
}
|
|
|
|
/* Other functions */
|
|
|
|
int gncCustomerCompare (const GncCustomer *a, const GncCustomer *b)
|
|
{
|
|
if (!a && !b) return 0;
|
|
if (!a && b) return 1;
|
|
if (a && !b) return -1;
|
|
|
|
return(strcmp(a->name, b->name));
|
|
}
|
|
|
|
gboolean
|
|
gncCustomerEqual(const GncCustomer *a, const GncCustomer *b)
|
|
{
|
|
if (a == NULL && b == NULL) return TRUE;
|
|
if (a == NULL || b == NULL) return FALSE;
|
|
|
|
g_return_val_if_fail(GNC_IS_CUSTOMER(a), FALSE);
|
|
g_return_val_if_fail(GNC_IS_CUSTOMER(b), FALSE);
|
|
|
|
if (g_strcmp0(a->id, b->id) != 0)
|
|
{
|
|
PWARN("IDs differ: %s vs %s", a->id, b->id);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_strcmp0(a->name, b->name) != 0)
|
|
{
|
|
PWARN("Names differ: %s vs %s", a->name, b->name);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_strcmp0(a->notes, b->notes) != 0)
|
|
{
|
|
PWARN("Notes differ: %s vs %s", a->notes, b->notes);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gncBillTermEqual(a->terms, b->terms))
|
|
{
|
|
PWARN("Bill terms differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gnc_commodity_equal(a->currency, b->currency))
|
|
{
|
|
PWARN("currencies differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gncTaxTableEqual(a->taxtable, b->taxtable))
|
|
{
|
|
PWARN("tax tables differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (a->taxtable_override != b->taxtable_override)
|
|
{
|
|
PWARN("Tax table override flags differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (a->taxincluded != b->taxincluded)
|
|
{
|
|
PWARN("Tax included flags differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (a->active != b->active)
|
|
{
|
|
PWARN("Active flags differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gncAddressEqual(a->addr, b->addr))
|
|
{
|
|
PWARN("addresses differ");
|
|
return FALSE;
|
|
}
|
|
if (!gncAddressEqual(a->shipaddr, b->shipaddr))
|
|
{
|
|
PWARN("addresses differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gnc_numeric_equal(a->credit, b->credit))
|
|
{
|
|
PWARN("Credit amounts differ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gnc_numeric_equal(a->discount, b->discount))
|
|
{
|
|
PWARN("Discount amounts differ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* FIXME: Need to check jobs list
|
|
GList * jobs;
|
|
*/
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Listen for qof events.
|
|
*
|
|
* - If the address of a customer has changed, mark the customer as dirty.
|
|
* - If a lot related to a customer has changed, clear the customer's
|
|
* cached balance as it likely has become invalid.
|
|
*
|
|
* @param entity Entity for the event
|
|
* @param event_type Event type
|
|
* @param user_data User data registered with the handler
|
|
* @param event_data Event data passed with the event.
|
|
*/
|
|
static void
|
|
cust_handle_qof_events (QofInstance *entity, QofEventId event_type,
|
|
gpointer user_data, gpointer event_data)
|
|
{
|
|
/* Handle address change events */
|
|
if ((GNC_IS_ADDRESS (entity) &&
|
|
(event_type & QOF_EVENT_MODIFY) != 0))
|
|
{
|
|
if (GNC_IS_CUSTOMER (event_data))
|
|
{
|
|
GncCustomer* cust = GNC_CUSTOMER (event_data);
|
|
gncCustomerBeginEdit (cust);
|
|
mark_customer (cust);
|
|
gncCustomerCommitEdit (cust);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Handle lot change events */
|
|
if (GNC_IS_LOT (entity))
|
|
{
|
|
GNCLot *lot = GNC_LOT (entity);
|
|
GncOwner lot_owner;
|
|
const GncOwner *end_owner = NULL;
|
|
GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
|
|
|
|
/* Determine the owner associated with the lot */
|
|
if (invoice)
|
|
/* Invoice lots */
|
|
end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
|
|
else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
|
|
/* Pre-payment lots */
|
|
end_owner = gncOwnerGetEndOwner (&lot_owner);
|
|
|
|
if (gncOwnerGetType (end_owner) == GNC_OWNER_CUSTOMER)
|
|
{
|
|
/* Clear the cached balance */
|
|
GncCustomer* cust = gncOwnerGetCustomer (end_owner);
|
|
g_free (cust->balance);
|
|
cust->balance = NULL;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* ============================================================== */
|
|
/* Package-Private functions */
|
|
static const char * _gncCustomerPrintable (gpointer item)
|
|
{
|
|
// GncCustomer *c = item;
|
|
if (!item) return "failed";
|
|
return gncCustomerGetName((GncCustomer*)item);
|
|
}
|
|
|
|
static void
|
|
destroy_customer_on_book_close(QofInstance *ent, gpointer data)
|
|
{
|
|
GncCustomer* c = GNC_CUSTOMER(ent);
|
|
|
|
gncCustomerBeginEdit(c);
|
|
gncCustomerDestroy(c);
|
|
}
|
|
|
|
/** Handles book end - frees all customers from the book
|
|
*
|
|
* @param book Book being closed
|
|
*/
|
|
static void
|
|
gnc_customer_book_end(QofBook* book)
|
|
{
|
|
QofCollection *col;
|
|
|
|
col = qof_book_get_collection(book, GNC_ID_CUSTOMER);
|
|
qof_collection_foreach(col, destroy_customer_on_book_close, NULL);
|
|
}
|
|
|
|
static QofObject gncCustomerDesc =
|
|
{
|
|
DI(.interface_version = ) QOF_OBJECT_VERSION,
|
|
DI(.e_type = ) _GNC_MOD_NAME,
|
|
DI(.type_label = ) "Customer",
|
|
DI(.create = ) (gpointer)gncCustomerCreate,
|
|
DI(.book_begin = ) NULL,
|
|
DI(.book_end = ) gnc_customer_book_end,
|
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
|
DI(.foreach = ) qof_collection_foreach,
|
|
DI(.printable = ) (const char * (*)(gpointer))gncCustomerGetName,
|
|
DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
|
|
};
|
|
|
|
gboolean gncCustomerRegister (void)
|
|
{
|
|
static QofParam params[] =
|
|
{
|
|
{ CUSTOMER_ID, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetID, (QofSetterFunc)gncCustomerSetID },
|
|
{ CUSTOMER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetName, (QofSetterFunc)gncCustomerSetName },
|
|
{ CUSTOMER_NOTES, QOF_TYPE_STRING, (QofAccessFunc)gncCustomerGetNotes, (QofSetterFunc)gncCustomerSetNotes },
|
|
{
|
|
CUSTOMER_DISCOUNT, QOF_TYPE_NUMERIC, (QofAccessFunc)gncCustomerGetDiscount,
|
|
(QofSetterFunc)gncCustomerSetDiscount
|
|
},
|
|
{
|
|
CUSTOMER_CREDIT, QOF_TYPE_NUMERIC, (QofAccessFunc)gncCustomerGetCredit,
|
|
(QofSetterFunc)gncCustomerSetCredit
|
|
},
|
|
{ CUSTOMER_ADDR, GNC_ID_ADDRESS, (QofAccessFunc)gncCustomerGetAddr, (QofSetterFunc)qofCustomerSetAddr },
|
|
{ CUSTOMER_SHIPADDR, GNC_ID_ADDRESS, (QofAccessFunc)gncCustomerGetShipAddr, (QofSetterFunc)qofCustomerSetShipAddr },
|
|
{
|
|
CUSTOMER_TT_OVER, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetTaxTableOverride,
|
|
(QofSetterFunc)gncCustomerSetTaxTableOverride
|
|
},
|
|
{ CUSTOMER_TERMS, GNC_ID_BILLTERM, (QofAccessFunc)gncCustomerGetTerms, (QofSetterFunc)gncCustomerSetTerms },
|
|
{ QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetActive, (QofSetterFunc)gncCustomerSetActive },
|
|
{ QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
|
|
{ QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
|
|
{ NULL },
|
|
};
|
|
|
|
if (!qof_choice_add_class(GNC_ID_INVOICE, GNC_ID_CUSTOMER, INVOICE_OWNER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (!qof_choice_add_class(GNC_ID_JOB, GNC_ID_CUSTOMER, JOB_OWNER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncCustomerCompare, params);
|
|
if (!qof_choice_create(GNC_ID_CUSTOMER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
/* temp */
|
|
_gncCustomerPrintable(NULL);
|
|
return qof_object_register (&gncCustomerDesc);
|
|
}
|
|
|
|
gchar *gncCustomerNextID (QofBook *book)
|
|
{
|
|
return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
|
|
}
|
|
|
|
const gnc_numeric*
|
|
gncCustomerGetCachedBalance (GncCustomer *cust)
|
|
{
|
|
return cust->balance;
|
|
}
|
|
|
|
void gncCustomerSetCachedBalance (GncCustomer *cust, const gnc_numeric *new_bal)
|
|
{
|
|
if (!new_bal)
|
|
{
|
|
if (cust->balance)
|
|
{
|
|
g_free (cust->balance);
|
|
cust->balance = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!cust->balance)
|
|
cust->balance = g_new0 (gnc_numeric, 1);
|
|
|
|
*cust->balance = *new_bal;
|
|
}
|