/* HomeBank -- Free, easy, personal accounting for everyone. * Copyright (C) 1995-2019 Maxime DOYEN * * This file is part of HomeBank. * * HomeBank is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * HomeBank is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "homebank.h" #include "dsp-mainwindow.h" #include "list-scheduled.h" #include "hub-scheduled.h" #include "ui-transaction.h" /****************************************************************************/ /* Debug macros */ /****************************************************************************/ #define MYDEBUG 0 #if MYDEBUG #define DB(x) (x); #else #define DB(x); #endif /* our global datas */ extern struct HomeBank *GLOBALS; extern struct Preferences *PREFS; /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* scheduled */ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ static Archive * ui_hub_scheduled_get_selected_item(GtkTreeView *treeview) { GtkTreeSelection *treeselection; GtkTreeModel *model; GtkTreeIter iter; treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); if( gtk_tree_selection_get_selected(treeselection, &model, &iter) ) { Archive *arc; gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1); return arc; } return NULL; } static void ui_hub_scheduled_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { //struct hbfile_data *data; Archive *arc; DB( g_print ("\n[hub-scheduled] row double-clicked\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data"); arc = ui_hub_scheduled_get_selected_item(treeview); ui_mainwindow_defarchive(arc); } static void ui_hub_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data) { struct hbfile_data *data = user_data; GtkWidget *window; gint result; Transaction *txn; DB( g_print("\n[hub-scheduled] do post\n") ); window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE, 0); /* fill in the transaction */ txn = da_transaction_malloc(); da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, arc->nextdate); deftransaction_set_transaction(window, txn); result = gtk_dialog_run (GTK_DIALOG (window)); DB( g_print(" - dialog result is %d\n", result) ); if(result == HB_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT) { deftransaction_get(window, NULL); transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn); GLOBALS->changes_count++; scheduled_date_advance(arc); DB( g_print(" - added 1 transaction to %d\n", txn->kacc) ); } da_transaction_free(txn); deftransaction_dispose(window, NULL); gtk_widget_destroy (window); } static void ui_hub_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; DB( g_print("\n[hub-scheduled] editpost\n") ); Archive *arc = ui_hub_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) ) { ui_hub_scheduled_do_post(arc, TRUE, data); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); } } static void ui_hub_scheduled_post_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; DB( g_print("\n[hub-scheduled] post\n") ); Archive *arc = ui_hub_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) ) { if( scheduled_is_postable(arc) ) { Transaction *txn = da_transaction_malloc (); da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, arc->nextdate); transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn); GLOBALS->changes_count++; scheduled_date_advance(arc); da_transaction_free (txn); } else { ui_hub_scheduled_do_post(arc, FALSE, data); } ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); } } static void ui_hub_scheduled_skip_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; DB( g_print("\n[hub-scheduled] skip\n") ); Archive *arc = ui_hub_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) && (arc->flags & OF_AUTO) ) { GLOBALS->changes_count++; scheduled_date_advance(arc); ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE)); } } static void ui_hub_scheduled_update(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; //gint filter; DB( g_print("\n[hub-scheduled] update\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter)); Archive *arc = ui_hub_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if(arc) { DB( g_print("archive is %s\n", arc->memo) ); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE); } else { gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE); } } static void ui_hub_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data) { ui_hub_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); } /* ** called after load, importamiga, on demand */ void ui_hub_scheduled_postall(GtkWidget *widget, gpointer user_data) { //struct hbfile_data *data; gint count; gint usermode = GPOINTER_TO_INT(user_data); DB( g_print("\n[hub-scheduled] post all\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); count = scheduled_post_all_pending(); //inform the user if(usermode == TRUE) { gchar *txt; //#125534 if( count > 0 ) { ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL)); } if(count == 0) txt = _("No transaction to add"); else txt = _("transaction added: %d"); ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO, _("Check scheduled transactions result"), txt, count); } } void ui_hub_scheduled_populate(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkTreeModel *model; GtkTreeIter iter; GList *list; gdouble totexp = 0; gdouble totinc = 0; gint count = 0; gchar buffer[256]; guint32 maxpostdate; GDate *date; //Account *acc; DB( g_print("\n[hub-scheduled] populate\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); gtk_list_store_clear (GTK_LIST_STORE(model)); homebank_app_date_get_julian(); maxpostdate = scheduled_date_get_post_max(); date = g_date_new_julian (maxpostdate); g_date_strftime (buffer, 256-1, PREFS->date_format, date); g_date_free(date); gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer); list = g_list_first(GLOBALS->arc_list); while (list != NULL) { Archive *arc = list->data; Account *acc; gdouble inc, exp; guint nbdays, nblate; if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0) { count++; nbdays = arc->nextdate - maxpostdate; nblate = scheduled_get_latepost_count(arc, GLOBALS->today); DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) ); if(arc->flags & OF_INCOME) { inc = arc->amount; exp = 0.0; } else { exp = arc->amount; inc = 0.0; } /* insert normal txn */ acc = da_acc_get(arc->kacc); if( acc) { totinc += hb_amount_base(inc, acc->kcur); totexp += hb_amount_base(exp, acc->kcur); } gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_NEXT, nbdays, LST_DSPUPC_ACCOUNT, acc, LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, exp, LST_DSPUPC_INCOME, inc, LST_DSPUPC_NB_LATE, nblate, -1); /* insert internal xfer txn : 1378836 */ if(arc->paymode == PAYMODE_INTXFER) { acc = da_acc_get(arc->kxferacc); if( acc) { totinc += hb_amount_base(-inc, acc->kcur); totexp += hb_amount_base(-exp, acc->kcur); } gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_NEXT, nbdays, LST_DSPUPC_ACCOUNT, acc, LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, -inc, LST_DSPUPC_INCOME, -exp, LST_DSPUPC_NB_LATE, nblate, -1); } } list = g_list_next(list); } // insert total if(count > 0 ) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, NULL, LST_DSPUPC_ACCOUNT, NULL, LST_DSPUPC_MEMO, _("Total"), LST_DSPUPC_EXPENSE, totexp, LST_DSPUPC_INCOME, totinc, -1); } ui_hub_scheduled_update(widget, NULL); } GtkWidget *ui_hub_scheduled_create(struct hbfile_data *data) { GtkWidget *hub, *hbox, *vbox, *bbox, *sw, *tbar; GtkWidget *label, *widget; GtkToolItem *toolitem; DB( g_print("\n[hub-scheduled] create\n") ); hub = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width(GTK_CONTAINER(hub), SPACING_SMALL); //data->GR_upc = hub; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); //gtk_widget_set_margin_top(GTK_WIDGET(vbox), 0); //gtk_widget_set_margin_bottom(GTK_WIDGET(vbox), SPACING_SMALL); //gtk_widget_set_margin_start(GTK_WIDGET(vbox), 2*SPACING_SMALL); //gtk_widget_set_margin_end(GTK_WIDGET(vbox), SPACING_SMALL); gtk_box_pack_start (GTK_BOX (hub), vbox, TRUE, TRUE, 0); sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); widget = (GtkWidget *)create_list_upcoming(); data->LV_upc = widget; gtk_container_add (GTK_CONTAINER (sw), widget); tbar = gtk_toolbar_new(); gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0); label = make_label_group(_("Scheduled transactions")); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), label); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, FALSE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), bbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); widget = gtk_button_new_with_label(_("Skip")); data->BT_sched_skip = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); widget = gtk_button_new_with_label(_("Edit & Post")); data->BT_sched_editpost = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); //TRANSLATORS: Posting a scheduled transaction is the action to materialize it into its target account. //TRANSLATORS: Before that action the automated transaction occurrence is pending and not yet really existing. widget = gtk_button_new_with_label (_("Post")); data->BT_sched_post = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, FALSE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), hbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); label = make_label(_("maximum post date"), 0.0, 0.7); gtk_widget_set_halign (label, GTK_ALIGN_CENTER); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); label = make_label(NULL, 0.0, 0.7); data->LB_maxpostdate = label; gtk_widget_set_halign (label, GTK_ALIGN_CENTER); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_upc)), "changed", G_CALLBACK (ui_hub_scheduled_selection_cb), NULL); g_signal_connect (GTK_TREE_VIEW(data->LV_upc), "row-activated", G_CALLBACK (ui_hub_scheduled_onRowActivated), NULL); g_signal_connect (G_OBJECT (data->BT_sched_skip), "clicked", G_CALLBACK (ui_hub_scheduled_skip_cb), data); g_signal_connect (G_OBJECT (data->BT_sched_editpost), "clicked", G_CALLBACK (ui_hub_scheduled_editpost_cb), data); g_signal_connect (G_OBJECT (data->BT_sched_post), "clicked", G_CALLBACK (ui_hub_scheduled_post_cb), data); return hub; }