From: senator Date: Sat, 20 Nov 2010 22:55:56 +0000 (+0000) Subject: Serials: a routing list editor for the alternate serials control view X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=b6ffd9ab6969a430cae03e399f2233df30948e7c;p=evergreen%2Fbjwebb.git Serials: a routing list editor for the alternate serials control view Now we still need to teach the receive interface to offer to print the list when there is one, but I think that should be relatively simple. git-svn-id: svn://svn.open-ils.org/ILS/trunk@18812 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index cb2a12650..e00b24c1f 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -3400,6 +3400,20 @@ SELECT usr, + + + + + + + + + + + + + + diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/OpenILS/Application/Actor.pm index 2fcacd25e..bb33e8905 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Actor.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Actor.pm @@ -456,14 +456,19 @@ sub apply_invalid_addr_penalty { sub flesh_user { my $id = shift; my $e = shift; - return new_flesh_user($id, [ + my $home_ou = shift; + + my $fields = [ "cards", "card", "standing_penalties", "addresses", "billing_address", "mailing_address", - "stat_cat_entries" ], $e ); + "stat_cat_entries" + ]; + push @$fields, "home_ou" if $home_ou; + return new_flesh_user($id, $fields, $e ); } @@ -1024,7 +1029,7 @@ __PACKAGE__->register_method( api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",); sub user_retrieve_by_barcode { - my($self, $client, $auth, $barcode) = @_; + my($self, $client, $auth, $barcode, $flesh_home_ou) = @_; my $e = new_editor(authtoken => $auth); return $e->event unless $e->checkauth; @@ -1032,8 +1037,10 @@ sub user_retrieve_by_barcode { my $card = $e->search_actor_card({barcode => $barcode})->[0] or return $e->event; - my $user = flesh_user($card->usr, $e); - return $e->event unless $e->allowed('VIEW_USER', $user->home_ou); + my $user = flesh_user($card->usr, $e, $flesh_home_ou); + return $e->event unless $e->allowed( + "VIEW_USER", $flesh_home_ou ? $user->home_ou->id : $user->home_ou + ); return $user; } diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm b/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm index 3623fb5e3..4393d40c8 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm @@ -2794,4 +2794,134 @@ sub get_receivable_issuances { undef; } + +__PACKAGE__->register_method( + "method" => "get_routing_list_users", + "api_name" => "open-ils.serial.routing_list_users.fleshed_and_ordered", + "stream" => 1, + "signature" => { + "desc" => "Return all routing list users with reader fleshed " . + "(with card and home_ou) for a given stream ID, sorted by pos", + "params" => [ + {"desc" => "Authtoken", "type" => "string"}, + {"desc" => "Stream ID", "type" => "number"}, + ], + "return" => { + "desc" => "Stream of routing list users", "type" => "object", + "class" => "srlu" + } + } +); + +sub get_routing_list_users { + my ($self, $client, $auth, $stream_id) = @_; + + return undef unless $stream_id = int $stream_id; # sic, assignment + + my $e = new_editor("authtoken" => $auth); + return $e->die_event unless $e->checkauth; + + my $users = $e->search_serial_routing_list_user([ + {"stream" => $stream_id}, { + "order_by" => {"srlu" => "pos"}, + "flesh" => 2, + "flesh_fields" => { + "srlu" => [qw/reader stream/], + "au" => [qw/card home_ou/], + "sstr" => ["distribution"] + } + } + ]) or return $e->die_event; + + return undef unless @$users; + + # The ADMIN_SERIAL_STREAM permission is used simply to avoid the + # need for any new permission. The context OU will be the same + # for every result of the above query, so we need only check once. + return $e->die_event unless $e->allowed( + "ADMIN_SERIAL_STREAM", $users->[0]->stream->distribution->holding_lib + ); + + $e->disconnect; + + # Now we can strip the stream/distribution info (only used for perm + # checking) and send back the srlu's to the caller. + $client->respond($_) for map { $_->stream($_->stream->id); $_ } @$users; + + undef; +} + + +__PACKAGE__->register_method( + "method" => "replace_routing_list_users", + "api_name" => "open-ils.serial.routing_list_users.replace", + "signature" => { + "desc" => "Replace all routing list users on the specified streams " . + "with those in the list argument", + "params" => [ + {"desc" => "Authtoken", "type" => "string"}, + {"desc" => "List of srlu objects", "type" => "array"}, + ], + "return" => { + "desc" => "event on failure, undef on success" + } + } +); + +sub replace_routing_list_users { + my ($self, $client, $auth, $users) = @_; + + return undef unless ref $users eq "ARRAY"; + + if (grep { ref $_ ne "Fieldmapper::serial::routing_list_user" } @$users) { + return new OpenILS::Event("BAD_PARAMS", "note" => "Only srlu objects"); + } + + my $e = new_editor("authtoken" => $auth, "xact" => 1); + return $e->die_event unless $e->checkauth; + + my %streams_ok = (); + my $pos = 0; + + foreach my $user (@$users) { + unless (exists $streams_ok{$user->stream}) { + my $stream = $e->retrieve_serial_stream([ + $user->stream, { + "flesh" => 1, + "flesh_fields" => {"sstr" => ["distribution"]} + } + ]) or return $e->die_event; + $e->allowed( + "ADMIN_SERIAL_STREAM", $stream->distribution->holding_lib + ) or return $e->die_event; + + my $to_delete = $e->search_serial_routing_list_user( + {"stream" => $user->stream} + ) or return $e->die_event; + + $logger->info( + "Deleting srlu: [" . + join(", ", map { $_->id; } @$to_delete) . + "]" + ); + + foreach (@$to_delete) { + $e->delete_serial_routing_list_user($_) or + return $e->die_event; + } + + $streams_ok{$user->stream} = 1; + } + + next if $user->isdeleted; + + $user->clear_id; + $user->pos($pos++); + $e->create_serial_routing_list_user($user) or return $e->die_event; + } + + $e->commit or return $e->die_event; + undef; +} + 1; diff --git a/Open-ILS/web/js/ui/default/serial/list_stream.js b/Open-ILS/web/js/ui/default/serial/list_stream.js index befc46e43..403b31712 100644 --- a/Open-ILS/web/js/ui/default/serial/list_stream.js +++ b/Open-ILS/web/js/ui/default/serial/list_stream.js @@ -1,6 +1,8 @@ dojo.require("dijit.form.Button"); +dojo.require("dijit.form.RadioButton"); dojo.require("dijit.form.NumberSpinner"); dojo.require("dijit.form.TextBox"); +dojo.require("dojo.dnd.Source"); dojo.require("openils.widget.AutoGrid"); dojo.require("openils.widget.ProgressDialog"); dojo.require("openils.PermaCrud"); @@ -8,6 +10,7 @@ dojo.require("openils.CGI"); var pcrud; var dist_id; +var rlu_editor; var cgi; function format_routing_label(routing_label) { @@ -72,10 +75,223 @@ function create_many_streams(fields) { ); } +function RLUEditor() { + var self = this; + + function _reader_xor_dept_toggle(value) { + var reader = dijit.byId("reader"); + var department = dijit.byId("department"); + + if (this.id.match(/\w+$/).pop() == "reader") + _reader_toggle(value, reader, department); + else + _department_toggle(value, reader, department); + } + + function _reader_toggle(value, reader, department) { + if (value) { + reader.attr("disabled", false); + department.attr("disabled", true); + setTimeout(function() { reader.focus(); }, 125); + } + } + + function _department_toggle(value, reader, department) { + if (value) { + reader.attr("disabled", true); + department.attr("disabled", false); + setTimeout(function() { department.focus(); }, 125); + } + } + + this.user_to_source_entry = function(user) { + var node = dojo.create("li"); + var s; + if (user.reader()) { + s = dojo.string.substitute( + this.template.reader, [ + user.reader().card().barcode(), + user.reader().family_name(), + user.reader().first_given_name(), + user.reader().second_given_name(), + user.reader().home_ou().shortname() + ].map(function(o) { return o == null ? "" : o; }) + ); + } else { + s = dojo.string.substitute( + this.template.department, [user.department()] + ); + } + + if (user.note()) { + s += dojo.string.substitute(this.template.note, [user.note()]); + } + + node.innerHTML = " " + s; + + dojo.create( + "a", { + "href": "javascript:void(0);", + "onclick": function() { self.toggle_deleted(node); }, + "innerHTML": this.template.remove + }, node, "first" + ); + + node._user = user; + return node; + }; + + this.toggle_deleted = function(node) { + if (node._user.isdeleted()) { + dojo.style(node, "textDecoration", "none"); + node._user.isdeleted(false); + } else { + dojo.style(node, "textDecoration", "line-through"); + node._user.isdeleted(true); + } + }; + + this.new_user = function() { + var form = this.dialog.attr("value"); + var user = new fieldmapper.srlu(); + user.isnew(true); + user.stream(this.stream); + + if (form.note) + user.note(form.note); + + if (form.department) { + user.department(form.department); + } else if (form.reader) { + this.add_button.attr("disabled", true); + fieldmapper.standardRequest( + ["open-ils.actor", + "open-ils.actor.user.fleshed.retrieve_by_barcode"], { + "params": [openils.User.authtoken, form.reader, true], + "timeout": 10, /* sync */ + "onresponse": function(r) { + if (r = openils.Util.readResponse(r)) { + user.reader(r); + } + } + } + ); + this.add_button.attr("disabled", false); + } else { + alert("Provide either a reader or a department."); /* XXX i18n */ + return; + } + + ["reader", "department", "note"].forEach( + function(s) { dijit.byId(s).attr("value", ""); } + ); + + this.source.insertNodes(false, [self.user_to_source_entry(user)]); + } + + this.show = function() { + if (sstr_grid.getSelectedRows().length != 1) { + alert( + "Use the checkboxes to select exactly one stream " + + "for this operation." /* XXX i18n */ + ); + } else { + /* AutoGrid.getSelectedItems() yields a weird, non-FM object */ + this.stream = sstr_grid.getSelectedItems()[0].id[0]; + + this.source.selectAll(); + this.source.deleteSelectedNodes(); + this.source.clearItems(); + + this.dialog.show(); + + fieldmapper.standardRequest( + ["open-ils.serial", + "open-ils.serial.routing_list_users.fleshed_and_ordered"], { + "params": [openils.User.authtoken, this.stream], + "async": true, + "onresponse": function(r) { + if (r = openils.Util.readResponse(r)) { + self.source.insertNodes( + false, [self.user_to_source_entry(r)] + ); + } + }, + "oncomplete": function() { + setTimeout( + function() { self.save_button.focus(); }, 125 + ); + } + } + ); + } + }; + + this.save = function() { + var obj_list = this.source.getAllNodes().map( + function(node) { + var obj = node._user; + if (obj.reader()) + obj.reader(obj.reader().id()); + + return obj; + } + ); + + this.save_button.attr("disabled", true); + + /* pcrud.apply *almost* could have handled this, but there's a reason + * it doesn't, and it has to do with the unique key constraint on the + * pos field in srlu objects. + */ + try { + fieldmapper.standardRequest( + /* This method will set pos in ascending order. */ + ["open-ils.serial", + "open-ils.serial.routing_list_users.replace"], { + "params": [openils.User.authtoken, obj_list], + "timeout": 10, /* sync */ + "oncomplete": function(r) { + openils.Util.readResponse(r); /* display exceptions */ + } + } + ); + } catch (E) { + alert(E); /* XXX i18n */ + } + + this.save_button.attr("disabled", false); + }; + + this._init = function(dialog) { + this.dialog = dijit.byId("routing_list_dialog"); + this.source = routing_list_source; + + this.template = {}; + ["reader", "department", "note", "remove"].forEach( + function(n) { + self.template[n] = + dojo.byId("routing_list_user_template_" + n).innerHTML; + } + ); + + this.add_button = dijit.byId("routing_list_add_button"); + this.save_button = dijit.byId("routing_list_save_button"); + + dijit.byId("reader_xor_dept-reader").onChange = + _reader_xor_dept_toggle; + dijit.byId("reader_xor_dept-department").onChange = + _reader_xor_dept_toggle; + }; + + this._init.apply(this, arguments); +} + openils.Util.addOnLoad( function() { cgi = new openils.CGI(); pcrud = new openils.PermaCrud(); + rlu_editor = new RLUEditor(); dist_id = cgi.param("distribution"); load_sdist_display(); diff --git a/Open-ILS/web/templates/default/serial/list_stream.tt2 b/Open-ILS/web/templates/default/serial/list_stream.tt2 index 660c76129..52e641c70 100644 --- a/Open-ILS/web/templates/default/serial/list_stream.tt2 +++ b/Open-ILS/web/templates/default/serial/list_stream.tt2 @@ -1,5 +1,11 @@ [% WRAPPER default/base.tt2 %] [% ctx.page_title = "Streams" %] +
@@ -11,6 +17,9 @@ onClick="multi_stream_dialog.show()"> Create Many Streams +