59 #include <glib/gi18n.h> 66 #include "TransactionP.hpp" 69 #include "engine-helpers.h" 74 static QofLogModule log_module = GNC_MOD_LOT;
82 gnc_commodity *acc_comm;
84 if (!acc)
return FALSE;
91 for (
auto s : xaccAccountGetSplits (acc))
93 Transaction *t = s->parent;
94 if (s->gains == GAINS_STATUS_GAINS)
continue;
95 if (acc_comm != t->common_currency)
return TRUE;
106 gnc_commodity *currency;
108 int (*numeric_pred)(gnc_numeric);
125 finder_helper (GNCLot *lot, gpointer user_data)
127 auto els =
static_cast<FindLot*
>(user_data);
131 gboolean opening_is_positive, bal_is_positive;
137 if (s ==
nullptr)
return nullptr;
143 if (0 == (els->numeric_pred) (s->amount))
return nullptr;
147 if (opening_is_positive != bal_is_positive)
return nullptr;
152 trans->common_currency)))
157 posted = trans->date_posted;
158 if (els->date_pred (els->time, posted))
160 els->time = trans->date_posted;
167 static inline GNCLot *
168 xaccAccountFindOpenLot (
Account *acc, gnc_numeric sign,
169 gnc_commodity *currency,
176 es.currency = currency;
178 es.date_pred = date_pred;
189 gnc_commodity *currency)
192 ENTER (
" sign=%" G_GINT64_FORMAT
"/%" G_GINT64_FORMAT, sign.num,
195 lot = xaccAccountFindOpenLot (acc, sign, currency,
196 G_MAXINT64, earliest_pred);
197 LEAVE (
"found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
203 xaccAccountFindLatestOpenLot (
Account *acc, gnc_numeric sign,
204 gnc_commodity *currency)
207 ENTER (
" sign=%" G_GINT64_FORMAT
"/%" G_GINT64_FORMAT,
208 sign.num, sign.denom);
210 lot = xaccAccountFindOpenLot (acc, sign, currency,
211 G_MININT64, latest_pred);
212 LEAVE (
"found lot=%p %s", lot, gnc_lot_get_title (lot));
224 gboolean baln_is_positive, amt_is_positive;
226 if (!lot)
return split;
227 if (!split)
return nullptr;
230 if (split->lot)
return nullptr;
240 PWARN (
"split with zero amount; value=%s gflag=%x gsplit=%p",
244 if (split->gains_split)
246 PWARN (
"gains amt=%s value=%s",
264 PINFO (
"added split to empty lot, new lot baln=%s (%s)",
266 gnc_lot_get_title (lot));
281 if ((baln_is_positive && amt_is_positive) ||
282 ((!baln_is_positive) && (!amt_is_positive)))
284 PWARN (
"accounting policy gave us split that enlarges the lot!\n" 285 "old lot baln=%s split amt=%s lot=%s",
288 gnc_lot_get_title (lot));
305 gnc_lot_get_title (lot));
313 PINFO (
"simple added split to lot, new lot baln=%s",
324 gnc_numeric amt_a, amt_b, amt_tot;
325 gnc_numeric val_a, val_b, val_tot;
331 trans = split->parent;
334 amt_tot = split->amount;
336 amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
339 PINFO (
"++++++++++++++ splitting split=%p into amt = %s + %s",
347 val_tot = split->value;
351 gnc_numeric_denom(val_tot),
354 val_b = gnc_numeric_sub_fixed (val_tot, val_a);
357 PERR(
"Numeric overflow\n" 359 "\tval_tot=%s amt_a=%s amt_tot=%s\n",
369 PERR (
"Failed to split into two!");
372 PINFO (
"split value is = %s = %s + %s",
395 gnc_set_num_action(
nullptr, new_split,
nullptr, gnc_get_num_action(
nullptr, split));
429 gboolean splits_split_up = FALSE;
433 if (!split)
return FALSE;
438 if (split->lot)
return FALSE;
439 g_return_val_if_fail (split->gains == GAINS_STATUS_UNKNOWN ||
440 (split->gains & GAINS_STATUS_GAINS) == FALSE, FALSE);
447 ENTER (
"(split=%p)", split);
459 PINFO (
"have split %p amount=%s", split,
461 split->gains |= GAINS_STATUS_VDIRTY;
462 lot = pcy->PolicyGetLot (pcy, split);
466 PINFO (
"start new lot (%s)", gnc_lot_get_title(lot));
469 if (split) splits_split_up = TRUE;
473 LEAVE (
" split_up=%d", splits_split_up);
474 return splits_split_up;
485 if (!split)
return nullptr;
488 "gains-split", &gains_guid,
490 if (!gains_guid)
return nullptr;
495 PINFO (
"split=%p has gains-split=%p", split, gains_split);
496 guid_free (gains_guid);
508 if (!split)
return nullptr;
511 "gains-source", &source_guid,
513 if (!source_guid)
return nullptr;
518 PINFO (
"split=%p has source-split=%p", split, source_split);
519 guid_free (source_guid);
531 gnc_commodity *currency =
nullptr;
532 gnc_numeric zero = gnc_numeric_zero();
535 gnc_numeric opening_amount, opening_value;
536 gnc_numeric lot_amount, lot_value;
537 gnc_commodity *opening_currency;
543 currency = split->parent->common_currency;
545 ENTER (
"(split=%p gains=%p status=0x%x lot=%s)", split,
546 split->gains_split, split->gains, gnc_lot_get_title(lot));
549 xaccSplitDetermineGainStatus(split);
556 LEAVE (
"Currency transfer, gains not possible, returning.");
560 if (pcy->PolicyIsOpeningSplit (pcy, lot, split))
562 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER 572 Transaction *trans = gains_split->parent;
573 PERR (
"Opening Split must not have cap gains!!\n");
580 LEAVE (
"Lot opening split, returning.");
586 LEAVE (
"Stock split split, returning.");
590 if (GAINS_STATUS_GAINS & split->gains)
593 PINFO (
"split is a gains recording split, switch over");
598 s = split->gains_split;
607 PERR (
"Bad gains-split pointer! .. trying to recover.");
609 s = split->gains_split;
611 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER 623 Split *s = GNC_SPLIT(node->data);
624 if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
626 if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus (s);
627 if (s->gains & GAINS_STATUS_VDIRTY)
630 split->gains |= GAINS_STATUS_VDIRTY;
638 if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) &&
639 (split->gains_split) &&
640 (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
642 LEAVE (
"split not dirty, returning");
657 pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
668 LEAVE (
"Can't compute gains, mismatched commodities!");
683 Split *s = GNC_SPLIT(n->data);
686 PERR (
"Malformed Lot \"%s\"! (too thin!) " 687 "opening amt=%s split amt=%s baln=%s",
688 gnc_lot_get_title (lot),
702 Split *s = GNC_SPLIT(n->data);
705 PERR (
"Malformed Lot \"%s\"! (too fat!) " 706 "opening amt=%s split amt=%s baln=%s",
707 gnc_lot_get_title (lot),
727 gnc_numeric_denom(opening_value),
732 PINFO (
"Open amt=%s val=%s; split amt=%s val=%s; gains=%s\n",
740 PERR (
"Numeric overflow during gains calculation\n" 742 "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
762 Split *lot_split, *gain_split;
763 gboolean new_gain_split;
771 lot_split = split->gains_split;
773 if (
nullptr == lot_split)
779 new_gain_split = TRUE;
785 if ((
nullptr == gain_acc) ||
828 trans = lot_split->parent;
835 new_gain_split = FALSE;
841 else if (split->gains_split == lot_split &&
842 lot_split->gains_split == split &&
843 gain_split->gains_split == split &&
849 new_gain_split = FALSE;
853 new_gain_split = TRUE;
860 PWARN (
"Resetting the transaction currency!");
880 split->gains = GAINS_STATUS_CLEAN;
881 split->gains_split = lot_split;
882 lot_split->gains = GAINS_STATUS_GAINS;
883 lot_split->gains_split = split;
884 gain_split->gains = GAINS_STATUS_GAINS;
885 gain_split->gains_split = split;
894 LEAVE (
"(lot=%s)", gnc_lot_get_title(lot));
902 if (!split)
return gnc_numeric_zero();
903 ENTER(
"(split=%p)", split);
905 if (GAINS_STATUS_UNKNOWN == split->gains)
906 xaccSplitDetermineGainStatus(split);
907 if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
908 (split->gains_split &&
909 (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
917 if (!(GAINS_STATUS_GAINS & split->gains))
920 split = split->gains_split;
923 LEAVE(
"(split=%p)", split);
924 if (!split)
return gnc_numeric_zero();
932 xaccLotComputeCapGains (GNCLot *lot,
Account *gain_acc)
936 gboolean is_dirty = FALSE;
942 ENTER(
"(lot=%p)", lot);
946 Split *s = GNC_SPLIT(node->data);
947 if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
949 if (GAINS_STATUS_UNKNOWN == s->gains)
950 xaccSplitDetermineGainStatus(s);
951 if (s->gains & GAINS_STATUS_VDIRTY)
954 s->gains &= ~GAINS_STATUS_VDIRTY;
963 Split *s = GNC_SPLIT(node->data);
964 s->gains |= GAINS_STATUS_VDIRTY;
970 Split *s = GNC_SPLIT(node->data);
973 LEAVE(
"(lot=%p)", lot);
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
GNCLot * xaccAccountFindEarliestOpenLot(Account *acc, gnc_numeric sign, gnc_commodity *currency)
The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open ...
This is the private header for the account structure.
High-Level API for imposing Lot constraints.
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split's lot-split list.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
gpointer xaccAccountForEachLot(const Account *acc, gpointer(*proc)(GNCLot *lot, gpointer user_data), gpointer user_data)
The xaccAccountForEachLot() method will apply the function 'proc' to each lot in the account...
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
#define PINFO(format, args...)
Print an informational note.
Utilities to Convert Stock Accounts to use Lots.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
All arguments are required to have the same denominator, that denominator is to be used in the output...
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gboolean xaccAccountHasTrades(const Account *acc)
The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of co...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
gnc_numeric xaccSplitGetCapGains(Split *split)
The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the ind...
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split...
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
GList SplitList
GList of Split.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Account public routines (C++ api)
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Implement Accounting Policy.
Implement Accounting Policy Private header File.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void gnc_lot_get_balance_before(const GNCLot *lot, const Split *split, gnc_numeric *amount, gnc_numeric *value)
Computes both the balance and value in the lot considering only splits in transactions prior to the o...
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Split * xaccMallocSplit(QofBook *book)
Constructor.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64. ...
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
GNCLot * gnc_lot_make_default(Account *acc)
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lo...
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Account * xaccAccountGainsAccount(Account *acc, gnc_commodity *curr)
Retrieve the gains account used by this account for the indicated currency, creating and recording a ...
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
time64 gnc_time(time64 *tbuf)
get the current time
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
const char * xaccSplitGetType(const Split *s)
The xaccIsPeerSplit() is a convenience routine that returns TRUE (a non-zero value) if the two splits...
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
API for Transactions and Splits (journal entries)
The type used to store guids in C.
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Utilities to Automatically Compute Capital Gains/Losses.
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.