[open-ils-commits] r15264 - in trunk/Open-ILS: src/extras src/perlmods/OpenILS src/perlmods/OpenILS/Application src/perlmods/OpenILS/Application/Circ src/sql/Pg src/sql/Pg/upgrade web/css/skin/default web/js/dojo/openils/booking/nls web/js/ui/default/booking web/opac/locale/en-US web/templates/default/booking xul/staff_client/chrome/content/main xul/staff_client/chrome/locale/en-US (miker)

svn at svn.open-ils.org svn at svn.open-ils.org
Wed Jan 6 13:13:31 EST 2010


Author: miker
Date: 2010-01-06 13:13:28 -0500 (Wed, 06 Jan 2010)
New Revision: 15264

Added:
   trunk/Open-ILS/src/sql/Pg/upgrade/0130.booking.resource_constraint_and_perms.sql
   trunk/Open-ILS/web/js/dojo/openils/booking/nls/capture.js
   trunk/Open-ILS/web/js/ui/default/booking/capture.js
   trunk/Open-ILS/web/templates/default/booking/capture.tt2
Modified:
   trunk/Open-ILS/src/extras/ils_events.xml
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Circ/Circulate.pm
   trunk/Open-ILS/src/perlmods/OpenILS/Const.pm
   trunk/Open-ILS/src/sql/Pg/002.schema.config.sql
   trunk/Open-ILS/src/sql/Pg/095.schema.booking.sql
   trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql
   trunk/Open-ILS/web/css/skin/default/booking.css
   trunk/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js
   trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js
   trunk/Open-ILS/web/js/ui/default/booking/pull_list.js
   trunk/Open-ILS/web/js/ui/default/booking/reservation.js
   trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
   trunk/Open-ILS/web/templates/default/booking/pull_list.tt2
   trunk/Open-ILS/web/templates/default/booking/reservation.tt2
   trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js
   trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
   trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties
Log:
Patch from Lebbeous Fogle-Weekley to reservation pull list and resource capture interfaces, and supporting backend and ML changes

Modified: trunk/Open-ILS/src/extras/ils_events.xml
===================================================================
--- trunk/Open-ILS/src/extras/ils_events.xml	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/extras/ils_events.xml	2010-01-06 18:13:28 UTC (rev 15264)
@@ -851,6 +851,9 @@
 	<event code='7022' textcode='RESERVATION_CAPTURE_FAILED'>
 		<desc xml:lang="en-US">Booking reservation capture failed</desc>
 	</event>
+	<event code='7023' textcode='RESERVATION_BAD_PARAMS'>
+		<desc xml:lang="en-US">Provided parameters describe unacceptable reservation.</desc>
+	</event>
 
 
 

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm	2010-01-06 18:13:28 UTC (rev 15264)
@@ -22,6 +22,7 @@
     $brt->name($mvr->title);
     $brt->record($record_id);
     $brt->catalog_item('t');
+    $brt->transferable('t');
     $brt->owner($owning_lib);
 
     return $brt;
@@ -189,7 +190,7 @@
 
 sub create_bresv {
     my ($self, $client, $authtoken,
-        $target_user_barcode, $datetime_range,
+        $target_user_barcode, $datetime_range, $pickup_lib,
         $brt, $brsrc_list, $attr_values) = @_;
 
     $brsrc_list = [ undef ] if not defined $brsrc_list;
@@ -210,7 +211,7 @@
         my $bresv = new Fieldmapper::booking::reservation;
         $bresv->usr($usr->id);
         $bresv->request_lib($e->requestor->ws_ou);
-        $bresv->pickup_lib($e->requestor->ws_ou);
+        $bresv->pickup_lib($pickup_lib);
         $bresv->start_time($datetime_range->[0]);
         $bresv->end_time($datetime_range->[1]);
 
@@ -218,9 +219,44 @@
         # brsrc and a brt when they don't match.  In fact, bomb out of
         # this transaction entirely.
         if ($brsrc) {
-            my $brsrc_itself = $e->retrieve_booking_resource($brsrc) or
-                return $e->die_event;
-            return $e->die_event if ($brsrc_itself->type != $brt);
+            my $brsrc_itself = $e->retrieve_booking_resource([
+                $brsrc, {
+                    "flesh" => 1,
+                    "flesh_fields" => {"brsrc" => ["type"]}
+                }
+            ]);
+
+            if (not $brsrc_itself) {
+                my $ev = new OpenILS::Event(
+                    "RESERVATION_BAD_PARAMS",
+                    desc => "brsrc $brsrc doesn't exist"
+                );
+                $e->disconnect;
+                return $ev;
+            }
+            elsif ($brsrc_itself->type->id != $brt) {
+                my $ev = new OpenILS::Event(
+                    "RESERVATION_BAD_PARAMS",
+                    desc => "brsrc $brsrc doesn't match given brt $brt"
+                );
+                $e->disconnect;
+                return $ev;
+            }
+
+            # Also bail if the user is trying to create a reservation at
+            # a pickup lib to which our resource won't go.
+            if (
+                $brsrc_itself->owner != $pickup_lib and
+                    not $brsrc_itself->type->transferable
+            ) {
+                my $ev = new OpenILS::Event(
+                    "RESERVATION_BAD_PARAMS",
+                    desc => "brsrc $brsrc doesn't belong to $pickup_lib and " .
+                        "is not transferable"
+                );
+                $e->disconnect;
+                return $ev;
+            }
         }
         $bresv->target_resource($brsrc);    # undef is ok here
         $bresv->target_resource_type($brt);
@@ -266,6 +302,7 @@
             {type => 'string', desc => 'Authentication token'},
             {type => 'string', desc => 'Barcode of user for whom to reserve'},
             {type => 'array', desc => 'Two elements: start and end timestamp'},
+            {type => 'int', desc => 'Desired reservation pickup lib'},
             {type => 'int', desc => 'Booking resource type'},
             {type => 'list', desc => 'Booking resource (undef ok; empty not ok)'},
             {type => 'array', desc => 'Attribute values selected'},
@@ -285,10 +322,10 @@
     return undef unless ($filters->{type} || $filters->{attribute_values});
 
     my $query = {
-        'select'   => { brsrc => [ 'id' ] },
-        'from'     => { brsrc => {} },
-        'where'    => {},
-        'distinct' => 1
+        "select"   => {brsrc => ["id"]},
+        "from"     => {brsrc => {"brt" => {}}},
+        "where"    => {},
+        "distinct" => 1
     };
 
     $query->{where} = {"-and" => []};
@@ -296,6 +333,14 @@
         push @{$query->{where}->{"-and"}}, {"type" => $filters->{type}};
     }
 
+    if ($filters->{pickup_lib}) {
+        push @{$query->{where}->{"-and"}},
+            {"-or" => [
+                {"owner" => $filters->{pickup_lib}},
+                {"+brt" => {"transferable" => "t"}}
+            ]};
+    }
+
     if ($filters->{attribute_values}) {
 
         $query->{from}->{brsrc}->{bram} = { field => 'resource' };
@@ -479,7 +524,7 @@
     } ];
     $cstore->disconnect;
 
