1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 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
;
42 da_acc_free(Account
*item
)
44 DB( g_print("da_acc_free\n") );
47 DB( g_print(" => %d, %s\n", item
->key
, item
->name
) );
51 g_free(item
->bankname
);
54 g_queue_free (item
->txn_queue
);
66 DB( g_print("da_acc_malloc\n") );
67 item
= rc_alloc(sizeof(Account
));
68 item
->kcur
= GLOBALS
->kcur
;
69 item
->txn_queue
= g_queue_new ();
77 DB( g_print("da_acc_destroy\n") );
78 g_hash_table_destroy(GLOBALS
->h_acc
);
85 DB( g_print("da_acc_new\n") );
86 GLOBALS
->h_acc
= g_hash_table_new_full(g_int_hash
, g_int_equal
, (GDestroyNotify
)g_free
, (GDestroyNotify
)da_acc_free
);
90 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
96 * Return value: the number of elements
101 return g_hash_table_size(GLOBALS
->h_acc
);
105 static void da_acc_max_key_ghfunc(gpointer key
, Account
*item
, guint32
*max_key
)
107 *max_key
= MAX(*max_key
, item
->key
);
112 * da_acc_get_max_key:
114 * Get the biggest key from the GHashTable
116 * Return value: the biggest key value
120 da_acc_get_max_key(void)
124 g_hash_table_foreach(GLOBALS
->h_acc
, (GHFunc
)da_acc_max_key_ghfunc
, &max_key
);
132 * delete an account from the GHashTable
134 * Return value: TRUE if the key was found and deleted
138 da_acc_remove(guint32 key
)
140 DB( g_print("da_acc_remove %d\n", key
) );
142 return g_hash_table_remove(GLOBALS
->h_acc
, &key
);
148 * insert an account into the GHashTable
150 * Return value: TRUE if inserted
154 da_acc_insert(Account
*item
)
158 DB( g_print("da_acc_insert\n") );
160 new_key
= g_new0(guint32
, 1);
161 *new_key
= item
->key
;
162 g_hash_table_insert(GLOBALS
->h_acc
, new_key
, item
);
164 GValue item_val
= G_VALUE_INIT
;
165 ext_hook("account_inserted", EXT_ACCOUNT(&item_val
, item
), NULL
);
174 * insert an account into the GHashTable
176 * Return value: TRUE if inserted
180 da_acc_append(Account
*item
)
184 DB( g_print("da_acc_append\n") );
186 existitem
= da_acc_get_by_name( item
->name
);
187 if( existitem
== NULL
)
189 item
->key
= da_acc_get_max_key() + 1;
190 item
->pos
= da_acc_length() + 1;
193 GValue item_val
= G_VALUE_INIT
;
194 ext_hook("account_inserted", EXT_ACCOUNT(&item_val
, item
), NULL
);
199 DB( g_print(" -> %s already exist: %d\n", item
->name
, item
->key
) );
205 static gboolean
da_acc_name_grfunc(gpointer key
, Account
*item
, gchar
*name
)
207 if( name
&& item
->name
)
209 if(!strcasecmp(name
, item
->name
))
216 * da_acc_get_by_name:
218 * Get an account structure by its name
220 * Return value: Account * or NULL if not found
224 da_acc_get_by_name(gchar
*rawname
)
226 Account
*retval
= NULL
;
229 DB( g_print("da_acc_get_by_name\n") );
233 stripname
= g_strdup(rawname
);
234 g_strstrip(stripname
);
235 if( strlen(stripname
) > 0 )
236 retval
= g_hash_table_find(GLOBALS
->h_acc
, (GHRFunc
)da_acc_name_grfunc
, stripname
);
248 * Get an account structure by key
250 * Return value: Account * or NULL if not found
254 da_acc_get(guint32 key
)
256 //DB( g_print("da_acc_get\n") );
258 return g_hash_table_lookup(GLOBALS
->h_acc
, &key
);
262 void da_acc_consistency(Account
*item
)
264 g_strstrip(item
->name
);
268 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
272 da_acc_debug_list_ghfunc(gpointer key
, gpointer value
, gpointer user_data
)
275 Account
*item
= value
;
277 DB( g_print(" %d :: %s\n", *id
, item
->name
) );
282 da_acc_debug_list(void)
285 DB( g_print("\n** debug **\n") );
287 g_hash_table_foreach(GLOBALS
->h_acc
, da_acc_debug_list_ghfunc
, NULL
);
289 DB( g_print("\n** end debug **\n") );
297 account_glist_name_compare_func(Account
*a
, Account
*b
)
299 return hb_string_utf8_compare(a
->name
, b
->name
);
304 account_glist_key_compare_func(Account
*a
, Account
*b
)
306 return a
->key
- b
->key
;
310 GList
*account_glist_sorted(gint column
)
312 GList
*list
= g_hash_table_get_values(GLOBALS
->h_acc
);
315 return g_list_sort(list
, (GCompareFunc
)account_glist_key_compare_func
);
317 return g_list_sort(list
, (GCompareFunc
)account_glist_name_compare_func
);
322 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
330 * controls if an account is used by any archive or transaction
332 * Return value: TRUE if used, FALSE, otherwise
335 account_is_used(guint32 key
)
339 GList
*lst_acc
, *lnk_acc
;
346 acc
= da_acc_get(key
);
347 if( g_queue_get_length(acc
->txn_queue
) > 0 )
353 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
354 lnk_acc
= g_list_first(lst_acc
);
355 while (lnk_acc
!= NULL
)
357 Account
*acc
= lnk_acc
->data
;
361 lnk_txn
= g_queue_peek_head_link(acc
->txn_queue
);
362 while (lnk_txn
!= NULL
)
364 Transaction
*entry
= lnk_txn
->data
;
366 if( key
== entry
->kxferacc
)
372 lnk_txn
= g_list_next(lnk_txn
);
375 lnk_acc
= g_list_next(lnk_acc
);
378 list
= g_list_first(GLOBALS
->arc_list
);
381 Archive
*entry
= list
->data
;
383 if( key
== entry
->kacc
|| key
== entry
->kxferacc
)
389 list
= g_list_next(list
);
393 g_list_free(lst_acc
);
400 account_get_stripname(gchar
*name
)
402 gchar
*stripname
= g_strdup(name
);
403 g_strstrip(stripname
);
410 account_exists(gchar
*name
)
413 gchar
*stripname
= account_get_stripname(name
);
415 existitem
= da_acc_get_by_name(stripname
);
418 return existitem
== NULL
? FALSE
: TRUE
;
423 account_rename(Account
*item
, gchar
*newname
)
426 gchar
*stripname
= account_get_stripname(newname
);
428 if( strlen(stripname
) > 0 )
430 existitem
= da_acc_get_by_name(stripname
);
431 if( existitem
== NULL
)
434 item
->name
= g_strdup(stripname
);
446 * change the account currency
447 * change every txn to currency
448 * ensure dst xfer transaction account will be set to same currency
450 void account_set_currency(Account
*acc
, guint32 kcur
)
457 DB( g_print("\n[account] set currency\n") );
459 if(acc
->kcur
== kcur
)
461 DB( g_print(" - already ok, return\n") );
465 DB( g_print(" - set for '%s'\n", acc
->name
) );
467 maxkey
= da_acc_get_max_key () + 1;
468 xfer_list
= g_malloc0(sizeof(gboolean
) * maxkey
);
469 DB( g_print(" - alloc for %d account\n", da_acc_length() ) );
471 list
= g_queue_peek_head_link(acc
->txn_queue
);
474 Transaction
*txn
= list
->data
;
477 if( (txn
->paymode
== PAYMODE_INTXFER
) && (txn
->kxferacc
> 0) && (txn
->kxfer
> 0) )
479 xfer_list
[txn
->kxferacc
] = TRUE
;
481 list
= g_list_next(list
);
485 DB( g_print(" - '%s'\n", acc
->name
) );
487 for(i
=1;i
<maxkey
;i
++)
489 DB( g_print(" - %d '%d'\n", i
, xfer_list
[i
]) );
490 if( xfer_list
[i
] == TRUE
)
492 dstacc
= da_acc_get(i
);
493 account_set_currency(dstacc
, kcur
);
503 * private function to sub transaction amount from account balances
505 static void account_balances_sub_internal(Account
*acc
, Transaction
*trn
)
507 acc
->bal_future
-= trn
->amount
;
509 if(trn
->date
<= GLOBALS
->today
)
510 acc
->bal_today
-= trn
->amount
;
512 if(trn
->status
== TXN_STATUS_RECONCILED
)
513 //if(trn->flags & OF_VALID)
514 acc
->bal_bank
-= trn
->amount
;
518 * private function to add transaction amount from account balances
520 static void account_balances_add_internal(Account
*acc
, Transaction
*trn
)
522 acc
->bal_future
+= trn
->amount
;
524 if(trn
->date
<= GLOBALS
->today
)
525 acc
->bal_today
+= trn
->amount
;
527 if(trn
->status
== TXN_STATUS_RECONCILED
)
528 //if(trn->flags & OF_VALID)
529 acc
->bal_bank
+= trn
->amount
;
534 * public function to sub transaction amount from account balances
536 gboolean
account_balances_sub(Transaction
*trn
)
539 if(!(trn
->status
== TXN_STATUS_REMIND
))
540 //if(!(trn->flags & OF_REMIND))
542 Account
*acc
= da_acc_get(trn
->kacc
);
543 if(acc
== NULL
) return FALSE
;
544 account_balances_sub_internal(acc
, trn
);
552 * public function to add transaction amount from account balances
554 gboolean
account_balances_add(Transaction
*trn
)
556 if(!(trn
->status
== TXN_STATUS_REMIND
))
557 //if(!(trn->flags & OF_REMIND))
559 Account
*acc
= da_acc_get(trn
->kacc
);
560 if(acc
== NULL
) return FALSE
;
561 account_balances_add_internal(acc
, trn
);
568 //todo: optim called 2 times from dsp_mainwindow
569 void account_compute_balances(void)
571 GList
*lst_acc
, *lnk_acc
;
574 DB( g_print("\naccount_compute_balances start\n") );
576 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
577 lnk_acc
= g_list_first(lst_acc
);
578 while (lnk_acc
!= NULL
)
580 Account
*acc
= lnk_acc
->data
;
582 /* set initial amount */
583 acc
->bal_bank
= acc
->initial
;
584 acc
->bal_today
= acc
->initial
;
585 acc
->bal_future
= acc
->initial
;
588 lnk_txn
= g_queue_peek_head_link(acc
->txn_queue
);
589 while (lnk_txn
!= NULL
)
591 Transaction
*txn
= lnk_txn
->data
;
593 if(!(txn
->status
== TXN_STATUS_REMIND
))
595 account_balances_add_internal(acc
, txn
);
597 lnk_txn
= g_list_next(lnk_txn
);
600 lnk_acc
= g_list_next(lnk_acc
);
602 g_list_free(lst_acc
);
604 DB( g_print("\naccount_compute_balances end\n") );
609 void account_convert_euro(Account
*acc
)
613 lnk_txn
= g_queue_peek_head_link(acc
->txn_queue
);
614 while (lnk_txn
!= NULL
)
616 Transaction
*txn
= lnk_txn
->data
;
617 gdouble oldamount
= txn
->amount
;
619 txn
->amount
= hb_amount_to_euro(oldamount
);
620 DB( g_print("%10.6f => %10.6f, %s\n", oldamount
, txn
->amount
, txn
->memo
) );
621 //todo: sync child xfer
622 lnk_txn
= g_list_next(lnk_txn
);
625 acc
->initial
= hb_amount_to_euro(acc
->initial
);
626 acc
->warning
= hb_amount_to_euro(acc
->warning
);
627 acc
->minimum
= hb_amount_to_euro(acc
->minimum
);