1 /********************************************************************\
2 * gncJob.c -- the Core Job Interface *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License, or (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License*
15 * along with this program; if not, contact: *
16 * *
17 * Free Software Foundation Voice: +1-617-542-5942 *
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 * Boston, MA 02110-1301, USA gnu@gnu.org *
20 * *
21 \********************************************************************/
22
23 /*
24 * Copyright (C) 2001, 2002 Derek Atkins
25 * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
26 * Author: Derek Atkins <warlord@MIT.EDU>
27 */
28
29 #include <config.h>
30
31 #include <glib.h>
32 #include <string.h>
33 #include <qofinstance-p.h>
34
35 #include "gnc-features.h"
36 #include "gncInvoice.h"
37 #include "gncJob.h"
38 #include "gncJobP.h"
39 #include "gncOwnerP.h"
40
41 struct _gncJob
42 {
43 QofInstance inst;
44 const char * id;
45 const char * name;
46 const char * desc;
47 GncOwner owner;
48 gboolean active;
49 };
50
51 struct _gncJobClass
52 {
53 QofInstanceClass parent_class;
54 };
55
56 static QofLogModule log_module = GNC_MOD_BUSINESS;
57
58 #define _GNC_MOD_NAME GNC_ID_JOB
59 #define GNC_JOB_RATE "job-rate"
60
61 /* ================================================================== */
62 /* misc inline functions */
63
64 static inline void mark_job (GncJob *job);
mark_job(GncJob * job)65 void mark_job (GncJob *job)
66 {
67 qof_instance_set_dirty(&job->inst);
68 qof_event_gen (&job->inst, QOF_EVENT_MODIFY, NULL);
69 }
70
71 /* ================================================================== */
72
73 enum
74 {
75 PROP_0,
76 // PROP_ID, /* Table */
77 PROP_NAME, /* Table */
78 // PROP_REFERENCE, /* Table */
79 // PROP_ACTIVE, /* Table */
80 // PROP_OWNER_TYPE, /* Table */
81 // PROP_OWNER, /* Table */
82 PROP_PDF_DIRNAME, /* KVP */
83 };
84
85 /* GObject Initialization */
86 G_DEFINE_TYPE(GncJob, gnc_job, QOF_TYPE_INSTANCE);
87
88 static void
gnc_job_init(GncJob * job)89 gnc_job_init(GncJob* job)
90 {
91 }
92
93 static void
gnc_job_dispose(GObject * jobp)94 gnc_job_dispose(GObject *jobp)
95 {
96 G_OBJECT_CLASS(gnc_job_parent_class)->dispose(jobp);
97 }
98
99 static void
gnc_job_finalize(GObject * jobp)100 gnc_job_finalize(GObject* jobp)
101 {
102 G_OBJECT_CLASS(gnc_job_parent_class)->finalize(jobp);
103 }
104
105 static void
gnc_job_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)106 gnc_job_get_property (GObject *object,
107 guint prop_id,
108 GValue *value,
109 GParamSpec *pspec)
110 {
111 GncJob *job;
112 gchar *key;
113
114 g_return_if_fail(GNC_IS_JOB(object));
115
116 job = GNC_JOB(object);
117 switch (prop_id)
118 {
119 case PROP_NAME:
120 g_value_set_string(value, job->name);
121 break;
122 case PROP_PDF_DIRNAME:
123 qof_instance_get_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
124 break;
125 default:
126 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
127 break;
128 }
129 }
130
131 static void
gnc_job_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)132 gnc_job_set_property (GObject *object,
133 guint prop_id,
134 const GValue *value,
135 GParamSpec *pspec)
136 {
137 GncJob *job;
138 gchar *key;
139
140 g_return_if_fail(GNC_IS_JOB(object));
141
142 job = GNC_JOB(object);
143 g_assert (qof_instance_get_editlevel(job));
144
145 switch (prop_id)
146 {
147 case PROP_NAME:
148 gncJobSetName(job, g_value_get_string(value));
149 break;
150 case PROP_PDF_DIRNAME:
151 qof_instance_set_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
152 break;
153 default:
154 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
155 break;
156 }
157 }
158
159 /** Returns a list of my type of object which refers to an object. For example, when called as
160 qof_instance_get_typed_referring_object_list(taxtable, account);
161 it will return the list of taxtables which refer to a specific account. The result should be the
162 same regardless of which taxtable object is used. The list must be freed by the caller but the
163 objects on the list must not.
164 */
165 static GList*
impl_get_typed_referring_object_list(const QofInstance * inst,const QofInstance * ref)166 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
167 {
168 /* Refers to nothing */
169 return NULL;
170 }
171
172 static void
gnc_job_class_init(GncJobClass * klass)173 gnc_job_class_init (GncJobClass *klass)
174 {
175 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
176 QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
177
178 gobject_class->dispose = gnc_job_dispose;
179 gobject_class->finalize = gnc_job_finalize;
180 gobject_class->set_property = gnc_job_set_property;
181 gobject_class->get_property = gnc_job_get_property;
182
183 qof_class->get_display_name = NULL;
184 qof_class->refers_to_object = NULL;
185 qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
186
187 g_object_class_install_property
188 (gobject_class,
189 PROP_NAME,
190 g_param_spec_string ("name",
191 "Job Name",
192 "The job name is an arbitrary string "
193 "assigned by the user. It is intended to "
194 "a short character string that is displayed "
195 "by the GUI as the job mnemonic.",
196 NULL,
197 G_PARAM_READWRITE));
198
199 g_object_class_install_property
200 (gobject_class,
201 PROP_PDF_DIRNAME,
202 g_param_spec_string ("export-pdf-dir",
203 "Export PDF Directory Name",
204 "A subdirectory for exporting PDF reports which is "
205 "appended to the target directory when writing them "
206 "out. It is retrieved from preferences and stored on "
207 "each 'Owner' object which prints items after "
208 "printing.",
209 NULL,
210 G_PARAM_READWRITE));
211 }
212
213 /* Create/Destroy Functions */
gncJobCreate(QofBook * book)214 GncJob *gncJobCreate (QofBook *book)
215 {
216 GncJob *job;
217
218 if (!book) return NULL;
219
220 job = g_object_new (GNC_TYPE_JOB, NULL);
221 qof_instance_init_data (&job->inst, _GNC_MOD_NAME, book);
222
223 job->id = CACHE_INSERT ("");
224 job->name = CACHE_INSERT ("");
225 job->desc = CACHE_INSERT ("");
226 job->active = TRUE;
227
228 /* GncOwner not initialized */
229 qof_event_gen (&job->inst, QOF_EVENT_CREATE, NULL);
230
231 return job;
232 }
233
gncJobDestroy(GncJob * job)234 void gncJobDestroy (GncJob *job)
235 {
236 if (!job) return;
237 qof_instance_set_destroying(job, TRUE);
238 gncJobCommitEdit (job);
239 }
240
gncJobFree(GncJob * job)241 static void gncJobFree (GncJob *job)
242 {
243 if (!job) return;
244
245 qof_event_gen (&job->inst, QOF_EVENT_DESTROY, NULL);
246
247 CACHE_REMOVE (job->id);
248 CACHE_REMOVE (job->name);
249 CACHE_REMOVE (job->desc);
250
251 switch (gncOwnerGetType (&(job->owner)))
252 {
253 case GNC_OWNER_CUSTOMER:
254 gncCustomerRemoveJob (gncOwnerGetCustomer(&job->owner), job);
255 break;
256 case GNC_OWNER_VENDOR:
257 gncVendorRemoveJob (gncOwnerGetVendor(&job->owner), job);
258 break;
259 default:
260 break;
261 }
262
263 /* qof_instance_release (&job->inst); */
264 g_object_unref (job);
265 }
266
267
268 /* ================================================================== */
269 /* Set Functions */
270
271 #define SET_STR(obj, member, str) { \
272 if (!g_strcmp0 (member, str)) return; \
273 gncJobBeginEdit (obj); \
274 CACHE_REPLACE (member, str); \
275 }
276
gncJobSetID(GncJob * job,const char * id)277 void gncJobSetID (GncJob *job, const char *id)
278 {
279 if (!job) return;
280 if (!id) return;
281 SET_STR(job, job->id, id);
282 mark_job (job);
283 gncJobCommitEdit (job);
284 }
285
gncJobSetName(GncJob * job,const char * name)286 void gncJobSetName (GncJob *job, const char *name)
287 {
288 if (!job) return;
289 if (!name) return;
290 SET_STR(job, job->name, name);
291 mark_job (job);
292 gncJobCommitEdit (job);
293 }
294
gncJobSetReference(GncJob * job,const char * desc)295 void gncJobSetReference (GncJob *job, const char *desc)
296 {
297 if (!job) return;
298 if (!desc) return;
299 SET_STR(job, job->desc, desc);
300 mark_job (job);
301 gncJobCommitEdit (job);
302 }
303
gncJobSetRate(GncJob * job,gnc_numeric rate)304 void gncJobSetRate (GncJob *job, gnc_numeric rate)
305 {
306 if (!job) return;
307 if (gnc_numeric_equal (gncJobGetRate(job), rate)) return;
308
309 gncJobBeginEdit (job);
310 if (!gnc_numeric_zero_p(rate))
311 {
312 GValue v = G_VALUE_INIT;
313 g_value_init (&v, GNC_TYPE_NUMERIC);
314 g_value_set_boxed (&v, &rate);
315 qof_instance_set_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
316 g_value_unset (&v);
317 }
318 else
319 {
320 qof_instance_set_kvp (QOF_INSTANCE (job), NULL, 1, GNC_JOB_RATE);
321 }
322 mark_job (job);
323 gncJobCommitEdit (job);
324 }
325
gncJobSetOwner(GncJob * job,GncOwner * owner)326 void gncJobSetOwner (GncJob *job, GncOwner *owner)
327 {
328 if (!job) return;
329 if (!owner) return;
330 if (gncOwnerEqual (owner, &(job->owner))) return;
331
332 switch (gncOwnerGetType (owner))
333 {
334 case GNC_OWNER_CUSTOMER:
335 case GNC_OWNER_VENDOR:
336 break;
337 default:
338 PERR("Unsupported Owner type: %d", gncOwnerGetType(owner));
339 return;
340 }
341
342 gncJobBeginEdit (job);
343
344 switch (gncOwnerGetType (&(job->owner)))
345 {
346 case GNC_OWNER_CUSTOMER:
347 gncCustomerRemoveJob (gncOwnerGetCustomer(&job->owner), job);
348 break;
349 case GNC_OWNER_VENDOR:
350 gncVendorRemoveJob (gncOwnerGetVendor(&job->owner), job);
351 break;
352 default:
353 break;
354 }
355
356 gncOwnerCopy (owner, &(job->owner));
357
358 switch (gncOwnerGetType (&(job->owner)))
359 {
360 case GNC_OWNER_CUSTOMER:
361 gncCustomerAddJob (gncOwnerGetCustomer(&job->owner), job);
362 break;
363 case GNC_OWNER_VENDOR:
364 gncVendorAddJob (gncOwnerGetVendor(&job->owner), job);
365 break;
366 default:
367 break;
368 }
369
370 mark_job (job);
371 gncJobCommitEdit (job);
372 }
373
gncJobSetActive(GncJob * job,gboolean active)374 void gncJobSetActive (GncJob *job, gboolean active)
375 {
376 if (!job) return;
377 if (active == job->active) return;
378 gncJobBeginEdit (job);
379 job->active = active;
380 mark_job (job);
381 gncJobCommitEdit (job);
382 }
383
384 static void
qofJobSetOwner(GncJob * job,QofInstance * ent)385 qofJobSetOwner (GncJob *job, QofInstance *ent)
386 {
387 if (!job || !ent)
388 {
389 return;
390 }
391
392 gncJobBeginEdit (job);
393 qofOwnerSetEntity(&job->owner, ent);
394 mark_job (job);
395 gncJobCommitEdit (job);
396 }
397
gncJobBeginEdit(GncJob * job)398 void gncJobBeginEdit (GncJob *job)
399 {
400 qof_begin_edit(&job->inst);
401 }
402
gncJobOnError(QofInstance * inst,QofBackendError errcode)403 static void gncJobOnError (QofInstance *inst, QofBackendError errcode)
404 {
405 PERR("Job QofBackend Failure: %d", errcode);
406 gnc_engine_signal_commit_error( errcode );
407 }
408
job_free(QofInstance * inst)409 static void job_free (QofInstance *inst)
410 {
411 GncJob *job = (GncJob *)inst;
412 gncJobFree (job);
413 }
414
gncJobOnDone(QofInstance * qof)415 static void gncJobOnDone (QofInstance *qof) { }
416
gncJobCommitEdit(GncJob * job)417 void gncJobCommitEdit (GncJob *job)
418 {
419 /* GnuCash 2.6.3 and earlier didn't handle job kvp's... */
420 if (qof_instance_has_kvp (QOF_INSTANCE (job)))
421 gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (job)), GNC_FEATURE_KVP_EXTRA_DATA);
422
423 if (!qof_commit_edit (QOF_INSTANCE(job))) return;
424 qof_commit_edit_part2 (&job->inst, gncJobOnError,
425 gncJobOnDone, job_free);
426 }
427
428 /* ================================================================== */
429 /* Get Functions */
430
gncJobGetID(const GncJob * job)431 const char * gncJobGetID (const GncJob *job)
432 {
433 if (!job) return NULL;
434 return job->id;
435 }
436
gncJobGetName(const GncJob * job)437 const char * gncJobGetName (const GncJob *job)
438 {
439 if (!job) return NULL;
440 return job->name;
441 }
442
gncJobGetReference(const GncJob * job)443 const char * gncJobGetReference (const GncJob *job)
444 {
445 if (!job) return NULL;
446 return job->desc;
447 }
448
gncJobGetRate(const GncJob * job)449 gnc_numeric gncJobGetRate (const GncJob *job)
450 {
451 GValue v = G_VALUE_INIT;
452 gnc_numeric *rate = NULL;
453 gnc_numeric retval;
454 if (!job) return gnc_numeric_zero ();
455 qof_instance_get_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
456 if (G_VALUE_HOLDS_BOXED (&v))
457 rate = (gnc_numeric*)g_value_get_boxed (&v);
458 retval = rate ? *rate : gnc_numeric_zero ();
459 g_value_unset (&v);
460 return retval;
461 }
462
gncJobGetOwner(GncJob * job)463 GncOwner * gncJobGetOwner (GncJob *job)
464 {
465 if (!job) return NULL;
466 return &(job->owner);
467 }
468
gncJobGetActive(const GncJob * job)469 gboolean gncJobGetActive (const GncJob *job)
470 {
471 if (!job) return FALSE;
472 return job->active;
473 }
474
475 static QofInstance*
qofJobGetOwner(GncJob * job)476 qofJobGetOwner (GncJob *job)
477 {
478 if (!job)
479 {
480 return NULL;
481 }
482 return QOF_INSTANCE(qofOwnerGetOwner(&job->owner));
483 }
484
485 /* Other functions */
486
gncJobCompare(const GncJob * a,const GncJob * b)487 int gncJobCompare (const GncJob * a, const GncJob *b)
488 {
489 if (!a && !b) return 0;
490 if (!a && b) return 1;
491 if (a && !b) return -1;
492
493 return (g_strcmp0(a->id, b->id));
494 }
495
gncJobEqual(const GncJob * a,const GncJob * b)496 gboolean gncJobEqual(const GncJob * a, const GncJob *b)
497 {
498 if (a == NULL && b == NULL) return TRUE;
499 if (a == NULL || b == NULL) return FALSE;
500
501 g_return_val_if_fail(GNC_IS_JOB(a), FALSE);
502 g_return_val_if_fail(GNC_IS_JOB(b), FALSE);
503
504 if (g_strcmp0(a->id, b->id) != 0)
505 {
506 PWARN("IDs differ: %s vs %s", a->id, b->id);
507 return FALSE;
508 }
509
510 if (g_strcmp0(a->name, b->name) != 0)
511 {
512 PWARN("Names differ: %s vs %s", a->name, b->name);
513 return FALSE;
514 }
515
516 if (g_strcmp0(a->desc, b->desc) != 0)
517 {
518 PWARN("Descriptions differ: %s vs %s", a->desc, b->desc);
519 return FALSE;
520 }
521
522 if (!gnc_numeric_equal(gncJobGetRate(a), gncJobGetRate(b)))
523 {
524 PWARN("Rates differ");
525 return FALSE;
526 }
527
528 if (a->active != b->active)
529 {
530 PWARN("Active flags differ");
531 return FALSE;
532 }
533
534 /* FIXME: Need real tests */
535 #if 0
536 GncOwner owner;
537 #endif
538
539 return TRUE;
540 }
541
542 /* ================================================================== */
543 /* Package-Private functions */
544
_gncJobPrintable(gpointer item)545 static const char * _gncJobPrintable (gpointer item)
546 {
547 GncJob *c;
548 if (!item) return NULL;
549 c = item;
550 return c->name;
551 }
552
553 static QofObject gncJobDesc =
554 {
555 DI(.interface_version = ) QOF_OBJECT_VERSION,
556 DI(.e_type = ) _GNC_MOD_NAME,
557 DI(.type_label = ) "Job",
558 DI(.create = ) (gpointer)gncJobCreate,
559 DI(.book_begin = ) NULL,
560 DI(.book_end = ) NULL,
561 DI(.is_dirty = ) qof_collection_is_dirty,
562 DI(.mark_clean = ) qof_collection_mark_clean,
563 DI(.foreach = ) qof_collection_foreach,
564 DI(.printable = ) _gncJobPrintable,
565 DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
566 };
567
gncJobRegister(void)568 gboolean gncJobRegister (void)
569 {
570 static QofParam params[] =
571 {
572 { JOB_ID, QOF_TYPE_STRING, (QofAccessFunc)gncJobGetID, (QofSetterFunc)gncJobSetID },
573 { JOB_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncJobGetName, (QofSetterFunc)gncJobSetName },
574 { JOB_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncJobGetActive, (QofSetterFunc)gncJobSetActive },
575 { JOB_REFERENCE, QOF_TYPE_STRING, (QofAccessFunc)gncJobGetReference, (QofSetterFunc)gncJobSetReference },
576 { JOB_RATE, QOF_TYPE_NUMERIC, (QofAccessFunc)gncJobGetRate, (QofSetterFunc)gncJobSetRate },
577 { JOB_OWNER, GNC_ID_OWNER, (QofAccessFunc)gncJobGetOwner, NULL },
578 { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncJobGetActive, NULL },
579 { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
580 { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
581 { NULL },
582 };
583
584 if (!qof_choice_create(GNC_ID_JOB))
585 {
586 return FALSE;
587 }
588 if (!qof_choice_add_class(GNC_ID_INVOICE, GNC_ID_JOB, INVOICE_OWNER))
589 {
590 return FALSE;
591 }
592
593 qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncJobCompare, params);
594 qofJobGetOwner(NULL);
595 qofJobSetOwner(NULL, NULL);
596 return qof_object_register (&gncJobDesc);
597 }
598
gncJobNextID(QofBook * book)599 gchar *gncJobNextID (QofBook *book)
600 {
601 return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
602 }
603