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