]> Dogcows Code - chaz/homebank/blobdiff - src/hb-archive.c
Merge branch 'upstream'
[chaz/homebank] / src / hb-archive.c
index 0ede27030cce95f71fb29d1ef1f7c0f67da9a627..cbb732883fd598b6d53f70e06dd497dc69a80a7a 100644 (file)
@@ -1,5 +1,5 @@
 /*  HomeBank -- Free, easy, personal accounting for everyone.
- *  Copyright (C) 1995-2014 Maxime DOYEN
+ *  Copyright (C) 1995-2019 Maxime DOYEN
  *
  *  This file is part of HomeBank.
  *
@@ -19,6 +19,7 @@
 
 #include "homebank.h"
 #include "hb-archive.h"
+#include "hb-split.h"
 
 /****************************************************************************/
 /* Debug macros                                                             */
 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));
@@ -50,22 +97,22 @@ Archive *new_item = g_memdup(src_item, sizeof(Archive));
        if(new_item)
        {
                //duplicate the string
-               new_item->wording = g_strdup(src_item->wording);
-       }
-       return new_item;
-}
+               new_item->memo = g_strdup(src_item->memo);
 
-void da_archive_free(Archive *item)
-{
-       if(item != NULL)
-       {
-               if(item->wording != NULL)
-                       g_free(item->wording);
+               //duplicate tags
+               //no g_free here to avoid free the src tags (memdup copie dthe ptr)
+               new_item->tags = tags_clone(src_item->tags);
 
-               g_free(item);
+               //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_destroy(GList *list)
 {
 GList *tmplist = g_list_first(list);
@@ -79,9 +126,13 @@ GList *tmplist = g_list_first(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);
 }
 
 
@@ -90,16 +141,77 @@ GList *da_archive_sort(GList *list)
        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);
@@ -107,27 +219,42 @@ Payee *pay;
        {
                g_warning("arc consistency: fixed invalid cat %d", item->kcat);
                item->kcat = 0;
+               GLOBALS->changes_count++;
        }
 
+       //#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);
        if(pay == NULL)
        {
                g_warning("arc consistency: fixed invalid pay %d", item->kpay);
                item->kpay = 0;
+               GLOBALS->changes_count++;
        }
 
        // reset dst acc for non xfer transaction
        if( item->paymode != PAYMODE_INTXFER )
                item->kxferacc = 0;
 
-       // remove automation if dst_acc not exists
+       // delete automation if dst_acc not exists
        if(item->paymode == PAYMODE_INTXFER)
        {
                acc = da_acc_get(item->kxferacc);
                if(acc == NULL)
                {
-                       item->flags &= ~(OF_AUTO);      //remove flag
+                       item->flags &= ~(OF_AUTO);      //delete flag
                }
        }
 
@@ -135,12 +262,43 @@ Payee *pay;
 
 /* = = = = = = = = = = = = = = = = = = = = */
 
-static guint32 _sched_date_get_next_post(Archive *arc, guint32 nextdate)
+Archive *da_archive_init_from_transaction(Archive *arc, Transaction *txn)
 {
-GDate *tmpdate;
-guint32 nextpostdate = nextdate;
+       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->status             = txn->status;
+       arc->kpay               = txn->kpay;
+       arc->kcat               = txn->kcat;
+       if(txn->memo != NULL)
+               arc->memo = g_strdup(txn->memo);
+       else
+               arc->memo = g_strdup(_("(new archive)"));
+
+       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
        
-       tmpdate = g_date_new_julian(nextpostdate);
+       return arc;
+}
+
+
+static guint32 _sched_date_get_next_post(GDate *tmpdate, Archive *arc, guint32 nextdate)
+{
+guint32 nextpostdate = nextdate;
+
+       //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) ) );
+
        switch(arc->unit)
        {
                case AUTO_UNIT_DAY:
@@ -157,21 +315,12 @@ guint32 nextpostdate = nextdate;
                        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);
        
-       /* check limit, update and maybe break */
-       if(arc->flags & OF_LIMIT)
-       {
-               arc->limit--;
-               if(arc->limit <= 0)
-               {
-                       arc->flags ^= (OF_LIMIT | OF_AUTO);     // invert flags
-                       nextpostdate = 0;
-               }
-       }
-
        return nextpostdate;
 }
 
@@ -180,7 +329,7 @@ gboolean scheduled_is_postable(Archive *arc)
 {
 gdouble value;
 
-       value = arrondi(arc->amount, 2);
+       value = hb_amount_round(arc->amount, 2);
        if( (arc->flags & OF_AUTO) && (arc->kacc > 0) && (value != 0.0) )
                return TRUE;
 
@@ -195,6 +344,9 @@ GDateWeekday wday;
 guint32 finalpostdate;
 gint shift;
 
+       DB( g_print("\n[scheduled] get_postdate\n") );
+
+
        finalpostdate = postdate;
        
        tmpdate = g_date_new_julian(finalpostdate);
@@ -203,7 +355,7 @@ gint shift;
        {
                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 )
                {
@@ -232,31 +384,126 @@ gint shift;
 }
 
 
+guint32 scheduled_get_latepost_count(Archive *arc, guint32 jrefdate)
+{
+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:
+                       nbpost = (curdate / arc->every);
+                       g_print("debug d: %d => %f\n", curdate, nbpost);
+                       break;
 
-guint32 scheduled_get_latepost_count(Archive *arc, guint32 jrefdate)
-{
-guint32 nbpost = 0;
-guint32 curdate = arc->nextdate;
+               case AUTO_UNIT_WEEK:
+                       nbpost = (curdate / ( 7 * arc->every));
+                       g_print("debug w: %d => %f\n", curdate, nbpost);
+                       break;
+
+               case AUTO_UNIT_MONTH:
+                       //approximate is sufficient
+                       nbpost = (curdate / (( 365.2425 / 12) * arc->every));
+                       g_print("debug m: %d => %f\n", curdate, nbpost);
+                       break;
+
+               case AUTO_UNIT_YEAR:
+                       //approximate is sufficient
+                       nbpost = (curdate / ( 365.2425 * arc->every));
+                       g_print("debug y: %d => %f\n", curdate, nbpost);
+                       break;
+       }
+
+       nblate = floor(nbpost);
+
+       if(arc->flags & OF_LIMIT)
+               nblate = MIN(nblate, arc->limit);
+       
+       nblate = MIN(nblate, 11);
+       */
        
+
+       // pre 5.1 way
+       post_date = g_date_new();
+       curdate = arc->nextdate;
        while(curdate <= jrefdate)
        {
-               curdate = _sched_date_get_next_post(arc, curdate);
-               nbpost++;
-               // break at 11 max (to display +10)
-               if(nbpost >= 11)
+               curdate = _sched_date_get_next_post(post_date, arc, curdate);
+               nblate++;
+               // break if over limit or at 11 max (to display +10)
+               if( nblate >= 11 || ( (arc->flags & OF_LIMIT) && (nblate >= arc->limit) ) )
                        break;
        }
 
-       return nbpost;
+       //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->limit--;
+               if(arc->limit <= 0)
+               {
+                       arc->flags ^= (OF_LIMIT | OF_AUTO);     // invert flags
+                       arc->nextdate = 0;
+               }
+       }
+
+       g_date_free(post_date);
+
        return arc->nextdate;
 }
 
@@ -322,7 +569,7 @@ Transaction *txn;
        {
        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)
                {
@@ -335,13 +582,13 @@ Transaction *txn;
 
                                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++;
 
This page took 0.026874 seconds and 4 git commands to generate.