]> Dogcows Code - chaz/homebank/blob - src/hb-account.c
add plugin engine (supports C and Perl plugins)
[chaz/homebank] / src / hb-account.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "homebank.h"
21 #include "hb-account.h"
22
23 #include "ext.h"
24 #include "refcount.h"
25
26 /****************************************************************************/
27 /* Debug macros */
28 /****************************************************************************/
29 #define MYDEBUG 0
30
31 #if MYDEBUG
32 #define DB(x) (x);
33 #else
34 #define DB(x);
35 #endif
36
37 /* our global datas */
38 extern struct HomeBank *GLOBALS;
39
40
41
42
43
44 Account *
45 da_acc_clone(Account *src_item)
46 {
47 Account *new_item = rc_dup(src_item, sizeof(Account));
48
49 DB( g_print("da_acc_clone\n") );
50 if(new_item)
51 {
52 //duplicate the string
53 new_item->name = g_strdup(src_item->name);
54 new_item->number = g_strdup(src_item->number);
55 new_item->bankname = g_strdup(src_item->bankname);
56 }
57 return new_item;
58 }
59
60
61 void
62 da_acc_free(Account *item)
63 {
64 DB( g_print("da_acc_free\n") );
65 if(rc_unref(item))
66 {
67 DB( g_print(" => %d, %s\n", item->key, item->name) );
68
69 g_free(item->imp_name);
70 g_free(item->name);
71 g_free(item->number);
72 g_free(item->bankname);
73 rc_free(item);
74 }
75 }
76
77
78 Account *
79 da_acc_malloc(void)
80 {
81 DB( g_print("da_acc_malloc\n") );
82 return rc_alloc(sizeof(Account));
83 }
84
85
86 void
87 da_acc_destroy(void)
88 {
89 DB( g_print("da_acc_destroy\n") );
90 g_hash_table_destroy(GLOBALS->h_acc);
91 }
92
93
94 void
95 da_acc_new(void)
96 {
97 DB( g_print("da_acc_new\n") );
98 GLOBALS->h_acc = g_hash_table_new_full(g_int_hash, g_int_equal, (GDestroyNotify)g_free, (GDestroyNotify)da_acc_free);
99 }
100
101
102 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
103 static void da_acc_max_key_ghfunc(gpointer key, Account *item, guint32 *max_key)
104 {
105 *max_key = MAX(*max_key, item->key);
106 }
107
108 static gboolean da_acc_name_grfunc(gpointer key, Account *item, gchar *name)
109 {
110 if( name && item->name )
111 {
112 if(!strcasecmp(name, item->name))
113 return TRUE;
114 }
115 return FALSE;
116 }
117
118 static gboolean da_acc_imp_name_grfunc(gpointer key, Account *item, gchar *name)
119 {
120 if( name && item->imp_name )
121 {
122 if(!strcasecmp(name, item->imp_name))
123 return TRUE;
124 }
125 return FALSE;
126 }
127
128 /**
129 * da_acc_length:
130 *
131 * Return value: the number of elements
132 */
133 guint
134 da_acc_length(void)
135 {
136 return g_hash_table_size(GLOBALS->h_acc);
137 }
138
139
140 /**
141 * da_acc_remove:
142 *
143 * remove an account from the GHashTable
144 *
145 * Return value: TRUE if the key was found and removed
146 *
147 */
148 gboolean
149 da_acc_remove(guint32 key)
150 {
151 DB( g_print("da_acc_remove %d\n", key) );
152
153 return g_hash_table_remove(GLOBALS->h_acc, &key);
154 }
155
156 /**
157 * da_acc_insert:
158 *
159 * insert an account into the GHashTable
160 *
161 * Return value: TRUE if inserted
162 *
163 */
164 gboolean
165 da_acc_insert(Account *item)
166 {
167 guint32 *new_key;
168
169 DB( g_print("da_acc_insert\n") );
170
171 new_key = g_new0(guint32, 1);
172 *new_key = item->key;
173 g_hash_table_insert(GLOBALS->h_acc, new_key, item);
174
175 GValue item_val = G_VALUE_INIT;
176 ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
177
178 return TRUE;
179 }
180
181
182 /**
183 * da_acc_append:
184 *
185 * insert an account into the GHashTable
186 *
187 * Return value: TRUE if inserted
188 *
189 */
190 gboolean
191 da_acc_append(Account *item)
192 {
193 Account *existitem;
194 guint32 *new_key;
195
196 DB( g_print("da_acc_append\n") );
197
198 /* ensure no duplicate */
199 g_strstrip(item->name);
200 if(item->name != NULL)
201 {
202 existitem = da_acc_get_by_name( item->name );
203 if( existitem == NULL )
204 {
205 new_key = g_new0(guint32, 1);
206 *new_key = da_acc_get_max_key() + 1;
207 item->key = *new_key;
208 item->pos = da_acc_length() + 1;
209
210 DB( g_print(" -> insert id: %d\n", *new_key) );
211
212 g_hash_table_insert(GLOBALS->h_acc, new_key, item);
213
214 GValue item_val = G_VALUE_INIT;
215 ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
216
217 return TRUE;
218 }
219 }
220
221 DB( g_print(" -> %s already exist: %d\n", item->name, item->key) );
222
223 return FALSE;
224 }
225
226 /**
227 * da_acc_get_max_key:
228 *
229 * Get the biggest key from the GHashTable
230 *
231 * Return value: the biggest key value
232 *
233 */
234 guint32
235 da_acc_get_max_key(void)
236 {
237 guint32 max_key = 0;
238
239 g_hash_table_foreach(GLOBALS->h_acc, (GHFunc)da_acc_max_key_ghfunc, &max_key);
240 return max_key;
241 }
242
243
244
245
246 /**
247 * da_acc_get_by_name:
248 *
249 * Get an account structure by its name
250 *
251 * Return value: Account * or NULL if not found
252 *
253 */
254 Account *
255 da_acc_get_by_name(gchar *name)
256 {
257 DB( g_print("da_acc_get_by_name\n") );
258
259 return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_name_grfunc, name);
260 }
261
262 Account *
263 da_acc_get_by_imp_name(gchar *name)
264 {
265 DB( g_print("da_acc_get_by_imp_name\n") );
266
267 return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_imp_name_grfunc, name);
268 }
269
270
271 /**
272 * da_acc_get:
273 *
274 * Get an account structure by key
275 *
276 * Return value: Account * or NULL if not found
277 *
278 */
279 Account *
280 da_acc_get(guint32 key)
281 {
282 //DB( g_print("da_acc_get\n") );
283
284 return g_hash_table_lookup(GLOBALS->h_acc, &key);
285 }
286
287
288 void da_acc_consistency(Account *item)
289 {
290 g_strstrip(item->name);
291 }
292
293
294 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
295 #if MYDEBUG
296
297 static void
298 da_acc_debug_list_ghfunc(gpointer key, gpointer value, gpointer user_data)
299 {
300 guint32 *id = key;
301 Account *item = value;
302
303 DB( g_print(" %d :: %s\n", *id, item->name) );
304
305 }
306
307 static void
308 da_acc_debug_list(void)
309 {
310
311 DB( g_print("\n** debug **\n") );
312
313 g_hash_table_foreach(GLOBALS->h_acc, da_acc_debug_list_ghfunc, NULL);
314
315 DB( g_print("\n** end debug **\n") );
316
317 }
318
319 #endif
320
321
322 static gint
323 account_glist_name_compare_func(Account *a, Account *b)
324 {
325 return hb_string_utf8_compare(a->name, b->name);
326 }
327
328
329 static gint
330 account_glist_key_compare_func(Account *a, Account *b)
331 {
332 return a->key - b->key;
333 }
334
335
336 GList *account_glist_sorted(gint column)
337 {
338 GList *list = g_hash_table_get_values(GLOBALS->h_acc);
339
340 if(column == 0)
341 return g_list_sort(list, (GCompareFunc)account_glist_key_compare_func);
342 else
343 return g_list_sort(list, (GCompareFunc)account_glist_name_compare_func);
344 }
345
346
347
348 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
349
350
351
352
353 /**
354 * account_is_used:
355 *
356 * controls if an account is used by any archive or transaction
357 *
358 * Return value: TRUE if used, FALSE, otherwise
359 */
360 gboolean
361 account_is_used(guint32 key)
362 {
363 GList *list;
364
365 list = g_list_first(GLOBALS->ope_list);
366 while (list != NULL)
367 {
368 Transaction *entry = list->data;
369 if( key == entry->kacc || key == entry->kxferacc)
370 return TRUE;
371 list = g_list_next(list);
372 }
373
374 list = g_list_first(GLOBALS->arc_list);
375 while (list != NULL)
376 {
377 Archive *entry = list->data;
378 if( key == entry->kacc || key == entry->kxferacc)
379 return TRUE;
380 list = g_list_next(list);
381 }
382
383 return FALSE;
384 }
385
386 void
387 account_move(guint32 key1, guint32 key2)
388 {
389 GList *list;
390
391 list = g_list_first(GLOBALS->ope_list);
392 while (list != NULL)
393 {
394 Transaction *entry = list->data;
395 if(entry->kacc == key1)
396 entry->kacc = key2;
397 if(entry->kxferacc == key1)
398 entry->kxferacc = key2;
399 list = g_list_next(list);
400 }
401
402 list = g_list_first(GLOBALS->arc_list);
403 while (list != NULL)
404 {
405 Archive *entry = list->data;
406 if(entry->kacc == key1)
407 entry->kacc = key2;
408 if(entry->kxferacc == key1)
409 entry->kxferacc = key2;
410 list = g_list_next(list);
411 }
412 }
413
414 static gchar *
415 account_get_stripname(gchar *name)
416 {
417 gchar *stripname = g_strdup(name);
418 g_strstrip(stripname);
419
420 return stripname;
421 }
422
423
424 gboolean
425 account_exists(gchar *name)
426 {
427 Account *existitem;
428 gchar *stripname = account_get_stripname(name);
429
430 existitem = da_acc_get_by_name(stripname);
431 g_free(stripname);
432
433 return existitem == NULL ? FALSE : TRUE;
434 }
435
436
437 gboolean
438 account_rename(Account *item, gchar *newname)
439 {
440 Account *existitem;
441 gchar *stripname = account_get_stripname(newname);
442
443 existitem = da_acc_get_by_name(stripname);
444 if( existitem == NULL )
445 {
446 g_free(item->name);
447 item->name = g_strdup(stripname);
448 return TRUE;
449 }
450
451 g_free(stripname);
452
453 return FALSE;
454 }
455
456 /* when we change the currency of an account, we must ensure
457 * xfer transaction account will be set to same currency
458 */
459 /*
460 void account_set_currency(Account *item, guint32 kcur)
461 {
462 GList *list;
463 Account *acc;
464
465 if(item->kcur != kcur)
466 {
467 item->kcur = kcur;
468
469 list = g_list_first(GLOBALS->ope_list);
470 while (list != NULL)
471 {
472 Transaction *entry = list->data;
473 if(entry->paymode == PAYMODE_INTXFER)
474 {
475 if(entry->kacc == item->key)
476 {
477 // change target account
478 acc = da_acc_get (entry->kxferacc);
479 acc->kcur = kcur;
480 }
481 if(entry->kxferacc == item->key)
482 {
483 // change source account
484 acc = da_acc_get (entry->kacc);
485 acc->kcur = kcur;
486 }
487 }
488
489 list = g_list_next(list);
490 }
491 }
492
493 }
494 */
495
496
497
498 /**
499 * private function to sub transaction amount from account balances
500 */
501 static void account_balances_sub_internal(Account *acc, Transaction *trn)
502 {
503 acc->bal_future -= trn->amount;
504
505 if(trn->date <= GLOBALS->today)
506 acc->bal_today -= trn->amount;
507
508 if(trn->flags & OF_VALID)
509 acc->bal_bank -= trn->amount;
510 }
511
512 /**
513 * private function to add transaction amount from account balances
514 */
515 static void account_balances_add_internal(Account *acc, Transaction *trn)
516 {
517 acc->bal_future += trn->amount;
518
519 if(trn->date <= GLOBALS->today)
520 acc->bal_today += trn->amount;
521
522 if(trn->flags & OF_VALID)
523 acc->bal_bank += trn->amount;
524 }
525
526
527 /**
528 * public function to sub transaction amount from account balances
529 */
530 gboolean account_balances_sub(Transaction *trn)
531 {
532 if(!(trn->flags & OF_REMIND))
533 {
534 Account *acc = da_acc_get(trn->kacc);
535 if(acc == NULL) return FALSE;
536 account_balances_sub_internal(acc, trn);
537 return TRUE;
538 }
539 return FALSE;
540 }
541
542
543 /**
544 * public function to add transaction amount from account balances
545 */
546 gboolean account_balances_add(Transaction *trn)
547 {
548 if(!(trn->flags & OF_REMIND))
549 {
550 Account *acc = da_acc_get(trn->kacc);
551 if(acc == NULL) return FALSE;
552 account_balances_add_internal(acc, trn);
553 return TRUE;
554 }
555 return FALSE;
556 }
557
558
559
560
561
562
563 void account_compute_balances(void)
564 {
565 GList *lacc, *list;
566 Account *acc;
567 Transaction *trn;
568
569 DB( g_print("\naccount_compute_balances start\n") );
570
571 /* set initial amount */
572 lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
573 while (list != NULL)
574 {
575 acc = list->data;
576 acc->bal_bank = acc->initial;
577 acc->bal_today = acc->initial;
578 acc->bal_future = acc->initial;
579 list = g_list_next(list);
580 }
581 g_list_free(lacc);
582
583
584 /* compute every transaction */
585 list = g_list_first(GLOBALS->ope_list);
586 while (list != NULL)
587 {
588 trn = list->data;
589
590 if(!(trn->flags & OF_REMIND))
591 {
592 account_balances_add(trn);
593 }
594 list = g_list_next(list);
595 }
596
597 DB( g_print("\naccount_compute_balances end\n") );
598
599 }
600
601
602
603
604
This page took 0.058032 seconds and 4 git commands to generate.