GnuCash  4.8a-132-gcdaeb421d+
gncJob.c
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 
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);
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
89 gnc_job_init(GncJob* job)
90 {
91 }
92 
93 static void
94 gnc_job_dispose(GObject *jobp)
95 {
96  G_OBJECT_CLASS(gnc_job_parent_class)->dispose(jobp);
97 }
98 
99 static void
100 gnc_job_finalize(GObject* jobp)
101 {
102  G_OBJECT_CLASS(gnc_job_parent_class)->finalize(jobp);
103 }
104 
105 static void
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
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 
165 static GList*
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
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 */
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 
234 void gncJobDestroy (GncJob *job)
235 {
236  if (!job) return;
237  qof_instance_set_destroying(job, TRUE);
238  gncJobCommitEdit (job);
239 }
240 
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 
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 
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 
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 
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 
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 
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
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 
398 void gncJobBeginEdit (GncJob *job)
399 {
400  qof_begin_edit(&job->inst);
401 }
402 
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 
409 static void job_free (QofInstance *inst)
410 {
411  GncJob *job = (GncJob *)inst;
412  gncJobFree (job);
413 }
414 
415 static void gncJobOnDone (QofInstance *qof) { }
416 
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 
431 const char * gncJobGetID (const GncJob *job)
432 {
433  if (!job) return NULL;
434  return job->id;
435 }
436 
437 const char * gncJobGetName (const GncJob *job)
438 {
439  if (!job) return NULL;
440  return job->name;
441 }
442 
443 const char * gncJobGetReference (const GncJob *job)
444 {
445  if (!job) return NULL;
446  return job->desc;
447 }
448 
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 
463 GncOwner * gncJobGetOwner (GncJob *job)
464 {
465  if (!job) return NULL;
466  return &(job->owner);
467 }
468 
469 gboolean gncJobGetActive (const GncJob *job)
470 {
471  if (!job) return FALSE;
472  return job->active;
473 }
474 
475 static QofInstance*
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 
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 
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 
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 
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 
599 gchar *gncJobNextID (QofBook *book)
600 {
601  return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
602 }
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:257
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
gchar * qof_book_increment_and_format_counter(QofBook *book, const char *counter_name)
This will increment the named counter for this book and format it.
Definition: qofbook.cpp:703
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
Definition: gnc-features.c:135
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:405
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:64
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
Definition: qofid.cpp:323
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:184
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:276
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
Definition: gncJob.c:41
gboolean qof_choice_create(char *type)
Set an object as using QOF_TYPE_CHOICE.
Definition: qofchoice.cpp:67
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition: gncOwner.c:320
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:263
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:201
Business Invoice Interface.
Job Interface.
gboolean qof_choice_add_class(const char *select, char *option, char *param_name)
Add the choices for this parameter to the object.
Definition: qofchoice.cpp:78
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
If the given owner is of type GNC_OWNER_VENDOR, returns the pointer to the vendor object...
Definition: gncOwner.c:384
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
If the given owner is of type GNC_OWNER_CUSTOMER, returns the pointer to the customer object...
Definition: gncOwner.c:370
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:317
gboolean qof_instance_has_kvp(QofInstance *inst)
Report whether a QofInstance has anything stored in KVP.
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
Utility functions for file access.