-    if (not $whole_obj) {
+    if (not $whole_obj or @$ids < 1) {
         $e->disconnect;
         return $ids;
     }
@@ -529,28 +574,16 @@
 
 sub naive_ts_string { strftime("%F %T", localtime(shift)); }
 
-sub get_pull_list {
-    my ($self, $client, $auth, $range, $interval_secs, $pickup_lib) = @_;
+# Return a list of bresv or an ilsevent on failure.
+sub get_uncaptured_bresv_for_brsrc {
+    my ($e, $o) = @_; # o's keys (all optional): owning_lib, barcode, range
 
-    my $e = new_editor(xact => 1, authtoken => $auth);
-    return $e->die_event unless $e->checkauth;
-    return $e->die_event unless $e->allowed('RETRIEVE_RESERVATION_PULL_LIST');
-    return $e->die_event unless (
-        ref($range) eq 'ARRAY' or
-        ($interval_secs = int($interval_secs)) > 0
-    );
+    my $from_clause = {
+        "bresv" => {
+            "brsrc" => {"field" => "id", "fkey" => "current_resource"}
+        }
+    };
 
-    $range = [ naive_ts_string(time), naive_ts_string(time + $interval_secs) ]
-        if not $range;
-
-    my @fundamental_constraints = (
-        {"current_resource" => {"!=" => undef}},
-        {"capture_time" => undef},
-        {"cancel_time" => undef},
-        {"return_time" => undef},
-        {"pickup_time" => undef}
-    );
-
     my $query = {
         "select" => {
             "bresv" => [
@@ -562,27 +595,39 @@
                 }
             ]
         },
-        "from" => "bresv",
+        "from" => $from_clause,
         "where" => {
             "-and" => [
-                json_query_ranges_overlap(
-                    $range->[0], $range->[1], "start_time", "end_time"
-                ),
-                @fundamental_constraints
-            ],
+                {"current_resource" => {"!=" => undef}},
+                {"capture_time" => undef},
+                {"cancel_time" => undef},
+                {"return_time" => undef},
+                {"pickup_time" => undef}
+            ]
         }
     };
-    if ($pickup_lib) {
-        push @{$query->{"where"}->{"-and"}}, {"pickup_lib" => $pickup_lib};
+    if ($o->{"owning_lib"}) {
+        push @{$query->{"where"}->{"-and"}},
+            {"+brsrc" => {"owner" => $o->{"owning_lib"}}};
     }
+    if ($o->{"range"}) {
+        push @{$query->{"where"}->{"-and"}},
+            json_query_ranges_overlap(
+                $o->{"range"}->[0], $o->{"range"}->[1],
+                "start_time", "end_time"
+            );
+    }
+    if ($o->{"barcode"}) {
+        push @{$query->{"where"}->{"-and"}},
+            {"+brsrc" => {"barcode" => $o->{"barcode"}}};
+    }
 
     my $rows = $e->json_query($query);
-    my %resource_id_map = ();
-    my @all_ids = ();
+    my $current_resource_bresv_map = {};
     if (@$rows) {
         my $id_query = {
             "select" => {"bresv" => ["id"]},
-            "from" => "bresv",
+            "from" => $from_clause,
             "where" => {
                 "-and" => [
                     {"current_resource" => "PLACEHOLDER"},
@@ -590,9 +635,9 @@
                 ]
             }
         };
-        if ($pickup_lib) {
+        if ($o->{"owning_lib"}) {
             push @{$id_query->{"where"}->{"-and"}},
-                {"pickup_lib" => $pickup_lib};
+                {"+brsrc" => {"owner" => $o->{"owning_lib"}}};
         }
 
         foreach (@$rows) {
@@ -602,23 +647,42 @@
                 $_->{"start_time"};
 
             my $results = $e->json_query($id_query);
-            if (@$results) {
-                my @these_ids = map { $_->{"id"} } @$results;
-                push @all_ids, @these_ids;
-
-                $resource_id_map{$_->{"current_resource"}} = [@these_ids];
+            if ($results && @$results) {
+                $current_resource_bresv_map->{$_->{"current_resource"}} =
+                    [map { $_->{"id"} } @$results];
             }
         }
     }
-    if (@all_ids) {
+    return $current_resource_bresv_map;
+}
+
+sub get_pull_list {
+    my ($self, $client, $auth, $range, $interval_secs, $owning_lib) = @_;
+
+    my $e = new_editor(xact => 1, authtoken => $auth);
+    return $e->die_event unless $e->checkauth;
+    return $e->die_event unless $e->allowed("RETRIEVE_RESERVATION_PULL_LIST");
+    return $e->die_event unless (
+        ref($range) eq "ARRAY" or
+        ($interval_secs = int($interval_secs)) > 0
+    );
+
+    $owning_lib = $e->requestor->ws_ou if not $owning_lib;
+    $range = [ naive_ts_string(time), naive_ts_string(time + $interval_secs) ]
+        if not $range;
+
+    my $uncaptured = get_uncaptured_bresv_for_brsrc(
+        $e, {"range" => $range, "owning_lib" => $owning_lib}
+    );
+
+    if (keys(%$uncaptured)) {
+        my @all_bresv_ids = map { @{$_} } values %$uncaptured;
         my %bresv_lookup = (
             map { $_->id => $_ } @{
-                $e->search_booking_reservation([{"id" => [@all_ids]}, {
+                $e->search_booking_reservation([{"id" => [@all_bresv_ids]}, {
                     flesh => 1,
                     flesh_fields => { bresv => [
-                            "usr",
-                            "target_resource_type",
-                            "current_resource"
+                        "usr", "target_resource_type", "current_resource"
                     ]}
                 }])
             }
@@ -626,12 +690,12 @@
         $e->disconnect;
         return [ map {
             my $key = $_;
-            my $one = $bresv_lookup{$resource_id_map{$key}->[0]};
+            my $one = $bresv_lookup{$uncaptured->{$key}->[0]};
             my $result = {
                 "current_resource" => $one->current_resource,
                 "target_resource_type" => $one->target_resource_type,
                 "reservations" => [
-                    map { $bresv_lookup{$_} } @{$resource_id_map{$key}}
+                    map { $bresv_lookup{$_} } @{$uncaptured->{$key}}
                 ]
             };
             foreach (@{$result->{"reservations"}}) {    # deflesh
@@ -639,7 +703,7 @@
                 $_->target_resource_type($_->target_resource_type->id);
             }
             $result;
-        } keys %resource_id_map ];
+        } keys %$uncaptured ];
     } else {
         $e->disconnect;
         return [];
@@ -656,7 +720,7 @@
                 "range: Date/time range for reservations (opt)"},
             {type => "int", desc =>
                 "interval: Seconds from now (instead of range)"},
-            {type => "number", desc => "(Optional) Pickup library"}
+            {type => "number", desc => "(Optional) Owning library"}
         ],
         return => { desc => "An array of hashes, each containing key/value " .
             "pairs describing resource, resource type, and a list of " .
@@ -668,6 +732,9 @@
 sub get_copy_fleshed_just_right {
     my ($self, $client, $auth, $barcode) = @_;
 
+    return undef if not defined $barcode;
+    return {} if ref($barcode) eq "ARRAY" and not @$barcode;
+
     my $e = new_editor(authtoken => $auth);
     my $results = $e->search_asset_copy([
         {"barcode" => $barcode},
@@ -677,7 +744,7 @@
         }
     ]);
 
-    if (ref($results) eq 'ARRAY') {
+    if (ref($results) eq "ARRAY") {
         $e->disconnect;
         return $results->[0] unless ref $barcode;
         return +{ map { $_->barcode => $_ } @$results };
@@ -702,18 +769,96 @@
 );
 
 
+sub best_bresv_candidate {
+    my ($e, $id_list) = @_;
+
+    # This will almost always be the case.
+    return $id_list->[0] if @$id_list == 1;
+
+    my @here = ();
+    my $this_ou = $e->requestor->ws_ou;
+    my $results = $e->json_query({
+        "select" => {"brsrc" => ["pickup_lib"], "bresv" => ["id"]},
+        "from" => {
+            "bresv" => {
+                "brsrc" => {"field" => "id", "fkey" => "current_resource"}
+            }
+        },
+        "where" => {
+            {"+bresv" => {"id" => $id_list}}
+        }
+    });
+
+    foreach (@$results) {
+        push @here, $_->{"id"} if $_->{"pickup_lib"} == $this_ou;
+    }
+
+    if (@here > 0) {
+        return pop @here if @here == 1;
+        return (sort @here)[0];
+    } else {
+        return (sort @$id_list)[0];
+    }
+}
+
+
+sub capture_resource_for_reservation {
+    my ($self, $client, $auth, $barcode) = @_;
+
+    my $e = new_editor(xact => 1, authtoken => $auth);
+    return $e->die_event unless $e->checkauth;
+    return $e->die_event unless $e->allowed("CAPTURE_RESERVATION");
+
+    my $uncaptured = get_uncaptured_bresv_for_brsrc(
+        $e, {"barcode" => $barcode}
+    );
+    $e->disconnect;
+
+    if (keys %$uncaptured) {
+        # Note this will only capture one reservation at a time, even in
+        # cases with overbooking (multiple "soonest" bresv's on a resource).
+        my $key = (sort(keys %$uncaptured))[0];
+        return capture_reservation(
+            $self, $client, $auth, best_bresv_candidate($e, $uncaptured->{$key})
+        );
+    } else {
+        return new OpenILS::Event(
+            "RESERVATION_NOT_FOUND",
+            desc => "No capturable reservation found pertaining " .
+                "to a resource with barcode $barcode",
+            payload => {fail_cause => 'no-reservation', captured => 0}
+        );
+    }
+}
+__PACKAGE__->register_method(
+    method   => "capture_resource_for_reservation",
+    api_name => "open-ils.booking.resources.capture_for_reservation",
+    argc     => 3,
+    signature=> {
+        params => [
+            {type => "string", desc => "Authentication token"},
+            {type => "string", desc => "Barcode of booked & targeted resource"},
+            {type => "int", desc => "Pickup library (default to client ws_ou)"},
+        ],
+        return => { desc => "An OpenILS event describing the capture outcome" }
+    }
+);
+
+
 sub capture_reservation {
-    my $self = shift;
-    my $client = shift;
-    my $auth = shift;
-    my $res_id = shift;
+    my ($self, $client, $auth, $res_id) = @_;
 
     my $e = new_editor(xact => 1, authtoken => $auth);
     return $e->event unless $e->checkauth;
     return $e->event unless $e->allowed('CAPTURE_RESERVATION');
     my $here = $e->requestor->ws_ou;
 
-    my $reservation = $e->retrieve_booking_reservation( $res_id );
+    my $reservation = $e->retrieve_booking_reservation([
+        $res_id, {
+            flesh => 2,
+            flesh_fields => {"bresv" => ["usr"], "au" => ["card"]}
+        }
+    ]);
     return OpenILS::Event->new('RESERVATION_NOT_FOUND') unless $reservation;
 
     return OpenILS::Event->new('RESERVATION_CAPTURE_FAILED', payload => { captured => 0, fail_cause => 'no-resource' })
@@ -723,13 +868,16 @@
         if ($reservation->cancel_time); # canceled
 
     my $resource = $e->retrieve_booking_resource( $reservation->current_resource );
-    my $type = $e->retrieve_booking_resource( $resource->type );
+    my $type = $e->retrieve_booking_resource_type( $resource->type );
 
     $reservation->capture_staff( $e->requestor->id );
     $reservation->capture_time( 'now' );
 
-    return $e->event unless ( $e->update_booking_reservation( $reservation ) and $reservation = $e->data );
+    my $reservation_id = undef;
+    return $e->event unless ( $e->update_booking_reservation( $reservation ) and $reservation_id = $e->data );
 
+    $reservation->id($reservation_id);
+
     my $ret = { captured => 1, reservation => $reservation };
 
     if ($here != $reservation->pickup_lib) {
@@ -740,9 +888,9 @@
         my $transit = $e->search_action_reservation_transit_copy( { reservation => $res_id, dest_recv_time => undef } )->[0];
 
         if (!$transit) { # not yet in transit
-            $transit = new Fieldmapper::action::reservation_transit_copy ();
+            $transit = new Fieldmapper::action::reservation_transit_copy;
 
-            $transit->copy($resource->id);
+            $transit->target_copy($resource->id);
             $transit->copy_status(15);
             $transit->source_send_time('now');
             $transit->source($here);
@@ -754,10 +902,13 @@
                 my $copy = $e->search_asset_copy( { barcode => $resource->barcode, deleted => 'f' } )->[0];
 
                 if ($copy) {
-                    return OpenILS::Event->new('OPEN_CIRCULATION_EXISTS', payload => $copy) if ($copy->status == 1);
+                    return new OpenILS::Event(
+                        "OPEN_CIRCULATION_EXISTS",
+                        payload => { captured => 0, copy => $copy }
+                    ) if $copy->status == 1;
                     $copy->status(6);
                     $e->update_asset_copy( $copy );
-                    $$ret{catalog_item} = $e->data;
+                    $$ret{catalog_item} = $copy; # $e->data is just id (int)
                 }
             }
         }
@@ -770,7 +921,7 @@
             return OpenILS::Event->new('OPEN_CIRCULATION_EXISTS', payload => { captured => 0, copy => $copy }) if ($copy->status == 1);
             $copy->status(15);
             $e->update_asset_copy( $copy );
-            $$ret{catalog_item} = $e->data;
+            $$ret{catalog_item} = $copy; # $e->data is just id (int)
         }
     }
 
@@ -785,11 +936,72 @@
     signature=> {
         params => [
             {type => 'string', desc => 'Authentication token'},
-            {type => 'number', desc => 'Reservation ID'}
+            {type => 'mixed', desc =>
+                'Reservation ID (number) or array of resource barcodes'}
         ],
         return => { desc => "An OpenILS Event object describing the outcome of the capture, with relevant payload." },
     }
 );
 
 
+sub cancel_reservation {
+    my ($self, $client, $auth, $id_list) = @_;
+
+    my $e = new_editor(xact => 1, authtoken => $auth);
+    return $e->die_event unless $e->checkauth;
+    # Should the following permission really be checked as relates to each
+    # individual reservation's request_lib?  Hrmm...
+    return $e->die_event unless $e->allowed("ADMIN_BOOKING_RESERVATION");
+
+    my $bresv_list = $e->search_booking_reservation([
+        {"id" => $id_list},
+        {"flesh" => 1, "flesh_fields" => {"bresv" => [
+            "current_resource", "target_resource_type"
+        ]}}
+    ]);
+    return $e->die_event if not $bresv_list;
+
+    my $circ = OpenSRF::AppSession->connect("open-ils.circ") or
+        return $e->die_event;
+    my @results = ();
+    foreach my $bresv (@$bresv_list) {
+        if (
+            $bresv->target_resource_type->catalog_item == "t" &&
+            $bresv->current_resource
+        ) {
+            $logger->info("result of no-op checkin (upon cxl bresv) is " .
+                $circ->request(
+                    "open-ils.circ.checkin", $auth,
+                    {"barcode" => $bresv->current_resource->barcode,
+                        "noop" => 1}
+                )->gather(1)->{"textcode"});
+        }
+        $bresv->cancel_time("now");
+        $e->update_booking_reservation($bresv) or do {
+            $circ->disconnect;
+            return $e->die_event;
+        };
+
+        push @results, $bresv->id;
+    }
+
+    $e->commit;
+    $circ->disconnect;
+
+    return \@results;
+}
+__PACKAGE__->register_method(
+    method   => "cancel_reservation",
+    api_name => "open-ils.booking.reservations.cancel",
+    argc     => 2,
+    signature=> {
+        params => [
+            {type => "string", desc => "Authentication token"},
+            {type => "array", desc => "List of reservation IDs"}
+        ],
+        return => { desc => "A list of canceled reservation IDs" },
+    }
+);
+
+
 1;

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Circ/Circulate.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Circ/Circulate.pm	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Circ/Circulate.pm	2010-01-06 18:13:28 UTC (rev 15264)
@@ -197,7 +197,7 @@
             if ($transit) { # yes! unwrap it.
 
                 my $reservation = $circulator->editor->retrieve_booking_reservation( $transit->reservation );
-                my $res_type = $circulator->editor->retrieve_booking_resource_type( $reservation->target_reservation_type );
+                my $res_type = $circulator->editor->retrieve_booking_resource_type( $reservation->target_resource_type );
 
                 if ($U->is_true($res_type->catalog_item)) { # is there a copy to be had here?
                     if (my $copy = circulator->editor->search_asset_copy({ barcode => $bc, deleted => 'f' })->[0]) { # got a copy
@@ -229,7 +229,7 @@
                 )->[0];
 
                 if ($reservation) { # we have a reservation for which we could capture this resource.  wheee!
-                    my $res_type = $circulator->editor->retrieve_booking_resource_type( $reservation->target_reservation_type );
+                    my $res_type = $circulator->editor->retrieve_booking_resource_type( $reservation->target_resource_type );
                     my $elbow_room = $res_type->elbow_room ||
                         $U->ou_ancestor_setting_value( $circulator->circ_lib, 'circ.booking_reservation.default_elbow_room', $circulator->editor );
                 
@@ -245,7 +245,7 @@
                     if ($reservation) { # no elbow room specified, or we still have a reservation within the elbow_room time
                         my $b_ses = OpenSRF::AppSession->create('open-ils.booking');
                         my $result = $b_ses->request(
-                            'open-ils.booking.reservation.capture',
+                            'open-ils.booking.reservations.capture',
                             $auth => $reservation->id
                         )->gather(1);
 
@@ -2810,6 +2810,7 @@
             $status == OILS_COPY_STATUS_ON_HOLDS_SHELF  ||
             $status == OILS_COPY_STATUS_IN_TRANSIT  ||
             $status == OILS_COPY_STATUS_CATALOGING  ||
+            $status == OILS_COPY_STATUS_ON_RESV_SHELF  ||
             $status == OILS_COPY_STATUS_RESHELVING );
 
    return OpenILS::Event->new('COPY_STATUS_LOST', payload => $copy )

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Const.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Const.pm	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Const.pm	2010-01-06 18:13:28 UTC (rev 15264)
@@ -41,6 +41,7 @@
 econst OILS_COPY_STATUS_RESERVES      => 12;
 econst OILS_COPY_STATUS_DISCARD       => 13;
 econst OILS_COPY_STATUS_DAMAGED       => 14;
+econst OILS_COPY_STATUS_ON_RESV_SHELF => 15;
 
 
 # ---------------------------------------------------------------------

Modified: trunk/Open-ILS/src/sql/Pg/002.schema.config.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/002.schema.config.sql	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/sql/Pg/002.schema.config.sql	2010-01-06 18:13:28 UTC (rev 15264)
@@ -51,7 +51,7 @@
     install_date    TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
 );
 
-INSERT INTO config.upgrade_log (version) VALUES ('0129'); -- Scott McKellar
+INSERT INTO config.upgrade_log (version) VALUES ('0130'); -- senator
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,

Modified: trunk/Open-ILS/src/sql/Pg/095.schema.booking.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/095.schema.booking.sql	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/sql/Pg/095.schema.booking.sql	2010-01-06 18:13:28 UTC (rev 15264)
@@ -50,7 +50,7 @@
 	deposit        BOOLEAN          NOT NULL DEFAULT FALSE,
 	deposit_amount DECIMAL(8,2)     NOT NULL DEFAULT 0.00,
 	user_fee       DECIMAL(8,2)     NOT NULL DEFAULT 0.00,
-	CONSTRAINT br_unique UNIQUE(owner, type, barcode)
+	CONSTRAINT br_unique UNIQUE(owner, barcode)
 );
 
 -- For non-catalog items: hijack barcode for name/description

Modified: trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql	2010-01-06 18:13:28 UTC (rev 15264)
@@ -1249,11 +1249,11 @@
     (356, 'ADMIN_BOOKING_RESOURCE_ATTR_VALUE', oils_i18n_gettext(356, 'Enables the user to create/update/delete booking resource attribute values', 'ppl', 'description')),
     (357, 'ADMIN_BOOKING_RESERVATION', oils_i18n_gettext(357, 'Enables the user to create/update/delete booking reservations', 'ppl', 'description')),
     (358, 'ADMIN_BOOKING_RESERVATION_ATTR_VALUE_MAP', oils_i18n_gettext(358, 'Enables the user to create/update/delete booking reservation attribute value maps', 'ppl', 'description')),
-    (359, 'HOLD_ITEM_CHECKED_OUT.override', oils_i18n_gettext(359, 'Allows a user to place a hold on an item that they already have checked out', 'ppl', 'description'))
+    (359, 'HOLD_ITEM_CHECKED_OUT.override', oils_i18n_gettext(359, 'Allows a user to place a hold on an item that they already have checked out', 'ppl', 'description')),
+    (360, 'RETRIEVE_RESERVATION_PULL_LIST', oils_i18n_gettext(360, 'Allows a user to retrieve a booking reservation pull list', 'ppl', 'description')),
+    (361, 'CAPTURE_RESERVATION', oils_i18n_gettext(361, 'Allows a user to capture booking reservations', 'ppl', 'description'))
 ;
 
-    ;
-
 SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 1000);
 
 INSERT INTO permission.grp_tree (id, name, parent, description, perm_interval, usergroup, application_perm) VALUES

Added: trunk/Open-ILS/src/sql/Pg/upgrade/0130.booking.resource_constraint_and_perms.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/upgrade/0130.booking.resource_constraint_and_perms.sql	                        (rev 0)
+++ trunk/Open-ILS/src/sql/Pg/upgrade/0130.booking.resource_constraint_and_perms.sql	2010-01-06 18:13:28 UTC (rev 15264)
@@ -0,0 +1,12 @@
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('0130'); -- senator
+
+ALTER TABLE booking.resource DROP CONSTRAINT br_unique;
+ALTER TABLE booking.resource ADD CONSTRAINT br_unique UNIQUE (owner, barcode);
+
+INSERT into permission.perm_list VALUES
+    (360, 'RETRIEVE_RESERVATION_PULL_LIST', oils_i18n_gettext(360, 'Allows a user to retrieve a booking reservation pull list', 'ppl', 'description')),
+    (361, 'CAPTURE_RESERVATION', oils_i18n_gettext(361, 'Allows a user to capture booking reservations', 'ppl', 'description')) ; 
+
+COMMIT;

Modified: trunk/Open-ILS/web/css/skin/default/booking.css
===================================================================
--- trunk/Open-ILS/web/css/skin/default/booking.css	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/css/skin/default/booking.css	2010-01-06 18:13:28 UTC (rev 15264)
@@ -61,7 +61,7 @@
     color: #000000;
     font-weight: bold;
     padding: 0 6px 0 6px;
-    border-left: 1px #333333 solid;
+    border-left: 1px #cccccc solid;
     border-right: 1px #333333 solid;
 }
 tbody#the_table_body td {
@@ -72,3 +72,12 @@
     border-bottom: 1px #333333 solid;
     border-right: 1px #333333 solid;
 }
+.capture_failure { color: #cc0000; }
+.capture_success { color: #00cc00; }
+ul { list-style-type: square; }
+.capture_info { font-size: 12pt; font-weight: bold; margin-bottom: 4px; }
+.transit_notice {
+    font-size: 12pt; font-weight: bold; color: #ff6666;
+    margin-bottom: 4px; margin-top: 4px;
+}
+span#result_display { margin-left: 12px; }

Added: trunk/Open-ILS/web/js/dojo/openils/booking/nls/capture.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/booking/nls/capture.js	                        (rev 0)
+++ trunk/Open-ILS/web/js/dojo/openils/booking/nls/capture.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -0,0 +1,24 @@
+{
+    'FAILURE': "Capture failed",
+    'SUCCESS': "Capture succeeded",
+    'UNKNOWN_PROBLEM': "An unknown problem occurred during capture attempt.",
+    'CAPTURED_NOTHING': "Didn't capture anything.",
+    'NO_PAYLOAD':
+        "We did not receive further information from the server about this" +
+        "attempt to capture.",
+    'HERES_WHAT_WE_KNOW':
+        "The following information is available about the failed capture:",
+    'CAPTURE_INFO': "Capture Information",
+    'CAPTURE_BRESV_DATES': "Reservation time:",
+    'CAPTURE_BRESV_BRSRC': "Resource barcode:",
+    'CAPTURE_BRESV_PICKUP_LIB': "Pickup library:",
+    'CAPTURE_BRESV_PATRON_BARCODE': "Patron barcode:",
+    'CAPTURE_CAUSES_TRANSIT': "This item is now in transit!",
+    'CAPTURE_TRANSIT_SOURCE': "From:",
+    'CAPTURE_TRANSIT_DEST': "To:",
+
+    'AUTO_capture_heading': "Capture Reserved Resources",
+    'AUTO_resource_barcode': "Enter barcode:",
+    'AUTO_pickup_lib_selector': "Pickup library:",
+    'AUTO_ATTR_VALUE_capture': "Capture"
+}

Modified: trunk/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -5,7 +5,7 @@
     'COPY_LOOKUP_ERROR': "Error looking up copies by barcode: ",
     'COPY_MISSING': "Unexpected error: No information for copy: ",
 
-    'AUTO_pickup_lib_selector': "Select a location for pickup:",
+    'AUTO_owning_lib_selector': "See pull list for library:",
     'AUTO_pull_list_title': "Booking Pull List",
     'AUTO_interval_in_days': "Generate list for this many days hence: ",
     'AUTO_ATTR_VALUE_fetch': "Fetch",

Modified: trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -6,7 +6,7 @@
     'CREATE_BRESV_LOCAL_ERROR': "Exception trying to create reservation: ",
     'CREATE_BRESV_SERVER_ERROR': "Server error trying to create reservation: ",
     'CREATE_BRESV_SERVER_NO_RESPONSE':
-        "No response from server after trying to create reservation: ",
+        "No response from server after trying to create reservation.",
     /* FIXME: Users aren't likely to be able to do anything with the following
      * message.  Figure out a way to do something more helpful.
      */
@@ -36,7 +36,8 @@
     'CXL_BRESV_SUCCESS': function(n) {
         return ("Canceled " + n + " reservation" + (n == 1 ? "" : "s") + ".");
     },
-    'CXL_BRESV_FAILURE': "Error canceling reservations.",
+    'CXL_BRESV_FAILURE': "Error canceling reservations; server silent.",
+    'CXL_BRESV_FAILURE2': "Error canceling reservations:\n",
     'CXL_BRESV_SELECT_SOMETHING':
         "You have not selected any reservations to cancel.",
     'NEED_EXACTLY_ONE_BRT_PASSED_IN':
@@ -71,5 +72,7 @@
         "To reserve an item that is not yet registered as a bookable " +
         "resource, find it in the catalog or under <em>Display Item</em>, and "+
         "select <em>Make Item Bookable</em> or <em>Book Item Now</em> there.",
+    'AUTO_pickup_lib_selector':
+        "Choose the pickup library for this reservation:",
     'AUTO_or': '- Or -'
 }

Added: trunk/Open-ILS/web/js/ui/default/booking/capture.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/booking/capture.js	                        (rev 0)
+++ trunk/Open-ILS/web/js/ui/default/booking/capture.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -0,0 +1,174 @@
+dojo.require("openils.User");
+dojo.require("openils.widget.OrgUnitFilteringSelect");
+dojo.requireLocalization("openils.booking", "capture");
+
+const CAPTURE_FAILURE = 0;
+const CAPTURE_SUCCESS = 1;
+const CAPTURE_UNKNOWN = 2;
+
+var localeStrings = dojo.i18n.getLocalization("openils.booking", "capture");
+
+function CaptureDisplay(element) { this.element = element; }
+CaptureDisplay.prototype.no_payload = function() {
+    this.element.appendChild(document.createTextNode(localeStrings.NO_PAYLOAD));
+};
+CaptureDisplay.prototype.dump = function(payload) {
+    var div = document.createElement("div");
+    div.appendChild(document.createTextNode(localeStrings.HERES_WHAT_WE_KNOW));
+    this.element.appendChild(div);
+
+    var ul = document.createElement("ul");
+    for (var k in payload) {
+        var li = document.createElement("li");
+        li.appendChild(document.createTextNode(k + ": " + payload[k]));
+        ul.appendChild(li);
+    }
+    this.element.appendChild(ul);
+};
+CaptureDisplay.prototype.generate_transit_display = function(payload) {
+    var super_div = document.createElement("div");
+    var div;
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_CAUSES_TRANSIT
+    ));
+    div.setAttribute("class", "transit_notice");
+    super_div.appendChild(div);
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_TRANSIT_SOURCE + " " +
+        fieldmapper.aou.findOrgUnit(payload.transit.source()).shortname()
+    ));
+    super_div.appendChild(div);
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_TRANSIT_DEST + " " +
+        fieldmapper.aou.findOrgUnit(payload.transit.dest()).shortname()
+    ));
+    super_div.appendChild(div);
+
+    return super_div;
+};
+CaptureDisplay.prototype.display_with_transit_info = function(payload) {
+    var div;
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(localeStrings.CAPTURE_INFO));
+    div.setAttribute("class", "capture_info");
+    this.element.appendChild(div);
+
+    if (payload.catalog_item) {
+        div = document.createElement("div");
+        div.appendChild(document.createTextNode(
+            localeStrings.CAPTURE_BRESV_BRSRC + " " +
+            payload.catalog_item.barcode()
+        ));
+        this.element.appendChild(div);
+    }
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_BRESV_DATES + " " +
+        humanize_timestamp_string(payload.reservation.start_time()) + " - " +
+        humanize_timestamp_string(payload.reservation.end_time())
+    ));
+    this.element.appendChild(div);
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_BRESV_PICKUP_LIB + " " +
+        fieldmapper.aou.findOrgUnit(
+            payload.reservation.pickup_lib()
+        ).shortname()
+    ));
+    this.element.appendChild(div);
+
+    div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+        localeStrings.CAPTURE_BRESV_PATRON_BARCODE + " " +
+        payload.reservation.usr().card().barcode()
+    ));
+    this.element.appendChild(div);
+
+    if (payload.transit) {
+        this.element.appendChild(this.generate_transit_display(payload));
+    }
+};
+CaptureDisplay.prototype.clear = function() { this.element.innerHTML = ""; };
+CaptureDisplay.prototype.load = function(payload) {
+    try {
+        this.element.appendChild(document.createElement("hr"));
+        if (!payload) {
+            this.no_payload();
+        } else if (!payload.fail_cause && payload.captured) {
+            this.display_with_transit_info(payload);
+        } else {
+            this.dump(payload);
+        }
+    } catch (E) {
+        alert(E); /* XXX */
+    }
+};
+
+var capture_display;
+var last_result;
+
+function clear_for_next() {
+    if (last_result == CAPTURE_SUCCESS) {
+        last_result = undefined;
+        document.getElementById("result_display").innerHTML = "";
+        document.getElementById("resource_barcode").value = "";
+    }
+}
+
+function capture() {
+    var barcode = document.getElementById("resource_barcode").value;
+    var result = fieldmapper.standardRequest(
+        [
+            "open-ils.booking",
+            "open-ils.booking.resources.capture_for_reservation"
+        ],
+        [xulG.auth.session.key, barcode]
+    );
+
+    if (result && result.ilsevent !== undefined) {
+        if (result.payload && result.payload.captured > 0) {
+            capture_display.load(result.payload);
+            return CAPTURE_SUCCESS;
+        } else {
+            capture_display.load(result.payload);
+            alert(my_ils_error(localeStrings.CAPTURED_NOTHING, result));
+            return CAPTURE_FAILURE;
+        }
+    } else {
+        return CAPTURE_UNKNOWN;
+    }
+}
+
+function attempt_capture() {
+    var rd = document.getElementById("result_display");
+    capture_display.clear();
+    switch(last_result = capture()) {
+        case CAPTURE_FAILURE:
+            rd.setAttribute("class", "capture_failure");
+            rd.innerHTML = localeStrings.FAILURE;
+            break;
+        case CAPTURE_SUCCESS:
+            rd.setAttribute("class", "capture_success");
+            rd.innerHTML = localeStrings.SUCCESS;
+            break;
+        default:
+            alert(localeStrings.UNKNOWN_PROBLEM);
+            break;
+    }
+}
+
+function my_init() {
+    init_auto_l10n(document.getElementById("auto_l10n_start_here"));
+    capture_display = new CaptureDisplay(
+        document.getElementById("capture_display")
+    );
+}

