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;
344 amt_tot = split->amount;
346 amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
349 PINFO (
"++++++++++++++ splitting split=%p into amt = %s + %s",
357 val_tot = split->value;
361 gnc_numeric_denom(val_tot),
364 val_b = gnc_numeric_sub_fixed (val_tot, val_a);
367 PERR(
"Numeric overflow\n" 369 "\tval_tot=%s amt_a=%s amt_tot=%s\n",
379 PERR (
"Failed to split into two!");
382 PINFO (
"split value is = %s = %s + %s",
405 gnc_set_num_action(
nullptr, new_split,
nullptr, gnc_get_num_action(
nullptr, split));
439 gboolean splits_split_up = FALSE;
443 if (!split)
return FALSE;
448 if (split->lot)
return FALSE;
449 g_return_val_if_fail (split->gains == GAINS_STATUS_UNKNOWN ||
450 (split->gains & GAINS_STATUS_GAINS) == FALSE, FALSE);
457 ENTER (
"(split=%p)", split);
469 PINFO (
"have split %p amount=%s", split,
471 split->gains |= GAINS_STATUS_VDIRTY;
472 lot = pcy->PolicyGetLot (pcy, split);
476 PINFO (
"start new lot (%s)", gnc_lot_get_title(lot));
479 if (split) splits_split_up = TRUE;
483 LEAVE (
" split_up=%d", splits_split_up);
484 return splits_split_up;
490 find_split_by_type (
const gchar *type,
const Split *split)
494 if (!split)
return nullptr;
497 if (!type_guid)
return nullptr;
501 PINFO (
"split=%p has %s=%p", split, type, guid_split);
502 guid_free (type_guid);
510 return find_split_by_type (
"gains-split", split);
516 return find_split_by_type (
"gains-source", split);
527 gnc_commodity *currency =
nullptr;
528 gnc_numeric zero = gnc_numeric_zero();
531 gnc_numeric opening_amount, opening_value;
532 gnc_numeric lot_amount, lot_value;
533 gnc_commodity *opening_currency;
539 currency = split->parent->common_currency;
541 ENTER (
"(split=%p gains=%p status=0x%x lot=%s)", split,
542 split->gains_split, split->gains, gnc_lot_get_title(lot));
545 xaccSplitDetermineGainStatus(split);
552 LEAVE (
"Currency transfer, gains not possible, returning.");
556 if (pcy->PolicyIsOpeningSplit (pcy, lot, split))
558 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER 568 Transaction *trans = gains_split->parent;
569 PERR (
"Opening Split must not have cap gains!!\n");
576 LEAVE (
"Lot opening split, returning.");
582 LEAVE (
"Stock split split, returning.");
586 if (GAINS_STATUS_GAINS & split->gains)
589 PINFO (
"split is a gains recording split, switch over");
594 s = split->gains_split;
603 PERR (
"Bad gains-split pointer! .. trying to recover.");
605 s = split->gains_split;
607 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER 619 Split *s = GNC_SPLIT(node->data);
620 if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
622 if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus (s);
623 if (s->gains & GAINS_STATUS_VDIRTY)
626 split->gains |= GAINS_STATUS_VDIRTY;
634 if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) &&
635 (split->gains_split) &&
636 (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
638 LEAVE (
"split not dirty, returning");
653 pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
664 LEAVE (
"Can't compute gains, mismatched commodities!");
679 Split *s = GNC_SPLIT(n->data);
682 PERR (
"Malformed Lot \"%s\"! (too thin!) " 683 "opening amt=%s split adj amt=%s baln=%s",
684 gnc_lot_get_title (lot),
698 Split *s = GNC_SPLIT(n->data);
701 PERR (
"Malformed Lot \"%s\"! (too fat!) " 702 "opening adj amt=%s split adj amt=%s baln=%s",
703 gnc_lot_get_title (lot),
723 gnc_numeric_denom(opening_value),
728 PINFO (
"Open amt=%s val=%s; split adj amt=%s val=%s; gains=%s\n",
736 PERR (
"Numeric overflow during gains calculation\n" 738 "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
758 Split *lot_split, *gain_split;
759 gboolean new_gain_split;
767 lot_split = split->gains_split;
769 if (
nullptr == lot_split)
775 new_gain_split = TRUE;
781 if ((
nullptr == gain_acc) ||
824 trans = lot_split->parent;
831 new_gain_split = FALSE;
837 else if (split->gains_split == lot_split &&
838 lot_split->gains_split == split &&
839 gain_split->gains_split == split &&
845 new_gain_split = FALSE;
849 new_gain_split = TRUE;
856 PWARN (
"Resetting the transaction currency!");
876 split->gains = GAINS_STATUS_CLEAN;
877 split->gains_split = lot_split;
878 lot_split->gains = GAINS_STATUS_GAINS;
879 lot_split->gains_split = split;
880 gain_split->gains = GAINS_STATUS_GAINS;
881 gain_split->gains_split = split;
890 LEAVE (
"(lot=%s)", gnc_lot_get_title(lot));
898 g_return_val_if_fail (split && lot && !split->lot, gnc_numeric_zero());
900 ENTER (
"(split=%p lot=%s)", split, gnc_lot_get_title(lot));
903 auto currency = split->parent->common_currency;
910 LEAVE (
"Currency transfer, gains not possible, returning.");
911 return gnc_numeric_zero();
917 LEAVE (
"Lot is empty, returning.");
918 return gnc_numeric_zero();
923 LEAVE (
"Split is too early, returning.");
924 return gnc_numeric_zero();
929 LEAVE (
"Stock split split, returning.");
930 return gnc_numeric_zero();
941 gnc_numeric lot_amount, lot_value;
944 gnc_numeric opening_amount, opening_value;
945 gnc_commodity *opening_currency;
946 pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
957 LEAVE (
"Can't compute gains, mismatched commodities!");
958 return gnc_numeric_zero();
971 auto *s = GNC_SPLIT(n->data);
974 return gnc_numeric_zero();
983 auto *s = GNC_SPLIT(n->data);
986 return gnc_numeric_zero();
1002 gnc_numeric_denom(opening_value),
1008 PINFO (
"Open amt=%s val=%s; split adj amt=%s val=%s; gains=%s\n",
1017 PERR (
"Numeric overflow during gains calculation\n" 1019 "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
1027 return gnc_numeric_zero();
1030 LEAVE (
"(lot=%s)", gnc_lot_get_title(lot));
1040 if (!split)
return gnc_numeric_zero();
1041 ENTER(
"(split=%p)", split);
1043 if (GAINS_STATUS_UNKNOWN == split->gains)
1044 xaccSplitDetermineGainStatus(split);
1045 if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
1046 (split->gains_split &&
1047 (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
1055 if (!(GAINS_STATUS_GAINS & split->gains))
1058 split = split->gains_split;
1061 LEAVE(
"(split=%p)", split);
1062 if (!split)
return gnc_numeric_zero();
1064 return split->value;
1070 xaccLotComputeCapGains (GNCLot *lot,
Account *gain_acc)
1074 gboolean is_dirty = FALSE;
1080 ENTER(
"(lot=%p)", lot);
1084 Split *s = GNC_SPLIT(node->data);
1085 if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
1087 if (GAINS_STATUS_UNKNOWN == s->gains)
1088 xaccSplitDetermineGainStatus(s);
1089 if (s->gains & GAINS_STATUS_VDIRTY)
1092 s->gains &= ~GAINS_STATUS_VDIRTY;
1101 Split *s = GNC_SPLIT(node->data);
1102 s->gains |= GAINS_STATUS_VDIRTY;
1108 Split *s = GNC_SPLIT(node->data);
1111 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...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
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. ...
gnc_numeric xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the i...
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.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
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...
gint 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...
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
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 x, gnc_numeric y, 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 a)
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 * xaccAccountGetName(const Account *acc)
Get the account's name.
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account's commodity.
#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.