/* HomeBank -- Free, easy, personal accounting for everyone.
- * Copyright (C) 1995-2017 Maxime DOYEN
+ * Copyright (C) 1995-2019 Maxime DOYEN
*
* This file is part of HomeBank.
*
extern struct HomeBank *GLOBALS;
-/* = = = = = = = = = = = = = = = = = = = = */
-/* Archive */
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+
+static void
+da_archive_clean(Archive *item)
+{
+ if(item != NULL)
+ {
+ if(item->memo != NULL)
+ {
+ g_free(item->memo);
+ item->memo = NULL;
+ }
+
+
+
+
+
+ //5.3 added as it was a leak
+ if(item->tags != NULL)
+ {
+ g_free(item->tags);
+ item->tags = NULL;
+ }
+ if(item->splits != NULL)
+ {
+ da_split_destroy(item->splits);
+ item->splits = NULL;
+ item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
+ }
+ }
+}
+
+
+void da_archive_free(Archive *item)
+{
+ if(item != NULL)
+ {
+ da_archive_clean(item);
+ g_free(item);
+ }
+}
+
Archive *da_archive_malloc(void)
{
- return g_malloc0(sizeof(Archive));
+Archive *item;
+
+ item = g_malloc0(sizeof(Archive));
+ item->key = 1;
+ return item;
}
+
Archive *da_archive_clone(Archive *src_item)
{
Archive *new_item = g_memdup(src_item, sizeof(Archive));
if(new_item)
{
//duplicate the string
- new_item->wording = g_strdup(src_item->wording);
-
- if( da_splits_clone(src_item->splits, new_item->splits) > 0)
+ new_item->memo = g_strdup(src_item->memo);
+
+ //duplicate tags
+ //no g_free here to avoid free the src tags (memdup copie dthe ptr)
+ new_item->tags = tags_clone(src_item->tags);
+
+ //duplicate splits
+ //no g_free here to avoid free the src tags (memdup copie dthe ptr)
+ new_item->splits = da_splits_clone(src_item->splits);
+ if( da_splits_length (new_item->splits) > 0 )
new_item->flags |= OF_SPLIT; //Flag that Splits are active
}
return new_item;
}
-void da_archive_free(Archive *item)
-{
- if(item != NULL)
- {
- if(item->wording != NULL)
- g_free(item->wording);
-
- da_splits_free(item->splits);
- //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
-
- g_free(item);
- }
-}
void da_archive_destroy(GList *list)
{
g_list_free(list);
}
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+
static gint da_archive_glist_compare_func(Archive *a, Archive *b)
{
- return hb_string_utf8_compare(a->wording, b->wording);
+ return hb_string_utf8_compare(a->memo, b->memo);
}
return g_list_sort(list, (GCompareFunc)da_archive_glist_compare_func);
}
+
guint da_archive_length(void)
{
return g_list_length(GLOBALS->arc_list);
}
+
+/* append a fav with an existing key (from xml file only) */
+gboolean
+da_archive_append(Archive *item)
+{
+ GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item);
+ return TRUE;
+}
+
+
+gboolean
+da_archive_append_new(Archive *item)
+{
+ item->key = da_archive_get_max_key() + 1;
+ GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item);
+ return TRUE;
+}
+
+
+guint32
+da_archive_get_max_key(void)
+{
+GList *tmplist = g_list_first(GLOBALS->arc_list);
+guint32 max_key = 0;
+
+ while (tmplist != NULL)
+ {
+ Archive *item = tmplist->data;
+
+ max_key = MAX(item->key, max_key);
+ tmplist = g_list_next(tmplist);
+ }
+
+ return max_key;
+}
+
+
+Archive *
+da_archive_get(guint32 key)
+{
+GList *tmplist;
+Archive *retval = NULL;
+
+ tmplist = g_list_first(GLOBALS->arc_list);
+ while (tmplist != NULL)
+ {
+ Archive *item = tmplist->data;
+
+ if(item->key == key)
+ {
+ retval = item;
+ break;
+ }
+ tmplist = g_list_next(tmplist);
+ }
+ return retval;
+}
+
+
void da_archive_consistency(Archive *item)
{
Account *acc;
Category *cat;
Payee *pay;
+guint nbsplit;
// check category exists
cat = da_cat_get(item->kcat);
item->kcat = 0;
GLOBALS->changes_count++;
}
-
- split_cat_consistency(item->splits);
+
+ //#1340142 check split category
+ if( item->splits != NULL )
+ {
+ nbsplit = da_splits_consistency(item->splits);
+ //# 1416624 empty category when split
+ if(nbsplit > 0 && item->kcat > 0)
+ {
+ g_warning("txn consistency: fixed invalid cat on split txn");
+ item->kcat = 0;
+ GLOBALS->changes_count++;
+ }
+ }
// check payee exists
pay = da_pay_get(item->kpay);
Archive *da_archive_init_from_transaction(Archive *arc, Transaction *txn)
{
+ DB( g_print("\n[scheduled] init from txn\n") );
+
//fill it
arc->amount = txn->amount;
arc->kacc = txn->kacc;
arc->kxferacc = txn->kxferacc;
- arc->paymode = txn->paymode;
- arc->flags = txn->flags & (OF_INCOME);
+ arc->paymode = txn->paymode;
+ arc->flags = txn->flags & (OF_INCOME);
arc->status = txn->status;
- arc->kpay = txn->kpay;
+ arc->kpay = txn->kpay;
arc->kcat = txn->kcat;
- if(txn->wording != NULL)
- arc->wording = g_strdup(txn->wording);
+ if(txn->memo != NULL)
+ arc->memo = g_strdup(txn->memo);
else
- arc->wording = g_strdup(_("(new archive)"));
+ arc->memo = g_strdup(_("(new archive)"));
- if( da_splits_clone(txn->splits, arc->splits) > 0)
+ arc->tags = tags_clone(txn->tags);
+ arc->splits = da_splits_clone(txn->splits);
+ if( da_splits_length (arc->splits) > 0 )
arc->flags |= OF_SPLIT; //Flag that Splits are active
return arc;
}
-
-
-static guint32 _sched_date_get_next_post(Archive *arc, guint32 nextdate)
+static guint32 _sched_date_get_next_post(GDate *tmpdate, Archive *arc, guint32 nextdate)
{
-GDate *tmpdate;
guint32 nextpostdate = nextdate;
- DB( g_print("\n[scheduled] _sched_date_get_next_post\n") );
+ //DB( g_print("\n[scheduled] date_get_next_post\n") );
+
+ g_date_set_julian(tmpdate, nextpostdate);
+
+ //DB( g_print("in : %2d-%2d-%4d\n", g_date_get_day(tmpdate), g_date_get_month (tmpdate), g_date_get_year(tmpdate) ) );
- tmpdate = g_date_new_julian(nextpostdate);
switch(arc->unit)
{
case AUTO_UNIT_DAY:
break;
}
+ //DB( g_print("out: %2d-%2d-%4d\n", g_date_get_day(tmpdate), g_date_get_month (tmpdate), g_date_get_year(tmpdate) ) );
+
+
/* get the final post date and free */
nextpostdate = g_date_get_julian(tmpdate);
- g_date_free(tmpdate);
return nextpostdate;
}
guint32 finalpostdate;
gint shift;
- DB( g_print("\n[scheduled] scheduled_get_postdate\n") );
+ DB( g_print("\n[scheduled] get_postdate\n") );
finalpostdate = postdate;
{
wday = g_date_get_weekday(tmpdate);
- DB( g_print(" %s wday=%d\n", arc->wording, wday) );
+ DB( g_print(" %s wday=%d\n", arc->memo, wday) );
if( wday >= G_DATE_SATURDAY )
{
guint32 scheduled_get_latepost_count(Archive *arc, guint32 jrefdate)
{
-guint32 curdate = jrefdate - arc->nextdate;
+GDate *post_date;
+guint32 curdate;
guint32 nblate = 0;
+ //DB( g_print("\n[scheduled] get_latepost_count\n") );
+
/*
+ curdate = jrefdate - arc->nextdate;
switch(arc->unit)
{
case AUTO_UNIT_DAY:
// pre 5.1 way
+ post_date = g_date_new();
curdate = arc->nextdate;
while(curdate <= jrefdate)
{
- curdate = _sched_date_get_next_post(arc, curdate);
+ curdate = _sched_date_get_next_post(post_date, arc, curdate);
nblate++;
// break if over limit or at 11 max (to display +10)
- if(nblate >= arc->limit || nblate >= 11)
+ if( nblate >= 11 || ( (arc->flags & OF_LIMIT) && (nblate >= arc->limit) ) )
break;
}
+ //DB( g_print(" nblate=%d\n", nblate) );
+
+ g_date_free(post_date);
+
return nblate;
}
/* return 0 is max number of post is reached */
guint32 scheduled_date_advance(Archive *arc)
{
- arc->nextdate = _sched_date_get_next_post(arc, arc->nextdate);
-
+GDate *post_date;
+gushort lastday;
+
+ DB( g_print("\n[scheduled] date_advance\n") );
+
+ DB( g_print(" arc: '%s'\n", arc->memo ) );
+
+ post_date = g_date_new();
+ g_date_set_julian(post_date, arc->nextdate);
+ // saved the current day number
+ lastday = g_date_get_day(post_date);
+
+ arc->nextdate = _sched_date_get_next_post(post_date, arc, arc->nextdate);
+
+ DB( g_print(" raw next post date: %2d-%2d-%4d\n", g_date_get_day(post_date), g_date_get_month (post_date), g_date_get_year(post_date) ) );
+
+ //for day > 28 we might have a gap to compensate later
+ if( (arc->unit==AUTO_UNIT_MONTH) || (arc->unit==AUTO_UNIT_YEAR) )
+ {
+ if( lastday >= 28 )
+ {
+ DB( g_print(" lastday:%d, daygap:%d\n", lastday, arc->daygap) );
+ if( arc->daygap > 0 )
+ {
+ g_date_add_days (post_date, arc->daygap);
+ arc->nextdate = g_date_get_julian (post_date);
+ lastday += arc->daygap;
+ DB( g_print(" adjusted post date: %2d-%2d-%4d\n", g_date_get_day(post_date), g_date_get_month (post_date), g_date_get_year(post_date) ) );
+ }
+
+ arc->daygap = CLAMP(lastday - g_date_get_day(post_date), 0, 3);
+
+ DB( g_print(" daygap is %d\n", arc->daygap) );
+ }
+ else
+ arc->daygap = 0;
+ }
+
+
//#1556289
/* check limit, update and maybe break */
if(arc->flags & OF_LIMIT)
arc->nextdate = 0;
}
}
-
+
+ g_date_free(post_date);
+
return arc->nextdate;
}
{
Archive *arc = list->data;
- DB( g_print("\n eval %d for '%s'\n", scheduled_is_postable(arc), arc->wording) );
+ DB( g_print("\n eval %d for '%s'\n", scheduled_is_postable(arc), arc->memo) );
if(scheduled_is_postable(arc) == TRUE)
{
while(mydate < maxpostdate)
{
- DB( hb_print_date(mydate, arc->wording) );
+ DB( hb_print_date(mydate, arc->memo) );
da_transaction_init_from_template(txn, arc);
txn->date = scheduled_get_postdate(arc, mydate);
/* todo: ? fill in cheque number */
- transaction_add(txn, NULL, 0);
+ transaction_add(NULL, txn);
GLOBALS->changes_count++;
count++;