Modified: trunk/Open-ILS/web/js/ui/default/booking/pull_list.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/booking/pull_list.js	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/js/ui/default/booking/pull_list.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -7,17 +7,17 @@
 var localeStrings = dojo.i18n.getLocalization("openils.booking", "pull_list");
 var pcrud = new openils.PermaCrud();
 
-var pickup_lib_selected;
+var owning_lib_selected;
 var acp_cache = {};
 
-function init_pickup_lib_selector() {
+function init_owning_lib_selector() {
     var User = new openils.User();
     User.buildPermOrgSelector(
-        "RETRIEVE_RESERVATION_PULL_LIST", pickup_lib_selector, null,
+        "RETRIEVE_RESERVATION_PULL_LIST", owning_lib_selector, null,
         function() {
-            pickup_lib_selected = pickup_lib_selector.getValue();
-            dojo.connect(pickup_lib_selector, "onChange",
-                function() { pickup_lib_selected = this.getValue(); }
+            owning_lib_selected = owning_lib_selector.getValue();
+            dojo.connect(owning_lib_selector, "onChange",
+                function() { owning_lib_selected = this.getValue(); }
             )
         }
     );
@@ -31,7 +31,7 @@
 
     return fieldmapper.standardRequest(
         ["open-ils.booking", "open-ils.booking.reservations.get_pull_list"],
-        [xulG.auth.session.key, null, secs, pickup_lib_selected]
+        [xulG.auth.session.key, null, secs, owning_lib_selected]
     );
 }
 
@@ -101,22 +101,24 @@
             barcodes.push(list[i].current_resource.barcode());
         }
     }
