LP#1378169: make context OU selector on funds page sticky
[Evergreen.git] / Open-ILS / web / js / ui / default / acq / financial / list_funds.js
1 dojo.require("dijit.Dialog");
2 dojo.require("dijit.form.FilteringSelect");
3 dojo.require('dijit.form.Button');
4 dojo.require('dijit.TooltipDialog');
5 dojo.require('dijit.form.DropDownButton');
6 dojo.require('dijit.form.CheckBox');
7 dojo.require('dojox.grid.DataGrid');
8 dojo.require('dojo.data.ItemFileWriteStore');
9 dojo.require('openils.widget.OrgUnitFilteringSelect');
10 dojo.require('openils.acq.CurrencyType');
11 dojo.require('openils.Event');
12 dojo.require('openils.Util');
13 dojo.require('openils.User');
14 dojo.require('openils.CGI');
15 dojo.require('openils.PermaCrud');
16 dojo.require('openils.widget.AutoGrid');
17 dojo.require('openils.widget.ProgressDialog');
18 dojo.require('fieldmapper.OrgUtils');
19 dojo.requireLocalization('openils.acq', 'acq');
20 var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq');
21
22 dojo.require('openils.XUL');
23 var xulStorage = openils.XUL.localStorage();
24 var storekey = 'eg.acq.fund.list.context_ou_selector';
25
26 var contextOrg;
27 var rolloverResponses;
28 var rolloverMode = false;
29 var fundFleshFields = [
30     'spent_balance', 
31     'combined_balance', 
32     'spent_total', 
33     'encumbrance_total', 
34     'debit_total', 
35     'allocation_total'
36 ];
37
38 var adminPermOrgs = [];
39 var cachedFunds = [];
40
41 function initPage() {
42     contextOrg = xulStorage.getItem(storekey) || openils.User.user.ws_ou();
43
44     /* Reveal controls for rollover without money if org units say ok.
45      * Actual ability to do the operation is controlled in the database, of
46      * course. */
47     var ouSettings = fieldmapper.aou.fetchOrgSettingBatch(
48         openils.User.user.ws_ou(), ["acq.fund.allow_rollover_without_money"]
49     );
50     if (
51         ouSettings["acq.fund.allow_rollover_without_money"] &&
52         ouSettings["acq.fund.allow_rollover_without_money"].value
53     ) {
54         dojo.query(".encumb_only").forEach(
55             function(o) { openils.Util.show(o, "table-row"); }
56         );
57     }
58
59     var connect = function() {
60         dojo.connect(contextOrgSelector, 'onChange',
61             function() {
62                 contextOrg = this.attr('value');
63                 xulStorage.setItem(storekey, contextOrg);
64                 dojo.byId('oils-acq-rollover-ctxt-org').innerHTML = 
65                     fieldmapper.aou.findOrgUnit(contextOrg).shortname();
66                 rolloverMode = false;
67                 gridDataLoader();
68             }
69         );
70     };
71
72     dojo.connect(refreshButton, 'onClick', 
73         function() { rolloverMode = false; gridDataLoader(); });
74
75     new openils.User().buildPermOrgSelector(
76         ['ADMIN_ACQ_FUND', 'VIEW_FUND'], 
77         contextOrgSelector, contextOrg, connect);
78
79     dojo.byId('oils-acq-rollover-ctxt-org').innerHTML = 
80         fieldmapper.aou.findOrgUnit(contextOrg).shortname();
81
82     loadYearSelector();
83     lfGrid.onItemReceived = function(item) {cachedFunds.push(item)};
84
85     new openils.User().getPermOrgList(
86         'ADMIN_ACQ_FUND',
87         function(list) {
88             adminPermOrgs = list;
89             loadFundGrid(
90                 new openils.CGI().param('year') 
91                     || new Date().getFullYear().toString());
92         },
93         true, true
94     );
95 }
96
97 function gridDataLoader() {
98     lfGrid.resetStore();
99     if(rolloverMode) {
100         var offset = lfGrid.displayOffset;
101         for(var i = offset; i < (offset + lfGrid.displayLimit - 1); i++) {
102             var fund = rolloverResponses[i];
103             if(!fund) break;
104             lfGrid.store.newItem(fieldmapper.acqf.toStoreItem(fund));
105         }
106     } else {
107         loadFundGrid();
108     }
109 }
110
111 function getBalanceInfo(rowIdx, item) {
112     if (!item) return '';
113     var fundId = this.grid.store.getValue(item, 'id');
114     var fund = cachedFunds.filter(function(f) { return f.id() == fundId })[0];
115     var cb = fund.combined_balance();
116     return cb ? cb.amount() : '0';
117 }
118
119 function loadFundGrid(year) {
120     openils.Util.hide('acq-fund-list-rollover-summary');
121     year = year || fundFilterYearSelect.attr('value');
122     cachedFunds = [];
123
124     var order_by = [{'class' : 'acqf', field : 'name'}];
125
126     if (adminPermOrgs.length) {
127         // sort funds I can edit to the front
128         order_by.unshift({   
129             'class' : 'acqf',
130             field : 'org',
131             compare : {'in' : adminPermOrgs},
132             direction : 'desc'
133         });
134     }
135
136     lfGrid.loadAll(
137         {   
138             flesh : 1,  
139             flesh_fields : {acqf : fundFleshFields},
140             order_by : order_by,
141         }, {   
142             year : year, 
143             org : fieldmapper.aou.descendantNodeList(contextOrg, true) 
144         } 
145     );
146 }
147
148 function loadYearSelector() {
149
150     fieldmapper.standardRequest(
151         ['open-ils.acq', 'open-ils.acq.fund.org.years.retrieve'],
152         {   async : true,
153             params : [openils.User.authtoken, {}, {limit_perm : 'VIEW_FUND'}],
154             oncomplete : function(r) {
155
156                 var yearList = openils.Util.readResponse(r);
157                 if(!yearList) return;
158                 yearList = yearList.map(function(year){return {year:year+''};}); // dojo wants strings
159
160                 var yearStore = {identifier:'year', name:'year', items:yearList};
161                 yearStore.items = yearStore.items.sort().reverse();
162                 fundFilterYearSelect.store = new dojo.data.ItemFileWriteStore({data:yearStore});
163
164                 // default to this year
165                 fundFilterYearSelect.setValue(new Date().getFullYear().toString());
166
167                 dojo.connect(
168                     fundFilterYearSelect, 
169                     'onChange', 
170                     function() { 
171                         rolloverMode = false;
172                         gridDataLoader();
173                     }
174                 );
175             }
176         }
177     );
178 }
179
180 function performRollover(args) {
181
182     rolloverMode = true;
183     progressDialog.show(true, "Processing...");
184     rolloverResponses = [];
185
186     var method = 'open-ils.acq.fiscal_rollover';
187
188     if(args.rollover[0] == 'on') {
189         method += '.combined';
190     } else {
191         method += '.propagate';
192     }
193         
194     var dryRun = args.dry_run[0] == 'on';
195     if(dryRun) method += '.dry_run';
196
197     var encumbOnly = args.encumb_only[0] == 'on';
198
199     var count = 0;
200     var amount_rolled = 0;
201     var year = fundFilterYearSelect.attr('value'); // TODO alternate selector?
202     
203     fieldmapper.standardRequest(
204         ['open-ils.acq', method],
205         {
206             async : true,
207
208             params : [
209                 openils.User.authtoken, 
210                 year,
211                 contextOrg,
212                 (args.child_orgs[0] == 'on'),
213                 { encumb_only : encumbOnly }
214             ],
215
216             onresponse : function(r) {
217                 var resp = openils.Util.readResponse(r);
218                 rolloverResponses.push(resp.fund);
219                 count += 1;
220                 amount_rolled += Number(resp.rollover_amount);
221             }, 
222
223             oncomplete : function() {
224                 
225                 var nextYear = Number(year) + 1;
226                 rolloverResponses = rolloverResponses.sort(
227                     function(a, b) {
228                         if(a.code() > b.code())
229                             return 1;
230                         return -1;
231                     }
232                 )
233
234                 // add the new, rolled funds to the cache.  Note that in dry-run 
235                 // mode, these are ephemeral and no longer exist on the server.
236                 cachedFunds = cachedFunds.concat(rolloverResponses);
237
238                 dojo.byId('acq-fund-list-rollover-summary-header').innerHTML = 
239                     dojo.string.substitute(
240                         localeStrings.FUND_LIST_ROLLOVER_SUMMARY,
241                         [nextYear]
242                     );
243
244                 dojo.byId('acq-fund-list-rollover-summary-funds').innerHTML = 
245                     dojo.string.substitute(
246                         localeStrings.FUND_LIST_ROLLOVER_SUMMARY_FUNDS,
247                         [nextYear, '<b>' + count + '</b>']
248                     );
249
250                 dojo.byId('acq-fund-list-rollover-summary-rollover-amount').innerHTML = 
251                     dojo.string.substitute(
252                         localeStrings.FUND_LIST_ROLLOVER_SUMMARY_ROLLOVER_AMOUNT,
253                         [nextYear, '<b>' + amount_rolled + '</b>']
254                     );
255
256                 if(!dryRun) {
257                     openils.Util.hide('acq-fund-list-rollover-summary-dry-run');
258                     
259                     // add the new year to the year selector if it's not already there
260                     fundFilterYearSelect.store.fetch({
261                         query : {year : ''+nextYear}, 
262                         onComplete:
263                             function(list) {
264                                 if(list && list.length > 0) return;
265                                 fundFilterYearSelect.store.newItem({year : nextYear});
266                             }
267                     });
268                 }
269
270                 openils.Util.show('acq-fund-list-rollover-summary');
271                 progressDialog.hide();
272                 gridDataLoader();
273             }
274         }
275     );
276 }
277
278 openils.Util.addOnLoad(initPage);