27 #include <glib/gi18n.h> 34 #include "gnc-autoclear.h" 40 AUTOCLEAR_OVERLOAD = 1,
44 } autoclear_error_type;
46 #define MAXIMUM_SACK_SIZE 1000000 48 #define log_module "autoclear" 59 gnc_numeric reachable_amount;
60 GList *list_of_splits;
63 static GList *DUP_LIST;
66 make_workitem (GHashTable *hash, gnc_numeric amount,
67 Split *split, GList *splits)
70 item->reachable_amount = amount;
71 if (g_hash_table_lookup (hash, GINT_TO_POINTER (amount.num)) || splits == DUP_LIST)
72 item->list_of_splits = DUP_LIST;
74 item->list_of_splits = g_list_prepend (g_list_copy (splits), split);
79 sack_foreach_func (gint thisvalue_num, GList *splits,
sack_data *data)
82 gnc_numeric this_value = gnc_numeric_create (thisvalue_num, itemval.denom);
83 gnc_numeric new_value = gnc_numeric_add_fixed (this_value, itemval);
84 WorkItem *item = make_workitem (data->sack, new_value, data->split, splits);
86 data->worklist = g_list_prepend (data->worklist, item);
90 sack_free (gpointer thisvalue_num, GList *splits,
sack_data *data)
92 if (splits != DUP_LIST)
97 process_work (
WorkItem *item, GHashTable *sack)
99 GList *existing = g_hash_table_lookup (sack, GINT_TO_POINTER(item->reachable_amount.num));
100 if (existing && existing != DUP_LIST)
102 DEBUG (
"removing existing for %6.2f\n",
104 g_list_free (existing);
106 g_hash_table_insert (sack, GINT_TO_POINTER(item->reachable_amount.num), item->list_of_splits);
110 gnc_autoclear_get_splits (
Account *account, gnc_numeric toclear_value,
112 GList **splits, GError **error, GtkLabel *label)
114 GList *nc_list = NULL, *toclear_list = NULL;
116 GQuark autoclear_quark = g_quark_from_static_string (
"autoclear");
118 g_return_val_if_fail (GNC_IS_ACCOUNT (account), FALSE);
119 g_return_val_if_fail (splits != NULL, FALSE);
121 sack = g_hash_table_new (NULL, NULL);
122 DUP_LIST = g_list_prepend (NULL, NULL);
126 for (GList *node = acc_splits; node; node = node->next)
128 Split *split = (Split *)node->data;
131 if (amount.denom != toclear_value.denom)
133 g_set_error (error, autoclear_quark, AUTOCLEAR_NOP,
"Split amount and toclear amount have different denoms");
137 toclear_value = gnc_numeric_sub_fixed (toclear_value, amount);
139 DEBUG (
"skipping zero-amount split %p", split);
140 else if (end_date != INT64_MAX &&
142 DEBUG (
"skipping split after statement_date %p", split);
144 nc_list = g_list_prepend (nc_list, split);
146 g_list_free (acc_splits);
150 g_set_error (error, autoclear_quark, AUTOCLEAR_NOP,
151 _(
"Account is already at Auto-Clear Balance."));
156 g_set_error (error, autoclear_quark, AUTOCLEAR_NOP,
157 _(
"No uncleared splits found."));
161 for (GList *node = nc_list; node; node = node->next)
163 Split *split = (Split *)node->data;
165 sack_data s_data = { g_list_prepend (NULL, item), sack, split };
167 g_hash_table_foreach (sack, (GHFunc) sack_foreach_func, &s_data);
168 g_list_foreach (s_data.worklist, (GFunc) process_work, sack);
169 g_list_free_full (s_data.worklist, g_free);
170 if (g_hash_table_size (sack) > MAXIMUM_SACK_SIZE)
172 g_set_error (error, autoclear_quark, AUTOCLEAR_OVERLOAD,
173 _(
"Too many uncleared splits"));
176 else if (g_hash_table_lookup (sack, GINT_TO_POINTER(toclear_value.num)) == DUP_LIST)
178 g_set_error (error, autoclear_quark, AUTOCLEAR_MULTIPLE,
179 _(
"Cannot uniquely clear splits. Found multiple possibilities."));
184 toclear_list = g_hash_table_lookup (sack, GINT_TO_POINTER(toclear_value.num));
189 g_set_error (error, autoclear_quark, AUTOCLEAR_UNABLE,
190 _(
"The selected amount cannot be cleared."));
195 *splits = g_list_copy (toclear_list);
198 g_hash_table_foreach (sack, (GHFunc) sack_free, NULL);
199 g_hash_table_destroy (sack);
200 g_list_free (nc_list);
201 g_list_free (DUP_LIST);
203 return (toclear_list != NULL);
208 gnc_account_get_autoclear_splits (
Account *account, gnc_numeric toclear_value,
211 GError *error = NULL;
212 GList *splits = NULL;
214 gnc_autoclear_get_splits (account, toclear_value, INT64_MAX,
215 &splits, &error, NULL);
219 *errmsg = g_strdup (error->message);
220 g_error_free (error);
Business Interface: Object OWNERs.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
#define DEBUG(format, args...)
Print a debugging message.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
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.
API for Transactions and Splits (journal entries)
gdouble gnc_numeric_to_double(gnc_numeric n)
Convert numeric to floating-point value.
Account handling public routines.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
API for Transactions and Splits (journal entries)
#define NREC
not reconciled or cleared
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.