1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 Maxime DOYEN
4 * This file is part of HomeBank.
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.
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.
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/>.
21 #include "hb-account.h"
26 /****************************************************************************/
28 /****************************************************************************/
37 /* our global datas */
38 extern struct HomeBank
*GLOBALS
;
45 da_acc_clone(Account
*src_item
)
47 Account
*new_item
= rc_dup(src_item
, sizeof(Account
));
49 DB( g_print("da_acc_clone\n") );
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
);
62 da_acc_free(Account
*item
)
64 DB( g_print("da_acc_free\n") );
67 DB( g_print(" => %d, %s\n", item
->key
, item
->name
) );
69 g_free(item
->imp_name
);
72 g_free(item
->bankname
);
81 DB( g_print("da_acc_malloc\n") );
82 return rc_alloc(sizeof(Account
));
89 DB( g_print("da_acc_destroy\n") );
90 g_hash_table_destroy(GLOBALS
->h_acc
);
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
);
102 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
103 static void da_acc_max_key_ghfunc(gpointer key
, Account
*item
, guint32
*max_key
)
105 *max_key
= MAX(*max_key
, item
->key
);
108 static gboolean
da_acc_name_grfunc(gpointer key
, Account
*item
, gchar
*name
)
110 if( name
&& item
->name
)
112 if(!strcasecmp(name
, item
->name
))
118 static gboolean
da_acc_imp_name_grfunc(gpointer key
, Account
*item
, gchar
*name
)
120 if( name
&& item
->imp_name
)
122 if(!strcasecmp(name
, item
->imp_name
))
131 * Return value: the number of elements
136 return g_hash_table_size(GLOBALS
->h_acc
);
143 * remove an account from the GHashTable
145 * Return value: TRUE if the key was found and removed
149 da_acc_remove(guint32 key
)
151 DB( g_print("da_acc_remove %d\n", key
) );
153 return g_hash_table_remove(GLOBALS
->h_acc
, &key
);
159 * insert an account into the GHashTable
161 * Return value: TRUE if inserted
165 da_acc_insert(Account
*item
)
169 DB( g_print("da_acc_insert\n") );
171 new_key
= g_new0(guint32
, 1);
172 *new_key
= item
->key
;
173 g_hash_table_insert(GLOBALS
->h_acc
, new_key
, item
);
175 GValue item_val
= G_VALUE_INIT
;
176 ext_hook("account_inserted", EXT_ACCOUNT(&item_val
, item
), NULL
);
185 * insert an account into the GHashTable
187 * Return value: TRUE if inserted
191 da_acc_append(Account
*item
)
196 DB( g_print("da_acc_append\n") );
198 /* ensure no duplicate */
199 g_strstrip(item
->name
);
200 if(item
->name
!= NULL
)
202 existitem
= da_acc_get_by_name( item
->name
);
203 if( existitem
== NULL
)
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;
210 DB( g_print(" -> insert id: %d\n", *new_key
) );
212 g_hash_table_insert(GLOBALS
->h_acc
, new_key
, item
);
214 GValue item_val
= G_VALUE_INIT
;
215 ext_hook("account_inserted", EXT_ACCOUNT(&item_val
, item
), NULL
);
221 DB( g_print(" -> %s already exist: %d\n", item
->name
, item
->key
) );
227 * da_acc_get_max_key:
229 * Get the biggest key from the GHashTable
231 * Return value: the biggest key value
235 da_acc_get_max_key(void)
239 g_hash_table_foreach(GLOBALS
->h_acc
, (GHFunc
)da_acc_max_key_ghfunc
, &max_key
);
247 * da_acc_get_by_name:
249 * Get an account structure by its name
251 * Return value: Account * or NULL if not found
255 da_acc_get_by_name(gchar
*name
)
257 DB( g_print("da_acc_get_by_name\n") );
259 return g_hash_table_find(GLOBALS
->h_acc
, (GHRFunc
)da_acc_name_grfunc
, name
);
263 da_acc_get_by_imp_name(gchar
*name
)
265 DB( g_print("da_acc_get_by_imp_name\n") );
267 return g_hash_table_find(GLOBALS
->h_acc
, (GHRFunc
)da_acc_imp_name_grfunc
, name
);
274 * Get an account structure by key
276 * Return value: Account * or NULL if not found
280 da_acc_get(guint32 key
)
282 //DB( g_print("da_acc_get\n") );
284 return g_hash_table_lookup(GLOBALS
->h_acc
, &key
);
288 void da_acc_consistency(Account
*item
)
290 g_strstrip(item
->name
);
294 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
298 da_acc_debug_list_ghfunc(gpointer key
, gpointer value
, gpointer user_data
)
301 Account
*item
= value
;
303 DB( g_print(" %d :: %s\n", *id
, item
->name
) );
308 da_acc_debug_list(void)
311 DB( g_print("\n** debug **\n") );
313 g_hash_table_foreach(GLOBALS
->h_acc
, da_acc_debug_list_ghfunc
, NULL
);
315 DB( g_print("\n** end debug **\n") );
323 account_glist_name_compare_func(Account
*a
, Account
*b
)
325 return hb_string_utf8_compare(a
->name
, b
->name
);
330 account_glist_key_compare_func(Account
*a
, Account
*b
)
332 return a
->key
- b
->key
;
336 GList
*account_glist_sorted(gint column
)
338 GList
*list
= g_hash_table_get_values(GLOBALS
->h_acc
);
341 return g_list_sort(list
, (GCompareFunc
)account_glist_key_compare_func
);
343 return g_list_sort(list
, (GCompareFunc
)account_glist_name_compare_func
);
348 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
356 * controls if an account is used by any archive or transaction
358 * Return value: TRUE if used, FALSE, otherwise
361 account_is_used(guint32 key
)
365 list
= g_list_first(GLOBALS
->ope_list
);
368 Transaction
*entry
= list
->data
;
369 if( key
== entry
->kacc
|| key
== entry
->kxferacc
)
371 list
= g_list_next(list
);
374 list
= g_list_first(GLOBALS
->arc_list
);
377 Archive
*entry
= list
->data
;
378 if( key
== entry
->kacc
|| key
== entry
->kxferacc
)
380 list
= g_list_next(list
);
387 account_move(guint32 key1
, guint32 key2
)
391 list
= g_list_first(GLOBALS
->ope_list
);
394 Transaction
*entry
= list
->data
;
395 if(entry
->kacc
== key1
)
397 if(entry
->kxferacc
== key1
)
398 entry
->kxferacc
= key2
;
399 list
= g_list_next(list
);
402 list
= g_list_first(GLOBALS
->arc_list
);
405 Archive
*entry
= list
->data
;
406 if(entry
->kacc
== key1
)
408 if(entry
->kxferacc
== key1
)
409 entry
->kxferacc
= key2
;
410 list
= g_list_next(list
);
415 account_get_stripname(gchar
*name
)
417 gchar
*stripname
= g_strdup(name
);
418 g_strstrip(stripname
);
425 account_exists(gchar
*name
)
428 gchar
*stripname
= account_get_stripname(name
);
430 existitem
= da_acc_get_by_name(stripname
);
433 return existitem
== NULL
? FALSE
: TRUE
;
438 account_rename(Account
*item
, gchar
*newname
)
441 gchar
*stripname
= account_get_stripname(newname
);
443 existitem
= da_acc_get_by_name(stripname
);
444 if( existitem
== NULL
)
447 item
->name
= g_strdup(stripname
);
456 /* when we change the currency of an account, we must ensure
457 * xfer transaction account will be set to same currency
460 void account_set_currency(Account *item, guint32 kcur)
465 if(item->kcur != kcur)
469 list = g_list_first(GLOBALS->ope_list);
472 Transaction *entry = list->data;
473 if(entry->paymode == PAYMODE_INTXFER)
475 if(entry->kacc == item->key)
477 // change target account
478 acc = da_acc_get (entry->kxferacc);
481 if(entry->kxferacc == item->key)
483 // change source account
484 acc = da_acc_get (entry->kacc);
489 list = g_list_next(list);
499 * private function to sub transaction amount from account balances
501 static void account_balances_sub_internal(Account
*acc
, Transaction
*trn
)
503 acc
->bal_future
-= trn
->amount
;
505 if(trn
->date
<= GLOBALS
->today
)
506 acc
->bal_today
-= trn
->amount
;
508 if(trn
->flags
& OF_VALID
)
509 acc
->bal_bank
-= trn
->amount
;
513 * private function to add transaction amount from account balances
515 static void account_balances_add_internal(Account
*acc
, Transaction
*trn
)
517 acc
->bal_future
+= trn
->amount
;
519 if(trn
->date
<= GLOBALS
->today
)
520 acc
->bal_today
+= trn
->amount
;
522 if(trn
->flags
& OF_VALID
)
523 acc
->bal_bank
+= trn
->amount
;
528 * public function to sub transaction amount from account balances
530 gboolean
account_balances_sub(Transaction
*trn
)
532 if(!(trn
->flags
& OF_REMIND
))
534 Account
*acc
= da_acc_get(trn
->kacc
);
535 if(acc
== NULL
) return FALSE
;
536 account_balances_sub_internal(acc
, trn
);
544 * public function to add transaction amount from account balances
546 gboolean
account_balances_add(Transaction
*trn
)
548 if(!(trn
->flags
& OF_REMIND
))
550 Account
*acc
= da_acc_get(trn
->kacc
);
551 if(acc
== NULL
) return FALSE
;
552 account_balances_add_internal(acc
, trn
);
563 void account_compute_balances(void)
569 DB( g_print("\naccount_compute_balances start\n") );
571 /* set initial amount */
572 lacc
= list
= g_hash_table_get_values(GLOBALS
->h_acc
);
576 acc
->bal_bank
= acc
->initial
;
577 acc
->bal_today
= acc
->initial
;
578 acc
->bal_future
= acc
->initial
;
579 list
= g_list_next(list
);
584 /* compute every transaction */
585 list
= g_list_first(GLOBALS
->ope_list
);
590 if(!(trn
->flags
& OF_REMIND
))
592 account_balances_add(trn
);
594 list
= g_list_next(list
);
597 DB( g_print("\naccount_compute_balances end\n") );