GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 [email protected] *
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 //static QofLogModule log_module = GNC_MOD_LOT;
46 
47 static Split *
48 DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
49 {
50  Split *split;
51  SplitList *node;
52  gnc_commodity *common_currency;
53  gboolean want_positive;
54  gnc_numeric baln;
55  Split *osplit;
56  Transaction *otrans;
57  Timespec open_ts;
58  Account* lot_account;
59 
60  if (!pcy || !lot || !gnc_lot_get_split_list(lot)) return NULL;
61  lot_account = gnc_lot_get_account(lot);
62  if (!lot_account) return NULL;
63 
64  /* Recomputing the balance re-evaluates the lot closure */
65  baln = gnc_lot_get_balance (lot);
66  if (gnc_lot_is_closed(lot)) return NULL;
67 
68  want_positive = gnc_numeric_negative_p (baln);
69 
70  /* All splits in lot must share a common transaction currency. */
71  split = gnc_lot_get_split_list(lot)->data;
72  common_currency = split->parent->common_currency;
73 
74  /* Don't add a split to the lot unless it will be the new last
75  split in the lot. Otherwise our balance tests will be wrong
76  and the lot may end up too thin or too fat. */
77  osplit = gnc_lot_get_latest_split (lot);
78  otrans = osplit ? xaccSplitGetParent (osplit) : 0;
79  open_ts = xaccTransRetDatePostedTS (otrans);
80 
81  /* Walk over *all* splits in the account, till we find one that
82  * hasn't been assigned to a lot. Return that split.
83  * Make use of the fact that the splits in an account are
84  * already in date order; so we don't have to sort. */
85  node = xaccAccountGetSplitList (lot_account);
86  if (reverse)
87  {
88  node = g_list_last (node);
89  }
90  while (node)
91  {
92  gboolean is_match;
93  gboolean is_positive;
94  Timespec this_ts;
95  split = node->data;
96  if (split->lot) goto donext;
97 
98  /* Skip it if it's too early */
99  this_ts = xaccTransRetDatePostedTS ( xaccSplitGetParent (split));
100  if ((this_ts.tv_sec < open_ts.tv_sec) ||
101  ((this_ts.tv_sec == open_ts.tv_sec) &&
102  (this_ts.tv_nsec < open_ts.tv_nsec)))
103  {
104  if (reverse)
105  /* Going backwards, no point in looking further */
106  break;
107  goto donext;
108  }
109 
110  /* Allow equiv currencies */
111  is_match = gnc_commodity_equiv (common_currency,
112  split->parent->common_currency);
113  if (FALSE == is_match) goto donext;
114 
115  /* Disallow zero-amount splits in general. */
116  if (gnc_numeric_zero_p(split->amount)) goto donext;
117 
118  is_positive = gnc_numeric_positive_p (split->amount);
119  if ((want_positive && is_positive) ||
120  ((!want_positive) && (!is_positive))) return split;
121 donext:
122  if (reverse)
123  {
124  node = node->prev;
125  }
126  else
127  {
128  node = node->next;
129  }
130  }
131  return NULL;
132 }
133 
134 /* ============================================================== */
135 
136 static GNCLot *
137 FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
138 {
139  if (!split) return NULL;
140  return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
141  split->parent->common_currency);
142 }
143 
144 static Split *
145 FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
146 {
147  return DirectionPolicyGetSplit (pcy, lot, 0);
148 }
149 
150 static void
151 FIFOPolicyGetLotOpening (GNCPolicy *pcy,
152  GNCLot *lot,
153  gnc_numeric *ret_amount, gnc_numeric *ret_value,
154  gnc_commodity **ret_currency)
155 {
156  Split *opening_split;
157  opening_split = gnc_lot_get_earliest_split(lot);
158 
159  if (ret_amount) *ret_amount = opening_split->amount;
160  if (ret_value) *ret_value = opening_split->value;
161  if (ret_currency) *ret_currency = opening_split->parent->common_currency;
162 }
163 
164 static gboolean
165 FIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
166 {
167  Split *opening_split;
168  opening_split = gnc_lot_get_earliest_split(lot);
169  return (split == opening_split);
170 }
171 
172 /* ============================================================== */
173 /* Define a single, static policy, since we have no per-object data.
174  * I suppose this could change, but we don't need any better at the
175  * moment ... */
176 
177 GNCPolicy *
179 {
180  static GNCPolicy *pcy = NULL;
181 
182  if (!pcy)
183  {
184  pcy = g_new (GNCPolicy, 1);
185  pcy->PolicyGetLot = FIFOPolicyGetLot;
186  pcy->PolicyGetSplit = FIFOPolicyGetSplit;
187  pcy->PolicyGetLotOpening = FIFOPolicyGetLotOpening;
188  pcy->PolicyIsOpeningSplit = FIFOPolicyIsOpeningSplit;
189  }
190  return pcy;
191 }
192 
193 /* ============================================================== */
194 /* Stab at implementing the LIFO policy. This is untested.
195  * I'm not sure I got it right.
196  */
197 
198 G_GNUC_UNUSED static GNCLot *
199 LIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
200 {
201  if (!split) return NULL;
202  return xaccAccountFindLatestOpenLot (split->acc, split->amount,
203  split->parent->common_currency);
204 }
205 
206 G_GNUC_UNUSED static Split *
207 LIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
208 {
209  return DirectionPolicyGetSplit (pcy, lot, 1);
210 }
211 
212 /* This routine is actually identical to FIFO... */
213 G_GNUC_UNUSED static void
214 LIFOPolicyGetLotOpening (GNCPolicy *pcy,
215  GNCLot *lot,
216  gnc_numeric *ret_amount, gnc_numeric *ret_value,
217  gnc_commodity **ret_currency)
218 {
219  Split *opening_split;
220  opening_split = gnc_lot_get_earliest_split(lot);
221 
222  if (ret_amount) *ret_amount = opening_split->amount;
223  if (ret_value) *ret_value = opening_split->value;
224  if (ret_currency) *ret_currency = opening_split->parent->common_currency;
225 }
226 
227 /* This routine is actually identical to FIFO... */
228 G_GNUC_UNUSED static gboolean
229 LIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
230 {
231  Split *opening_split;
232  opening_split = gnc_lot_get_earliest_split(lot);
233  return (split == opening_split);
234 }
235 
236 /* =========================== END OF FILE ======================= */
GNCLot * xaccAccountFindEarliestOpenLot(Account *acc, gnc_numeric sign, gnc_commodity *currency)
Definition: cap-gains.c:191
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Definition: gnc-lot.c:648
gboolean gnc_numeric_negative_p(gnc_numeric a)
Split * gnc_lot_get_latest_split(GNCLot *lot)
Definition: gnc-lot.c:660
GList SplitList
Definition: gnc-engine.h:203
Account handling public routines.
Implement Accounting Policy.
Implement Accounting Policy Private header File.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:376
Definition: SplitP.h:71
Timespec xaccTransRetDatePostedTS(const Transaction *trans)
Definition: Transaction.c:2243
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
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)
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
GNCPolicy * xaccGetFIFOPolicy(void)
Definition: policy.c:178