00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026
00027 #include <glib.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030
00031 #include "AccountP.h"
00032 #include "Group.h"
00033 #include "GroupP.h"
00034 #include "TransactionP.h"
00035 #include "gnc-date.h"
00036 #include "gnc-engine.h"
00037 #include "gnc-engine-util.h"
00038 #include "gnc-event.h"
00039 #include "gnc-lot.h"
00040 #include "gnc-lot-p.h"
00041 #include "gnc-pricedb.h"
00042 #include "gnc-trace.h"
00043 #include "kvp_frame.h"
00044 #include "kvp-util.h"
00045 #include "messages.h"
00046 #include "policy.h"
00047
00048 #include "qofbackend.h"
00049 #include "qof-be-utils.h"
00050 #include "qofbook.h"
00051 #include "qofquery.h"
00052 #include "qofclass.h"
00053 #include "qofid-p.h"
00054 #include "qofinstance-p.h"
00055 #include "qofobject.h"
00056
00057 static short module = MOD_ACCOUNT;
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static void xaccAccountBringUpToDate (Account *);
00068
00069
00070
00071
00072 G_INLINE_FUNC void mark_account (Account *account);
00073 G_INLINE_FUNC void
00074 mark_account (Account *account)
00075 {
00076 if (account->parent) account->parent->saved = FALSE;
00077 account->inst.dirty = TRUE;
00078 }
00079
00080
00081
00082
00083 static void
00084 xaccInitAccount (Account * acc, QofBook *book)
00085 {
00086 ENTER ("book=%p\n", book);
00087 qof_instance_init (&acc->inst, GNC_ID_ACCOUNT, book);
00088
00089 acc->parent = NULL;
00090 acc->children = NULL;
00091
00092 acc->balance = gnc_numeric_zero();
00093 acc->cleared_balance = gnc_numeric_zero();
00094 acc->reconciled_balance = gnc_numeric_zero();
00095
00096 acc->starting_balance = gnc_numeric_zero();
00097 acc->starting_cleared_balance = gnc_numeric_zero();
00098 acc->starting_reconciled_balance = gnc_numeric_zero();
00099
00100 acc->type = NO_TYPE;
00101
00102 acc->accountName = g_strdup("");
00103 acc->accountCode = g_strdup("");
00104 acc->description = g_strdup("");
00105
00106 acc->idata = 0;
00107
00108 acc->commodity = NULL;
00109 acc->commodity_scu = 0;
00110 acc->non_standard_scu = FALSE;
00111
00112 acc->splits = NULL;
00113 acc->lots = NULL;
00114 acc->policy = xaccGetFIFOPolicy();
00115
00116 acc->version = 0;
00117 acc->version_check = 0;
00118 acc->balance_dirty = FALSE;
00119 acc->sort_dirty = FALSE;
00120
00121 LEAVE ("account=%p\n", acc);
00122 }
00123
00124
00125
00126
00127 Account *
00128 xaccMallocAccount (QofBook *book)
00129 {
00130 Account *acc;
00131
00132 g_return_val_if_fail (book, NULL);
00133
00134 acc = g_new (Account, 1);
00135 xaccInitAccount (acc, book);
00136 gnc_engine_gen_event (&acc->inst.entity, GNC_EVENT_CREATE);
00137
00138 return acc;
00139 }
00140
00141 Account *
00142 xaccCloneAccountSimple(const Account *from, QofBook *book)
00143 {
00144 Account *ret;
00145
00146 if (!from || !book) return NULL;
00147 ENTER (" ");
00148
00149 ret = g_new (Account, 1);
00150 g_return_val_if_fail (ret, NULL);
00151
00152 xaccInitAccount (ret, book);
00153
00154
00155
00156
00157 ret->type = from->type;
00158
00159 ret->accountName = g_strdup(from->accountName);
00160 ret->accountCode = g_strdup(from->accountCode);
00161 ret->description = g_strdup(from->description);
00162
00163 ret->inst.kvp_data = kvp_frame_copy(from->inst.kvp_data);
00164
00165
00166
00167 ret->commodity = gnc_commodity_obtain_twin (from->commodity, book);
00168
00169 ret->commodity_scu = from->commodity_scu;
00170 ret->non_standard_scu = from->non_standard_scu;
00171 ret->inst.dirty = TRUE;
00172
00173 LEAVE (" ");
00174 return ret;
00175 }
00176
00177 Account *
00178 xaccCloneAccount (const Account *from, QofBook *book)
00179 {
00180 Account *ret;
00181
00182 if (!from || !book) return NULL;
00183 ENTER (" ");
00184
00185 ret = g_new (Account, 1);
00186 g_return_val_if_fail (ret, NULL);
00187
00188 xaccInitAccount (ret, book);
00189
00190
00191
00192
00193 ret->type = from->type;
00194
00195 ret->accountName = g_strdup(from->accountName);
00196 ret->accountCode = g_strdup(from->accountCode);
00197 ret->description = g_strdup(from->description);
00198
00199 ret->inst.kvp_data = kvp_frame_copy(from->inst.kvp_data);
00200
00201
00202
00203 ret->commodity = gnc_commodity_obtain_twin (from->commodity, book);
00204
00205 ret->commodity_scu = from->commodity_scu;
00206 ret->non_standard_scu = from->non_standard_scu;
00207
00208 qof_instance_gemini (&ret->inst, (QofInstance *) &from->inst);
00209
00210 LEAVE (" ");
00211 return ret;
00212 }
00213
00214
00215
00216
00217 void
00218 xaccFreeAccount (Account *acc)
00219 {
00220 Transaction *t;
00221 GList *lp;
00222
00223 if (!acc) return;
00224
00225 gnc_engine_gen_event (&acc->inst.entity, GNC_EVENT_DESTROY);
00226
00227 if (acc->children)
00228 {
00229 PERR (" instead of calling xaccFreeAccount(), please call \n"
00230 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
00231
00232
00233 xaccFreeAccountGroup (acc->children);
00234 acc->children = NULL;
00235 }
00236
00237
00238 if (acc->lots)
00239 {
00240 PERR (" instead of calling xaccFreeAccount(), please call \n"
00241 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
00242
00243 for (lp=acc->lots; lp; lp=lp->next)
00244 {
00245 GNCLot *lot = lp->data;
00246 gnc_lot_destroy (lot);
00247 }
00248 g_list_free (acc->lots);
00249 acc->lots = NULL;
00250 }
00251
00252
00253
00254
00255
00256 if (acc->splits)
00257 {
00258 PERR (" instead of calling xaccFreeAccount(), please call \n"
00259 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
00260
00261
00262 for(lp = acc->splits; lp; lp = lp->next)
00263 {
00264 Split *s = lp->data;
00265 s->acc = NULL;
00266 }
00267
00268 acc->inst.editlevel = 0;
00269
00270 for(lp = acc->splits; lp; lp = lp->next) {
00271 Split *s = (Split *) lp->data;
00272 t = s->parent;
00273 xaccTransBeginEdit (t);
00274 xaccSplitDestroy (s);
00275 xaccTransCommitEdit (t);
00276 }
00277
00278
00279 g_list_free(acc->splits);
00280 acc->splits = NULL;
00281 }
00282
00283 if (acc->accountName) g_free (acc->accountName);
00284 acc->accountName = NULL;
00285 if (acc->accountCode) g_free (acc->accountCode);
00286 acc->accountCode = NULL;
00287 if (acc->description) g_free (acc->description);
00288 acc->description = NULL;
00289
00290
00291
00292
00293 acc->commodity = NULL;
00294 acc->parent = NULL;
00295 acc->children = NULL;
00296
00297 acc->balance = gnc_numeric_zero();
00298 acc->cleared_balance = gnc_numeric_zero();
00299 acc->reconciled_balance = gnc_numeric_zero();
00300
00301 acc->type = NO_TYPE;
00302 acc->accountName = NULL;
00303 acc->description = NULL;
00304 acc->commodity = NULL;
00305
00306 acc->version = 0;
00307 acc->balance_dirty = FALSE;
00308 acc->sort_dirty = FALSE;
00309
00310 qof_instance_release (&acc->inst);
00311 g_free(acc);
00312 }
00313
00314
00315
00316
00317
00318 void
00319 xaccAccountBeginEdit (Account *acc)
00320 {
00321 QOF_BEGIN_EDIT (&acc->inst);
00322 }
00323
00324 static inline void noop(QofInstance *inst) {}
00325
00326 static inline void on_err (QofInstance *inst, QofBackendError errcode)
00327 {
00328 PERR("commit error: %d", errcode);
00329 }
00330
00331 static inline void acc_free (QofInstance *inst)
00332 {
00333 Account *acc = (Account *) inst;
00334 xaccGroupRemoveAccount(acc->parent, acc);
00335 xaccFreeAccount(acc);
00336 }
00337
00338 void
00339 xaccAccountCommitEdit (Account *acc)
00340 {
00341 QOF_COMMIT_EDIT_PART1 (&acc->inst);
00342
00343
00344
00345 if (acc->inst.do_free)
00346 {
00347 GList *lp;
00348
00349 acc->inst.editlevel++;
00350
00351
00352 xaccFreeAccountGroup (acc->children);
00353 acc->children = NULL;
00354
00355 PINFO ("freeing splits for account %p (%s)",
00356 acc, acc->accountName ? acc->accountName : "(null)");
00357
00358 while (acc->splits)
00359 {
00360 Split *s = acc->splits->data;
00361 Transaction *t = s->parent;
00362
00363 xaccTransBeginEdit (t);
00364 xaccSplitDestroy (s);
00365 xaccTransCommitEdit (t);
00366 }
00367
00368
00369 for (lp=acc->lots; lp; lp=lp->next)
00370 {
00371 GNCLot *lot = lp->data;
00372 gnc_lot_destroy (lot);
00373 }
00374 g_list_free (acc->lots);
00375 acc->lots = NULL;
00376
00377 acc->inst.dirty = TRUE;
00378 acc->inst.editlevel--;
00379 }
00380 else
00381 {
00382 xaccAccountBringUpToDate(acc);
00383
00384
00385 xaccGroupInsertAccount(acc->parent, acc);
00386 }
00387
00388 QOF_COMMIT_EDIT_PART2 (&acc->inst, on_err, noop, acc_free);
00389
00390 gnc_engine_gen_event (&acc->inst.entity, GNC_EVENT_MODIFY);
00391 }
00392
00393 void
00394 xaccAccountDestroy (Account *acc)
00395 {
00396 if (!acc) return;
00397 acc->inst.do_free = TRUE;
00398
00399 xaccAccountCommitEdit (acc);
00400 }
00401
00402 void
00403 xaccAccountSetVersion (Account *acc, gint32 vers)
00404 {
00405 if (!acc) return;
00406 acc->version = vers;
00407 }
00408
00409 gint32
00410 xaccAccountGetVersion (Account *acc)
00411 {
00412 if (!acc) return 0;
00413 return (acc->version);
00414 }
00415
00416
00417
00418
00419 gboolean
00420 xaccAccountEqual(Account *aa, Account *ab, gboolean check_guids)
00421 {
00422 if(!aa && !ab) return TRUE;
00423
00424 if(!aa || !ab)
00425 {
00426 PWARN ("one is NULL");
00427 return FALSE;
00428 }
00429
00430 if (aa->type != ab->type)
00431 {
00432 PWARN ("types differ: %d vs %d", aa->type, ab->type);
00433 return FALSE;
00434 }
00435
00436 if (safe_strcmp(aa->accountName, ab->accountName) != 0)
00437 {
00438 PWARN ("names differ: %s vs %s", aa->accountName, ab->accountName);
00439 return FALSE;
00440 }
00441
00442 if (safe_strcmp(aa->accountCode, ab->accountCode) != 0)
00443 {
00444 PWARN ("codes differ: %s vs %s", aa->accountCode, ab->accountCode);
00445 return FALSE;
00446 }
00447
00448 if (safe_strcmp(aa->description, ab->description) != 0)
00449 {
00450 PWARN ("descriptions differ: %s vs %s", aa->description, ab->description);
00451 return FALSE;
00452 }
00453
00454 if (!gnc_commodity_equal(aa->commodity, ab->commodity))
00455 {
00456 PWARN ("commodities differ");
00457 return FALSE;
00458 }
00459
00460 if(check_guids) {
00461 if(!guid_equal(&aa->inst.entity.guid, &ab->inst.entity.guid))
00462 {
00463 PWARN ("GUIDs differ");
00464 return FALSE;
00465 }
00466 }
00467
00468 if (kvp_frame_compare(aa->inst.kvp_data, ab->inst.kvp_data) != 0)
00469 {
00470 char *frame_a;
00471 char *frame_b;
00472
00473 frame_a = kvp_frame_to_string (aa->inst.kvp_data);
00474 frame_b = kvp_frame_to_string (ab->inst.kvp_data);
00475
00476 PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
00477
00478 g_free (frame_a);
00479 g_free (frame_b);
00480
00481 return FALSE;
00482 }
00483
00484 if (!gnc_numeric_equal (aa->starting_balance, ab->starting_balance))
00485 {
00486 char *str_a;
00487 char *str_b;
00488
00489 str_a = gnc_numeric_to_string (aa->starting_balance);
00490 str_b = gnc_numeric_to_string (ab->starting_balance);
00491
00492 PWARN ("starting balances differ: %s vs %s", str_a, str_b);
00493
00494 g_free (str_a);
00495 g_free (str_b);
00496
00497 return FALSE;
00498 }
00499
00500 if (!gnc_numeric_equal (aa->starting_cleared_balance,
00501 ab->starting_cleared_balance))
00502 {
00503 char *str_a;
00504 char *str_b;
00505
00506 str_a = gnc_numeric_to_string (aa->starting_cleared_balance);
00507 str_b = gnc_numeric_to_string (ab->starting_cleared_balance);
00508
00509 PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
00510
00511 g_free (str_a);
00512 g_free (str_b);
00513
00514 return FALSE;
00515 }
00516
00517 if (!gnc_numeric_equal (aa->starting_reconciled_balance,
00518 ab->starting_reconciled_balance))
00519 {
00520 char *str_a;
00521 char *str_b;
00522
00523 str_a = gnc_numeric_to_string (aa->starting_reconciled_balance);
00524 str_b = gnc_numeric_to_string (ab->starting_reconciled_balance);
00525
00526 PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
00527
00528 g_free (str_a);
00529 g_free (str_b);
00530
00531 return FALSE;
00532 }
00533
00534 if (!gnc_numeric_equal (aa->balance, ab->balance))
00535 {
00536 char *str_a;
00537 char *str_b;
00538
00539 str_a = gnc_numeric_to_string (aa->balance);
00540 str_b = gnc_numeric_to_string (ab->balance);
00541
00542 PWARN ("balances differ: %s vs %s", str_a, str_b);
00543
00544 g_free (str_a);
00545 g_free (str_b);
00546
00547 return FALSE;
00548 }
00549
00550 if (!gnc_numeric_equal (aa->cleared_balance, ab->cleared_balance))
00551 {
00552 char *str_a;
00553 char *str_b;
00554
00555 str_a = gnc_numeric_to_string (aa->cleared_balance);
00556 str_b = gnc_numeric_to_string (ab->cleared_balance);
00557
00558 PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
00559
00560 g_free (str_a);
00561 g_free (str_b);
00562
00563 return FALSE;
00564 }
00565
00566 if (!gnc_numeric_equal (aa->reconciled_balance, ab->reconciled_balance))
00567 {
00568 char *str_a;
00569 char *str_b;
00570
00571 str_a = gnc_numeric_to_string (aa->reconciled_balance);
00572 str_b = gnc_numeric_to_string (ab->reconciled_balance);
00573
00574 PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
00575
00576 g_free (str_a);
00577 g_free (str_b);
00578
00579 return FALSE;
00580 }
00581
00582
00583
00584 {
00585 GList *la = aa->splits;
00586 GList *lb = ab->splits;
00587
00588 if ((la && !lb) || (!la && lb))
00589 {
00590 PWARN ("only one has splits");
00591 return FALSE;
00592 }
00593
00594 if(la && lb)
00595 {
00596
00597 while (la && lb)
00598 {
00599 Split *sa = (Split *) la->data;
00600 Split *sb = (Split *) lb->data;
00601
00602 if (!xaccSplitEqual(sa, sb, check_guids, TRUE, FALSE))
00603 {
00604 PWARN ("splits differ");
00605 return(FALSE);
00606 }
00607
00608 la = la->next;
00609 lb = lb->next;
00610 }
00611
00612 if ((la != NULL) || (lb != NULL))
00613 {
00614 PWARN ("number of splits differs");
00615 return(FALSE);
00616 }
00617 }
00618 }
00619
00620 if (!xaccGroupEqual(aa->children, ab->children, check_guids))
00621 {
00622 PWARN ("children differ");
00623 return FALSE;
00624 }
00625
00626 return(TRUE);
00627 }
00628
00629
00630
00631
00632 static gint
00633 split_sort_func(gconstpointer a, gconstpointer b) {
00634
00635 Split *sa = (Split *) a;
00636 Split *sb = (Split *) b;
00637 return(xaccSplitDateOrder(sa, sb));
00638 }
00639
00640 void
00641 xaccAccountSortSplits (Account *acc, gboolean force)
00642 {
00643 if(!acc) return;
00644 if(!acc->sort_dirty) return;
00645 if(!force && acc->inst.editlevel > 0) return;
00646
00647 acc->splits = g_list_sort(acc->splits, split_sort_func);
00648
00649 acc->sort_dirty = FALSE;
00650 acc->balance_dirty = TRUE;
00651 }
00652
00653 static void
00654 xaccAccountBringUpToDate(Account *acc)
00655 {
00656 if(!acc) return;
00657
00658
00659
00660 xaccAccountSortSplits(acc, FALSE);
00661 xaccAccountRecomputeBalance(acc);
00662 }
00663
00664
00665
00666
00667 void
00668 xaccAccountSetGUID (Account *account, const GUID *guid)
00669 {
00670 if (!account || !guid) return;
00671
00672
00673 PINFO("acct=%p", account);
00674 xaccAccountBeginEdit (account);
00675 qof_entity_set_guid (&account->inst.entity, guid);
00676 account->inst.dirty = TRUE;
00677 xaccAccountCommitEdit (account);
00678 }
00679
00680
00681
00682
00683 Account *
00684 xaccAccountLookup (const GUID *guid, QofBook *book)
00685 {
00686 QofCollection *col;
00687 if (!guid || !book) return NULL;
00688 col = qof_book_get_collection (book, GNC_ID_ACCOUNT);
00689 return (Account *) qof_collection_lookup_entity (col, guid);
00690 }
00691
00692
00693
00694
00695 short
00696 xaccAccountGetMark (Account *acc)
00697 {
00698 if (!acc) return 0;
00699 return acc->mark;
00700 }
00701
00702 void
00703 xaccAccountSetMark (Account *acc, short m)
00704 {
00705 if (!acc) return;
00706 acc->mark = m;
00707 }
00708
00709 void
00710 xaccClearMark (Account *acc, short val)
00711 {
00712 AccountGroup *topgrp;
00713
00714 if (!acc) return;
00715 topgrp = xaccAccountGetRoot (acc);
00716
00717 if (topgrp)
00718 {
00719 GList *list;
00720 GList *node;
00721
00722 list = xaccGroupGetAccountList (topgrp);
00723
00724 for (node = list; node; node = node->next)
00725 {
00726 Account *account = node->data;
00727
00728 xaccClearMarkDown (account, val);
00729 }
00730 }
00731 else
00732 xaccClearMarkDown (acc, val);
00733 }
00734
00735 void
00736 xaccClearMarkDown (Account *acc, short val)
00737 {
00738 AccountGroup *children;
00739
00740 if (!acc) return;
00741 acc->mark = val;
00742
00743 children = acc->children;
00744 if (children)
00745 {
00746 GList *list;
00747 GList *node;
00748
00749 list = xaccGroupGetAccountList (children);
00750
00751 for (node = list; node; node = node->next)
00752 {
00753 Account *account = node->data;
00754
00755 xaccClearMarkDown (account, val);
00756 }
00757 }
00758 }
00759
00760 void
00761 xaccClearMarkDownGr (AccountGroup *grp, short val)
00762 {
00763 GList *list;
00764 GList *node;
00765
00766 if (!grp) return;
00767
00768 list = xaccGroupGetAccountList (grp);
00769
00770 for (node = list; node; node = node->next)
00771 {
00772 Account *account = node->data;
00773
00774 xaccClearMarkDown (account, val);
00775 }
00776 }
00777
00778
00779
00780
00781 void
00782 xaccAccountRemoveLot (Account *acc, GNCLot *lot)
00783 {
00784 if (!acc || !lot) return;
00785 ENTER ("(acc=%p, lot=%p)", acc, lot);
00786
00787 xaccAccountBeginEdit (acc);
00788 acc->lots = g_list_remove (acc->lots, lot);
00789 xaccAccountCommitEdit (acc);
00790 LEAVE ("(acc=%p, lot=%p)", acc, lot);
00791 }
00792
00793 void
00794 xaccAccountInsertLot (Account *acc, GNCLot *lot)
00795 {
00796 GList *sl;
00797 Account * old_acc = NULL;
00798
00799 if (!acc || !lot) return;
00800 ENTER ("(acc=%p, lot=%p)", acc, lot);
00801
00802
00803 if (lot->account && lot->account != acc)
00804 {
00805 old_acc = lot->account;
00806 xaccAccountBeginEdit (old_acc);
00807 old_acc->lots = g_list_remove (old_acc->lots, lot);
00808
00809 }
00810
00811 xaccAccountBeginEdit(acc);
00812
00813
00814 if (lot->account != acc)
00815 {
00816 acc->lots = g_list_prepend (acc->lots, lot);
00817 lot->account = acc;
00818 }
00819
00820
00821
00822 if (lot->splits)
00823 {
00824 for (sl = lot->splits; sl; sl=sl->next)
00825 {
00826 Split *s = sl->data;
00827 if (s->acc != acc)
00828 {
00829 xaccAccountInsertSplit (acc, s);
00830 }
00831 }
00832 }
00833 xaccAccountCommitEdit(acc);
00834 xaccAccountCommitEdit(old_acc);
00835 LEAVE ("(acc=%p, lot=%p)", acc, lot);
00836 }
00837
00838
00839
00840
00841 void
00842 xaccAccountInsertSplit (Account *acc, Split *split)
00843 {
00844 Transaction *trans;
00845 gnc_numeric old_amt;
00846
00847 if (!acc) return;
00848 if (!split) return;
00849 ENTER ("(acc=%p, split=%p)", acc, split);
00850
00851
00852 g_return_if_fail (acc->inst.book == split->book);
00853
00854 trans = xaccSplitGetParent (split);
00855 old_amt = xaccSplitGetAmount (split);
00856
00857 xaccAccountBeginEdit(acc);
00858 xaccTransBeginEdit(trans);
00859
00860 acc->balance_dirty = TRUE;
00861 acc->sort_dirty = TRUE;
00862
00863
00864
00865
00866
00867 if (split->acc && split->acc != acc)
00868 {
00869 xaccAccountRemoveSplit (split->acc, split);
00870 }
00871
00872 split->acc = acc;
00873 if (split->lot && (NULL == split->lot->account))
00874 {
00875 xaccAccountInsertLot (acc, split->lot);
00876 }
00877
00878 if (g_list_index(acc->splits, split) == -1)
00879 {
00880 if (acc->inst.editlevel == 1)
00881 {
00882 acc->splits = g_list_insert_sorted(acc->splits, split,
00883 split_sort_func);
00884 acc->sort_dirty = FALSE;
00885 }
00886 else
00887 {
00888 acc->splits = g_list_prepend(acc->splits, split);
00889 }
00890
00891 mark_account (acc);
00892 }
00893
00894
00895
00896
00897 split->amount = gnc_numeric_convert (old_amt,
00898 xaccAccountGetCommoditySCU(acc), GNC_HOW_RND_ROUND);
00899 xaccTransCommitEdit(trans);
00900 xaccAccountCommitEdit(acc);
00901 LEAVE ("(acc=%p, split=%p)", acc, split);
00902 }
00903
00904
00905
00906
00907 void
00908 xaccAccountRemoveSplit (Account *acc, Split *split)
00909 {
00910 if (!acc) return;
00911 if (!split) return;
00912 if (split->acc && split->acc != acc) return;
00913
00914 ENTER ("(acc=%p, split=%p)", acc, split);
00915
00916 xaccAccountBeginEdit(acc);
00917 {
00918 GList *node;
00919
00920 node = g_list_find (acc->splits, split);
00921 if (!node)
00922 {
00923 PERR ("split not in account");
00924 }
00925 else
00926 {
00927 Transaction *trans = xaccSplitGetParent (split);
00928
00929 acc->splits = g_list_remove_link (acc->splits, node);
00930 g_list_free_1 (node);
00931
00932 acc->balance_dirty = TRUE;
00933
00934 xaccTransBeginEdit (trans);
00935 split->acc = NULL;
00936
00937
00938 if (split->lot && split->lot->account == acc)
00939 {
00940 gnc_lot_remove_split (split->lot, split);
00941 }
00942 xaccTransCommitEdit (trans);
00943
00944 mark_account (acc);
00945 if (split->parent)
00946 gnc_engine_gen_event (&split->parent->inst.entity, GNC_EVENT_MODIFY);
00947 }
00948 }
00949 xaccAccountCommitEdit(acc);
00950 LEAVE ("(acc=%p, split=%p)", acc, split);
00951 }
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 void
00983 xaccAccountRecomputeBalance (Account * acc)
00984 {
00985 gnc_numeric balance;
00986 gnc_numeric cleared_balance;
00987 gnc_numeric reconciled_balance;
00988 Split *last_split = NULL;
00989 GList *lp;
00990
00991 if (NULL == acc) return;
00992 if (acc->inst.editlevel > 0) return;
00993 if (!acc->balance_dirty) return;
00994 if (acc->inst.do_free) return;
00995
00996 balance = acc->starting_balance;
00997 cleared_balance = acc->starting_cleared_balance;
00998 reconciled_balance = acc->starting_reconciled_balance;
00999
01000 PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
01001 acc->accountName, balance.num, balance.denom);
01002 for(lp = acc->splits; lp; lp = lp->next)
01003 {
01004 Split *split = (Split *) lp->data;
01005 gnc_numeric amt = xaccSplitGetAmount (split);
01006
01007 balance = gnc_numeric_add_fixed(balance, amt);
01008
01009 if (NREC != split->reconciled)
01010 {
01011 cleared_balance = gnc_numeric_add_fixed(cleared_balance, amt);
01012 }
01013
01014 if (YREC == split->reconciled ||
01015 FREC == split->reconciled)
01016 {
01017 reconciled_balance =
01018 gnc_numeric_add_fixed(reconciled_balance, amt);
01019 }
01020
01021 split->balance = balance;
01022 split->cleared_balance = cleared_balance;
01023 split->reconciled_balance = reconciled_balance;
01024
01025 last_split = split;
01026 }
01027
01028 acc->balance = balance;
01029 acc->cleared_balance = cleared_balance;
01030 acc->reconciled_balance = reconciled_balance;
01031
01032 acc->balance_dirty = FALSE;
01033 gnc_engine_gen_event (&acc->inst.entity, GNC_EVENT_MODIFY);
01034 }
01035
01036
01037
01038
01039 void
01040 xaccAccountSetStartingBalance(Account *acc,
01041 const gnc_numeric start_baln,
01042 const gnc_numeric start_cleared_baln,
01043 const gnc_numeric start_reconciled_baln)
01044 {
01045 if (!acc) return;
01046
01047 acc->starting_balance = start_baln;
01048 acc->starting_cleared_balance = start_cleared_baln;
01049 acc->starting_reconciled_balance = start_reconciled_baln;
01050
01051 acc->balance_dirty = TRUE;
01052 }
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 void
01066 xaccAccountFixSplitDateOrder (Account * acc, Split *split)
01067 {
01068 if (NULL == acc) return;
01069 if (NULL == split) return;
01070
01071 if (acc->inst.do_free) return;
01072
01073 acc->sort_dirty = TRUE;
01074 acc->balance_dirty = TRUE;
01075
01076 if (acc->inst.editlevel > 0) return;
01077
01078 xaccAccountBringUpToDate (acc);
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092 void
01093 xaccTransFixSplitDateOrder (Transaction *trans)
01094 {
01095 GList *node;
01096
01097 if (trans == NULL) return;
01098
01099 gnc_engine_suspend_events();
01100 for (node = trans->splits; node; node = node->next)
01101 {
01102 Split *s = node->data;
01103 xaccAccountFixSplitDateOrder (s->acc, s);
01104 }
01105 gnc_engine_resume_events();
01106 }
01107
01108
01109
01110
01111
01112
01113
01114 static int typeorder[NUM_ACCOUNT_TYPES] = {
01115 BANK, STOCK, MUTUAL, CURRENCY, CASH, ASSET, RECEIVABLE,
01116 CREDIT, LIABILITY, PAYABLE, INCOME, EXPENSE, EQUITY };
01117
01118 static int revorder[NUM_ACCOUNT_TYPES] = {
01119 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
01120
01121
01122 int
01123 xaccAccountOrder (Account **aa, Account **ab)
01124 {
01125 char *da, *db;
01126 char *endptr = NULL;
01127 int ta, tb;
01128 long la, lb;
01129
01130 if ( (*aa) && !(*ab) ) return -1;
01131 if ( !(*aa) && (*ab) ) return +1;
01132 if ( !(*aa) && !(*ab) ) return 0;
01133
01134
01135 da = (*aa)->accountCode;
01136 db = (*ab)->accountCode;
01137
01138
01139 la = strtoul (da, &endptr, 36);
01140 if((*da != '\0') && (*endptr == '\0')) {
01141 lb = strtoul (db, &endptr, 36);
01142 if((*db != '\0') && (*endptr == '\0')) {
01143 if (la < lb) return -1;
01144 if (la > lb) return +1;
01145 }
01146 }
01147
01148
01149 SAFE_STRCMP (da, db);
01150
01151
01152
01153 if (-1 == revorder[0]) {
01154 int i;
01155 for (i=0; i<NUM_ACCOUNT_TYPES; i++) {
01156 revorder [typeorder[i]] = i;
01157 }
01158 }
01159
01160
01161 ta = (*aa)->type;
01162 tb = (*ab)->type;
01163 ta = revorder[ta];
01164 tb = revorder[tb];
01165 if (ta < tb) return -1;
01166 if (ta > tb) return +1;
01167
01168
01169 da = (*aa)->accountName;
01170 db = (*ab)->accountName;
01171 SAFE_STRCMP (da, db);
01172
01173
01174 return guid_compare (&((*aa)->inst.entity.guid), &((*ab)->inst.entity.guid));
01175 }
01176
01177
01178
01179
01180 void
01181 xaccAccountSetType (Account *acc, GNCAccountType tip)
01182 {
01183
01184 if (!acc) return;
01185
01186 xaccAccountBeginEdit(acc);
01187 {
01188
01189 if((NUM_ACCOUNT_TYPES > tip) && (acc->type != tip)) {
01190 acc->type = tip;
01191 acc->balance_dirty = TRUE;
01192 }
01193
01194 mark_account (acc);
01195 }
01196 acc->inst.dirty = TRUE;
01197 xaccAccountCommitEdit(acc);
01198 }
01199
01200 void
01201 xaccAccountSetName (Account *acc, const char *str)
01202 {
01203 char * tmp;
01204
01205 if ((!acc) || (!str)) return;
01206
01207 xaccAccountBeginEdit(acc);
01208 {
01209
01210 tmp = g_strdup (str);
01211 g_free (acc->accountName);
01212 acc->accountName = tmp;
01213
01214 mark_account (acc);
01215 }
01216 acc->inst.dirty = TRUE;
01217 xaccAccountCommitEdit(acc);
01218 }
01219
01220 void
01221 xaccAccountSetCode (Account *acc, const char *str)
01222 {
01223 char * tmp;
01224 if ((!acc) || (!str)) return;
01225
01226 xaccAccountBeginEdit(acc);
01227 {
01228
01229 tmp = g_strdup (str);
01230 g_free (acc->accountCode);
01231 acc->accountCode = tmp;
01232
01233 mark_account (acc);
01234 }
01235 acc->inst.dirty = TRUE;
01236 xaccAccountCommitEdit(acc);
01237 }
01238
01239 void
01240 xaccAccountSetDescription (Account *acc, const char *str)
01241 {
01242 char * tmp;
01243 if ((!acc) || (!str)) return;
01244
01245 xaccAccountBeginEdit(acc);
01246 {
01247
01248 tmp = g_strdup (str);
01249 g_free (acc->description);
01250 acc->description = tmp;
01251
01252 mark_account (acc);
01253 }
01254 acc->inst.dirty = TRUE;
01255 xaccAccountCommitEdit(acc);
01256 }
01257
01258 static void
01259 qofAccountSetParent (Account *acc, QofEntity *parent)
01260 {
01261 Account *parent_acc;
01262
01263 if((!acc)||(!parent)) { return; }
01264 parent_acc = (Account*)parent;
01265 xaccAccountBeginEdit(acc);
01266 xaccAccountBeginEdit(parent_acc);
01267 xaccAccountInsertSubAccount(parent_acc, acc);
01268 mark_account (parent_acc);
01269 mark_account (acc);
01270 xaccAccountCommitEdit(acc);
01271 xaccAccountCommitEdit(parent_acc);
01272 }
01273
01274 void
01275 xaccAccountSetNotes (Account *acc, const char *str)
01276 {
01277 if ((!acc) || (!str)) return;
01278
01279 xaccAccountBeginEdit(acc);
01280 kvp_frame_set_slot_nc(acc->inst.kvp_data, "notes",
01281 kvp_value_new_string(str));
01282 mark_account (acc);
01283 acc->inst.dirty = TRUE;
01284 xaccAccountCommitEdit(acc);
01285 }
01286
01287
01288 static void
01289 update_split_commodity(Account * acc)
01290 {
01291 GList *lp;
01292
01293 if(!acc) return;
01294
01295 xaccAccountBeginEdit(acc);
01296
01297
01298 for (lp = acc->splits; lp; lp = lp->next)
01299 {
01300 Split *s = (Split *) lp->data;
01301 Transaction *trans = xaccSplitGetParent (s);
01302 gnc_numeric amt;
01303
01304 amt = xaccSplitGetAmount (s);
01305 xaccTransBeginEdit (trans);
01306 xaccSplitSetAmount (s, amt);
01307 xaccTransCommitEdit (trans);
01308 }
01309
01310 xaccAccountCommitEdit(acc);
01311 }
01312
01313
01314
01315
01316 void
01317 xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
01318 {
01319 if ((!acc) || (!com)) return;
01320
01321 xaccAccountBeginEdit(acc);
01322 {
01323 acc->commodity = com;
01324 acc->commodity_scu = gnc_commodity_get_fraction(com);
01325 acc->non_standard_scu = FALSE;
01326 update_split_commodity(acc);
01327
01328 acc->sort_dirty = TRUE;
01329 acc->balance_dirty = TRUE;
01330
01331 mark_account (acc);
01332 }
01333 acc->inst.dirty = TRUE;
01334
01335 if (gnc_commodity_is_iso(com))
01336 {
01337
01338
01339 gnc_commodity_set_quote_flag(com, TRUE);
01340 }
01341 xaccAccountCommitEdit(acc);
01342 }
01343
01344
01345
01346
01347
01348
01349
01350 void
01351 xaccAccountSetCommoditySCU (Account *acc, int scu)
01352 {
01353 if (!acc) return;
01354
01355 xaccAccountBeginEdit(acc);
01356 {
01357 acc->commodity_scu = scu;
01358 if (scu != gnc_commodity_get_fraction(acc->commodity))
01359 acc->non_standard_scu = TRUE;
01360 mark_account (acc);
01361 }
01362 acc->inst.dirty = TRUE;
01363 xaccAccountCommitEdit(acc);
01364 }
01365
01366 int
01367 xaccAccountGetCommoditySCUi (Account * acc)
01368 {
01369 if (!acc) return 0;
01370
01371 return acc->commodity_scu;
01372 }
01373
01374 int
01375 xaccAccountGetCommoditySCU (Account * acc)
01376 {
01377 if (!acc) return 0;
01378
01379 if (acc->non_standard_scu || !acc->commodity)
01380 return acc->commodity_scu;
01381 return gnc_commodity_get_fraction(acc->commodity);
01382 }
01383
01384 void
01385 xaccAccountSetNonStdSCU (Account *acc, gboolean flag)
01386 {
01387 if (!acc) return;
01388
01389 xaccAccountBeginEdit(acc);
01390 {
01391 acc->non_standard_scu = flag;
01392 mark_account (acc);
01393 }
01394 acc->inst.dirty = TRUE;
01395 xaccAccountCommitEdit(acc);
01396 }
01397
01398 gboolean
01399 xaccAccountGetNonStdSCU (Account * acc)
01400 {
01401 if (!acc) return 0;
01402
01403 return acc->non_standard_scu;
01404 }
01405
01406
01407
01408
01409
01410 void
01411 DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
01412 {
01413 const char *string;
01414 gnc_commodity *commodity;
01415
01416 if ((!acc) || (!currency)) return;
01417
01418 xaccAccountBeginEdit(acc);
01419 string = gnc_commodity_get_unique_name (currency);
01420 kvp_frame_set_slot_nc(acc->inst.kvp_data, "old-currency",
01421 kvp_value_new_string(string));
01422 mark_account (acc);
01423 acc->inst.dirty = TRUE;
01424 xaccAccountCommitEdit(acc);
01425
01426 commodity = DxaccAccountGetCurrency (acc);
01427 if (!commodity)
01428 {
01429 gnc_commodity_table_insert (gnc_commodity_table_get_table (acc->inst.book), currency);
01430 }
01431 }
01432
01433
01434
01435
01436 AccountGroup *
01437 xaccAccountGetChildren (Account *acc)
01438 {
01439 if (!acc) return NULL;
01440 return (acc->children);
01441 }
01442
01443 AccountGroup *
01444 xaccAccountGetParent (Account *acc)
01445 {
01446 if (!acc) return NULL;
01447 return (acc->parent);
01448 }
01449
01450 Account *
01451 xaccAccountGetParentAccount (Account * acc)
01452 {
01453 if (!acc) return NULL;
01454 return xaccGroupGetParentAccount(acc->parent);
01455 }
01456
01457 GList *
01458 xaccAccountGetDescendants (Account *acc)
01459 {
01460 GList *accounts;
01461
01462 if (!acc) return NULL;
01463 accounts = xaccGroupGetSubAccounts(acc->children);
01464 return (accounts);
01465 }
01466
01467 GNCAccountType
01468 xaccAccountGetType (Account *acc)
01469 {
01470 if (!acc) return NO_TYPE;
01471 return (acc->type);
01472 }
01473
01474 static const char*
01475 qofAccountGetTypeString (Account *acc)
01476 {
01477 if(!acc) { return NULL; }
01478 return (xaccAccountTypeEnumAsString(acc->type));
01479 }
01480
01481 static void
01482 qofAccountSetType (Account *acc, const char *type_string)
01483 {
01484 GNCAccountType type;
01485
01486 type = xaccAccountStringToEnum(type_string);
01487 xaccAccountSetType(acc, type);
01488 }
01489
01490 const char *
01491 xaccAccountGetName (Account *acc)
01492 {
01493 if (!acc) return NULL;
01494 return (acc->accountName);
01495 }
01496
01497 char *
01498 xaccAccountGetFullName(Account *account, const char separator)
01499 {
01500 Account *a;
01501 char *fullname;
01502 const char *name;
01503 char *p;
01504 int length;
01505
01506 if (account == NULL)
01507 return g_strdup("");
01508
01509
01510 length = 0;
01511 a = account;
01512 while (a != NULL)
01513 {
01514 name = a->accountName;
01515
01516 length += strlen(name) + 1;
01517
01518 a = xaccAccountGetParentAccount(a);
01519 }
01520
01521
01522
01523
01524
01525 fullname = g_new(char, length);
01526
01527
01528 p = fullname + length - 1;
01529
01530
01531 *p-- = 0;
01532
01533 a = account;
01534 while (a != NULL)
01535 {
01536 name = a->accountName;
01537 length = strlen(name);
01538
01539
01540 while (length > 0)
01541 *p-- = name[--length];
01542
01543 a = xaccAccountGetParentAccount(a);
01544
01545
01546 if (a != NULL)
01547 *p-- = separator;
01548 }
01549
01550 return fullname;
01551 }
01552
01553 const char *
01554 xaccAccountGetCode (Account *acc)
01555 {
01556 if (!acc) return NULL;
01557 return (acc->accountCode);
01558 }
01559
01560 const char *
01561 xaccAccountGetDescription (Account *acc)
01562 {
01563 if (!acc) return NULL;
01564 return (acc->description);
01565 }
01566
01567 const char *
01568 xaccAccountGetNotes (Account *acc)
01569 {
01570 KvpValue *v;
01571
01572 if (!acc) return NULL;
01573 v = kvp_frame_get_slot(acc->inst.kvp_data, "notes");
01574 if(v) return(kvp_value_get_string(v));
01575 return(NULL);
01576 }
01577
01578 gnc_commodity *
01579 DxaccAccountGetCurrency (Account *acc)
01580 {
01581 KvpValue *v;
01582 const char *s;
01583 gnc_commodity_table *table;
01584
01585 if (!acc) return NULL;
01586
01587 v = kvp_frame_get_slot(acc->inst.kvp_data, "old-currency");
01588 if (!v) return NULL;
01589
01590 s = kvp_value_get_string (v);
01591 if (!s) return NULL;
01592
01593 table = gnc_commodity_table_get_table (acc->inst.book);
01594
01595 return gnc_commodity_table_lookup_unique (table, s);
01596 }
01597
01598 gnc_commodity *
01599 xaccAccountGetCommodity (Account *acc)
01600 {
01601 if (!acc) return NULL;
01602
01603 return (acc->commodity);
01604 }
01605
01606 gnc_numeric
01607 xaccAccountGetBalance (Account *acc)
01608 {
01609 if (!acc) return gnc_numeric_zero();
01610 return acc->balance;
01611 }
01612
01613 gnc_numeric
01614 xaccAccountGetClearedBalance (Account *acc)
01615 {
01616 if (!acc) return gnc_numeric_zero();
01617 return acc->cleared_balance;
01618 }
01619
01620 gnc_numeric
01621 xaccAccountGetReconciledBalance (Account *acc)
01622 {
01623 if (!acc) return gnc_numeric_zero();
01624 return acc->reconciled_balance;
01625 }
01626
01627 gnc_numeric
01628 xaccAccountGetProjectedMinimumBalance (Account *account)
01629 {
01630 GList *node;
01631 time_t today;
01632 gnc_numeric lowest = gnc_numeric_zero ();
01633 int seen_a_transaction = 0;
01634
01635 if (!account)
01636 return gnc_numeric_zero ();
01637
01638 today = gnc_timet_get_today_end();
01639 for (node = g_list_last (account->splits); node; node = node->prev)
01640 {
01641 Split *split = node->data;
01642
01643 if (!seen_a_transaction)
01644 {
01645 lowest = xaccSplitGetBalance (split);
01646 seen_a_transaction = 1;
01647 } else if (gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0) {
01648 lowest = xaccSplitGetBalance (split);
01649 }
01650
01651 if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
01652 return lowest;
01653 }
01654
01655 return lowest;
01656 }
01657
01658
01659
01660
01661
01662 gnc_numeric
01663 xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
01664 {
01665
01666
01667
01668
01669
01670
01671 GList *lp;
01672 Timespec ts, trans_ts;
01673 gboolean found = FALSE;
01674 gnc_numeric balance;
01675
01676 if (!acc) return gnc_numeric_zero ();
01677
01678 xaccAccountSortSplits (acc, TRUE);
01679 xaccAccountRecomputeBalance (acc);
01680
01681 balance = acc->balance;
01682
01683
01684
01685
01686
01687 ts.tv_sec = date;
01688 ts.tv_nsec = 0;
01689
01690 lp = acc->splits;
01691 while( lp && !found )
01692 {
01693 xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ),
01694 &trans_ts );
01695 if( timespec_cmp( &trans_ts, &ts ) > 0 )
01696 found = TRUE;
01697 else
01698 lp = lp->next;
01699 }
01700
01701 if( lp ) {
01702 if ( lp->prev ) {
01703
01704
01705
01706 balance = xaccSplitGetBalance( (Split *)lp->prev->data );
01707 }
01708 else {
01709
01710 balance = gnc_numeric_zero();
01711 }
01712 }
01713
01714
01715
01716
01717
01718 return( balance );
01719 }
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729 gnc_numeric
01730 xaccAccountGetPresentBalance (Account *account)
01731 {
01732 GList *node;
01733 time_t today;
01734
01735 if (!account)
01736 return gnc_numeric_zero ();
01737
01738 today = gnc_timet_get_today_end();
01739 for (node = g_list_last (account->splits); node; node = node->prev)
01740 {
01741 Split *split = node->data;
01742
01743 if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
01744 return xaccSplitGetBalance (split);
01745 }
01746
01747 return gnc_numeric_zero ();
01748 }
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760 gnc_numeric
01761 xaccAccountConvertBalanceToCurrency(Account *account,
01762 gnc_numeric balance,
01763 gnc_commodity *balance_currency,
01764 gnc_commodity *new_currency)
01765 {
01766 QofBook *book;
01767 GNCPriceDB *pdb;
01768
01769 if (gnc_numeric_zero_p (balance) ||
01770 gnc_commodity_equiv (balance_currency, new_currency))
01771 return balance;
01772
01773 book = xaccGroupGetBook (xaccAccountGetRoot (account));
01774 pdb = gnc_pricedb_get_db (book);
01775
01776 balance = gnc_pricedb_convert_balance_latest_price(pdb, balance, balance_currency, new_currency);
01777
01778 return balance;
01779 }
01780
01781
01782
01783
01784
01785 gnc_numeric
01786 xaccAccountConvertBalanceToCurrencyAsOfDate(Account *account,
01787 gnc_numeric balance,
01788 gnc_commodity *balance_currency,
01789 gnc_commodity *new_currency,
01790 time_t date)
01791 {
01792 QofBook *book;
01793 GNCPriceDB *pdb;
01794 Timespec ts;
01795
01796 if (gnc_numeric_zero_p (balance) ||
01797 gnc_commodity_equiv (balance_currency, new_currency))
01798 return balance;
01799
01800 book = xaccGroupGetBook (xaccAccountGetRoot (account));
01801 pdb = gnc_book_get_pricedb (book);
01802
01803 ts.tv_sec = date;
01804 ts.tv_nsec = 0;
01805
01806 balance = gnc_pricedb_convert_balance_nearest_price(pdb, balance, balance_currency, new_currency, ts);
01807
01808 return balance;
01809 }
01810
01811
01812
01813
01814
01815
01816 static gnc_numeric
01817 xaccAccountGetXxxBalanceInCurrency (Account *account,
01818 xaccGetBalanceFn fn,
01819 gnc_commodity *report_currency)
01820 {
01821 gnc_numeric balance;
01822
01823 if (!account || !fn || !report_currency) return gnc_numeric_zero ();
01824 balance = fn(account);
01825 balance = xaccAccountConvertBalanceToCurrency(account, balance,
01826 account->commodity,
01827 report_currency);
01828 return balance;
01829 }
01830
01831
01832
01833
01834 typedef struct
01835 {
01836 gnc_commodity *currency;
01837 gnc_numeric balance;
01838 xaccGetBalanceFn fn;
01839 } CurrencyBalance;
01840
01841
01842
01843
01844
01845
01846
01847 static gpointer
01848 xaccAccountBalanceHelper (Account *account, gpointer data)
01849 {
01850 CurrencyBalance *cb = data;
01851 gnc_numeric balance;
01852
01853 if (!cb->fn || !cb->currency)
01854 return NULL;
01855 balance = xaccAccountGetXxxBalanceInCurrency (account, cb->fn, cb->currency);
01856 cb->balance = gnc_numeric_add (cb->balance, balance,
01857 gnc_commodity_get_fraction (cb->currency),
01858 GNC_HOW_RND_ROUND);
01859 return NULL;
01860 }
01861
01862
01863
01864
01865
01866
01867
01868
01869 static gnc_numeric
01870 xaccAccountGetXxxBalanceInCurrencyRecursive (Account *account,
01871 xaccGetBalanceFn fn,
01872 gnc_commodity *report_commodity,
01873 gboolean include_children)
01874 {
01875 gnc_numeric balance;
01876
01877 if (account == NULL)
01878 return gnc_numeric_zero ();
01879 if (!report_commodity)
01880 report_commodity = xaccAccountGetCommodity (account);
01881 balance = xaccAccountGetXxxBalanceInCurrency (account, fn, report_commodity);
01882
01883
01884 if (include_children)
01885 {
01886 CurrencyBalance cb = { report_commodity, balance, fn };
01887
01888 xaccGroupForEachAccount (account->children, xaccAccountBalanceHelper, &cb, TRUE);
01889 balance = cb.balance;
01890 }
01891
01892 return balance;
01893 }
01894
01895 gnc_numeric
01896 xaccAccountGetBalanceInCurrency (Account *account,
01897 gnc_commodity *report_commodity,
01898 gboolean include_children)
01899 {
01900 gnc_numeric rc;
01901 rc = xaccAccountGetXxxBalanceInCurrencyRecursive (account,
01902 xaccAccountGetBalance,
01903 report_commodity, include_children);
01904 PINFO (" baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, rc.num, rc.denom);
01905 return rc;
01906 }
01907
01908
01909 gnc_numeric
01910 xaccAccountGetClearedBalanceInCurrency (Account *account,
01911 gnc_commodity *report_commodity,
01912 gboolean include_children)
01913 {
01914 return
01915 xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetClearedBalance,
01916 report_commodity, include_children);
01917 }
01918
01919
01920 gnc_numeric
01921 xaccAccountGetReconciledBalanceInCurrency (Account *account,
01922 gnc_commodity *report_commodity,
01923 gboolean include_children)
01924 {
01925 return
01926 xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetReconciledBalance,
01927 report_commodity, include_children);
01928 }
01929
01930 gnc_numeric
01931 xaccAccountGetPresentBalanceInCurrency (Account *account,
01932 gnc_commodity *report_commodity,
01933 gboolean include_children)
01934 {
01935 return
01936 xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetPresentBalance,
01937 report_commodity, include_children);
01938 }
01939
01940 gnc_numeric
01941 xaccAccountGetProjectedMinimumBalanceInCurrency (Account *account,
01942 gnc_commodity *report_commodity,
01943 gboolean include_children)
01944 {
01945 return
01946 xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetProjectedMinimumBalance,
01947 report_commodity, include_children);
01948 }
01949
01950
01951
01952
01953 SplitList *
01954 xaccAccountGetSplitList (Account *acc)
01955 {
01956 if (!acc) return NULL;
01957 return (acc->splits);
01958 }
01959
01960 LotList *
01961 xaccAccountGetLotList (Account *acc)
01962 {
01963 if (!acc) return NULL;
01964 return (acc->lots);
01965 }
01966
01967 LotList *
01968 xaccAccountFindOpenLots (Account *acc,
01969 gboolean (*match_func)(GNCLot *lot,
01970 gpointer user_data),
01971 gpointer user_data, GCompareFunc sort_func)
01972 {
01973 GList *lot_list;
01974 GList *retval = NULL;
01975
01976 if (!acc)
01977 return NULL;
01978
01979 lot_list = xaccAccountGetLotList (acc);
01980 for ( ; lot_list ; lot_list = lot_list->next ) {
01981 GNCLot *lot = lot_list->data;
01982
01983
01984 if (gnc_lot_is_closed (lot))
01985 continue;
01986
01987 if (match_func && !(match_func)(lot, user_data))
01988 continue;
01989
01990
01991 if (sort_func)
01992 retval = g_list_insert_sorted (retval, lot, sort_func);
01993 else
01994 retval = g_list_prepend (retval, lot);
01995 }
01996
01997 return retval;
01998 }
01999
02000 gpointer
02001 xaccAccountForEachLot(Account *acc,
02002 gpointer (*proc)(GNCLot *lot, void *data),
02003 void *data)
02004 {
02005 LotList *node;
02006
02007 if (!acc) return(NULL);
02008 if (!proc) return(NULL);
02009
02010 for (node = acc->lots; node; node=node->next)
02011 {
02012 GNCLot *lot = node->data;
02013 gpointer result = proc (lot, data);
02014 if (result) return result;
02015 }
02016
02017 return(NULL);
02018 }
02019
02020
02021
02022
02023 gboolean
02024 xaccAccountGetTaxRelated (Account *account)
02025 {
02026 KvpValue *kvp;
02027
02028 if (!account)
02029 return FALSE;
02030
02031 kvp = kvp_frame_get_slot (account->inst.kvp_data, "tax-related");
02032 if (!kvp)
02033 return FALSE;
02034
02035 return kvp_value_get_gint64 (kvp);
02036 }
02037
02038 void
02039 xaccAccountSetTaxRelated (Account *account, gboolean tax_related)
02040 {
02041 KvpValue *new_value;
02042
02043 if (!account)
02044 return;
02045
02046 if (tax_related)
02047 new_value = kvp_value_new_gint64 (tax_related);
02048 else
02049 new_value = NULL;
02050
02051 xaccAccountBeginEdit (account);
02052 kvp_frame_set_slot_nc(account->inst.kvp_data, "tax-related", new_value);
02053
02054 mark_account (account);
02055 account->inst.dirty = TRUE;
02056 xaccAccountCommitEdit (account);
02057 }
02058
02059 const char *
02060 xaccAccountGetTaxUSCode (Account *account)
02061 {
02062 KvpValue *value;
02063
02064 if (!account)
02065 return FALSE;
02066
02067 value = kvp_frame_get_slot_path (account->inst.kvp_data, "tax-US", "code", NULL);
02068 if (!value)
02069 return NULL;
02070
02071 return kvp_value_get_string (value);
02072 }
02073
02074 void
02075 xaccAccountSetTaxUSCode (Account *account, const char *code)
02076 {
02077 if (!account) return;
02078
02079 xaccAccountBeginEdit (account);
02080 kvp_frame_set_str (account->inst.kvp_data, "/tax-US/code", code);
02081
02082 mark_account (account);
02083 account->inst.dirty = TRUE;
02084 xaccAccountCommitEdit (account);
02085 }
02086
02087 const char *
02088 xaccAccountGetTaxUSPayerNameSource (Account *account)
02089 {
02090 if (!account) return NULL;
02091 return kvp_frame_get_string (account->inst.kvp_data, "/tax-US/payer-name-source");
02092 }
02093
02094 void
02095 xaccAccountSetTaxUSPayerNameSource (Account *account, const char *source)
02096 {
02097 if (!account) return;
02098
02099 xaccAccountBeginEdit (account);
02100 kvp_frame_set_str (account->inst.kvp_data, "/tax-US/payer-name-source", source);
02101
02102 mark_account (account);
02103 account->inst.dirty = TRUE;
02104 xaccAccountCommitEdit (account);
02105 }
02106
02107
02108
02109
02110 gboolean
02111 xaccAccountGetPlaceholder (Account *account)
02112 {
02113 KvpValue *kvp;
02114 char *setting;
02115
02116 if ( ( account ) &&
02117 ( kvp = kvp_frame_get_slot (account->inst.kvp_data, "placeholder" ) ) &&
02118 ( kvp_value_get_type (kvp) == KVP_TYPE_STRING ) &&
02119 ( setting = kvp_value_get_string(kvp) ) &&
02120 ( !strcmp( setting, "true" ) ) )
02121 return TRUE;
02122
02123 return FALSE;
02124 }
02125
02126 void
02127 xaccAccountSetPlaceholder (Account *account, gboolean option)
02128 {
02129 if (!account)
02130 return;
02131
02132 xaccAccountBeginEdit (account);
02133 kvp_frame_set_slot_nc(account->inst.kvp_data, "placeholder",
02134 kvp_value_new_string (option ? "true" : "false"));
02135
02136 mark_account (account);
02137 account->inst.dirty = TRUE;
02138 xaccAccountCommitEdit (account);
02139 }
02140
02141 GNCPlaceholderType
02142 xaccAccountGetDescendantPlaceholder (Account *account)
02143 {
02144 GList *descendants, *node;
02145
02146 if (!account)
02147 return PLACEHOLDER_NONE;
02148
02149 if (xaccAccountGetPlaceholder(account))
02150 return PLACEHOLDER_THIS;
02151
02152 descendants = xaccGroupGetSubAccounts(account->children);
02153 node = g_list_first(descendants);
02154 for ( ; node ; node = g_list_next(node) )
02155 {
02156 account = (Account *)node->data;
02157 if (xaccAccountGetPlaceholder(account)) return(PLACEHOLDER_CHILD);
02158 }
02159
02160 return PLACEHOLDER_NONE;
02161 }
02162
02163
02164
02165
02166 gboolean
02167 xaccAccountHasAncestor (Account *account, Account * ancestor)
02168 {
02169 Account *parent;
02170
02171 if ((account == NULL) || (ancestor == NULL))
02172 return FALSE;
02173
02174 parent = xaccAccountGetParentAccount(account);
02175 while (parent != NULL)
02176 {
02177 if (parent == ancestor)
02178 return TRUE;
02179
02180 parent = xaccAccountGetParentAccount(parent);
02181 }
02182
02183 return FALSE;
02184 }
02185
02186
02187
02188
02189
02190
02191
02192 #define GNC_RETURN_ENUM_AS_STRING(x) case (x): return #x;
02193
02194 const char *
02195 xaccAccountTypeEnumAsString(GNCAccountType type)
02196 {
02197 switch(type)
02198 {
02199 GNC_RETURN_ENUM_AS_STRING(NO_TYPE);
02200 GNC_RETURN_ENUM_AS_STRING(BANK);
02201 GNC_RETURN_ENUM_AS_STRING(CASH);
02202 GNC_RETURN_ENUM_AS_STRING(CREDIT);
02203 GNC_RETURN_ENUM_AS_STRING(ASSET);
02204 GNC_RETURN_ENUM_AS_STRING(LIABILITY);
02205 GNC_RETURN_ENUM_AS_STRING(STOCK);
02206 GNC_RETURN_ENUM_AS_STRING(MUTUAL);
02207 GNC_RETURN_ENUM_AS_STRING(CURRENCY);
02208 GNC_RETURN_ENUM_AS_STRING(INCOME);
02209 GNC_RETURN_ENUM_AS_STRING(EXPENSE);
02210 GNC_RETURN_ENUM_AS_STRING(EQUITY);
02211 GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
02212 GNC_RETURN_ENUM_AS_STRING(PAYABLE);
02213 GNC_RETURN_ENUM_AS_STRING(CHECKING);
02214 GNC_RETURN_ENUM_AS_STRING(SAVINGS);
02215 GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
02216 GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
02217 default:
02218 PERR ("asked to translate unknown account type %d.\n", type);
02219 break;
02220 }
02221 return(NULL);
02222 }
02223
02224 #undef GNC_RETURN_ENUM_AS_STRING
02225
02226 #define GNC_RETURN_ON_MATCH(x) \
02227 if(safe_strcmp(#x, (str)) == 0) { *type = x; return(TRUE); }
02228
02229 gboolean
02230 xaccAccountStringToType(const char* str, GNCAccountType *type)
02231 {
02232
02233 GNC_RETURN_ON_MATCH(NO_TYPE);
02234 GNC_RETURN_ON_MATCH(BANK);
02235 GNC_RETURN_ON_MATCH(CASH);
02236 GNC_RETURN_ON_MATCH(CREDIT);
02237 GNC_RETURN_ON_MATCH(ASSET);
02238 GNC_RETURN_ON_MATCH(LIABILITY);
02239 GNC_RETURN_ON_MATCH(STOCK);
02240 GNC_RETURN_ON_MATCH(MUTUAL);
02241 GNC_RETURN_ON_MATCH(CURRENCY);
02242 GNC_RETURN_ON_MATCH(INCOME);
02243 GNC_RETURN_ON_MATCH(EXPENSE);
02244 GNC_RETURN_ON_MATCH(EQUITY);
02245 GNC_RETURN_ON_MATCH(RECEIVABLE);
02246 GNC_RETURN_ON_MATCH(PAYABLE);
02247 GNC_RETURN_ON_MATCH(CHECKING);
02248 GNC_RETURN_ON_MATCH(SAVINGS);
02249 GNC_RETURN_ON_MATCH(MONEYMRKT);
02250 GNC_RETURN_ON_MATCH(CREDITLINE);
02251
02252 PERR("asked to translate unknown account type string %s.\n",
02253 str ? str : "(null)");
02254
02255 return(FALSE);
02256 }
02257
02258 #undef GNC_RETURN_ON_MATCH
02259
02260
02261 GNCAccountType
02262 xaccAccountStringToEnum(const char* str)
02263 {
02264 GNCAccountType type;
02265 gboolean rc;
02266 rc = xaccAccountStringToType(str, &type);
02267 if (FALSE == rc) return BAD_TYPE;
02268 return type;
02269 }
02270
02271
02272
02273
02274 static char *
02275 account_type_name[NUM_ACCOUNT_TYPES] = {
02276 N_("Bank"),
02277 N_("Cash"),
02278 N_("Asset"),
02279 N_("Credit Card"),
02280 N_("Liability"),
02281 N_("Stock"),
02282 N_("Mutual Fund"),
02283 N_("Currency"),
02284 N_("Income"),
02285 N_("Expense"),
02286 N_("Equity"),
02287 N_("A/Receivable"),
02288 N_("A/Payable")
02289
02290
02291
02292
02293
02294
02295 };
02296
02297 const char *
02298 xaccAccountGetTypeStr(GNCAccountType type) {
02299 if (0 > type) return "";
02300 if (NUM_ACCOUNT_TYPES <= type) return "";
02301 return _(account_type_name [type]);
02302 }
02303
02304 GNCAccountType
02305 xaccAccountGetTypeFromStr (const gchar *str)
02306 {
02307 gint type;
02308
02309 for (type = 0; type < NUM_ACCOUNT_TYPES; type++)
02310 {
02311 if (!safe_strcmp (str, _(account_type_name [type])))
02312 return type;
02313 }
02314
02315 PERR("asked to translate unknown account type string %s.\n",
02316 str ? str : "(null)");
02317
02318 return BAD_TYPE;
02319 }
02320
02321
02322
02323
02324
02325 gboolean
02326 xaccAccountTypesCompatible (GNCAccountType parent_type,
02327 GNCAccountType child_type)
02328 {
02329 gboolean compatible = FALSE;
02330
02331 switch(parent_type)
02332 {
02333 case BANK:
02334 case CASH:
02335 case ASSET:
02336 case STOCK:
02337 case MUTUAL:
02338 case CURRENCY:
02339 case CREDIT:
02340 case LIABILITY:
02341 case RECEIVABLE:
02342 case PAYABLE:
02343 compatible = ((child_type == BANK) ||
02344 (child_type == CASH) ||
02345 (child_type == ASSET) ||
02346 (child_type == STOCK) ||
02347 (child_type == MUTUAL) ||
02348 (child_type == CURRENCY) ||
02349 (child_type == CREDIT) ||
02350 (child_type == LIABILITY)||
02351 (child_type == RECEIVABLE)||
02352 (child_type == PAYABLE));
02353 break;
02354 case INCOME:
02355 case EXPENSE:
02356 compatible = ((child_type == INCOME) ||
02357 (child_type == EXPENSE));
02358 break;
02359 case EQUITY:
02360 compatible = (child_type == EQUITY);
02361 break;
02362 default:
02363 PERR("bad account type: %d", parent_type);
02364 break;
02365 }
02366
02367 return compatible;
02368 }
02369
02370
02371
02372
02373 gboolean
02374 xaccAccountGetReconcileLastDate (Account *account, time_t *last_date)
02375 {
02376 KvpValue *value;
02377
02378 if (!account)
02379 return FALSE;
02380
02381 value = kvp_frame_get_slot_path (account->inst.kvp_data,
02382 "reconcile-info", "last-date", NULL);
02383 if (!value)
02384 return FALSE;
02385
02386 if (kvp_value_get_type (value) == KVP_TYPE_GINT64)
02387 {
02388 if (last_date)
02389 *last_date = kvp_value_get_gint64 (value);
02390
02391 return TRUE;
02392 }
02393
02394 return FALSE;
02395 }
02396
02397
02398
02399
02400 void
02401 xaccAccountSetReconcileLastDate (Account *account, time_t last_date)
02402 {
02403 if (!account) return;
02404
02405 xaccAccountBeginEdit (account);
02406 kvp_frame_set_gint64 (account->inst.kvp_data,
02407 "/reconcile-info/last-date", last_date);
02408
02409 mark_account (account);
02410 account->inst.dirty = TRUE;
02411 xaccAccountCommitEdit (account);
02412 }
02413
02414
02415
02416
02417 gboolean
02418 xaccAccountGetReconcileLastInterval (Account *account, int *months, int *days)
02419 {
02420 KvpValue *value1, *value2;
02421
02422 if (!account)
02423 return FALSE;
02424
02425 value1 = kvp_frame_get_slot_path (account->inst.kvp_data, "reconcile-info",
02426 "last-interval", "months", NULL);
02427 value2 = kvp_frame_get_slot_path (account->inst.kvp_data, "reconcile-info",
02428 "last-interval", "days", NULL);
02429 if (!value1 || (kvp_value_get_type (value1) != KVP_TYPE_GINT64) ||
02430 !value2 || (kvp_value_get_type (value2) != KVP_TYPE_GINT64))
02431 return FALSE;
02432
02433 if (months)
02434 *months = kvp_value_get_gint64 (value1);
02435 if (days)
02436 *days = kvp_value_get_gint64 (value2);
02437 return TRUE;
02438 }
02439
02440
02441
02442
02443 void
02444 xaccAccountSetReconcileLastInterval (Account *account, int months, int days)
02445 {
02446 KvpFrame *frame;
02447 if (!account) return;
02448
02449 xaccAccountBeginEdit (account);
02450
02451 frame = kvp_frame_get_frame_slash (account->inst.kvp_data,
02452 "/reconcile-info/last-interval");
02453 g_assert(frame);
02454
02455 kvp_frame_set_gint64 (frame, "months", months);
02456 kvp_frame_set_gint64 (frame, "days", days);
02457
02458 mark_account (account);
02459 account->inst.dirty = TRUE;
02460 xaccAccountCommitEdit (account);
02461 }
02462
02463
02464
02465
02466 gboolean
02467 xaccAccountGetReconcilePostponeDate (Account *account,
02468 time_t *postpone_date)
02469 {
02470 KvpValue *value;
02471
02472 if (!account)
02473 return FALSE;
02474
02475 value = kvp_frame_get_slot_path (account->inst.kvp_data,
02476 "reconcile-info", "postpone", "date", NULL);
02477 if (!value)
02478 return FALSE;
02479
02480 if (kvp_value_get_type (value) == KVP_TYPE_GINT64)
02481 {
02482 if (postpone_date)
02483 *postpone_date = kvp_value_get_gint64 (value);
02484
02485 return TRUE;
02486 }
02487
02488 return FALSE;
02489 }
02490
02491
02492
02493
02494 void
02495 xaccAccountSetReconcilePostponeDate (Account *account,
02496 time_t postpone_date)
02497 {
02498 if (!account) return;
02499
02500 xaccAccountBeginEdit (account);
02501
02502
02503 kvp_frame_set_gint64 (account->inst.kvp_data,
02504 "/reconcile-info/postpone/date", postpone_date);
02505
02506 mark_account (account);
02507 account->inst.dirty = TRUE;
02508 xaccAccountCommitEdit (account);
02509 }
02510
02511
02512
02513
02514 gboolean
02515 xaccAccountGetReconcilePostponeBalance (Account *account,
02516 gnc_numeric *balance)
02517 {
02518 KvpValue *value;
02519
02520 if (!account)
02521 return FALSE;
02522
02523 value = kvp_frame_get_slot_path (account->inst.kvp_data,
02524 "reconcile-info", "postpone", "balance",
02525 NULL);
02526 if (!value)
02527 return FALSE;
02528
02529 if (kvp_value_get_type (value) == KVP_TYPE_NUMERIC)
02530 {
02531 if (balance)
02532 *balance = kvp_value_get_numeric (value);
02533
02534 return TRUE;
02535 }
02536
02537 return FALSE;
02538 }
02539
02540
02541
02542
02543 void
02544 xaccAccountSetReconcilePostponeBalance (Account *account,
02545 gnc_numeric balance)
02546 {
02547 if (!account) return;
02548
02549 xaccAccountBeginEdit (account);
02550 kvp_frame_set_gnc_numeric (account->inst.kvp_data,
02551 "/reconcile-info/postpone/balance", balance);
02552
02553 mark_account (account);
02554 account->inst.dirty = TRUE;
02555 xaccAccountCommitEdit (account);
02556 }
02557
02558
02559
02560
02561
02562 void
02563 xaccAccountClearReconcilePostpone (Account *account)
02564 {
02565 if (!account)
02566 return;
02567
02568 xaccAccountBeginEdit (account);
02569 {
02570 kvp_frame_set_slot_path (account->inst.kvp_data, NULL,
02571 "reconcile-info", "postpone", NULL);
02572
02573 mark_account (account);
02574 }
02575 account->inst.dirty = TRUE;
02576 xaccAccountCommitEdit (account);
02577 }
02578
02579
02580
02581
02582
02583
02584
02585
02586 gboolean
02587 xaccAccountGetAutoInterestXfer (Account *account, gboolean default_value)
02588 {
02589 KvpValue *value = NULL;
02590 char *setting = NULL;
02591 gboolean result = default_value;
02592
02593 if ( ( account ) &&
02594 ( value = kvp_frame_get_slot_path (account->inst.kvp_data,
02595 "reconcile-info",
02596 "auto-interest-transfer",
02597 NULL) ) &&
02598 ( kvp_value_get_type (value) == KVP_TYPE_STRING ) &&
02599 ( setting = kvp_value_get_string(value) ) )
02600 {
02601 if( !strcmp( setting, "true" ) )
02602 result = TRUE;
02603 else if( !strcmp( setting, "false" ) )
02604 result = FALSE;
02605 }
02606
02607 return (result);
02608 }
02609
02610
02611
02612
02613 void
02614 xaccAccountSetAutoInterestXfer (Account *account, gboolean option)
02615 {
02616 if (!account)
02617 return;
02618
02619 xaccAccountBeginEdit (account);
02620
02621
02622 kvp_frame_set_str (account->inst.kvp_data,
02623 "/reconcile-info/auto-interest-transfer",
02624 (option ? "true" : "false"));
02625
02626 mark_account (account);
02627 account->inst.dirty = TRUE;
02628 xaccAccountCommitEdit (account);
02629 }
02630
02631
02632
02633
02634 const char *
02635 xaccAccountGetLastNum (Account *account)
02636 {
02637 KvpValue *value;
02638
02639 if (!account)
02640 return FALSE;
02641
02642 value = kvp_frame_get_slot (account->inst.kvp_data, "last-num");
02643 if (!value)
02644 return FALSE;
02645
02646 return kvp_value_get_string (value);
02647 }
02648
02649
02650
02651
02652 void
02653 xaccAccountSetLastNum (Account *account, const char *num)
02654 {
02655 if (!account)
02656 return;
02657
02658 xaccAccountBeginEdit (account);
02659 kvp_frame_set_slot_nc (account->inst.kvp_data, "last-num",
02660 kvp_value_new_string (num));
02661 mark_account (account);
02662 account->inst.dirty = TRUE;
02663 xaccAccountCommitEdit (account);
02664 }
02665
02666
02667
02668
02669 void
02670 dxaccAccountSetPriceSrc(Account *acc, const char *src)
02671 {
02672 if(!acc) return;
02673
02674 xaccAccountBeginEdit(acc);
02675 {
02676 GNCAccountType t = acc->type;
02677
02678 if((t == STOCK) || (t == MUTUAL) || (t == CURRENCY)) {
02679 kvp_frame_set_slot_nc(acc->inst.kvp_data,
02680 "old-price-source",
02681 src ? kvp_value_new_string(src) : NULL);
02682 mark_account (acc);
02683 }
02684 }
02685 acc->inst.dirty = TRUE;
02686 xaccAccountCommitEdit(acc);
02687 }
02688
02689
02690
02691
02692 const char*
02693 dxaccAccountGetPriceSrc(Account *acc)
02694 {
02695 GNCAccountType t;
02696 if(!acc) return NULL;
02697
02698 t = acc->type;
02699 if((t == STOCK) || (t == MUTUAL) || (t == CURRENCY))
02700 {
02701 KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data, "old-price-source");
02702 if(value) return (kvp_value_get_string(value));
02703 }
02704 return NULL;
02705 }
02706
02707
02708
02709
02710 void
02711 dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
02712 {
02713 if(!acc) return;
02714
02715 xaccAccountBeginEdit(acc);
02716 {
02717 GNCAccountType t = acc->type;
02718
02719 if((t == STOCK) || (t == MUTUAL) || (t == CURRENCY)) {
02720 kvp_frame_set_slot_nc(acc->inst.kvp_data,
02721 "old-quote-tz",
02722 tz ? kvp_value_new_string(tz) : NULL);
02723 mark_account (acc);
02724 }
02725 }
02726 acc->inst.dirty = TRUE;
02727 xaccAccountCommitEdit(acc);
02728 }
02729
02730
02731
02732
02733 const char*
02734 dxaccAccountGetQuoteTZ(Account *acc)
02735 {
02736 GNCAccountType t;
02737 if(!acc) return NULL;
02738
02739 t = acc->type;
02740 if((t == STOCK) || (t == MUTUAL) || (t == CURRENCY))
02741 {
02742 KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data, "old-quote-tz");
02743 if(value) return (kvp_value_get_string(value));
02744 }
02745 return NULL;
02746 }
02747
02748
02749
02750
02751 void
02752 xaccAccountSetReconcileChildrenStatus(Account *account, gboolean status)
02753 {
02754 if (!account) return;
02755
02756 xaccAccountBeginEdit (account);
02757
02758
02759 kvp_frame_set_gint64 (account->inst.kvp_data,
02760 "/reconcile-info/include-children", status);
02761
02762 account->inst.dirty = TRUE;
02763 xaccAccountCommitEdit (account);
02764 }
02765
02766
02767
02768
02769 gboolean
02770 xaccAccountGetReconcileChildrenStatus(Account *account)
02771 {
02772 KvpValue *status;
02773 if (!account)
02774 return FALSE;
02775
02776
02777
02778
02779 status = kvp_frame_get_slot_path (account->inst.kvp_data,
02780 "reconcile-info",
02781 "include-children",
02782 NULL);
02783 if (!status)
02784 return FALSE;
02785 return kvp_value_get_gint64 (status);
02786 }
02787
02788
02789
02790
02791 gint
02792 xaccAccountForEachTransaction(Account *acc,
02793 TransactionCallback proc,
02794 void *data)
02795 {
02796 if(!acc || !proc) return 0;
02797 xaccAccountBeginStagedTransactionTraversals (acc);
02798 return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
02799 }
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809 static void
02810 finder_help_function(Account *account,
02811 const char *description,
02812 Split **split,
02813 Transaction **trans )
02814 {
02815 GList *slp;
02816
02817
02818 if (split) *split = NULL;
02819 if (trans) *trans = NULL;
02820
02821
02822 if (account == NULL) return;
02823
02824
02825
02826
02827 for (slp = g_list_last (account->splits);
02828 slp;
02829 slp = slp->prev)
02830 {
02831 Split *lsplit = slp->data;
02832 Transaction *ltrans = xaccSplitGetParent(lsplit);
02833
02834 if (safe_strcmp (description, xaccTransGetDescription (ltrans)) == 0)
02835 {
02836 if( split ) *split = lsplit;
02837 if( trans ) *trans = ltrans;
02838 return;
02839 }
02840 }
02841 }
02842
02843 Split *
02844 xaccAccountFindSplitByDesc(Account *account, const char *description)
02845 {
02846 Split *split;
02847
02848
02849 finder_help_function(account, description, &split, NULL );
02850
02851 return( split );
02852 }
02853
02854
02855
02856
02857
02858 Transaction *
02859 xaccAccountFindTransByDesc(Account *account, const char *description)
02860 {
02861 Transaction *trans;
02862
02863
02864 finder_help_function(account, description, NULL, &trans );
02865
02866 return( trans );
02867 }
02868
02869
02870
02871
02872 static QofObject account_object_def = {
02873 interface_version: QOF_OBJECT_VERSION,
02874 e_type: GNC_ID_ACCOUNT,
02875 type_label: "Account",
02876 create: (gpointer)xaccMallocAccount,
02877 book_begin: NULL,
02878 book_end: NULL,
02879 is_dirty: NULL,
02880 mark_clean: NULL,
02881 foreach: qof_collection_foreach,
02882 printable: (const char* (*)(gpointer)) xaccAccountGetName,
02883 version_cmp: (int (*)(gpointer,gpointer)) qof_instance_version_cmp,
02884 };
02885
02886 gboolean xaccAccountRegister (void)
02887 {
02888 static QofParam params[] = {
02889 { ACCOUNT_NAME_, QOF_TYPE_STRING, (QofAccessFunc)xaccAccountGetName, (QofSetterFunc) xaccAccountSetName },
02890 { ACCOUNT_CODE_, QOF_TYPE_STRING, (QofAccessFunc)xaccAccountGetCode, (QofSetterFunc) xaccAccountSetCode },
02891 { ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING, (QofAccessFunc)xaccAccountGetDescription, (QofSetterFunc) xaccAccountSetDescription },
02892 { ACCOUNT_NOTES_, QOF_TYPE_STRING, (QofAccessFunc)xaccAccountGetNotes, (QofSetterFunc) xaccAccountSetNotes },
02893 { ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetPresentBalance, NULL },
02894 { ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetBalance, NULL },
02895 { ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetClearedBalance, NULL },
02896 { ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetReconciledBalance, NULL },
02897 { ACCOUNT_TYPE_, QOF_TYPE_STRING, (QofAccessFunc)qofAccountGetTypeString, (QofSetterFunc)qofAccountSetType },
02898 { ACCOUNT_FUTURE_MINIMUM_,QOF_TYPE_NUMERIC, (QofAccessFunc)xaccAccountGetProjectedMinimumBalance, NULL },
02899 { ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN, (QofAccessFunc)xaccAccountGetTaxRelated, (QofSetterFunc) xaccAccountSetTaxRelated },
02900 { ACCOUNT_SCU, QOF_TYPE_INT32, (QofAccessFunc)xaccAccountGetCommoditySCU,(QofSetterFunc)xaccAccountSetCommoditySCU },
02901 { ACCOUNT_NSCU, QOF_TYPE_BOOLEAN, (QofAccessFunc)xaccAccountGetNonStdSCU, (QofSetterFunc)xaccAccountSetNonStdSCU },
02902 { ACCOUNT_PARENT, GNC_ID_ACCOUNT, (QofAccessFunc)xaccAccountGetParentAccount,(QofSetterFunc)qofAccountSetParent },
02903 { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
02904 { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
02905 { ACCOUNT_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
02906 { NULL },
02907 };
02908
02909 qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc)xaccAccountOrder, params);
02910
02911 return qof_object_register (&account_object_def);
02912 }
02913
02914