-    var results = fieldmapper.standardRequest(
-        [
-            "open-ils.booking",
-            "open-ils.booking.asset.get_copy_fleshed_just_right"
-        ],
-        [xulG.auth.session.key, barcodes]
-    );
+    if (barcodes.length > 0) {
+        var results = fieldmapper.standardRequest(
+            [
+                "open-ils.booking",
+                "open-ils.booking.asset.get_copy_fleshed_just_right"
+            ],
+            [xulG.auth.session.key, barcodes]
+        );
 
-    if (!results) {
-        alert(localeStrings.COPY_LOOKUP_NO_RESPONSE);
-        return null;
-    } else if (is_ils_error(results)) {
-        alert(my_ils_error(localeStrings.COPY_LOOKUP_ERROR, results));
-        return null;
-    } else {
-        return results;
+        if (!results) {
+            alert(localeStrings.COPY_LOOKUP_NO_RESPONSE);
+            return null;
+        } else if (is_ils_error(results)) {
+            alert(my_ils_error(localeStrings.COPY_LOOKUP_ERROR, results));
+            return null;
+        } else {
+            return results;
+        }
     }
 }
 
@@ -185,6 +187,6 @@
 }
 
 function my_init() {
-    init_pickup_lib_selector();
+    init_owning_lib_selector();
     init_auto_l10n(document.getElementById("auto_l10n_start_here"));
 }

