Acq: Line item batch update API method
[working/Evergreen.git] / Open-ILS / web / js / ui / default / conify / global / acq / distribution_formula.js
1 dojo.require("dojo.dnd.Container");
2 dojo.require("dojo.dnd.Source");
3 dojo.require('openils.widget.AutoGrid');
4 dojo.require('dijit.form.FilteringSelect');
5 dojo.require('openils.PermaCrud');
6 dojo.require('openils.widget.AutoFieldWidget');
7 dojo.requireLocalization('openils.conify', 'conify');
8 var localeStrings = dojo.i18n.getLocalization('openils.conify', 'conify');
9
10
11 var formCache = {};
12 var formula, entryTbody, entryTemplate, dndSource;
13 var virtualId = -1;
14 var pcrud;
15 var _collection_code_textboxes = [];
16 var _collection_code_kludge_active = false;
17
18 function gridDataLoader() {
19     fListGrid.resetStore();
20     fListGrid.showLoadProgressIndicator();
21     fieldmapper.standardRequest(
22         ["open-ils.acq", "open-ils.acq.distribution_formula.ranged.retrieve"], {
23             "async": true,
24             "params": [
25                 openils.User.authtoken,
26                 fListGrid.displayOffset,
27                 fListGrid.displayLimit
28             ],
29             "onresponse": function(r) {
30                 var form = openils.Util.readResponse(r);
31                 formCache[form.id()] = form;
32                 fListGrid.store.newItem(form.toStoreItem());
33             },
34             "oncomplete": function() {
35                 fListGrid.hideLoadProgressIndicator();
36             }
37         }
38     );
39 }
40
41 function draw() {
42
43     pcrud = new openils.PermaCrud();
44
45     if(formulaId) {
46         openils.Util.hide('formula-list-div');
47         drawFormulaSummary();
48     } else {
49
50         openils.Util.hide('formula-entry-div');
51         fListGrid.onPostCreate = function(fmObject) {
52             location.href = location.href + '/' + fmObject.id();
53         }
54
55         fListGrid.dataLoader = gridDataLoader;
56         gridDataLoader();
57     }
58 }
59
60 function cloneSelectedFormula() {
61     var item = fListGrid.getSelectedItems()[0];
62     if(!item) return;
63     var formula = new fieldmapper.acqf().fromStoreItem(item);
64     fieldmapper.standardRequest(
65         ['open-ils.acq', 'open-ils.acq.distribution_formula.clone'],
66         {
67             asnyc : true,
68             params : [
69                 openils.User.authtoken, 
70                 formula.id(), 
71                 dojo.string.substitute(localeStrings.ACQ_DISTRIB_FORMULA_NAME_CLONE, [formula.name()])
72             ],
73             oncomplete : function(r) {
74                 if(r = openils.Util.readResponse(r)) {
75                     location.href = oilsBasePath + '/conify/global/acq/distribution_formula/' + r;
76                 }
77             }
78         }
79     );
80 }
81
82 openils.Util.addOnLoad(draw);
83
84 function getItemCount(rowIndex, item) {
85     if(!item) return '';
86     var form = formCache[this.grid.store.getValue(item, "id")];
87     if(!form) return 0;
88     var count = 0;
89     dojo.forEach(form.entries(), function(e) { count = count + e.item_count(); });
90     return count;
91 }
92
93 function byName(node, name) {
94     return dojo.query('[name='+name+']', node)[0];
95 }
96
97 function drawFormulaSummary() {
98     openils.Util.show('formula-entry-div');
99
100     var entries = pcrud.search('acqdfe', {formula: formulaId}, {order_by:{acqdfe : 'position'}});
101     formula = pcrud.retrieve('acqdf', formulaId);
102     formula.entries(entries);
103
104     dojo.byId('formula_head').innerHTML = formula.name();
105     dojo.byId('formula_head').onclick = function() {
106         var name = prompt(localeStrings.ACQ_DISTRIB_FORMULA_NAME_PROMPT, formula.name());
107         if(name && name != formula.name()) {
108             formula.name(name);
109             pcrud = new openils.PermaCrud();
110             pcrud.update(formula);
111             dojo.byId('formula_head').innerHTML = name;
112         }
113     }
114
115     dojo.forEach(entries, function(entry) { addEntry(entry); } );
116 }
117
118 function addEntry(entry) {
119
120     if(!entryTbody) {
121         entryTbody = dojo.byId('formula-entry-tbody');
122         entryTemplate = entryTbody.removeChild(dojo.byId('formula-entry-tempate'));
123         dndSource = new dojo.dnd.Source(entryTbody);
124         dndSource.selectAll(); 
125         dndSource.deleteSelectedNodes();
126         dndSource.clearItems();
127     }
128
129     if(!entry) {
130         entry = new fieldmapper.acqdfe();
131         entry.formula(formulaId);
132         entry.item_count(1);
133         entry.owning_lib(openils.User.user.ws_ou());
134         entry.id(virtualId--);
135         entry.isnew(true);
136         formula.entries().push(entry);
137     }
138
139     var row = entryTbody.appendChild(entryTemplate.cloneNode(true));
140     row.setAttribute('entry', entry.id());
141     dndSource.insertNodes(false, [row]);
142     byName(row, 'delete').onclick = function() {
143         entry.isdeleted(true);
144         entryTbody.removeChild(row);
145         dndSource.sync();
146     };
147
148     dojo.forEach(
149         ['owning_lib', 'location', 'fund', 'circ_modifier', 'collection_code', 'item_count'],
150         function(field) {
151             new openils.widget.AutoFieldWidget({
152                 forceSync : true,
153                 fmField : field, 
154                 fmObject : entry,
155                 fmClass : 'acqdfe',
156                 parentNode : byName(row, field),
157                 orgDefaultsToWs : true,
158                 orgLimitPerms : ['ADMIN_ACQ_DISTRIB_FORMULA'],
159                 widgetClass : (field == 'item_count') ? 'dijit.form.NumberSpinner' : null,
160                 dijitArgs : (field == 'item_count') ? {min:1, places:0} : null
161             }).build(
162                 function(w, ww) {
163                     if (field == "collection_code") {
164                         /* kludge for glitchy textbox */
165                         _collection_code_textboxes.push(w);
166                     }
167                     dojo.connect(w, 'onChange', 
168                         function(newVal) {
169                             entry[field]( newVal );
170                             entry.ischanged(true);
171                         }
172                     )
173                 }
174             );
175         }
176     );
177
178     /* For some reason (bug) the dndSource intercepts onMouseDown events
179      * that should hit dijit textboxes in our table thingy. Other dijits
180      * (buttons, filteringselects, etc) seem not to be affected.  This
181      * workaround deals with the only textboxes we have for now: the ones
182      * for the collection_code field. */
183     if (!_collection_code_kludge_active) {
184         _collection_code_kludge_active = true;
185         var original = dojo.hitch(dndSource, dndSource.onMouseDown);
186         dndSource.onMouseDown = function(e) {
187             var hits = _collection_code_textboxes.filter(
188                 function(w) {
189                     var c = dojo.coords(w.domNode);
190                     if (e.clientX >= c.x && e.clientX < c.x + c.w) {
191                         if (e.clientY >= c.y && e.clientY < c.y + c.h) {
192                             return true;
193                         }
194                     }
195                     return false;
196                 }
197             );
198
199             if (hits.length) {
200                 hits[0].focus();
201             } else {
202                 original(e);
203             }
204         };
205     }
206 }
207
208 function saveFormula() {
209     var pos = 1;
210     var updatedEntries = [];
211     var deletedEntries = [];
212
213     // remove deleted entries from consideration for collision protection
214     for(var i = 0; i < formula.entries().length; i++) {
215         if(formula.entries()[i].isdeleted())
216             deletedEntries.push(formula.entries().splice(i--, 1)[0])
217     }
218
219     // update entry positions and create temporary collision avoidance entries
220     dojo.forEach(
221         dndSource.getAllNodes(),
222         function(node) {
223
224             var entryId = node.getAttribute('entry');
225             var entry = formula.entries().filter(function(e) {return (e.id() == entryId)})[0];
226
227             if(entry.position() != pos) {
228
229                 // update the position
230                 var changedEntry = entry.clone();
231                 changedEntry.position(pos);
232                 changedEntry.ischanged(true);
233                 updatedEntries.push(changedEntry);
234
235                 // clear the virtual ID
236                 if(changedEntry.isnew())
237                     changedEntry.id(null); 
238
239                 var oldEntry = formula.entries().filter(function(e) {return (e.position() == pos)})[0];
240
241                 if(oldEntry) {
242                     // move the entry currently in that spot temporarily into negative territory
243                     var moveMe = oldEntry.clone();
244                     moveMe.ischanged(true);
245                     moveMe.position(moveMe.position() * -1); 
246                     updatedEntries.unshift(moveMe);
247                 }
248             }
249             pos++;
250         }
251     );
252
253     // finally, for every entry that changed w/o changing position
254     // throw it on the list for update
255     dojo.forEach(
256         formula.entries(),
257         function(entry) {
258             if(entry.ischanged() && !entry.isdeleted() && !entry.isnew()) {
259                 if(updatedEntries.filter(function(e) { return (e.id() == entry.id()) }).length == 0)
260                     updatedEntries.push(entry);
261             }
262         }
263     );
264
265     updatedEntries = deletedEntries.concat(updatedEntries);
266     if(updatedEntries.length) {
267         pcrud = new openils.PermaCrud();
268         try { 
269             pcrud.apply(updatedEntries);
270         } catch(E) {
271             alert('error updating: ' + E);
272             return;
273         }
274         location.href = location.href;
275     }
276 }
277
278