GnuCash  4.8a-80-g9825132ea+
policy.c
Go to the documentation of this file.
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 "Transaction.h"
38 #include "TransactionP.h"
39 #include "cap-gains.h"
40 #include "gnc-engine.h"
41 #include "gnc-lot.h"
42 #include "policy.h"
43 #include "policy-p.h"
44 
45 #ifndef SWIG /* swig doesn't see N_() as a string constant */
46 #include <glib/gi18n.h>
47 #else
48 #define N_(string) string
49 #endif
50 
51 #define FIFO_POLICY "fifo"
52 #define FIFO_POLICY_DESC N_("First In, First Out")
53 #define FIFO_POLICY_HINT N_("Use oldest lots first.")
54 #define LIFO_POLICY "lifo"
55 #define LIFO_POLICY_DESC N_("Last In, First Out")
56 #define LIFO_POLICY_HINT N_("Use newest lots first.")
57 #define AVERAGE_POLICY "average"
58 #define AVERAGE_POLICY_DESC N_("Average")
59 #define AVERAGE_POLICY_HINT N_("Average cost of open lots.")
60 #define MANUAL_POLICY "manual"
61 #define MANUAL_POLICY_DESC N_("Manual")
62 #define MANUAL_POLICY_HINT N_("Manually select lots.")
63 
64 //static QofLogModule log_module = GNC_MOD_LOT;
65 
66 GList *
68 {
69  GList *return_list = NULL;
70 
71 /* return_list = g_list_prepend (return_list, xaccGetManualPolicy());
72  return_list = g_list_prepend (return_list, xaccGetAveragePolicy()); */
73  return_list = g_list_prepend (return_list, xaccGetLIFOPolicy());
74  return_list = g_list_prepend (return_list, xaccGetFIFOPolicy());
75 
76  return return_list;
77 }
78 
79 gboolean
80 gnc_valid_policy_name (const gchar *policy_name)
81 {
82  GList *list_of_policies = NULL;
83  gboolean ret_val = FALSE;
84 
85  if (!policy_name)
86  return ret_val;
87 
88  list_of_policies = gnc_get_valid_policy_list();
89  if (!list_of_policies)
90  {
91  return ret_val;
92  }
93  else
94  {
95  GList *l = NULL;
96  for (l = list_of_policies; l != NULL; l = l->next)
97  {
98  GNCPolicy *list_pcy = l->data;
99  if (g_strcmp0(PolicyGetName (list_pcy), policy_name) == 0)
100  ret_val = TRUE;
101  }
102  g_list_free(list_of_policies);
103  return ret_val;
104  }
105 }
106 
107 static Split *
108 DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
109 {
110  Split *split;
111  SplitList *node;
112  gnc_commodity *common_currency;
113  gboolean want_positive;
114  gnc_numeric baln;
115  Split *osplit;
116  Transaction *otrans;
117  time64 open_time;
118  Account* lot_account;
119 
120  if (!pcy || !lot || !gnc_lot_get_split_list(lot)) return NULL;
121  lot_account = gnc_lot_get_account(lot);
122  if (!lot_account) return NULL;
123 
124  /* Recomputing the balance re-evaluates the lot closure */
125  baln = gnc_lot_get_balance (lot);
126  if (gnc_lot_is_closed(lot)) return NULL;
127 
128  want_positive = gnc_numeric_negative_p (baln);
129 
130  /* All splits in lot must share a common transaction currency. */
131  split = gnc_lot_get_split_list(lot)->data;
132  common_currency = split->parent->common_currency;
133 
134  /* Don't add a split to the lot unless it will be the new last
135  split in the lot. Otherwise our balance tests will be wrong
136  and the lot may end up too thin or too fat. */
137  osplit = gnc_lot_get_latest_split (lot);
138  otrans = osplit ? xaccSplitGetParent (osplit) : 0;
139  open_time = xaccTransRetDatePosted (otrans);
140 
141  /* Walk over *all* splits in the account, till we find one that
142  * hasn't been assigned to a lot. Return that split.
143  * Make use of the fact that the splits in an account are
144  * already in date order; so we don't have to sort. */
145  node = xaccAccountGetSplitList (lot_account);
146  if (reverse)
147  {
148  node = g_list_last (node);
149  }
150  while (node)
151  {
152  gboolean is_match;
153  gboolean is_positive;
154  time64 this_time;
155  split = node->data;
156  if (split->lot) goto donext;
157 
158  /* Skip it if it's too early */
159  this_time = xaccTransRetDatePosted ( xaccSplitGetParent (split));
160  if (this_time < open_time)
161  {
162  if (reverse)
163  /* Going backwards, no point in looking further */
164  break;
165  goto donext;
166  }
167 
168  /* Allow equiv currencies */
169  is_match = gnc_commodity_equiv (common_currency,
170  split->parent->common_currency);
171  if (FALSE == is_match) goto donext;
172 
173  /* Disallow zero-amount splits in general. */
174  if (gnc_numeric_zero_p(split->amount)) goto donext;
175 
176  is_positive = gnc_numeric_positive_p (split->amount);
177  if ((want_positive && is_positive) ||
178  ((!want_positive) && (!is_positive))) return split;
179 donext:
180  if (reverse)
181  {
182  node = node->prev;
183  }
184  else
185  {
186  node = node->next;
187  }
188  }
189  return NULL;
190 }
191 
192 const char *
193 PolicyGetName (const GNCPolicy *pcy)
194 {
195  if(!pcy) return NULL;
196  return pcy->name;
197 }
198 
199 const char *
200 PolicyGetDescription (const GNCPolicy *pcy)
201 {
202  if(!pcy) return NULL;
203  return pcy->description;
204 }
205 const char *
206 PolicyGetHint (const GNCPolicy *pcy)
207 {
208  if(!pcy) return NULL;
209  return pcy->hint;
210 }
211 
212 /* ============================================================== */
213 
214 static GNCLot *
215 FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
216 {
217  if (!split) return NULL;
218  return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
219  split->parent->common_currency);
220 }
221 
222 static Split *
223 FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
224 {
225  return DirectionPolicyGetSplit (pcy, lot, 0);
226 }
227 
228 static void
229 FIFOPolicyGetLotOpening (GNCPolicy *pcy,
230  GNCLot *lot,
231  gnc_numeric *ret_amount, gnc_numeric *ret_value,
232  gnc_commodity **ret_currency)
233 {
234  Split *opening_split;
235  opening_split = gnc_lot_get_earliest_split(lot);
236 
237  if (ret_amount) *ret_amount = opening_split->amount;
238  if (ret_value) *ret_value = opening_split->value;
239  if (ret_currency) *ret_currency = opening_split->parent->common_currency;
240 }
241 
242 static gboolean
243 FIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
244 {
245  Split *opening_split;
246  opening_split = gnc_lot_get_earliest_split(lot);
247  return (split == opening_split);
248 }
249 
250 GNCPolicy *
252 {
253  static GNCPolicy *pcy = NULL;
254 
255  if (!pcy)
256  {
257  pcy = g_new (GNCPolicy, 1);
258  pcy->name = FIFO_POLICY;
259  pcy->description = FIFO_POLICY_DESC;
260  pcy->hint = FIFO_POLICY_HINT;
261  pcy->PolicyGetLot = FIFOPolicyGetLot;
262  pcy->PolicyGetSplit = FIFOPolicyGetSplit;
263  pcy->PolicyGetLotOpening = FIFOPolicyGetLotOpening;
264  pcy->PolicyIsOpeningSplit = FIFOPolicyIsOpeningSplit;
265  }
266  return pcy;
267 }
268 
269 static GNCLot *
270 LIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
271 {
272  if (!split) return NULL;
273  return xaccAccountFindLatestOpenLot (split->acc, split->amount,
274  split->parent->common_currency);
275 }
276 
277 static Split *
278 LIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
279 {
280  return DirectionPolicyGetSplit (pcy, lot, 1);
281 }
282 
283 /* This routine is actually identical to FIFO... */
284 static void
285 LIFOPolicyGetLotOpening (GNCPolicy *pcy,
286  GNCLot *lot,
287  gnc_numeric *ret_amount, gnc_numeric *ret_value,
288  gnc_commodity **ret_currency)
289 {
290  Split *opening_split;
291  opening_split = gnc_lot_get_earliest_split(lot);
292 
293  if (ret_amount) *ret_amount = opening_split->amount;
294  if (ret_value) *ret_value = opening_split->value;
295  if (ret_currency) *ret_currency = opening_split->parent->common_currency;
296 }
297 
298 /* This routine is actually identical to FIFO... */
299 static gboolean
300 LIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
301 {
302  Split *opening_split;
303  opening_split = gnc_lot_get_earliest_split(lot);
304  return (split == opening_split);
305 }
306 
307 GNCPolicy *
309 {
310  static GNCPolicy *pcy = NULL;
311 
312  if (!pcy)
313  {
314  pcy = g_new (GNCPolicy, 1);
315  pcy->name = LIFO_POLICY;
316  pcy->description = LIFO_POLICY_DESC;
317  pcy->hint = LIFO_POLICY_HINT;
318  pcy->PolicyGetLot = LIFOPolicyGetLot;
319  pcy->PolicyGetSplit = LIFOPolicyGetSplit;
320  pcy->PolicyGetLotOpening = LIFOPolicyGetLotOpening;
321  pcy->PolicyIsOpeningSplit = LIFOPolicyIsOpeningSplit;
322  }
323  return pcy;
324 }
325 
326 /* =========================== END OF FILE ======================= */
GList * gnc_get_valid_policy_list(void)
Valid Policy List Provides a glist of implemented policies.
Definition: policy.c:67
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.c:190
GNCPolicy * xaccGetLIFOPolicy(void)
Last-in, Last-out Policy This policy will create LIFO Lots.
Definition: policy.c:308
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3964
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)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest da...
Definition: gnc-lot.c:701
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
Split * gnc_lot_get_latest_split(GNCLot *lot)
The gnc_lot_get_latest_split() routine is a convenience routine that helps identify the date this lot...
Definition: gnc-lot.c:713
GList SplitList
GList of Split.
Definition: gnc-engine.h:211
Account handling public routines.
Implement Accounting Policy.
Implement Accounting Policy Private header File.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:436
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2484
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)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:382
gboolean gnc_valid_policy_name(const gchar *policy_name)
Valid Policy Name Uses the Valid Policy List to determine if a policy name is valid.
Definition: policy.c:80
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:392
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)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:530
GNCPolicy * xaccGetFIFOPolicy(void)
First-in, First-out Policy This policy will create FIFO Lots.
Definition: policy.c:251