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