326
379
pos = year_ope - year_from;
328
DB( g_print(" from=%d ope=%d => %d\n", year_from, year_ope, pos) );
381
DB3( g_print(" from=%d ope=%d => %d\n", year_from, year_ope, pos) );
335
void datatable_init_items(DataTable *dt, gint src, guint32 jfrom)
343
DB( g_print("\ndatatable_init_items\n") );
347
case REPORT_SRC_CATEGORY:
348
case REPORT_SRC_SUBCATEGORY:
349
list = category_glist_sorted(1);
351
case REPORT_SRC_PAYEE:
352
list = payee_glist_sorted(1);
354
case REPORT_SRC_ACCOUNT:
355
list = account_glist_sorted(1);
358
list = tag_glist_sorted(1);
363
//todo: list_index has a cost
364
//preferable to iter through the list
365
for(i=0;i<dt->nbrows;i++)
367
DataRow *dr = dt->rows[i];
387
static guint32 _datatable_interval_get_jdate(gint intvl, guint32 jfrom, gint idx)
389
GDate *date = g_date_new_julian(jfrom);
395
case REPORT_INTVL_DAY:
396
g_date_add_days(date, idx);
398
case REPORT_INTVL_WEEK:
399
g_date_add_days(date, idx*7);
400
//#1915643 week iso 8601
401
//ISO 8601 from must be monday, to slice in correct week
402
wday = g_date_get_weekday(date);
403
g_date_subtract_days (date, wday-G_DATE_MONDAY);
404
g_date_add_days (date, G_DATE_WEDNESDAY);
407
case REPORT_INTVL_FORTNIGHT:
408
_hb_date_clamp_iso8601(date);
409
g_date_add_days(date, idx*14);
411
case REPORT_INTVL_MONTH:
412
g_date_add_months(date, idx);
414
case REPORT_INTVL_QUARTER:
415
g_date_add_months(date, idx*3);
417
case REPORT_INTVL_HALFYEAR:
418
g_date_add_months(date, idx*6);
420
case REPORT_INTVL_YEAR:
421
g_date_add_years(date, idx);
425
jdate = g_date_get_julian(date);
433
/* = = = = = = = = = = = = = = = = = = = = */
435
static void datatable_set_keylist(DataTable *dt, guint32 idx, guint32 key)
437
if( idx <= dt->nbrows )
438
dt->keylist[idx] = key;
440
g_warning("datatable invalid set keylist %d of %d", idx , dt->nbrows);
443
static void datatable_set_keyindex(DataTable *dt, guint32 key, guint32 idx)
445
if( key <= dt->nbkeys )
446
dt->keyindex[key] = idx;
448
g_warning("datatable invalid set keyindex %d of %d", key , dt->nbkeys);
451
static void _datatable_init_count_key_row(DataTable *dt, gint src, Filter *flt)
456
if( src != REPORT_SRC_MONTH && src != REPORT_SRC_YEAR )
460
case REPORT_SRC_NONE:
464
case REPORT_SRC_CATEGORY:
465
n_row = da_cat_length();
466
n_key = da_cat_get_max_key();
468
case REPORT_SRC_PAYEE:
469
n_row = da_pay_length();
470
n_key = da_pay_get_max_key();
472
//5.7: todo check this +1
473
case REPORT_SRC_ACCOUNT:
474
n_row = da_acc_length();
475
n_key = da_acc_get_max_key();
478
n_row = da_tag_length();
479
n_key = da_tag_get_max_key();
485
GDate *date1 = g_date_new_julian(flt->mindate);
486
GDate *date2 = g_date_new_julian(flt->maxdate);
490
case REPORT_SRC_MONTH:
491
n_row = ((g_date_get_year(date2) - g_date_get_year(date1)) * 12) + g_date_get_month(date2) - g_date_get_month(date1) + 1;
494
case REPORT_SRC_YEAR:
495
n_row = g_date_get_year(date2) - g_date_get_year(date1) + 1;
504
//we add 1 to every key as 0 is an item
505
dt->nbkeys = n_key + 1;
510
static void _datatable_init_items_cat(DataTable *dt)
515
lcat = l = category_glist_sorted(HB_GLIST_SORT_NAME);
518
Category *cat = l->data;
519
DataRow *dr = dt->rows[idx];
524
dr->label = g_strdup( (cat->key == 0) ? _("(no category)") : cat->name );
525
//dt->keyindex[cat->key] = idx;
526
datatable_set_keyindex(dt, cat->key, idx);
528
DB1( g_print(" +cat k:%d, idx:%d %s'%s'\n", cat->key, idx, cat->parent==0 ? "" : " +", dr->label) );
536
DB2( g_print(" add cat keys") );
538
lcat = l = category_glist_sorted(HB_GLIST_SORT_KEY);
541
Category *cat = l->data;
543
//dt->keylist[idx] = cat->key;
544
datatable_set_keylist(dt, idx, cat->key);
545
DB2( g_print(" %d", cat->key) );
550
DB2( g_print("\n") );
553
static void _datatable_init_items_pay(DataTable *dt)
558
lpay = l = payee_glist_sorted(HB_GLIST_SORT_NAME);
561
Payee *pay = l->data;
562
DataRow *dr = dt->rows[idx];
567
dr->label = g_strdup( (pay->key == 0) ? _("(no payee)") : pay->name );
568
DB1( g_print(" +pay k:%d, idx:%d '%s'\n", pay->key, idx, dr->label) );
570
//dt->keyindex[pay->key] = idx;
571
datatable_set_keyindex(dt, pay->key, idx);
573
//dt->keylist[idx] = pay->key;
574
datatable_set_keylist(dt, idx, pay->key);
582
static void _datatable_init_items_acc(DataTable *dt)
587
lacc = l = account_glist_sorted(HB_GLIST_SORT_NAME);
590
Account *acc = l->data;
591
DataRow *dr = dt->rows[idx];
597
dr->label = g_strdup( acc->name );
598
DB1( g_print(" +acc k:%d, idx:%d '%s'\n", acc->key, idx, dr->label) );
600
dt->keyindex[acc->key] = idx;
601
//datatable_set_keyindex(dt, acc->key, idx);
603
dt->keylist[idx] = acc->key;
604
//datatable_set_keylist(dt, idx, acc->key);
613
static void _datatable_init_items_tag(DataTable *dt)
618
ltag = l = tag_glist_sorted(HB_GLIST_SORT_NAME);
622
DataRow *dr = dt->rows[idx];
627
dr->label = g_strdup( (tag->key == 0) ? _("(no tag)") : tag->name );
628
DB1( g_print(" +tag k:%d, idx:%d '%s'\n", tag->key, idx, dr->label) );
630
//dt->keyindex[tag->key] = idx;
631
datatable_set_keyindex(dt, tag->key, idx);
633
//dt->keylist[idx] = tag->key;
634
datatable_set_keylist(dt, idx, tag->key);
643
static void datatable_data_get_xlabel(GDate *date, guint intvl, gchar *intvlname, gsize slen)
648
case REPORT_INTVL_DAY:
649
case REPORT_INTVL_FORTNIGHT:
650
g_date_strftime (intvlname, slen, "%b-%d", date);
652
case REPORT_INTVL_WEEK:
653
//TRANSLATORS: printf string for year of week W, ex. 2019-W52 for week 52 of 2019
654
g_snprintf(intvlname, slen, _("w%02d"), g_date_get_iso8601_week_of_year(date));
656
case REPORT_INTVL_MONTH:
657
g_snprintf(intvlname, slen, "%s", _(CYA_ABMONTHS[g_date_get_month(date)]));
659
case REPORT_INTVL_QUARTER:
660
//todo: will be innacurrate here if fiscal year start not 1/jan
661
//TRANSLATORS: printf string for year of quarter Q, ex. 2019-Q4 for quarter 4 of 2019
662
g_snprintf(intvlname, slen, _("q%d"), ((g_date_get_month(date)-1)/3)+1);
664
case REPORT_INTVL_HALFYEAR:
666
//TRANSLATORS: printf string for half-year H, ex. 2019-H1 for 1st half-year of 2019
667
g_snprintf(intvlname, slen, _("h%d"), g_date_get_month(date) < 7 ? 1 : 2);
669
case REPORT_INTVL_YEAR:
670
g_snprintf(intvlname, slen, "%d", g_date_get_year(date));
676
static void datatable_init_items(DataTable *dt, gint src, guint32 jfrom)
679
gchar buffer[64], *name;
681
guint idx, slen = 63;
682
GDateYear prevyear = 0;
684
DB1( g_print("\n-- datatable_init_items--\n") );
686
if( src != REPORT_SRC_MONTH && src != REPORT_SRC_YEAR )
690
case REPORT_SRC_CATEGORY:
691
_datatable_init_items_cat(dt);
693
case REPORT_SRC_PAYEE:
694
_datatable_init_items_pay(dt);
696
case REPORT_SRC_ACCOUNT:
697
_datatable_init_items_acc(dt);
700
_datatable_init_items_tag(dt);
708
for(idx=0;idx<dt->nbrows;idx++)
710
DataRow *dr = dt->rows[idx];
711
guint intvl = REPORT_INTVL_NONE;
373
case REPORT_SRC_CATEGORY:
374
case REPORT_SRC_SUBCATEGORY:
376
Category *entry = da_cat_get(i);
379
name = entry->key == 0 ? _("(no category)") : entry->fullname;
380
//if( src == REPORT_SRC_SUBCATEGORY )
381
//name = entry->name;
382
pos = g_list_index(list, entry);
386
case REPORT_SRC_PAYEE:
388
Payee *entry = da_pay_get(i);
391
name = entry->key == 0 ? _("(no payee)") : entry->name;
392
pos = g_list_index(list, entry);
397
case REPORT_SRC_ACCOUNT:
399
Account *entry = da_acc_get(i);
403
pos = g_list_index(list, entry);
410
Tag *entry = da_tag_get(i+1);
414
pos = g_list_index(list, entry);
716
case REPORT_SRC_NONE:
717
//technical label for sum
719
DB1( g_print(" +none k:%d, idx:%d '%s'\n", idx, idx, name) );
419
721
case REPORT_SRC_MONTH:
420
report_interval_snprint_name(buffer, sizeof(buffer)-1, REPORT_INTVL_MONTH, jfrom, i);
722
intvl = REPORT_INTVL_MONTH;
723
jdate = report_interval_snprint_name(buffer, sizeof(buffer)-1, intvl, jfrom, idx);
725
DB1( g_print(" +month k:%d, idx:%d '%s'\n", idx, idx, name) );
425
727
case REPORT_SRC_YEAR:
426
report_interval_snprint_name(buffer, sizeof(buffer)-1, REPORT_INTVL_YEAR, jfrom, i);
728
intvl = REPORT_INTVL_YEAR;
729
jdate = report_interval_snprint_name(buffer, sizeof(buffer)-1, intvl, jfrom, idx);
731
DB1( g_print(" +year k:%d, idx:%d '%s'\n", idx, idx, name) );
432
DB( g_print("- init row:%d / pos:%d '%s'\n", i, pos, name) );
435
dr->label = g_strdup(name);
443
// this is the add in total mode
444
void datatable_amount_add(DataTable *dt, guint32 idx, gdouble amount)
446
if( idx <= (dt->nbrows) )
448
DataRow *dr = dt->rows[idx];
452
dr->income[1] += amount;
453
dt->totinc += amount;
457
dr->expense[0] += amount;
458
dt->totexp += amount;
462
g_warning("invalid datatable index");
466
DataTable *report_compute_total(gint tmpsrc, Filter *flt, GQueue *txn_queue)
473
DB( g_print("\n[report] compute_total\n") );
475
//todo: remove this later on
476
n_result = report_items_count(tmpsrc, flt->mindate, flt->maxdate);
478
DB( g_print(" %d :: n_result=%d\n", tmpsrc, n_result) );
480
dt = da_datatable_malloc (0, n_result, 3);
483
datatable_init_items(dt, tmpsrc, flt->mindate);
485
list = g_queue_peek_head_link(txn_queue);
488
Transaction *ope = list->data;
490
DB( g_print("** testing '%s', cat=%d==> %d\n", ope->memo, ope->kcat, filter_txn_match(flt, ope)) );
492
if( (filter_txn_match(flt, ope) == 1) )
737
dr->label = g_strdup(name);
740
//dt->keyindex[idx] = idx;
741
datatable_set_keyindex(dt, idx, idx);
743
//dt->keylist[idx] = idx;
744
datatable_set_keylist(dt, idx, idx);
747
g_date_set_julian(date, jdate);
749
datatable_data_get_xlabel(date, intvl, buffer, slen);
751
dr->xlabel = g_strdup(buffer);
753
//set flags => moved into forecast
754
//if( jdate > GLOBALS->today )
755
// dc->flags |= RF_FORECAST;
757
if( (intvl != REPORT_INTVL_YEAR) && (g_date_get_year(date) > prevyear) && (g_date_get_month(date) == 1) )
759
g_snprintf(buffer, slen, "%d", g_date_get_year(date));
760
dr->misclabel = g_strdup(buffer);
761
dr->flags |= RF_NEWYEAR;
764
prevyear = g_date_get_year(date);
772
g_print(" keyindex:");
773
for(idx=0;idx<dt->nbkeys;idx++)
774
g_print(" %d", dt->keyindex[idx]);
778
g_print(" keylist:");
779
for(idx=0;idx<dt->nbrows;idx++)
780
g_print(" %d", dt->keylist[idx]);
786
static void datatable_init_columns(DataTable *dt, gint intvl, guint32 jfrom)
791
guint idx, slen = 63;
792
GDateYear prevyear = 0;
796
for(idx=0;idx<dt->nbcols;idx++)
798
DataCol *dc = dt->cols[idx];
801
report_interval_snprint_name(intvlname, sizeof(intvlname)-1, intvl, jfrom, idx);
802
dc->label = g_strdup(intvlname);
805
jdate = _datatable_interval_get_jdate(intvl, jfrom, idx);
806
g_date_set_julian(date, jdate);
808
datatable_data_get_xlabel(date, intvl, intvlname, slen);
810
dc->xlabel = g_strdup(intvlname);
812
//set flags => moved into forecast
813
if( jdate > GLOBALS->today )
814
dc->flags |= RF_FORECAST;
816
if( (intvl != REPORT_INTVL_YEAR) && (g_date_get_year(date) > prevyear) && (g_date_get_month(date) == 1) )
818
g_snprintf(intvlname, slen, "%d", g_date_get_year(date));
819
dc->misclabel = g_strdup(intvlname);
820
dc->flags |= RF_NEWYEAR;
823
prevyear = g_date_get_year(date);
830
static void datatable_add(DataTable *dt, guint32 key, guint32 col, gdouble amount, gboolean addtotal)
834
DB3( g_print(" add to k:%d c:%d %.2f\n", key, col, amount) );
836
//row = dt->keyindex[key];
837
dr = report_data_get_row(dt, key);
841
if( col <= dt->nbcols )
843
if( hb_amount_equal(amount, 0.0) == FALSE )
497
DB( g_print(" - should insert\n") );
499
trn_amount = report_txn_amount_get(flt, ope);
500
trn_amount = hb_amount_base(trn_amount, ope->kcur);
503
if( tmpsrc != REPORT_SRC_TAG )
505
//for split, affect the amount to the category
506
if( (tmpsrc == REPORT_SRC_CATEGORY || tmpsrc == REPORT_SRC_SUBCATEGORY) && ope->flags & OF_SPLIT )
508
guint nbsplit = da_splits_length(ope->splits);
513
for(i=0;i<nbsplit;i++)
515
split = da_splits_get(ope->splits, i);
516
status = da_flt_status_cat_get(flt, split->kcat);
517
sinsert = ( status == TRUE ) ? 1 : 0;
518
if(flt->option[FLT_GRP_CATEGORY] == 2) sinsert ^= 1;
520
DB( g_print(" split insert=%d, kcat=%d\n", sinsert, split->kcat) );
522
if( (flt->option[FLT_GRP_CATEGORY] == 0) || sinsert)
524
pos = category_report_id(split->kcat, (tmpsrc == REPORT_SRC_SUBCATEGORY) ? TRUE : FALSE);
525
trn_amount = hb_amount_base(split->amount, ope->kcur);
526
datatable_amount_add(dt, pos, trn_amount);
532
pos = report_items_get_pos(tmpsrc, flt->mindate, ope);
533
datatable_amount_add(dt, pos, trn_amount);
847
dr->colexp[col] += amount;
848
dr->rowexp += amount;
849
if( addtotal == TRUE )
851
dt->totrow->colexp[col] += amount;
852
dt->totrow->rowexp += amount;
537
/* the TAG process is particular */
539
if(ope->tags != NULL)
541
guint32 *tptr = ope->tags;
546
datatable_amount_add(dt, pos, trn_amount);
552
list = g_list_next(list);
560
static void datatable_trend_add(DataTable *dt, guint32 row, guint32 col, gdouble amount, gboolean addtotal)
562
DB( g_print(" add to r%d,c%d %.2f\n", row, col, amount) );
564
if( row <= (dt->nbrows) )
566
DataRow *dr = dt->rows[row];
568
if( col <= dt->nbcols )
572
dr->income[col] += amount;
573
dr->income[dt->nbcols] += (amount/dt->nbcols);
574
dr->income[dt->nbcols+1] += amount;
575
//dt->totinc += amount;
576
if( addtotal == TRUE )
578
dt->totrow->income[col] += amount;
579
dt->totrow->income[dt->nbcols] += (amount/dt->nbcols);
580
dt->totrow->income[dt->nbcols+1] += amount;
585
dr->expense[col] += amount;
586
dr->expense[dt->nbcols] += (amount/dt->nbcols);
587
dr->expense[dt->nbcols+1] += amount;
588
//dt->totexp += amount;
589
if( addtotal == TRUE )
591
dt->totrow->expense[col] += amount;
592
dt->totrow->expense[dt->nbcols] += (amount/dt->nbcols);
593
dt->totrow->expense[dt->nbcols+1] += amount;
599
g_warning("invalid datatable index");
603
DataTable *report_compute_trend(gint tmpsrc, gint tmpintvl, Filter *flt, GQueue *txn_queue)
608
gint n_result, n_cols;
610
DB( g_print("\n[report] compute_trend\n") );
612
//todo: remove this later on
613
n_result = report_items_count(tmpsrc, flt->mindate, flt->maxdate);
614
n_cols = report_interval_count(tmpintvl, flt->mindate, flt->maxdate);
616
DB( g_print(" %d :: rows=%d cols=%d\n", tmpsrc, n_result, n_cols) );
618
dt = da_datatable_malloc (0, n_result, n_cols);
621
datatable_init_items(dt, tmpsrc, flt->mindate);
623
list = g_queue_peek_head_link(txn_queue);
626
Transaction *ope = list->data;
628
if( (filter_txn_match(flt, ope) == 1) )
634
DB( g_print("\n srctxn '%s' %.2f, cat=%d, pay=%d, acc=%d\n", ope->memo, ope->amount, ope->kcat, ope->kpay, ope->kacc) );
636
trn_amount = report_txn_amount_get(flt, ope);
637
trn_amount = hb_amount_base(trn_amount, ope->kcur);
639
col = report_interval_get_pos(tmpintvl, flt->mindate, ope);
643
case REPORT_SRC_CATEGORY:
644
case REPORT_SRC_SUBCATEGORY:
645
//for split, affect the amount to the category
646
if( ope->flags & OF_SPLIT )
648
guint nbsplit = da_splits_length(ope->splits);
653
for(i=0;i<nbsplit;i++)
655
split = da_splits_get(ope->splits, i);
656
status = da_flt_status_cat_get(flt, split->kcat);
657
sinsert = ( status == TRUE ) ? 1 : 0;
658
if(flt->option[FLT_GRP_CATEGORY] == 2) sinsert ^= 1;
659
if( (flt->option[FLT_GRP_CATEGORY] == 0) || sinsert)
661
DB( g_print(" split insert=%d, kcat=%d\n", sinsert, split->kcat) );
662
trn_amount = hb_amount_base(split->amount, ope->kcur);
663
pos = category_report_id(split->kcat, (tmpsrc == REPORT_SRC_CATEGORY) ? FALSE : TRUE);
664
datatable_trend_add(dt, pos, col, trn_amount, TRUE);
665
//add to parent as well
666
//#1955046 treeview with child was a test faulty released
667
/*if( tmpsrc == REPORT_SRC_SUBCATEGORY )
669
//#1859279 test cat as subtype here to avoid count twice
670
Category *cat = da_cat_get(split->kcat);
672
if((cat != NULL) && (cat->flags & GF_SUB))
675
datatable_trend_add(dt, pos, col, trn_amount, FALSE);
683
pos = category_report_id(ope->kcat, (tmpsrc == REPORT_SRC_CATEGORY) ? FALSE : TRUE);
684
datatable_trend_add(dt, pos, col, trn_amount, TRUE);
685
//add to parent as well
686
//#1955046 treeview with child was a test faulty released
687
/*if( tmpsrc == REPORT_SRC_SUBCATEGORY )
689
//#1859279 test cat as subtype here to avoid count twice
690
Category *cat = da_cat_get(ope->kcat);
692
if((cat != NULL) && (cat->flags & GF_SUB))
695
datatable_trend_add(dt, pos, col, trn_amount, FALSE);
702
if(ope->tags != NULL)
704
guint32 *tptr = ope->tags;
709
datatable_trend_add(dt, pos, col, trn_amount, TRUE);
716
pos = report_items_get_pos(tmpsrc, flt->mindate, ope);
717
datatable_trend_add(dt, pos, col, trn_amount, TRUE);
722
list = g_list_next(list);
730
DataTable *report_compute_trend_balance(gint tmpsrc, gint tmpintvl, Filter *flt)
733
GList *lst_acc, *lnk_acc;
735
gint n_result, n_cols;
738
DB( g_print("\n[report] compute_trend_balance\n") );
740
//todo: remove this later on
741
n_result = report_items_count(tmpsrc, flt->mindate, flt->maxdate);
742
n_cols = report_interval_count(tmpintvl, flt->mindate, flt->maxdate);
744
DB( g_print(" %d :: n_result=%d\n", tmpsrc, n_result) );
746
dt = da_datatable_malloc (0, n_result, n_cols);
749
datatable_init_items(dt, tmpsrc, flt->mindate);
751
// account initial amount
752
lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
753
lnk_acc = g_list_first(lst_acc);
754
while (lnk_acc != NULL)
756
Account *acc = lnk_acc->data;
761
//#1674045 ony rely on nosummary
762
if( (acc->flags & (AF_NOREPORT)) )
765
//#2000294 enable account filtering
766
if( filter_acc_match(flt, acc) == 0 )
770
trn_amount = hb_amount_base(acc->initial, acc->kcur);
773
DB( g_print(" ** add initbal %8.2f to row:%d, col:%d\n", trn_amount, acc->key, 0) );
774
datatable_trend_add(dt, acc->key, 0, trn_amount, TRUE);
776
lnk_txn = g_queue_peek_head_link(acc->txn_queue);
777
while (lnk_txn != NULL)
779
Transaction *txn = lnk_txn->data;
781
//5.5 forgot to filter...
782
//#1886123 include remind based on user prefs
783
if( (txn->status == TXN_STATUS_REMIND) && (PREFS->includeremind == FALSE) )
786
if( !( txn->status == TXN_STATUS_VOID ) )
787
//TODO: enable filters : make no sense no ?
788
//if( (filter_txn_match(flt, txn) == 1) )
790
pos = report_items_get_pos(tmpsrc, flt->mindate, txn);
792
trn_amount = report_txn_amount_get(flt, txn);
793
trn_amount = hb_amount_base(trn_amount, txn->kcur);
795
DB( g_print("srctxn: %d - cat=%d, pay=%d, acc=%d | [%d - %d]\n", txn->date, txn->kcat, txn->kpay, txn->kacc, flt->mindate, flt->maxdate) );
797
//if( (filter_txn_match(flt, txn) == 1) )
798
if( (txn->date >= flt->mindate) && (txn->date <= flt->maxdate) )
800
col = report_interval_get_pos(tmpintvl, flt->mindate, txn);
801
DB( g_print(" add %8.2f row:%d, col:%d\n", trn_amount, pos, col) );
802
datatable_trend_add(dt, pos, col, trn_amount, TRUE);
805
if( txn->date < flt->mindate)
807
DB( g_print(" **add %8.2f row:%d, col:%d\n", trn_amount, pos, 0) );
808
datatable_trend_add(dt, pos, 0, trn_amount, TRUE);
812
lnk_txn = g_list_next(lnk_txn);
816
lnk_acc = g_list_next(lnk_acc);
818
g_list_free(lst_acc);
857
dr->colinc[col] += amount;
858
dr->rowinc += amount;
859
if( addtotal == TRUE )
861
dt->totrow->colinc[col] += amount;
862
dt->totrow->rowinc += amount;
868
g_warning("datatable add invalid col %d of %d", col, dt->nbcols);
873
static void datatable_data_cols_cumulate(DataTable *dt, gint intvl, Filter *flt)
877
DB2( g_print("\n-- cumulate columns --\n") );
878
DB2( g_print(" n_row=%d n_col=%d\n", dt->nbrows, dt->nbcols) );
822
879
//cumulate columns
823
880
if( dt->nbcols > 1 )
825
884
for(row=0;row<dt->nbrows;row++)
827
886
DataRow *dr = dt->rows[row];
829
//#2012576 nbcols-2 to not scratch avg and total columns
830
for(col=1;col<dt->nbcols-2;col++)
832
dr->income[col] += dr->income[col-1];
833
dr->expense[col] += dr->expense[col-1];
835
dt->totrow->income[col] += dr->income[col-1];
836
dt->totrow->expense[col] += dr->expense[col-1];
888
DB2( g_print(" row %d: ", row) );
889
for(col=1;col<dr->nbcols;col++)
891
guint32 jdate = _datatable_interval_get_jdate(intvl, flt->mindate, col);
893
if( jdate < dt->maxpostdate)
895
DB2( g_print("%d, ", col) );
896
dr->colinc[col] += dr->colinc[col-1];
897
dr->colexp[col] += dr->colexp[col-1];
899
dt->totrow->colinc[col] += dr->colinc[col-1];
900
dt->totrow->colexp[col] += dr->colexp[col-1];
903
DB2( g_print("\n") );
909
static void datatable_data_add_balance(DataTable *dt, gint src, gint intvl, Filter *flt)
911
GList *lst_acc, *lnk_acc;
914
if( src != REPORT_SRC_ACCOUNT && src != REPORT_SRC_NONE )
917
DB1( g_print(" -- add balance\n") );
919
//TODO: we should rely on rows...
920
lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
921
lnk_acc = g_list_first(lst_acc);
922
while (lnk_acc != NULL)
924
Account *acc = lnk_acc->data;
928
//#1674045 ony rely on nosummary
929
if( (acc->flags & (AF_NOREPORT)) )
932
//#2000294 enable account filtering
933
if( filter_acc_match(flt, acc) == 0 )
936
//add initial amount to col[0]
937
trn_amount = hb_amount_base(acc->initial, acc->kcur);
938
//for none, we only allocate the row[0]
939
datatable_add(dt, (src == REPORT_SRC_NONE) ? 0 : acc->key, 0, trn_amount, TRUE);
940
DB2( g_print(" ** add initbal %8.2f to row:%d, col:%d\n", trn_amount, acc->key, 0) );
942
//add txn amount prior mindate to col[0]
943
lnk_txn = g_queue_peek_head_link(acc->txn_queue);
944
while (lnk_txn != NULL)
946
Transaction *txn = lnk_txn->data;
948
//5.5 forgot to filter...
949
//#1886123 include remind based on user prefs
950
if( (txn->status == TXN_STATUS_REMIND) && (PREFS->includeremind == FALSE) )
953
if( !( txn->status == TXN_STATUS_VOID ) )
954
//enable filters : make no sense or not
955
//if( (filter_txn_match(flt, txn) == 1) )
957
pos = report_items_get_key(src, flt->mindate, txn);
959
trn_amount = report_txn_amount_get(flt, txn);
960
trn_amount = hb_amount_base(trn_amount, txn->kcur);
962
if( txn->date < flt->mindate )
964
//DB2( g_print(" **add %8.2f row:%d, col:%d\n", trn_amount, pos, 0) );
965
datatable_add(dt, pos, 0, trn_amount, TRUE);
969
lnk_txn = g_list_next(lnk_txn);
973
lnk_acc = g_list_next(lnk_acc);
975
g_list_free(lst_acc);
980
static void datatable_data_add_txn(DataTable *dt, gint src, gint intvl, Transaction *txn, Filter *flt)
987
//DB2( g_print("\n srctxn '%s' %.2f, cat=%d, pay=%d, acc=%d\n", txn->memo, txn->amount, txn->kcat, txn->kpay, txn->kacc) );
989
trn_amount = report_txn_amount_get(flt, txn);
990
trn_amount = hb_amount_base(trn_amount, txn->kcur);
992
col = report_interval_get_pos(intvl, flt->mindate, txn);
996
case REPORT_SRC_CATEGORY:
997
//case REPORT_SRC_SUBCATEGORY:
998
//for split, affect the amount to the category
999
if( txn->flags & OF_SPLIT )
1001
guint nbsplit = da_splits_length(txn->splits);
1006
for(i=0;i<nbsplit;i++)
1008
split = da_splits_get(txn->splits, i);
1009
status = da_flt_status_cat_get(flt, split->kcat);
1010
sinsert = ( status == TRUE ) ? 1 : 0;
1011
if(flt->option[FLT_GRP_CATEGORY] == 2) sinsert ^= 1;
1012
if( (flt->option[FLT_GRP_CATEGORY] == 0) || sinsert)
1014
Category *cat = da_cat_get(split->kcat);
1016
//DB2( g_print(" split insert=%d, kcat=%d\n", sinsert, split->kcat) );
1017
trn_amount = hb_amount_base(split->amount, txn->kcur);
1018
//pos = category_report_id(split->kcat, (src == REPORT_SRC_CATEGORY) ? FALSE : TRUE);
1019
//datatable_add(dt, pos, col, trn_amount, TRUE);
1023
datatable_add(dt, cat->key, col, trn_amount, TRUE);
1024
if( cat->parent != 0 )
1025
datatable_add(dt, cat->parent, col, trn_amount, FALSE);
1032
Category *cat = da_cat_get(txn->kcat);
1034
//pos = category_report_id(txn->kcat, (src == REPORT_SRC_CATEGORY) ? FALSE : TRUE);
1035
//datatable_add(dt, pos, col, trn_amount, TRUE);
1038
datatable_add(dt, cat->key, col, trn_amount, TRUE);
1039
if( cat->parent != 0 )
1040
datatable_add(dt, cat->parent, col, trn_amount, FALSE);
1045
case REPORT_SRC_TAG:
1046
if(txn->tags != NULL)
1048
guint32 *tptr = txn->tags;
1052
//#2031693 not -1 here
1054
datatable_add(dt, key, col, trn_amount, TRUE);
1058
//2031693 + add notags
1060
datatable_add(dt, 0, col, trn_amount, TRUE);
1064
key = report_items_get_key(src, flt->mindate, txn);
1065
datatable_add(dt, key, col, trn_amount, TRUE);
1074
//5.7 forecast attempt
1075
static void report_compute_forecast(DataTable *dt, gint src, gint intvl, Filter *flt)
1079
guint32 curdate, maxpostdate;
1082
DB1( g_print("\n[report] compute_forecast\n") );
1084
if( intvl == REPORT_INTVL_NONE )
1086
DB1( g_print(" no forecast for total mode\n") );
1090
post_date = g_date_new();
1093
maxpostdate = dt->maxpostdate;
1096
list = g_list_first(GLOBALS->arc_list);
1097
while (list != NULL)
1099
Archive *arc = list->data;
1101
DB2( g_print("--------\n eval post of '%s' %.2f\n", arc->memo, arc->amount) );
1103
if(scheduled_is_postable(arc) == TRUE)
1108
DB2( g_print(" is postable\n") );
1111
txn = da_transaction_malloc();
1112
da_transaction_init_from_template(txn, arc);
1114
acc = da_acc_get(txn->kacc);
1116
txn->kcur = acc->kcur;
1118
txn->date = curdate = arc->nextdate;
1120
if( (filter_txn_match(flt, txn) == 1) )
1122
while(curdate <= maxpostdate)
1124
txn->date = curdate;
1125
DB3( hb_print_date(curdate, "curdate=") );
1127
datatable_data_add_txn(dt, src, intvl, txn, flt);
1129
//mark column as forecast
1130
guint idx = report_interval_get_pos(intvl, flt->mindate, txn);
1131
DataCol *dc = report_data_get_col(dt, idx);
1133
dc->flags |= RF_FORECAST;
1135
curdate = scheduled_date_get_next_post(post_date, arc, curdate);
1137
// break if over limit
1138
if( (arc->flags & OF_LIMIT) && (nbinsert >= arc->limit) )
1143
da_transaction_free (txn);
1145
list = g_list_next(list);
1148
g_date_free(post_date);
1152
/* = = = = = = = = = = = = = = = = = = = = */
1155
DataTable *report_compute(gint src, gint intvl, Filter *flt, GQueue *txn_queue, gboolean do_forecast, gboolean do_balance)
1159
guint32 maxpostdate = flt->maxdate;
1161
DB1( g_print("\n[report] == report_compute ==\n") );
1163
DB2( hb_print_date(maxpostdate, "maxdate") );
1168
if( filter_preset_daterange_future_enable(flt, flt->range) )
1170
GDate *post_date = g_date_new();
1172
g_date_set_time_t(post_date, time(NULL));
1173
g_date_add_months(post_date, PREFS->rep_forecat_nbmonth);
1174
g_date_set_day(post_date, g_date_get_days_in_month(g_date_get_month(post_date), g_date_get_year(post_date)));
1175
maxpostdate = g_date_get_julian(post_date);
1176
DB2( hb_print_date(maxpostdate, "max forecast date") );
1178
g_date_free(post_date);
1180
flt->maxdate = maxpostdate;
1184
dt = da_datatable_malloc(src, intvl, flt);
1189
dt->maxpostdate = maxpostdate;
1191
datatable_init_items(dt, src, flt->mindate);
1192
datatable_init_columns(dt, intvl, flt->mindate);
1194
//balance must keep xfer
1195
/*if( do_balance == TRUE )
1202
list = g_queue_peek_head_link(txn_queue);
1203
while (list != NULL)
1205
Transaction *txn = list->data;
1207
if( (filter_txn_match(flt, txn) == 1) )
1209
datatable_data_add_txn(dt, src, intvl, txn, flt);
1211
list = g_list_next(list);
1216
if( do_forecast == TRUE )
1218
//DB2( g_print("\n-- compute forecast --\n") );
1219
report_compute_forecast(dt, src, intvl, flt);
1222
//process balance mode
1223
if( do_balance == TRUE )
1225
datatable_data_add_balance(dt, src, intvl, flt);
1226
datatable_data_cols_cumulate(dt, intvl, flt);
845
gint report_items_count(gint src, guint32 jfrom, guint32 jto)
847
GDate *date1, *date2;
1233
DataCol *report_data_get_col(DataTable *dt, guint32 idx)
1235
DataCol *retval = NULL;
1237
if( idx <= dt->nbcols )
1239
retval = dt->cols[idx];
1242
g_warning("datatable invalid get col %d of %d", idx, dt->nbcols);
1248
//get a specific row by key
1249
//hub-reptime/hub-reptotal/repstats
1250
DataRow *report_data_get_row(DataTable *dt, guint32 key)
1252
DataRow *retval = NULL;
1255
if( key <= dt->nbkeys )
1257
//we should transpose here
1258
idx = dt->keyindex[key];
1259
if( idx <= dt->nbrows )
1261
DB1( g_print(" get row=%d for key=%d\n", idx, key) );
1262
retval = dt->rows[idx];
1265
g_warning("datatable invalid get row %d of %d", idx, dt->nbrows);
1268
g_warning("datatable invalid get row key %d of %d", key, dt->nbkeys);
1274
//gtk-chart/list-report
1275
gdouble da_datarow_get_cell_sum(DataRow *dr, guint32 index)
1277
if( index <= dr->nbcols )
1279
return (dr->colexp[index] + dr->colinc[index]);
1282
g_warning("invalid datarow column");
1288
guint report_items_get_key(gint src, guint jfrom, Transaction *txn)
852
case REPORT_SRC_CATEGORY:
853
case REPORT_SRC_SUBCATEGORY:
854
nbsrc = da_cat_get_max_key() + 1;
856
case REPORT_SRC_PAYEE:
857
nbsrc = da_pay_get_max_key() + 1;
859
case REPORT_SRC_ACCOUNT:
860
nbsrc = da_acc_get_max_key() + 1;
863
nbsrc = da_tag_length();
865
case REPORT_SRC_MONTH:
866
date1 = g_date_new_julian(jfrom);
867
date2 = g_date_new_julian(jto);
868
nbsrc = ((g_date_get_year(date2) - g_date_get_year(date1)) * 12) + g_date_get_month(date2) - g_date_get_month(date1) + 1;
872
case REPORT_SRC_YEAR:
873
date1 = g_date_new_julian(jfrom);
874
date2 = g_date_new_julian(jto);
875
nbsrc = g_date_get_year(date2) - g_date_get_year(date1) + 1;
886
gint report_items_get_pos(gint tmpsrc, guint jfrom, Transaction *ope)
892
case REPORT_SRC_CATEGORY:
893
pos = category_report_id(ope->kcat, FALSE);
895
case REPORT_SRC_SUBCATEGORY:
898
case REPORT_SRC_PAYEE:
901
case REPORT_SRC_ACCOUNT:
904
case REPORT_SRC_MONTH:
905
pos = DateInMonth(jfrom, ope->date);
907
case REPORT_SRC_YEAR:
908
pos = DateInYear(jfrom, ope->date);
916
gint report_interval_get_pos(gint intvl, guint jfrom, Transaction *ope)
1294
case REPORT_SRC_NONE:
1297
case REPORT_SRC_CATEGORY:
1298
key = category_report_id(txn->kcat, FALSE);
1300
//case REPORT_SRC_SUBCATEGORY:
1303
case REPORT_SRC_PAYEE:
1306
case REPORT_SRC_ACCOUNT:
1311
case REPORT_SRC_MONTH:
1312
key = DateInMonth(jfrom, txn->date);
1314
case REPORT_SRC_YEAR:
1315
key = DateInYear(jfrom, txn->date);
1323
//rep- balance/budget/time
1324
gint report_interval_get_pos(gint intvl, guint jfrom, Transaction *txn)
922
1330
case REPORT_INTVL_DAY:
923
pos = ope->date - jfrom;
1331
pos = txn->date - jfrom;
925
1333
case REPORT_INTVL_WEEK:
926
1334
//#1915643 week iso 8601
927
//pos = (ope->date - jfrom)/7;
928
pos = DateInWeek(jfrom, ope->date);
1335
//pos = (txn->date - jfrom)/7;
1336
pos = DateInWeek(jfrom, txn->date);
931
1339
case REPORT_INTVL_FORTNIGHT:
932
pos = DateInFortNight(jfrom, ope->date);
1340
pos = DateInFortNight(jfrom, txn->date);
934
1342
case REPORT_INTVL_MONTH:
935
pos = DateInMonth(jfrom, ope->date);
1343
pos = DateInMonth(jfrom, txn->date);
937
1345
case REPORT_INTVL_QUARTER:
938
pos = DateInQuarter(jfrom, ope->date);
1346
pos = DateInQuarter(jfrom, txn->date);
940
1348
case REPORT_INTVL_HALFYEAR:
941
pos = DateInHalfYear(jfrom, ope->date);
1349
pos = DateInHalfYear(jfrom, txn->date);
943
1351
case REPORT_INTVL_YEAR:
944
pos = DateInYear(jfrom, ope->date);
1352
pos = DateInYear(jfrom, txn->date);
1354
default: //REPORT_INTVL_NONE