Modified: trunk/Open-ILS/web/js/ui/default/booking/reservation.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/booking/reservation.js	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/js/ui/default/booking/reservation.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -3,6 +3,7 @@
  */
 dojo.require("fieldmapper.OrgUtils");
 dojo.require("openils.PermaCrud");
+dojo.require("openils.widget.OrgUnitFilteringSelect");
 dojo.require("dojo.data.ItemFileReadStore");
 dojo.require("dijit.form.DateTextBox");
 dojo.require("dijit.form.TimeTextBox");
@@ -15,6 +16,7 @@
 var pcrud = new openils.PermaCrud();
 var opts;
 var our_brt;
+var pickup_lib_selected;
 var brt_list = [];
 var brsrc_index = {};
 var bresv_index = {};
@@ -208,7 +210,7 @@
 }
 
 function get_brsrc_id_list() {
-    var options = {"type": our_brt.id()};
+    var options = {"type": our_brt.id(), "pickup_lib": pickup_lib_selected};
 
     /* This mechanism for avoiding the passing of an empty 'attribute_values'
      * option is essential because if you pass such an option to the
@@ -298,6 +300,7 @@
                 xulG.auth.session.key,
                 barcode,
                 reserve_timestamp_range.get_range(),
+                pickup_lib_selected,
                 our_brt.id(),
                 resource_list,
                 attr_value_table.get_all_values()
@@ -358,7 +361,7 @@
     var selector = document.getElementById("brsrc_list");
     var selected_values = [];
     for (var i in selector.options) {
-        if (selector.options[i].selected)
+        if (selector.options[i] && selector.options[i].selected)
             selected_values.push(selector.options[i].value);
     }
     if (selected_values.length > 0)
@@ -440,20 +443,19 @@
     }
 }
 
-function cancel_reservations(bresv_list) {
-    for (var i in bresv_list) { bresv_list[i].cancel_time("now"); }
-    pcrud.update(
-        bresv_list, {
-            "oncomplete": function() {
-                update_bresv_grid();
-                alert(localeStrings.CXL_BRESV_SUCCESS(bresv_list.length));
-            },
-            "onerror": function(o) {
-                update_bresv_grid();
-                alert(localeStrings.CXL_BRESV_FAILURE + "\n" + o);
-            }
-        }
+function cancel_reservations(bresv_id_list) {
+    var result = fieldmapper.standardRequest(
+        ["open-ils.booking", "open-ils.booking.reservations.cancel"],
+        [xulG.auth.session.key, bresv_id_list]
     );
+    setTimeout(update_bresv_grid, 0);
+    if (!result) {
+        alert(localeStrings.CXL_BRESV_FAILURE);
+    } else if (is_ils_error(result)) {
+        alert(my_ils_error(localeStrings.CXL_BRESV_FAILURE2, result));
+    } else {
+        alert(localeStrings.CXL_BRESV_SUCCESS(result.length));
+    }
 }
 
 function munge_specific_resource(barcode) {
@@ -481,6 +483,22 @@
  * These functions deal with interface tricks (populating widgets,
  * changing the page, etc.).
  */
+function init_pickup_lib_selector() {
+    var User = new openils.User();
+    User.buildPermOrgSelector(
+        "ADMIN_BOOKING_RESERVATION", pickup_lib_selector, null,
+        function() {
+            pickup_lib_selected = pickup_lib_selector.getValue();
+            dojo.connect(pickup_lib_selector, "onChange",
+                function() {
+                    pickup_lib_selected = this.getValue();
+                    update_brsrc_list();
+                }
+            )
+        }
+    );
+}
+
 function provide_brt_selector(targ_div) {
     if (!targ_div) {
         alert(localeStrings.NO_TARG_DIV);
@@ -588,6 +606,7 @@
     /* Add a prominent label reminding the user what resource type they're
      * asking about. */
     document.getElementById("brsrc_list_header").innerHTML = our_brt.name();
+    init_pickup_lib_selector();
     update_brsrc_list();
 }
 
@@ -686,7 +705,7 @@
 function cancel_selected_bresv(bresv_dojo_items) {
     if (bresv_dojo_items && bresv_dojo_items.length > 0) {
         cancel_reservations(
-            bresv_dojo_items.map(function(o) { return bresv_index[o.id]; })
+            bresv_dojo_items.map(function(o) { return o.id[0]; })
         );
         /* After some delay to allow the cancellations a chance to get
          * committed, refresh the brsrc list as it might reflect newly

Modified: trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
===================================================================
--- trunk/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-01-06 18:13:28 UTC (rev 15264)
@@ -772,6 +772,8 @@
 <!ENTITY staff.main.menu.booking.reservation.accesskey "C">
 <!ENTITY staff.main.menu.booking.pull_list.label "Pull List">
 <!ENTITY staff.main.menu.booking.pull_list.accesskey "L">
+<!ENTITY staff.main.menu.booking.capture.label "Capture Resources">
+<!ENTITY staff.main.menu.booking.capture.accesskey "A">
 <!ENTITY staff.main.menu.booking.reservation_pickup.label "Pick Up Reservations">
 <!ENTITY staff.main.menu.booking.reservation_pickup.accesskey "P">
 <!ENTITY staff.main.menu.booking.reservation_return.label "Return Reservations">

Added: trunk/Open-ILS/web/templates/default/booking/capture.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/booking/capture.tt2	                        (rev 0)
+++ trunk/Open-ILS/web/templates/default/booking/capture.tt2	2010-01-06 18:13:28 UTC (rev 15264)
@@ -0,0 +1,21 @@
+[% WRAPPER "default/base.tt2" %]
+<script src="[% ctx.media_prefix %]/js/ui/default/booking/common.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/booking/capture.js"></script>
+<link rel="stylesheet" type="text/css" href="[% ctx.media_prefix %]/css/skin/[% ctx.skin %]/booking.css" />
+<script type="text/javascript">openils.Util.addOnLoad(my_init);</script>
+<div id="auto_l10n_start_here">
+<!-- XXX This interface will probably go away soon in favor of merging its
+behavior into the regular checkin/process/capture interface. -->
+    <h1 class="AUTO_capture_heading booking"></h1>
+    <form class="nice_vertical_padding"
+        onsubmit="attempt_capture(); return false">
+        <label for="resource_barcode" class="AUTO_resource_barcode"></label>
+        <input id="resource_barcode" onfocus="clear_for_next();" />
+        <input type="button" class="AUTO_ATTR_VALUE_capture"
+            onclick="attempt_capture();" />
+        <span id="result_display"></span>
+    </form>
+    <div class="nice_vertical_padding" id="capture_display">
+    </div>
+</div>
+[% END %]

Modified: trunk/Open-ILS/web/templates/default/booking/pull_list.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/booking/pull_list.tt2	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/templates/default/booking/pull_list.tt2	2010-01-06 18:13:28 UTC (rev 15264)
@@ -6,11 +6,11 @@
 <div id="auto_l10n_start_here">
     <h1 class="booking AUTO_pull_list_title"></h1>
     <form onsubmit="populate_pull_list(this); return false;">
-        <div id="pickup_lib_selector_row" class="nice_vertical_padding">
-            <label for="pickup_lib_selector" class="AUTO_pickup_lib_selector">
+        <div id="owning_lib_selector_row" class="nice_vertical_padding">
+            <label for="owning_lib_selector" class="AUTO_owning_lib_selector">
             </label>
             <select dojoType="openils.widget.OrgUnitFilteringSelect"
-                id="pickup_lib_selector" jsId="pickup_lib_selector"
+                id="owning_lib_selector" jsId="owning_lib_selector"
                 searchAttr="shortname" labelAttr="shortname"></select>
         </div>
         <div id="interval_input_row" class="nice_vertical_padding">
@@ -25,7 +25,7 @@
     </form>
     <hr />
     <div id="table_goes_here" class="nice_vertical_padding">
-        <table id="the_table" width="90%">
+        <table id="the_table" width="100%">
             <thead>
                 <tr>
                     <th width="30%" class="AUTO_th_title_or_name"></th>

Modified: trunk/Open-ILS/web/templates/default/booking/reservation.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/booking/reservation.tt2	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/web/templates/default/booking/reservation.tt2	2010-01-06 18:13:28 UTC (rev 15264)
@@ -47,6 +47,13 @@
                     <input name="patron_barcode" id="patron_barcode"
                         onchange="update_bresv_grid();" />
                 </div>
+                <div id="pickup_lib_selector_row" class="nice_vertical_padding">
+                    <label for="pickup_lib_selector"
+                        class="AUTO_pickup_lib_selector"></label>
+                    <select dojoType="openils.widget.OrgUnitFilteringSelect"
+                        id="pickup_lib_selector" jsId="pickup_lib_selector"
+                        searchAttr="shortname" labelAttr="shortname"></select>
+                </div>
                 <div class="nice_vertical_padding">
                     <span class="two_buttons">
                         <input type="button"
@@ -99,9 +106,8 @@
         </table>
         <div class="nice_vertical_padding"
             id="existing_bresv_under_buttons">
-            <input type="button" id="button_edit_existing"
-                class="AUTO_ATTR_VALUE_button_edit_existing"
-                disabled="disabled" />
+            <!-- <input type="button" id="button_edit_existing"
+                class="AUTO_ATTR_VALUE_button_edit_existing" /> -->
             <input type="button" id="button_cancel_existing"
                 class="AUTO_ATTR_VALUE_button_cancel_existing"
                 onclick="cancel_selected_bresv(bresvGrid.selection.getSelected());" />

Modified: trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js
===================================================================
--- trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js	2010-01-06 18:13:28 UTC (rev 15264)
@@ -729,6 +729,21 @@
                     );
                 }
             ],
+            'cmd_booking_capture' : [
+                ['oncommand'],
+                function() {
+                    obj.set_tab(
+                        "/eg/booking/capture",
+                        {
+                            "tab_name": offlineStrings.getString(
+                                "menu.cmd_booking_capture.tab"
+                            ),
+                            "browser": false
+                        },
+                        xulG
+                    );
+                }
+            ],
             'cmd_booking_reservation_pickup' : [
                 ['oncommand'],
                 function() {

Modified: trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
===================================================================
--- trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul	2010-01-06 18:13:28 UTC (rev 15264)
@@ -90,6 +90,7 @@
 
     <command id="cmd_booking_reservation" />
     <command id="cmd_booking_pull_list" />
+    <command id="cmd_booking_capture" />
     <command id="cmd_booking_reservation_pickup" />
     <command id="cmd_booking_reservation_return" />
 
@@ -267,6 +268,7 @@
     <menupopup id="main.menu.booking.popup">
         <menuitem label="&staff.main.menu.booking.reservation.label;" accesskey="&staff.main.menu.booking.reservation.accesskey;" command="cmd_booking_reservation"/>
         <menuitem label="&staff.main.menu.booking.pull_list.label;" accesskey="&staff.main.menu.booking.pull_list.accesskey;" command="cmd_booking_pull_list"/>
+        <menuitem label="&staff.main.menu.booking.capture.label;" accesskey="&staff.main.menu.booking.capture.accesskey;" command="cmd_booking_capture"/>
         <!-- <menuitem label="&staff.main.menu.booking.reservation_pickup.label;" accesskey="&staff.main.menu.booking.reservation_pickup.accesskey;" command="cmd_booking_reservation_pickup"/>
         <menuitem label="&staff.main.menu.booking.reservation_return.label;" accesskey="&staff.main.menu.booking.reservation_return.accesskey;" command="cmd_booking_reservation_return"/> -->
     </menupopup>

Modified: trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties
===================================================================
--- trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties	2010-01-06 16:41:52 UTC (rev 15263)
+++ trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties	2010-01-06 18:13:28 UTC (rev 15264)
@@ -237,6 +237,7 @@
 menu.cmd_booking_reservation_pickup.tab=Reservation Pickup
 menu.cmd_booking_reservation_return.tab=Reservation Return
 menu.cmd_booking_pull_list.tab=Booking Pull List
+menu.cmd_booking_capture.tab=Booking Capture
 menu.local_admin.circ_matrix_matchpoint.tab=Circulation Policies
 menu.local_admin.hold_matrix_matchpoint.tab=Hold Policies
 menu.local_admin.work_log.tab=Work Log



More information about the open-ils-commits mailing list