GnuCash  5.6-150-g038405b370+
policy.cpp
1 /********************************************************************\
2  * policy.c -- Implement FIFO Accounting Policy *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20 \********************************************************************/
21 
32 #include <config.h>
33 
34 #include <glib.h>
35 
36 #include "Account.h"
37 #include "Account.hpp"
38 #include "Transaction.h"
39 #include "TransactionP.hpp"
40 #include "cap-gains.h"
41 #include "gnc-engine.h"
42 #include "gnc-lot.h"
43 #include "policy.h"
44 #include "policy-p.h"
45 
46 #ifndef SWIG /* swig doesn't see N_() as a string constant */
47 #include <glib/gi18n.h>
48 #else
49 #define N_(string) string
50 #endif
51 
52 #define FIFO_POLICY "fifo"
53 #define FIFO_POLICY_DESC N_("First In, First Out")
54 #define FIFO_POLICY_HINT N_("Use oldest lots first.")
55 #define LIFO_POLICY "lifo"
56 #define LIFO_POLICY_DESC N_("Last In, First Out")
57 #define LIFO_POLICY_HINT N_("Use newest lots first.")
58 #define AVERAGE_POLICY "average"
59 #define AVERAGE_POLICY_DESC N_("Average")
60 #define AVERAGE_POLICY_HINT N_("Average cost of open lots.")
61 #define MANUAL_POLICY "manual"
62 #define MANUAL_POLICY_DESC N_("Manual")
63 #define MANUAL_POLICY_HINT N_("Manually select lots.")
64 
65 //static QofLogModule log_module = GNC_MOD_LOT;
66 
67 static Split *
68 DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
69 {
70  Split *split;
71  gnc_commodity *common_currency;
72  gboolean want_positive;
73  gnc_numeric baln;
74  Split *osplit;
75  Transaction *otrans;
76  time64 open_time;
77  Account* lot_account;
78 
79  if (!pcy || !lot || !gnc_lot_get_split_list(lot)) return nullptr;
80  lot_account = gnc_lot_get_account(lot);
81  if (!lot_account) return nullptr;
82 
83  /* Recomputing the balance re-evaluates the lot closure */
84  baln = gnc_lot_get_balance (lot);
85  if (gnc_lot_is_closed(lot)) return nullptr;
86 
87  want_positive = gnc_numeric_negative_p (baln);
88 
89  /* All splits in lot must share a common transaction currency. */
90  split = GNC_SPLIT(gnc_lot_get_split_list(lot)->data);
91  common_currency = split->parent->common_currency;
92 
93  /* Don't add a split to the lot unless it will be the new last
94  split in the lot. Otherwise our balance tests will be wrong
95  and the lot may end up too thin or too fat. */
96  osplit = gnc_lot_get_latest_split (lot);
97  otrans = osplit ? xaccSplitGetParent (osplit) : 0;
98  open_time = xaccTransRetDatePosted (otrans);
99 
100  /* Walk over *all* splits in the account, till we find one that
101  * hasn't been assigned to a lot. Return that split.
102  * Make use of the fact that the splits in an account are
103  * already in date order; so we don't have to sort. */
104  auto find_split = [open_time, common_currency, want_positive](const Split* split)
105  {
106  return (!split->lot &&
107  xaccTransRetDatePosted (xaccSplitGetParent (split)) >= open_time &&
108  gnc_commodity_equiv (common_currency, split->parent->common_currency) &&
109  !gnc_numeric_zero_p (split->amount) &&
110  want_positive == gnc_numeric_positive_p (split->amount));
111  };
112 
113  return gnc_account_find_split (lot_account, find_split, reverse);
114 }
115 
116 /* ============================================================== */
117 
118 static GNCLot *
119 FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
120 {
121  if (!split) return nullptr;
122  return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
123  split->parent->common_currency);
124 }
125 
126 static Split *
127 FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
128 {
129  return DirectionPolicyGetSplit (pcy, lot, 0);
130 }
131 
132 static void
133 FIFOPolicyGetLotOpening (GNCPolicy *pcy,
134  GNCLot *lot,
135  gnc_numeric *ret_amount, gnc_numeric *ret_value,
136  gnc_commodity **ret_currency)
137 {
138  Split *opening_split;
139  opening_split = gnc_lot_get_earliest_split(lot);
140 
141  if (ret_amount) *ret_amount = opening_split->amount;
142  if (ret_value) *ret_value = opening_split->value;
143  if (ret_currency) *ret_currency = opening_split->parent->common_currency;
144 }
145 
146 static gboolean
147 FIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
148 {
149  Split *opening_split;
150  opening_split = gnc_lot_get_earliest_split(lot);
151  return (split == opening_split);
152 }
153 
154 GNCPolicy *
156 {
157  static GNCPolicy *pcy = nullptr;
158 
159  if (!pcy)
160  {
161  pcy = g_new (GNCPolicy, 1);
162  pcy->PolicyGetLot = FIFOPolicyGetLot;
163  pcy->PolicyGetSplit = FIFOPolicyGetSplit;
164  pcy->PolicyGetLotOpening = FIFOPolicyGetLotOpening;
165  pcy->PolicyIsOpeningSplit = FIFOPolicyIsOpeningSplit;
166  }
167  return pcy;
168 }
169 
170 
171 /* =========================== END OF FILE ======================= */
GNCLot * xaccAccountFindEarliestOpenLot(Account *acc, gnc_numeric sign, gnc_commodity *currency)
The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open ...
Definition: cap-gains.cpp:188
def find_split(split_list, search_string)
STRUCTS.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition: gnc-lot.cpp:673
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
Split * gnc_lot_get_latest_split(GNCLot *lot)
Convenience routineto identify the date this lot was closed.
Definition: gnc-lot.cpp:685
Account handling public routines.
Account public routines (C++ api)
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.
Definition: gnc-lot.cpp:425
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition: gnc-lot.cpp:367
Split * gnc_account_find_split(const Account *acc, std::function< bool(const Split *)> predicate, bool reverse)
scans account split list (in forward or reverse order) until predicate split->bool returns true...
Definition: Account.cpp:1168
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
API for Transactions and Splits (journal entries)
Utilities to Automatically Compute Capital Gains/Losses.
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.
Definition: gnc-lot.cpp:502
GNCPolicy * xaccGetFIFOPolicy(void)
First-in, First-out Policy This policy will create FIFO Lots.
Definition: policy.cpp:155