LP1193095 lineitem batch actions sanity filters
authorBill Erickson <berick@esilibrary.com>
Thu, 20 Jun 2013 19:46:33 +0000 (15:46 -0400)
committerMike Rylander <mrylander@gmail.com>
Thu, 12 Sep 2013 17:33:21 +0000 (13:33 -0400)
Avoid applying the following actions to lineitems which are in a state
where each action makes no sense.

The following actions are affected.  For each, the set of states for
which a lineitem must be in for the action to proceed is listed.

create PO
    - new selector-ready order-ready approved
add to PO
    - new selector-ready order-ready approved
create invoice
    - !cancelled
add to invoice
    - !cancelled
cancel lineitem
    - !cancelled
mark selector ready
    - new
mark order ready
    - new selector-ready
mark received
    - pending-order on-order

Depending on the interface, some top-level lineitem actions may be
globally disabled.  The list of states listed above represent the bare
minimum requirements.

Signed-off-by: Bill Erickson <berick@esilibrary.com>
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/web/js/dojo/openils/acq/nls/acq.js
Open-ILS/web/js/ui/default/acq/common/li_table.js

index a202039..c7e0bd3 100644 (file)
@@ -93,5 +93,5 @@
     "INVOICE_COPY_COUNT_INFO": "Copies received on this invoice: ${0} out of ${1}.",
     "INVOICE_IDENT_COLLIDE": "There is already an invoice in the system with the given combination of 'Vendor Invoice ID' and 'Provider,' which is not allowed.",
     "NEW_INVOICE": "New Invoice",
     "INVOICE_COPY_COUNT_INFO": "Copies received on this invoice: ${0} out of ${1}.",
     "INVOICE_IDENT_COLLIDE": "There is already an invoice in the system with the given combination of 'Vendor Invoice ID' and 'Provider,' which is not allowed.",
     "NEW_INVOICE": "New Invoice",
-    "NO_LI_GENERAL" : "You have not selected any line items."
+    "NO_LI_GENERAL" : "You have not selected any (suitable) line items."
 }
 }
index 2efadf7..2bca126 100644 (file)
@@ -44,6 +44,18 @@ var fundStyles = {
     "warning": "color: #c93;"
 };
 
     "warning": "color: #c93;"
 };
 
+/**
+ * We're not using 'approved' today, but there is API support for it.
+ * I believe it's been replaced by "order-ready".
+ * LIs go new => selector-ready => order-ready/approved => pending-order => 
+ * on-order => received.  'cancelled' can pop up anywhere.
+ * Is this all of 'em?
+ */
+var li_pre_po_states = ["new", "selector-ready", "order-ready", "approved"];
+var li_post_po_states = ["pending-order", "on-order", "received"];
+// i.e. not-canceled ("cancelled") lineitems
+var li_active_states = li_pre_po_states.concat(li_post_po_states);
+
 function AcqLiTable() {
 
     var self = this;
 function AcqLiTable() {
 
     var self = this;
@@ -133,7 +145,12 @@ function AcqLiTable() {
     }
     acqLitSaveLiStateButton.onClick = function() {
         acqLitChangeLiStateDialog.hide();
     }
     acqLitSaveLiStateButton.onClick = function() {
         acqLitChangeLiStateDialog.hide();
-        self._updateLiState(acqLitChangeLiStateDialog.getValues(), acqLitChangeLiStateDialog.attr('state'));
+        var state = acqLitChangeLiStateDialog.attr('state');
+        var state_filter = ['new'];
+        if (state == 'order-ready')
+            state_filter.push('selector-ready');
+        self._updateLiState(
+            acqLitChangeLiStateDialog.getValues(), state, state_filter);
     }
 
 
     }
 
 
@@ -437,12 +454,15 @@ function AcqLiTable() {
     };
 
 
     };
 
 
