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
00026 #include "config.h"
00027
00028 #include <glib.h>
00029 #include <glib/gi18n.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032
00033 #include "AccountP.h"
00034 #include "Split.h"
00035 #include "Transaction.h"
00036 #include "TransactionP.h"
00037 #include "gnc-event.h"
00038 #include "gnc-glib-utils.h"
00039 #include "gnc-lot.h"
00040 #include "gnc-pricedb.h"
00041
00042 #define GNC_ID_ROOT_ACCOUNT "RootAccount"
00043
00044 static QofLogModule log_module = GNC_MOD_ACCOUNT;
00045
00046
00047 static gchar account_separator[8] = ".";
00048 gunichar account_uc_separator = ':';
00049
00050 enum
00051 {
00052 LAST_SIGNAL
00053 };
00054
00055 enum
00056 {
00057 PROP_0,
00058 PROP_NAME,
00059 PROP_FULL_NAME,
00060 PROP_CODE,
00061 PROP_DESCRIPTION,
00062 PROP_COLOR,
00063 PROP_NOTES,
00064 PROP_TYPE,
00065
00066 PROP_COMMODITY,
00067 PROP_COMMODITY_SCU,
00068 PROP_NON_STD_SCU,
00069 PROP_SORT_DIRTY,
00070 PROP_BALANCE_DIRTY,
00071 PROP_START_BALANCE,
00072 PROP_START_CLEARED_BALANCE,
00073 PROP_START_RECONCILED_BALANCE,
00074 PROP_END_BALANCE,
00075 PROP_END_CLEARED_BALANCE,
00076 PROP_END_RECONCILED_BALANCE,
00077
00078 PROP_POLICY,
00079 PROP_MARK,
00080 PROP_TAX_RELATED,
00081 PROP_TAX_CODE,
00082 PROP_TAX_SOURCE,
00083 PROP_TAX_COPY_NUMBER,
00084
00085 PROP_HIDDEN,
00086 PROP_PLACEHOLDER,
00087 };
00088
00089 typedef struct AccountPrivate
00090 {
00091
00092
00093
00094
00095 char *accountName;
00096
00097
00098
00099
00100
00101
00102
00103
00104 char *accountCode;
00105
00106
00107
00108
00109
00110 char *description;
00111
00112
00113
00114
00115
00116
00117
00118 GNCAccountType type;
00119
00120
00121
00122
00123
00124
00125 gnc_commodity * commodity;
00126 int commodity_scu;
00127 gboolean non_standard_scu;
00128
00129
00130
00131
00132 Account *parent;
00133 GList *children;
00134
00135
00136 gnc_numeric starting_balance;
00137 gnc_numeric starting_cleared_balance;
00138 gnc_numeric starting_reconciled_balance;
00139
00140
00141 gnc_numeric balance;
00142 gnc_numeric cleared_balance;
00143 gnc_numeric reconciled_balance;
00144
00145 gboolean balance_dirty;
00146
00147 GList *splits;
00148 gboolean sort_dirty;
00149
00150 LotList *lots;
00151 GNCPolicy *policy;
00152
00153
00154
00155
00156 short mark;
00157 } AccountPrivate;
00158
00159 #define GET_PRIVATE(o) \
00160 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_ACCOUNT, AccountPrivate))
00161
00162
00163
00164
00165
00166
00167
00168
00169 static void xaccAccountBringUpToDate (Account *acc);
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 const gchar *
00180 gnc_get_account_separator_string (void)
00181 {
00182 return account_separator;
00183 }
00184
00185 gunichar
00186 gnc_get_account_separator (void)
00187 {
00188 return account_uc_separator;
00189 }
00190
00191 void
00192 gnc_set_account_separator (const gchar *separator)
00193 {
00194 gunichar uc;
00195 gint count;
00196
00197 uc = g_utf8_get_char_validated(separator, -1);
00198 if ((uc == (gunichar) - 2) || (uc == (gunichar) - 1) || g_unichar_isalnum(uc))
00199 {
00200 account_uc_separator = ':';
00201 strcpy(account_separator, ":");
00202 return;
00203 }
00204
00205 account_uc_separator = uc;
00206 count = g_unichar_to_utf8(uc, account_separator);
00207 account_separator[count] = '\0';
00208 }
00209
00210 gchar *gnc_account_name_violations_errmsg (const gchar *separator, GList* invalid_account_names)
00211 {
00212 GList *node;
00213 gchar *message = NULL;
00214 gchar *account_list = NULL;
00215
00216 if ( !invalid_account_names )
00217 return NULL;
00218
00219 for ( node = invalid_account_names; node; node = g_list_next(node))
00220 {
00221 if ( !account_list )
00222 account_list = node->data;
00223 else
00224 {
00225 gchar *tmp_list = NULL;
00226
00227 tmp_list = g_strconcat (account_list, "\n", node->data, NULL );
00228 g_free ( account_list );
00229 account_list = tmp_list;
00230 }
00231 }
00232
00233
00234
00235
00236
00237 message = g_strdup_printf(
00238 _("The separator character \"%s\" is used in one or more account names.\n\n"
00239 "This will result in unexpected behaviour. "
00240 "Either change the account names or choose another separator character.\n\n"
00241 "Below you will find the list of invalid account names:\n"
00242 "%s"), separator, account_list );
00243 g_free ( account_list );
00244 return message;
00245 }
00246
00247 GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator)
00248 {
00249 Account *root_account = gnc_book_get_root_account(book);
00250 GList *accounts, *node;
00251 GList *invalid_list = NULL;
00252
00253 g_return_val_if_fail (separator != NULL, NULL);
00254
00255 if (root_account == NULL)
00256 return NULL;
00257
00258 accounts = gnc_account_get_descendants (root_account);
00259 for (node = accounts; node; node = g_list_next(node))
00260 {
00261 Account *acct = (Account*)node->data;
00262 gchar *acct_name = g_strdup ( xaccAccountGetName ( acct ) );
00263
00264 if ( g_strstr_len ( acct_name, -1, separator ) )
00265 invalid_list = g_list_prepend ( invalid_list, (gpointer) acct_name );
00266 else
00267 g_free ( acct_name );
00268 }
00269 if (accounts != NULL)
00270 {
00271 g_list_free(accounts);
00272 }
00273
00274 return invalid_list;
00275 }
00276
00277
00278
00279
00280 G_INLINE_FUNC void mark_account (Account *acc);
00281 void
00282 mark_account (Account *acc)
00283 {
00284 qof_instance_set_dirty(&acc->inst);
00285 }
00286
00287
00288
00289
00290
00291 G_DEFINE_TYPE(Account, gnc_account, QOF_TYPE_INSTANCE)
00292
00293 static void
00294 gnc_account_init(Account* acc)
00295 {
00296 AccountPrivate *priv;
00297
00298 priv = GET_PRIVATE(acc);
00299 priv->parent = NULL;
00300 priv->children = NULL;
00301
00302 priv->accountName = CACHE_INSERT("");
00303 priv->accountCode = CACHE_INSERT("");
00304 priv->description = CACHE_INSERT("");
00305
00306 priv->type = ACCT_TYPE_NONE;
00307
00308 priv->mark = 0;
00309
00310 priv->policy = xaccGetFIFOPolicy();
00311 priv->lots = NULL;
00312
00313 priv->commodity = NULL;
00314 priv->commodity_scu = 0;
00315 priv->non_standard_scu = FALSE;
00316
00317 priv->balance = gnc_numeric_zero();
00318 priv->cleared_balance = gnc_numeric_zero();
00319 priv->reconciled_balance = gnc_numeric_zero();
00320 priv->starting_balance = gnc_numeric_zero();
00321 priv->starting_cleared_balance = gnc_numeric_zero();
00322 priv->starting_reconciled_balance = gnc_numeric_zero();
00323 priv->balance_dirty = FALSE;
00324
00325 priv->splits = NULL;
00326 priv->sort_dirty = FALSE;
00327 }
00328
00329 static void
00330 gnc_account_dispose (GObject *acctp)
00331 {
00332 G_OBJECT_CLASS(gnc_account_parent_class)->dispose(acctp);
00333 }
00334
00335 static void
00336 gnc_account_finalize(GObject* acctp)
00337 {
00338 G_OBJECT_CLASS(gnc_account_parent_class)->finalize(acctp);
00339 }
00340
00341 static void
00342 gnc_account_get_property (GObject *object,
00343 guint prop_id,
00344 GValue *value,
00345 GParamSpec *pspec)
00346 {
00347 Account *account;
00348 AccountPrivate *priv;
00349
00350 g_return_if_fail(GNC_IS_ACCOUNT(object));
00351
00352 account = GNC_ACCOUNT(object);
00353 priv = GET_PRIVATE(account);
00354 switch (prop_id)
00355 {
00356 case PROP_NAME:
00357 g_value_set_string(value, priv->accountName);
00358 break;
00359 case PROP_FULL_NAME:
00360 g_value_take_string(value, gnc_account_get_full_name(account));
00361 break;
00362 case PROP_CODE:
00363 g_value_set_string(value, priv->accountCode);
00364 break;
00365 case PROP_DESCRIPTION:
00366 g_value_set_string(value, priv->description);
00367 break;
00368 case PROP_COLOR:
00369 g_value_set_string(value, xaccAccountGetColor(account));
00370 break;
00371 case PROP_NOTES:
00372 g_value_set_string(value, xaccAccountGetNotes(account));
00373 break;
00374 case PROP_TYPE:
00375
00376 g_value_set_int(value, priv->type);
00377 break;
00378 case PROP_COMMODITY:
00379 g_value_set_object(value, priv->commodity);
00380 break;
00381 case PROP_COMMODITY_SCU:
00382 g_value_set_int(value, priv->commodity_scu);
00383 break;
00384 case PROP_NON_STD_SCU:
00385 g_value_set_boolean(value, priv->non_standard_scu);
00386 break;
00387 case PROP_SORT_DIRTY:
00388 g_value_set_boolean(value, priv->sort_dirty);
00389 break;
00390 case PROP_BALANCE_DIRTY:
00391 g_value_set_boolean(value, priv->balance_dirty);
00392 break;
00393 case PROP_START_BALANCE:
00394 g_value_set_boxed(value, &priv->starting_balance);
00395 break;
00396 case PROP_START_CLEARED_BALANCE:
00397 g_value_set_boxed(value, &priv->starting_cleared_balance);
00398 break;
00399 case PROP_START_RECONCILED_BALANCE:
00400 g_value_set_boxed(value, &priv->starting_reconciled_balance);
00401 break;
00402 case PROP_END_BALANCE:
00403 g_value_set_boxed(value, &priv->balance);
00404 break;
00405 case PROP_END_CLEARED_BALANCE:
00406 g_value_set_boxed(value, &priv->cleared_balance);
00407 break;
00408 case PROP_END_RECONCILED_BALANCE:
00409 g_value_set_boxed(value, &priv->reconciled_balance);
00410 break;
00411 case PROP_POLICY:
00412
00413 g_value_set_pointer(value, priv->policy);
00414 break;
00415 case PROP_MARK:
00416 g_value_set_int(value, priv->mark);
00417 break;
00418 case PROP_TAX_RELATED:
00419 g_value_set_boolean(value, xaccAccountGetTaxRelated(account));
00420 break;
00421 case PROP_TAX_CODE:
00422 g_value_set_string(value, xaccAccountGetTaxUSCode(account));
00423 break;
00424 case PROP_TAX_SOURCE:
00425 g_value_set_string(value,
00426 xaccAccountGetTaxUSPayerNameSource(account));
00427 break;
00428 case PROP_TAX_COPY_NUMBER:
00429 g_value_set_int64(value,
00430 xaccAccountGetTaxUSCopyNumber(account));
00431 break;
00432 case PROP_HIDDEN:
00433 g_value_set_boolean(value, xaccAccountGetHidden(account));
00434 break;
00435 case PROP_PLACEHOLDER:
00436 g_value_set_boolean(value, xaccAccountGetPlaceholder(account));
00437 break;
00438 default:
00439 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00440 break;
00441 }
00442 }
00443
00444 static void
00445 gnc_account_set_property (GObject *object,
00446 guint prop_id,
00447 const GValue *value,
00448 GParamSpec *pspec)
00449 {
00450 Account *account;
00451 gnc_numeric *number;
00452
00453 g_return_if_fail(GNC_IS_ACCOUNT(object));
00454
00455 account = GNC_ACCOUNT(object);
00456
00457 switch (prop_id)
00458 {
00459 case PROP_NAME:
00460 xaccAccountSetName(account, g_value_get_string(value));
00461 break;
00462 case PROP_CODE:
00463 xaccAccountSetCode(account, g_value_get_string(value));
00464 break;
00465 case PROP_DESCRIPTION:
00466 xaccAccountSetDescription(account, g_value_get_string(value));
00467 break;
00468 case PROP_COLOR:
00469 xaccAccountSetColor(account, g_value_get_string(value));
00470 break;
00471 case PROP_NOTES:
00472 xaccAccountSetNotes(account, g_value_get_string(value));
00473 break;
00474 case PROP_TYPE:
00475
00476 xaccAccountSetType(account, g_value_get_int(value));
00477 break;
00478 case PROP_COMMODITY:
00479 xaccAccountSetCommodity(account, g_value_get_object(value));
00480 break;
00481 case PROP_COMMODITY_SCU:
00482 xaccAccountSetCommoditySCU(account, g_value_get_int(value));
00483 break;
00484 case PROP_NON_STD_SCU:
00485 xaccAccountSetNonStdSCU(account, g_value_get_boolean(value));
00486 break;
00487 case PROP_SORT_DIRTY:
00488 gnc_account_set_sort_dirty(account);
00489 break;
00490 case PROP_BALANCE_DIRTY:
00491 gnc_account_set_balance_dirty(account);
00492 break;
00493 case PROP_START_BALANCE:
00494 number = g_value_get_boxed(value);
00495 gnc_account_set_start_balance(account, *number);
00496 break;
00497 case PROP_START_CLEARED_BALANCE:
00498 number = g_value_get_boxed(value);
00499 gnc_account_set_start_cleared_balance(account, *number);
00500 break;
00501 case PROP_START_RECONCILED_BALANCE:
00502 number = g_value_get_boxed(value);
00503 gnc_account_set_start_reconciled_balance(account, *number);
00504 break;
00505 case PROP_POLICY:
00506 gnc_account_set_policy(account, g_value_get_pointer(value));
00507 break;
00508 case PROP_MARK:
00509 xaccAccountSetMark(account, g_value_get_int(value));
00510 break;
00511 case PROP_TAX_RELATED:
00512 xaccAccountSetTaxRelated(account, g_value_get_boolean(value));
00513 break;
00514 case PROP_TAX_CODE:
00515 xaccAccountSetTaxUSCode(account, g_value_get_string(value));
00516 break;
00517 case PROP_TAX_SOURCE:
00518 xaccAccountSetTaxUSPayerNameSource(account,
00519 g_value_get_string(value));
00520 case PROP_TAX_COPY_NUMBER:
00521 xaccAccountSetTaxUSCopyNumber(account,
00522 g_value_get_int64(value));
00523 break;
00524 case PROP_HIDDEN:
00525 xaccAccountSetHidden(account, g_value_get_boolean(value));
00526 break;
00527 case PROP_PLACEHOLDER:
00528 xaccAccountSetPlaceholder(account, g_value_get_boolean(value));
00529 break;
00530 default:
00531 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00532 break;
00533 }
00534 }
00535
00536 static void
00537 gnc_account_class_init (AccountClass *klass)
00538 {
00539 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00540
00541 gobject_class->dispose = gnc_account_dispose;
00542 gobject_class->finalize = gnc_account_finalize;
00543 gobject_class->set_property = gnc_account_set_property;
00544 gobject_class->get_property = gnc_account_get_property;
00545
00546 g_type_class_add_private(klass, sizeof(AccountPrivate));
00547
00548 g_object_class_install_property
00549 (gobject_class,
00550 PROP_NAME,
00551 g_param_spec_string ("name",
00552 "Account Name",
00553 "The accountName is an arbitrary string "
00554 "assigned by the user. It is intended to "
00555 "a short, 5 to 30 character long string "
00556 "that is displayed by the GUI as the "
00557 "account mnemonic. Account names may be "
00558 "repeated. but no two accounts that share "
00559 "a parent may have the same name.",
00560 NULL,
00561 G_PARAM_READWRITE));
00562
00563 g_object_class_install_property
00564 (gobject_class,
00565 PROP_FULL_NAME,
00566 g_param_spec_string ("fullname",
00567 "Full Account Name",
00568 "The name of the account concatenated with "
00569 "all its parent account names to indicate "
00570 "a unique account.",
00571 NULL,
00572 G_PARAM_READABLE));
00573
00574 g_object_class_install_property
00575 (gobject_class,
00576 PROP_CODE,
00577 g_param_spec_string ("code",
00578 "Account Code",
00579 "The account code is an arbitrary string "
00580 "assigned by the user. It is intended to "
00581 "be reporting code that is a synonym for "
00582 "the accountName.",
00583 NULL,
00584 G_PARAM_READWRITE));
00585
00586 g_object_class_install_property
00587 (gobject_class,
00588 PROP_DESCRIPTION,
00589 g_param_spec_string ("description",
00590 "Account Description",
00591 "The account description is an arbitrary "
00592 "string assigned by the user. It is intended "
00593 "to be a longer, 1-5 sentence description of "
00594 "what this account is all about.",
00595 NULL,
00596 G_PARAM_READWRITE));
00597
00598 g_object_class_install_property
00599 (gobject_class,
00600 PROP_COLOR,
00601 g_param_spec_string ("color",
00602 "Account Color",
00603 "The account color is a color string assigned "
00604 "by the user. It is intended to highlight the "
00605 "account based on the users wishes.",
00606 NULL,
00607 G_PARAM_READWRITE));
00608
00609 g_object_class_install_property
00610 (gobject_class,
00611 PROP_NOTES,
00612 g_param_spec_string ("notes",
00613 "Account Notes",
00614 "The account notes is an arbitrary provided "
00615 "for the user to attach any other text that "
00616 "they would like to associate with the account.",
00617 NULL,
00618 G_PARAM_READWRITE));
00619
00620 g_object_class_install_property
00621 (gobject_class,
00622 PROP_TYPE,
00623 g_param_spec_int ("type",
00624 "Account Type",
00625 "The account type, picked from the enumerated list "
00626 "that includes ACCT_TYPE_BANK, ACCT_TYPE_STOCK, "
00627 "ACCT_TYPE_CREDIT, ACCT_TYPE_INCOME, etc.",
00628 ACCT_TYPE_NONE,
00629 NUM_ACCOUNT_TYPES - 1,
00630 ACCT_TYPE_BANK,
00631 G_PARAM_READWRITE));
00632
00633 g_object_class_install_property
00634 (gobject_class,
00635 PROP_COMMODITY,
00636 g_param_spec_object ("commodity",
00637 "Commodity",
00638 "The commodity field denotes the kind of "
00639 "'stuff' stored in this account, whether "
00640 "it is USD, gold, stock, etc.",
00641 GNC_TYPE_COMMODITY,
00642 G_PARAM_READWRITE));
00643
00644 g_object_class_install_property
00645 (gobject_class,
00646 PROP_COMMODITY_SCU,
00647 g_param_spec_int ("commodity-scu",
00648 "Commodity SCU",
00649 "The smallest fraction of the commodity that is "
00650 "tracked. This number is used as the denominator "
00651 "value in 1/x, so a value of 100 says that the "
00652 "commodity can be divided into hundreths. E.G."
00653 "1 USD can be divided into 100 cents.",
00654 0,
00655 G_MAXINT32,
00656 1000000,
00657 G_PARAM_READWRITE));
00658
00659 g_object_class_install_property
00660 (gobject_class,
00661 PROP_NON_STD_SCU,
00662 g_param_spec_boolean ("non-std-scu",
00663 "Non-std SCU",
00664 "TRUE if the account SCU doesn't match "
00665 "the commodity SCU. This indicates a case "
00666 "where the two were accidentally set to "
00667 "mismatched values in older versions of "
00668 "GnuCash.",
00669 FALSE,
00670 G_PARAM_READWRITE));
00671
00672 g_object_class_install_property
00673 (gobject_class,
00674 PROP_SORT_DIRTY,
00675 g_param_spec_boolean("sort-dirty",
00676 "Sort Dirty",
00677 "TRUE if the splits in the account needs to be "
00678 "resorted. This flag is set by the accounts "
00679 "code for certain internal modifications, or "
00680 "when external code calls the engine to say a "
00681 "split has been modified in a way that may "
00682 "affect the sort order of the account. Note: "
00683 "This value can only be set to TRUE.",
00684 FALSE,
00685 G_PARAM_READWRITE));
00686
00687 g_object_class_install_property
00688 (gobject_class,
00689 PROP_BALANCE_DIRTY,
00690 g_param_spec_boolean("balance-dirty",
00691 "Balance Dirty",
00692 "TRUE if the running balances in the account "
00693 "needs to be recalculated. This flag is set "
00694 "by the accounts code for certain internal "
00695 "modifications, or when external code calls "
00696 "the engine to say a split has been modified. "
00697 "Note: This value can only be set to TRUE.",
00698 FALSE,
00699 G_PARAM_READWRITE));
00700
00701 g_object_class_install_property
00702 (gobject_class,
00703 PROP_START_BALANCE,
00704 g_param_spec_boxed("start-balance",
00705 "Starting Balance",
00706 "The starting balance for the account. This "
00707 "parameter is intended for use with backends that "
00708 "do not return the complete list of splits for an "
00709 "account, but rather return a partial list. In "
00710 "such a case, the backend will typically return "
00711 "all of the splits after some certain date, and "
00712 "the 'starting balance' will represent the "
00713 "summation of the splits up to that date.",
00714 GNC_TYPE_NUMERIC,
00715 G_PARAM_READWRITE));
00716
00717 g_object_class_install_property
00718 (gobject_class,
00719 PROP_START_CLEARED_BALANCE,
00720 g_param_spec_boxed("start-cleared-balance",
00721 "Starting Cleared Balance",
00722 "The starting cleared balance for the account. "
00723 "This parameter is intended for use with backends "
00724 "that do not return the complete list of splits "
00725 "for an account, but rather return a partial "
00726 "list. In such a case, the backend will "
00727 "typically return all of the splits after "
00728 "some certain date, and the 'starting cleared "
00729 "balance' will represent the summation of the "
00730 "splits up to that date.",
00731 GNC_TYPE_NUMERIC,
00732 G_PARAM_READWRITE));
00733
00734 g_object_class_install_property
00735 (gobject_class,
00736 PROP_START_RECONCILED_BALANCE,
00737 g_param_spec_boxed("start-reconciled-balance",
00738 "Starting Reconciled Balance",
00739 "The starting reconciled balance for the "
00740 "account. This parameter is intended for use "
00741 "with backends that do not return the complete "
00742 "list of splits for an account, but rather return "
00743 "a partial list. In such a case, the backend "
00744 "will typically return all of the splits after "
00745 "some certain date, and the 'starting reconciled "
00746 "balance' will represent the summation of the "
00747 "splits up to that date.",
00748 GNC_TYPE_NUMERIC,
00749 G_PARAM_READWRITE));
00750
00751 g_object_class_install_property
00752 (gobject_class,
00753 PROP_END_BALANCE,
00754 g_param_spec_boxed("end-balance",
00755 "Ending Account Balance",
00756 "This is the current ending balance for the "
00757 "account. It is computed from the sum of the "
00758 "starting balance and all splits in the account.",
00759 GNC_TYPE_NUMERIC,
00760 G_PARAM_READABLE));
00761
00762 g_object_class_install_property
00763 (gobject_class,
00764 PROP_END_CLEARED_BALANCE,
00765 g_param_spec_boxed("end-cleared-balance",
00766 "Ending Account Cleared Balance",
00767 "This is the current ending cleared balance for "
00768 "the account. It is computed from the sum of the "
00769 "starting balance and all cleared splits in the "
00770 "account.",
00771 GNC_TYPE_NUMERIC,
00772 G_PARAM_READABLE));
00773
00774 g_object_class_install_property
00775 (gobject_class,
00776 PROP_END_RECONCILED_BALANCE,
00777 g_param_spec_boxed("end-reconciled-balance",
00778 "Ending Account Reconciled Balance",
00779 "This is the current ending reconciled balance "
00780 "for the account. It is computed from the sum of "
00781 "the starting balance and all reconciled splits "
00782 "in the account.",
00783 GNC_TYPE_NUMERIC,
00784 G_PARAM_READABLE));
00785
00786 g_object_class_install_property
00787 (gobject_class,
00788 PROP_POLICY,
00789 g_param_spec_pointer ("policy",
00790 "Policy",
00791 "The account lots policy.",
00792 G_PARAM_READWRITE));
00793
00794 g_object_class_install_property
00795 (gobject_class,
00796 PROP_MARK,
00797 g_param_spec_int ("acct-mark",
00798 "Account Mark",
00799 "Ipsum Lorem",
00800 0,
00801 G_MAXINT16,
00802 0,
00803 G_PARAM_READWRITE));
00804
00805 g_object_class_install_property
00806 (gobject_class,
00807 PROP_TAX_RELATED,
00808 g_param_spec_boolean ("tax-related",
00809 "Tax Related",
00810 "Whether the account maps to an entry on an "
00811 "income tax document.",
00812 FALSE,
00813 G_PARAM_READWRITE));
00814
00815 g_object_class_install_property
00816 (gobject_class,
00817 PROP_TAX_CODE,
00818 g_param_spec_string ("tax-code",
00819 "Tax Code",
00820 "This is the code for mapping an account to a "
00821 "specific entry on a taxable document. In the "
00822 "United States it is used to transfer totals "
00823 "into tax preparation software.",
00824 NULL,
00825 G_PARAM_READWRITE));
00826
00827 g_object_class_install_property
00828 (gobject_class,
00829 PROP_TAX_SOURCE,
00830 g_param_spec_string ("tax-source",
00831 "Tax Source",
00832 "This specifies where exported name comes from.",
00833 NULL,
00834 G_PARAM_READWRITE));
00835
00836 g_object_class_install_property
00837 (gobject_class,
00838 PROP_TAX_COPY_NUMBER,
00839 g_param_spec_int ("tax-copy-number",
00840 "Tax Copy Number",
00841 "This specifies the copy number of the tax "
00842 "form/schedule.",
00843 1,
00844 G_MAXINT16,
00845 1,
00846 G_PARAM_READWRITE));
00847
00848 g_object_class_install_property
00849 (gobject_class,
00850 PROP_HIDDEN,
00851 g_param_spec_boolean ("hidden",
00852 "Hidden",
00853 "Whether the account should be hidden in the "
00854 "account tree.",
00855 FALSE,
00856 G_PARAM_READWRITE));
00857
00858 g_object_class_install_property
00859 (gobject_class,
00860 PROP_PLACEHOLDER,
00861 g_param_spec_boolean ("placeholder",
00862 "Placeholder",
00863 "Whether the account is a placeholder account which does not "
00864 "allow transactions to be created, edited or deleted.",
00865 FALSE,
00866 G_PARAM_READWRITE));
00867 }
00868
00869 static void
00870 xaccInitAccount (Account * acc, QofBook *book)
00871 {
00872 ENTER ("book=%p\n", book);
00873 qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book);
00874
00875 LEAVE ("account=%p\n", acc);
00876 }
00877
00878
00879
00880
00881 QofBook *
00882 gnc_account_get_book(const Account *account)
00883 {
00884 return qof_instance_get_book(QOF_INSTANCE(account));
00885 }
00886
00887
00888
00889
00890 static Account *
00891 gnc_coll_get_root_account (QofCollection *col)
00892 {
00893 if (!col) return NULL;
00894 return qof_collection_get_data (col);
00895 }
00896
00897 static void
00898 gnc_coll_set_root_account (QofCollection *col, Account *root)
00899 {
00900 AccountPrivate *rpriv;
00901 Account *old_root;
00902 if (!col) return;
00903
00904 old_root = gnc_coll_get_root_account (col);
00905 if (old_root == root) return;
00906
00907
00908
00909
00910 rpriv = GET_PRIVATE(root);
00911 if (rpriv->parent)
00912 {
00913 xaccAccountBeginEdit(root);
00914 gnc_account_remove_child(rpriv->parent, root);
00915 xaccAccountCommitEdit(root);
00916 }
00917
00918 qof_collection_set_data (col, root);
00919
00920 if (old_root)
00921 {
00922 xaccAccountBeginEdit (old_root);
00923 xaccAccountDestroy (old_root);
00924 }
00925 }
00926
00927 Account *
00928 gnc_book_get_root_account (QofBook *book)
00929 {
00930 QofCollection *col;
00931 Account *root;
00932
00933 if (!book) return NULL;
00934 col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
00935 root = gnc_coll_get_root_account (col);
00936 if (root == NULL)
00937 root = gnc_account_create_root(book);
00938 return root;
00939 }
00940
00941 void
00942 gnc_book_set_root_account (QofBook *book, Account *root)
00943 {
00944 QofCollection *col;
00945 if (!book) return;
00946
00947 if (root && gnc_account_get_book(root) != book)
00948 {
00949 PERR ("cannot mix and match books freely!");
00950 return;
00951 }
00952
00953 col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
00954 gnc_coll_set_root_account (col, root);
00955 }
00956
00957
00958
00959
00960 Account *
00961 xaccMallocAccount (QofBook *book)
00962 {
00963 Account *acc;
00964
00965 g_return_val_if_fail (book, NULL);
00966
00967 acc = g_object_new (GNC_TYPE_ACCOUNT, NULL);
00968 xaccInitAccount (acc, book);
00969 qof_event_gen (&acc->inst, QOF_EVENT_CREATE, NULL);
00970
00971 return acc;
00972 }
00973
00974 Account *
00975 gnc_account_create_root (QofBook *book)
00976 {
00977 Account *root;
00978 AccountPrivate *rpriv;
00979
00980 root = xaccMallocAccount(book);
00981 rpriv = GET_PRIVATE(root);
00982 xaccAccountBeginEdit(root);
00983 rpriv->type = ACCT_TYPE_ROOT;
00984 CACHE_REPLACE(rpriv->accountName, "Root Account");
00985 xaccAccountCommitEdit(root);
00986 gnc_book_set_root_account(book, root);
00987 return root;
00988 }
00989
00990 static Account *
00991 xaccCloneAccountCommon(const Account *from, QofBook *book)
00992 {
00993 Account *ret;
00994 AccountPrivate *from_priv, *priv;
00995
00996 g_return_val_if_fail(GNC_IS_ACCOUNT(from), NULL);
00997 g_return_val_if_fail(QOF_IS_BOOK(book), NULL);
00998
00999 ENTER (" ");
01000 ret = g_object_new (GNC_TYPE_ACCOUNT, NULL);
01001 g_return_val_if_fail (ret, NULL);
01002
01003 from_priv = GET_PRIVATE(from);
01004 priv = GET_PRIVATE(ret);
01005 xaccInitAccount (ret, book);
01006
01007
01008
01009
01010 priv->type = from_priv->type;
01011
01012 priv->accountName = CACHE_INSERT(from_priv->accountName);
01013 priv->accountCode = CACHE_INSERT(from_priv->accountCode);
01014 priv->description = CACHE_INSERT(from_priv->description);
01015
01016 kvp_frame_delete(ret->inst.kvp_data);
01017 ret->inst.kvp_data = kvp_frame_copy(from->inst.kvp_data);
01018
01019
01020
01021 priv->commodity = gnc_commodity_obtain_twin(from_priv->commodity, book);
01022 gnc_commodity_increment_usage_count(priv->commodity);
01023
01024 priv->commodity_scu = from_priv->commodity_scu;
01025 priv->non_standard_scu = from_priv->non_standard_scu;
01026
01027 LEAVE (" ");
01028 return ret;
01029 }
01030
01031 Account *
01032 xaccCloneAccount (const Account *from, QofBook *book)
01033 {
01034 Account *ret = xaccCloneAccountCommon(from, book);
01035 qof_instance_gemini (&ret->inst, (QofInstance *) &from->inst);
01036 g_assert (ret ==
01037 (Account*) qof_instance_lookup_twin (QOF_INSTANCE(from), book));
01038 return ret;
01039 }
01040
01041 Account *
01042 xaccCloneAccountSimple (const Account *from, QofBook *book)
01043 {
01044 Account *ret = xaccCloneAccountCommon(from, book);
01045 qof_instance_set_dirty(&ret->inst);
01046 return ret;
01047 }
01048
01049
01050
01051
01052 static void
01053 xaccFreeOneChildAccount (Account *acc, gpointer dummy)
01054 {
01055
01056
01057 if (qof_instance_get_editlevel(acc) == 0)
01058 xaccAccountBeginEdit(acc);
01059 xaccAccountDestroy(acc);
01060 }
01061
01062 static void
01063 xaccFreeAccountChildren (Account *acc)
01064 {
01065 AccountPrivate *priv;
01066 GList *children;
01067
01068
01069 priv = GET_PRIVATE(acc);
01070 children = g_list_copy(priv->children);
01071 g_list_foreach(children, (GFunc)xaccFreeOneChildAccount, NULL);
01072 g_list_free(children);
01073
01074
01075 if (priv->children)
01076 g_list_free(priv->children);
01077 priv->children = NULL;
01078 }
01079
01080
01081
01082
01083
01084 static void
01085 xaccFreeAccount (Account *acc)
01086 {
01087 AccountPrivate *priv;
01088 GList *lp;
01089
01090 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01091
01092 priv = GET_PRIVATE(acc);
01093 qof_event_gen (&acc->inst, QOF_EVENT_DESTROY, NULL);
01094
01095 if (priv->children)
01096 {
01097 PERR (" instead of calling xaccFreeAccount(), please call \n"
01098 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
01099
01100
01101 xaccFreeAccountChildren(acc);
01102 }
01103
01104
01105 if (priv->lots)
01106 {
01107 PERR (" instead of calling xaccFreeAccount(), please call \n"
01108 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
01109
01110 for (lp = priv->lots; lp; lp = lp->next)
01111 {
01112 GNCLot *lot = lp->data;
01113 gnc_lot_destroy (lot);
01114 }
01115 g_list_free (priv->lots);
01116 priv->lots = NULL;
01117 }
01118
01119
01120
01121
01122
01123 if (priv->splits)
01124 {
01125 GList *slist;
01126 PERR (" instead of calling xaccFreeAccount(), please call \n"
01127 " xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
01128
01129 qof_instance_reset_editlevel(acc);
01130
01131 slist = g_list_copy(priv->splits);
01132 for (lp = slist; lp; lp = lp->next)
01133 {
01134 Split *s = (Split *) lp->data;
01135 g_assert(xaccSplitGetAccount(s) == acc);
01136 xaccSplitDestroy (s);
01137 }
01138 g_list_free(slist);
01139 g_assert(priv->splits == NULL);
01140 }
01141
01142 CACHE_REPLACE(priv->accountName, NULL);
01143 CACHE_REPLACE(priv->accountCode, NULL);
01144 CACHE_REPLACE(priv->description, NULL);
01145
01146
01147
01148
01149 priv->parent = NULL;
01150 priv->children = NULL;
01151
01152 priv->balance = gnc_numeric_zero();
01153 priv->cleared_balance = gnc_numeric_zero();
01154 priv->reconciled_balance = gnc_numeric_zero();
01155
01156 priv->type = ACCT_TYPE_NONE;
01157 gnc_commodity_decrement_usage_count(priv->commodity);
01158 priv->commodity = NULL;
01159
01160 priv->balance_dirty = FALSE;
01161 priv->sort_dirty = FALSE;
01162
01163
01164 g_object_unref(acc);
01165 }
01166
01167
01168
01169
01170
01171 void
01172 xaccAccountBeginEdit (Account *acc)
01173 {
01174 g_return_if_fail(acc);
01175 qof_begin_edit(&acc->inst);
01176 }
01177
01178 static void on_done(QofInstance *inst)
01179 {
01180
01181 qof_event_gen (inst, QOF_EVENT_MODIFY, NULL);
01182 }
01183
01184 static void on_err (QofInstance *inst, QofBackendError errcode)
01185 {
01186 PERR("commit error: %d", errcode);
01187 gnc_engine_signal_commit_error( errcode );
01188 }
01189
01190 static void acc_free (QofInstance *inst)
01191 {
01192 AccountPrivate *priv;
01193 Account *acc = (Account *) inst;
01194
01195 priv = GET_PRIVATE(acc);
01196 if (priv->parent)
01197 gnc_account_remove_child(priv->parent, acc);
01198 xaccFreeAccount(acc);
01199 }
01200
01201 static void
01202 destroy_pending_splits_for_account(QofInstance *ent, gpointer acc)
01203 {
01204 Transaction *trans = (Transaction *) ent;
01205 Split *split;
01206
01207 if (xaccTransIsOpen(trans))
01208 while ((split = xaccTransFindSplitByAccount(trans, acc)))
01209 xaccSplitDestroy(split);
01210 }
01211
01212 void
01213 xaccAccountCommitEdit (Account *acc)
01214 {
01215 AccountPrivate *priv;
01216 QofBook *book;
01217
01218 g_return_if_fail(acc);
01219 if (!qof_commit_edit(&acc->inst)) return;
01220
01221
01222
01223 priv = GET_PRIVATE(acc);
01224 if (qof_instance_get_destroying(acc))
01225 {
01226 GList *lp, *slist;
01227 QofCollection *col;
01228
01229 qof_instance_increase_editlevel(acc);
01230
01231
01232 xaccFreeAccountChildren(acc);
01233
01234 PINFO ("freeing splits for account %p (%s)",
01235 acc, priv->accountName ? priv->accountName : "(null)");
01236
01237 book = qof_instance_get_book(acc);
01238
01239
01240
01241 if (!qof_book_shutting_down(book))
01242 {
01243 slist = g_list_copy(priv->splits);
01244 for (lp = slist; lp; lp = lp->next)
01245 {
01246 Split *s = lp->data;
01247 xaccSplitDestroy (s);
01248 }
01249 g_list_free(slist);
01250 }
01251 else
01252 {
01253 g_list_free(priv->splits);
01254 priv->splits = NULL;
01255 }
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265 if (!qof_book_shutting_down(book))
01266 {
01267 col = qof_book_get_collection(book, GNC_ID_TRANS);
01268 qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
01269
01270
01271 for (lp = priv->lots; lp; lp = lp->next)
01272 {
01273 GNCLot *lot = lp->data;
01274 gnc_lot_destroy (lot);
01275 }
01276 }
01277 g_list_free(priv->lots);
01278 priv->lots = NULL;
01279
01280 qof_instance_set_dirty(&acc->inst);
01281 qof_instance_decrease_editlevel(acc);
01282 }
01283 else
01284 {
01285 xaccAccountBringUpToDate(acc);
01286 }
01287
01288 qof_commit_edit_part2(&acc->inst, on_err, on_done, acc_free);
01289 }
01290
01291 void
01292 xaccAccountDestroy (Account *acc)
01293 {
01294 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01295
01296 qof_instance_set_destroying(acc, TRUE);
01297
01298 xaccAccountCommitEdit (acc);
01299 }
01300
01301
01302
01303
01304 static gboolean
01305 xaccAcctChildrenEqual(const GList *na,
01306 const GList *nb,
01307 gboolean check_guids)
01308 {
01309 if ((!na && nb) || (na && !nb))
01310 {
01311 PWARN ("only one has accounts");
01312 return(FALSE);
01313 }
01314
01315 while (na && nb)
01316 {
01317 Account *aa = na->data;
01318 Account *ab = nb->data;
01319
01320 if (!xaccAccountEqual(aa, ab, check_guids))
01321 {
01322 char sa[GUID_ENCODING_LENGTH + 1];
01323 char sb[GUID_ENCODING_LENGTH + 1];
01324
01325 guid_to_string_buff (xaccAccountGetGUID (aa), sa);
01326 guid_to_string_buff (xaccAccountGetGUID (ab), sb);
01327
01328 PWARN ("accounts %s and %s differ", sa, sb);
01329
01330 return(FALSE);
01331 }
01332
01333 na = na->next;
01334 nb = nb->next;
01335 }
01336
01337 if (na || nb)
01338 {
01339 PWARN ("different numbers of accounts");
01340 return(FALSE);
01341 }
01342
01343 return(TRUE);
01344 }
01345
01346 gboolean
01347 xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
01348 {
01349 AccountPrivate *priv_aa, *priv_ab;
01350
01351 if (!aa && !ab) return TRUE;
01352
01353 g_return_val_if_fail(GNC_IS_ACCOUNT(aa), FALSE);
01354 g_return_val_if_fail(GNC_IS_ACCOUNT(ab), FALSE);
01355
01356 priv_aa = GET_PRIVATE(aa);
01357 priv_ab = GET_PRIVATE(ab);
01358 if (priv_aa->type != priv_ab->type)
01359 {
01360 PWARN ("types differ: %d vs %d", priv_aa->type, priv_ab->type);
01361 return FALSE;
01362 }
01363
01364 if (safe_strcmp(priv_aa->accountName, priv_ab->accountName) != 0)
01365 {
01366 PWARN ("names differ: %s vs %s", priv_aa->accountName, priv_ab->accountName);
01367 return FALSE;
01368 }
01369
01370 if (safe_strcmp(priv_aa->accountCode, priv_ab->accountCode) != 0)
01371 {
01372 PWARN ("codes differ: %s vs %s", priv_aa->accountCode, priv_ab->accountCode);
01373 return FALSE;
01374 }
01375
01376 if (safe_strcmp(priv_aa->description, priv_ab->description) != 0)
01377 {
01378 PWARN ("descriptions differ: %s vs %s", priv_aa->description, priv_ab->description);
01379 return FALSE;
01380 }
01381
01382 if (!gnc_commodity_equal(priv_aa->commodity, priv_ab->commodity))
01383 {
01384 PWARN ("commodities differ");
01385 return FALSE;
01386 }
01387
01388 if (check_guids)
01389 {
01390 if (qof_instance_guid_compare(aa, ab) != 0)
01391 {
01392 PWARN ("GUIDs differ");
01393 return FALSE;
01394 }
01395 }
01396
01397 if (kvp_frame_compare(aa->inst.kvp_data, ab->inst.kvp_data) != 0)
01398 {
01399 char *frame_a;
01400 char *frame_b;
01401
01402 frame_a = kvp_frame_to_string (aa->inst.kvp_data);
01403 frame_b = kvp_frame_to_string (ab->inst.kvp_data);
01404
01405 PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
01406
01407 g_free (frame_a);
01408 g_free (frame_b);
01409
01410 return FALSE;
01411 }
01412
01413 if (!gnc_numeric_equal(priv_aa->starting_balance, priv_ab->starting_balance))
01414 {
01415 char *str_a;
01416 char *str_b;
01417
01418 str_a = gnc_numeric_to_string(priv_aa->starting_balance);
01419 str_b = gnc_numeric_to_string(priv_ab->starting_balance);
01420
01421 PWARN ("starting balances differ: %s vs %s", str_a, str_b);
01422
01423 g_free (str_a);
01424 g_free (str_b);
01425
01426 return FALSE;
01427 }
01428
01429 if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
01430 priv_ab->starting_cleared_balance))
01431 {
01432 char *str_a;
01433 char *str_b;
01434
01435 str_a = gnc_numeric_to_string(priv_aa->starting_cleared_balance);
01436 str_b = gnc_numeric_to_string(priv_ab->starting_cleared_balance);
01437
01438 PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
01439
01440 g_free (str_a);
01441 g_free (str_b);
01442
01443 return FALSE;
01444 }
01445
01446 if (!gnc_numeric_equal(priv_aa->starting_reconciled_balance,
01447 priv_ab->starting_reconciled_balance))
01448 {
01449 char *str_a;
01450 char *str_b;
01451
01452 str_a = gnc_numeric_to_string(priv_aa->starting_reconciled_balance);
01453 str_b = gnc_numeric_to_string(priv_ab->starting_reconciled_balance);
01454
01455 PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
01456
01457 g_free (str_a);
01458 g_free (str_b);
01459
01460 return FALSE;
01461 }
01462
01463 if (!gnc_numeric_equal(priv_aa->balance, priv_ab->balance))
01464 {
01465 char *str_a;
01466 char *str_b;
01467
01468 str_a = gnc_numeric_to_string(priv_aa->balance);
01469 str_b = gnc_numeric_to_string(priv_ab->balance);
01470
01471 PWARN ("balances differ: %s vs %s", str_a, str_b);
01472
01473 g_free (str_a);
01474 g_free (str_b);
01475
01476 return FALSE;
01477 }
01478
01479 if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
01480 {
01481 char *str_a;
01482 char *str_b;
01483
01484 str_a = gnc_numeric_to_string(priv_aa->cleared_balance);
01485 str_b = gnc_numeric_to_string(priv_ab->cleared_balance);
01486
01487 PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
01488
01489 g_free (str_a);
01490 g_free (str_b);
01491
01492 return FALSE;
01493 }
01494
01495 if (!gnc_numeric_equal(priv_aa->reconciled_balance, priv_ab->reconciled_balance))
01496 {
01497 char *str_a;
01498 char *str_b;
01499
01500 str_a = gnc_numeric_to_string(priv_aa->reconciled_balance);
01501 str_b = gnc_numeric_to_string(priv_ab->reconciled_balance);
01502
01503 PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
01504
01505 g_free (str_a);
01506 g_free (str_b);
01507
01508 return FALSE;
01509 }
01510
01511
01512
01513 {
01514 GList *la = priv_aa->splits;
01515 GList *lb = priv_ab->splits;
01516
01517 if ((la && !lb) || (!la && lb))
01518 {
01519 PWARN ("only one has splits");
01520 return FALSE;
01521 }
01522
01523 if (la && lb)
01524 {
01525
01526 while (la && lb)
01527 {
01528 Split *sa = (Split *) la->data;
01529 Split *sb = (Split *) lb->data;
01530
01531 if (!xaccSplitEqual(sa, sb, check_guids, TRUE, FALSE))
01532 {
01533 PWARN ("splits differ");
01534 return(FALSE);
01535 }
01536
01537 la = la->next;
01538 lb = lb->next;
01539 }
01540
01541 if ((la != NULL) || (lb != NULL))
01542 {
01543 PWARN ("number of splits differs");
01544 return(FALSE);
01545 }
01546 }
01547 }
01548
01549 if (!xaccAcctChildrenEqual(priv_aa->children, priv_ab->children, check_guids))
01550 {
01551 PWARN ("children differ");
01552 return FALSE;
01553 }
01554
01555 return(TRUE);
01556 }
01557
01558
01559
01560
01561 gboolean
01562 gnc_account_get_sort_dirty (Account *acc)
01563 {
01564 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
01565 return GET_PRIVATE(acc)->sort_dirty;
01566 }
01567
01568 void
01569 gnc_account_set_sort_dirty (Account *acc)
01570 {
01571 AccountPrivate *priv;
01572
01573 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01574
01575 if (qof_instance_get_destroying(acc))
01576 return;
01577
01578 priv = GET_PRIVATE(acc);
01579 priv->sort_dirty = TRUE;
01580 }
01581
01582 gboolean
01583 gnc_account_get_balance_dirty (Account *acc)
01584 {
01585 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
01586 return GET_PRIVATE(acc)->balance_dirty;
01587 }
01588
01589 void
01590 gnc_account_set_balance_dirty (Account *acc)
01591 {
01592 AccountPrivate *priv;
01593
01594 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01595
01596 if (qof_instance_get_destroying(acc))
01597 return;
01598
01599 priv = GET_PRIVATE(acc);
01600 priv->balance_dirty = TRUE;
01601 }
01602
01603
01604
01605
01606 gboolean
01607 gnc_account_find_split (Account *acc, Split *s)
01608 {
01609 AccountPrivate *priv;
01610 GList *node;
01611
01612 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
01613 g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
01614
01615 priv = GET_PRIVATE(acc);
01616 node = g_list_find(priv->splits, s);
01617 return node ? TRUE : FALSE;
01618 }
01619
01620 gboolean
01621 gnc_account_insert_split (Account *acc, Split *s)
01622 {
01623 AccountPrivate *priv;
01624 GList *node;
01625
01626 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
01627 g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
01628
01629 priv = GET_PRIVATE(acc);
01630 node = g_list_find(priv->splits, s);
01631 if (node)
01632 return FALSE;
01633
01634 if (qof_instance_get_editlevel(acc) == 0)
01635 {
01636 priv->splits = g_list_insert_sorted(priv->splits, s,
01637 (GCompareFunc)xaccSplitOrder);
01638 }
01639 else
01640 {
01641 priv->splits = g_list_prepend(priv->splits, s);
01642 priv->sort_dirty = TRUE;
01643 }
01644
01645
01646 qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
01647
01648 qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
01649
01650 priv->balance_dirty = TRUE;
01651
01652
01653 return TRUE;
01654 }
01655
01656 gboolean
01657 gnc_account_remove_split (Account *acc, Split *s)
01658 {
01659 AccountPrivate *priv;
01660 GList *node;
01661
01662 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
01663 g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
01664
01665 priv = GET_PRIVATE(acc);
01666 node = g_list_find(priv->splits, s);
01667 if (NULL == node)
01668 return FALSE;
01669
01670 priv->splits = g_list_delete_link(priv->splits, node);
01671
01672 qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, NULL);
01673
01674 qof_event_gen(&acc->inst, GNC_EVENT_ITEM_REMOVED, s);
01675
01676 priv->balance_dirty = TRUE;
01677 xaccAccountRecomputeBalance(acc);
01678 return TRUE;
01679 }
01680
01681 void
01682 xaccAccountSortSplits (Account *acc, gboolean force)
01683 {
01684 AccountPrivate *priv;
01685
01686 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01687
01688 priv = GET_PRIVATE(acc);
01689 if (!priv->sort_dirty || (!force && qof_instance_get_editlevel(acc) > 0))
01690 return;
01691 priv->splits = g_list_sort(priv->splits, (GCompareFunc)xaccSplitOrder);
01692 priv->sort_dirty = FALSE;
01693 priv->balance_dirty = TRUE;
01694 }
01695
01696 static void
01697 xaccAccountBringUpToDate(Account *acc)
01698 {
01699 if (!acc) return;
01700
01701
01702
01703 xaccAccountSortSplits(acc, FALSE);
01704 xaccAccountRecomputeBalance(acc);
01705 }
01706
01707
01708
01709
01710 void
01711 xaccAccountSetGUID (Account *acc, const GncGUID *guid)
01712 {
01713 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01714 g_return_if_fail(guid);
01715
01716
01717 PINFO("acct=%p", acc);
01718 xaccAccountBeginEdit (acc);
01719 qof_instance_set_guid (&acc->inst, guid);
01720 qof_instance_set_dirty(&acc->inst);
01721 xaccAccountCommitEdit (acc);
01722 }
01723
01724
01725
01726
01727 Account *
01728 xaccAccountLookup (const GncGUID *guid, QofBook *book)
01729 {
01730 QofCollection *col;
01731 if (!guid || !book) return NULL;
01732 col = qof_book_get_collection (book, GNC_ID_ACCOUNT);
01733 return (Account *) qof_collection_lookup_entity (col, guid);
01734 }
01735
01736
01737
01738
01739 short
01740 xaccAccountGetMark (const Account *acc)
01741 {
01742 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
01743
01744 return GET_PRIVATE(acc)->mark;
01745 }
01746
01747 void
01748 xaccAccountSetMark (Account *acc, short m)
01749 {
01750 AccountPrivate *priv;
01751
01752 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01753
01754 priv = GET_PRIVATE(acc);
01755 priv->mark = m;
01756 }
01757
01758 void
01759 xaccClearMark (Account *acc, short val)
01760 {
01761 Account *root;
01762
01763 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01764
01765 root = gnc_account_get_root(acc);
01766 xaccClearMarkDown(root ? root : acc, val);
01767 }
01768
01769 void
01770 xaccClearMarkDown (Account *acc, short val)
01771 {
01772 AccountPrivate *priv;
01773 GList *node;
01774
01775 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01776
01777 priv = GET_PRIVATE(acc);
01778 priv->mark = val;
01779 for (node = priv->children; node; node = node->next)
01780 {
01781 xaccClearMarkDown(node->data, val);
01782 }
01783 }
01784
01785
01786
01787
01788 GNCPolicy *
01789 gnc_account_get_policy (Account *acc)
01790 {
01791 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
01792
01793 return GET_PRIVATE(acc)->policy;
01794 }
01795
01796 void
01797 gnc_account_set_policy (Account *acc, GNCPolicy *policy)
01798 {
01799 AccountPrivate *priv;
01800
01801 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01802
01803 priv = GET_PRIVATE(acc);
01804 priv->policy = policy ? policy : xaccGetFIFOPolicy();
01805 }
01806
01807
01808
01809
01810 void
01811 xaccAccountRemoveLot (Account *acc, GNCLot *lot)
01812 {
01813 AccountPrivate *priv;
01814
01815 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01816 g_return_if_fail(GNC_IS_LOT(lot));
01817
01818 priv = GET_PRIVATE(acc);
01819 g_return_if_fail(priv->lots);
01820
01821 ENTER ("(acc=%p, lot=%p)", acc, lot);
01822 priv->lots = g_list_remove(priv->lots, lot);
01823 qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_REMOVE, NULL);
01824 qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
01825 LEAVE ("(acc=%p, lot=%p)", acc, lot);
01826 }
01827
01828 void
01829 xaccAccountInsertLot (Account *acc, GNCLot *lot)
01830 {
01831 AccountPrivate *priv, *opriv;
01832 Account * old_acc = NULL;
01833 Account* lot_account;
01834
01835
01836 g_return_if_fail(GNC_IS_ACCOUNT(acc));
01837 g_return_if_fail(GNC_IS_LOT(lot));
01838
01839
01840 lot_account = gnc_lot_get_account(lot);
01841 if (lot_account == acc)
01842 return;
01843
01844 ENTER ("(acc=%p, lot=%p)", acc, lot);
01845
01846
01847 if (lot_account)
01848 {
01849 old_acc = lot_account;
01850 opriv = GET_PRIVATE(old_acc);
01851 opriv->lots = g_list_remove(opriv->lots, lot);
01852 }
01853
01854 priv = GET_PRIVATE(acc);
01855 priv->lots = g_list_prepend(priv->lots, lot);
01856 gnc_lot_set_account(lot, acc);
01857
01858
01859
01860
01861
01862
01863 qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_ADD, NULL);
01864 qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
01865
01866 LEAVE ("(acc=%p, lot=%p)", acc, lot);
01867 }
01868
01869
01870
01871 static void
01872 xaccPreSplitMove (Split *split, gpointer dummy)
01873 {
01874 xaccTransBeginEdit (xaccSplitGetParent (split));
01875 }
01876
01877 static void
01878 xaccPostSplitMove (Split *split, Account *accto)
01879 {
01880 Transaction *trans;
01881
01882 xaccSplitSetAccount(split, accto);
01883 xaccSplitSetAmount(split, split->amount);
01884 trans = xaccSplitGetParent (split);
01885 xaccTransCommitEdit (trans);
01886 }
01887
01888 void
01889 xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
01890 {
01891 AccountPrivate *from_priv, *to_priv;
01892
01893
01894 g_return_if_fail(GNC_IS_ACCOUNT(accfrom));
01895 g_return_if_fail(GNC_IS_ACCOUNT(accto));
01896
01897
01898 from_priv = GET_PRIVATE(accfrom);
01899 to_priv = GET_PRIVATE(accto);
01900 if (!from_priv->splits || accfrom == accto)
01901 return;
01902
01903
01904 g_return_if_fail (qof_instance_books_equal(accfrom, accto));
01905 ENTER ("(accfrom=%p, accto=%p)", accfrom, accto);
01906
01907 xaccAccountBeginEdit(accfrom);
01908 xaccAccountBeginEdit(accto);
01909
01910 g_list_foreach(from_priv->splits, (GFunc)xaccPreSplitMove, NULL);
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 g_list_foreach(from_priv->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
01928
01929
01930 g_assert(from_priv->splits == NULL);
01931 g_assert(from_priv->lots == NULL);
01932 xaccAccountCommitEdit(accfrom);
01933 xaccAccountCommitEdit(accto);
01934
01935 LEAVE ("(accfrom=%p, accto=%p)", accfrom, accto);
01936 }
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967 void
01968 xaccAccountRecomputeBalance (Account * acc)
01969 {
01970 AccountPrivate *priv;
01971 gnc_numeric balance;
01972 gnc_numeric cleared_balance;
01973 gnc_numeric reconciled_balance;
01974 Split *last_split = NULL;
01975 GList *lp;
01976
01977 if (NULL == acc) return;
01978
01979 priv = GET_PRIVATE(acc);
01980 if (qof_instance_get_editlevel(acc) > 0) return;
01981 if (!priv->balance_dirty) return;
01982 if (qof_instance_get_destroying(acc)) return;
01983 if (qof_book_shutting_down(qof_instance_get_book(acc))) return;
01984
01985 balance = priv->starting_balance;
01986 cleared_balance = priv->starting_cleared_balance;
01987 reconciled_balance = priv->starting_reconciled_balance;
01988
01989 PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
01990 priv->accountName, balance.num, balance.denom);
01991 for (lp = priv->splits; lp; lp = lp->next)
01992 {
01993 Split *split = (Split *) lp->data;
01994 gnc_numeric amt = xaccSplitGetAmount (split);
01995
01996 balance = gnc_numeric_add_fixed(balance, amt);
01997
01998 if (NREC != split->reconciled)
01999 {
02000 cleared_balance = gnc_numeric_add_fixed(cleared_balance, amt);
02001 }
02002
02003 if (YREC == split->reconciled ||
02004 FREC == split->reconciled)
02005 {
02006 reconciled_balance =
02007 gnc_numeric_add_fixed(reconciled_balance, amt);
02008 }
02009
02010 split->balance = balance;
02011 split->cleared_balance = cleared_balance;
02012 split->reconciled_balance = reconciled_balance;
02013
02014 last_split = split;
02015 }
02016
02017 priv->balance = balance;
02018 priv->cleared_balance = cleared_balance;
02019 priv->reconciled_balance = reconciled_balance;
02020 priv->balance_dirty = FALSE;
02021 }
02022
02023
02024
02025
02026
02027
02028
02029 static int typeorder[NUM_ACCOUNT_TYPES] =
02030 {
02031 ACCT_TYPE_BANK, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL, ACCT_TYPE_CURRENCY,
02032 ACCT_TYPE_CASH, ACCT_TYPE_ASSET, ACCT_TYPE_RECEIVABLE,
02033 ACCT_TYPE_CREDIT, ACCT_TYPE_LIABILITY, ACCT_TYPE_PAYABLE,
02034 ACCT_TYPE_INCOME, ACCT_TYPE_EXPENSE, ACCT_TYPE_EQUITY, ACCT_TYPE_TRADING
02035 };
02036
02037 static int revorder[NUM_ACCOUNT_TYPES] =
02038 {
02039 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
02040 };
02041
02042
02043 int
02044 xaccAccountOrder (const Account *aa, const Account *ab)
02045 {
02046 AccountPrivate *priv_aa, *priv_ab;
02047 char *da, *db;
02048 char *endptr = NULL;
02049 int ta, tb, result;
02050 long la, lb;
02051
02052 if ( aa && !ab ) return -1;
02053 if ( !aa && ab ) return +1;
02054 if ( !aa && !ab ) return 0;
02055
02056 priv_aa = GET_PRIVATE(aa);
02057 priv_ab = GET_PRIVATE(ab);
02058
02059
02060 da = priv_aa->accountCode;
02061 db = priv_ab->accountCode;
02062
02063
02064 la = strtoul (da, &endptr, 36);
02065 if ((*da != '\0') && (*endptr == '\0'))
02066 {
02067 lb = strtoul (db, &endptr, 36);
02068 if ((*db != '\0') && (*endptr == '\0'))
02069 {
02070 if (la < lb) return -1;
02071 if (la > lb) return +1;
02072 }
02073 }
02074
02075
02076 result = safe_strcmp (da, db);
02077 if (result)
02078 return result;
02079
02080
02081
02082 if (-1 == revorder[0])
02083 {
02084 int i;
02085 for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
02086 {
02087 revorder [typeorder[i]] = i;
02088 }
02089 }
02090
02091
02092 ta = priv_aa->type;
02093 tb = priv_ab->type;
02094 ta = revorder[ta];
02095 tb = revorder[tb];
02096 if (ta < tb) return -1;
02097 if (ta > tb) return +1;
02098
02099
02100 da = priv_aa->accountName;
02101 db = priv_ab->accountName;
02102 result = safe_utf8_collate(da, db);
02103 if (result)
02104 return result;
02105
02106
02107 return qof_instance_guid_compare(aa, ab);
02108 }
02109
02110 static int
02111 qof_xaccAccountOrder (const Account **aa, const Account **ab)
02112 {
02113 return xaccAccountOrder(*aa, *ab);
02114 }
02115
02116
02117
02118
02119 void
02120 xaccAccountSetType (Account *acc, GNCAccountType tip)
02121 {
02122 AccountPrivate *priv;
02123
02124
02125 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02126 g_return_if_fail(tip < NUM_ACCOUNT_TYPES);
02127
02128
02129 priv = GET_PRIVATE(acc);
02130 if (priv->type == tip)
02131 return;
02132
02133 xaccAccountBeginEdit(acc);
02134 priv->type = tip;
02135 priv->balance_dirty = TRUE;
02136 mark_account(acc);
02137 xaccAccountCommitEdit(acc);
02138 }
02139
02140 void
02141 xaccAccountSetName (Account *acc, const char *str)
02142 {
02143 AccountPrivate *priv;
02144
02145
02146 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02147 g_return_if_fail(str);
02148
02149
02150 priv = GET_PRIVATE(acc);
02151 if (safe_strcmp(str, priv->accountName) == 0)
02152 return;
02153
02154 xaccAccountBeginEdit(acc);
02155 CACHE_REPLACE(priv->accountName, str);
02156 mark_account (acc);
02157 xaccAccountCommitEdit(acc);
02158 }
02159
02160 void
02161 xaccAccountSetCode (Account *acc, const char *str)
02162 {
02163 AccountPrivate *priv;
02164
02165
02166 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02167
02168
02169 priv = GET_PRIVATE(acc);
02170 if (safe_strcmp(str, priv->accountCode) == 0)
02171 return;
02172
02173 xaccAccountBeginEdit(acc);
02174 CACHE_REPLACE(priv->accountCode, str ? str : "");
02175 mark_account (acc);
02176 xaccAccountCommitEdit(acc);
02177 }
02178
02179 void
02180 xaccAccountSetDescription (Account *acc, const char *str)
02181 {
02182 AccountPrivate *priv;
02183
02184
02185 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02186
02187
02188 priv = GET_PRIVATE(acc);
02189 if (safe_strcmp(str, priv->description) == 0)
02190 return;
02191
02192 xaccAccountBeginEdit(acc);
02193 CACHE_REPLACE(priv->description, str ? str : "");
02194 mark_account (acc);
02195 xaccAccountCommitEdit(acc);
02196 }
02197
02198 void
02199 xaccAccountSetColor (Account *acc, const char *str)
02200 {
02201 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02202
02203 xaccAccountBeginEdit(acc);
02204 if (str)
02205 {
02206 gchar *tmp = g_strstrip(g_strdup(str));
02207 kvp_frame_set_slot_nc(acc->inst.kvp_data, "color",
02208 strlen(tmp) ? kvp_value_new_string(tmp) : NULL);
02209 g_free(tmp);
02210 }
02211 else
02212 {
02213 kvp_frame_set_slot_nc(acc->inst.kvp_data, "color", NULL);
02214 }
02215 mark_account (acc);
02216 xaccAccountCommitEdit(acc);
02217 }
02218
02219 static void
02220 qofAccountSetParent (Account *acc, QofInstance *parent)
02221 {
02222 Account *parent_acc;
02223
02224 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02225 g_return_if_fail(GNC_IS_ACCOUNT(parent));
02226
02227 parent_acc = GNC_ACCOUNT(parent);
02228 xaccAccountBeginEdit(acc);
02229 xaccAccountBeginEdit(parent_acc);
02230 gnc_account_append_child(parent_acc, acc);
02231 mark_account (parent_acc);
02232 mark_account (acc);
02233 xaccAccountCommitEdit(acc);
02234 xaccAccountCommitEdit(parent_acc);
02235 }
02236
02237 void
02238 xaccAccountSetNotes (Account *acc, const char *str)
02239 {
02240 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02241
02242 xaccAccountBeginEdit(acc);
02243 if (str)
02244 {
02245 gchar *tmp = g_strstrip(g_strdup(str));
02246 kvp_frame_set_slot_nc(acc->inst.kvp_data, "notes",
02247 strlen(tmp) ? kvp_value_new_string(tmp) : NULL);
02248 g_free(tmp);
02249 }
02250 else
02251 {
02252 kvp_frame_set_slot_nc(acc->inst.kvp_data, "notes", NULL);
02253 }
02254 mark_account(acc);
02255 xaccAccountCommitEdit(acc);
02256 }
02257
02258 void
02259 xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
02260 {
02261 AccountPrivate *priv;
02262 GList *lp;
02263
02264
02265 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02266 g_return_if_fail(GNC_IS_COMMODITY(com));
02267
02268
02269 priv = GET_PRIVATE(acc);
02270 if (com == priv->commodity)
02271 return;
02272
02273 xaccAccountBeginEdit(acc);
02274 gnc_commodity_decrement_usage_count(priv->commodity);
02275 priv->commodity = com;
02276 gnc_commodity_increment_usage_count(com);
02277 priv->commodity_scu = gnc_commodity_get_fraction(com);
02278 priv->non_standard_scu = FALSE;
02279
02280
02281 for (lp = priv->splits; lp; lp = lp->next)
02282 {
02283 Split *s = (Split *) lp->data;
02284 Transaction *trans = xaccSplitGetParent (s);
02285
02286 xaccTransBeginEdit (trans);
02287 xaccSplitSetAmount (s, xaccSplitGetAmount(s));
02288 xaccTransCommitEdit (trans);
02289 }
02290
02291 priv->sort_dirty = TRUE;
02292 priv->balance_dirty = TRUE;
02293 mark_account (acc);
02294
02295 xaccAccountCommitEdit(acc);
02296 }
02297
02298
02299
02300
02301
02302
02303
02304 void
02305 xaccAccountSetCommoditySCU (Account *acc, int scu)
02306 {
02307 AccountPrivate *priv;
02308
02309 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02310
02311 priv = GET_PRIVATE(acc);
02312 xaccAccountBeginEdit(acc);
02313 priv->commodity_scu = scu;
02314 if (scu != gnc_commodity_get_fraction(priv->commodity))
02315 priv->non_standard_scu = TRUE;
02316 mark_account(acc);
02317 xaccAccountCommitEdit(acc);
02318 }
02319
02320 int
02321 xaccAccountGetCommoditySCUi (const Account * acc)
02322 {
02323 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
02324 return GET_PRIVATE(acc)->commodity_scu;
02325 }
02326
02327 int
02328 xaccAccountGetCommoditySCU (const Account * acc)
02329 {
02330 AccountPrivate *priv;
02331
02332 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
02333
02334 priv = GET_PRIVATE(acc);
02335 if (priv->non_standard_scu || !priv->commodity)
02336 return priv->commodity_scu;
02337 return gnc_commodity_get_fraction(priv->commodity);
02338 }
02339
02340 void
02341 xaccAccountSetNonStdSCU (Account *acc, gboolean flag)
02342 {
02343 AccountPrivate *priv;
02344
02345 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02346
02347 priv = GET_PRIVATE(acc);
02348 if (priv->non_standard_scu == flag)
02349 return;
02350 xaccAccountBeginEdit(acc);
02351 priv->non_standard_scu = flag;
02352 mark_account (acc);
02353 xaccAccountCommitEdit(acc);
02354 }
02355
02356 gboolean
02357 xaccAccountGetNonStdSCU (const Account * acc)
02358 {
02359 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
02360 return GET_PRIVATE(acc)->non_standard_scu;
02361 }
02362
02363
02364
02365
02366
02367 void
02368 DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
02369 {
02370 QofBook *book;
02371 const char *string;
02372 gnc_commodity *commodity;
02373
02374 if ((!acc) || (!currency)) return;
02375
02376 xaccAccountBeginEdit(acc);
02377 string = gnc_commodity_get_unique_name (currency);
02378 kvp_frame_set_slot_nc(acc->inst.kvp_data, "old-currency",
02379 kvp_value_new_string(string));
02380 mark_account (acc);
02381 xaccAccountCommitEdit(acc);
02382
02383 commodity = DxaccAccountGetCurrency (acc);
02384 if (!commodity)
02385 {
02386 book = qof_instance_get_book(acc);
02387 gnc_commodity_table_insert (gnc_commodity_table_get_table (book), currency);
02388 }
02389 }
02390
02391
02392
02393
02394 void
02395 gnc_account_append_child (Account *new_parent, Account *child)
02396 {
02397 AccountPrivate *ppriv, *cpriv;
02398 Account *old_parent;
02399 QofCollection *col;
02400
02401
02402 g_assert(GNC_IS_ACCOUNT(new_parent));
02403 g_assert(GNC_IS_ACCOUNT(child));
02404
02405
02406 ppriv = GET_PRIVATE(new_parent);
02407 cpriv = GET_PRIVATE(child);
02408 old_parent = cpriv->parent;
02409 if (old_parent == new_parent)
02410 return;
02411
02412
02413 xaccAccountBeginEdit(child);
02414 if (old_parent)
02415 {
02416 gnc_account_remove_child(old_parent, child);
02417
02418 if (!qof_instance_books_equal(old_parent, new_parent))
02419 {
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431 PWARN ("reparenting accounts across books is not correctly supported\n");
02432
02433 qof_event_gen (&child->inst, QOF_EVENT_DESTROY, NULL);
02434 col = qof_book_get_collection (qof_instance_get_book(new_parent),
02435 GNC_ID_ACCOUNT);
02436 qof_collection_insert_entity (col, &child->inst);
02437 qof_event_gen (&child->inst, QOF_EVENT_CREATE, NULL);
02438 }
02439 }
02440 cpriv->parent = new_parent;
02441 ppriv->children = g_list_append(ppriv->children, child);
02442 qof_instance_set_dirty(&new_parent->inst);
02443 qof_instance_set_dirty(&child->inst);
02444
02445
02446
02447
02448
02449 qof_event_gen (&child->inst, QOF_EVENT_ADD, NULL);
02450
02451
02452 xaccAccountCommitEdit (child);
02453
02454 }
02455
02456 void
02457 gnc_account_remove_child (Account *parent, Account *child)
02458 {
02459 AccountPrivate *ppriv, *cpriv;
02460 GncEventData ed;
02461
02462 if (!child) return;
02463
02464
02465
02466 if (!parent) return;
02467
02468 ppriv = GET_PRIVATE(parent);
02469 cpriv = GET_PRIVATE(child);
02470
02471 if (cpriv->parent != parent)
02472 {
02473 PERR ("account not a child of parent");
02474 return;
02475 }
02476
02477
02478 ed.node = parent;
02479 ed.idx = g_list_index(ppriv->children, child);
02480
02481 ppriv->children = g_list_remove(ppriv->children, child);
02482
02483
02484 qof_event_gen(&child->inst, QOF_EVENT_REMOVE, &ed);
02485
02486
02487 cpriv->parent = NULL;
02488
02489 qof_event_gen (&parent->inst, QOF_EVENT_MODIFY, NULL);
02490 }
02491
02492 Account *
02493 gnc_account_get_parent (const Account *acc)
02494 {
02495 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02496 return GET_PRIVATE(acc)->parent;
02497 }
02498
02499 Account *
02500 gnc_account_get_root (Account *acc)
02501 {
02502 AccountPrivate *priv;
02503
02504 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02505
02506 priv = GET_PRIVATE(acc);
02507 while (priv->parent)
02508 {
02509 acc = priv->parent;
02510 priv = GET_PRIVATE(acc);
02511 }
02512
02513 return acc;
02514 }
02515
02516 gboolean
02517 gnc_account_is_root (const Account *account)
02518 {
02519 g_return_val_if_fail(GNC_IS_ACCOUNT(account), FALSE);
02520 return (GET_PRIVATE(account)->parent == NULL);
02521 }
02522
02523 GList *
02524 gnc_account_get_children (const Account *account)
02525 {
02526 g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
02527 return g_list_copy(GET_PRIVATE(account)->children);
02528 }
02529
02530 GList *
02531 gnc_account_get_children_sorted (const Account *account)
02532 {
02533 AccountPrivate *priv;
02534
02535
02536 g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
02537
02538
02539 priv = GET_PRIVATE(account);
02540 if (!priv->children)
02541 return NULL;
02542 return g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder);
02543 }
02544
02545 gint
02546 gnc_account_n_children (const Account *account)
02547 {
02548 g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
02549 return g_list_length(GET_PRIVATE(account)->children);
02550 }
02551
02552 gint
02553 gnc_account_child_index (const Account *parent, const Account *child)
02554 {
02555 g_return_val_if_fail(GNC_IS_ACCOUNT(parent), -1);
02556 g_return_val_if_fail(GNC_IS_ACCOUNT(child), -1);
02557 return g_list_index(GET_PRIVATE(parent)->children, child);
02558 }
02559
02560 Account *
02561 gnc_account_nth_child (const Account *parent, gint num)
02562 {
02563 g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
02564 return g_list_nth_data(GET_PRIVATE(parent)->children, num);
02565 }
02566
02567 gint
02568 gnc_account_n_descendants (const Account *account)
02569 {
02570 AccountPrivate *priv;
02571 GList *node;
02572 gint count = 0;
02573
02574 g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
02575
02576 priv = GET_PRIVATE(account);
02577 for (node = priv->children; node; node = g_list_next(node))
02578 {
02579 count += gnc_account_n_descendants(node->data) + 1;
02580 }
02581 return count;
02582 }
02583
02584 gint
02585 gnc_account_get_current_depth (const Account *account)
02586 {
02587 AccountPrivate *priv;
02588 int depth = 0;
02589
02590 g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
02591
02592 priv = GET_PRIVATE(account);
02593 while (priv->parent && (priv->type != ACCT_TYPE_ROOT))
02594 {
02595 account = priv->parent;
02596 priv = GET_PRIVATE(account);
02597 depth++;
02598 }
02599
02600 return depth;
02601 }
02602
02603 gint
02604 gnc_account_get_tree_depth (const Account *account)
02605 {
02606 AccountPrivate *priv;
02607 GList *node;
02608 gint depth = 0, child_depth;
02609
02610 g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
02611
02612 priv = GET_PRIVATE(account);
02613 if (!priv->children)
02614 return 1;
02615
02616 for (node = priv->children; node; node = g_list_next(node))
02617 {
02618 child_depth = gnc_account_get_tree_depth(node->data);
02619 depth = MAX(depth, child_depth);
02620 }
02621 return depth + 1;
02622 }
02623
02624 GList *
02625 gnc_account_get_descendants (const Account *account)
02626 {
02627 AccountPrivate *priv;
02628 GList *child, *descendants;
02629
02630 g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
02631
02632 priv = GET_PRIVATE(account);
02633 if (!priv->children)
02634 return NULL;
02635
02636 descendants = NULL;
02637 for (child = priv->children; child; child = g_list_next(child))
02638 {
02639 descendants = g_list_append(descendants, child->data);
02640 descendants = g_list_concat(descendants,
02641 gnc_account_get_descendants(child->data));
02642 }
02643 return descendants;
02644 }
02645
02646 GList *
02647 gnc_account_get_descendants_sorted (const Account *account)
02648 {
02649 AccountPrivate *priv;
02650 GList *child, *children, *descendants;
02651
02652
02653 g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
02654
02655
02656 priv = GET_PRIVATE(account);
02657 if (!priv->children)
02658 return NULL;
02659
02660 descendants = NULL;
02661 children = g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder);
02662 for (child = children; child; child = g_list_next(child))
02663 {
02664 descendants = g_list_append(descendants, child->data);
02665 descendants = g_list_concat(descendants,
02666 gnc_account_get_descendants(child->data));
02667 }
02668 g_list_free(children);
02669 return descendants;
02670 }
02671
02672 Account *
02673 gnc_account_lookup_by_name (const Account *parent, const char * name)
02674 {
02675 AccountPrivate *cpriv, *ppriv;
02676 Account *child, *result;
02677 GList *node;
02678
02679 g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
02680 g_return_val_if_fail(name, NULL);
02681
02682
02683 ppriv = GET_PRIVATE(parent);
02684 for (node = ppriv->children; node; node = node->next)
02685 {
02686 child = node->data;
02687 cpriv = GET_PRIVATE(child);
02688 if (safe_strcmp(cpriv->accountName, name) == 0)
02689 return child;
02690 }
02691
02692
02693
02694 for (node = ppriv->children; node; node = node->next)
02695 {
02696 child = node->data;
02697 result = gnc_account_lookup_by_name (child, name);
02698 if (result)
02699 return result;
02700 }
02701
02702 return NULL;
02703 }
02704
02705 Account *
02706 gnc_account_lookup_by_code (const Account *parent, const char * code)
02707 {
02708 AccountPrivate *cpriv, *ppriv;
02709 Account *child, *result;
02710 GList *node;
02711
02712 g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
02713 g_return_val_if_fail(code, NULL);
02714
02715
02716 ppriv = GET_PRIVATE(parent);
02717 for (node = ppriv->children; node; node = node->next)
02718 {
02719 child = node->data;
02720 cpriv = GET_PRIVATE(child);
02721 if (safe_strcmp(cpriv->accountCode, code) == 0)
02722 return child;
02723 }
02724
02725
02726
02727 for (node = ppriv->children; node; node = node->next)
02728 {
02729 child = node->data;
02730 result = gnc_account_lookup_by_code (child, code);
02731 if (result)
02732 return result;
02733 }
02734
02735 return NULL;
02736 }
02737
02738
02739
02740
02741
02742 static Account *
02743 gnc_account_lookup_by_full_name_helper (const Account *parent,
02744 gchar **names)
02745 {
02746 const AccountPrivate *priv, *ppriv;
02747 Account *found;
02748 GList *node;
02749
02750 g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
02751 g_return_val_if_fail(names, NULL);
02752
02753
02754 ppriv = GET_PRIVATE(parent);
02755 for (node = ppriv->children; node; node = node->next)
02756 {
02757 Account *account = node->data;
02758
02759 priv = GET_PRIVATE(account);
02760 if (safe_strcmp(priv->accountName, names[0]) == 0)
02761 {
02762
02763
02764 if (names[1] == NULL)
02765 return account;
02766
02767
02768 if (!priv->children)
02769 return NULL;
02770
02771
02772 found = gnc_account_lookup_by_full_name_helper(account, &names[1]);
02773 if (found != NULL)
02774 {
02775 return found;
02776 }
02777 }
02778 }
02779
02780 return NULL;
02781 }
02782
02783
02784 Account *
02785 gnc_account_lookup_by_full_name (const Account *any_acc,
02786 const gchar *name)
02787 {
02788 const AccountPrivate *rpriv;
02789 const Account *root;
02790 Account *found;
02791 gchar **names;
02792
02793 g_return_val_if_fail(GNC_IS_ACCOUNT(any_acc), NULL);
02794 g_return_val_if_fail(name, NULL);
02795
02796 root = any_acc;
02797 rpriv = GET_PRIVATE(root);
02798 while (rpriv->parent)
02799 {
02800 root = rpriv->parent;
02801 rpriv = GET_PRIVATE(root);
02802 }
02803 names = g_strsplit(name, gnc_get_account_separator_string(), -1);
02804 found = gnc_account_lookup_by_full_name_helper(root, names);
02805 g_strfreev(names);
02806 return found;
02807 }
02808
02809 void
02810 gnc_account_foreach_child (const Account *acc,
02811 AccountCb thunk,
02812 gpointer user_data)
02813 {
02814 const AccountPrivate *priv;
02815 GList *node;
02816
02817 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02818 g_return_if_fail(thunk);
02819
02820 priv = GET_PRIVATE(acc);
02821 for (node = priv->children; node; node = node->next)
02822 {
02823 thunk (node->data, user_data);
02824 }
02825 }
02826
02827 gpointer
02828 gnc_account_foreach_child_until (const Account *acc,
02829 AccountCb2 thunk,
02830 gpointer user_data)
02831 {
02832 const AccountPrivate *priv;
02833 GList *node;
02834 gpointer result;
02835
02836 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02837 g_return_val_if_fail(thunk, NULL);
02838
02839 priv = GET_PRIVATE(acc);
02840 for (node = priv->children; node; node = node->next)
02841 {
02842 result = thunk (node->data, user_data);
02843 if (result)
02844 return(result);
02845 }
02846
02847 return NULL;
02848 }
02849
02850 void
02851 gnc_account_foreach_descendant (const Account *acc,
02852 AccountCb thunk,
02853 gpointer user_data)
02854 {
02855 const AccountPrivate *priv;
02856 GList *node;
02857 Account *child;
02858
02859 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02860 g_return_if_fail(thunk);
02861
02862 priv = GET_PRIVATE(acc);
02863 for (node = priv->children; node; node = node->next)
02864 {
02865 child = node->data;
02866 thunk(child, user_data);
02867 gnc_account_foreach_descendant(child, thunk, user_data);
02868 }
02869 }
02870
02871 gpointer
02872 gnc_account_foreach_descendant_until (const Account *acc,
02873 AccountCb2 thunk,
02874 gpointer user_data)
02875 {
02876 const AccountPrivate *priv;
02877 GList *node;
02878 Account *child;
02879 gpointer result;
02880
02881 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02882 g_return_val_if_fail(thunk, NULL);
02883
02884 priv = GET_PRIVATE(acc);
02885 for (node = priv->children; node; node = node->next)
02886 {
02887 child = node->data;
02888 result = thunk(child, user_data);
02889 if (result)
02890 return(result);
02891
02892 result = gnc_account_foreach_descendant_until(child, thunk, user_data);
02893 if (result)
02894 return(result);
02895 }
02896
02897 return NULL;
02898 }
02899
02900
02901 GNCAccountType
02902 xaccAccountGetType (const Account *acc)
02903 {
02904 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), ACCT_TYPE_NONE);
02905 return GET_PRIVATE(acc)->type;
02906 }
02907
02908 static const char*
02909 qofAccountGetTypeString (const Account *acc)
02910 {
02911 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02912 return xaccAccountTypeEnumAsString(GET_PRIVATE(acc)->type);
02913 }
02914
02915 static void
02916 qofAccountSetType (Account *acc, const char *type_string)
02917 {
02918 g_return_if_fail(GNC_IS_ACCOUNT(acc));
02919 g_return_if_fail(type_string);
02920 xaccAccountSetType(acc, xaccAccountStringToEnum(type_string));
02921 }
02922
02923 const char *
02924 xaccAccountGetName (const Account *acc)
02925 {
02926 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02927 return GET_PRIVATE(acc)->accountName;
02928 }
02929
02930 gchar *
02931 gnc_account_get_full_name(const Account *account)
02932 {
02933 AccountPrivate *priv;
02934 const Account *a;
02935 char *fullname;
02936 gchar **names;
02937 int level;
02938
02939
02940
02941 if (NULL == account)
02942 return g_strdup("");
02943
02944
02945 g_return_val_if_fail(GNC_IS_ACCOUNT(account), g_strdup(""));
02946
02947
02948 priv = GET_PRIVATE(account);
02949 if (!priv->parent)
02950 return g_strdup("");
02951
02952
02953
02954 level = 0;
02955 for (a = account; a; a = priv->parent)
02956 {
02957 priv = GET_PRIVATE(a);
02958 level++;
02959 }
02960
02961
02962
02963 names = g_malloc(level * sizeof(gchar *));
02964 names[--level] = NULL;
02965 for (a = account; level > 0; a = priv->parent)
02966 {
02967 priv = GET_PRIVATE(a);
02968 names[--level] = priv->accountName;
02969 }
02970
02971
02972 fullname = g_strjoinv(account_separator, names);
02973 g_free(names);
02974
02975 return fullname;
02976 }
02977
02978 const char *
02979 xaccAccountGetCode (const Account *acc)
02980 {
02981 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02982 return GET_PRIVATE(acc)->accountCode;
02983 }
02984
02985 const char *
02986 xaccAccountGetDescription (const Account *acc)
02987 {
02988 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02989 return GET_PRIVATE(acc)->description;
02990 }
02991
02992 const char *
02993 xaccAccountGetColor (const Account *acc)
02994 {
02995 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
02996 return acc ? kvp_frame_get_string(acc->inst.kvp_data, "color") : NULL;
02997 }
02998
02999 const char *
03000 xaccAccountGetNotes (const Account *acc)
03001 {
03002 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03003 return acc ? kvp_frame_get_string(acc->inst.kvp_data, "notes") : NULL;
03004 }
03005
03006 gnc_commodity *
03007 DxaccAccountGetCurrency (const Account *acc)
03008 {
03009 KvpValue *v;
03010 const char *s;
03011 gnc_commodity_table *table;
03012
03013 if (!acc) return NULL;
03014
03015 v = kvp_frame_get_slot(acc->inst.kvp_data, "old-currency");
03016 if (!v) return NULL;
03017
03018 s = kvp_value_get_string (v);
03019 if (!s) return NULL;
03020
03021 table = gnc_commodity_table_get_table (qof_instance_get_book(acc));
03022
03023 return gnc_commodity_table_lookup_unique (table, s);
03024 }
03025
03026 gnc_commodity *
03027 xaccAccountGetCommodity (const Account *acc)
03028 {
03029 if (!GNC_IS_ACCOUNT(acc))
03030 return NULL;
03031 return GET_PRIVATE(acc)->commodity;
03032 }
03033
03034
03035
03036
03037 gnc_numeric
03038 gnc_account_get_start_balance (Account *acc)
03039 {
03040 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03041
03042 return GET_PRIVATE(acc)->starting_balance;
03043 }
03044
03045 void
03046 gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
03047 {
03048 AccountPrivate *priv;
03049
03050 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03051
03052 priv = GET_PRIVATE(acc);
03053 priv->starting_balance = start_baln;
03054 priv->balance_dirty = TRUE;
03055 }
03056
03057 gnc_numeric
03058 gnc_account_get_start_cleared_balance (Account *acc)
03059 {
03060 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03061
03062 return GET_PRIVATE(acc)->starting_cleared_balance;
03063 }
03064
03065 void
03066 gnc_account_set_start_cleared_balance (Account *acc,
03067 const gnc_numeric start_baln)
03068 {
03069 AccountPrivate *priv;
03070
03071 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03072
03073 priv = GET_PRIVATE(acc);
03074 priv->starting_cleared_balance = start_baln;
03075 priv->balance_dirty = TRUE;
03076 }
03077
03078 gnc_numeric
03079 gnc_account_get_start_reconciled_balance (Account *acc)
03080 {
03081 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03082
03083 return GET_PRIVATE(acc)->starting_reconciled_balance;
03084 }
03085
03086 void
03087 gnc_account_set_start_reconciled_balance (Account *acc,
03088 const gnc_numeric start_baln)
03089 {
03090 AccountPrivate *priv;
03091
03092 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03093
03094 priv = GET_PRIVATE(acc);
03095 priv->starting_reconciled_balance = start_baln;
03096 priv->balance_dirty = TRUE;
03097 }
03098
03099 gnc_numeric
03100 xaccAccountGetBalance (const Account *acc)
03101 {
03102 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03103 return GET_PRIVATE(acc)->balance;
03104 }
03105
03106 gnc_numeric
03107 xaccAccountGetClearedBalance (const Account *acc)
03108 {
03109 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03110 return GET_PRIVATE(acc)->cleared_balance;
03111 }
03112
03113 gnc_numeric
03114 xaccAccountGetReconciledBalance (const Account *acc)
03115 {
03116 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03117 return GET_PRIVATE(acc)->reconciled_balance;
03118 }
03119
03120 gnc_numeric
03121 xaccAccountGetProjectedMinimumBalance (const Account *acc)
03122 {
03123 AccountPrivate *priv;
03124 GList *node;
03125 time_t today;
03126 gnc_numeric lowest = gnc_numeric_zero ();
03127 int seen_a_transaction = 0;
03128
03129 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03130
03131 priv = GET_PRIVATE(acc);
03132 today = gnc_timet_get_today_end();
03133 for (node = g_list_last(priv->splits); node; node = node->prev)
03134 {
03135 Split *split = node->data;
03136
03137 if (!seen_a_transaction)
03138 {
03139 lowest = xaccSplitGetBalance (split);
03140 seen_a_transaction = 1;
03141 }
03142 else if (gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0)
03143 {
03144 lowest = xaccSplitGetBalance (split);
03145 }
03146
03147 if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
03148 return lowest;
03149 }
03150
03151 return lowest;
03152 }
03153
03154
03155
03156
03157
03158 gnc_numeric
03159 xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
03160 {
03161
03162
03163
03164
03165
03166
03167 AccountPrivate *priv;
03168 GList *lp;
03169 Timespec ts, trans_ts;
03170 gboolean found = FALSE;
03171 gnc_numeric balance;
03172
03173 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03174
03175 xaccAccountSortSplits (acc, TRUE);
03176 xaccAccountRecomputeBalance (acc);
03177
03178 priv = GET_PRIVATE(acc);
03179 balance = priv->balance;
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193 ts.tv_sec = date;
03194 ts.tv_nsec = 0;
03195
03196 lp = priv->splits;
03197 while ( lp && !found )
03198 {
03199 xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ),
03200 &trans_ts );
03201 if ( timespec_cmp( &trans_ts, &ts ) >= 0 )
03202 found = TRUE;
03203 else
03204 lp = lp->next;
03205 }
03206
03207 if ( lp )
03208 {
03209 if ( lp->prev )
03210 {
03211
03212
03213
03214 balance = xaccSplitGetBalance( (Split *)lp->prev->data );
03215 }
03216 else
03217 {
03218
03219 balance = gnc_numeric_zero();
03220 }
03221 }
03222
03223
03224
03225
03226
03227 return( balance );
03228 }
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238 gnc_numeric
03239 xaccAccountGetPresentBalance (const Account *acc)
03240 {
03241 AccountPrivate *priv;
03242 GList *node;
03243 time_t today;
03244
03245 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03246
03247 priv = GET_PRIVATE(acc);
03248 today = gnc_timet_get_today_end();
03249 for (node = g_list_last(priv->splits); node; node = node->prev)
03250 {
03251 Split *split = node->data;
03252
03253 if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
03254 return xaccSplitGetBalance (split);
03255 }
03256
03257 return gnc_numeric_zero ();
03258 }
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270 gnc_numeric
03271 xaccAccountConvertBalanceToCurrency(const Account *acc,
03272 gnc_numeric balance,
03273 const gnc_commodity *balance_currency,
03274 const gnc_commodity *new_currency)
03275 {
03276 QofBook *book;
03277 GNCPriceDB *pdb;
03278
03279 if (gnc_numeric_zero_p (balance) ||
03280 gnc_commodity_equiv (balance_currency, new_currency))
03281 return balance;
03282
03283 book = gnc_account_get_book (acc);
03284 pdb = gnc_pricedb_get_db (book);
03285
03286 balance = gnc_pricedb_convert_balance_latest_price(
03287 pdb, balance, balance_currency, new_currency);
03288
03289 return balance;
03290 }
03291
03292
03293
03294
03295
03296 gnc_numeric
03297 xaccAccountConvertBalanceToCurrencyAsOfDate(const Account *acc,
03298 gnc_numeric balance,
03299 gnc_commodity *balance_currency,
03300 gnc_commodity *new_currency,
03301 time_t date)
03302 {
03303 QofBook *book;
03304 GNCPriceDB *pdb;
03305 Timespec ts;
03306
03307 if (gnc_numeric_zero_p (balance) ||
03308 gnc_commodity_equiv (balance_currency, new_currency))
03309 return balance;
03310
03311 book = gnc_account_get_book (acc);
03312 pdb = gnc_pricedb_get_db (book);
03313
03314 ts.tv_sec = date;
03315 ts.tv_nsec = 0;
03316
03317 balance = gnc_pricedb_convert_balance_nearest_price(
03318 pdb, balance, balance_currency, new_currency, ts);
03319
03320 return balance;
03321 }
03322
03323
03324
03325
03326
03327
03328 static gnc_numeric
03329 xaccAccountGetXxxBalanceInCurrency (const Account *acc,
03330 xaccGetBalanceFn fn,
03331 const gnc_commodity *report_currency)
03332 {
03333 AccountPrivate *priv;
03334 gnc_numeric balance;
03335
03336 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03337 g_return_val_if_fail(fn, gnc_numeric_zero());
03338 g_return_val_if_fail(GNC_IS_COMMODITY(report_currency), gnc_numeric_zero());
03339
03340 priv = GET_PRIVATE(acc);
03341 balance = fn(acc);
03342 balance = xaccAccountConvertBalanceToCurrency(acc, balance,
03343 priv->commodity,
03344 report_currency);
03345 return balance;
03346 }
03347
03348 static gnc_numeric
03349 xaccAccountGetXxxBalanceAsOfDateInCurrency(Account *acc, time_t date,
03350 xaccGetBalanceAsOfDateFn fn,
03351 const gnc_commodity *report_commodity)
03352 {
03353 AccountPrivate *priv;
03354
03355 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
03356 g_return_val_if_fail(fn, gnc_numeric_zero());
03357 g_return_val_if_fail(GNC_IS_COMMODITY(report_commodity), gnc_numeric_zero());
03358
03359 priv = GET_PRIVATE(acc);
03360 return xaccAccountConvertBalanceToCurrency(
03361 acc, fn(acc, date), priv->commodity, report_commodity);
03362 }
03363
03364
03365
03366
03367 typedef struct
03368 {
03369 const gnc_commodity *currency;
03370 gnc_numeric balance;
03371 xaccGetBalanceFn fn;
03372 xaccGetBalanceAsOfDateFn asOfDateFn;
03373 time_t date;
03374 } CurrencyBalance;
03375
03376
03377
03378
03379
03380
03381
03382 static void
03383 xaccAccountBalanceHelper (Account *acc, gpointer data)
03384 {
03385 CurrencyBalance *cb = data;
03386 gnc_numeric balance;
03387
03388 if (!cb->fn || !cb->currency)
03389 return;
03390 balance = xaccAccountGetXxxBalanceInCurrency (acc, cb->fn, cb->currency);
03391 cb->balance = gnc_numeric_add (cb->balance, balance,
03392 gnc_commodity_get_fraction (cb->currency),
03393 GNC_HOW_RND_ROUND_HALF_UP);
03394 }
03395
03396 static void
03397 xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data)
03398 {
03399 CurrencyBalance *cb = data;
03400 gnc_numeric balance;
03401
03402 g_return_if_fail (cb->asOfDateFn && cb->currency);
03403
03404 balance = xaccAccountGetXxxBalanceAsOfDateInCurrency (
03405 acc, cb->date, cb->asOfDateFn, cb->currency);
03406 cb->balance = gnc_numeric_add (cb->balance, balance,
03407 gnc_commodity_get_fraction (cb->currency),
03408 GNC_HOW_RND_ROUND_HALF_UP);
03409 }
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423 static gnc_numeric
03424 xaccAccountGetXxxBalanceInCurrencyRecursive (const Account *acc,
03425 xaccGetBalanceFn fn,
03426 const gnc_commodity *report_commodity,
03427 gboolean include_children)
03428 {
03429 gnc_numeric balance;
03430
03431 if (!acc) return gnc_numeric_zero ();
03432 if (!report_commodity)
03433 report_commodity = xaccAccountGetCommodity (acc);
03434 if (!report_commodity)
03435 return gnc_numeric_zero();
03436
03437 balance = xaccAccountGetXxxBalanceInCurrency (acc, fn, report_commodity);
03438
03439
03440
03441 if (include_children)
03442 {
03443 #ifdef _MSC_VER
03444
03445
03446
03447 CurrencyBalance cb = { report_commodity, { 0 }, fn, NULL, 0 };
03448 cb.balance = balance;
03449 #else
03450 CurrencyBalance cb = { report_commodity, balance, fn, NULL, 0 };
03451 #endif
03452
03453 gnc_account_foreach_descendant (acc, xaccAccountBalanceHelper, &cb);
03454 balance = cb.balance;
03455 }
03456
03457 return balance;
03458 }
03459
03460 static gnc_numeric
03461 xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
03462 Account *acc, time_t date, xaccGetBalanceAsOfDateFn fn,
03463 gnc_commodity *report_commodity, gboolean include_children)
03464 {
03465 gnc_numeric balance;
03466
03467 g_return_val_if_fail(acc, gnc_numeric_zero());
03468 if (!report_commodity)
03469 report_commodity = xaccAccountGetCommodity (acc);
03470 if (!report_commodity)
03471 return gnc_numeric_zero();
03472
03473 balance = xaccAccountGetXxxBalanceAsOfDateInCurrency(
03474 acc, date, fn, report_commodity);
03475
03476
03477
03478 if (include_children)
03479 {
03480 #ifdef _MSC_VER
03481
03482
03483
03484 CurrencyBalance cb = { report_commodity, 0, NULL, fn, date };
03485 cb.balance = balance;
03486 #else
03487 CurrencyBalance cb = { report_commodity, balance, NULL, fn, date };
03488 #endif
03489
03490 gnc_account_foreach_descendant (acc, xaccAccountBalanceAsOfDateHelper, &cb);
03491 balance = cb.balance;
03492 }
03493
03494 return balance;
03495 }
03496
03497 gnc_numeric
03498 xaccAccountGetBalanceInCurrency (const Account *acc,
03499 const gnc_commodity *report_commodity,
03500 gboolean include_children)
03501 {
03502 gnc_numeric rc;
03503 rc = xaccAccountGetXxxBalanceInCurrencyRecursive (
03504 acc, xaccAccountGetBalance, report_commodity, include_children);
03505 PINFO(" baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, rc.num, rc.denom);
03506 return rc;
03507 }
03508
03509
03510 gnc_numeric
03511 xaccAccountGetClearedBalanceInCurrency (const Account *acc,
03512 const gnc_commodity *report_commodity,
03513 gboolean include_children)
03514 {
03515 return xaccAccountGetXxxBalanceInCurrencyRecursive (
03516 acc, xaccAccountGetClearedBalance, report_commodity,
03517 include_children);
03518 }
03519
03520
03521 gnc_numeric
03522 xaccAccountGetReconciledBalanceInCurrency (const Account *acc,
03523 const gnc_commodity *report_commodity,
03524 gboolean include_children)
03525 {
03526 return xaccAccountGetXxxBalanceInCurrencyRecursive (
03527 acc, xaccAccountGetReconciledBalance, report_commodity,
03528 include_children);
03529 }
03530
03531 gnc_numeric
03532 xaccAccountGetPresentBalanceInCurrency (const Account *acc,
03533 const gnc_commodity *report_commodity,
03534 gboolean include_children)
03535 {
03536 return xaccAccountGetXxxBalanceInCurrencyRecursive (
03537 acc, xaccAccountGetPresentBalance, report_commodity,
03538 include_children);
03539 }
03540
03541 gnc_numeric
03542 xaccAccountGetProjectedMinimumBalanceInCurrency (
03543 const Account *acc,
03544 const gnc_commodity *report_commodity,
03545 gboolean include_children)
03546 {
03547 return xaccAccountGetXxxBalanceInCurrencyRecursive (
03548 acc, xaccAccountGetProjectedMinimumBalance, report_commodity,
03549 include_children);
03550 }
03551
03552 gnc_numeric
03553 xaccAccountGetBalanceAsOfDateInCurrency(
03554 Account *acc, time_t date, gnc_commodity *report_commodity,
03555 gboolean include_children)
03556 {
03557 return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
03558 acc, date, xaccAccountGetBalanceAsOfDate, report_commodity,
03559 include_children);
03560 }
03561
03562 gnc_numeric
03563 xaccAccountGetBalanceChangeForPeriod (Account *acc, time_t t1, time_t t2, gboolean recurse)
03564 {
03565 gnc_numeric b1, b2;
03566
03567 b1 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t1, NULL, recurse);
03568 b2 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t2, NULL, recurse);
03569 return gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
03570 }
03571
03572
03573
03574
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587 SplitList *
03588 xaccAccountGetSplitList (const Account *acc)
03589 {
03590 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03591 xaccAccountSortSplits((Account*)acc, FALSE);
03592 return GET_PRIVATE(acc)->splits;
03593 }
03594
03595 LotList *
03596 xaccAccountGetLotList (const Account *acc)
03597 {
03598 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03599 return g_list_copy(GET_PRIVATE(acc)->lots);
03600 }
03601
03602 LotList *
03603 xaccAccountFindOpenLots (const Account *acc,
03604 gboolean (*match_func)(GNCLot *lot,
03605 gpointer user_data),
03606 gpointer user_data, GCompareFunc sort_func)
03607 {
03608 AccountPrivate *priv;
03609 GList *lot_list;
03610 GList *retval = NULL;
03611
03612 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03613
03614 priv = GET_PRIVATE(acc);
03615 for (lot_list = priv->lots; lot_list; lot_list = lot_list->next)
03616 {
03617 GNCLot *lot = lot_list->data;
03618
03619
03620 if (gnc_lot_is_closed (lot))
03621 continue;
03622
03623 if (match_func && !(match_func)(lot, user_data))
03624 continue;
03625
03626
03627 if (sort_func)
03628 retval = g_list_insert_sorted (retval, lot, sort_func);
03629 else
03630 retval = g_list_prepend (retval, lot);
03631 }
03632
03633 return retval;
03634 }
03635
03636 gpointer
03637 xaccAccountForEachLot(const Account *acc,
03638 gpointer (*proc)(GNCLot *lot, void *data), void *data)
03639 {
03640 AccountPrivate *priv;
03641 LotList *node;
03642 gpointer result = NULL;
03643
03644 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03645 g_return_val_if_fail(proc, NULL);
03646
03647 priv = GET_PRIVATE(acc);
03648 for (node = priv->lots; node; node = node->next)
03649 if ((result = proc((GNCLot *)node->data, data)))
03650 break;
03651
03652 return result;
03653 }
03654
03655
03656
03657
03658
03659 gboolean
03660 xaccAccountGetTaxRelated (const Account *acc)
03661 {
03662 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
03663 return kvp_frame_get_gint64(acc->inst.kvp_data, "tax-related");
03664 }
03665
03666 void
03667 xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
03668 {
03669 KvpValue *new_value;
03670
03671 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03672
03673 if (tax_related)
03674 new_value = kvp_value_new_gint64 (tax_related);
03675 else
03676 new_value = NULL;
03677
03678 xaccAccountBeginEdit (acc);
03679 kvp_frame_set_slot_nc(acc->inst.kvp_data, "tax-related", new_value);
03680 mark_account (acc);
03681 xaccAccountCommitEdit (acc);
03682 }
03683
03684 const char *
03685 xaccAccountGetTaxUSCode (const Account *acc)
03686 {
03687 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03688 return kvp_frame_get_string(acc->inst.kvp_data, "tax-US/code");
03689 }
03690
03691 void
03692 xaccAccountSetTaxUSCode (Account *acc, const char *code)
03693 {
03694 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03695
03696 xaccAccountBeginEdit (acc);
03697 kvp_frame_set_string (acc->inst.kvp_data, "/tax-US/code", code);
03698 if (!code)
03699 {
03700 KvpFrame *frame = NULL;
03701 kvp_frame_set_frame (acc->inst.kvp_data, "/tax-US", frame);
03702 }
03703 mark_account (acc);
03704 xaccAccountCommitEdit (acc);
03705 }
03706
03707 const char *
03708 xaccAccountGetTaxUSPayerNameSource (const Account *acc)
03709 {
03710 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
03711 return kvp_frame_get_string(acc->inst.kvp_data,
03712 "tax-US/payer-name-source");
03713 }
03714
03715 void
03716 xaccAccountSetTaxUSPayerNameSource (Account *acc, const char *source)
03717 {
03718 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03719
03720 xaccAccountBeginEdit (acc);
03721 kvp_frame_set_string (acc->inst.kvp_data,
03722 "/tax-US/payer-name-source", source);
03723 mark_account (acc);
03724 xaccAccountCommitEdit (acc);
03725 }
03726
03727 gint64
03728 xaccAccountGetTaxUSCopyNumber (const Account *acc)
03729 {
03730 gint64 copy_number;
03731
03732 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 1);
03733 copy_number = kvp_frame_get_gint64(acc->inst.kvp_data,
03734 "tax-US/copy-number");
03735 return (copy_number == 0) ? 1 : copy_number;
03736 }
03737
03738 void
03739 xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
03740 {
03741 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03742
03743 xaccAccountBeginEdit (acc);
03744 if (copy_number != 0)
03745 kvp_frame_set_gint64 (acc->inst.kvp_data, "/tax-US/copy-number", copy_number);
03746 else
03747 {
03748 KvpFrame * frame;
03749 KvpValue *value;
03750
03751 value = NULL;
03752 frame = kvp_frame_set_value_nc (acc->inst.kvp_data,
03753 "/tax-US/copy-number", value);
03754 if (!frame) kvp_value_delete (value);
03755 }
03756 mark_account (acc);
03757 xaccAccountCommitEdit (acc);
03758 }
03759
03760
03761
03762
03763 gboolean
03764 xaccAccountGetPlaceholder (const Account *acc)
03765 {
03766 const char *str;
03767
03768 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
03769
03770 str = kvp_frame_get_string(acc->inst.kvp_data, "placeholder");
03771 return (str && !strcmp(str, "true"));
03772 }
03773
03774 void
03775 xaccAccountSetPlaceholder (Account *acc, gboolean val)
03776 {
03777 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03778
03779 xaccAccountBeginEdit (acc);
03780 kvp_frame_set_string (acc->inst.kvp_data,
03781 "placeholder", val ? "true" : NULL);
03782 mark_account (acc);
03783 xaccAccountCommitEdit (acc);
03784 }
03785
03786 GNCPlaceholderType
03787 xaccAccountGetDescendantPlaceholder (const Account *acc)
03788 {
03789 GList *descendants, *node;
03790 GNCPlaceholderType ret = PLACEHOLDER_NONE;
03791
03792 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), PLACEHOLDER_NONE);
03793 if (xaccAccountGetPlaceholder(acc)) return PLACEHOLDER_THIS;
03794
03795 descendants = gnc_account_get_descendants(acc);
03796 for (node = descendants; node; node = node->next)
03797 if (xaccAccountGetPlaceholder((Account *) node->data))
03798 {
03799 ret = PLACEHOLDER_CHILD;
03800 break;
03801 }
03802
03803 g_list_free(descendants);
03804 return ret;
03805 }
03806
03807
03808
03809
03810 gboolean
03811 xaccAccountGetHidden (const Account *acc)
03812 {
03813 const char *str;
03814
03815 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
03816
03817 str = kvp_frame_get_string(acc->inst.kvp_data, "hidden");
03818 return (str && !strcmp(str, "true"));
03819 }
03820
03821 void
03822 xaccAccountSetHidden (Account *acc, gboolean val)
03823 {
03824 g_return_if_fail(GNC_IS_ACCOUNT(acc));
03825
03826 xaccAccountBeginEdit (acc);
03827 kvp_frame_set_string (acc->inst.kvp_data, "hidden",
03828 val ? "true" : NULL);
03829 mark_account (acc);
03830 xaccAccountCommitEdit (acc);
03831 }
03832
03833 gboolean
03834 xaccAccountIsHidden (const Account *acc)
03835 {
03836 AccountPrivate *priv;
03837
03838 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
03839
03840 if (xaccAccountGetHidden(acc))
03841 return TRUE;
03842 priv = GET_PRIVATE(acc);
03843 while ((acc = priv->parent) != NULL)
03844 {
03845 priv = GET_PRIVATE(acc);
03846 if (xaccAccountGetHidden(acc))
03847 return TRUE;
03848 }
03849 return FALSE;
03850 }
03851
03852
03853
03854
03855 gboolean
03856 xaccAccountHasAncestor (const Account *acc, const Account * ancestor)
03857 {
03858 const Account *parent;
03859
03860 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
03861 g_return_val_if_fail(GNC_IS_ACCOUNT(ancestor), FALSE);
03862
03863 parent = acc;
03864 while (parent && parent != ancestor)
03865 parent = GET_PRIVATE(parent)->parent;
03866
03867 return (parent == ancestor);
03868 }
03869
03870
03871
03872
03873
03874
03875
03876 #define GNC_RETURN_ENUM_AS_STRING(x) case (ACCT_TYPE_ ## x): return #x;
03877
03878 const char *
03879 xaccAccountTypeEnumAsString(GNCAccountType type)
03880 {
03881 switch (type)
03882 {
03883 GNC_RETURN_ENUM_AS_STRING(NONE);
03884 GNC_RETURN_ENUM_AS_STRING(BANK);
03885 GNC_RETURN_ENUM_AS_STRING(CASH);
03886 GNC_RETURN_ENUM_AS_STRING(CREDIT);
03887 GNC_RETURN_ENUM_AS_STRING(ASSET);
03888 GNC_RETURN_ENUM_AS_STRING(LIABILITY);
03889 GNC_RETURN_ENUM_AS_STRING(STOCK);
03890 GNC_RETURN_ENUM_AS_STRING(MUTUAL);
03891 GNC_RETURN_ENUM_AS_STRING(CURRENCY);
03892 GNC_RETURN_ENUM_AS_STRING(INCOME);
03893 GNC_RETURN_ENUM_AS_STRING(EXPENSE);
03894 GNC_RETURN_ENUM_AS_STRING(EQUITY);
03895 GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
03896 GNC_RETURN_ENUM_AS_STRING(PAYABLE);
03897 GNC_RETURN_ENUM_AS_STRING(ROOT);
03898 GNC_RETURN_ENUM_AS_STRING(TRADING);
03899 GNC_RETURN_ENUM_AS_STRING(CHECKING);
03900 GNC_RETURN_ENUM_AS_STRING(SAVINGS);
03901 GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
03902 GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
03903 default:
03904 PERR ("asked to translate unknown account type %d.\n", type);
03905 break;
03906 }
03907 return(NULL);
03908 }
03909
03910 #undef GNC_RETURN_ENUM_AS_STRING
03911
03912 #define GNC_RETURN_ON_MATCH(x) \
03913 if(safe_strcmp(#x, (str)) == 0) { *type = ACCT_TYPE_ ## x; return(TRUE); }
03914
03915 gboolean
03916 xaccAccountStringToType(const char* str, GNCAccountType *type)
03917 {
03918
03919 GNC_RETURN_ON_MATCH(NONE);
03920 GNC_RETURN_ON_MATCH(BANK);
03921 GNC_RETURN_ON_MATCH(CASH);
03922 GNC_RETURN_ON_MATCH(CREDIT);
03923 GNC_RETURN_ON_MATCH(ASSET);
03924 GNC_RETURN_ON_MATCH(LIABILITY);
03925 GNC_RETURN_ON_MATCH(STOCK);
03926 GNC_RETURN_ON_MATCH(MUTUAL);
03927 GNC_RETURN_ON_MATCH(CURRENCY);
03928 GNC_RETURN_ON_MATCH(INCOME);
03929 GNC_RETURN_ON_MATCH(EXPENSE);
03930 GNC_RETURN_ON_MATCH(EQUITY);
03931 GNC_RETURN_ON_MATCH(RECEIVABLE);
03932 GNC_RETURN_ON_MATCH(PAYABLE);
03933 GNC_RETURN_ON_MATCH(ROOT);
03934 GNC_RETURN_ON_MATCH(TRADING);
03935 GNC_RETURN_ON_MATCH(CHECKING);
03936 GNC_RETURN_ON_MATCH(SAVINGS);
03937 GNC_RETURN_ON_MATCH(MONEYMRKT);
03938 GNC_RETURN_ON_MATCH(CREDITLINE);
03939
03940 PERR("asked to translate unknown account type string %s.\n",
03941 str ? str : "(null)");
03942
03943 return(FALSE);
03944 }
03945
03946 #undef GNC_RETURN_ON_MATCH
03947
03948
03949 GNCAccountType
03950 xaccAccountStringToEnum(const char* str)
03951 {
03952 GNCAccountType type;
03953 gboolean rc;
03954 rc = xaccAccountStringToType(str, &type);
03955 if (FALSE == rc) return ACCT_TYPE_INVALID;
03956 return type;
03957 }
03958
03959
03960
03961
03962 static char *
03963 account_type_name[NUM_ACCOUNT_TYPES] =
03964 {
03965 N_("Bank"),
03966 N_("Cash"),
03967 N_("Asset"),
03968 N_("Credit Card"),
03969 N_("Liability"),
03970 N_("Stock"),
03971 N_("Mutual Fund"),
03972 N_("Currency"),
03973 N_("Income"),
03974 N_("Expense"),
03975 N_("Equity"),
03976 N_("A/Receivable"),
03977 N_("A/Payable"),
03978 N_("Root"),
03979 N_("Trading")
03980
03981
03982
03983
03984
03985
03986 };
03987
03988 const char *
03989 xaccAccountGetTypeStr(GNCAccountType type)
03990 {
03991 if (type < 0 || NUM_ACCOUNT_TYPES <= type ) return "";
03992 return _(account_type_name [type]);
03993 }
03994
03995 GNCAccountType
03996 xaccAccountGetTypeFromStr (const gchar *str)
03997 {
03998 gint type;
03999
04000 for (type = 0; type < NUM_ACCOUNT_TYPES; type++)
04001 {
04002 if (!safe_strcmp (str, _(account_type_name [type])))
04003 return type;
04004 }
04005
04006 PERR("asked to translate unknown account type string %s.\n",
04007 str ? str : "(null)");
04008
04009 return ACCT_TYPE_INVALID;
04010 }
04011
04012
04013
04014
04015
04016 guint32
04017 xaccParentAccountTypesCompatibleWith (GNCAccountType type)
04018 {
04019 switch (type)
04020 {
04021 case ACCT_TYPE_BANK:
04022 case ACCT_TYPE_CASH:
04023 case ACCT_TYPE_ASSET:
04024 case ACCT_TYPE_STOCK:
04025 case ACCT_TYPE_MUTUAL:
04026 case ACCT_TYPE_CURRENCY:
04027 case ACCT_TYPE_CREDIT:
04028 case ACCT_TYPE_LIABILITY:
04029 case ACCT_TYPE_RECEIVABLE:
04030 case ACCT_TYPE_PAYABLE:
04031 return
04032 (1 << ACCT_TYPE_BANK) |
04033 (1 << ACCT_TYPE_CASH) |
04034 (1 << ACCT_TYPE_ASSET) |
04035 (1 << ACCT_TYPE_STOCK) |
04036 (1 << ACCT_TYPE_MUTUAL) |
04037 (1 << ACCT_TYPE_CURRENCY) |
04038 (1 << ACCT_TYPE_CREDIT) |
04039 (1 << ACCT_TYPE_LIABILITY) |
04040 (1 << ACCT_TYPE_RECEIVABLE) |
04041 (1 << ACCT_TYPE_PAYABLE) |
04042 (1 << ACCT_TYPE_ROOT);
04043 case ACCT_TYPE_INCOME:
04044 case ACCT_TYPE_EXPENSE:
04045 return
04046 (1 << ACCT_TYPE_INCOME) |
04047 (1 << ACCT_TYPE_EXPENSE) |
04048 (1 << ACCT_TYPE_ROOT);
04049 case ACCT_TYPE_EQUITY:
04050 return
04051 (1 << ACCT_TYPE_EQUITY) |
04052 (1 << ACCT_TYPE_ROOT);
04053 case ACCT_TYPE_TRADING:
04054 return
04055 (1 << ACCT_TYPE_TRADING) |
04056 (1 << ACCT_TYPE_ROOT);
04057 default:
04058 PERR("bad account type: %d", type);
04059 return 0;
04060 }
04061 }
04062
04063 gboolean
04064 xaccAccountTypesCompatible (GNCAccountType parent_type,
04065 GNCAccountType child_type)
04066 {
04067 return ((xaccParentAccountTypesCompatibleWith (parent_type) &
04068 (1 << child_type))
04069 != 0);
04070 }
04071
04072 guint32
04073 xaccAccountTypesValid(void)
04074 {
04075 guint32 mask = (1 << NUM_ACCOUNT_TYPES) - 1;
04076 mask &= ~((1 << ACCT_TYPE_CURRENCY) |
04077 (1 << ACCT_TYPE_ROOT));
04078
04079 return mask;
04080 }
04081
04082 gboolean
04083 xaccAccountIsPriced(const Account *acc)
04084 {
04085 AccountPrivate *priv;
04086
04087 g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
04088
04089 priv = GET_PRIVATE(acc);
04090 return (priv->type == ACCT_TYPE_STOCK || priv->type == ACCT_TYPE_MUTUAL ||
04091 priv->type == ACCT_TYPE_CURRENCY);
04092 }
04093
04094
04095
04096
04097 gboolean
04098 xaccAccountGetReconcileLastDate (const Account *acc, time_t *last_date)
04099 {
04100 KvpValue *v;
04101
04102 if (!acc) return FALSE;
04103
04104 v = kvp_frame_get_value(acc->inst.kvp_data, "reconcile-info/last-date");
04105
04106 if (!v || kvp_value_get_type(v) != KVP_TYPE_GINT64)
04107 return FALSE;
04108
04109 if (last_date)
04110 *last_date = kvp_value_get_gint64(v);
04111
04112 return TRUE;
04113 }
04114
04115
04116
04117
04118 void
04119 xaccAccountSetReconcileLastDate (Account *acc, time_t last_date)
04120 {
04121 if (!acc) return;
04122
04123 xaccAccountBeginEdit (acc);
04124 kvp_frame_set_gint64 (acc->inst.kvp_data,
04125 "/reconcile-info/last-date", last_date);
04126 mark_account (acc);
04127 xaccAccountCommitEdit (acc);
04128 }
04129
04130
04131
04132
04133 gboolean
04134 xaccAccountGetReconcileLastInterval (const Account *acc,
04135 int *months, int *days)
04136 {
04137 KvpValue *v1, *v2;
04138
04139 if (!acc) return FALSE;
04140
04141 v1 = kvp_frame_get_value(acc->inst.kvp_data,
04142 "reconcile-info/last-interval/months");
04143 v2 = kvp_frame_get_value(acc->inst.kvp_data,
04144 "reconcile-info/last-interval/days");
04145 if (!v1 || (kvp_value_get_type (v1) != KVP_TYPE_GINT64) ||
04146 !v2 || (kvp_value_get_type (v2) != KVP_TYPE_GINT64))
04147 return FALSE;
04148
04149 if (months)
04150 *months = kvp_value_get_gint64 (v1);
04151 if (days)
04152 *days = kvp_value_get_gint64 (v2);
04153 return TRUE;
04154 }
04155
04156
04157
04158
04159 void
04160 xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
04161 {
04162 KvpFrame *frame;
04163 if (!acc) return;
04164
04165 xaccAccountBeginEdit (acc);
04166
04167 frame = kvp_frame_get_frame_slash (acc->inst.kvp_data,
04168 "/reconcile-info/last-interval");
04169 g_assert(frame);
04170
04171 kvp_frame_set_gint64 (frame, "months", months);
04172 kvp_frame_set_gint64 (frame, "days", days);
04173
04174 mark_account (acc);
04175 xaccAccountCommitEdit (acc);
04176 }
04177
04178
04179
04180
04181 gboolean
04182 xaccAccountGetReconcilePostponeDate (const Account *acc, time_t *postpone_date)
04183 {
04184 KvpValue *v;
04185
04186 if (!acc) return FALSE;
04187
04188 v = kvp_frame_get_value(acc->inst.kvp_data, "reconcile-info/postpone/date");
04189 if (!v || kvp_value_get_type (v) != KVP_TYPE_GINT64)
04190 return FALSE;
04191
04192 if (postpone_date)
04193 *postpone_date = kvp_value_get_gint64 (v);
04194
04195 return TRUE;
04196 }
04197
04198
04199
04200
04201 void
04202 xaccAccountSetReconcilePostponeDate (Account *acc, time_t postpone_date)
04203 {
04204 if (!acc) return;
04205
04206 xaccAccountBeginEdit (acc);
04207
04208
04209 kvp_frame_set_gint64 (acc->inst.kvp_data,
04210 "reconcile-info/postpone/date", postpone_date);
04211 mark_account (acc);
04212 xaccAccountCommitEdit (acc);
04213 }
04214
04215
04216
04217
04218 gboolean
04219 xaccAccountGetReconcilePostponeBalance (const Account *acc,
04220 gnc_numeric *balance)
04221 {
04222 KvpValue *v;
04223
04224 if (!acc) return FALSE;
04225
04226 v = kvp_frame_get_value(acc->inst.kvp_data,
04227 "reconcile-info/postpone/balance");
04228 if (!v || kvp_value_get_type (v) != KVP_TYPE_NUMERIC)
04229 return FALSE;
04230
04231 if (balance)
04232 *balance = kvp_value_get_numeric (v);
04233
04234 return TRUE;
04235 }
04236
04237
04238
04239
04240 void
04241 xaccAccountSetReconcilePostponeBalance (Account *acc, gnc_numeric balance)
04242 {
04243 if (!acc) return;
04244
04245 xaccAccountBeginEdit (acc);
04246 kvp_frame_set_gnc_numeric (acc->inst.kvp_data,
04247 "/reconcile-info/postpone/balance", balance);
04248 mark_account (acc);
04249 xaccAccountCommitEdit (acc);
04250 }
04251
04252
04253
04254
04255
04256 void
04257 xaccAccountClearReconcilePostpone (Account *acc)
04258 {
04259 if (!acc) return;
04260
04261 xaccAccountBeginEdit (acc);
04262 kvp_frame_set_value (acc->inst.kvp_data, "reconcile-info/postpone", NULL);
04263 mark_account (acc);
04264 xaccAccountCommitEdit (acc);
04265 }
04266
04267
04268
04269
04270
04271
04272
04273
04274 gboolean
04275 xaccAccountGetAutoInterestXfer (const Account *acc, gboolean default_value)
04276 {
04277 const char *str = NULL;
04278 if (!acc) return default_value;
04279
04280 str = kvp_frame_get_string(acc->inst.kvp_data,
04281 "reconcile-info/auto-interest-transfer");
04282 return str ? !strcmp(str, "true") : default_value;
04283 }
04284
04285
04286
04287
04288 void
04289 xaccAccountSetAutoInterestXfer (Account *acc, gboolean option)
04290 {
04291 if (!acc) return;
04292
04293 xaccAccountBeginEdit (acc);
04294
04295 kvp_frame_set_string (acc->inst.kvp_data,
04296 "/reconcile-info/auto-interest-transfer",
04297 (option ? "true" : "false"));
04298 mark_account (acc);
04299 xaccAccountCommitEdit (acc);
04300 }
04301
04302
04303
04304
04305 const char *
04306 xaccAccountGetLastNum (const Account *acc)
04307 {
04308 return acc ? kvp_frame_get_string(acc->inst.kvp_data, "last-num") : NULL;
04309 }
04310
04311
04312
04313
04314 void
04315 xaccAccountSetLastNum (Account *acc, const char *num)
04316 {
04317 if (!acc) return;
04318
04319 xaccAccountBeginEdit (acc);
04320 kvp_frame_set_string(acc->inst.kvp_data, "last-num", num);
04321 mark_account (acc);
04322 xaccAccountCommitEdit (acc);
04323 }
04324
04325
04326
04327
04328 void
04329 dxaccAccountSetPriceSrc(Account *acc, const char *src)
04330 {
04331 if (!acc) return;
04332
04333 xaccAccountBeginEdit(acc);
04334 if (xaccAccountIsPriced(acc))
04335 {
04336 kvp_frame_set_slot_nc(acc->inst.kvp_data,
04337 "old-price-source",
04338 src ? kvp_value_new_string(src) : NULL);
04339 mark_account (acc);
04340 }
04341
04342 qof_instance_set_dirty(&acc->inst);
04343 xaccAccountCommitEdit(acc);
04344 }
04345
04346
04347
04348
04349 const char*
04350 dxaccAccountGetPriceSrc(const Account *acc)
04351 {
04352 if (!acc) return NULL;
04353
04354 if (xaccAccountIsPriced(acc))
04355 {
04356 KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data,
04357 "old-price-source");
04358 if (value) return (kvp_value_get_string(value));
04359 }
04360 return NULL;
04361 }
04362
04363
04364
04365
04366 void
04367 dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
04368 {
04369 if (!acc) return;
04370
04371 xaccAccountBeginEdit(acc);
04372 if (xaccAccountIsPriced(acc))
04373 {
04374 kvp_frame_set_slot_nc(acc->inst.kvp_data,
04375 "old-quote-tz",
04376 tz ? kvp_value_new_string(tz) : NULL);
04377 mark_account (acc);
04378 }
04379 qof_instance_set_dirty(&acc->inst);
04380 xaccAccountCommitEdit(acc);
04381 }
04382
04383
04384
04385
04386 const char*
04387 dxaccAccountGetQuoteTZ(const Account *acc)
04388 {
04389 if (!acc) return NULL;
04390
04391 if (xaccAccountIsPriced(acc))
04392 {
04393 KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data, "old-quote-tz");
04394 if (value) return (kvp_value_get_string(value));
04395 }
04396 return NULL;
04397 }
04398
04399
04400
04401
04402 void
04403 xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
04404 {
04405 if (!acc) return;
04406
04407 xaccAccountBeginEdit (acc);
04408
04409
04410 kvp_frame_set_gint64 (acc->inst.kvp_data,
04411 "/reconcile-info/include-children", status);
04412 mark_account(acc);
04413 xaccAccountCommitEdit (acc);
04414 }
04415
04416
04417
04418
04419 gboolean
04420 xaccAccountGetReconcileChildrenStatus(const Account *acc)
04421 {
04422
04423
04424
04425
04426 return acc ? kvp_frame_get_gint64(acc->inst.kvp_data,
04427 "reconcile-info/include-children") : FALSE;
04428 }
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438 static void
04439 finder_help_function(const Account *acc, const char *description,
04440 Split **split, Transaction **trans )
04441 {
04442 AccountPrivate *priv;
04443 GList *slp;
04444
04445
04446 if (split) *split = NULL;
04447 if (trans) *trans = NULL;
04448
04449
04450 if (acc == NULL) return;
04451
04452
04453
04454
04455 priv = GET_PRIVATE(acc);
04456 for (slp = g_list_last(priv->splits); slp; slp = slp->prev)
04457 {
04458 Split *lsplit = slp->data;
04459 Transaction *ltrans = xaccSplitGetParent(lsplit);
04460
04461 if (safe_strcmp (description, xaccTransGetDescription (ltrans)) == 0)
04462 {
04463 if (split) *split = lsplit;
04464 if (trans) *trans = ltrans;
04465 return;
04466 }
04467 }
04468 }
04469
04470 Split *
04471 xaccAccountFindSplitByDesc(const Account *acc, const char *description)
04472 {
04473 Split *split;
04474
04475
04476 finder_help_function(acc, description, &split, NULL);
04477 return split;
04478 }
04479
04480
04481
04482
04483
04484
04485 Transaction *
04486 xaccAccountFindTransByDesc(const Account *acc, const char *description)
04487 {
04488 Transaction *trans;
04489
04490
04491 finder_help_function(acc, description, NULL, &trans);
04492 return trans;
04493 }
04494
04495
04496
04497
04498 void
04499 gnc_account_join_children (Account *to_parent, Account *from_parent)
04500 {
04501 AccountPrivate *from_priv;
04502 GList *children, *node;
04503
04504
04505 g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
04506 g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
04507
04508
04509 from_priv = GET_PRIVATE(from_parent);
04510 if (!from_priv->children)
04511 return;
04512
04513 ENTER (" ");
04514 children = g_list_copy(from_priv->children);
04515 for (node = children; node; node = g_list_next(node))
04516 gnc_account_append_child(to_parent, node->data);
04517 g_list_free(children);
04518 LEAVE (" ");
04519 }
04520
04521 void
04522 gnc_account_copy_children (Account *to, Account *from)
04523 {
04524 AccountPrivate *to_priv, *from_priv;
04525 GList *node;
04526 QofBook *to_book;
04527
04528
04529 g_return_if_fail(GNC_IS_ACCOUNT(to));
04530 g_return_if_fail(GNC_IS_ACCOUNT(from));
04531
04532
04533 to_priv = GET_PRIVATE(to);
04534 from_priv = GET_PRIVATE(from);
04535 if (!from_priv->children)
04536 return;
04537
04538 to_book = gnc_account_get_book(to);
04539 if (!to_book) return;
04540
04541 ENTER (" ");
04542 xaccAccountBeginEdit(to);
04543 xaccAccountBeginEdit(from);
04544 for (node = from_priv->children; node; node = node->next)
04545 {
04546 Account *to_acc, *from_acc = node->data;
04547
04548
04549
04550 to_acc = xaccCloneAccount (from_acc, to_book);
04551
04552 xaccAccountBeginEdit (to_acc);
04553 to_priv->children = g_list_append(to_priv->children, to_acc);
04554
04555 GET_PRIVATE(to_acc)->parent = to;
04556 qof_instance_set_dirty(&to_acc->inst);
04557
04558
04559 if (GET_PRIVATE(from_acc)->children)
04560 {
04561 gnc_account_copy_children(to_acc, from_acc);
04562 }
04563 xaccAccountCommitEdit (to_acc);
04564 qof_event_gen (&to_acc->inst, QOF_EVENT_CREATE, NULL);
04565
04566 }
04567 xaccAccountCommitEdit(from);
04568 xaccAccountCommitEdit(to);
04569 LEAVE (" ");
04570 }
04571
04572
04573
04574
04575 void
04576 gnc_account_merge_children (Account *parent)
04577 {
04578 AccountPrivate *ppriv, *priv_a, *priv_b;
04579 GList *node_a, *node_b, *work, *worker;
04580
04581 g_return_if_fail(GNC_IS_ACCOUNT(parent));
04582
04583 ppriv = GET_PRIVATE(parent);
04584 for (node_a = ppriv->children; node_a; node_a = node_a->next)
04585 {
04586 Account *acc_a = node_a->data;
04587
04588 priv_a = GET_PRIVATE(acc_a);
04589 for (node_b = node_a->next; node_b; node_b = g_list_next(node_b))
04590 {
04591 Account *acc_b = node_b->data;
04592
04593 priv_b = GET_PRIVATE(acc_b);
04594 if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
04595 continue;
04596 if (0 != null_strcmp(priv_a->accountCode, priv_b->accountCode))
04597 continue;
04598 if (0 != null_strcmp(priv_a->description, priv_b->description))
04599 continue;
04600 if (0 != null_strcmp(xaccAccountGetColor(acc_a),
04601 xaccAccountGetColor(acc_b)))
04602 continue;
04603 if (!gnc_commodity_equiv(priv_a->commodity, priv_b->commodity))
04604 continue;
04605 if (0 != null_strcmp(xaccAccountGetNotes(acc_a),
04606 xaccAccountGetNotes(acc_b)))
04607 continue;
04608 if (priv_a->type != priv_b->type)
04609 continue;
04610
04611
04612 if (priv_b->children)
04613 {
04614 work = g_list_copy(priv_b->children);
04615 for (worker = work; worker; worker = g_list_next(worker))
04616 gnc_account_append_child (acc_a, (Account *)worker->data);
04617 g_list_free(work);
04618
04619 qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, NULL);
04620 qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, NULL);
04621 }
04622
04623
04624 gnc_account_merge_children (acc_a);
04625
04626
04627 while (priv_b->splits)
04628 xaccSplitSetAccount (priv_b->splits->data, acc_a);
04629
04630
04631
04632 node_b = g_list_previous(node_b);
04633
04634
04635
04636 xaccAccountBeginEdit (acc_b);
04637 xaccAccountDestroy (acc_b);
04638 }
04639 }
04640 }
04641
04642
04643
04644
04645
04646 void
04647 xaccSplitsBeginStagedTransactionTraversals (GList *splits)
04648 {
04649 GList *lp;
04650
04651 for (lp = splits; lp; lp = lp->next)
04652 {
04653 Split *s = lp->data;
04654 Transaction *trans = s->parent;
04655
04656 if (trans)
04657 trans->marker = 0;
04658 }
04659 }
04660
04661
04662 void
04663 xaccAccountBeginStagedTransactionTraversals (const Account *account)
04664 {
04665 AccountPrivate *priv;
04666
04667 if (!account)
04668 return;
04669 priv = GET_PRIVATE(account);
04670 xaccSplitsBeginStagedTransactionTraversals(priv->splits);
04671 }
04672
04673 gboolean
04674 xaccTransactionTraverse (Transaction *trans, int stage)
04675 {
04676 if (trans == NULL) return FALSE;
04677
04678 if (trans->marker < stage)
04679 {
04680 trans->marker = stage;
04681 return TRUE;
04682 }
04683
04684 return FALSE;
04685 }
04686
04687 gboolean
04688 xaccSplitTransactionTraverse (Split *split, int stage)
04689 {
04690 if (split == NULL) return FALSE;
04691
04692 return xaccTransactionTraverse (split->parent, stage);
04693 }
04694
04695 static void do_one_split (Split *s, gpointer data)
04696 {
04697 Transaction *trans = s->parent;
04698 trans->marker = 0;
04699 }
04700
04701 static void do_one_account (Account *account, gpointer data)
04702 {
04703 AccountPrivate *priv = GET_PRIVATE(account);
04704 g_list_foreach(priv->splits, (GFunc)do_one_split, NULL);
04705 }
04706
04707
04708 void
04709 gnc_account_tree_begin_staged_transaction_traversals (Account *account)
04710 {
04711 GList *descendants;
04712
04713 descendants = gnc_account_get_descendants(account);
04714 g_list_foreach(descendants, (GFunc)do_one_account, NULL);
04715 g_list_free(descendants);
04716 }
04717
04718 int
04719 xaccAccountStagedTransactionTraversal (const Account *acc,
04720 unsigned int stage,
04721 TransactionCallback thunk,
04722 void *cb_data)
04723 {
04724 AccountPrivate *priv;
04725 GList *split_p;
04726 GList *next;
04727 Transaction *trans;
04728 Split *s;
04729 int retval;
04730
04731 if (!acc) return 0;
04732
04733 priv = GET_PRIVATE(acc);
04734 for (split_p = priv->splits; split_p; split_p = next)
04735 {
04736
04737
04738
04739
04740 next = g_list_next(split_p);
04741
04742 s = split_p->data;
04743 trans = s->parent;
04744 if (trans && (trans->marker < stage))
04745 {
04746 trans->marker = stage;
04747 if (thunk)
04748 {
04749 retval = thunk(trans, cb_data);
04750 if (retval) return retval;
04751 }
04752 }
04753 }
04754
04755 return 0;
04756 }
04757
04758 int
04759 gnc_account_tree_staged_transaction_traversal (const Account *acc,
04760 unsigned int stage,
04761 TransactionCallback thunk,
04762 void *cb_data)
04763 {
04764 const AccountPrivate *priv;
04765 GList *acc_p, *split_p;
04766 Transaction *trans;
04767 Split *s;
04768 int retval;
04769
04770 if (!acc) return 0;
04771
04772
04773 priv = GET_PRIVATE(acc);
04774 for (acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
04775 {
04776 retval = gnc_account_tree_staged_transaction_traversal(acc_p->data, stage,
04777 thunk, cb_data);
04778 if (retval) return retval;
04779 }
04780
04781
04782 for (split_p = priv->splits; split_p; split_p = g_list_next(split_p))
04783 {
04784 s = split_p->data;
04785 trans = s->parent;
04786 if (trans && (trans->marker < stage))
04787 {
04788 trans->marker = stage;
04789 if (thunk)
04790 {
04791 retval = thunk(trans, cb_data);
04792 if (retval) return retval;
04793 }
04794 }
04795 }
04796
04797 return 0;
04798 }
04799
04800
04801
04802
04803 int
04804 xaccAccountTreeForEachTransaction (Account *acc,
04805 int (*proc)(Transaction *t, void *data),
04806 void *data)
04807 {
04808 if (!acc || !proc) return 0;
04809
04810 gnc_account_tree_begin_staged_transaction_traversals (acc);
04811 return gnc_account_tree_staged_transaction_traversal (acc, 42, proc, data);
04812 }
04813
04814
04815 gint
04816 xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
04817 void *data)
04818 {
04819 if (!acc || !proc) return 0;
04820 xaccAccountBeginStagedTransactionTraversals (acc);
04821 return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
04822 }
04823
04824
04825
04826
04827 static void
04828 gnc_account_book_end(QofBook* book)
04829 {
04830 Account *root_account = gnc_book_get_root_account(book);
04831
04832 xaccAccountBeginEdit(root_account);
04833 xaccAccountDestroy(root_account);
04834 }
04835
04836 #ifdef _MSC_VER
04837
04838
04839 # define DI(x)
04840 #else
04841 # define DI(x) x
04842 #endif
04843 static QofObject account_object_def =
04844 {
04845 DI(.interface_version = ) QOF_OBJECT_VERSION,
04846 DI(.e_type = ) GNC_ID_ACCOUNT,
04847 DI(.type_label = ) "Account",
04848 DI(.create = ) (gpointer)xaccMallocAccount,
04849 DI(.book_begin = ) NULL,
04850 DI(.book_end = ) gnc_account_book_end,
04851 DI(.is_dirty = ) qof_collection_is_dirty,
04852 DI(.mark_clean = ) qof_collection_mark_clean,
04853 DI(.foreach = ) qof_collection_foreach,
04854 DI(.printable = ) (const char * (*)(gpointer)) xaccAccountGetName,
04855 DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
04856 };
04857
04858 gboolean xaccAccountRegister (void)
04859 {
04860 static QofParam params[] =
04861 {
04862 {
04863 ACCOUNT_NAME_, QOF_TYPE_STRING,
04864 (QofAccessFunc) xaccAccountGetName,
04865 (QofSetterFunc) xaccAccountSetName
04866 },
04867 {
04868 ACCOUNT_CODE_, QOF_TYPE_STRING,
04869 (QofAccessFunc) xaccAccountGetCode,
04870 (QofSetterFunc) xaccAccountSetCode
04871 },
04872 {
04873 ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING,
04874 (QofAccessFunc) xaccAccountGetDescription,
04875 (QofSetterFunc) xaccAccountSetDescription
04876 },
04877 {
04878 ACCOUNT_COLOR_, QOF_TYPE_STRING,
04879 (QofAccessFunc) xaccAccountGetColor,
04880 (QofSetterFunc) xaccAccountSetColor
04881 },
04882 {
04883 ACCOUNT_NOTES_, QOF_TYPE_STRING,
04884 (QofAccessFunc) xaccAccountGetNotes,
04885 (QofSetterFunc) xaccAccountSetNotes
04886 },
04887 {
04888 ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC,
04889 (QofAccessFunc) xaccAccountGetPresentBalance, NULL
04890 },
04891 {
04892 ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC,
04893 (QofAccessFunc) xaccAccountGetBalance, NULL
04894 },
04895 {
04896 ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC,
04897 (QofAccessFunc) xaccAccountGetClearedBalance, NULL
04898 },
04899 {
04900 ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC,
04901 (QofAccessFunc) xaccAccountGetReconciledBalance, NULL
04902 },
04903 {
04904 ACCOUNT_TYPE_, QOF_TYPE_STRING,
04905 (QofAccessFunc) qofAccountGetTypeString,
04906 (QofSetterFunc) qofAccountSetType
04907 },
04908 {
04909 ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC,
04910 (QofAccessFunc) xaccAccountGetProjectedMinimumBalance, NULL
04911 },
04912 {
04913 ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN,
04914 (QofAccessFunc) xaccAccountGetTaxRelated,
04915 (QofSetterFunc) xaccAccountSetTaxRelated
04916 },
04917 {
04918 ACCOUNT_SCU, QOF_TYPE_INT32,
04919 (QofAccessFunc) xaccAccountGetCommoditySCU,
04920 (QofSetterFunc) xaccAccountSetCommoditySCU
04921 },
04922 {
04923 ACCOUNT_NSCU, QOF_TYPE_BOOLEAN,
04924 (QofAccessFunc) xaccAccountGetNonStdSCU,
04925 (QofSetterFunc) xaccAccountSetNonStdSCU
04926 },
04927 {
04928 ACCOUNT_PARENT, GNC_ID_ACCOUNT,
04929 (QofAccessFunc) gnc_account_get_parent,
04930 (QofSetterFunc) qofAccountSetParent
04931 },
04932 {
04933 QOF_PARAM_BOOK, QOF_ID_BOOK,
04934 (QofAccessFunc) qof_instance_get_book, NULL
04935 },
04936 {
04937 QOF_PARAM_GUID, QOF_TYPE_GUID,
04938 (QofAccessFunc) qof_instance_get_guid, NULL
04939 },
04940 {
04941 ACCOUNT_KVP, QOF_TYPE_KVP,
04942 (QofAccessFunc) qof_instance_get_slots, NULL
04943 },
04944 { NULL },
04945 };
04946
04947 qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc) qof_xaccAccountOrder, params);
04948
04949 return qof_object_register (&account_object_def);
04950 }
04951
04952
04953
04954
04955
04956
04957
04958
04959