59#include <glib/gi18n.h>
66#include "TransactionP.hpp"
69#include "engine-helpers.h"
74static 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);
125finder_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;
167static inline GNCLot *
168xaccAccountFindOpenLot (
Account *acc, gnc_numeric sign,
169 gnc_commodity *currency,
176 es.currency = currency;
178 es.date_pred = date_pred;
183 xaccAccountForEachLot (acc, finder_helper, &es);
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),
203xaccAccountFindLatestOpenLot (
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;
490find_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;
1070xaccLotComputeCapGains (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);
This is the private header for the account structure.
Account public routines (C++ api)
Utilities to Convert Stock Accounts to use Lots.
High-Level API for imposing Lot constraints.
API for Transactions and Splits (journal entries)
Utilities to Automatically Compute Capital Gains/Losses.
All type declarations for the whole Gnucash engine.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Account * xaccAccountGainsAccount(Account *acc, gnc_commodity *curr)
Retrieve the gains account used by this account for the indicated currency, creating and recording a ...
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false.
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
gboolean xaccAccountHasTrades(const Account *acc)
The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of co...
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot,...
GNCLot * xaccAccountFindEarliestOpenLot(Account *acc, gnc_numeric sign, gnc_commodity *currency)
The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open ...
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lo...
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split.
gnc_numeric xaccSplitGetCapGains(Split *split)
The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the ind...
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
gnc_numeric xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the i...
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
time64 gnc_time(time64 *tbuf)
get the current time
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
GList SplitList
GList of Split.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
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.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
#define PINFO(format, args...)
Print an informational note.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PERR(format, args...)
Log a serious error.
#define PWARN(format, args...)
Log a warning.
#define ENTER(format, args...)
Print a function entry debugging message.
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...
GNCLot * gnc_lot_make_default(Account *acc)
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
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.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
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.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
@ GNC_HOW_RND_ROUND_HALF_UP
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
@ GNC_HOW_DENOM_REDUCE
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
@ GNC_HOW_DENOM_FIXED
All arguments are required to have the same denominator, that denominator is to be used in the output...
@ GNC_HOW_DENOM_EXACT
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
#define xaccSplitGetGUID(X)
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits.
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account's commodity.
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split's lot-split list.
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Implement Accounting Policy Private header File.
Implement Accounting Policy.
The type used to store guids in C.