]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/acq/po/view_po.js
Acq: Improved invoice-linking and -viewing features in LI, PO interfaces
[working/Evergreen.git] / Open-ILS / web / js / ui / default / acq / po / view_po.js
1 dojo.require("dojo.string");
2 dojo.require('dijit.layout.ContentPane');
3 dojo.require('openils.PermaCrud');
4
5 var pcrud = new openils.PermaCrud();
6 var PO = null;
7 var liTable;
8 var poNoteTable;
9 var invoiceLinkDialogManager;
10
11 function AcqPoNoteTable() {
12     var self = this;
13
14     this.notesTbody = dojo.byId("acq-po-notes-tbody");
15     this.notesRow = this.notesTbody.removeChild(dojo.byId("acq-po-notes-row"));
16
17     dojo.byId("acq-po-notes-back-button").onclick = function() { self.hide(); };
18     dojo.byId("acq-po-view-notes").onclick = function() { self.show(); };
19
20     /* widgets' event properties are cased likeThis */
21     acqPoCreateNoteSubmit.onClick = function() {
22         if (!acqPoCreateNoteText.attr("value")) return;
23
24         /* prep new note */
25         var note = new acqpon();
26         note.vendor_public(
27             Boolean(acqPoCreateNoteVendorPublic.attr('checked'))
28         );
29         note.value(acqPoCreateNoteText.attr("value"));
30         note.purchase_order(PO.id());
31         note.isnew(true);
32
33         /* save it */
34         self.updatePoNotes(note);
35
36         /* reset fields for next use */
37         acqPoCreateNoteText.attr("value", "");
38         acqPoCreateNoteVendorPublic.attr("checked", false);
39     };
40
41     this.drawPoNote = function(note) {
42         if (note.isdeleted())
43             return;
44
45         var row = dojo.clone(this.notesRow);
46
47         nodeByName("value", row).innerHTML = note.value();
48
49         if (openils.Util.isTrue(note.vendor_public()))
50             nodeByName("vendor_public", row).innerHTML =
51                 localeStrings.VENDOR_PUBLIC;
52
53         nodeByName("delete", row).onclick = function() {
54             note.isdeleted(true);
55             self.notesTbody.removeChild(row);
56             self.updatePoNotes();
57         };
58
59         if (note.edit_time()) {
60             nodeByName("edit_time", row).innerHTML =
61                 dojo.date.locale.format(
62                     dojo.date.stamp.fromISOString(note.edit_time()),
63                     {"formatLength": "short"}
64                 );
65         }
66
67         self.notesTbody.appendChild(row);
68     };
69
70     this.drawPoNotes = function() {
71         /* sort */
72         PO.notes(
73             PO.notes().sort(
74                 function(a, b) {
75                     return (a.edit_time() < b.edit_time()) ? 1 : -1;
76                 }
77             )
78         );
79
80         /* remove old renderings of notes */
81         dojo.empty(this.notesTbody);
82
83         PO.notes().forEach(function(o) { self.drawPoNote(o); });
84     };
85
86     this.updatePoNotesCount = function() {
87         dojo.byId("acq-po-view-notes").innerHTML = PO.notes().length;
88     };
89
90     this.updatePoNotes = function(newNote) {
91         var notes = newNote ?
92             [newNote] :
93             PO.notes().filter(
94                 function(o) {
95                     if (o.ischanged() || o.isnew() || o.isdeleted())
96                         return o;
97                 }
98             );
99
100         if (notes.length < 1)
101             return;
102
103         progressDialog.show();
104
105         fieldmapper.standardRequest(
106             ["open-ils.acq", "open-ils.acq.po_note.cud.batch"], {
107                 "async": true,
108                 "params": [openils.User.authtoken, notes],
109                 "onresponse": function(r) {
110                     var resp = openils.Util.readResponse(r);
111                     if (resp) {
112                         progressDialog.update(resp);
113
114                         if (!resp.note.isdeleted()) {
115                             resp.note.isnew(false);
116                             resp.note.ischanged(false);
117                             PO.notes().push(resp.note);
118                         }
119                     }
120                 },
121                 "oncomplete": function() {
122                     if (!newNote) {
123                         /* remove the old changed notes */
124                         var list = [];
125                         PO.notes(
126                             PO.notes().filter(
127                                 function(o) {
128                                     return (!(
129                                         o.ischanged() || o.isnew() ||
130                                         o.isdeleted()
131                                     ));
132                                 }
133                             )
134                         );
135                     }
136
137                     progressDialog.hide();
138                     self.updatePoNotesCount();
139                     self.drawPoNotes();
140                 }
141             }
142         );
143     };
144
145     this.hide = function() {
146         openils.Util.hide("acq-po-notes-div");
147         liTable.show("list");
148     };
149
150     this.show = function() {
151         liTable.hide();
152         self.drawPoNotes();
153         openils.Util.show("acq-po-notes-div");
154     };
155 }
156
157 function updatePoState(po_info) {
158     var data = po_info[PO.id()];
159     if (data) {
160         for (var key in data)
161             PO[key](data[key]);
162         renderPo();
163     }
164 }
165
166 function cancellationUpdater(r) {
167     var r = openils.Util.readResponse(r);
168     if (r) {
169         if (r.po) updatePoState(r.po);
170         if (r.li) {
171             for (var id in r.li) {
172                 liTable.liCache[id].state(r.li[id].state);
173                 liTable.liCache[id].cancel_reason(r.li[id].cancel_reason);
174                 liTable.updateLiState(liTable.liCache[id]);
175             }
176         }
177         if (r.lid && liTable.copyCache) {
178             for (var id in r.lid) {
179                 if (liTable.copyCache[id]) {
180                     liTable.copyCache[id].cancel_reason(
181                         r.lid[id].cancel_reason
182                     );
183                     liTable.updateLidState(liTable.copyCache[id]);
184                 }
185             }
186         }
187     }
188 }
189
190 function makeProviderLink(node, provider) {
191     return dojo.create(
192         "a", {
193             "href": "/eg/conify/global/acq/provider/" + provider.id(),
194             "innerHTML": provider.name() + " (" + provider.code() + ")",
195         },
196         node,
197         "only"
198     );
199 }
200 function makePrepayWidget(node, prepay) {
201     if (prepay) {
202         openils.Util.addCSSClass(node, "oils-acq-po-prepay");
203         node.innerHTML = localeStrings.YES;
204     } else {
205         openils.Util.removeCSSClass(node, "oils-acq-po-prepay");
206         node.innerHTML = localeStrings.NO;
207     }
208 }
209
210 function makeCancelWidget(node, labelnode) {
211     openils.Util.hide("acq-po-choose-cancel-reason");
212
213     if (PO.cancel_reason()) {
214         labelnode.innerHTML = localeStrings.CANCEL_REASON;
215         node.innerHTML = PO.cancel_reason().description() + " (" +
216             PO.cancel_reason().label() + ")";
217     } else if (["on-order", "pending"].indexOf(PO.state()) == -1) {
218         dojo.destroy(this.oldTip);
219         labelnode.innerHTML = "";
220         node.innerHTML = "";
221     } else {
222         dojo.destroy(this.oldTip);
223         labelnode.innerHTML = localeStrings.CANCEL;
224         node.innerHTML = "";
225         if (!acqPoCancelReasonSubmit._prepared) {
226             var widget = new openils.widget.AutoFieldWidget({
227                 "fmField": "cancel_reason",
228                 "fmClass": "acqpo",
229                 "parentNode": dojo.byId("acq-po-cancel-reason"),
230                 "orgLimitPerms": ["CREATE_PURCHASE_ORDER"],
231                 "forceSync": true
232             });
233             widget.build(
234                 function(w, ww) {
235                     acqPoCancelReasonSubmit.onClick = function() {
236                         if (w.attr("value")) {
237                             if (confirm(localeStrings.PO_CANCEL_CONFIRM)) {
238                                 fieldmapper.standardRequest(
239                                     ["open-ils.acq",
240                                         "open-ils.acq.purchase_order.cancel"],
241                                     {
242                                         "params": [
243                                             openils.User.authtoken,
244                                             PO.id(), 
245                                             w.attr("value")
246                                         ],
247                                         "async": true,
248                                         "oncomplete": cancellationUpdater
249                                     }
250                                 );
251                             }
252                         }
253                     };
254                     acqPoCancelReasonSubmit._prepared = true;
255                 }
256             );
257         }
258         openils.Util.show("acq-po-choose-cancel-reason", "inline");
259     }
260 }
261
262 function prepareInvoiceFeatures() {
263     /* show the count of related invoices on the "view invoices" button */
264     fieldmapper.standardRequest(
265         ["open-ils.acq", "open-ils.acq.invoice.unified_search.atomic"], {
266             "params": [
267                 openils.User.authtoken,
268                 {"acqpo":[{"id": PO.id()}]},
269                 null,
270                 null,
271                 {"id_list": true}
272             ],
273             "async": true,
274             "oncomplete": function(r) {
275                 dojo.byId("acq-po-view-invoice-count").innerHTML =
276                     openils.Util.readResponse(r).length;
277             }
278         }
279     );
280
281     /* view invoices button */
282     dijit.byId("acq-po-view-invoice-link").onClick = function() {
283         location.href = oilsBasePath + "/acq/search/unified?so=" +
284             base64Encode({"jub":[{"purchase_order": PO.id()}]}) +
285             "&rt=invoice";
286     };
287
288     /* create invoice button */
289     dijit.byId("acq-po-create-invoice-link").onClick = function() {
290         location.href = oilsBasePath +
291             "/acq/invoice/view?create=1&attach_po=" + PO.id();
292     };
293
294     if (!invoiceLinkDialogManager)
295         invoiceLinkDialogManager = new InvoiceLinkDialogManager("po", PO);
296
297     openils.Util.show("acq-po-view-invoices", "table-row");
298 }
299
300 function renderPo() {
301     dojo.byId("acq-po-view-id").innerHTML = PO.id();
302     dojo.byId("acq-po-view-name").innerHTML = PO.name();
303     makeProviderLink(
304         dojo.byId("acq-po-view-provider"),
305         PO.provider()
306     );
307     dojo.byId("acq-po-view-total-li").innerHTML = PO.lineitem_count();
308     dojo.byId("acq-po-view-total-enc").innerHTML = PO.amount_encumbered();
309     dojo.byId("acq-po-view-total-spent").innerHTML = PO.amount_spent();
310     dojo.byId("acq-po-view-state").innerHTML = PO.state(); // TODO i18n
311     makePrepayWidget(
312         dojo.byId("acq-po-view-prepay"),
313         openils.Util.isTrue(PO.prepayment_required())
314     );
315     makeCancelWidget(
316         dojo.byId("acq-po-view-cancel-reason"),
317         dojo.byId("acq-po-cancel-label")
318     );
319     dojo.byId("acq-po-view-notes").innerHTML = PO.notes().length;
320
321     if(PO.state() == "pending") {
322         openils.Util.show("acq-po-activate", "table-row");
323         checkCouldActivatePo();
324         if (PO.lineitem_count() > 1)
325             openils.Util.show("acq-po-split");
326     }
327
328     prepareInvoiceFeatures();
329 }
330
331
332 function init() {
333     /* set up li table */
334     liTable = new AcqLiTable();
335     liTable.reset();
336     liTable.isPO = poId;
337     liTable.poUpdateCallback = updatePoState;
338
339     /* set up po notes table */
340     poNoteTable = new AcqPoNoteTable();
341
342     /* retrieve data and populate */
343     fieldmapper.standardRequest(
344         ['open-ils.acq', 'open-ils.acq.purchase_order.retrieve'],
345         {   async: true,
346             params: [openils.User.authtoken, poId, {
347                 "flesh_provider": true,
348                 "flesh_price_summary": true,
349                 "flesh_lineitem_count": true,
350                 "flesh_notes": true
351             }],
352             oncomplete: function(r) {
353                 PO = openils.Util.readResponse(r); /* save PO globally */
354                 renderPo();
355             }
356         }
357     );
358
359     fieldmapper.standardRequest(
360         ['open-ils.acq', 'open-ils.acq.lineitem.search'],
361         {   async: true,
362 params: [openils.User.authtoken, {purchase_order:poId}, {flesh_attrs:true, flesh_notes:true, flesh_cancel_reason:true}],
363             onresponse: function(r) {
364                 liTable.show('list');
365                 liTable.addLineitem(openils.Util.readResponse(r));
366             }
367         }
368     );
369 }
370
371 function checkCouldActivatePo() {
372     var d = dojo.byId("acq-po-activate-checking");
373     var a = dojo.byId("acq-po-activate-link");
374     d.innerHTML = localeStrings.PO_CHECKING;
375     var warnings = [];
376     var stops = [];
377
378     fieldmapper.standardRequest(
379         ["open-ils.acq", "open-ils.acq.purchase_order.activate.dry_run"], {
380             "params": [openils.User.authtoken, PO.id()],
381             "async": true,
382             "onresponse": function(r) {
383                 if ((r = openils.Util.readResponse(r, true /* eventOk */))) {
384                     if (typeof(r.textcode) != "undefined") {
385                         switch(r.textcode) {
386                             case "ACQ_FUND_EXCEEDS_STOP_PERCENT":
387                                 stops.push(r);
388                                 break;
389                             case "ACQ_FUND_EXCEEDS_WARN_PERCENT":
390                                 warnings.push(r);
391                                 break;
392                         }
393                     }
394                 }
395             },
396             "oncomplete": function() {
397                 /* XXX in the future, this might be tweaked to display info
398                  * about more than one stop or warning event from the ML. */
399                 if (!(warnings.length || stops.length)) {
400                     d.innerHTML = localeStrings.PO_COULD_ACTIVATE;
401                     openils.Util.show(a, "inline");
402                 } else {
403                     if (stops.length) {
404                         d.innerHTML =
405                             dojo.string.substitute(
406                                 localeStrings.PO_STOP_BLOCKS_ACTIVATION, [
407                                     stops[0].payload.fund.code(),
408                                     stops[0].payload.fund.year()
409                                 ]
410                             );
411                         openils.Util.hide(a);
412                     } else {
413                         PO._warning_hack = true;
414                         d.innerHTML =
415                             dojo.string.substitute(
416                                 localeStrings.PO_WARNING_NO_BLOCK_ACTIVATION, [
417                                     warnings[0].payload.fund.code(),
418                                     warnings[0].payload.fund.year()
419                                 ]
420                             );
421                         openils.Util.show(a, "inline");
422                     }
423                 }
424             }
425         }
426     );
427 }
428
429 function activatePo() {
430     if (openils.Util.isTrue(PO.prepayment_required())) {
431         if (!confirm(localeStrings.PREPAYMENT_REQUIRED_REMINDER))
432             return false;
433     }
434
435     if (PO._warning_hack) {
436         if (!confirm(localeStrings.PO_FUND_WARNING_CONFIRM))
437             return false;
438     }
439
440     progressDialog.show(true);
441     try {
442         fieldmapper.standardRequest(
443             ['open-ils.acq', 'open-ils.acq.purchase_order.activate'],
444             {   async: true,
445                 params: [openils.User.authtoken, PO.id()],
446                 oncomplete : function() {
447                     location.href = location.href;
448                 }
449             }
450         );
451     } catch(E) {
452         progressDialog.hide();
453     }
454 }
455
456 function splitPo() {
457     progressDialog.show(true);
458     try {
459         var list;
460         fieldmapper.standardRequest(
461             ['open-ils.acq', 'open-ils.acq.purchase_order.split_by_lineitems'],
462             {   async: true,
463                 params: [openils.User.authtoken, PO.id()],
464                 onresponse : function(r) {
465                     list = openils.Util.readResponse(r);
466                 },
467                 oncomplete : function() {
468                     progressDialog.hide();
469                     if (list) {
470                         location.href = oilsBasePath + '/eg/acq/po/search/' +
471                             list.join(",");
472                     }
473                 }
474             }
475         );
476     } catch(E) {
477         progressDialog.hide();
478         alert(E);
479     }
480 }
481
482 function updatePoName() {
483     var value = prompt('Enter new purchase order name:', PO.name()); // TODO i18n
484     if(!value || value == PO.name()) return;
485     PO.name(value);
486     pcrud.update(PO, {
487         oncomplete : function(r, cudResults) {
488             var stat = cudResults[0];
489             if(stat)
490                 dojo.byId('acq-po-view-name').innerHTML = value;
491         }
492     });
493 }
494
495 openils.Util.addOnLoad(init);