Tfe

Ongi etorri tfe-ren webgunera...

Projects/kmymoney basic viewer/js/kmymoney.js

(Deskargatu)
/* Kmymoney basic viewer 
    - tfe <  tfe@ptain.info>
*/


// Loadding google visualizacion apis
/*
google.load('visualization', '1', {packages: ['annotatedtimeline']});
google.load('visualization', '1', {packages: ['areachart']});
google.load('visualization', '1', {packages: ['columnchart']});
google.load('visualization', '1', {packages: ['linechart']});
*/


/* Main */
var kmymoney = {
    // XML Vars
    file            : 'Budget.xml',
    xml             : false,   
    xmlDoc          : false,
    prefix          : '/KMYMONEY-FILE',

    // Google chart types
    graph_types     : [ 'AnnotatedTimeLine', 'AreaChart', 'ColumnChart', 'LineChart' ],
    chart_width     : '90%', // 90% of screen width
    chart_height    : '400px',

    // Data
    created_date    : false,

    // Default filter data 
    startdate       : '',
    enddate         : '',
    step_trans      : 50,


    // HTML Links
    layout            : false,

    // Init: get xml file
    init            : function(layout)
    {

        // Init default values
        this.layout = $(layout);
        this.layout.update('');
        this.startdate='20001230';
        this.enddate=this.date_format(new Date());

        // Loading advise after basic menu
        this.layout.appendChild(new Element('p').update('Loading Kmymoney XML File '+this.file+'. Please wait...'));

        // Request XML Kmymoney file
        this.xml= new Ajax.Request(this.file,{
            onSuccess: function() 
            {
                // Not using "this" (?) , bug??
                setTimeout(function() { kmymoney.firstanalyse();},100);
            },
            onFailure : function()
            {
                setTimeout(function() { kmymoney.failure();},100);
            }
        });


    },

    // On load xml failure
    failure : function()
    {
        $(this.layout).update('');
        if(this.xml.transport.status=='404')
        {
            $(this.layout).appendChild(new Element('p', { 'class':'error'}).update('The file '+this.file+' cannot be found. Please check the file and try again later.'));
        }
        else
        {
            $(this.layout).appendChild(new Element('p', { 'class':'error'}).update('An error occured downloading the file '+this.file+' : error '+this.xml.transport.status));
        }
        var p = new Element('p');
        p.appendChild(new Element('a', { href:'#', onclick:'kmymoney.init(\'loading\'); return false;'}).update('Retry'));
        $(this.layout).appendChild(p);
    },

    // XML FOrmat to  user readable format
    date_format_user : function(dateformat)
    {
        return dateformat.replace(/(\d{4})(\d{2})(\d{2})/,'$3/$2/$1');
    },

    // XML user format to xml format
    undate_format_user : function(dateformat)
    {
        return dateformat.replace(/(\d{2})\/(\d{2})\/(\d{4})/,'$3$2$1');
    },


    // date object to xml format
    date_format : function(dateformat)
    {
        var year = dateformat.getYear()+1900;
        var month = dateformat.getMonth()+1;
        var day = dateformat.getDate();
        if(month<10) {  month='0'+month; }
        if(day<10) {  day='0'+day; }

        return year+''+month+''+day;
    },

    // xml format to date object
    undate_format : function(date_format)
    {
        var reg= /(\d{4})(\d{2})(\d{2})/i;
        var date_data = reg.exec(date_format);
        if(!date_data)
        {
            return false;
        }
        return new Date(date_data[1], date_data[2]-1, date_data[3]);
    },

    // GetXPath 
    // Cross browser
    xpath           : function(path)
    {
        if(this.xmlDoc.evaluate)
        {
        return this.xmlDoc.evaluate(
            this.prefix+path,
            this.xmlDoc, 
            null, 
            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE , 
            null 
        );
        }
        else
        {
            return this.xmlDoc.selectNodes(this.prefix+path);
        }
    },

    // XPath result item
    // Cross browser
    xpathItem   : function(elt,i)
    {
        if(elt.snapshotLength)
        {
            return elt.snapshotItem(i);
        }
        return elt[i];
    },

    // XPath result length
    // Cross browser
    xpathLength : function(elt)
    {
        if(elt.snapshotLength)
        {
            return elt.snapshotLength
        }
        return elt.length;
    },


    // First analysis
    // Used to correct date-formats and create basic elements
    // Generate menu
    firstanalyse    : function()
    {
        // Deleting loading advise
	$(this.layout).update('');
        $(this.layout).appendChild(new Element('p').update('XML Kmymoney file '+this.file+' loaded.'));

        this.xmlDoc= this.xml.transport.responseXML;

        // Correcting date format (numerics)
        var trans = this.xpath('/TRANSACTIONS/TRANSACTION');
        for(var i=0;i<this.xpathLength(trans); i++)
        {
            var item_modify = this.xpathItem(trans,i);
            var current_date = item_modify.getAttribute('postdate');
            item_modify.setAttribute('postdate', current_date.replace(/\D/g,''));
            if(i==0)
            {
                this.startdate=item_modify.getAttribute('postdate');
            }
            else if(i==this.xpathLength(trans)-1)
            {
                this.enddate=item_modify.getAttribute('postdate');
            }
        }
        // Endo date format correction

        // Modify general startdate and enddate


        // Get created_date DATE
        var fileinfo = this.xpath('/FILEINFO/CREATION_DATE');
        this.created_date= this.xpathItem(fileinfo,0).getAttribute('date');


        // Creating menu
        var div = new Element('div', { 'class':'menu'});
        var ul = new Element('ul');
        var li = new Element('li');
        li.appendChild(new Element('a', { href:'#', onclick:'kmymoney.mouvements_list(); return false;'}).update('Categories'));
        ul.appendChild(li);

        li = new Element('li');
        li.appendChild(new Element('a', { href:'#', onclick:'kmymoney.graphiques_start(); return false;'}).update('Charts'));
        ul.appendChild(li);
        div.appendChild(ul);

        document.body.insertBefore(div,$(this.layout));

        // Calculate graph values using filters
        this.calculate_sums();

    },

    // Liste des comptes disponibles
    mouvements_list : function()
    {
        $(this.layout).update('');

	var div = new Element('div', { 'class' : 'tier'});
	this.layout.appendChild(div);
        div.appendChild(new Element('h2').update('Account list'));
        this.mouvements_list_detail('AStd::Asset', div);

	div = new Element('div', { 'class' : 'tier'});
	this.layout.appendChild(div);
        div.appendChild(new Element('h2').update('Income list'));
        this.mouvements_list_detail('AStd::Income', div);

	div = new Element('div', { 'class' : 'tier'});
	this.layout.appendChild(div);
        div.appendChild(new Element('h2').update('Expense list'));
        this.mouvements_list_detail('AStd::Expense', div);

	div = new Element('div', { 'class' : 'endtier'});
	this.layout.appendChild(div);


    },


    mouvements_list_detail : function(account_id, elt, antifreeze)
    {
	if(!antifreeze)
	{
		antifreeze=new Array();
	}
        // Calculate totals for each categorie
        var data = this.xpath('/ACCOUNTS/ACCOUNT[@parentaccount=\''+account_id+'\']');

	var main_tag = elt.tagName=='UL' ? 'LI': 'DIV';

	var main = new Element(main_tag);

        var ul=new Element('ul');
	if(this.xpathLength(data)>0)
	{
		for(i=0; i<this.xpathLength(data); i++)
		{
			var id= this.xpathItem(data,i).getAttribute('id');
			var last_total= (parseInt(this.xpathItem(data, i).getAttribute('total'))/100).toFixed(2)+'&euro';

			var li = new Element('li');
			li.appendChild(new Element('a', { href:'#' , onclick:'kmymoney.mouvements(\''+id+'\'); return false;'}).update(this.xpathItem(data,i).getAttribute('name')));
			li.appendChild(new Element('span').update(' ('+last_total+')'));
			ul.appendChild(li);

			if(antifreeze.indexOf(id)==-1)
			{
				antifreeze.push(id);
				this.mouvements_list_detail(id, ul);
			}
		}
        	main.appendChild(ul);
		elt.appendChild(main);
	}
    },

    // Mouvements du compte
    mouvements: function(account_id, endid)
    {
    	if(!endid)
	{
		endid=0;
	}
	this.graphiques_start(account_id);

	var data = this.xpath('/TRANSACTIONS/TRANSACTION/SPLITS/SPLIT[@account=\''+account_id+'\']');

	// Show last 20
	endid=parseInt(endid);
	var rowstart=  this.xpathLength(data)-(this.step_trans*endid)-1;
	var rowend= this.xpathLength(data)-(this.step_trans*endid)-(this.step_trans+1);

	if(rowend<0)
	{
		rowend=-1;
	}

    	if(!$('table_'+account_id))
	{
        	//$(this.layout).update();
		var xml_cat = this.xpath('/ACCOUNTS/ACCOUNT[@id=\''+account_id+'\']');
		$(this.layout).appendChild(new Element('h2').update(''+this.xpathItem(xml_cat,0).getAttribute('name')));
		var span = new Element('span', { id:'last_trans_steps'}).update(this.step_trans);
		$(this.layout).appendChild(new Element('p', {id:'last_trans_steps'}).update('Displaying '+this.step_trans+' transactions/update'));


		var form= new Element('form');

		var table= new Element('table', { id:'table_'+account_id, border:1});
		form.appendChild(table);
		var tr= new Element('tr');
		var td= new Element('th').update('Date');
		tr.appendChild(td);
		td= new Element('th').update('Categorie');
		tr.appendChild(td);
		td= new Element('th').update('Payee');
		tr.appendChild(td);
		td= new Element('th').update('Amount');
		tr.appendChild(td);
		td= new Element('th').update('Account current value');
		tr.appendChild(td);
		td= new Element('th').update('Memo');
		tr.appendChild(td);
		table.appendChild(tr);
        	$(this.layout).appendChild(form);

	}
	else
	{
		table =$('table_'+account_id);
	}
	var p = new Element('p');
	if(rowend>0)
	{
		p.appendChild(new Element('a', { id:'next_trans', href:'#', onclick:'this.parentNode.remove();kmymoney.mouvements(\''+account_id+'\',\''+(endid+1)+'\'); return false'}).update('Display more'));
		p.appendChild(document.createTextNode(' - '));
		$(this.layout).appendChild(p);
	}
	p.appendChild(new Element('a', {href:'#', onclick:'kmymoney.mouvements_list()'}).update('Go back'));
	$(this.layout).appendChild(p);



        var cats_name= new Hash();
        var payee_name= new Hash();


	/* Transaction loops */
        for(i=rowstart; i>rowend; i--)
        {
            var trans = this.xpathItem(data,i).parentNode.parentNode;
            var splits = this.xpathItem(data,i).parentNode;
            var current = this.xpathItem(data,i).getAttribute('shares');
            var current=current.replace(/\/10(0?)$/,'$1');

            var categorie='';
	    /* Splits loop */
            for(var j=0;j<splits.childNodes.length;j++)
            {
                if(splits.childNodes[j].tagName && splits.childNodes[j]!=this.xpathItem(data,i))
                {
                    categorieId= splits.childNodes[j].getAttribute('account');
                    if(!cats_name.get(categorieId))
                    {
                        var xml_cat = this.xpath('/ACCOUNTS/ACCOUNT[@id=\''+categorieId+'\']');
                        cats_name.set(categorieId, this.xpathItem(xml_cat,0).getAttribute('name'));
                    }
                    categorie = cats_name.get(categorieId);

                    payee= splits.childNodes[j].getAttribute('payee');
		    if(payee!='')
		    {
			    if(!cats_name.get(payee))
			    {
		
				    var xml_cat = this.xpath('/PAYEES/PAYEE[@id=\''+payee+'\']');
				    payee_name.set(categorie, this.xpathItem(xml_cat,0).getAttribute('name'));
			    }
			    payee = payee_name.get(categorie);
		    }
                }
            }

            tr= new Element('tr');
            td= new Element('td').update(this.date_format_user(trans.getAttribute('postdate')));
            tr.appendChild(td);
	        var a = new Element('a', { href:'#', onclick:'kmymoney.mouvements(\''+categorieId+'\'); return false;'}).update(categorie);
            td= new Element('td');
            td.appendChild(a);
            tr.appendChild(td);
            td= new Element('td').update(payee);
            tr.appendChild(td);
            var num  = (parseInt(this.xpathItem(data,i).getAttribute('shares'))/100).toFixed(2);
	    var className = num>0 ? 'ok' : 'ko';
            td= new Element('td', { 'class':className+' euro'}).update(num+'&euro;');
            tr.appendChild(td);
            num  = (parseInt(this.xpathItem(data,i).getAttribute('total'))/100).toFixed(2);
	    var className = num>0 ? 'ok_total' : 'ko_total';
            td= new Element('td', { 'class':className+' euro'}).update(num+'&euro;');
            tr.appendChild(td);
            td= new Element('td').update(this.xpathItem(data,i).getAttribute('memo'));
            tr.appendChild(td);
            table.appendChild(tr);
	}


    },


    // Chart part

    // Calculats sums for each categories
    calculate_sums : function()
    {
        /* Reset category totals */
        var xml_trans = this.xpath('/ACCOUNTS/ACCOUNT');
        for(i=0; i<this.xpathLength(xml_trans);i++)
        {
            this.xpathItem(xml_trans,i).setAttribute('total',0);
        }
        /* Reset transactions totals */
        var xml_trans = this.xpath('/TRANSACTIONS/TRANSACTION/SPLITS/SPLIT');
        for(i=0; i<this.xpathLength(xml_trans);i++)
        {
            this.xpathItem(xml_trans,i).setAttribute('total',0);
        }

        // Calculate totals for each categorie
        //var xml_split = this.xpath('/TRANSACTIONS/TRANSACTION[@postdate>'+startdate+' and @postdate<'+enddate+']/SPLITS/SPLIT');
        var xml_split = this.xpath('/TRANSACTIONS/TRANSACTION/SPLITS/SPLIT');
        var reg = /(.*)\/(.*)/;

        /* Loop - calculate totals */
        for(i=0; i<this.xpathLength(xml_split); i++)
        {
            var trans = this.xpathItem(xml_split,i);
            var current =  trans.getAttribute('shares');
            var account = trans.getAttribute('account');
            var categorie = this.xpath('/ACCOUNTS/ACCOUNT[@id=\''+account+'\']');
            var account_current_total = this.xpathItem(categorie, 0).getAttribute('total');


            if(!account_current_total)
            {
                account_current_total=0;
            }

            // Calculate new total
            var newtotal = parseInt(current)+parseInt(account_current_total);
            // Xpath links
            var modify_item = this.xpathItem(categorie, 0);
            var modify_item2 = this.xpathItem(xml_split, i);

            // Modify categorie (displayed in table)
            // Sum of all transactions
            modify_item.setAttribute('total',newtotal);
            // Modify split total (displayed in char)
            modify_item2.setAttribute('total',newtotal);
        }

    },

    // Graphiques start
    graphiques_start         : function(accounts)
    {
	    this.layout.update('');

	    var form=new Element('form');
            var div=new Element('div', { id : 'div_charts', 'class':'category'});
            // Creating menu
            var submenu=new Element('div', { 'class':'submenu'} );


            var p = new Element('p');
            p.appendChild( new Element('label', { 'for': 'startdate'}).update('Display from'));
            p.appendChild( new Element('input', { type:'text',id: 'startdate', value: this.date_format_user(this.startdate) }));
	    p.appendChild(document.createTextNode(' to '));
            p.appendChild( new Element('input', { type:'text',id: 'enddate', value: this.date_format_user(this.enddate) }));
            submenu.appendChild(p);

        
	    // Steps
            p = new Element('p');
            p.appendChild( new Element('label', { 'for': 'step_num'}).update('Interval'));
            p.appendChild( new Element('input', { type:'text',id: 'step_num', value:1 }));
	    var select= new Element('select', { id:'step_type'});
	    select.appendChild(new Element('option', { value:'year'}).update('Years'));
	    select.appendChild(new Element('option', { selected:'selected', value:'months'}).update('Months'));
	    select.appendChild(new Element('option', { value:'days'}).update('Days'));
            p.appendChild(select);
            submenu.appendChild(p);

	    // Summarize
            p = new Element('p');
	    var checked  = accounts ? false : 'checked';
            p.appendChild( new Element('label', { 'for': 'attribute'}).update('Summarize values/dates'));
            p.appendChild( new Element('input', { type:'checkbox','checked':checked, 'id': 'attribute'}));
            submenu.appendChild(p);

            p = new Element('p');
            p.appendChild( new Element('label', { 'for': 'summarize'}).update('Total of categories'));
            p.appendChild( new Element('input', { type:'checkbox', 'id': 'summarize'}));
            submenu.appendChild(p);


	    // Graph type
            p = new Element('p');
            p.appendChild( new Element('label', { 'for': 'graphtype'}).update('Chart type'));
            var select= new Element('select', { id:'graphtype'});
            select.appendChild(new Element('option', { value:0}).update(this.graph_types[0]));
            select.appendChild(new Element('option', { value:1}).update(this.graph_types[1]));
            select.appendChild(new Element('option', { selected:'selected', value:2}).update(this.graph_types[2]));
            select.appendChild(new Element('option', { value:3}).update(this.graph_types[3]));
            p.appendChild(select);
            submenu.appendChild(p);

	    /* If accounts not set */
	    if(!accounts)
	    {
		    // Chart type data
		    p = new Element('p');
		    p.appendChild( new Element('label', { 'for': 'chart_type_data'}).update('Data type'));
		    var select=new Element('select', { id:'chart_type_data'});
		    select.appendChild(new Element('option', { value:'AStd::Asset,AStd::Liability'}).update('Accounts'));
		    select.appendChild(new Element('option', { value:'AStd::Income'}).update('Income'));
		    select.appendChild(new Element('option', { value:'AStd::Expense'}).update('Expense'));
		    select.appendChild(new Element('option', { value:'AStd::Income,AStd::Expense'}).update('Income - Expense'));
		    p.appendChild(select);
		    submenu.appendChild(p);
	    }
	    /* if accounts sets */
	    else
	    {
		    // Chart type data
		    p = new Element('p');
		    p.appendChild( new Element('input', { 'type': 'hidden', id:'chart_type_data', value:accounts}));
		    submenu.appendChild(p);
	    }

	    // Invert chart
            p = new Element('p');
            p.appendChild( new Element('label', { 'for': 'invert'}).update('Invert values'));
            p.appendChild( new Element('input', { type:'checkbox', 'id': 'invert'}));
            submenu.appendChild(p);

	    // Submit
            p = new Element('p');
            p.appendChild( new Element('input', { type:'submit', value: 'Update chart', onclick:'kmymoney.display_category_chart(); return false' }));
            submenu.appendChild(p);


            form.appendChild(submenu);
            $(this.layout).appendChild(form);
            $(this.layout).appendChild(div);
	    kmymoney.display_category_chart(); 
    },

    display_category_chart            : function()
    {
        $('div_charts').update();
        attribute= $('attribute').checked ? 'total' : 'shares';
        display_subcats= $('summarize').checked ? true : false;
        graph_type= $('graphtype').value;

        // Empty layer
        var cats_init= $F('chart_type_data').split(',');
        var categories = new Array();

        // Display expense categories
        for(var i=0;i<cats_init.length;i++)
        {
                var cats_temp = this.get_categorie_list(cats_init[i], true, attribute, $('div_charts'));
            for(var j=0;j<cats_temp.length;j++)
            {
                if(categories.indexOf(cats_temp[j])==-1)
                {
                    categories.push(cats_temp[j]);
                }
            }
        }

            // Display shares column
        
        // Get step data
        var stepNum = parseInt($F('step_num'));
        if(stepNum==0)
        {
            alert('fail');
        }
        var stepType = $F('step_type');

        var days=0;
        var months=0;
        if(stepType=='days')
        {
            days=stepNum;
        }
        else if(stepType=='months')
        {
            months=stepNum;
        }
        else
        {
            months=stepNum*12;
        }

            this.chart(
                this.undate_format_user($F('startdate')), 
                this.undate_format_user($F('enddate')), 
                categories, 
                attribute, 
                display_subcats,
                graph_type, 
                $('div_charts'),
            $F('invert'),
                days,
                months
            );
    },

    get_categorie_list            : function(parent_id, display_subcats, attribute, elt)
    {
        var cats = Array(parent_id);
        if(!parent_id)
        {
            parent_id='';
        }
        // View categorie
        var categorie = this.xpath('/ACCOUNTS/ACCOUNT[@parentaccount=\''+parent_id+'\']');
        // Init loop categorie

        if(this.xpathLength(categorie)>0)
        {
            var ul = new Element('ul');
            for(var i=0;i<this.xpathLength(categorie);i++)
            {
                var current_categorie = this.xpathItem(categorie, i);
                var td = new Element('td').update(current_categorie.getAttribute('name'));
                var td2 = new Element('td').update(current_categorie.getAttribute('total'));
                var valeur = current_categorie.getAttribute('total') || 0;
                var p = new Element('p').update(
                        current_categorie.getAttribute('name')+' = '+(valeur/100).toFixed(2)+'&euro;');
                var p2 = new Element('p2');
                var li = new Element('li');
                li.appendChild(p);
                li.appendChild(p2);
                ul.appendChild(li);

                cats.push(current_categorie.getAttribute('id'));
                if(display_subcats)
                {
                    var new_cats = this.get_categorie_list(current_categorie.getAttribute('id'), display_subcats, attribute, p2);
                    for(var j=0;j< new_cats.length; j++)
                    {
                        cats.push(new_cats[j]);
                    }
                }
            }
            //elt.appendChild(ul);
        }
        // End account view
        return cats;
    },



                        


    // Display chart
    chart       : function(startdate, enddate, categories, attribute, display_subcats, graph_type, html_item, invert, daystep, monthstep)
    {
        monthstep = parseInt(monthstep);
        daystep = parseInt(daystep);

        var date_init = this.undate_format(startdate);
        var date_end = this.undate_format(enddate);
        var reg= /(\d{4})(\d{2})(\d{2})/i;

        if(!date_init || !date_end || date_init>date_end)
        {
            return false;
        }

        if(categories.length==0)
        {
            html_item.appendChild(new Element('p').update('No data available'));
            return false;
        }
        var data = new google.visualization.DataTable();
        data.addColumn('date', 'Date');
        if(display_subcats)
        {
            data.addColumn('number', 'Total');
        }
        
        // Sub query for categories
        var xpath_sub= new Array();

        if(categories.length==0)
        {
            xpath_sub.push('@account=0');
        }
        else
        {
            for(var i=0;i<categories.length;i++)
            {
                xpath_sub.push('@account=\''+categories[i]+'\'');
            }
        }

        var columns_totals=new Hash();
        var columns=Array();
        date_end.setDate(date_end.getDate()+1);


        if(attribute=='total')
        {
            var columns_parcial=new Hash();
        }

        /* Get Previous values of startdate to get correct total value*/
        var xpath_query = '/TRANSACTIONS/TRANSACTION[@postdate<'+startdate+']/SPLITS/SPLIT';
        xpath_query+='['+xpath_sub.join(' or ')+']';
        var xml_data = this.xpath(xpath_query);
        var columns_parcial=new Hash();

        /* Loop to get previous values */
        for(var i=0;i<this.xpathLength(xml_data);i++)
        {
                var transaction = this.xpathItem(xml_data, i).parentNode.parentNode;
                var kmy_split = this.xpathItem(xml_data, i);
                var account = ''+kmy_split.getAttribute('account');

                // Date extract
                var ar  = reg.exec(''+transaction.getAttribute('postdate'));
                var num = kmy_split.getAttribute(attribute);
                num= num.replace(/\/100$/,'');
                num= parseFloat(num.replace(/\/10$/,'0'));

                columns_totals.set(account,num);
        }

        // Loop main dates
        while(date_init<date_end)
        {
            var date_init_old = new Date();
            date_init_old.setTime(date_init.valueOf());

            date_init.setMonth(date_init.getMonth()+monthstep);
            if(daystep==0)
            {
                date_init.setDate(1);
            }
            else
            {
                date_init.setDate(date_init.getDate()+daystep);
            }

            var addData = [ date_init_old ];

            // Start construcion dada here
            // Main query
            var xpath_query = '/TRANSACTIONS/TRANSACTION[@postdate>='+this.date_format(date_init_old)+' and @postdate<'+this.date_format(date_init)+']/SPLITS/SPLIT';
            xpath_query+='['+xpath_sub.join(' or ')+']';

            var xml_data = this.xpath(xpath_query);

                var columns_parcial=new Hash();

            for(var i=0;i<this.xpathLength(xml_data);i++)
            {
                var transaction = this.xpathItem(xml_data, i).parentNode.parentNode;
                var kmy_split = this.xpathItem(xml_data, i);
                var account = ''+kmy_split.getAttribute('account');

                // Date extract
                var ar  = reg.exec(''+transaction.getAttribute('postdate'));
                var num = kmy_split.getAttribute(attribute);
                num= num.replace(/\/100$/,'');
                num= parseFloat(num.replace(/\/10$/,'0'));


                // Adding column if no exists
                if(!display_subcats)
                {
                    if(columns.indexOf(kmy_split.getAttribute('account'))==-1)
                    {
                        // Searchin column name in accounts
                        var xml_column = this.xpath('/ACCOUNTS/ACCOUNT[@id=\''+kmy_split.getAttribute('account')+'\']');
                        data.addColumn('number', this.xpathItem(xml_column, 0).getAttribute('name'));
                        columns.push(kmy_split.getAttribute('account'));
                    }
                }
                columns_totals.set(account,num);
		var old=0;
		if(columns_parcial.get(account,num))
		{
			old=columns_parcial.get(account,num);
		}
                columns_parcial.set(account,num+old);
            }

            if(attribute=='total')
            {
                var cat_display= columns_totals;
            }
            else
            {
                var cat_display= columns_parcial;
            }
            // Display current categorie value
            if(!display_subcats)
            {
                var total=0;
                for(var i=0;i<columns.length;i++)
                {
                    if(cat_display.get(columns[i]))
                    {
			if(invert)
			{
                        	addData.push(-cat_display.get(columns[i])/100);
			}
			else
			{
                        	addData.push(cat_display.get(columns[i])/100);
			}
                    }
                    else
                    {
                        addData.push(0);
                    }
                }
            }
            // Display sum of all categories
            else
            {
                var total=0;
                cat_display.each(function(e) { 
                        total+=e.value;
                        });
		if(invert)
		{
                	addData.push(-total/100);
		}
		else
		{
                	addData.push(total/100);
		}
            }

            data.addRow(addData);
        }



        var div_graph = new Element('div', { style: 'width:'+this.chart_width+'; margin:auto; height:'+this.chart_height });
        html_item.appendChild(div_graph);

        var annotatedtimeline = eval('new google.visualization.'+this.graph_types[graph_type]+'(div_graph)');

        annotatedtimeline.draw(data, 
        {   
            displayLegendDots: true,
            isStacked: true,
            displayAnnotationsFilter : true,
            legendFontSize: '15px',
            titleFontsize: '15px',
            axisFontSize: '15px',
            fill:60, 
            numberFormats: '##############.##'
        });
    }
}