00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00032 #include "config.h"
00033
00034 #include <glib.h>
00035
00036 #include "Account.h"
00037 #include "Transaction.h"
00038 #include "TransactionP.h"
00039 #include "cap-gains.h"
00040 #include "gnc-engine.h"
00041 #include "gnc-lot.h"
00042 #include "gnc-lot-p.h"
00043 #include "policy.h"
00044 #include "policy-p.h"
00045
00046
00047
00048 static Split *
00049 DirectionPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot, short reverse)
00050 {
00051 Split *split;
00052 SplitList *node;
00053 gnc_commodity *common_currency;
00054 gboolean want_positive;
00055 gnc_numeric baln;
00056 Split *osplit;
00057 Transaction *otrans;
00058 Timespec open_ts;
00059
00060 if (!pcy || !lot || !lot->account || !lot->splits) return NULL;
00061
00062
00063 baln = gnc_lot_get_balance (lot);
00064 if (gnc_lot_is_closed(lot)) return NULL;
00065
00066 want_positive = gnc_numeric_negative_p (baln);
00067
00068
00069 split = lot->splits->data;
00070 common_currency = split->parent->common_currency;
00071
00072
00073
00074
00075 osplit = gnc_lot_get_latest_split (lot);
00076 otrans = osplit ? xaccSplitGetParent (osplit) : 0;
00077 open_ts = xaccTransRetDatePostedTS (otrans);
00078
00079
00080
00081
00082
00083 node = xaccAccountGetSplitList (lot->account);
00084 if (reverse)
00085 {
00086 node = g_list_last (node);
00087 }
00088 while (node)
00089 {
00090 gboolean is_match;
00091 gboolean is_positive;
00092 Timespec this_ts;
00093 split = node->data;
00094 if (split->lot) goto donext;
00095
00096
00097 this_ts = xaccTransRetDatePostedTS ( xaccSplitGetParent (split));
00098 if ((this_ts.tv_sec < open_ts.tv_sec) ||
00099 ((this_ts.tv_sec == open_ts.tv_sec) &&
00100 (this_ts.tv_nsec < open_ts.tv_nsec)))
00101 {
00102 if (reverse)
00103
00104 break;
00105 goto donext;
00106 }
00107
00108
00109 is_match = gnc_commodity_equiv (common_currency,
00110 split->parent->common_currency);
00111 if (FALSE == is_match) goto donext;
00112
00113
00114 if (gnc_numeric_zero_p(split->amount)) goto donext;
00115
00116 is_positive = gnc_numeric_positive_p (split->amount);
00117 if ((want_positive && is_positive) ||
00118 ((!want_positive) && (!is_positive))) return split;
00119 donext:
00120 if (reverse)
00121 {
00122 node=node->prev;
00123 }
00124 else
00125 {
00126 node=node->next;
00127 }
00128 }
00129 return NULL;
00130 }
00131
00132
00133
00134 static GNCLot *
00135 FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
00136 {
00137 if (!split) return NULL;
00138 return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
00139 split->parent->common_currency);
00140 }
00141
00142 static Split *
00143 FIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
00144 {
00145 return DirectionPolicyGetSplit (pcy, lot, 0);
00146 }
00147
00148 static void
00149 FIFOPolicyGetLotOpening (GNCPolicy *pcy,
00150 GNCLot *lot,
00151 gnc_numeric *ret_amount, gnc_numeric *ret_value,
00152 gnc_commodity **ret_currency)
00153 {
00154 Split *opening_split;
00155 opening_split = gnc_lot_get_earliest_split(lot);
00156
00157 if (ret_amount) *ret_amount = opening_split->amount;
00158 if (ret_value) *ret_value = opening_split->value;
00159 if (ret_currency) *ret_currency = opening_split->parent->common_currency;
00160 }
00161
00162 static gboolean
00163 FIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
00164 {
00165 Split *opening_split;
00166 opening_split = gnc_lot_get_earliest_split(lot);
00167 return (split == opening_split);
00168 }
00169
00170
00171
00172
00173
00174
00175 GNCPolicy *
00176 xaccGetFIFOPolicy (void)
00177 {
00178 static GNCPolicy *pcy = NULL;
00179
00180 if (!pcy)
00181 {
00182 pcy = g_new (GNCPolicy, 1);
00183 pcy->PolicyGetLot = FIFOPolicyGetLot;
00184 pcy->PolicyGetSplit = FIFOPolicyGetSplit;
00185 pcy->PolicyGetLotOpening = FIFOPolicyGetLotOpening;
00186 pcy->PolicyIsOpeningSplit = FIFOPolicyIsOpeningSplit;
00187 }
00188 return pcy;
00189 }
00190
00191
00192
00193
00194
00195
00196 static GNCLot *
00197 LIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
00198 {
00199 if (!split) return NULL;
00200 return xaccAccountFindLatestOpenLot (split->acc, split->amount,
00201 split->parent->common_currency);
00202 }
00203
00204 static Split *
00205 LIFOPolicyGetSplit (GNCPolicy *pcy, GNCLot *lot)
00206 {
00207 return DirectionPolicyGetSplit (pcy, lot, 1);
00208 }
00209
00210
00211 static void
00212 LIFOPolicyGetLotOpening (GNCPolicy *pcy,
00213 GNCLot *lot,
00214 gnc_numeric *ret_amount, gnc_numeric *ret_value,
00215 gnc_commodity **ret_currency)
00216 {
00217 Split *opening_split;
00218 opening_split = gnc_lot_get_earliest_split(lot);
00219
00220 if (ret_amount) *ret_amount = opening_split->amount;
00221 if (ret_value) *ret_value = opening_split->value;
00222 if (ret_currency) *ret_currency = opening_split->parent->common_currency;
00223 }
00224
00225
00226 static gboolean
00227 LIFOPolicyIsOpeningSplit (GNCPolicy *pcy, GNCLot *lot, Split *split)
00228 {
00229 Split *opening_split;
00230 opening_split = gnc_lot_get_earliest_split(lot);
00231 return (split == opening_split);
00232 }
00233
00234
00235
00236
00237
00238
00239
00240 GNCPolicy *
00241 xaccGetLIFOPolicy (void)
00242 {
00243 static GNCPolicy *pcy = NULL;
00244
00245 if (!pcy)
00246 {
00247 pcy = g_new (GNCPolicy, 1);
00248 pcy->PolicyGetLot = LIFOPolicyGetLot;
00249 pcy->PolicyGetSplit = LIFOPolicyGetSplit;
00250 pcy->PolicyGetLotOpening = LIFOPolicyGetLotOpening;
00251 pcy->PolicyIsOpeningSplit = LIFOPolicyIsOpeningSplit;
00252 }
00253 return pcy;
00254 }
00255
00256