1 /********************************************************************\
2  * gncEmployee.c -- the Core Employee 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 "Account.h"
36 #include "gnc-commodity.h"
37 #include "gncAddressP.h"
38 #include "gncEmployee.h"
39 #include "gncEmployeeP.h"
40 #include "gnc-lot.h"
41 #include "gncOwner.h"
42 
43 static gint empl_qof_event_handler_id = 0;
44 static void empl_handle_qof_events (QofInstance *entity, QofEventId event_type,
45                                     gpointer user_data, gpointer event_data);
46 
47 struct _gncEmployee
48 {
49     QofInstance     inst;
50     const char *    id;
51     const char *    username;
52     GncAddress *    addr;
53     gnc_commodity * currency;
54     gboolean        active;
55     gnc_numeric *   balance;
56 
57     const char *    language;
58     const char *    acl;
59     gnc_numeric     workday;
60     gnc_numeric     rate;
61 
62     Account *        ccard_acc;
63 };
64 
65 struct _gncEmployeeClass
66 {
67     QofInstanceClass parent_class;
68 };
69 
70 static QofLogModule log_module = GNC_MOD_BUSINESS;
71 
72 #define _GNC_MOD_NAME        GNC_ID_EMPLOYEE
73 
74 static inline void mark_employee (GncEmployee *employee);
mark_employee(GncEmployee * employee)75 void mark_employee (GncEmployee *employee)
76 {
77     qof_instance_set_dirty(&employee->inst);
78     qof_event_gen (&employee->inst, QOF_EVENT_MODIFY, NULL);
79 }
80 
81 /* ============================================================== */
82 
83 enum
84 {
85     PROP_0,
86     PROP_USERNAME,		/* Table */
87     PROP_ID,			/* Table */
88     PROP_LANGUAGE,		/* Table */
89     PROP_ACL,			/* Table */
90     PROP_ACTIVE,		/* Table */
91     PROP_CURRENCY,		/* Table */
92     PROP_CCARD,			/* Table */
93     PROP_WORKDAY,		/* Table (numeric) */
94     PROP_RATE,			/* Table (numeric) */
95     PROP_ADDRESS,		/* Table, 8 fields */
96     PROP_PDF_DIRNAME,		/* KVP */
97     PROP_LAST_POSTED,		/* KVP */
98     PROP_PAYMENT_LAST_ACCT,	/* KVP */
99 };
100 
101 /* GObject Initialization */
102 G_DEFINE_TYPE(GncEmployee, gnc_employee, QOF_TYPE_INSTANCE);
103 
104 static void
gnc_employee_init(GncEmployee * emp)105 gnc_employee_init(GncEmployee* emp)
106 {
107 }
108 
109 static void
gnc_employee_dispose(GObject * empp)110 gnc_employee_dispose(GObject *empp)
111 {
112     G_OBJECT_CLASS(gnc_employee_parent_class)->dispose(empp);
113 }
114 
115 static void
gnc_employee_finalize(GObject * empp)116 gnc_employee_finalize(GObject* empp)
117 {
118     G_OBJECT_CLASS(gnc_employee_parent_class)->finalize(empp);
119 }
120 
121 /* Note that g_value_set_object() refs the object, as does
122  * g_object_get(). But g_object_get() only unrefs once when it disgorges
123  * the object, leaving an unbalanced ref, which leaks. So instead of
124  * using g_value_set_object(), use g_value_take_object() which doesn't
125  * ref the object when used in get_property().
126  */
127 static void
gnc_employee_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)128 gnc_employee_get_property (GObject         *object,
129                            guint            prop_id,
130                            GValue          *value,
131                            GParamSpec      *pspec)
132 {
133     GncEmployee *emp;
134     g_return_if_fail(GNC_IS_EMPLOYEE(object));
135     emp = GNC_EMPLOYEE(object);
136     switch (prop_id)
137     {
138     case PROP_USERNAME:
139         g_value_set_string(value, emp->username);
140         break;
141     case PROP_ID:
142         g_value_set_string(value, emp->id);
143         break;
144     case PROP_ACTIVE:
145         g_value_set_boolean(value, emp->active);
146         break;
147     case PROP_LANGUAGE:
148         g_value_set_string(value, emp->language);
149         break;
150     case PROP_CURRENCY:
151         g_value_take_object(value, emp->currency);
152         break;
153     case PROP_ACL:
154         g_value_set_string(value, emp->acl);
155         break;
156     case PROP_ADDRESS:
157         g_value_take_object(value, emp->addr);
158         break;
159     case PROP_WORKDAY:
160         g_value_set_boxed(value, &emp->workday);
161         break;
162     case PROP_RATE:
163         g_value_set_boxed(value, &emp->rate);
164         break;
165     case PROP_CCARD:
166         g_value_take_object(value, emp->ccard_acc);
167         break;
168     case PROP_PDF_DIRNAME:
169         qof_instance_get_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
170         break;
171     case PROP_LAST_POSTED:
172         qof_instance_get_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
173         break;
174     case PROP_PAYMENT_LAST_ACCT:
175         qof_instance_get_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
176         break;
177     default:
178         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
179         break;
180     }
181 }
182 
183 static void
gnc_employee_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)184 gnc_employee_set_property (GObject         *object,
185                            guint            prop_id,
186                            const GValue          *value,
187                            GParamSpec      *pspec)
188 {
189     GncEmployee *emp;
190     g_return_if_fail(GNC_IS_EMPLOYEE(object));
191     emp = GNC_EMPLOYEE(object);
192     g_assert (qof_instance_get_editlevel(emp));
193     switch (prop_id)
194     {
195     case PROP_USERNAME:
196         gncEmployeeSetUsername(emp, g_value_get_string(value));
197         break;
198     case PROP_ID:
199         gncEmployeeSetID(emp, g_value_get_string(value));
200         break;
201     case PROP_ACTIVE:
202         gncEmployeeSetActive(emp, g_value_get_boolean(value));
203         break;
204     case PROP_LANGUAGE:
205         gncEmployeeSetLanguage(emp, g_value_get_string(value));
206         break;
207     case PROP_CURRENCY:
208         gncEmployeeSetCurrency(emp, g_value_get_object(value));
209         break;
210     case PROP_ACL:
211         gncEmployeeSetAcl(emp, g_value_get_string(value));
212         break;
213     case PROP_ADDRESS:
214         qofEmployeeSetAddr(emp, g_value_get_object(value));
215         break;
216     case PROP_WORKDAY:
217         gncEmployeeSetWorkday(emp, *(gnc_numeric*)g_value_get_boxed(value));
218         break;
219     case PROP_RATE:
220         gncEmployeeSetRate(emp, *(gnc_numeric*)g_value_get_boxed(value));
221         break;
222     case PROP_CCARD:
223         gncEmployeeSetCCard(emp, g_value_get_object(value));
224         break;
225     case PROP_PDF_DIRNAME:
226         qof_instance_set_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
227         break;
228     case PROP_LAST_POSTED:
229         qof_instance_set_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
230         break;
231     case PROP_PAYMENT_LAST_ACCT:
232         qof_instance_set_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
233         break;
234     default:
235         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
236         break;
237     }
238 }
239 
240 /** Does this object refer to a specific object */
241 static gboolean
impl_refers_to_object(const QofInstance * inst,const QofInstance * ref)242 impl_refers_to_object(const QofInstance* inst, const QofInstance* ref)
243 {
244     GncEmployee* emp;
245 
246     g_return_val_if_fail(inst != NULL, FALSE);
247     g_return_val_if_fail(GNC_IS_EMPLOYEE(inst), FALSE);
248 
249     emp = GNC_EMPLOYEE(inst);
250 
251     if (GNC_IS_COMMODITY(ref))
252     {
253         return (emp->currency == GNC_COMMODITY(ref));
254     }
255     else if (GNC_IS_ACCOUNT(ref))
256     {
257         return (emp->ccard_acc == GNC_ACCOUNT(ref));
258     }
259 
260     return FALSE;
261 }
262 
263 /** Returns a list of my type of object which refers to an object.  For example, when called as
264         qof_instance_get_typed_referring_object_list(taxtable, account);
265     it will return the list of taxtables which refer to a specific account.  The result should be the
266     same regardless of which taxtable object is used.  The list must be freed by the caller but the
267     objects on the list must not.
268  */
269 static GList*
impl_get_typed_referring_object_list(const QofInstance * inst,const QofInstance * ref)270 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
271 {
272     if (!GNC_IS_COMMODITY(ref) && !GNC_IS_ACCOUNT(ref))
273     {
274         return NULL;
275     }
276 
277     return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
278 }
279 
280 static void
gnc_employee_class_init(GncEmployeeClass * klass)281 gnc_employee_class_init (GncEmployeeClass *klass)
282 {
283     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
284     QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
285 
286     gobject_class->dispose = gnc_employee_dispose;
287     gobject_class->finalize = gnc_employee_finalize;
288     gobject_class->set_property = gnc_employee_set_property;
289     gobject_class->get_property = gnc_employee_get_property;
290 
291     qof_class->get_display_name = NULL;
292     qof_class->refers_to_object = impl_refers_to_object;
293     qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
294 
295     g_object_class_install_property
296     (gobject_class,
297      PROP_USERNAME,
298      g_param_spec_string ("username",
299                           "Employee Name",
300                           "The employee name is an arbitrary string "
301                           "assigned by the user which provides the employee "
302                           "name.",
303                           NULL,
304                           G_PARAM_READWRITE));
305 
306     g_object_class_install_property
307     (gobject_class,
308      PROP_ID,
309      g_param_spec_string ("id",
310                           "Employee ID",
311                           "The employee ID is an arbitrary string "
312                           "assigned by the user which provides the employee "
313                           "ID.",
314                           NULL,
315                           G_PARAM_READWRITE));
316 
317     g_object_class_install_property
318     (gobject_class,
319      PROP_ACTIVE,
320      g_param_spec_boolean ("active",
321                            "Active",
322                            "TRUE if the employee is active.  FALSE if inactive.",
323                            FALSE,
324                            G_PARAM_READWRITE));
325 
326     g_object_class_install_property
327     (gobject_class,
328      PROP_LANGUAGE,
329      g_param_spec_string ("language",
330                           "Employee Language",
331                           "The language is an arbitrary string "
332                           "assigned by the user which provides the language spoken "
333                           " by the employee.",
334                           NULL,
335                           G_PARAM_READWRITE));
336 
337     g_object_class_install_property
338     (gobject_class,
339      PROP_CURRENCY,
340      g_param_spec_object ("currency",
341                           "Currency",
342                           "The currency property denotes the currency used by this employee.",
343                           GNC_TYPE_COMMODITY,
344                           G_PARAM_READWRITE));
345 
346     g_object_class_install_property
347     (gobject_class,
348      PROP_ACL,
349      g_param_spec_string ("acl",
350                           "Employee ACL",
351                           "The acl is an arbitrary string "
352                           "assigned by the user which provides ??? "
353                           " for the employee.",
354                           NULL,
355                           G_PARAM_READWRITE));
356 
357     g_object_class_install_property
358     (gobject_class,
359      PROP_ADDRESS,
360      g_param_spec_object ("address",
361                           "Address",
362                           "The address property contains the address information for this employee.",
363                           GNC_TYPE_ADDRESS,
364                           G_PARAM_READWRITE));
365 
366     g_object_class_install_property
367     (gobject_class,
368      PROP_WORKDAY,
369      g_param_spec_boxed("workday",
370                         "Workday rate",
371                         "The daily rate for this employee.",
372                         GNC_TYPE_NUMERIC,
373                         G_PARAM_READWRITE));
374 
375     g_object_class_install_property
376     (gobject_class,
377      PROP_RATE,
378      g_param_spec_boxed("rate",
379                         "Hourly rate",
380                         "The hourly rate for this employee.",
381                         GNC_TYPE_NUMERIC,
382                         G_PARAM_READWRITE));
383 
384     g_object_class_install_property
385     (gobject_class,
386      PROP_CCARD,
387      g_param_spec_object ("credit-card-account",
388                           "Credit card account",
389                           "The credit card account for this employee.",
390                           GNC_TYPE_ACCOUNT,
391                           G_PARAM_READWRITE));
392 
393     g_object_class_install_property
394     (gobject_class,
395      PROP_PDF_DIRNAME,
396      g_param_spec_string ("export-pdf-dir",
397                           "Export PDF Directory Name",
398                           "A subdirectory for exporting PDF reports which is "
399 			  "appended to the target directory when writing them "
400 			  "out. It is retrieved from preferences and stored on "
401 			  "each 'Owner' object which prints items after "
402 			  "printing.",
403                           NULL,
404                           G_PARAM_READWRITE));
405 
406     g_object_class_install_property(
407        gobject_class,
408        PROP_LAST_POSTED,
409        g_param_spec_boxed("invoice-last-posted-account",
410 			  "Invoice Last Posted Account",
411 			  "The last account to which an invoice belonging to "
412 			  "this owner was posted.",
413 			  GNC_TYPE_GUID,
414 			  G_PARAM_READWRITE));
415 
416     g_object_class_install_property(
417        gobject_class,
418        PROP_PAYMENT_LAST_ACCT,
419        g_param_spec_boxed("payment-last-account",
420 			  "Payment Last Account",
421 			  "The last account to which an payment belonging to "
422 			  "this owner was posted.",
423 			  GNC_TYPE_GUID,
424 			  G_PARAM_READWRITE));
425 }
426 
427 /* Create/Destroy Functions */
gncEmployeeCreate(QofBook * book)428 GncEmployee *gncEmployeeCreate (QofBook *book)
429 {
430     GncEmployee *employee;
431 
432     if (!book) return NULL;
433 
434     employee = g_object_new (GNC_TYPE_EMPLOYEE, NULL);
435     qof_instance_init_data (&employee->inst, _GNC_MOD_NAME, book);
436 
437     employee->id = CACHE_INSERT ("");
438     employee->username = CACHE_INSERT ("");
439     employee->language = CACHE_INSERT ("");
440     employee->acl = CACHE_INSERT ("");
441     employee->addr = gncAddressCreate (book, &employee->inst);
442     employee->workday = gnc_numeric_zero();
443     employee->rate = gnc_numeric_zero();
444     employee->active = TRUE;
445     employee->balance = NULL;
446 
447     if (empl_qof_event_handler_id == 0)
448         empl_qof_event_handler_id = qof_event_register_handler (empl_handle_qof_events, NULL);
449 
450     qof_event_gen (&employee->inst, QOF_EVENT_CREATE, NULL);
451 
452     return employee;
453 }
454 
gncEmployeeDestroy(GncEmployee * employee)455 void gncEmployeeDestroy (GncEmployee *employee)
456 {
457     if (!employee) return;
458     qof_instance_set_destroying(employee, TRUE);
459     gncEmployeeCommitEdit(employee);
460 }
461 
gncEmployeeFree(GncEmployee * employee)462 static void gncEmployeeFree (GncEmployee *employee)
463 {
464     if (!employee) return;
465 
466     qof_event_gen (&employee->inst, QOF_EVENT_DESTROY, NULL);
467 
468     CACHE_REMOVE (employee->id);
469     CACHE_REMOVE (employee->username);
470     CACHE_REMOVE (employee->language);
471     CACHE_REMOVE (employee->acl);
472     gncAddressBeginEdit (employee->addr);
473     gncAddressDestroy (employee->addr);
474     g_free (employee->balance);
475 
476     /* qof_instance_release (&employee->inst); */
477     g_object_unref (employee);
478 }
479 
480 /* ============================================================== */
481 /* Set Functions */
482 
483 #define SET_STR(obj, member, str) { \
484         if (!g_strcmp0 (member, str)) return; \
485         gncEmployeeBeginEdit (obj); \
486         CACHE_REPLACE (member, str); \
487         }
488 
gncEmployeeSetID(GncEmployee * employee,const char * id)489 void gncEmployeeSetID (GncEmployee *employee, const char *id)
490 {
491     if (!employee) return;
492     if (!id) return;
493     SET_STR(employee, employee->id, id);
494     mark_employee (employee);
495     gncEmployeeCommitEdit (employee);
496 }
497 
gncEmployeeSetUsername(GncEmployee * employee,const char * username)498 void gncEmployeeSetUsername (GncEmployee *employee, const char *username)
499 {
500     if (!employee) return;
501     if (!username) return;
502     SET_STR(employee, employee->username, username);
503     mark_employee (employee);
504     gncEmployeeCommitEdit (employee);
505 }
506 
507 /* Employees don't have a name property defined, but
508  * in order to get a consistent interface with other owner types,
509  * this function fakes one by setting the name property of
510  * the employee's address.
511  */
gncEmployeeSetName(GncEmployee * employee,const char * name)512 void gncEmployeeSetName (GncEmployee *employee, const char *name)
513 {
514     if (!employee) return;
515     if (!name) return;
516     gncAddressSetName (gncEmployeeGetAddr (employee), name);
517 }
518 
gncEmployeeSetLanguage(GncEmployee * employee,const char * language)519 void gncEmployeeSetLanguage (GncEmployee *employee, const char *language)
520 {
521     if (!employee) return;
522     if (!language) return;
523     SET_STR(employee, employee->language, language);
524     mark_employee (employee);
525     gncEmployeeCommitEdit (employee);
526 }
527 
gncEmployeeSetAcl(GncEmployee * employee,const char * acl)528 void gncEmployeeSetAcl (GncEmployee *employee, const char *acl)
529 {
530     if (!employee) return;
531     if (!acl) return;
532     SET_STR(employee, employee->acl, acl);
533     mark_employee (employee);
534     gncEmployeeCommitEdit (employee);
535 }
536 
gncEmployeeSetWorkday(GncEmployee * employee,gnc_numeric workday)537 void gncEmployeeSetWorkday (GncEmployee *employee, gnc_numeric workday)
538 {
539     if (!employee) return;
540     if (gnc_numeric_equal (workday, employee->workday)) return;
541     gncEmployeeBeginEdit (employee);
542     employee->workday = workday;
543     mark_employee (employee);
544     gncEmployeeCommitEdit (employee);
545 }
546 
gncEmployeeSetRate(GncEmployee * employee,gnc_numeric rate)547 void gncEmployeeSetRate (GncEmployee *employee, gnc_numeric rate)
548 {
549     if (!employee) return;
550     if (gnc_numeric_equal (rate, employee->rate)) return;
551     gncEmployeeBeginEdit (employee);
552     employee->rate = rate;
553     mark_employee (employee);
554     gncEmployeeCommitEdit (employee);
555 }
556 
gncEmployeeSetCurrency(GncEmployee * employee,gnc_commodity * currency)557 void gncEmployeeSetCurrency (GncEmployee *employee, gnc_commodity *currency)
558 {
559     if (!employee || !currency) return;
560     if (employee->currency &&
561             gnc_commodity_equal (employee->currency, currency))
562         return;
563     gncEmployeeBeginEdit (employee);
564     employee->currency = currency;
565     mark_employee (employee);
566     gncEmployeeCommitEdit (employee);
567 }
568 
gncEmployeeSetActive(GncEmployee * employee,gboolean active)569 void gncEmployeeSetActive (GncEmployee *employee, gboolean active)
570 {
571     if (!employee) return;
572     if (active == employee->active) return;
573     gncEmployeeBeginEdit (employee);
574     employee->active = active;
575     mark_employee (employee);
576     gncEmployeeCommitEdit (employee);
577 }
578 
gncEmployeeSetCCard(GncEmployee * employee,Account * ccard_acc)579 void gncEmployeeSetCCard (GncEmployee *employee, Account* ccard_acc)
580 {
581     if (!employee) return;
582     if (ccard_acc == employee->ccard_acc) return;
583     gncEmployeeBeginEdit (employee);
584     employee->ccard_acc = ccard_acc;
585     mark_employee (employee);
586     gncEmployeeCommitEdit (employee);
587 }
588 
589 void
qofEmployeeSetAddr(GncEmployee * employee,QofInstance * addr_ent)590 qofEmployeeSetAddr (GncEmployee *employee, QofInstance *addr_ent)
591 {
592     GncAddress *addr;
593 
594     if (!employee || !addr_ent)
595     {
596         return;
597     }
598     addr = (GncAddress*)addr_ent;
599     if (addr == employee->addr)
600     {
601         return;
602     }
603     if (employee->addr != NULL)
604     {
605         gncAddressBeginEdit(employee->addr);
606         gncAddressDestroy(employee->addr);
607     }
608     gncEmployeeBeginEdit(employee);
609     employee->addr = addr;
610     mark_employee (employee);
611     gncEmployeeCommitEdit(employee);
612 }
613 
614 /* ============================================================== */
615 /* Get Functions */
gncEmployeeGetID(const GncEmployee * employee)616 const char * gncEmployeeGetID (const GncEmployee *employee)
617 {
618     if (!employee) return NULL;
619     return employee->id;
620 }
621 
gncEmployeeGetUsername(const GncEmployee * employee)622 const char * gncEmployeeGetUsername (const GncEmployee *employee)
623 {
624     if (!employee) return NULL;
625     return employee->username;
626 }
627 
628 /* Employees don't have a name property defined, but
629  * in order to get a consistent interface with other owner types,
630  * this function fakes one by returning the name property of
631  * the employee's address.
632  */
gncEmployeeGetName(const GncEmployee * employee)633 const char * gncEmployeeGetName (const GncEmployee *employee)
634 {
635     if (!employee) return NULL;
636     return gncAddressGetName ( gncEmployeeGetAddr (employee));
637 }
638 
gncEmployeeGetAddr(const GncEmployee * employee)639 GncAddress * gncEmployeeGetAddr (const GncEmployee *employee)
640 {
641     if (!employee) return NULL;
642     return employee->addr;
643 }
644 
gncEmployeeGetLanguage(const GncEmployee * employee)645 const char * gncEmployeeGetLanguage (const GncEmployee *employee)
646 {
647     if (!employee) return NULL;
648     return employee->language;
649 }
650 
gncEmployeeGetAcl(const GncEmployee * employee)651 const char * gncEmployeeGetAcl (const GncEmployee *employee)
652 {
653     if (!employee) return NULL;
654     return employee->acl;
655 }
656 
gncEmployeeGetWorkday(const GncEmployee * employee)657 gnc_numeric gncEmployeeGetWorkday (const GncEmployee *employee)
658 {
659     if (!employee) return gnc_numeric_zero();
660     return employee->workday;
661 }
662 
gncEmployeeGetRate(const GncEmployee * employee)663 gnc_numeric gncEmployeeGetRate (const GncEmployee *employee)
664 {
665     if (!employee) return gnc_numeric_zero();
666     return employee->rate;
667 }
668 
gncEmployeeGetCurrency(const GncEmployee * employee)669 gnc_commodity * gncEmployeeGetCurrency (const GncEmployee *employee)
670 {
671     if (!employee) return NULL;
672     return employee->currency;
673 }
674 
gncEmployeeGetActive(const GncEmployee * employee)675 gboolean gncEmployeeGetActive (const GncEmployee *employee)
676 {
677     if (!employee) return FALSE;
678     return employee->active;
679 }
680 
gncEmployeeGetCCard(const GncEmployee * employee)681 Account * gncEmployeeGetCCard (const GncEmployee *employee)
682 {
683     if (!employee) return NULL;
684     return employee->ccard_acc;
685 }
686 
gncEmployeeIsDirty(const GncEmployee * employee)687 gboolean gncEmployeeIsDirty (const GncEmployee *employee)
688 {
689     if (!employee) return FALSE;
690     return (qof_instance_get_dirty_flag(employee)
691             || gncAddressIsDirty (employee->addr));
692 }
693 
gncEmployeeBeginEdit(GncEmployee * employee)694 void gncEmployeeBeginEdit (GncEmployee *employee)
695 {
696     qof_begin_edit(&employee->inst);
697 }
698 
gncEmployeeOnError(QofInstance * employee,QofBackendError errcode)699 static void gncEmployeeOnError (QofInstance *employee, QofBackendError errcode)
700 {
701     PERR("Employee QofBackend Failure: %d", errcode);
702     gnc_engine_signal_commit_error( errcode );
703 }
704 
gncEmployeeOnDone(QofInstance * inst)705 static void gncEmployeeOnDone (QofInstance *inst)
706 {
707     GncEmployee *employee = (GncEmployee *) inst;
708     gncAddressClearDirty (employee->addr);
709 }
710 
emp_free(QofInstance * inst)711 static void emp_free (QofInstance *inst)
712 {
713     GncEmployee *employee = (GncEmployee *) inst;
714     gncEmployeeFree (employee);
715 }
716 
717 
gncEmployeeCommitEdit(GncEmployee * employee)718 void gncEmployeeCommitEdit (GncEmployee *employee)
719 {
720     if (!qof_commit_edit (QOF_INSTANCE(employee))) return;
721     qof_commit_edit_part2 (&employee->inst, gncEmployeeOnError,
722                            gncEmployeeOnDone, emp_free);
723 }
724 
725 /* ============================================================== */
726 /* Other functions */
727 
gncEmployeeCompare(const GncEmployee * a,const GncEmployee * b)728 int gncEmployeeCompare (const GncEmployee *a, const GncEmployee *b)
729 {
730     if (!a && !b) return 0;
731     if (!a && b) return 1;
732     if (a && !b) return -1;
733 
734     return(strcmp(a->username, b->username));
735 }
736 
gncEmployeeEqual(const GncEmployee * a,const GncEmployee * b)737 gboolean gncEmployeeEqual(const GncEmployee* a, const GncEmployee* b)
738 {
739     if (a == NULL && b == NULL) return TRUE;
740     if (a == NULL || b == NULL ) return FALSE;
741 
742     g_return_val_if_fail(GNC_IS_EMPLOYEE(a), FALSE);
743     g_return_val_if_fail(GNC_IS_EMPLOYEE(b), FALSE);
744 
745     if (g_strcmp0(a->id, b->id) != 0)
746     {
747         PWARN("IDs differ: %s vs %s", a->id, b->id);
748         return FALSE;
749     }
750 
751     if (g_strcmp0(a->username, b->username) != 0)
752     {
753         PWARN("Usernames differ: %s vs %s", a->username, b->username);
754         return FALSE;
755     }
756 
757     if (!gncAddressEqual(a->addr, b->addr))
758     {
759         PWARN("Addresses differ");
760         return FALSE;
761     }
762 
763     if (!gnc_commodity_equal(a->currency, b->currency))
764     {
765         PWARN("Currencies differ");
766         return FALSE;
767     }
768 
769     if (a->active != b->active)
770     {
771         PWARN("Active flags differ");
772         return FALSE;
773     }
774 
775     if (g_strcmp0(a->language, b->language) != 0)
776     {
777         PWARN("Languages differ: %s vs %s", a->language, b->language);
778         return FALSE;
779     }
780 
781     if (g_strcmp0(a->acl, b->acl) != 0)
782     {
783         PWARN("ACLs differ: %s vs %s", a->acl, b->acl);
784         return FALSE;
785     }
786 
787     if (!xaccAccountEqual(a->ccard_acc, b->ccard_acc, TRUE))
788     {
789         PWARN("Accounts differ");
790         return FALSE;
791     }
792 
793     if (!gnc_numeric_equal(a->workday, b->workday))
794     {
795         PWARN("Workdays differ");
796         return FALSE;
797     }
798 
799     if (!gnc_numeric_equal(a->rate, b->rate))
800     {
801         PWARN("Rates differ");
802         return FALSE;
803     }
804 
805     return TRUE;
806 }
807 
808 /* Package-Private functions */
809 
_gncEmployeePrintable(gpointer item)810 static const char * _gncEmployeePrintable (gpointer item)
811 {
812     GncEmployee *v = item;
813     if (!item) return NULL;
814     return gncAddressGetName(v->addr);
815 }
816 
817 /**
818  * Listen for qof events.
819  *
820  * - If the address of an employee has changed, mark the employee as dirty.
821  * - If a lot related to an employee has changed, clear the employee's
822  *   cached balance as it likely has become invalid.
823  *
824  * @param entity Entity for the event
825  * @param event_type Event type
826  * @param user_data User data registered with the handler
827  * @param event_data Event data passed with the event.
828  */
829 static void
empl_handle_qof_events(QofInstance * entity,QofEventId event_type,gpointer user_data,gpointer event_data)830 empl_handle_qof_events (QofInstance *entity, QofEventId event_type,
831                         gpointer user_data, gpointer event_data)
832 {
833 
834     /* Handle address change events */
835     if ((GNC_IS_ADDRESS (entity) &&
836         (event_type & QOF_EVENT_MODIFY) != 0))
837     {
838         if (GNC_IS_EMPLOYEE (event_data))
839         {
840             GncEmployee* empl = GNC_EMPLOYEE (event_data);
841             gncEmployeeBeginEdit (empl);
842             mark_employee (empl);
843             gncEmployeeCommitEdit (empl);
844         }
845         return;
846     }
847 
848     /* Handle lot change events */
849     if (GNC_IS_LOT (entity))
850     {
851         GNCLot *lot = GNC_LOT (entity);
852         GncOwner lot_owner;
853         const GncOwner *end_owner = NULL;
854         GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
855 
856         /* Determine the owner associated with the lot */
857         if (invoice)
858             /* Invoice lots */
859             end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
860         else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
861             /* Pre-payment lots */
862             end_owner = gncOwnerGetEndOwner (&lot_owner);
863 
864         if (gncOwnerGetType (end_owner) == GNC_OWNER_EMPLOYEE)
865         {
866             /* Clear the cached balance */
867             GncEmployee* empl = gncOwnerGetEmployee (end_owner);
868             g_free (empl->balance);
869             empl->balance = NULL;
870         }
871         return;
872     }
873 }
874 
875 static void
destroy_employee_on_book_close(QofInstance * ent,gpointer data)876 destroy_employee_on_book_close(QofInstance *ent, gpointer data)
877 {
878     GncEmployee* e = GNC_EMPLOYEE(ent);
879 
880     gncEmployeeBeginEdit(e);
881     gncEmployeeDestroy(e);
882 }
883 
884 /** Handles book end - frees all employees from the book
885  *
886  * @param book Book being closed
887  */
888 static void
gnc_employee_book_end(QofBook * book)889 gnc_employee_book_end(QofBook* book)
890 {
891     QofCollection *col;
892 
893     col = qof_book_get_collection(book, GNC_ID_EMPLOYEE);
894     qof_collection_foreach(col, destroy_employee_on_book_close, NULL);
895 }
896 
897 static QofObject gncEmployeeDesc =
898 {
899     DI(.interface_version = ) QOF_OBJECT_VERSION,
900     DI(.e_type            = ) _GNC_MOD_NAME,
901     DI(.type_label        = ) "Employee",
902     DI(.create            = ) (gpointer)gncEmployeeCreate,
903     DI(.book_begin        = ) NULL,
904     DI(.book_end          = ) gnc_employee_book_end,
905     DI(.is_dirty          = ) qof_collection_is_dirty,
906     DI(.mark_clean        = ) qof_collection_mark_clean,
907     DI(.foreach           = ) qof_collection_foreach,
908     DI(.printable         = ) _gncEmployeePrintable,
909     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
910 };
911 
gncEmployeeRegister(void)912 gboolean gncEmployeeRegister (void)
913 {
914     static QofParam params[] =
915     {
916         { EMPLOYEE_ID, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetID, (QofSetterFunc)gncEmployeeSetID },
917         {
918             EMPLOYEE_USERNAME, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetUsername,
919             (QofSetterFunc)gncEmployeeSetUsername
920         },
921         {
922             EMPLOYEE_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetName,
923             (QofSetterFunc)gncEmployeeSetName
924         },
925         {
926             EMPLOYEE_LANGUAGE, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetLanguage,
927             (QofSetterFunc)gncEmployeeSetLanguage
928         },
929         { EMPLOYEE_ACL, QOF_TYPE_STRING, (QofAccessFunc)gncEmployeeGetAcl, (QofSetterFunc)gncEmployeeSetAcl },
930         {
931             EMPLOYEE_WORKDAY, QOF_TYPE_NUMERIC, (QofAccessFunc)gncEmployeeGetWorkday,
932             (QofSetterFunc)gncEmployeeSetWorkday
933         },
934         { EMPLOYEE_RATE, QOF_TYPE_NUMERIC, (QofAccessFunc)gncEmployeeGetRate, (QofSetterFunc)gncEmployeeSetRate },
935         { EMPLOYEE_ADDR, GNC_ID_ADDRESS, (QofAccessFunc)gncEmployeeGetAddr, (QofSetterFunc)qofEmployeeSetAddr },
936         { EMPLOYEE_CC,  GNC_ID_ACCOUNT, (QofAccessFunc)gncEmployeeGetCCard, (QofSetterFunc)gncEmployeeSetCCard },
937         { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncEmployeeGetActive, (QofSetterFunc)gncEmployeeSetActive },
938         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
939         { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
940         { NULL },
941     };
942 
943     qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncEmployeeCompare, params);
944 
945     return qof_object_register (&gncEmployeeDesc);
946 }
947 
gncEmployeeNextID(QofBook * book)948 gchar *gncEmployeeNextID (QofBook *book)
949 {
950     return qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
951 }
952 
953 const gnc_numeric*
gncEmployeeGetCachedBalance(GncEmployee * empl)954 gncEmployeeGetCachedBalance (GncEmployee *empl)
955 {
956     return empl->balance;
957 }
958 
gncEmployeeSetCachedBalance(GncEmployee * empl,const gnc_numeric * new_bal)959 void gncEmployeeSetCachedBalance (GncEmployee *empl, const gnc_numeric *new_bal)
960 {
961     if (!new_bal)
962     {
963         if (empl->balance)
964         {
965             g_free (empl->balance);
966             empl->balance = NULL;
967         }
968         return;
969     }
970 
971     if (!empl->balance)
972         empl->balance = g_new0 (gnc_numeric, 1);
973 
974     *empl->balance = *new_bal;
975 }
976