-    this.getAll = function(callback, id_only) {
+    this.getAll = function(callback, id_only, state) {
         /* For some uses of the li table, we may not really know about "all"
          * the lineitems that the user thinks we know about. If we're a paged
          * picklist, for example, we only know about the lineitems we've
          * displayed, but not necessarily all the lineitems on the picklist.
          * So we reach out to pcrud to inform us.
         /* For some uses of the li table, we may not really know about "all"
          * the lineitems that the user thinks we know about. If we're a paged
          * picklist, for example, we only know about the lineitems we've
          * displayed, but not necessarily all the lineitems on the picklist.
          * So we reach out to pcrud to inform us.
+         * state: string/array.  only lineitems in one of these states are
+         * included in the final result set.  Not currently supported for
+         * paging mode.
          */
 
         var oncomplete = function(r) {
          */
 
         var oncomplete = function(r) {
@@ -454,8 +474,10 @@ function AcqLiTable() {
         };
 
         if (this.isPL) {
         };
 
         if (this.isPL) {
+            var search = {"picklist": this.isPL};
+            if (state) search.state = state;
             this.pcrud.search(
             this.pcrud.search(
-                "jub", {"picklist": this.isPL}, {
+                "jub", search, {
                     "id_list": true,    /* sic, even if id_only */
                     "async": true,
                     "oncomplete": oncomplete
                     "id_list": true,    /* sic, even if id_only */
                     "async": true,
                     "oncomplete": oncomplete
@@ -463,8 +485,10 @@ function AcqLiTable() {
             );
             return;
         } else if (this.isPO) {
             );
             return;
         } else if (this.isPO) {
+            var search = {"purchase_order": this.isPO};
+            if (state) search.state = state;
             this.pcrud.search(
             this.pcrud.search(
-                "jub", {"purchase_order": this.isPO}, {
+                "jub", search, {
                     "id_list": true,
                     "async": true,
                     "oncomplete": oncomplete
                     "id_list": true,
                     "async": true,
                     "oncomplete": oncomplete
@@ -480,7 +504,7 @@ function AcqLiTable() {
          * any special tricks to find out the "real" list of "all" lineitems
          * in this context, so we fall back to the old method.
          */
          * any special tricks to find out the "real" list of "all" lineitems
          * in this context, so we fall back to the old method.
          */
-        callback(this.getSelected(true, null, id_only));
+        callback(this.getSelected(true, null, id_only, state));
     };
 
     /** @param all If true, assume all are selected */
     };
 
     /** @param all If true, assume all are selected */
@@ -489,10 +513,12 @@ function AcqLiTable() {
         callback /* If you want a "good" idea of "all" lineitems, you must
         provide a callback that accepts an array parameter, rather than
         relying on the return value of this method itself. */,
         callback /* If you want a "good" idea of "all" lineitems, you must
         provide a callback that accepts an array parameter, rather than
         relying on the return value of this method itself. */,
-        id_only
+        id_only,
+        state 
     ) {
     ) {
+        console.log("getSelected states = " + state);
         if (all && callback)
         if (all && callback)
-            return this.getAll(callback, id_only);
+            return this.getAll(callback, id_only, filter);
 
         var indices = {};   /* use to uniqify. needed in paging situations. */
         dojo.forEach(this.selectors,
 
         var indices = {};   /* use to uniqify. needed in paging situations. */
         dojo.forEach(this.selectors,
@@ -504,6 +530,19 @@ function AcqLiTable() {
 
         var result = openils.Util.objectProperties(indices);
 
 
         var result = openils.Util.objectProperties(indices);
 
+        // caller provided a lineitem state filter.  remove IDs for lineitems 
+        // not in the selected state.
+        if (state) {
+            var trimmed = [];
+            if (!dojo.isArray(state)) state = [state];
+            dojo.forEach(result, function(liId) {
+                console.log('filter LI state ' + self.liCache[liId].state());
+                if (state.indexOf(self.liCache[liId].state()) >= 0)
+                    trimmed.push(liId);
+            });
+            result = trimmed;
+        };
+
         if (!id_only)
             result = result.map(function(liId) { return self.liCache[liId]; });
 
         if (!id_only)
             result = result.map(function(liId) { return self.liCache[liId]; });
 
@@ -2694,8 +2733,15 @@ function AcqLiTable() {
             case 'add_to_order':
                 addToPoDialog._get_li = dojo.hitch(
                     this,
             case 'add_to_order':
                 addToPoDialog._get_li = dojo.hitch(
                     this,
-                    function() { return this.getSelected(false, null, true); }
+                    function() { 
+                        return this.getSelected(
+                            false, null, true, li_pre_po_states);
+                    }
                 );
                 );
+                if (addToPoDialog._get_li().length == 0) {
+                    alert(localeStrings.NO_LI_GENERAL);
+                    return;
+                }
                 addToPoDialog.show();
                 break;
 
                 addToPoDialog.show();
                 break;
 
@@ -2759,6 +2805,7 @@ function AcqLiTable() {
                 break;
 
             case "cancel_lineitems":
                 break;
 
             case "cancel_lineitems":
+                console.log('HERE');
                 this.maybeCancelLineitems();
                 break;
 
                 this.maybeCancelLineitems();
                 break;
 
@@ -2872,7 +2919,12 @@ function AcqLiTable() {
     };
 
     this._cancelLineitems = function(reason) {
     };
 
     this._cancelLineitems = function(reason) {
-        var id_list = this.getSelected().map(function(o) { return o.id(); });
+        var id_list = this.getSelected(
+            null, null, true, li_active_states);
+        if (!id_list.length) {
+            alert(localeStrings.NO_LI_GENERAL);
+            return;
+        }
         fieldmapper.standardRequest(
             ["open-ils.acq", "open-ils.acq.lineitem.cancel.batch"], {
                 "params": [openils.User.authtoken, id_list, reason],
         fieldmapper.standardRequest(
             ["open-ils.acq", "open-ils.acq.lineitem.cancel.batch"], {
                 "params": [openils.User.authtoken, id_list, reason],
@@ -2980,8 +3032,12 @@ function AcqLiTable() {
     };
 
     this.batchCreateInvoice = function() {
     };
 
     this.batchCreateInvoice = function() {
-        var liIds = this.getSelected(false, null, true /* id_list */)
-        if (!liIds.length) return;
+        var liIds = this.getSelected(
+            false, null, true /* id_list */, li_active_states)
+        if (!liIds.length) {
+            alert(localeStrings.NO_LI_GENERAL);
+            return;
+        }
         var path = oilsBasePath + '/acq/invoice/view?create=1';
         dojo.forEach(liIds, function(li, idx) { path += '&attach_li=' + li });
         if (openils.XUL.isXUL())
         var path = oilsBasePath + '/acq/invoice/view?create=1';
         dojo.forEach(liIds, function(li, idx) { path += '&attach_li=' + li });
         if (openils.XUL.isXUL())
@@ -2991,8 +3047,12 @@ function AcqLiTable() {
     };
 
     this.batchLinkInvoice = function(create) {
     };
 
     this.batchLinkInvoice = function(create) {
-        var liIds = this.getSelected(false, null, true /* id_list */)
-        if (!liIds.length) return;
+        var liIds = this.getSelected(
+            false, null, true /* id_list */, li_active_states)
+        if (!liIds.length) {
+            alert(localeStrings.NO_LI_GENERAL);
+            return;
+        }
         if (!self.invoiceLinkDialogManager) {
             self.invoiceLinkDialogManager =
                 new InvoiceLinkDialogManager("li");
         if (!self.invoiceLinkDialogManager) {
             self.invoiceLinkDialogManager =
                 new InvoiceLinkDialogManager("li");
@@ -3002,7 +3062,9 @@ function AcqLiTable() {
     };
 
     this.receiveSelectedLineitems = function() {
     };
 
     this.receiveSelectedLineitems = function() {
-        var li_list = this.getSelected();
+        var states = li_post_po_states.filter(
+            function(s) { return s != 'received' });
+        var li_list = this.getSelected(null, null, null, states);
 
         if (!li_list.length) {
             alert(localeStrings.NO_LI_GENERAL);
 
         if (!li_list.length) {
             alert(localeStrings.NO_LI_GENERAL);
@@ -3135,15 +3197,21 @@ function AcqLiTable() {
             this.getSelected(
                 true, function(list) {
                     self._createPOFromLineitems(fields, list);
             this.getSelected(
                 true, function(list) {
                     self._createPOFromLineitems(fields, list);
-                }, /* id_list */ true
+                }, /* id_list */ true, li_pre_po_states
             );
         } else {
             );
         } else {
-            this._createPOFromLineitems(fields, this.getSelected(false, null, true /* id_list */));
+            this._createPOFromLineitems(
+                fields, this.getSelected(
+                    false, null, true /* id_list */, li_pre_po_states)
+            );
         }
     };
 
     this._createPOFromLineitems = function(fields, selected) {
         }
     };
 
     this._createPOFromLineitems = function(fields, selected) {
-        if (selected.length == 0) return;
+        if (selected.length == 0) {
+            alert(localeStrings.NO_LI_GENERAL);
+            return;
+        }
         var self = this;
 
         var po = new fieldmapper.acqpo();
         var self = this;
 
         var po = new fieldmapper.acqpo();
@@ -3347,18 +3415,22 @@ function AcqLiTable() {
         }
     };
 
         }
     };
 
-    this._updateLiState = function(values, state) {
+    this._updateLiState = function(values, state, state_filter) {
         progressDialog.show(true);
         this.getSelected(
             (values.which == 'all'),
             function(list) {
                 self._updateLiStateFromLineitems(values, state, list);
         progressDialog.show(true);
         this.getSelected(
             (values.which == 'all'),
             function(list) {
                 self._updateLiStateFromLineitems(values, state, list);
-            }
+            }, false /* id_list */, state_filter
         );
     };
 
     this._updateLiStateFromLineitems = function(values, state, selected) {
         );
     };
 
     this._updateLiStateFromLineitems = function(values, state, selected) {
-        if(!selected.length) return;
+        if(!selected.length) {
+            try { progressDialog.hide() } catch(E) {};
+            alert(localeStrings.NO_LI_GENERAL);
+            return;
+        }
         dojo.forEach(selected, function(li) {li.state(state);});
         self._updateLiList(null, selected, 0,
             // TODO consider inline updates for efficiency
         dojo.forEach(selected, function(li) {li.state(state);});
         self._updateLiList(null, selected, 0,
             // TODO consider inline updates for efficiency