From 76d2e15b02e8c65659408e82c3ddfe7744ca24cc Mon Sep 17 00:00:00 2001 From: Lebbeous Fogle-Weekley Date: Tue, 26 Feb 2013 14:28:40 -0500 Subject: [PATCH] Acq: several interface improvements Several usability improvements throughout Acq, including: * A logical re-ordering of the main "actions" dropdown in several Acq interfaces (selection lists, purchase orders, acq search results, MARC federated search interface, etc). * "Actions" dropdown also has its options enabled/disabled depending what interface you're seeing it through, and redundant entries are removed from the per-lineitem secondary dropdown. * Add to Purchase Order dialog added to "actions" dropdown * Middle layer support for adding many line items to a PO at once * Create/add to Purchase Order operations can no longer steal line items from current POs * Create invoice from / link to invoice now work in new tab * Receive/unreceive now by selected lineitem instead of whole PO * Claim policy application works more simply now * Invoices interface auto-populates "# Invoiced" column with number of invoicable copies, and copies the "billed cost" column to the "amount paid" column if the latter doesn't have anything in it yet. * You can now only cancel specific lineitems when they're actually on a PO and have the state of 'on-order'. * Avoid double-activation of POs at UI level * Disable invoice and cancel options for whole pending POs * Disable zero-copy checkbox for activated POs * Disable new misc charges (acq.invoice_item) for activated POs Signed-off-by: Lebbeous Fogle-Weekley Signed-off-by: Bill Erickson --- Open-ILS/examples/fm_IDL.xml | 2 +- .../lib/OpenILS/Application/Acq/Order.pm | 169 +++++++++++++-- .../src/templates/acq/common/add_to_po.tt2 | 57 +++++ .../src/templates/acq/common/li_table.tt2 | 70 ++++--- .../src/templates/acq/invoice/receive.tt2 | 2 +- Open-ILS/src/templates/acq/invoice/view.tt2 | 8 +- .../src/templates/acq/lineitem/related.tt2 | 15 +- Open-ILS/src/templates/acq/po/item_table.tt2 | 2 +- Open-ILS/src/templates/acq/po/view.tt2 | 8 +- .../global/acq/distribution_formula.tt2 | 2 +- .../templates/conify/global/acq/provider.tt2 | 2 +- Open-ILS/web/css/skin/default/acq.css | 2 + Open-ILS/web/js/dojo/openils/acq/nls/acq.js | 4 +- .../js/ui/default/acq/common/inv_dialog.js | 13 +- .../web/js/ui/default/acq/common/li_table.js | 198 ++++++++++-------- .../web/js/ui/default/acq/invoice/view.js | 27 ++- .../web/js/ui/default/acq/lineitem/related.js | 45 +--- .../js/ui/default/acq/picklist/bib_search.js | 1 + .../js/ui/default/acq/picklist/from_bib.js | 3 + .../web/js/ui/default/acq/picklist/view.js | 2 + Open-ILS/web/js/ui/default/acq/po/search.js | 1 + Open-ILS/web/js/ui/default/acq/po/view_po.js | 58 +++-- .../web/js/ui/default/acq/search/unified.js | 5 +- .../acq_po_interface_improvements.txt | 23 ++ 24 files changed, 493 insertions(+), 226 deletions(-) create mode 100644 Open-ILS/src/templates/acq/common/add_to_po.tt2 create mode 100644 docs/RELEASE_NOTES_NEXT/acq_po_interface_improvements.txt diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 75f0e328fc..1380f85c17 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -7970,7 +7970,7 @@ SELECT usr, - + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm index a86d4e6d6b..ca49a79c4b 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm @@ -580,6 +580,8 @@ sub receive_lineitem { my($mgr, $li_id, $skip_complete_check) = @_; my $li = $mgr->editor->retrieve_acq_lineitem($li_id) or return 0; + return 0 unless $li->state eq 'on-order' or $li->state eq 'cancelled'; # sic + my $lid_ids = $mgr->editor->search_acq_lineitem_detail( {lineitem => $li_id, recv_time => undef}, {idlist => 1}); @@ -1781,6 +1783,14 @@ sub create_purchase_order_api { {flesh => 1, flesh_fields => {jub => ['attributes']}} ]) or return $e->die_event; + return $e->die_event( + new OpenILS::Event( + "BAD_PARAMS", payload => $li, + note => "acq.lineitem #" . $li->id . + ": purchase_order #" . $li->purchase_order + ) + ) if $li->purchase_order; + $li->provider($po->provider); $li->purchase_order($po->id); $li->state('pending-order'); @@ -2145,6 +2155,56 @@ sub receive_lineitem_api { } +__PACKAGE__->register_method( + method => 'receive_lineitem_batch_api', + api_name => 'open-ils.acq.lineitem.receive.batch', + signature => { + desc => 'Mark lineitems as received', + params => [ + {desc => 'Authentication token', type => 'string'}, + {desc => 'lineitem ID list', type => 'array'} + ], + return => {desc => + q/On success, stream of objects describing changes to LIs and + possibly PO; onerror, Event. Any event, even after lots of other + objects, should mean general failure of whole batch operation./ + } + } +); + +sub receive_lineitem_batch_api { + my ($self, $conn, $auth, $li_idlist) = @_; + + return unless ref $li_idlist eq 'ARRAY' and @$li_idlist; + + my $e = new_editor(xact => 1, authtoken => $auth); + return $e->die_event unless $e->checkauth; + + my $mgr = new OpenILS::Application::Acq::BatchManager( + editor => $e, conn => $conn + ); + + for my $li_id (map { int $_ } @$li_idlist) { + my $li = $e->retrieve_acq_lineitem([ + $li_id, { + flesh => 1, + flesh_fields => { jub => ['purchase_order'] } + } + ]) or return $e->die_event; + + return $e->die_event unless $e->allowed( + 'RECEIVE_PURCHASE_ORDER', $li->purchase_order->ordering_agency + ); + + receive_lineitem($mgr, $li_id) or return $e->die_event; + $mgr->respond; + } + + $e->commit or return $e->die_event; + $mgr->respond_complete; + $mgr->run_post_response_hooks; +} + __PACKAGE__->register_method( method => 'rollback_receive_po_api', api_name => 'open-ils.acq.purchase_order.receive.rollback' @@ -2281,6 +2341,65 @@ sub rollback_receive_lineitem_api { $e->commit and return $result or return $e->die_event; } +__PACKAGE__->register_method( + method => 'rollback_receive_lineitem_batch_api', + api_name => 'open-ils.acq.lineitem.receive.rollback.batch', + signature => { + desc => 'Mark a list of lineitems as Un-received', + params => [ + {desc => 'Authentication token', type => 'string'}, + {desc => 'lineitem ID list', type => 'array'} + ], + return => {desc => + q/on success, a stream of objects describing changes to LI and + possibly PO; on error, Event. Any event means all previously + returned objects indicate changes that didn't really happen./ + } + } +); + +sub rollback_receive_lineitem_batch_api { + my ($self, $conn, $auth, $li_idlist) = @_; + + return unless ref $li_idlist eq 'ARRAY' and @$li_idlist; + + my $e = new_editor(xact => 1, authtoken => $auth); + return $e->die_event unless $e->checkauth; + + my $mgr = new OpenILS::Application::Acq::BatchManager( + editor => $e, conn => $conn + ); + + for my $li_id (map { int $_ } @$li_idlist) { + my $li = $e->retrieve_acq_lineitem([ + $li_id, { + "flesh" => 1, + "flesh_fields" => {"jub" => ["purchase_order"]} + } + ]); + + my $po = $li->purchase_order; + + return $e->die_event unless + $e->allowed('RECEIVE_PURCHASE_ORDER', $po->ordering_agency); + + $li = rollback_receive_lineitem($mgr, $li_id) or return $e->die_event; + + my $result = {"li" => {$li->id => {"state" => $li->state}}}; + if ($po->state eq "received") { # should happen first time, not after + $po->state("on-order"); + $po = update_purchase_order($mgr, $po) or return $e->die_event; + } + $result->{"po"} = describe_affected_po($e, $po); + + $mgr->respond(%$result); + } + + $e->commit or return $e->die_event; + $mgr->respond_complete; + $mgr->run_post_response_hooks; +} + __PACKAGE__->register_method( method => 'set_lineitem_price_api', @@ -2887,16 +3006,12 @@ sub cancel_lineitem { # Depending on context, this may not warrant an event. return -1 if $li->state eq "cancelled"; - # But this always does. + # But this always does. Note that this used to be looser, but you can + # no longer cancel lineitems that lack a PO or that are in "pending-order" + # state (you could in the past). return new OpenILS::Event( "ACQ_NOT_CANCELABLE", "note" => "lineitem $li_id" - ) unless ( - (! $li->purchase_order) or ( - $li->purchase_order and ( - $li->state eq "on-order" or $li->state eq "pending-order" - ) - ) - ); + ) unless $li->purchase_order and $li->state eq "on-order"; $li->state("cancelled"); $li->cancel_reason($cancel_reason->id); @@ -3517,7 +3632,7 @@ __PACKAGE__->register_method( params => [ {desc => 'Authentication token', type => 'string'}, {desc => 'The purchase order id', type => 'number'}, - {desc => 'The lineitem ID', type => 'number'}, + {desc => 'The lineitem ID (or an array of them)', type => 'mixed'}, ], return => {desc => 'Streams a total versus completed counts object, event on error'} } @@ -3534,9 +3649,6 @@ sub add_li_to_po { my $po = $e->retrieve_acq_purchase_order($po_id) or return $e->die_event; - my $li = $e->retrieve_acq_lineitem($li_id) - or return $e->die_event; - return $e->die_event unless $e->allowed('CREATE_PURCHASE_ORDER', $po->ordering_agency); @@ -3545,16 +3657,33 @@ sub add_li_to_po { return {success => 0, po => $po, error => 'bad-po-state'}; } - unless ($li->state =~ /new|order-ready|pending-order/) { - $e->rollback; - return {success => 0, li => $li, error => 'bad-li-state'}; + my $lis; + + if (ref $li_id eq "ARRAY") { + $li_id = [ map { int($_) } @$li_id ]; + return $e->die_event(new OpenILS::Event("BAD_PARAMS")) unless @$li_id; + + $lis = $e->search_acq_lineitem({id => $li_id}) + or return $e->die_event; + } else { + my $li = $e->retrieve_acq_lineitem(int($li_id)) + or return $e->die_event; + $lis = [$li]; + } + + foreach my $li (@$lis) { + if ($li->state !~ /new|order-ready|pending-order/ or + $li->purchase_order) { + $e->rollback; + return {success => 0, li => $li, error => 'bad-li-state'}; + } + + $li->provider($po->provider); + $li->purchase_order($po_id); + $li->state('pending-order'); + update_lineitem($mgr, $li) or return $e->die_event; } - $li->provider($po->provider); - $li->purchase_order($po_id); - $li->state('pending-order'); - update_lineitem($mgr, $li) or return $e->die_event; - $e->commit; return {success => 1}; } diff --git a/Open-ILS/src/templates/acq/common/add_to_po.tt2 b/Open-ILS/src/templates/acq/common/add_to_po.tt2 new file mode 100644 index 0000000000..370bd2893d --- /dev/null +++ b/Open-ILS/src/templates/acq/common/add_to_po.tt2 @@ -0,0 +1,57 @@ +
+ + + + + + + + + + +
+ + +
+ [% l('Save') %] +
+
diff --git a/Open-ILS/src/templates/acq/common/li_table.tt2 b/Open-ILS/src/templates/acq/common/li_table.tt2 index 8e1c20933a..064ff52c3c 100644 --- a/Open-ILS/src/templates/acq/common/li_table.tt2 +++ b/Open-ILS/src/templates/acq/common/li_table.tt2 @@ -5,7 +5,7 @@
- + [% INCLUDE "acq/common/info.tt2" which = "Lit" %] - + [% INCLUDE "acq/common/notes.tt2" which = "Lit" %] @@ -276,7 +283,7 @@ [% l('Owning Branch') %] - [% l('Shelving Location') %] + [% l('Copy Location') %] [% l('Collection Code') %] [% l('Fund') %] [% l('Circ Modifier') %] @@ -303,7 +310,7 @@ [% l('Owning Branch') %] - [% l('Shelving Location') %] + [% l('Copy Location') %] [% l('Collection Code') %] [% l('Fund') %] [% l('Circ Modifier') %] @@ -356,7 +363,7 @@ [% l('Owning Branch') %] - [% l('Shelving Location') %] + [% l('Copy Location') %] [% l('Circ Modifier') %] [% l('Callnumber') %] [% l('Barcode') %] @@ -379,6 +386,7 @@
[% INCLUDE "acq/common/inv_dialog.tt2" which = "li" %]
+ [% INCLUDE "acq/common/add_to_po.tt2" %]
@@ -418,11 +426,11 @@ - [% l('All Lineitems') %] + [% l('All Line Items') %] - [% l('Selected Lineitems') %] + [% l('Selected Line Items') %] diff --git a/Open-ILS/src/templates/acq/invoice/receive.tt2 b/Open-ILS/src/templates/acq/invoice/receive.tt2 index 1a964a6e2a..80756cf2f3 100644 --- a/Open-ILS/src/templates/acq/invoice/receive.tt2 +++ b/Open-ILS/src/templates/acq/invoice/receive.tt2 @@ -39,7 +39,7 @@ /> [% l('Owning Branch') %] - [% l('Shelving Location') %] + [% l('Copy Location') %] [% l('Collection Code') %] [% l('Fund') %] [% l('Circ Modifier') %] diff --git a/Open-ILS/src/templates/acq/invoice/view.tt2 b/Open-ILS/src/templates/acq/invoice/view.tt2 index 3871c64390..678eec5a9a 100644 --- a/Open-ILS/src/templates/acq/invoice/view.tt2 +++ b/Open-ILS/src/templates/acq/invoice/view.tt2 @@ -73,9 +73,9 @@ [% l('Title Details') %] - [% l('# Invoiced / # Paid') %] + [% l('# Invoiced / # Paid') %] [% l('Billed') %] - [% l('Per Copy') %] + [% l('Per Copy') %] [% l('Paid') %] [% l('Detach') %] @@ -103,11 +103,11 @@ - + [% l('Charge Type') %] [% l('Fund') %] - [% l('Title/Description') %] + [% l('Title / Description') %] [% l('Billed') %] [% l('Paid') %] diff --git a/Open-ILS/src/templates/acq/lineitem/related.tt2 b/Open-ILS/src/templates/acq/lineitem/related.tt2 index fe2f527414..337a64f752 100644 --- a/Open-ILS/src/templates/acq/lineitem/related.tt2 +++ b/Open-ILS/src/templates/acq/lineitem/related.tt2 @@ -49,23 +49,12 @@ [% INCLUDE "acq/common/info.tt2" which = "Related" %] [% INCLUDE "acq/common/li_table.tt2" %] + [% END %] diff --git a/Open-ILS/src/templates/acq/po/item_table.tt2 b/Open-ILS/src/templates/acq/po/item_table.tt2 index 80497c5b87..be61c8e208 100644 --- a/Open-ILS/src/templates/acq/po/item_table.tt2 +++ b/Open-ILS/src/templates/acq/po/item_table.tt2 @@ -27,7 +27,7 @@ -
+ diff --git a/Open-ILS/src/templates/acq/po/view.tt2 b/Open-ILS/src/templates/acq/po/view.tt2 index 2bc08e6c76..143a9d2c31 100644 --- a/Open-ILS/src/templates/acq/po/view.tt2 +++ b/Open-ILS/src/templates/acq/po/view.tt2 @@ -21,7 +21,7 @@ [% l('Activatable?') %] - + @@ -54,7 +54,7 @@ [% l('Total Encumbered') %] [% l('$[_1]', '') %] - [% l('Invoicing') %] + [% l('Invoicing') %]
- [% l('Allow activation with
zero-copy lineitems') %] - + [% l('Allow activation with
zero-copy lineitems') %] + diff --git a/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2 b/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2 index e3dfd1ac90..d80e29e157 100644 --- a/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2 +++ b/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2 @@ -49,7 +49,7 @@ [% l('Owning Library') %] - [% l('Shelving Location') %] + [% l('Copy Location') %] [% l('Item Count') %] diff --git a/Open-ILS/src/templates/conify/global/acq/provider.tt2 b/Open-ILS/src/templates/conify/global/acq/provider.tt2 index 7040320a47..1eeafab5cd 100644 --- a/Open-ILS/src/templates/conify/global/acq/provider.tt2 +++ b/Open-ILS/src/templates/conify/global/acq/provider.tt2 @@ -153,7 +153,7 @@ - + diff --git a/Open-ILS/web/css/skin/default/acq.css b/Open-ILS/web/css/skin/default/acq.css index e881e26fb9..cfa600d527 100644 --- a/Open-ILS/web/css/skin/default/acq.css +++ b/Open-ILS/web/css/skin/default/acq.css @@ -216,6 +216,8 @@ span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;mar .acq-invoice-paid-col {background : #E0E0E0; text-align: center;} .acq-invoice-center-col { text-align: center; } .acq-invoice-money { width: 7em; } +#acq-invoice-entry-thead th { white-space: nowrap; } +#acq-invoice-item-thead th { white-space: nowrap; } .acq-lineitem-summary { font-weight: bold; } .acq-lineitem-summary-extra { padding-left: 10px; } diff --git a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js index fd7949ff84..ad82f7b155 100644 --- a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js +++ b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js @@ -1,6 +1,7 @@ { "CREATE_PO_ASSETS_CONFIRM" : "This will create bibliographic, call number, and copy records for this purchase order in the ILS.\n\nContinue?", "ROLLBACK_PO_RECEIVE_CONFIRM" : "This will rollback receipt of all copies for this purchase order.\n\nContinue?", + "ROLLBACK_LI_RECEIVE_CONFIRM" : "This will rollback receipt of selected line items from this purchase order.\n\nContinue?", "XUL_RECORD_DETAIL_PAGE" : "Record Details", "DELETE_LI_COPIES_CONFIRM" : "This will delete the last ${0} copies in the table. Proceed?", "NO_PO_RESULTS" : "No results", @@ -87,5 +88,6 @@ "COPIES_TO_RECEIVE": "Number of copies to receive: ", "CREATE_PO_INVALID": "A purchase order must have an ordering agency and a provider.", "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." + "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" } diff --git a/Open-ILS/web/js/ui/default/acq/common/inv_dialog.js b/Open-ILS/web/js/ui/default/acq/common/inv_dialog.js index 7a5789e1dc..6ef5126611 100644 --- a/Open-ILS/web/js/ui/default/acq/common/inv_dialog.js +++ b/Open-ILS/web/js/ui/default/acq/common/inv_dialog.js @@ -11,7 +11,18 @@ function InvoiceLinkDialogManager(which, target) { var join = (idx == 0) ? '?' : '&'; path += join + "attach_" + self.which + "=" + id; }); - location.href = path; + if (openils.XUL.isXUL()) { + openils.XUL.newTabEasy( + path, + /* tab title */ dojo.string.substitute( + localeStrings.INVOICE_NUMBER, [self.inv.inv_ident()] + ), + null, + true /* wrapper */ + ); + } else { + location.href = path; + } }; this.which = which; diff --git a/Open-ILS/web/js/ui/default/acq/common/li_table.js b/Open-ILS/web/js/ui/default/acq/common/li_table.js index d1cfe99699..b58f6123e7 100644 --- a/Open-ILS/web/js/ui/default/acq/common/li_table.js +++ b/Open-ILS/web/js/ui/default/acq/common/li_table.js @@ -6,6 +6,7 @@ dojo.require('dijit.form.FilteringSelect'); dojo.require('dijit.form.Textarea'); dojo.require('dijit.Tooltip'); dojo.require('dijit.ProgressBar'); +dojo.require('dojox.timing.doLater'); dojo.require('openils.acq.Lineitem'); dojo.require('openils.acq.PO'); dojo.require('openils.acq.Picklist'); @@ -173,6 +174,28 @@ function AcqLiTable() { } }; + this.enableActionsDropdownOptions = function(mask) { + /* 'mask' is probably a minomer the way I'm using it, but it needs to + * be one of pl,po,ao,gs,vp, or fs. */ + dojo.query("option", "acq-lit-li-actions-selector").forEach( + function(option) { + var opt_mask = dojo.attr(option, "mask"); + + /* For each