1 /********************************************************************\
2  * gncVendor.c -- the Core Vendor 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@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 #include "gncAddressP.h"
37 #include "gncBillTermP.h"
38 #include "gncInvoice.h"
39 #include "gncJobP.h"
40 #include "gncTaxTableP.h"
41 #include "gncVendor.h"
42 #include "gncVendorP.h"
43 
44 static gint vend_qof_event_handler_id = 0;
45 static void vend_handle_qof_events (QofInstance *entity, QofEventId event_type,
46                                     gpointer user_data, gpointer event_data);
47 static void qofVendorSetAddr (GncVendor *vendor, QofInstance *addr_ent);
48 static const char* qofVendorGetTaxIncluded(const GncVendor *vendor);
49 static void qofVendorSetTaxIncluded(GncVendor *vendor, const char* type_string);
50 
51 struct _gncVendor
52 {
53     QofInstance     inst;
54 
55     const char *    id;
56     const char *    name;
57     const char *    notes;
58     GncBillTerm *   terms;
59     GncAddress *    addr;
60     gnc_commodity * currency;
61     GncTaxTable*    taxtable;
62     gboolean        taxtable_override;
63     GncTaxIncluded  taxincluded;
64     gboolean        active;
65     GList *         jobs;
66     gnc_numeric *   balance; /* cached vendor balance, will not be stored */
67 };
68 
69 struct _gncVendorClass
70 {
71     QofInstanceClass parent_class;
72 };
73 
74 static QofLogModule log_module = GNC_MOD_BUSINESS;
75 
76 #define _GNC_MOD_NAME        GNC_ID_VENDOR
77 
78 /* ============================================================ */
79 /* Misc inline funcs */
80 
81 static inline void mark_vendor (GncVendor *vendor);
mark_vendor(GncVendor * vendor)82 void mark_vendor (GncVendor *vendor)
83 {
84     qof_instance_set_dirty(&vendor->inst);
85     qof_event_gen (&vendor->inst, QOF_EVENT_MODIFY, NULL);
86 }
87 
88 /* ============================================================== */
89 
90 enum
91 {
92     PROP_0,
93     PROP_NAME,			/* Table */
94     PROP_ID,			/* Table */
95     PROP_NOTES,			/* Table */
96     PROP_CURRENCY,		/* Table */
97     PROP_ACTIVE,		/* Table */
98     PROP_TAXTABLE_OVERRIDE,	/* Table */
99     PROP_BILLTERMS,		/* Table */
100     PROP_TAXTABLE,		/* Table */
101     PROP_ADDRESS,		/* Table, 8 fields */
102     PROP_TAX_INCLUDED,		/* Table */
103     PROP_TAX_INCLUDED_STR,	/* Alternate setter for PROP_TAX_INCLUDED */
104     PROP_PDF_DIRNAME,		/* KVP */
105     PROP_LAST_POSTED,		/* KVP */
106     PROP_PAYMENT_LAST_ACCT,	/* KVP */
107 };
108 
109 /* GObject Initialization */
110 G_DEFINE_TYPE(GncVendor, gnc_vendor, QOF_TYPE_INSTANCE);
111 
112 static void
gnc_vendor_init(GncVendor * vendor)113 gnc_vendor_init(GncVendor* vendor)
114 {
115 }
116 
117 static void
gnc_vendor_dispose(GObject * vendorp)118 gnc_vendor_dispose(GObject *vendorp)
119 {
120     G_OBJECT_CLASS(gnc_vendor_parent_class)->dispose(vendorp);
121 }
122 
123 static void
gnc_vendor_finalize(GObject * vendorp)124 gnc_vendor_finalize(GObject* vendorp)
125 {
126     G_OBJECT_CLASS(gnc_vendor_parent_class)->finalize(vendorp);
127 }
128 
129 /* Note that g_value_set_object() refs the object, as does
130  * g_object_get(). But g_object_get() only unrefs once when it disgorges
131  * the object, leaving an unbalanced ref, which leaks. So instead of
132  * using g_value_set_object(), use g_value_take_object() which doesn't
133  * ref the object when used in get_property().
134  */
135 static void
gnc_vendor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)136 gnc_vendor_get_property (GObject         *object,
137                          guint            prop_id,
138                          GValue          *value,
139                          GParamSpec      *pspec)
140 {
141     GncVendor *vendor;
142     gchar *key;
143 
144     g_return_if_fail(GNC_IS_VENDOR(object));
145 
146     vendor = GNC_VENDOR(object);
147     switch (prop_id)
148     {
149     case PROP_NAME:
150         g_value_set_string(value, vendor->name);
151         break;
152     case PROP_ID:
153         g_value_set_string(value, vendor->id);
154         break;
155     case PROP_NOTES:
156         g_value_set_string(value, vendor->notes);
157         break;
158     case PROP_CURRENCY:
159         g_value_take_object(value, vendor->currency);
160         break;
161     case PROP_ACTIVE:
162         g_value_set_boolean(value, vendor->active);
163         break;
164     case PROP_TAXTABLE_OVERRIDE:
165         g_value_set_boolean(value, vendor->taxtable_override);
166         break;
167     case PROP_BILLTERMS:
168         g_value_take_object(value, vendor->terms);
169         break;
170     case PROP_TAXTABLE:
171         g_value_take_object(value, vendor->taxtable);
172         break;
173     case PROP_ADDRESS:
174         g_value_take_object(value, vendor->addr);
175         break;
176     case PROP_TAX_INCLUDED:
177         g_value_set_int(value, vendor->taxincluded);
178         break;
179     case PROP_TAX_INCLUDED_STR:
180         g_value_set_string(value, qofVendorGetTaxIncluded(vendor));
181         break;
182     case PROP_PDF_DIRNAME:
183         qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
184         break;
185     case PROP_LAST_POSTED:
186         qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
187         break;
188     case PROP_PAYMENT_LAST_ACCT:
189         qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
190         break;
191     default:
192         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
193         break;
194     }
195 }
196 
197 static void
gnc_vendor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)198 gnc_vendor_set_property (GObject         *object,
199                          guint            prop_id,
200                          const GValue          *value,
201                          GParamSpec      *pspec)
202 {
203     GncVendor *vendor;
204     gchar *key;
205 
206     g_return_if_fail(GNC_IS_VENDOR(object));
207 
208     vendor = GNC_VENDOR(object);
209     g_assert (qof_instance_get_editlevel(vendor));
210 
211     switch (prop_id)
212     {
213     case PROP_NAME:
214         gncVendorSetName(vendor, g_value_get_string(value));
215         break;
216     case PROP_ID:
217         gncVendorSetID(vendor, g_value_get_string(value));
218         break;
219     case PROP_NOTES:
220         gncVendorSetNotes(vendor, g_value_get_string(value));
221         break;
222     case PROP_CURRENCY:
223         gncVendorSetCurrency(vendor, g_value_get_object(value));
224         break;
225     case PROP_ACTIVE:
226         gncVendorSetActive(vendor, g_value_get_boolean(value));
227         break;
228     case PROP_TAXTABLE_OVERRIDE:
229         gncVendorSetTaxTableOverride(vendor, g_value_get_boolean(value));
230         break;
231     case PROP_BILLTERMS:
232         gncVendorSetTerms(vendor, g_value_get_object(value));
233         break;
234     case PROP_TAXTABLE:
235         gncVendorSetTaxTable(vendor, g_value_get_object(value));
236         break;
237     case PROP_ADDRESS:
238         qofVendorSetAddr(vendor, g_value_get_object(value));
239         break;
240     case PROP_TAX_INCLUDED:
241         gncVendorSetTaxIncluded(vendor, (GncTaxIncluded)g_value_get_int(value));
242         break;
243     case PROP_TAX_INCLUDED_STR:
244         qofVendorSetTaxIncluded(vendor, g_value_get_string(value));
245         break;
246     case PROP_PDF_DIRNAME:
247         qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
248         break;
249     case PROP_LAST_POSTED:
250         qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
251         break;
252     case PROP_PAYMENT_LAST_ACCT:
253         qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
254         break;
255     default:
256         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
257         break;
258     }
259 }
260 
261 /** Does this object refer to a specific object */
262 static gboolean
impl_refers_to_object(const QofInstance * inst,const QofInstance * ref)263 impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
264 {
265     GncVendor* v;
266 
267     g_return_val_if_fail(inst != NULL, FALSE);
268     g_return_val_if_fail(GNC_IS_VENDOR(inst), FALSE);
269 
270     v = GNC_VENDOR(inst);
271 
272     if (GNC_IS_BILLTERM(ref))
273     {
274         return (v->terms == GNC_BILLTERM(ref));
275     }
276     else if (GNC_IS_TAXTABLE(ref))
277     {
278         return (v->taxtable == GNC_TAXTABLE(ref));
279     }
280 
281     return FALSE;
282 }
283 
284 /** Returns a list of my type of object which refers to an object.  For example, when called as
285         qof_instance_get_typed_referring_object_list(taxtable, account);
286     it will return the list of taxtables which refer to a specific account.  The result should be the
287     same regardless of which taxtable object is used.  The list must be freed by the caller but the
288     objects on the list must not.
289  */
290 static GList*
impl_get_typed_referring_object_list(const QofInstance * inst,const QofInstance * ref)291 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
292 {
293     if (!GNC_IS_BILLTERM(ref) && !GNC_IS_TAXTABLE(ref))
294     {
295         return NULL;
296     }
297 
298     return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
299 }
300 
301 static void
gnc_vendor_class_init(GncVendorClass * klass)302 gnc_vendor_class_init (GncVendorClass *klass)
303 {
304     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
305     QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
306 
307     gobject_class->dispose = gnc_vendor_dispose;
308     gobject_class->finalize = gnc_vendor_finalize;
309     gobject_class->set_property = gnc_vendor_set_property;
310     gobject_class->get_property = gnc_vendor_get_property;
311 
312     qof_class->get_display_name = NULL;
313     qof_class->refers_to_object = impl_refers_to_object;
314     qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
315 
316     g_object_class_install_property
317     (gobject_class,
318      PROP_NAME,
319      g_param_spec_string ("name",
320                           "Vendor Name",
321                           "The vendor name is an arbitrary string "
322                           "assigned by the user to provide the vendor name.",
323                           NULL,
324                           G_PARAM_READWRITE));
325 
326     g_object_class_install_property
327     (gobject_class,
328      PROP_ID,
329      g_param_spec_string ("id",
330                           "Vendor ID",
331                           "The vendor id is an arbitrary string "
332                           "assigned by the user to identify the vendor.",
333                           NULL,
334                           G_PARAM_READWRITE));
335 
336     g_object_class_install_property
337     (gobject_class,
338      PROP_NOTES,
339      g_param_spec_string ("notes",
340                           "Vendor notes",
341                           "The vendor notes is an arbitrary string "
342                           "assigned by the user to add extra information about the vendor.",
343                           NULL,
344                           G_PARAM_READWRITE));
345 
346     g_object_class_install_property
347     (gobject_class,
348      PROP_CURRENCY,
349      g_param_spec_object ("currency",
350                           "Currency",
351                           "The currency property denotes the currency used by this vendor.",
352                           GNC_TYPE_COMMODITY,
353                           G_PARAM_READWRITE));
354 
355     g_object_class_install_property
356     (gobject_class,
357      PROP_ACTIVE,
358      g_param_spec_boolean ("active",
359                            "Active",
360                            "TRUE if the vendor is active.  FALSE if inactive.",
361                            FALSE,
362                            G_PARAM_READWRITE));
363 
364     g_object_class_install_property
365     (gobject_class,
366      PROP_TAXTABLE_OVERRIDE,
367      g_param_spec_boolean ("tax-table-override",
368                            "Tax table override",
369                            "TRUE if the vendor has a specific tax table which overrides the default "
370                            "tax table.  FALSE if the default table should be used.",
371                            FALSE,
372                            G_PARAM_READWRITE));
373 
374     g_object_class_install_property
375     (gobject_class,
376      PROP_BILLTERMS,
377      g_param_spec_object ("terms",
378                           "Terms",
379                           "The billing terms used by this vendor.",
380                           GNC_TYPE_BILLTERM,
381                           G_PARAM_READWRITE));
382 
383     g_object_class_install_property
384     (gobject_class,
385      PROP_TAXTABLE,
386      g_param_spec_object ("tax-table",
387                           "Tax table",
388                           "The tax table which applies to this vendor.",
389                           GNC_TYPE_TAXTABLE,
390                           G_PARAM_READWRITE));
391 
392     g_object_class_install_property
393     (gobject_class,
394      PROP_ADDRESS,
395      g_param_spec_object ("address",
396                           "Address",
397                           "The address property contains the address information for this vendor.",
398                           GNC_TYPE_ADDRESS,
399                           G_PARAM_READWRITE));
400 
401     g_object_class_install_property
402     (gobject_class,
403      PROP_TAX_INCLUDED,
404      g_param_spec_int  ("tax-included",
405                         "Tax included",
406                         "The tax-included property contains the information about tax calculation this vendor.",
407                         GNC_TAXINCLUDED_YES,       /* min */
408                         GNC_TAXINCLUDED_USEGLOBAL, /* max */
409                         GNC_TAXINCLUDED_USEGLOBAL, /* default */
410                         G_PARAM_READWRITE));
411 
412     g_object_class_install_property
413     (gobject_class,
414      PROP_TAX_INCLUDED_STR,
415      g_param_spec_string("tax-included-string",
416                          "Tax included string",
417                          "The tax-included-string property contains a character version of tax-included.",
418                          FALSE,
419                          G_PARAM_READWRITE));
420     g_object_class_install_property
421     (gobject_class,
422      PROP_PDF_DIRNAME,
423      g_param_spec_string ("export-pdf-dir",
424                           "Export PDF Directory Name",
425                           "A subdirectory for exporting PDF reports which is "
426 			  "appended to the target directory when writing them "
427 			  "out. It is retrieved from preferences and stored on "
428 			  "each 'Owner' object which prints items after "
429 			  "printing.",
430                           NULL,
431                           G_PARAM_READWRITE));
432 
433     g_object_class_install_property(
434        gobject_class,
435        PROP_LAST_POSTED,
436        g_param_spec_boxed("invoice-last-posted-account",
437 			  "Invoice Last Posted Account",
438 			  "The last account to which an invoice belonging to "
439 			  "this owner was posted.",
440 			  GNC_TYPE_GUID,
441 			  G_PARAM_READWRITE));
442 
443     g_object_class_install_property(
444        gobject_class,
445        PROP_PAYMENT_LAST_ACCT,
446        g_param_spec_boxed("payment-last-account",
447 			  "Payment Last Account",
448 			  "The last account to which an payment belonging to "
449 			  "this owner was posted.",
450 			  GNC_TYPE_GUID,
451 			  G_PARAM_READWRITE));
452 }
453 
454 /* Create/Destroy Functions */
gncVendorCreate(QofBook * book)455 GncVendor *gncVendorCreate (QofBook *book)
456 {
457     GncVendor *vendor;
458 
459     if (!book) return NULL;
460 
461     vendor = g_object_new (GNC_TYPE_VENDOR, NULL);
462     qof_instance_init_data (&vendor->inst, _GNC_MOD_NAME, book);
463 
464     vendor->id = CACHE_INSERT ("");
465     vendor->name = CACHE_INSERT ("");
466     vendor->notes = CACHE_INSERT ("");
467     vendor->addr = gncAddressCreate (book, &vendor->inst);
468     vendor->taxincluded = GNC_TAXINCLUDED_USEGLOBAL;
469     vendor->active = TRUE;
470     vendor->jobs = NULL;
471     vendor->balance = NULL;
472 
473     if (vend_qof_event_handler_id == 0)
474         vend_qof_event_handler_id = qof_event_register_handler (vend_handle_qof_events, NULL);
475 
476     qof_event_gen (&vendor->inst, QOF_EVENT_CREATE, NULL);
477 
478     return vendor;
479 }
480 
gncVendorDestroy(GncVendor * vendor)481 void gncVendorDestroy (GncVendor *vendor)
482 {
483     if (!vendor) return;
484     qof_instance_set_destroying(vendor, TRUE);
485     gncVendorCommitEdit (vendor);
486 }
487 
gncVendorFree(GncVendor * vendor)488 static void gncVendorFree (GncVendor *vendor)
489 {
490     if (!vendor) return;
491 
492     qof_event_gen (&vendor->inst, QOF_EVENT_DESTROY, NULL);
493 
494     CACHE_REMOVE (vendor->id);
495     CACHE_REMOVE (vendor->name);
496     CACHE_REMOVE (vendor->notes);
497     gncAddressBeginEdit (vendor->addr);
498     gncAddressDestroy (vendor->addr);
499     g_list_free (vendor->jobs);
500     g_free (vendor->balance);
501 
502     if (vendor->terms)
503         gncBillTermDecRef (vendor->terms);
504     if (vendor->taxtable)
505         gncTaxTableDecRef (vendor->taxtable);
506 
507     /* qof_instance_release (&vendor->inst); */
508     g_object_unref (vendor);
509 }
510 
511 /* ============================================================== */
512 /* Set Functions */
513 
514 #define SET_STR(obj, member, str) { \
515         if (!g_strcmp0 (member, str)) return; \
516         gncVendorBeginEdit (obj); \
517         CACHE_REPLACE (member, str); \
518         }
519 
gncVendorSetID(GncVendor * vendor,const char * id)520 void gncVendorSetID (GncVendor *vendor, const char *id)
521 {
522     if (!vendor) return;
523     if (!id) return;
524     SET_STR(vendor, vendor->id, id);
525     mark_vendor (vendor);
526     gncVendorCommitEdit (vendor);
527 }
528 
gncVendorSetName(GncVendor * vendor,const char * name)529 void gncVendorSetName (GncVendor *vendor, const char *name)
530 {
531     if (!vendor) return;
532     if (!name) return;
533     SET_STR(vendor, vendor->name, name);
534     mark_vendor (vendor);
535     gncVendorCommitEdit (vendor);
536 }
537 
gncVendorSetNotes(GncVendor * vendor,const char * notes)538 void gncVendorSetNotes (GncVendor *vendor, const char *notes)
539 {
540     if (!vendor) return;
541     if (!notes) return;
542     SET_STR(vendor, vendor->notes, notes);
543     mark_vendor (vendor);
544     gncVendorCommitEdit (vendor);
545 }
546 
gncVendorSetTerms(GncVendor * vendor,GncBillTerm * terms)547 void gncVendorSetTerms (GncVendor *vendor, GncBillTerm *terms)
548 {
549     if (!vendor) return;
550     if (vendor->terms == terms) return;
551 
552     gncVendorBeginEdit (vendor);
553     if (vendor->terms)
554         gncBillTermDecRef (vendor->terms);
555     vendor->terms = terms;
556     if (vendor->terms)
557         gncBillTermIncRef (vendor->terms);
558     mark_vendor (vendor);
559     gncVendorCommitEdit (vendor);
560 }
561 
gncVendorSetTaxIncluded(GncVendor * vendor,GncTaxIncluded taxincl)562 void gncVendorSetTaxIncluded (GncVendor *vendor, GncTaxIncluded taxincl)
563 {
564     if (!vendor) return;
565     if (taxincl == vendor->taxincluded) return;
566     gncVendorBeginEdit (vendor);
567     vendor->taxincluded = taxincl;
568     mark_vendor (vendor);
569     gncVendorCommitEdit (vendor);
570 }
571 
gncVendorSetCurrency(GncVendor * vendor,gnc_commodity * currency)572 void gncVendorSetCurrency (GncVendor *vendor, gnc_commodity *currency)
573 {
574     if (!vendor || !currency) return;
575     if (vendor->currency &&
576             gnc_commodity_equal (vendor->currency, currency))
577         return;
578     gncVendorBeginEdit (vendor);
579     vendor->currency = currency;
580     mark_vendor (vendor);
581     gncVendorCommitEdit (vendor);
582 }
583 
gncVendorSetActive(GncVendor * vendor,gboolean active)584 void gncVendorSetActive (GncVendor *vendor, gboolean active)
585 {
586     if (!vendor) return;
587     if (active == vendor->active) return;
588     gncVendorBeginEdit (vendor);
589     vendor->active = active;
590     mark_vendor (vendor);
591     gncVendorCommitEdit (vendor);
592 }
593 
gncVendorSetTaxTableOverride(GncVendor * vendor,gboolean override)594 void gncVendorSetTaxTableOverride (GncVendor *vendor, gboolean override)
595 {
596     if (!vendor) return;
597     if (vendor->taxtable_override == override) return;
598     gncVendorBeginEdit (vendor);
599     vendor->taxtable_override = override;
600     mark_vendor (vendor);
601     gncVendorCommitEdit (vendor);
602 }
603 
gncVendorSetTaxTable(GncVendor * vendor,GncTaxTable * table)604 void gncVendorSetTaxTable (GncVendor *vendor, GncTaxTable *table)
605 {
606     if (!vendor) return;
607     if (vendor->taxtable == table) return;
608     gncVendorBeginEdit (vendor);
609     if (vendor->taxtable)
610         gncTaxTableDecRef (vendor->taxtable);
611     if (table)
612         gncTaxTableIncRef (table);
613     vendor->taxtable = table;
614     mark_vendor (vendor);
615     gncVendorCommitEdit (vendor);
616 }
617 
618 static void
qofVendorSetAddr(GncVendor * vendor,QofInstance * addr_ent)619 qofVendorSetAddr (GncVendor *vendor, QofInstance *addr_ent)
620 {
621     GncAddress *addr;
622 
623     if (!vendor || !addr_ent)
624     {
625         return;
626     }
627     addr = (GncAddress*)addr_ent;
628     if (addr == vendor->addr)
629     {
630         return;
631     }
632     if (vendor->addr != NULL)
633     {
634         gncAddressBeginEdit(vendor->addr);
635         gncAddressDestroy(vendor->addr);
636     }
637     gncVendorBeginEdit(vendor);
638     vendor->addr = addr;
639     gncVendorCommitEdit(vendor);
640 }
641 
642 static void
qofVendorSetTaxIncluded(GncVendor * vendor,const char * type_string)643 qofVendorSetTaxIncluded(GncVendor *vendor, const char* type_string)
644 {
645     GncTaxIncluded inc;
646 
647     if (!gncTaxIncludedStringToType(type_string, &inc))
648     {
649         return;
650     }
651     gncVendorBeginEdit(vendor);
652     vendor->taxincluded = inc;
653     gncVendorCommitEdit(vendor);
654 }
655 
656 /* ============================================================== */
657 /* Get Functions */
658 
gncVendorGetID(const GncVendor * vendor)659 const char * gncVendorGetID (const GncVendor *vendor)
660 {
661     if (!vendor) return NULL;
662     return vendor->id;
663 }
664 
gncVendorGetName(const GncVendor * vendor)665 const char * gncVendorGetName (const GncVendor *vendor)
666 {
667     if (!vendor) return NULL;
668     return vendor->name;
669 }
670 
gncVendorGetAddr(const GncVendor * vendor)671 GncAddress * gncVendorGetAddr (const GncVendor *vendor)
672 {
673     if (!vendor) return NULL;
674     return vendor->addr;
675 }
676 
gncVendorGetNotes(const GncVendor * vendor)677 const char * gncVendorGetNotes (const GncVendor *vendor)
678 {
679     if (!vendor) return NULL;
680     return vendor->notes;
681 }
682 
gncVendorGetTerms(const GncVendor * vendor)683 GncBillTerm * gncVendorGetTerms (const GncVendor *vendor)
684 {
685     if (!vendor) return 0;
686     return vendor->terms;
687 }
688 
gncVendorGetTaxIncluded(const GncVendor * vendor)689 GncTaxIncluded gncVendorGetTaxIncluded (const GncVendor *vendor)
690 {
691     if (!vendor) return GNC_TAXINCLUDED_USEGLOBAL;
692     return vendor->taxincluded;
693 }
694 
gncVendorGetCurrency(const GncVendor * vendor)695 gnc_commodity * gncVendorGetCurrency (const GncVendor *vendor)
696 {
697     if (!vendor) return NULL;
698     return vendor->currency;
699 }
700 
gncVendorGetActive(const GncVendor * vendor)701 gboolean gncVendorGetActive (const GncVendor *vendor)
702 {
703     if (!vendor) return FALSE;
704     return vendor->active;
705 }
706 
gncVendorGetTaxTableOverride(const GncVendor * vendor)707 gboolean gncVendorGetTaxTableOverride (const GncVendor *vendor)
708 {
709     if (!vendor) return FALSE;
710     return vendor->taxtable_override;
711 }
712 
gncVendorGetTaxTable(const GncVendor * vendor)713 GncTaxTable* gncVendorGetTaxTable (const GncVendor *vendor)
714 {
715     if (!vendor) return NULL;
716     return vendor->taxtable;
717 }
718 
719 static const char*
qofVendorGetTaxIncluded(const GncVendor * vendor)720 qofVendorGetTaxIncluded(const GncVendor *vendor)
721 {
722     return gncTaxIncludedTypeToString(vendor->taxincluded);
723 }
724 
725 /* Note that JobList changes do not affect the "dirtiness" of the vendor */
gncVendorAddJob(GncVendor * vendor,GncJob * job)726 void gncVendorAddJob (GncVendor *vendor, GncJob *job)
727 {
728     if (!vendor) return;
729     if (!job) return;
730 
731     if (g_list_index(vendor->jobs, job) == -1)
732         vendor->jobs = g_list_insert_sorted (vendor->jobs, job,
733                                              (GCompareFunc)gncJobCompare);
734 
735     qof_event_gen (&vendor->inst, QOF_EVENT_MODIFY, NULL);
736 }
737 
gncVendorRemoveJob(GncVendor * vendor,GncJob * job)738 void gncVendorRemoveJob (GncVendor *vendor, GncJob *job)
739 {
740     GList *node;
741 
742     if (!vendor) return;
743     if (!job) return;
744 
745     node = g_list_find (vendor->jobs, job);
746     if (!node)
747     {
748         /*    PERR ("split not in account"); */
749     }
750     else
751     {
752         vendor->jobs = g_list_remove_link (vendor->jobs, node);
753         g_list_free_1 (node);
754     }
755 
756     qof_event_gen (&vendor->inst, QOF_EVENT_MODIFY, NULL);
757 }
758 
gncVendorBeginEdit(GncVendor * vendor)759 void gncVendorBeginEdit (GncVendor *vendor)
760 {
761     qof_begin_edit(&vendor->inst);
762 }
763 
gncVendorOnError(QofInstance * vendor,QofBackendError errcode)764 static void gncVendorOnError (QofInstance *vendor, QofBackendError errcode)
765 {
766     PERR("Vendor QofBackend Failure: %d", errcode);
767     gnc_engine_signal_commit_error( errcode );
768 }
769 
gncVendorOnDone(QofInstance * inst)770 static void gncVendorOnDone (QofInstance *inst)
771 {
772     GncVendor *vendor = (GncVendor *) inst;
773     gncAddressClearDirty (vendor->addr);
774 }
775 
vendor_free(QofInstance * inst)776 static void vendor_free (QofInstance *inst)
777 {
778     GncVendor *vendor = (GncVendor *) inst;
779     gncVendorFree (vendor);
780 }
781 
gncVendorCommitEdit(GncVendor * vendor)782 void gncVendorCommitEdit (GncVendor *vendor)
783 {
784     if (!qof_commit_edit (QOF_INSTANCE(vendor))) return;
785     qof_commit_edit_part2 (&vendor->inst, gncVendorOnError,
786                            gncVendorOnDone, vendor_free);
787 }
788 
789 /* ============================================================== */
790 /* Other functions */
791 
gncVendorCompare(const GncVendor * a,const GncVendor * b)792 int gncVendorCompare (const GncVendor *a, const GncVendor *b)
793 {
794     if (!a && !b) return 0;
795     if (!a && b) return 1;
796     if (a && !b) return -1;
797 
798     return(strcmp(a->name, b->name));
799 }
800 
gncVendorEqual(const GncVendor * a,const GncVendor * b)801 gboolean gncVendorEqual(const GncVendor *a, const GncVendor *b)
802 {
803     if (a == NULL && b == NULL) return TRUE;
804     if (a == NULL ||  b == NULL) return FALSE;
805 
806     g_return_val_if_fail(GNC_IS_VENDOR(a), FALSE);
807     g_return_val_if_fail(GNC_IS_VENDOR(b), FALSE);
808 
809     if (g_strcmp0(a->id, b->id) != 0)
810     {
811         PWARN("IDs differ: %s vs %s", a->id, b->id);
812         return FALSE;
813     }
814 
815     if (g_strcmp0(a->name, b->name) != 0)
816     {
817         PWARN("Names differ: %s vs %s", a->name, b->name);
818         return FALSE;
819     }
820 
821     if (g_strcmp0(a->notes, b->notes) != 0)
822     {
823         PWARN("Notes differ");
824         return FALSE;
825     }
826 
827     if (!gncBillTermEqual(a->terms, b->terms))
828     {
829         PWARN("BillTerms differ");
830         return FALSE;
831     }
832 
833     if (!gncAddressEqual(a->addr, b->addr))
834     {
835         PWARN("Addresses differ");
836         return FALSE;
837     }
838 
839     if (!gnc_commodity_equal(a->currency, b->currency))
840     {
841         PWARN("Currencies differ");
842         return FALSE;
843     }
844 
845     if (!gncTaxTableEqual(a->taxtable, b->taxtable))
846     {
847         PWARN("Tax tables differ");
848         return FALSE;
849     }
850 
851     if (a->taxtable_override != b->taxtable_override)
852     {
853         PWARN("Tax table override flags differ");
854         return FALSE;
855     }
856 
857     if (a->taxincluded != b->taxincluded)
858     {
859         PWARN("Tax included flags differ");
860         return FALSE;
861     }
862 
863     if (a->active != b->active)
864     {
865         PWARN("Active flags differ");
866         return FALSE;
867     }
868 
869 //    GList *         jobs;
870     return TRUE;
871 }
872 
873 gboolean
gncVendorIsDirty(const GncVendor * vendor)874 gncVendorIsDirty (const GncVendor *vendor)
875 {
876     if (!vendor) return FALSE;
877     return (qof_instance_get_dirty_flag(vendor)
878             || gncAddressIsDirty (vendor->addr));
879 }
880 
881 /**
882  * Listen for qof events.
883  *
884  * - If the address of a vendor has changed, mark the vendor as dirty.
885  * - If a lot related to a vendor has changed, clear the vendor's
886  *   cached balance as it likely has become invalid.
887  *
888  * @param entity Entity for the event
889  * @param event_type Event type
890  * @param user_data User data registered with the handler
891  * @param event_data Event data passed with the event.
892  */
893 static void
vend_handle_qof_events(QofInstance * entity,QofEventId event_type,gpointer user_data,gpointer event_data)894 vend_handle_qof_events (QofInstance *entity, QofEventId event_type,
895                         gpointer user_data, gpointer event_data)
896 {
897     /* Handle address change events */
898     if ((GNC_IS_ADDRESS (entity) &&
899         (event_type & QOF_EVENT_MODIFY) != 0))
900     {
901         if (GNC_IS_VENDOR (event_data))
902         {
903             GncVendor* vend = GNC_VENDOR (event_data);
904             gncVendorBeginEdit (vend);
905             mark_vendor (vend);
906             gncVendorCommitEdit (vend);
907         }
908         return;
909     }
910 
911     /* Handle lot change events */
912     if (GNC_IS_LOT (entity))
913     {
914         GNCLot *lot = GNC_LOT (entity);
915         GncOwner lot_owner;
916         const GncOwner *end_owner = NULL;
917         GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
918 
919         /* Determine the owner associated with the lot */
920         if (invoice)
921             /* Invoice lots */
922             end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
923         else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
924             /* Pre-payment lots */
925             end_owner = gncOwnerGetEndOwner (&lot_owner);
926 
927         if (gncOwnerGetType (end_owner) == GNC_OWNER_VENDOR)
928         {
929             /* Clear the cached balance */
930             GncVendor* vend = gncOwnerGetVendor (end_owner);
931             g_free (vend->balance);
932             vend->balance = NULL;
933         }
934         return;
935     }
936 }
937 
938 /* ============================================================== */
939 /* Package-Private functions */
940 
_gncVendorPrintable(gpointer item)941 static const char * _gncVendorPrintable (gpointer item)
942 {
943     GncVendor *v = item;
944     if (!item) return NULL;
945     return v->name;
946 }
947 
948 static void
destroy_vendor_on_book_close(QofInstance * ent,gpointer data)949 destroy_vendor_on_book_close(QofInstance *ent, gpointer data)
950 {
951     GncVendor* v = GNC_VENDOR(ent);
952 
953     gncVendorBeginEdit(v);
954     gncVendorDestroy(v);
955 }
956 
957 /** Handles book end - frees all vendors from the book
958  *
959  * @param book Book being closed
960  */
961 static void
gnc_vendor_book_end(QofBook * book)962 gnc_vendor_book_end(QofBook* book)
963 {
964     QofCollection *col;
965 
966     col = qof_book_get_collection(book, GNC_ID_VENDOR);
967     qof_collection_foreach(col, destroy_vendor_on_book_close, NULL);
968 }
969 
970 static QofObject gncVendorDesc =
971 {
972     DI(.interface_version = ) QOF_OBJECT_VERSION,
973     DI(.e_type            = ) _GNC_MOD_NAME,
974     DI(.type_label        = ) "Vendor",
975     DI(.create            = ) (gpointer)gncVendorCreate,
976     DI(.book_begin        = ) NULL,
977     DI(.book_end          = ) gnc_vendor_book_end,
978     DI(.is_dirty          = ) qof_collection_is_dirty,
979     DI(.mark_clean        = ) qof_collection_mark_clean,
980     DI(.foreach           = ) qof_collection_foreach,
981     DI(.printable         = ) _gncVendorPrintable,
982     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
983 };
984 
gncVendorRegister(void)985 gboolean gncVendorRegister (void)
986 {
987     static QofParam params[] =
988     {
989         { VENDOR_ID, QOF_TYPE_STRING, (QofAccessFunc)gncVendorGetID, (QofSetterFunc)gncVendorSetID },
990         { VENDOR_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncVendorGetName, (QofSetterFunc)gncVendorSetName },
991         { VENDOR_ADDR,    GNC_ID_ADDRESS, (QofAccessFunc)gncVendorGetAddr, (QofSetterFunc)qofVendorSetAddr },
992         { VENDOR_NOTES,   QOF_TYPE_STRING, (QofAccessFunc)gncVendorGetNotes, (QofSetterFunc)gncVendorSetNotes },
993         { VENDOR_TERMS,   GNC_ID_BILLTERM, (QofAccessFunc)gncVendorGetTerms, (QofSetterFunc)gncVendorSetTerms },
994         {
995             VENDOR_TAX_OVERRIDE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncVendorGetTaxTableOverride,
996             (QofSetterFunc)gncVendorSetTaxTableOverride
997         },
998         {
999             VENDOR_TAX_TABLE, GNC_ID_TAXTABLE, (QofAccessFunc)gncVendorGetTaxTable,
1000             (QofSetterFunc)gncVendorSetTaxTable
1001         },
1002         {
1003             VENDOR_TAX_INC, QOF_TYPE_STRING, (QofAccessFunc)qofVendorGetTaxIncluded,
1004             (QofSetterFunc)qofVendorSetTaxIncluded
1005         },
1006         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
1007         { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
1008         { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncVendorGetActive, NULL },
1009         { NULL },
1010     };
1011 
1012     if (!qof_choice_add_class(GNC_ID_INVOICE, GNC_ID_VENDOR, INVOICE_OWNER))
1013     {
1014         return FALSE;
1015     }
1016     if (!qof_choice_add_class(GNC_ID_JOB, GNC_ID_VENDOR, JOB_OWNER))
1017     {
1018         return FALSE;
1019     }
1020 
1021     qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncVendorCompare, params);
1022 
1023     return qof_object_register (&gncVendorDesc);
1024 }
1025 
gncVendorNextID(QofBook * book)1026 gchar *gncVendorNextID (QofBook *book)
1027 {
1028     return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
1029 }
1030 
1031 const gnc_numeric*
gncVendorGetCachedBalance(GncVendor * vend)1032 gncVendorGetCachedBalance (GncVendor *vend)
1033 {
1034     return vend->balance;
1035 }
1036 
gncVendorSetCachedBalance(GncVendor * vend,const gnc_numeric * new_bal)1037 void gncVendorSetCachedBalance (GncVendor *vend, const gnc_numeric *new_bal)
1038 {
1039     if (!new_bal)
1040     {
1041         if (vend->balance)
1042         {
1043             g_free (vend->balance);
1044             vend->balance = NULL;
1045         }
1046         return;
1047     }
1048 
1049     if (!vend->balance)
1050         vend->balance = g_new0 (gnc_numeric, 1);
1051 
1052     *vend->balance = *new_bal;
1053 }
1054