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