Advertisement
Guest User

Untitled

a guest
Dec 1st, 2014
462
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var DateFormat = require('dateformatjs').DateFormat;
  2. var df = new DateFormat("MM/dd/yyyy");
  3. var dfW3C = new DateFormat(DateFormat.W3C);
  4. var async = require("async");
  5. var _ = require('underscore');
  6. var repCmdty = {space:"ISO4217",id:"RUB"};
  7. var safe = require('safe');
  8.  
  9. module.exports = function account(webapp) {
  10.     var app = webapp.web;
  11.     var cashapi = webapp.api;
  12.     var prefix = webapp.prefix;
  13.     var ctx = webapp.ctx;
  14.     var reportSettingsVersion = 2;
  15.  
  16.     app.get(prefix + "/reports/barflow", webapp.layout(), function (req, res, next ) {
  17.         report1(req, res, next, "barflow");
  18.     });
  19.  
  20.     app.get(prefix + "/reports/pieflow", webapp.layout(), function (req, res, next ) {
  21.         report1(req, res, next, "pieflow");
  22.     });
  23.  
  24.     function report1(req, res, next, type) {
  25.         if (!req.query || !req.query.name) {
  26.             var ct = "Income statement";
  27.             if (type == 'pieflow')
  28.                 ct = 'Pie flow chart';
  29.             else if (type == 'barflow')
  30.                 ct = 'Bar flow chart';
  31.  
  32.             res.redirect(req.url + "?name=" +  ctx.i18n(req.session.apiToken, 'cash', ct));
  33.             return;
  34.         }
  35.  
  36.         var pid = "reports-" + type + "-" + req.query.name;
  37.         var vtabs,data,reportSettings;
  38.         async.waterfall([
  39.             function (cb1) {
  40.                 async.series([
  41.                     function(cb2) {
  42.                         webapp.guessTab(req, {pid: pid, name:req.query.name, url:req.url}, cb2);
  43.                     },
  44.                     function(cb2) {
  45.                         webapp.getTabSettings(req.session.apiToken, pid, cb2);
  46.                     }
  47.                 ],
  48.                 function (err, results) {
  49.                     cb1(null, results[0], results[1]);
  50.                 });
  51.             },
  52.             function (vtabs_, reportSettings_, cb1) {              
  53.                 vtabs = vtabs_;
  54.                 reportSettings = reportSettings_;
  55.                 if (_.isEmpty(reportSettings) || !reportSettings.version || (reportSettings.version != reportSettingsVersion)){
  56.                     reportSettings = getDefaultSettings(req.query.name);       
  57.                     webapp.saveTabSettings(req.session.apiToken, pid, reportSettings, function(err){
  58.                         if (err) console.log(err);
  59.                     });
  60.                 }
  61.                 calculateGraphData(req.session.apiToken,type,reportSettings,cb1);
  62.             },
  63.             function(data_,cb1){               
  64.                 data = data_;              
  65.                 cb1()
  66.             },
  67.             function(){                                    
  68.                 data.tabs = vtabs;
  69.                 data.pmenu = {name:req.query.name,
  70.                     items:[{name:webapp.ctx.i18n(req.session.apiToken, 'cash','Page settings'),id:"settings",href:"#"}]}
  71.                 data.reportSettings = reportSettings;
  72.                
  73.                 res.render(__dirname+"/../res/views/report", data);
  74.             }],
  75.             next
  76.         );
  77.     }; 
  78.  
  79.     function calculateGraphData(token, type, params, cb){
  80.         var periods=categories=null;
  81.         var accountsTree,accKeys;
  82.         switch(type){
  83.             case 'barflow':
  84.                 periods = getPeriods(new Date(params.startDate), new Date(params.endDate));
  85.                 categories = _.map(periods, function (p) { return (p.start.getMonth()+1)+"."+p.start.getFullYear();});
  86.             break;
  87.             case 'pieflow':
  88.             break;
  89.         }
  90.         async.waterfall([
  91.             function (cb1) {
  92.                 cashapi.getAllAccounts(token, cb1);
  93.             },
  94.             function (accounts, cb1) {                 
  95.                 //here not filter accounts yet
  96.                 accKeys = _(accounts).reduce(function (memo, acc) {                
  97.                     memo[acc._id] = {name:acc.name, _id:acc._id, parentId:acc.parentId,summ:0,type:acc.type};
  98.                     if(periods)
  99.                         memo[acc._id].periods = _(periods).map(function (p) { return _.clone(p); });
  100.                     return memo;
  101.                 }, {});    
  102.                 cashapi.getTransactionsInDateRange(token,[params.startDate,params.endDate,true,false],cb1);
  103.             },
  104.             function(trns,cb1){        
  105.                 (function (cb) {               
  106.                 async.forEach(trns, function (tr,cb) {
  107.                     cashapi.getCmdtyPrice(token,tr.currency,{space:"ISO4217",id:params.reportCurrency},null,'safe',function(err,rate){
  108.                         if(err && !(err.skilap && err.skilap.subject == "UnknownRate"))
  109.                             return cb(err);
  110.                         if (!err && rate!=0)
  111.                             var irate = rate;
  112.                         _.forEach(tr.splits, function(split) {
  113.                             var acs = accKeys[split.accountId];
  114.                             if (acs) {
  115.                                 var val = split.value*irate;
  116.                                 if (params.accType!=acs.type){
  117.                                     acs.summ  = 0;
  118.                                     val = 0;
  119.                                 }
  120.                                 if (params.accType == "INCOME")
  121.                                     val *= -1;                             
  122.                                 acs.summ += val;                               
  123.                                 if (periods) {
  124.                                     var d = tr.datePosted.valueOf();
  125.                                     _.forEach(acs.periods, function (p) {
  126.                                         if (d > p.start.valueOf() && d <= p.end.valueOf()) {
  127.                                             p.summ += val;
  128.                                         }
  129.                                     });
  130.                                 }
  131.                             }
  132.                         });
  133.                         cb();
  134.                     })
  135.                 },cb);
  136.             })(safe.sure(cb1, function () {
  137.                 //collapse accounts to accLevel
  138.                 if(params.accLevel != 'All'){
  139.                     async.series([
  140.                         function(cb2){
  141.                             async.forEachSeries(_.keys(accKeys), function(key,cb3){                            
  142.                                 cashapi.getAccountInfo(token,key,['level'],function(err,res){
  143.                                     if (err) return cb3(err);                                  
  144.                                     accKeys[key].level = res.level;
  145.                                     cb3();
  146.                                 });
  147.                             },cb2);
  148.                         },
  149.                         function(cb2){                         
  150.                             do {
  151.                                 // get current ids
  152.                                 var ids = _.reduce(_.values(accKeys), function (memo, item) {
  153.                                     memo[item._id] = 1;
  154.                                     return memo;
  155.                                 }, {})
  156.                                 // remove accounts that can't be reduced now
  157.                                 // accounts that have child or with level
  158.                                 // not covered by collapse
  159.                                 _.each(accKeys, function (item, id) {
  160.                                     delete ids[item.parentId];
  161.                                     if (item.level<=params.accLevel)
  162.                                         delete ids[id];
  163.                                     if (item.type!=params.accType)
  164.                                         delete ids[id];
  165.                                 })
  166.                                 // reduce
  167.                                 _.each(ids, function (v,id) {
  168.                                     var child = accKeys[id];
  169.                                     var parent = accKeys[child.parentId];                              
  170.                                     parent.summ+=child.summ;
  171.                                     parent.expand = 1;
  172.                                     if (child.periods) {
  173.                                         for (var i = 0 ; i<child.periods.length; i++) {
  174.                                             parent.periods[i].summ+=child.periods[i].summ;
  175.                                         }                                  
  176.                                     }
  177.                                     delete accKeys[id];
  178.                                 })
  179.                             } while (_.size(ids)!=0);
  180.                             //filter by id and type
  181.                             if(_.isArray(params.accIds) && _.size(accKeys) != params.accIds.length){                               
  182.                                 accKeys = _.filter(accKeys, function(elem){
  183.                                     if (elem.expand)
  184.                                         return true;
  185.                                     return _.find(params.accIds, function(item){return _.isEqual(elem._id.toString(),item.toString())}
  186.                                 )});                                       
  187.                             }                                                  
  188.                             accKeys = _(accKeys).reduce(function (memo, acc) {                             
  189.                                 if (acc.type == params.accType || acc.expand)
  190.                                     memo[acc._id] = acc;                   
  191.                                 return memo;
  192.                             }, {});    
  193.                             cb2();
  194.                         }
  195.                     ],function(err){
  196.                         if(err) return cb1(err);
  197.                         cb1();
  198.                     });
  199.                 }
  200.                 else{                  
  201.                     //filter by id and type;
  202.                     if(_.isArray(params.accIds) && _.size(accKeys) != params.accIds.length){
  203.                         accKeys = _.filter(accKeys, function(elem){ return _.find(params.accIds, function(item){return _.isEqual(elem._id.toString(),item.toString())})});                                     
  204.                     }                      
  205.                     accKeys = _(accKeys).reduce(function (memo, acc) {                             
  206.                         if (acc.type == params.accType)
  207.                             memo[acc._id] = acc;                   
  208.                         return memo;
  209.                     }, {});    
  210.                     cb1();
  211.                 }
  212.                 }))
  213.             },
  214.             function(cb1){             
  215.                 var total = 0;
  216.                 // find important accounts (with biggest summ over entire period)
  217.                 var iacs = _(accKeys).chain().map(function (acs) { return {_id:acs._id, summ:acs.summ}})
  218.                     .sortBy(function (acs) {return acs.summ}).last(params.maxAcc)
  219.                     .reduce(function (memo, acs) { memo[acs._id]=1; return memo; }, {}).value();
  220.                 // colapse non important
  221.                 var final = _(accKeys).reduce( function (memo, accKey) {
  222.                     total += accKey.summ;
  223.                     if (_(iacs).has(accKey._id))
  224.                         memo[accKey._id] = accKey;
  225.                     else {
  226.                         var other = memo['other'];
  227.                         if (other==null) {
  228.                             accKey.name = "Other";
  229.                             accKey._id = 'other';
  230.                             memo['other'] = accKey;
  231.                         } else {
  232.                             other.summ+=accKey.summ;
  233.                             if (periods)
  234.                                 for(var i =0; i<other.periods.length; i++) {
  235.                                     other.periods[i].summ+=accKey.periods[i].summ;
  236.                                 }
  237.                         }
  238.                     }
  239.                     return memo;
  240.                 }, {});
  241.                 // transform into report form
  242.                 var report = _(final).reduce( function (memo,accKey) {
  243.                     var obj = {};
  244.                     if (periods){
  245.                         var obj = {name:accKey.name, data:_(accKey.periods).pluck('summ')}
  246.                     } else {
  247.                         obj = [accKey.name, accKey.summ];
  248.                     }
  249.                     memo.push(obj);
  250.                     return memo;
  251.                 }, [])
  252.                 cb1(null,report);
  253.  
  254.             }
  255.         ], function (err, series) {
  256.             if(err) return cb(err);
  257.             if(type == 'pieflow')
  258.                 series = {type:'pie', data: series};
  259.  
  260.             var data = {categories:JSON.stringify(categories), series:JSON.stringify(series)};
  261.             data[type] = 1;
  262.             cb(null, data);
  263.         });
  264.     }
  265.  
  266.     // split date range into periods
  267.     function getPeriods (sd, ed) {
  268.         var ret = [];
  269.         var start = new Date(sd.valueOf());
  270.         var end = new Date(sd.valueOf());
  271.         while (end.valueOf() < ed.valueOf()) {
  272.             end = new Date(start.getFullYear(),start.getMonth()+1,1);
  273.             if (ed.valueOf()<end.valueOf())
  274.                 end = ed;
  275.             ret.push({start:start, end:end, summ:0});
  276.             start = end;
  277.         }
  278.         return ret;
  279.     }
  280.  
  281.     function getDefaultSettings(reportName) {
  282.         var defaultSettings = {
  283.                 startDate:dfW3C.format(new Date(new Date().getFullYear(), 0, 1)),
  284.                 endDate:dfW3C.format(new Date(new Date().getFullYear(), 11, 31)),
  285.                 accIsVisible:1,
  286.                 accType:"EXPENSE",
  287.                 maxAcc:10,
  288.                 reportName:reportName,
  289.                 accIds:null,
  290.                 accLevel:2,
  291.                 accLevelOptions:[{name:'All'},{name:1},{name:2},{name:3},{name:4},{name:5},{name:6}],
  292.                 version: reportSettingsVersion,
  293.                 reportCurrency:repCmdty.id
  294.             };
  295.         return defaultSettings;
  296.     }  
  297. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement