]> Dogcows Code - chaz/homebank/blob - src/hb-archive.c
add plugin engine (supports C and Perl plugins)
[chaz/homebank] / src / hb-archive.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "homebank.h"
21 #include "hb-archive.h"
22
23 #include "ext.h"
24 #include "refcount.h"
25
26 /****************************************************************************/
27 /* Debug macros */
28 /****************************************************************************/
29 #define MYDEBUG 0
30
31 #if MYDEBUG
32 #define DB(x) (x);
33 #else
34 #define DB(x);
35 #endif
36
37 /* our global datas */
38 extern struct HomeBank *GLOBALS;
39
40
41 /* = = = = = = = = = = = = = = = = = = = = */
42 /* Archive */
43
44 Archive *da_archive_malloc(void)
45 {
46 return rc_alloc(sizeof(Archive));
47 }
48
49 Archive *da_archive_clone(Archive *src_item)
50 {
51 Archive *new_item = rc_dup(src_item, sizeof(Archive));
52
53 if(new_item)
54 {
55 //duplicate the string
56 new_item->wording = g_strdup(src_item->wording);
57 }
58 return new_item;
59 }
60
61 void da_archive_free(Archive *item)
62 {
63 if(rc_unref(item))
64 {
65 if(item->wording != NULL)
66 g_free(item->wording);
67
68 rc_free(item);
69 }
70 }
71
72 void da_archive_destroy(GList *list)
73 {
74 GList *tmplist = g_list_first(list);
75
76 while (tmplist != NULL)
77 {
78 Archive *item = tmplist->data;
79 da_archive_free(item);
80 tmplist = g_list_next(tmplist);
81 }
82 g_list_free(list);
83 }
84
85 static gint da_archive_glist_compare_func(Archive *a, Archive *b)
86 {
87 return hb_string_utf8_compare(a->wording, b->wording);
88 }
89
90
91 GList *da_archive_sort(GList *list)
92 {
93 return g_list_sort(list, (GCompareFunc)da_archive_glist_compare_func);
94 }
95
96 guint da_archive_length(void)
97 {
98 return g_list_length(GLOBALS->arc_list);
99 }
100
101 void da_archive_consistency(Archive *item)
102 {
103 Account *acc;
104 Category *cat;
105 Payee *pay;
106
107 // check category exists
108 cat = da_cat_get(item->kcat);
109 if(cat == NULL)
110 {
111 g_warning("arc consistency: fixed invalid cat %d", item->kcat);
112 item->kcat = 0;
113 }
114
115 // check payee exists
116 pay = da_pay_get(item->kpay);
117 if(pay == NULL)
118 {
119 g_warning("arc consistency: fixed invalid pay %d", item->kpay);
120 item->kpay = 0;
121 }
122
123 // reset dst acc for non xfer transaction
124 if( item->paymode != PAYMODE_INTXFER )
125 item->kxferacc = 0;
126
127 // remove automation if dst_acc not exists
128 if(item->paymode == PAYMODE_INTXFER)
129 {
130 acc = da_acc_get(item->kxferacc);
131 if(acc == NULL)
132 {
133 item->flags &= ~(OF_AUTO); //remove flag
134 }
135 }
136
137 }
138
139 /* = = = = = = = = = = = = = = = = = = = = */
140
141 static guint32 _sched_date_get_next_post(Archive *arc, guint32 nextdate)
142 {
143 GDate *tmpdate;
144 guint32 nextpostdate = nextdate;
145
146 tmpdate = g_date_new_julian(nextpostdate);
147 switch(arc->unit)
148 {
149 case AUTO_UNIT_DAY:
150 g_date_add_days(tmpdate, arc->every);
151 break;
152 case AUTO_UNIT_WEEK:
153 g_date_add_days(tmpdate, 7 * arc->every);
154 break;
155 case AUTO_UNIT_MONTH:
156 g_date_add_months(tmpdate, arc->every);
157 break;
158 case AUTO_UNIT_YEAR:
159 g_date_add_years(tmpdate, arc->every);
160 break;
161 }
162
163 /* get the final post date and free */
164 nextpostdate = g_date_get_julian(tmpdate);
165 g_date_free(tmpdate);
166
167 /* check limit, update and maybe break */
168 if(arc->flags & OF_LIMIT)
169 {
170 arc->limit--;
171 if(arc->limit <= 0)
172 {
173 arc->flags ^= (OF_LIMIT | OF_AUTO); // invert flags
174 nextpostdate = 0;
175 }
176 }
177
178 return nextpostdate;
179 }
180
181
182 gboolean scheduled_is_postable(Archive *arc)
183 {
184 gdouble value;
185
186 value = arrondi(arc->amount, 2);
187 if( (arc->flags & OF_AUTO) && (arc->kacc > 0) && (value != 0.0) )
188 return TRUE;
189
190 return FALSE;
191 }
192
193
194 guint32 scheduled_get_postdate(Archive *arc, guint32 postdate)
195 {
196 GDate *tmpdate;
197 GDateWeekday wday;
198 guint32 finalpostdate;
199 gint shift;
200
201 finalpostdate = postdate;
202
203 tmpdate = g_date_new_julian(finalpostdate);
204 /* manage weekend exception */
205 if( arc->weekend > 0 )
206 {
207 wday = g_date_get_weekday(tmpdate);
208
209 DB( g_print(" %s wday=%d\n", arc->wording, wday) );
210
211 if( wday >= G_DATE_SATURDAY )
212 {
213 switch(arc->weekend)
214 {
215 case 1: /* shift before : sun 7-5=+2 , sat 6-5=+1 */
216 shift = wday - G_DATE_FRIDAY;
217 DB( g_print("sub=%d\n", shift) );
218 g_date_subtract_days (tmpdate, shift);
219 break;
220
221 case 2: /* shift after : sun 8-7=1 , sat 8-6=2 */
222 shift = 8 - wday;
223 DB( g_print("add=%d\n", shift) );
224 g_date_add_days (tmpdate, shift);
225 break;
226 }
227 }
228 }
229
230 /* get the final post date and free */
231 finalpostdate = g_date_get_julian(tmpdate);
232 g_date_free(tmpdate);
233
234 return finalpostdate;
235 }
236
237
238
239
240
241 guint32 scheduled_get_latepost_count(Archive *arc, guint32 jrefdate)
242 {
243 guint32 nbpost = 0;
244 guint32 curdate = arc->nextdate;
245
246 while(curdate <= jrefdate)
247 {
248 curdate = _sched_date_get_next_post(arc, curdate);
249 nbpost++;
250 // break at 11 max (to display +10)
251 if(nbpost >= 11)
252 break;
253 }
254
255 return nbpost;
256 }
257
258
259 /* return 0 is max number of post is reached */
260 guint32 scheduled_date_advance(Archive *arc)
261 {
262 arc->nextdate = _sched_date_get_next_post(arc, arc->nextdate);
263 return arc->nextdate;
264 }
265
266
267 /*
268 * return the maximum date a scheduled txn can be posted to
269 */
270 guint32 scheduled_date_get_post_max(void)
271 {
272 guint nbdays;
273 GDate *today, *maxdate;
274
275 DB( g_print("\n[scheduled] date_get_post_max\n") );
276
277 //add until xx of the next month (excluded)
278 if(GLOBALS->auto_smode == 0)
279 {
280 DB( g_print(" - max is %d of next month\n", GLOBALS->auto_weekday) );
281
282 today = g_date_new_julian(GLOBALS->today);
283
284 //we compute user xx weekday of next month
285 maxdate = g_date_new_julian(GLOBALS->today);
286 g_date_set_day(maxdate, GLOBALS->auto_weekday);
287 if(g_date_get_day (today) >= GLOBALS->auto_weekday)
288 g_date_add_months(maxdate, 1);
289
290 nbdays = g_date_days_between(today, maxdate);
291
292 g_date_free(maxdate);
293 g_date_free(today);
294 }
295 else
296 {
297 nbdays = GLOBALS->auto_nbdays;
298 }
299
300 DB( hb_print_date(GLOBALS->today, "today") );
301 DB( g_print(" - %d nbdays\n", nbdays) );
302 DB( hb_print_date(GLOBALS->today + nbdays, "maxpostdate") );
303
304 return GLOBALS->today + nbdays;
305 }
306
307
308 gint scheduled_post_all_pending(void)
309 {
310 GList *list;
311 gint count;
312 guint32 maxpostdate;
313 Transaction *txn;
314
315 DB( g_print("\n[scheduled] post_all_pending\n") );
316
317 count = 0;
318
319 maxpostdate = scheduled_date_get_post_max();
320
321 txn = da_transaction_malloc();
322
323 list = g_list_first(GLOBALS->arc_list);
324 while (list != NULL)
325 {
326 Archive *arc = list->data;
327
328 DB( g_print("\n eval %d for '%s'\n", scheduled_is_postable(arc), arc->wording) );
329
330 if(scheduled_is_postable(arc) == TRUE)
331 {
332 DB( g_print(" - every %d limit %d (to %d)\n", arc->every, arc->flags & OF_LIMIT, arc->limit) );
333 DB( hb_print_date(arc->nextdate, "next post") );
334
335 if(arc->nextdate < maxpostdate)
336 {
337 guint32 mydate = arc->nextdate;
338
339 while(mydate < maxpostdate)
340 {
341 DB( hb_print_date(mydate, arc->wording) );
342
343 da_transaction_init_from_template(txn, arc);
344 txn->date = scheduled_get_postdate(arc, mydate);
345 /* todo: ? fill in cheque number */
346
347 transaction_add(txn, NULL, 0);
348 GLOBALS->changes_count++;
349 count++;
350
351 da_transaction_clean(txn);
352
353 mydate = scheduled_date_advance(arc);
354
355 //DB( hb_print_date(mydate, "next on") );
356
357 if(mydate == 0)
358 goto nextarchive;
359 }
360
361 }
362 }
363 nextarchive:
364 list = g_list_next(list);
365 }
366
367 da_transaction_free (txn);
368
369 return count;
370 }
371
This page took 0.047968 seconds and 4 git commands to generate.