diff --git a/erpnext/accounts/page/financial_analytics/financial_analytics.js b/erpnext/accounts/page/financial_analytics/financial_analytics.js index e48ccb4815..19cf3553a8 100644 --- a/erpnext/accounts/page/financial_analytics/financial_analytics.js +++ b/erpnext/accounts/page/financial_analytics/financial_analytics.js @@ -29,12 +29,26 @@ wn.pages['financial-analytics'].onload = function(wrapper) { erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ filters: [ {fieldtype:"Select", label: "PL or BS", options:["Profit and Loss", "Balance Sheet"], - filter: function(val, item, opts) { - if(val=='Profit and Loss') { - return item.is_pl_account=='Yes' || item._show; - } else { - return item.is_pl_account=='No' || item._show; - } + filter: function(val, item, opts, me) { + if(item._show) return true; + + // pl or bs + var out = (val=='Profit and Loss') ? item.is_pl_account=='Yes' : item.is_pl_account!='Yes'; + if(!out) return false; + + // show only non-zero values + if(!me.show_zero) { + for(var i=0, j=me.columns.length; i 0.001) { + return true; + } + } + } + return false; + } + return true; }}, {fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...", filter: function(val, item, opts) { @@ -51,18 +65,15 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ {fieldtype:"Button", label: "Reset Filters"} ], setup_columns: function() { - this.columns = [ + var std_columns = [ {id: "check", name: "Plot", field: "check", width: 30, - formatter: function(row, cell, value, columnDef, dataContext) { - return repl("", { - "name": dataContext.name, - "checked": dataContext.checked ? "checked" : "" - }) - }}, + formatter: this.check_formatter}, {id: "name", name: "Account", field: "name", width: 300, formatter: this.account_formatter}, + {id: "opening", name: "Opening", field: "opening", hidden: true, + formatter: this.currency_formatter} ]; + this.columns = []; var me = this; var range = this.filter_inputs.range.val(); @@ -70,27 +81,34 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ this.to_date = dateutil.user_to_str(this.filter_inputs.to_date.val()); var date_diff = dateutil.get_diff(this.to_date, this.from_date); - me.column_map = {}; + me.column_map = {}; + + var add_column = function(date) { + me.columns.push({ + id: date, + name: dateutil.str_to_user(date), + field: date, + formatter: me.currency_formatter, + width: 100 + }); + } + var build_columns = function(condition) { + // add column for each date range for(var i=0; i < date_diff; i++) { var date = dateutil.add_days(me.from_date, i); if(!condition) condition = function() { return true; } - if(condition(date)) { - me.columns.push({ - from_date: date, - id: date, - name: dateutil.str_to_user(date), - field: date, - formatter: me.currency_formatter, - width: 100 - }); - } + if(condition(date)) add_column(date); me.last_date = date; - me.column_map[date] = me.columns[me.columns.length-1]; + + if(me.columns.length) { + me.column_map[date] = me.columns[me.columns.length-1]; + } } } + // make columns for all date ranges if(range=='Daily') { build_columns(); } else if(range=='Weekly') { @@ -110,13 +128,38 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ }); } else if(range=='Yearly') { build_columns(function(date) { - if(!me.last_date) return true; + if(!me.last_date) return true; return $.map(wn.report_dump.data['Fiscal Year'], function(v) { return date==v.year_start_date ? true : null; }).length; }); } + // set label as last date of period + $.each(this.columns, function(i, col) { + col.name = me.columns[i+1] + ? dateutil.str_to_user(dateutil.add_days(me.columns[i+1].id, -1)) + : dateutil.str_to_user(me.to_date); + }); + + me.columns = std_columns.concat(me.columns); + }, + setup_filters: function() { + var me = this; + this._super(); + this.filter_inputs.pl_or_bs.change(function() { + me.filter_inputs.refresh.click(); + }); + this.wrapper.bind('make', function() { + me.wrapper.find('.show-zero').toggle(true).find('input').click(function(){ + me.refresh(); + }); + me.wrapper.on("click", ".plot-check", function() { + var checked = $(this).attr("checked"); + me.account_by_name[$(this).attr("data-id")].checked = checked ? true : false; + me.render_plot(); + }); + }); }, init_filter_values: function() { this._super(); @@ -127,7 +170,7 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ $.each(wn.report_dump.data['GL Entry'], function(i, gl) { var posting_date = dateutil.str_to_obj(gl.posting_date); - var account = me.accounts_by_name[gl.account]; + var account = me.account_by_name[gl.account]; var col = me.column_map[gl.posting_date]; if(col) { @@ -162,38 +205,27 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ }) } this.update_groups(); + this.accounts_initialized = true; + this.show_zero = $('.show-zero input:checked').length; }, add_balance: function(field, account, gl) { account[field] = flt(account[field]) + - ((account.debit_or_credit == "Debit" ? 1 : -1) * (gl.debit - gl.credit)) + ((account.debit_or_credit == "Debit" ? 1 : -1) * (flt(gl.debit) - flt(gl.credit))) }, init_account: function(d) { + // set 0 values for all columns var me = this; $.each(this.columns, function(i, col) { if (col.formatter==me.currency_formatter) { - d[col.from_date] = 0; + d[col.id] = 0; } }); - }, - init_refresh: function() { - var me = this; - $.each(this.accounts || [], function(i, account) { - account.checked && me.preset_checks.push(account.name); - }); - }, - init_plot: function() { - var me = this; - if(this.preset_checks.length) { - $.each(me.preset_checks, function(i, name) { - me.accounts_by_name[name].checked = true; - }); - } else { - $.each(this.accounts, function(i, account) { - if(!account.parent_account) { - account.checked = true; - } - }); + + // check for default graphs + if(!this.accounts_initialized && !d.parent_account) { + d.checked = true; } + }, get_plot_data: function() { var data = []; @@ -205,22 +237,35 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ data.push({ label: account.name, data: $.map(me.columns, function(col, idx) { - if(col.formatter==me.currency_formatter) - return [[idx, account[col.field]]] - }) + if(col.formatter==me.currency_formatter && !col.hidden) { + if (pl_or_bs == "Profit and Loss") { + return [[dateutil.str_to_obj(col.id).getTime(), account[col.field]], + [dateutil.user_to_obj(col.name).getTime(), account[col.field]]]; + } else { + return [[dateutil.user_to_obj(col.name).getTime(), account[col.field]]]; + } + } + }), + points: {show: true}, + lines: {show: true, fill: true}, }); + + if(pl_or_bs == "Balance Sheet") { + // prepend opening for balance sheet accounts + data[data.length-1].data = [[dateutil.str_to_obj(me.from_date).getTime(), + account.opening]].concat(data[data.length-1].data); + } } }); return data; }, - add_grid_events: function() { - this._super(); - var me = this; - this.wrapper.find('.plot-check').click(function() { - var checked = $(this).attr("checked"); - me.accounts_by_name[$(this).attr("account")].checked = checked ? true : false; - me.render_plot(); - }); + get_plot_options: function() { + return { + grid: { hoverable: true, clickable: true }, + xaxis: { mode: "time", + min: dateutil.str_to_obj(this.from_date).getTime(), + max: dateutil.str_to_obj(this.to_date).getTime() } + } } }) \ No newline at end of file diff --git a/erpnext/accounts/page/general_ledger/general_ledger.js b/erpnext/accounts/page/general_ledger/general_ledger.js index 7fdf57c517..c74b8c5024 100644 --- a/erpnext/accounts/page/general_ledger/general_ledger.js +++ b/erpnext/accounts/page/general_ledger/general_ledger.js @@ -41,11 +41,11 @@ wn.pages['general-ledger'].onload = function(wrapper) { filters: [ {fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...", filter: function(val, item, opts) { - return item.company == val || val == opts.default_value || item._show; + return item.company == val || val == opts.default_value; }}, {fieldtype:"Select", label: "Account", link:"Account", default_value: "Select Account...", filter: function(val, item, opts, me) { - if(val == opts.default_value || item._show) { + if(val == opts.default_value) { return true; } else { // true if GL Entry belongs to selected @@ -56,14 +56,14 @@ wn.pages['general-ledger'].onload = function(wrapper) { {fieldtype:"Data", label: "Voucher No", filter: function(val, item, opts) { if(!val) return true; - return (item.voucher_no && item.voucher_no.indexOf(val)!=-1) || item._show; + return (item.voucher_no && item.voucher_no.indexOf(val)!=-1); }}, {fieldtype:"Date", label: "From Date", filter: function(val, item) { - return item._show || dateutil.user_to_obj(val) <= dateutil.str_to_obj(item.posting_date); + return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date); }}, {fieldtype:"Label", label: "To"}, {fieldtype:"Date", label: "To Date", filter: function(val, item) { - return item._show || dateutil.user_to_obj(val) >= dateutil.str_to_obj(item.posting_date); + return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date); }}, {fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"}, {fieldtype:"Button", label: "Reset Filters"} @@ -85,14 +85,15 @@ wn.pages['general-ledger'].onload = function(wrapper) { // add Opening, Closing, Totals rows // if filtered by account and / or voucher var data = wn.report_dump.data["GL Entry"]; - this.make_account_by_name(); + var out = []; + + if(!this.account_by_name) + this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]); + var me = this; - var account = this.filter_inputs.account.val(); - var from_date = dateutil.user_to_obj(this.filter_inputs.from_date.val()); - var to_date = dateutil.user_to_obj(this.filter_inputs.to_date.val()); - var voucher_no = this.filter_inputs.voucher_no.val(); - var default_account = this.filter_inputs.account.get(0).opts.default_value; + var from_date = dateutil.str_to_obj(this.from_date); + var to_date = dateutil.str_to_obj(this.to_date); if(to_date < from_date) { msgprint("From Date must be before To Date"); @@ -109,8 +110,8 @@ wn.pages['general-ledger'].onload = function(wrapper) { } $.each(data, function(i, item) { - if((account!=default_account ? me.is_child_account(account, item.account) : true) && - (voucher_no ? item.voucher_no==voucher_no : true)) { + if((!me.is_default("account") ? me.is_child_account(me.account, item.account) : true) && + (me.voucher_no ? item.voucher_no==me.voucher_no : true)) { var date = dateutil.str_to_obj(item.posting_date); @@ -121,6 +122,10 @@ wn.pages['general-ledger'].onload = function(wrapper) { totals.debit += item.debit; totals.credit += item.credit; } + + if(me.apply_filters(item)) { + out.push(item); + } } }) @@ -131,21 +136,14 @@ wn.pages['general-ledger'].onload = function(wrapper) { } - if(account != default_account) { - var out = [opening].concat(data).concat([totals, closing]); + if(!me.is_default("account")) { + var out = [opening].concat(out).concat([totals, closing]); } else { - var out = data.concat([totals]); + var out = out.concat([totals]); } this.prepare_data_view(out); }, - make_account_by_name: function() { - this.account_by_name = {}; - var me = this; - $.each(wn.report_dump.data['Account'], function(i, v) { - me.account_by_name[v.name] = v; - }) - } }); } diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py index 5a38c5b1bf..dbd4b8c10b 100644 --- a/erpnext/patches/patch_list.py +++ b/erpnext/patches/patch_list.py @@ -580,4 +580,8 @@ patch_list = [ 'patch_module': 'patches.september_2012', 'patch_file': 'customer_permission_patch', }, + { + 'patch_module': 'patches.september_2012', + 'patch_file': 'add_stock_ledger_entry_index', + }, ] diff --git a/erpnext/patches/september_2012/add_stock_ledger_entry_index.py b/erpnext/patches/september_2012/add_stock_ledger_entry_index.py new file mode 100644 index 0000000000..bac9a086df --- /dev/null +++ b/erpnext/patches/september_2012/add_stock_ledger_entry_index.py @@ -0,0 +1,10 @@ +import webnotes + +def execute(): + webnotes.conn.commit() + try: + webnotes.conn.sql("""alter table `tabStock Ledger Entry` add index posting_sort_index(posting_date, posting_time, name)""")webnotes.conn.commit() + except Exception, e: + if e.args[0]!=1061: raise e + webnotes.conn.begin() + \ No newline at end of file diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py index 3c3fa4bc24..b13218014f 100644 --- a/erpnext/startup/report_data_map.py +++ b/erpnext/startup/report_data_map.py @@ -15,6 +15,10 @@ # along with this program. If not, see . from __future__ import unicode_literals + +# mappings for table dumps +# "remember to add indexes!" + data_map = { "Account": { "columns": ["name", "parent_account", "lft", "rgt", "debit_or_credit", "is_pl_account", @@ -30,7 +34,11 @@ data_map = { "columns": ["account", "posting_date", "cost_center", "debit", "credit", "is_opening", "company", "voucher_type", "voucher_no", "remarks"], "conditions": ["ifnull(is_cancelled, 'No')='No'"], - "order_by": "posting_date, account" + "order_by": "posting_date, account", + "links": { + "account": ["Account", "name"], + "company": ["Company", "name"] + } }, "Company": { "columns": ["name"], @@ -39,5 +47,29 @@ data_map = { "Fiscal Year": { "columns": ["name", "year_start_date", "adddate(adddate(year_start_date, interval 1 year), interval -1 day) as year_end_date"] + }, + "Stock Ledger Entry": { + "columns": ["posting_date", "posting_time", "item_code", "warehouse", "actual_qty as qty", + "voucher_type", "voucher_no"], + "conditions": ["ifnull(is_cancelled, 'No')='No'"], + "order_by": "posting_date, posting_time, name", + "links": { + "item_code": ["Item", "name"], + "warehouse": ["Warehouse", "name"] + }, + "force_index": "posting_sort_index" + }, + "Item": { + "columns": ["name", "if(item_name=name, '', item_name) as item_name", + "item_group", "stock_uom", "brand"], + "order_by": "name" + }, + "Item Group": { + "columns": ["name", "lft", "rgt", "parent_item_group"], + "order_by": "lft" + }, + "Warehouse": { + "columns": ["name"], + "order_by": "name" } } diff --git a/erpnext/stock/page/stock_ledger/__init__.py b/erpnext/stock/page/stock_ledger/__init__.py new file mode 100644 index 0000000000..baffc48825 --- /dev/null +++ b/erpnext/stock/page/stock_ledger/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/erpnext/stock/page/stock_ledger/stock_ledger.js b/erpnext/stock/page/stock_ledger/stock_ledger.js new file mode 100644 index 0000000000..ee97868d16 --- /dev/null +++ b/erpnext/stock/page/stock_ledger/stock_ledger.js @@ -0,0 +1,147 @@ +wn.pages['stock-ledger'].onload = function(wrapper) { + wn.ui.make_app_page({ + parent: wrapper, + title: 'Stock Ledger', + single_column: true + }); + + erpnext.stock_ledger = new wn.views.GridReport({ + title: "Stock Ledger", + page: wrapper, + parent: $(wrapper).find('.layout-main'), + appframe: wrapper.appframe, + doctypes: ["Item", "Item Group", "Warehouse", "Stock Ledger Entry"], + + setup_columns: function() { + this.columns = [ + {id: "posting_datetime", name: "Posting Date", field: "posting_datetime", width: 120, + formatter: this.date_formatter}, + {id: "item_code", name: "Item Code", field: "item_code", width: 160, + link_formatter: { + filter_input: "item_code", + open_btn: true, + doctype: '"Item"' + }}, + {id: "warehouse", name: "Warehouse", field: "warehouse", width: 100, + link_formatter: {filter_input: "warehouse"}}, + {id: "qty", name: "Qty", field: "qty", width: 100, + formatter: this.currency_formatter}, + {id: "balance", name: "Balance", field: "balance", width: 100, + formatter: this.currency_formatter}, + {id: "voucher_type", name: "Voucher Type", field: "voucher_type", width: 120}, + {id: "voucher_no", name: "Voucher No", field: "voucher_no", width: 160, + link_formatter: { + filter_input: "voucher_no", + open_btn: true, + doctype: "dataContext.voucher_type" + }}, + {id: "description", name: "Description", field: "description", width: 200, + formatter: this.text_formatter}, + ]; + }, + filters: [ + {fieldtype:"Select", label: "Warehouse", link:"Warehouse", default_value: "Select Warehouse...", + filter: function(val, item, opts) { + return item.warehouse == val || val == opts.default_value; + }}, + {fieldtype:"Select", label: "Item Code", link:"Item", default_value: "Select Item...", + filter: function(val, item, opts) { + return item.item_code == val || val == opts.default_value; + }}, + {fieldtype:"Data", label: "Voucher No", + filter: function(val, item, opts) { + if(!val) return true; + return (item.voucher_no && item.voucher_no.indexOf(val)!=-1); + }}, + {fieldtype:"Date", label: "From Date", filter: function(val, item) { + return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date); + }}, + {fieldtype:"Label", label: "To"}, + {fieldtype:"Date", label: "To Date", filter: function(val, item) { + return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date); + }}, + {fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"}, + {fieldtype:"Button", label: "Reset Filters"} + ], + init_filter_values: function() { + this.filter_inputs.warehouse.get(0).selectedIndex = 0; + this.filter_inputs.item_code.get(0).selectedIndex = 0; + this.filter_inputs.from_date.val(dateutil.str_to_user(sys_defaults.year_start_date)); + this.filter_inputs.to_date.val(dateutil.str_to_user(sys_defaults.year_end_date)); + this.filter_inputs.voucher_no.val(""); + }, + prepare_data: function() { + var me = this; + if(!this.item_by_name) + this.item_by_name = this.make_name_map(wn.report_dump.data["Item"]); + var data = wn.report_dump.data["Stock Ledger Entry"]; + var out = []; + + if(this.to_date < this.from_date) { + msgprint("From Date must be before To Date"); + return; + } + + var opening = { + item_code: "On " + dateutil.str_to_user(this.from_date), qty: 0.0, balance: 0.0, + id:"_opening", _show: true, _style: "font-weight: bold" + } + var total_in = { + item_code: "Total In", qty: 0.0, balance: 0.0, + id:"_total_in", _show: true, _style: "font-weight: bold" + } + var total_out = { + item_code: "Total Out", qty: 0.0, balance: 0.0, + id:"_total_out", _show: true, _style: "font-weight: bold" + } + + // clear balance + $.each(wn.report_dump.data["Item"], function(i, item) { item.balance = 0.0; }); + + // + for(var i=0, j=data.length; i 0) total_in.qty += sl.qty; + else total_out.qty += (-1 * sl.qty); + } + } + + if(!before_end) break; + + // apply filters + if(me.apply_filters(sl)) { + out.push(sl); + } + + // update balance + if((!me.is_default("warehouse") ? me.apply_filter(sl, "warehouse") : true)) { + sl.balance = me.item_by_name[sl.item_code].balance + sl.qty; + me.item_by_name[sl.item_code].balance = sl.balance; + } + } + + if(me.item_code != me.item_code_default && !me.voucher_no) { + var closing = { + item_code: "On " + dateutil.str_to_user(this.to_date), + balane: me.item_by_name[sl.item_code].balance, qty: 0, + id:"_closing", _show: true, _style: "font-weight: bold" + }; + var out = [opening].concat(out).concat([total_in, total_out, closing]); + } + + this.data = out; + this.prepare_data_view(out); + }, + }); +} \ No newline at end of file diff --git a/erpnext/stock/page/stock_ledger/stock_ledger.txt b/erpnext/stock/page/stock_ledger/stock_ledger.txt new file mode 100644 index 0000000000..a9460aaf05 --- /dev/null +++ b/erpnext/stock/page/stock_ledger/stock_ledger.txt @@ -0,0 +1,28 @@ +# Page, stock-ledger +[ + + # These values are common in all dictionaries + { + u'creation': '2012-09-18 14:55:15', + u'docstatus': 0, + u'modified': '2012-09-18 14:55:15', + u'modified_by': u'Administrator', + u'owner': u'Administrator' + }, + + # These values are common for all Page + { + u'doctype': u'Page', + 'module': u'Stock', + u'name': u'__common__', + 'page_name': u'stock-ledger', + 'standard': u'Yes', + 'title': u'Stock Ledger' + }, + + # Page, stock-ledger + { + u'doctype': u'Page', + u'name': u'stock-ledger' + } +] \ No newline at end of file diff --git a/public/js/all-app.js b/public/js/all-app.js index 89ce7c3d42..6c564045b9 100644 --- a/public/js/all-app.js +++ b/public/js/all-app.js @@ -392,7 +392,8 @@ return;} if(r.server_messages){r.server_messages=JSON.parse(r.server_messages) msgprint(r.server_messages);} if(r.exc){r.exc=JSON.parse(r.exc);if(r.exc instanceof Array){$.each(r.exc,function(i,v){if(v)console.log(v);})}else{console.log(r.exc);}};if(r['403']){wn.container.change_to('403');} -if(r.docs){LocalDB.sync(r.docs);}} +if(r.docs){LocalDB.sync(r.docs);} +wn.last_response=r;} wn.request.call=function(opts){wn.request.prepare(opts);var ajax_args={url:opts.url||wn.request.url,data:opts.args,type:opts.type||'POST',dataType:opts.dataType||'json',success:function(r,xhr){wn.request.cleanup(opts,r);opts.success&&opts.success(r,xhr.responseText);},error:function(xhr,textStatus){wn.request.cleanup(opts,{});show_alert('Unable to complete request: '+textStatus) opts.error&&opts.error(xhr)}};if(opts.progress_bar){var interval=null;$.extend(ajax_args,{xhr:function(){var xhr=jQuery.ajaxSettings.xhr();interval=setInterval(function(){if(xhr.readyState>2){var total=parseInt(xhr.getResponseHeader('Original-Length')||0)||parseInt(xhr.getResponseHeader('Content-Length'));var completed=parseInt(xhr.responseText.length);var percent=(100.0/total*completed).toFixed(2);opts.progress_bar.css('width',(percent<10?10:percent)+'%');}},50);wn.last_xhr=xhr;return xhr;},complete:function(){opts.progress_bar.css('width','100%');clearInterval(interval);}})} $.ajax(ajax_args);} @@ -1073,28 +1074,36 @@ me.list.run();});this.dialog.show();},add_column:function(c){var w=$('
').appendTo(this.parent);if(this.filters){this.make_filters();} -this.make_waiting();this.import_slickgrid();var me=this;this.get_data();},get_data:function(){var me=this;wn.report_dump.with_data(this.doctypes,function(){me.setup_filters();me.init_filter_values();me.refresh();},this.wrapper.find(".progress .bar"));},setup_filters:function(){var me=this;$.each(me.filter_inputs,function(i,v){var opts=v.get(0).opts;if(opts.fieldtype=="Select"&&inList(me.doctypes,opts.link)){$(v).add_options($.map(wn.report_dump.data[opts.link],function(d){return d.name;}));}});this.filter_inputs.refresh&&this.filter_inputs.refresh.click(function(){me.set_route();});this.filter_inputs.reset_filters&&this.filter_inputs.reset_filters.click(function(){me.init_filter_values();me.set_route();});},make_waiting:function(){this.waiting=$('
\ +if(missing.length){wn.call({method:"webnotes.widgets.report_dump.get_data",args:{doctypes:missing},callback:function(r){$.each(r.message,function(doctype,doctype_data){var data=[];$.each(doctype_data.data,function(i,d){var row={};$.each(doctype_data.columns,function(idx,col){row[col]=d[idx];});row.id=row.name||doctype+"-"+i +data.push(row);});wn.report_dump.data[doctype]=data;});$.each(r.message,function(doctype,doctype_data){if(doctype_data.links){$.each(wn.report_dump.data[doctype],function(row_idx,row){$.each(doctype_data.links,function(link_key,link){row[link_key]=wn.report_dump.data[link[0]][row[link_key]][link[1]];})})}});callback();},progress_bar:progress_bar})}else{callback();}}});wn.provide("wn.views");wn.views.GridReport=Class.extend({init:function(opts){this.filter_inputs={};this.preset_checks=[];$.extend(this,opts);this.wrapper=$('
').appendTo(this.parent);if(this.filters){this.make_filters();} +this.make_waiting();this.import_slickgrid();var me=this;this.get_data();},bind_show:function(){var me=this;$(this.page).bind('show',function(){wn.cur_grid_report=me;me.apply_filters_from_route();me.refresh();});},get_data:function(){var me=this;wn.report_dump.with_data(this.doctypes,function(){me.setup_filters();me.init_filter_values();me.refresh();},this.wrapper.find(".progress .bar"));},setup_filters:function(){var me=this;$.each(me.filter_inputs,function(i,v){var opts=v.get(0).opts;if(opts.fieldtype=="Select"&&inList(me.doctypes,opts.link)){$(v).add_options($.map(wn.report_dump.data[opts.link],function(d){return d.name;}));}});this.filter_inputs.refresh&&this.filter_inputs.refresh.click(function(){me.set_route();});this.filter_inputs.reset_filters&&this.filter_inputs.reset_filters.click(function(){me.init_filter_values();me.set_route();});},make_waiting:function(){this.waiting=$('
\

Loading Report...

\
\ -
').appendTo(this.wrapper);},make_grid_wrapper:function(){$('
').appendTo(this.wrapper);},make_filters:function(){var me=this;$.each(this.filters,function(i,v){v.fieldname=v.fieldname||v.label.replace(/ /g,'_').toLowerCase();var input=null;if(v.fieldtype=='Select'){input=me.appframe.add_select(v.label,v.options||[v.default_value]);}else if(v.fieldtype=='Button'){input=me.appframe.add_button(v.label);if(v.icon){$('').prependTo(input);}}else if(v.fieldtype=='Date'){input=me.appframe.add_date(v.label);}else if(v.fieldtype=='Label'){input=me.appframe.add_label(v.label);}else if(v.fieldtype=='Data'){input=me.appframe.add_data(v.label);} +if(input){input&&(input.get(0).opts=v);if(v.cssClass){input.addClass(v.cssClass);} +input.keypress(function(e){if(e.which==13){me.refresh();}})} +me.filter_inputs[v.fieldname]=input;});},load_filter_values:function(){var me=this;$.each(this.filter_inputs,function(i,f){var opts=f.get(0).opts;if(opts.fieldtype!='Button'){me[opts.fieldname]=f.val();if(opts.fieldtype=="Date"){me[opts.fieldname]=dateutil.user_to_str(me[opts.fieldname]);}else if(opts.fieldtype=="Select"){me[opts.fieldname+'_default']=opts.default_value;}}});},make_name_map:function(data,key){var map={};key=key||"name";$.each(data,function(i,v){map[v[key]]=v;}) +return map;},import_slickgrid:function(){wn.require('js/lib/slickgrid/slick.grid.css');wn.require('js/lib/slickgrid/slick-default-theme.css');wn.require('js/lib/slickgrid/jquery.event.drag.min.js');wn.require('js/lib/slickgrid/slick.core.js');wn.require('js/lib/slickgrid/slick.grid.js');wn.require('js/lib/slickgrid/slick.dataview.js');wn.dom.set_style('.slick-cell { font-size: 12px; }');},refresh:function(){this.waiting.toggle(false);if(!this.grid_wrapper) +this.make();this.setup_columns();this.apply_link_formatters();this.load_filter_values();this.prepare_data();this.render();this.render_plot();},make:function(){$('').appendTo(this.wrapper);$('
\ Print \ | \ Export \
').appendTo(this.wrapper);this.wrapper.find(".grid-report-export").click(function(){return me.export();});this.grid_wrapper=$("
").appendTo(this.wrapper);this.id=wn.dom.set_unique_id(this.grid_wrapper.get(0));var me=this;$(this.page).bind('show',function(){wn.cur_grid_report=me;me.apply_filters_from_route();me.refresh();});wn.cur_grid_report=this;this.apply_filters_from_route();},load_filters:function(callback){callback();},make_filters:function(){var me=this;$.each(this.filters,function(i,v){v.fieldname=v.fieldname||v.label.replace(/ /g,'_').toLowerCase();var input=null;if(v.fieldtype=='Select'){input=me.appframe.add_select(v.label,v.options||[v.default_value]);}else if(v.fieldtype=='Button'){input=me.appframe.add_button(v.label);if(v.icon){$('').prependTo(input);}}else if(v.fieldtype=='Date'){input=me.appframe.add_date(v.label);}else if(v.fieldtype=='Label'){input=me.appframe.add_label(v.label);}else if(v.fieldtype=='Data'){input=me.appframe.add_data(v.label);} -if(input){input&&(input.get(0).opts=v);if(v.cssClass){input.addClass(v.cssClass);} -input.keypress(function(e){if(e.which==13){me.refresh();}})} -me.filter_inputs[v.fieldname]=input;});},import_slickgrid:function(){wn.require('js/lib/slickgrid/slick.grid.css');wn.require('js/lib/slickgrid/slick-default-theme.css');wn.require('js/lib/slickgrid/jquery.event.drag.min.js');wn.require('js/lib/slickgrid/slick.core.js');wn.require('js/lib/slickgrid/slick.grid.js');wn.require('js/lib/slickgrid/slick.dataview.js');wn.dom.set_style('.slick-cell { font-size: 12px; }');},refresh:function(){this.init_refresh&&this.init_refresh();this.waiting.toggle(false);if(!this.grid_wrapper) -this.make_grid_wrapper();this.setup_columns();this.apply_link_formatters();this.prepare_data();this.init_plot&&this.init_plot();this.render();this.render_plot();},apply_filters_from_route:function(){var hash=window.location.hash;var me=this;if(hash.indexOf('/')!=-1){$.each(hash.split('/').splice(1).join('/').split('&'),function(i,f){var f=f.split("=");if(me.filter_inputs[f[0]]){me.filter_inputs[f[0]].val(decodeURIComponent(f[1]));}else{console.log("Invalid filter: "+f[0]);}});}},set_route:function(){wn.set_route(wn.container.page.page_name,$.map(this.filter_inputs,function(v){var val=v.val();var opts=v.get(0).opts;if(val&&val!=opts.default_value) + background-color: #eee; margin-top: 15px;'>").appendTo(this.wrapper);this.id=wn.dom.set_unique_id(this.grid_wrapper.get(0));$('').appendTo(this.wrapper);this.bind_show();wn.cur_grid_report=this;this.apply_filters_from_route();$(this.wrapper).trigger('make');},apply_filters_from_route:function(){var hash=window.location.hash;var me=this;if(hash.indexOf('/')!=-1){$.each(hash.split('/').splice(1).join('/').split('&'),function(i,f){var f=f.split("=");if(me.filter_inputs[f[0]]){me.filter_inputs[f[0]].val(decodeURIComponent(f[1]));}else{console.log("Invalid filter: "+f[0]);}});}},set_route:function(){wn.set_route(wn.container.page.page_name,$.map(this.filter_inputs,function(v){var val=v.val();var opts=v.get(0).opts;if(val&&val!=opts.default_value) return encodeURIComponent(opts.fieldname) -+'='+encodeURIComponent(val);}).join('&'))},render:function(){this.grid=new Slick.Grid("#"+this.id,this.dataView,this.columns,this.options);var me=this;this.dataView.onRowsChanged.subscribe(function(e,args){me.grid.invalidateRows(args.rows);me.grid.render();});this.dataView.onRowCountChanged.subscribe(function(e,args){me.grid.updateRowCount();me.grid.render();});this.add_grid_events&&this.add_grid_events();},prepare_data_view:function(items){this.dataView=new Slick.Data.DataView({inlineFilters:true});this.dataView.beginUpdate();this.dataView.setItems(items);this.dataView.setFilter(this.dataview_filter);this.dataView.endUpdate();},export:function(){var me=this;var res=[$.map(this.columns,function(v){return v.name;})].concat(this.get_view_data());wn.require("js/lib/downloadify/downloadify.min.js");wn.require("js/lib/downloadify/swfobject.js");var id=wn.dom.set_unique_id();var msgobj=msgprint('

You must have Flash 10 installed to download this file.

');Downloadify.create(id,{filename:function(){return me.title+'.csv';},data:function(){return wn.to_csv(res);},swf:'js/lib/downloadify/downloadify.swf',downloadImage:'js/lib/downloadify/download.png',onComplete:function(){msgobj.hide();},onCancel:function(){msgobj.hide();},onError:function(){msgobj.hide();},width:100,height:30,transparent:true,append:false});return false;},render_plot:function(){if(!this.get_plot_data)return;wn.require('js/lib/flot/jquery.flot.js');$.plot(this.wrapper.find('.plot').toggle(true),this.get_plot_data());},get_view_data:function(){var res=[];var col_map=$.map(this.columns,function(v){return v.field;});for(var i=0,len=this.dataView.getLength();iYou must have Flash 10 installed to download this file.

');Downloadify.create(id,{filename:function(){return me.title+'.csv';},data:function(){return wn.to_csv(res);},swf:'js/lib/downloadify/downloadify.swf',downloadImage:'js/lib/downloadify/download.png',onComplete:function(){msgobj.hide();},onCancel:function(){msgobj.hide();},onError:function(){msgobj.hide();},width:100,height:30,transparent:true,append:false});return false;},render_plot:function(){if(!this.get_plot_data)return;wn.require('js/lib/flot/jquery.flot.js');$.plot(this.wrapper.find('.plot').toggle(true),this.get_plot_data(),this.get_plot_options());this.setup_plot_hover();},setup_plot_hover:function(){var me=this;this.tooltip_id=wn.dom.set_unique_id();function showTooltip(x,y,contents){$('
'+contents+'
').css({position:'absolute',display:'none',top:y+5,left:x+5,border:'1px solid #fdd',padding:'2px','background-color':'#fee',opacity:0.80}).appendTo("body").fadeIn(200);} +this.previousPoint=null;this.wrapper.find('.plot').bind("plothover",function(event,pos,item){if(item){if(me.previousPoint!=item.dataIndex){me.previousPoint=item.dataIndex;$("#"+me.tooltip_id).remove();var x=dateutil.obj_to_user(new Date(item.datapoint[0])),y=fmt_money(item.datapoint[1]);showTooltip(item.pageX,item.pageY,item.series.label+" on "+x+" = "+y);}} +else{$("#"+me.tooltip_id).remove();me.previousPoint=null;}});},get_view_data:function(){var res=[];var col_map=$.map(this.columns,function(v){return v.field;});for(var i=0,len=this.dataView.getLength();i%(value)s
',{_style:dataContext._style||"",value:fmt_money(value)});},text_formatter:function(row,cell,value,columnDef,dataContext){return repl('%(value)s',{_style:dataContext._style||"",esc_value:cstr(value).replace(/"/g,'\"'),value:cstr(value)});},apply_link_formatters:function(){var me=this;$.each(this.columns,function(i,col){if(col.link_formatter){col.formatter=function(row,cell,value,columnDef,dataContext){if(!value)return"";if(dataContext._show){return repl('%(value)s',{_style:dataContext._style||"",value:value});} +return res;},options:{editable:false,enableColumnReorder:false},apply_filters:function(item){var filters=this.filter_inputs;if(item._show)return true;for(i in filters){if(!this.apply_filter(item,i))return false;} +if(this.custom_dataview_filter){return this.custom_dataview_filter(item);} +return true;},apply_filter:function(item,fieldname){var filter=this.filter_inputs[fieldname].get(0);if(filter.opts.filter){if(!filter.opts.filter(this[filter.opts.fieldname],item,filter.opts,this)){return false;}} +return true;},is_default:function(fieldname){return this[fieldname]==this[fieldname+"_default"];},date_formatter:function(row,cell,value,columnDef,dataContext){return dateutil.str_to_user(value);},currency_formatter:function(row,cell,value,columnDef,dataContext){return repl('
%(value)s
',{_style:dataContext._style||"",value:fmt_money(value)});},text_formatter:function(row,cell,value,columnDef,dataContext){return repl('%(value)s',{_style:dataContext._style||"",esc_value:cstr(value).replace(/"/g,'\"'),value:cstr(value)});},check_formatter:function(row,cell,value,columnDef,dataContext){return repl("",{"id":dataContext.id,"checked":dataContext.checked?"checked":""})},apply_link_formatters:function(){var me=this;$.each(this.columns,function(i,col){if(col.link_formatter){col.formatter=function(row,cell,value,columnDef,dataContext){if(!value)return"";if(dataContext._show){return repl('%(value)s',{_style:dataContext._style||"",value:value});} var link_formatter=wn.cur_grid_report.columns[cell].link_formatter;var html=repl('\ diff --git a/public/js/all-web.js b/public/js/all-web.js index 535762fef3..c8bab897f4 100644 --- a/public/js/all-web.js +++ b/public/js/all-web.js @@ -279,7 +279,8 @@ return;} if(r.server_messages){r.server_messages=JSON.parse(r.server_messages) msgprint(r.server_messages);} if(r.exc){r.exc=JSON.parse(r.exc);if(r.exc instanceof Array){$.each(r.exc,function(i,v){if(v)console.log(v);})}else{console.log(r.exc);}};if(r['403']){wn.container.change_to('403');} -if(r.docs){LocalDB.sync(r.docs);}} +if(r.docs){LocalDB.sync(r.docs);} +wn.last_response=r;} wn.request.call=function(opts){wn.request.prepare(opts);var ajax_args={url:opts.url||wn.request.url,data:opts.args,type:opts.type||'POST',dataType:opts.dataType||'json',success:function(r,xhr){wn.request.cleanup(opts,r);opts.success&&opts.success(r,xhr.responseText);},error:function(xhr,textStatus){wn.request.cleanup(opts,{});show_alert('Unable to complete request: '+textStatus) opts.error&&opts.error(xhr)}};if(opts.progress_bar){var interval=null;$.extend(ajax_args,{xhr:function(){var xhr=jQuery.ajaxSettings.xhr();interval=setInterval(function(){if(xhr.readyState>2){var total=parseInt(xhr.getResponseHeader('Original-Length')||0)||parseInt(xhr.getResponseHeader('Content-Length'));var completed=parseInt(xhr.responseText.length);var percent=(100.0/total*completed).toFixed(2);opts.progress_bar.css('width',(percent<10?10:percent)+'%');}},50);wn.last_xhr=xhr;return xhr;},complete:function(){opts.progress_bar.css('width','100%');clearInterval(interval);}})} $.ajax(ajax_args);} diff --git a/public/js/app/account_tree_grid.js b/public/js/app/account_tree_grid.js index c8dd8a5fa3..f1bf6bf180 100644 --- a/public/js/app/account_tree_grid.js +++ b/public/js/app/account_tree_grid.js @@ -75,24 +75,31 @@ erpnext.AccountTreeGrid = wn.views.GridReport.extend({ this.filter_inputs.to_date.val(dateutil.str_to_user(sys_defaults.year_end_date)); }, prepare_data: function() { - var me = this; - var data = []; - var parent_map = {}; - var data_by_name = {}; - $.each(wn.report_dump.data["Account"], function(i, v) { - var d = copy_dict(v); - me.init_account(d); + var me = this; + if(this.accounts) { + // refresh -- only initialize + $.each(this.accounts, function(i, d) { + me.init_account(d); + }) + } else { + // make accounts list + me.accounts = []; + me.parent_map = {}; + me.account_by_name = {}; - data.push(d); - data_by_name[d.name] = d; - if(d.parent_account) { - parent_map[d.name] = d.parent_account; - } - }); - this.set_indent(data, parent_map); - this.accounts = data; - this.parent_map = parent_map; - this.accounts_by_name = data_by_name; + $.each(wn.report_dump.data["Account"], function(i, v) { + var d = copy_dict(v); + + me.accounts.push(d); + me.account_by_name[d.name] = d; + if(d.parent_account) { + me.parent_map[d.name] = d.parent_account; + } + + me.init_account(d); + }); + } + this.set_indent(); this.prepare_balances(); this.prepare_data_view(this.accounts); }, @@ -122,7 +129,7 @@ erpnext.AccountTreeGrid = wn.views.GridReport.extend({ $.each(gl, function(i, v) { var posting_date = dateutil.str_to_obj(v.posting_date); - var account = me.accounts_by_name[v.account]; + var account = me.account_by_name[v.account]; me.update_balances(account, posting_date, v) }); @@ -159,16 +166,20 @@ erpnext.AccountTreeGrid = wn.views.GridReport.extend({ var me= this; $.each(this.accounts, function(i, account) { // update groups - var parent = me.parent_map[account.name]; - while(parent) { - parent_account = me.accounts_by_name[parent]; - $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_account[col.field] += account[col.field]; - } - }); - parent = me.parent_map[parent]; - } + if(account.rgt - account.lft == 1) { + var parent = me.parent_map[account.name]; + while(parent) { + parent_account = me.account_by_name[parent]; + $.each(me.columns, function(c, col) { + if (col.formatter == me.currency_formatter) { + parent_account[col.field] = + flt(parent_account[col.field]) + + flt(account[col.field]); + } + }); + parent = me.parent_map[parent]; + } + } }); }, @@ -192,14 +203,15 @@ erpnext.AccountTreeGrid = wn.views.GridReport.extend({ return; } }, - set_indent: function(data, parent_map) { - $.each(data, function(i, d) { + set_indent: function() { + var me = this; + $.each(this.accounts, function(i, d) { var indent = 0; - var parent = parent_map[d.name]; + var parent = me.parent_map[d.name]; if(parent) { while(parent) { indent++; - parent = parent_map[parent]; + parent = me.parent_map[parent]; } } d.indent = indent; @@ -248,7 +260,7 @@ erpnext.AccountTreeGrid = wn.views.GridReport.extend({ if (item.parent_account) { var parent = item.parent_account; while (parent) { - if (wn.cur_grid_report.accounts_by_name[parent]._collapsed) { + if (wn.cur_grid_report.account_by_name[parent]._collapsed) { return false; } parent = wn.cur_grid_report.parent_map[parent];