[open-ils-commits] r15207 - in trunk/Open-ILS: examples src/perlmods/OpenILS/Application src/perlmods/OpenILS/Application/Storage/CDBI src/perlmods/OpenILS/Application/Storage/Publisher src/perlmods/OpenILS/Utils web/css/skin/default web/js/dojo/openils web/js/dojo/openils/booking web/js/dojo/openils/booking/nls web/js/ui/default web/js/ui/default/booking web/opac/locale/en-US web/templates/default web/templates/default/booking web/templates/default/conify/global/booking xul/staff_client/chrome/content/main xul/staff_client/chrome/locale/en-US xul/staff_client/server/cat xul/staff_client/server/locale/en-US (miker)
svn at svn.open-ils.org
svn at svn.open-ils.org
Mon Dec 21 11:21:50 EST 2009
Author: miker
Date: 2009-12-21 11:21:48 -0500 (Mon, 21 Dec 2009)
New Revision: 15207
Added:
trunk/Open-ILS/web/css/skin/default/booking.css
trunk/Open-ILS/web/js/dojo/openils/booking/
trunk/Open-ILS/web/js/dojo/openils/booking/nls/
trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js
trunk/Open-ILS/web/js/ui/default/booking/
trunk/Open-ILS/web/js/ui/default/booking/reservation.js
trunk/Open-ILS/web/templates/default/booking/
trunk/Open-ILS/web/templates/default/booking/reservation.tt2
Removed:
trunk/Open-ILS/web/templates/default/conify/global/booking/reservation.tt2
trunk/Open-ILS/web/templates/default/conify/global/booking/reservation_attr_value_map.tt2
Modified:
trunk/Open-ILS/examples/fm_IDL.xml
trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm
trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm
trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm
trunk/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm
trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
trunk/Open-ILS/web/templates/default/conify/global/booking/resource.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/content/main/menu_frame_overlay.xul
trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties
trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.js
trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.xul
trunk/Open-ILS/xul/staff_client/server/cat/util.js
trunk/Open-ILS/xul/staff_client/server/locale/en-US/cat.properties
Log:
Patch from Lebbeous Fogle-Weekley to add booking reservation interfaces, supporting backend changes and IDL cleanup. It's ... big.
Modified: trunk/Open-ILS/examples/fm_IDL.xml
===================================================================
--- trunk/Open-ILS/examples/fm_IDL.xml 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/examples/fm_IDL.xml 2009-12-21 16:21:48 UTC (rev 15207)
@@ -2536,8 +2536,8 @@
<link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
<link field="summary" reltype="might_have" key="id" map="" class="mbts"/>
<link field="target_resource_type" reltype="has_a" key="id" map="" class="brt"/>
- <link field="target_resource" reltype="might_have" key="id" map="" class="brsrc"/>
- <link field="current_resource" reltype="might_have" key="id" map="" class="brsrc"/>
+ <link field="target_resource" reltype="has_a" key="id" map="" class="brsrc"/>
+ <link field="current_resource" reltype="has_a" key="id" map="" class="brsrc"/>
<link field="request_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="pickup_lib" reltype="might_have" key="id" map="" class="aou"/>
<link field="capture_staff" reltype="might_have" key="id" map="" class="au"/>
Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm 2009-12-21 16:21:48 UTC (rev 15207)
@@ -12,8 +12,6 @@
my $U = "OpenILS::Application::AppUtils";
use OpenSRF::Utils::Logger qw/$logger/;
-use DateTime;
-use DateTime::Format::ISO8601;
sub prepare_new_brt {
my ($record_id, $owning_lib, $mvr) = @_;
@@ -34,7 +32,7 @@
{name => $mvr->title, owner => $owning_lib, record => $record_id}
);
- return $results->[0] if (length @$results > 0);
+ return $results->[0] if scalar(@$results) > 0;
return undef;
}
@@ -72,21 +70,26 @@
return $record_id;
}
-__PACKAGE__->register_method(
- method => "create_brt_and_brsrc",
- api_name => "open-ils.booking.create_brt_and_brsrc_from_copies",
- signature => {
- params => [
- {type => 'string', desc => 'Authentication token'},
- {type => 'array', desc => 'Copy IDs'},
- ],
- return => { desc => "A two-element hash. The 'brt' element " .
- "is a list of created booking resource types described by " .
- "id/copyid pairs. The 'brsrc' element is a similar " .
- "list of created booking resources described by copy/recordid " .
- "pairs"}
- }
-);
+# This function generates the correct json_query clause for determining
+# whether two given ranges overlap. Each range is composed of a start
+# and an end point. All four points should be the same type (could be int,
+# date, time, timestamp, or perhaps other types).
+#
+# The first range (or the first two points) should be specified as
+# literal values. The second range (or the last two points) should be
+# specified as the names of columns, the values of which in a given row
+# will constitute the second range in the comparison.
+#
+# ALSO: PostgreSQL includes an OVERLAPS operator which provides the same
+# functionality in a much more concise way, but json_query does not (yet).
+sub json_query_ranges_overlap {
+ +{ '-or' => [
+ { '-and' => [{$_[2] => {'>=', $_[0]}}, {$_[2] => {'<', $_[1]}}]},
+ { '-and' => [{$_[3] => {'>', $_[0]}}, {$_[3] => {'<', $_[1]}}]},
+ { '-and' => { $_[3] => {'>', $_[0]}, $_[2] => {'<=', $_[0]}}},
+ { '-and' => { $_[3] => {'>', $_[1]}, $_[2] => {'<', $_[1]}}},
+ ]};
+}
sub create_brt_and_brsrc {
my ($self, $conn, $authtoken, $copy_ids) = @_;
@@ -106,39 +109,59 @@
}
while (my ($owning_lib, $brt) = each %brt_table) {
+ my $pre_existing = 1;
if ($brt->isnew) {
- if ($e->allowed('CREATE_BOOKING_RESOURCE_TYPE', $owning_lib)) {
- # We can/should abort if this creation fails, because the
- # logic isn't going to be trying to create any redundnat
- # brt's, therefore any error will be more serious than
- # that. See the different take on creating brsrc's below.
+ if ($e->allowed('ADMIN_BOOKING_RESOURCE_TYPE', $owning_lib)) {
+ $pre_existing = 0;
return $e->die_event unless (
# v-- Important: assignment modifies original hash
$brt = $e->create_booking_resource_type($brt)
);
}
- push @created_brt, [$brt->id, $brt->record];
}
+ push @created_brt, [$brt->id, $brt->record, $pre_existing];
}
foreach (@copies) {
- if (
- $e->allowed('CREATE_BOOKING_RESOURCE', $_->call_number->owning_lib)
- ) {
+ if ($e->allowed(
+ 'ADMIN_BOOKING_RESOURCE', $_->call_number->owning_lib
+ )) {
+ # This block needs to disregard any cstore failures and just
+ # return what results it can.
my $brsrc = new Fieldmapper::booking::resource;
$brsrc->isnew(1);
$brsrc->type($brt_table{$_->call_number->owning_lib}->id);
$brsrc->owner($_->call_number->owning_lib);
$brsrc->barcode($_->barcode);
- # We don't want to abort the transaction or do anything dramatic if
- # this fails, because quite possibly a user selected many copies on
- # which to perform this "create booking resource" operation, and
- # among those copies there may be some that we still need to
- # create, and some that we don't. So we just do what we can.
- push @created_brsrc, [$brsrc->id, $_->id] if
- ($brsrc = $e->create_booking_resource($brsrc));
- # ^--- Important: assignment.
+ $e->set_savepoint("alpha");
+ my $pre_existing = 0;
+ my $usable_result = undef;
+ if (!($usable_result = $e->create_booking_resource($brsrc))) {
+ $e->rollback_savepoint("alpha");
+ if (($usable_result = $e->search_booking_resource(
+ +{ map { ($_, $brsrc->$_()) } qw/type owner barcode/ }
+ ))) {
+ $usable_result = $usable_result->[0];
+ $pre_existing = 1;
+ } else {
+ # So we failed to create a booking resource for this copy.
+ # For now, let's just keep going. If the calling app wants
+ # to consider this an error, it can notice the absence
+ # of a booking resource for the copy in the returned
+ # results.
+ $logger->warn(
+ "Couldn't create or find brsrc for acp #" . $_->id
+ );
+ }
+ } else {
+ $e->release_savepoint("alpha");
+ }
+
+ if ($usable_result) {
+ push @created_brsrc,
+ [$usable_result->id, $_->id, $pre_existing];
+ }
}
}
@@ -146,18 +169,120 @@
return {brt => \@created_brt, brsrc => \@created_brsrc} or
return $e->die_event;
}
+__PACKAGE__->register_method(
+ method => "create_brt_and_brsrc",
+ api_name => "open-ils.booking.resources.create_from_copies",
+ signature => {
+ params => [
+ {type => 'string', desc => 'Authentication token'},
+ {type => 'array', desc => 'Copy IDs'},
+ ],
+ return => { desc => "A two-element hash. The 'brt' element " .
+ "is a list of created booking resource types described by " .
+ "3-tuples (id, copy id, was pre-existing). The 'brsrc' " .
+ "element is a similar list of created booking resources " .
+ "described by (id, record id, was pre-existing) 3-tuples."}
+ }
+);
+
+sub create_bresv {
+ my ($self, $client, $authtoken,
+ $target_user_barcode, $datetime_range,
+ $brt, $brsrc_list, $attr_values) = @_;
+
+ $brsrc_list = [ undef ] if not defined $brsrc_list;
+ return undef if scalar(@$brsrc_list) < 1; # Empty list not ok.
+
+ my $e = new_editor(xact => 1, authtoken => $authtoken);
+ return $e->die_event unless (
+ $e->checkauth and
+ $e->allowed("ADMIN_BOOKING_RESERVATION") and
+ $e->allowed("ADMIN_BOOKING_RESERVATION_ATTR_MAP")
+ );
+
+ my $usr = $U->fetch_user_by_barcode($target_user_barcode);
+ return $usr if ref($usr) eq 'HASH' and exists($usr->{"ilsevent"});
+
+ my $results = [];
+ foreach my $brsrc (@$brsrc_list) {
+ 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->start_time($datetime_range->[0]);
+ $bresv->end_time($datetime_range->[1]);
+
+ # A little sanity checking: don't agree to put a reservation on a
+ # 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);
+ }
+ $bresv->target_resource($brsrc); # undef is ok here
+ $bresv->target_resource_type($brt);
+
+ ($bresv = $e->create_booking_reservation($bresv)) or
+ return $e->die_event;
+
+ # We could/should do some sanity checking on this too: namely, on
+ # whether the attribute values given actually apply to the relevant
+ # brt. Not seeing any grievous side effects of not checking, though.
+ my @bravm = ();
+ foreach my $value (@$attr_values) {
+ my $bravm = new Fieldmapper::booking::reservation_attr_value_map;
+ $bravm->reservation($bresv->id);
+ $bravm->attr_value($value);
+ $bravm = $e->create_booking_reservation_attr_value_map($bravm) or
+ return $e->die_event;
+ push @bravm, $bravm;
+ }
+ push @$results, {
+ "bresv" => $bresv->id,
+ "bravm" => \@bravm,
+ };
+ }
+
+ $e->commit or return $e->die_event;
+
+ # Targeting must be tacked on _after_ committing the transaction where the
+ # reservations are actually created.
+ foreach (@$results) {
+ $_->{"targeting"} = $U->storagereq(
+ "open-ils.storage.booking.reservation.resource_targeter",
+ $_->{"bresv"}
+ )->[0];
+ }
+ return $results;
+}
+__PACKAGE__->register_method(
+ method => "create_bresv",
+ api_name => "open-ils.booking.reservations.create",
+ signature => {
+ params => [
+ {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 => 'Booking resource type'},
+ {type => 'list', desc => 'Booking resource (undef ok; empty not ok)'},
+ {type => 'array', desc => 'Attribute values selected'},
+ ],
+ return => { desc => "A hash containing the new bresv and a list " .
+ "of new bravm"}
+ }
+);
+
+
sub resource_list_by_attrs {
my $self = shift;
my $client = shift;
- my $auth = shift;
+ my $auth = shift; # Keep as argument, though not used just now.
my $filters = shift;
return undef unless ($filters->{type} || $filters->{attribute_values});
- my $e = new_editor(authtoken=>$auth);
- return $e->event unless $e->checkauth;
-
my $query = {
'select' => { brsrc => [ 'id' ] },
'from' => { brsrc => {} },
@@ -165,8 +290,9 @@
'distinct' => 1
};
+ $query->{where} = {"-and" => []};
if ($filters->{type}) {
- $query->{where}->{type} = $filters->{type};
+ push @{$query->{where}->{"-and"}}, {"type" => $filters->{type}};
}
if ($filters->{attribute_values}) {
@@ -178,95 +304,82 @@
$query->{having}->{'+bram'}->{value}->{'@>'} = {
transform => 'array_accum',
- value => '$'.$$.'${'.join(',', @{ $filters->{attribute_values} } ).'}$'.$$.'$'
+ value => '$_' . $$ . '${' .
+ join(',', @{$filters->{attribute_values}}) .
+ '}$_' . $$ . '$'
};
}
if ($filters->{available}) {
- $query->{from}->{brsrc}->{bresv} = { field => 'current_resource' };
+ # If only one timestamp has been provided, make it into a range.
+ if (!ref($filters->{available})) {
+ $filters->{available} = [($filters->{available}) x 2];
+ }
- if (!ref($filters->{available})) { # just one time, start perhaps
- $query->{where}->{'+bresv'} = {
- '-or' => [
- { '+brsrc' => {'overbook' => 't'} },
- { '-or' =>
- { start_time => { '>=' => $filters->{available} },
- end_time => { '<=' => $filters->{available} },
- }
- }
- ]
- };
- } else { # start and end times
- $query->{where}->{'+bresv'} = {
- '-or' => [
- { '+brsrc' => {'overbook' => 't'} },
- { '-and' =>
- [{ '-or' =>
- { start_time => { '>=' => $filters->{available}->[0] },
- end_time => { '<=' => $filters->{available}->[0] },
- }
- },{'-or' =>
- { start_time => { '>=' => $filters->{available}->[1] },
- end_time => { '<=' => $filters->{available}->[1] },
- }
- }]
- }
- ]
- };
- }
+ push @{$query->{where}->{"-and"}}, {
+ "-or" => [
+ {"overbook" => "t"},
+ {"-not-exists" => {
+ "select" => {"bresv" => ["id"]},
+ "from" => "bresv",
+ "where" => {"-and" => [
+ json_query_ranges_overlap(
+ $filters->{available}->[0],
+ $filters->{available}->[1],
+ "start_time",
+ "end_time"
+ ),
+ {"cancel_time" => undef},
+ {"current_resource" => {"=" => {"+brsrc" => "id"}}}
+ ]},
+ }}
+ ]
+ };
}
-
if ($filters->{booked}) {
- $query->{from}->{brsrc}->{bresv} = { field => 'current_resource' };
+ # If only one timestamp has been provided, make it into a range.
+ if (!ref($filters->{booked})) {
+ $filters->{booked} = [($filters->{booked}) x 2];
+ }
- if (!ref($filters->{booked})) { # just one time, start perhaps
- $query->{where}->{'+bresv'} = {
- start_time => { '<=' => $filters->{booked} },
- end_time => { '>=' => $filters->{booked} },
- };
- } else { # start and end times
- $query->{where}->{'+bresv'} = {
- '-or' => {
- '-and' => {
- start_time => { '<=' => $filters->{booked}->[0] },
- end_time => { '>=' => $filters->{booked}->[0] },
- },
- '-and' => {
- start_time => { '<=' => $filters->{booked}->[1] },
- end_time => { '>=' => $filters->{booked}->[1] },
- }
- }
- };
- }
+ push @{$query->{where}->{"-and"}}, {
+ "-exists" => {
+ "select" => {"bresv" => ["id"]},
+ "from" => "bresv",
+ "where" => {"-and" => [
+ json_query_ranges_overlap(
+ $filters->{booked}->[0],
+ $filters->{booked}->[1],
+ "start_time",
+ "end_time"
+ ),
+ {"cancel_time" => undef},
+ {"current_resource" => { "=" => {"+brsrc" => "id"}}}
+ ]},
+ }
+ };
+ # I think that the "booked" case could be done with a JOIN instead of
+ # an EXISTS, but I'm leaving it this way for symmetry with the
+ # "available" case for now. The available case cannot be done with a
+ # join.
}
my $cstore = OpenSRF::AppSession->connect('open-ils.cstore');
- my $ids = $cstore->request( 'open-ils.cstore.json_query.atomic', $query )->gather(1);
+ my $rows = $cstore->request( 'open-ils.cstore.json_query.atomic', $query )->gather(1);
$cstore->disconnect;
- if (@$ids) {
- $ids = [ map { $_->{id} } @$ids ];
-
- my $pcrud = OpenSRF::AppSession->connect('open-ils.pcrud');
- my $allowed_ids = $pcrud->request(
- 'open-ils.pcrud.id_list.brsrc.atomic',
- $auth => { id => $ids }
- )->gather(1);
- $pcrud->disconnect;
-
- return $allowed_ids;
- } else {
- return $ids; # empty []
- }
+ return @$rows ? [map { $_->{id} } @$rows] : [];
}
__PACKAGE__->register_method(
method => "resource_list_by_attrs",
api_name => "open-ils.booking.resources.filtered_id_list",
- argc => 2,
+ argc => 3,
signature=> {
params => [
- {type => 'string', desc => 'Authentication token'},
- {type => 'object', desc => 'Filter object -- see notes for details'}
+ {type => 'string', desc => 'Authentication token (unused for now,' .
+ ' but at least pass undef here)'},
+ {type => 'object', desc => 'Filter object: see notes for details'},
+ {type => 'bool', desc => 'Return whole objects instead of IDs?'}
],
return => { desc => "An array of brsrc ids matching the requested filters." },
},
@@ -285,23 +398,24 @@
Note that at least one of 'type' or 'attribute_values' is required.
NOTES
-
);
+
sub reservation_list_by_filters {
my $self = shift;
my $client = shift;
my $auth = shift;
my $filters = shift;
+ my $whole_obj = shift;
- return undef unless ($filters->{user} || $filters->{resource} || $filters->{type} || $filters->{attribute_values});
+ return undef unless ($filters->{user} || $filters->{user_barcode} || $filters->{resource} || $filters->{type} || $filters->{attribute_values});
my $e = new_editor(authtoken=>$auth);
return $e->event unless $e->checkauth;
return $e->event unless $e->allowed('VIEW_TRANSACTION');
my $query = {
- 'select' => { bresv => [ 'id' ] },
+ 'select' => { bresv => [ 'id', 'start_time' ] },
'from' => { bresv => {} },
'where' => {},
'order_by' => [{ class => bresv => field => start_time => direction => 'asc' }],
@@ -316,7 +430,13 @@
if ($filters->{user}) {
$query->{where}->{usr} = $filters->{user};
}
+ elsif ($filters->{user_barcode}) { # just one of user and user_barcode
+ my $usr = $U->fetch_user_by_barcode($filters->{user_barcode});
+ return $usr if ref($usr) eq 'HASH' and exists($usr->{"ilsevent"});
+ $query->{where}->{usr} = $usr->id;
+ }
+
if ($filters->{type}) {
$query->{where}->{target_resource_type} = $filters->{type};
}
@@ -334,12 +454,13 @@
$query->{having}->{'+bravm'}->{attr_value}->{'@>'} = {
transform => 'array_accum',
- value => '$'.$$.'${'.join(',', @{ $filters->{attribute_values} } ).'}$'.$$.'$'
+ value => '$_' . $$ . '${' .
+ join(',', @{$filters->{attribute_values}}) .
+ '}$_' . $$ . '$'
};
}
if ($filters->{search_start} || $filters->{search_end}) {
-
$query->{where}->{'-or'} = {};
$query->{where}->{'-or'}->{start_time} = { 'between' => [ $filters->{search_start}, $filters->{search_end} ] }
@@ -350,11 +471,25 @@
}
my $cstore = OpenSRF::AppSession->connect('open-ils.cstore');
- my $ids = $cstore->request( 'open-ils.cstore.json_query.atomic', $query )->gather(1);
- $ids = [ map { $_->{id} } @$ids ];
+ my $ids = [ map { $_->{id} } @{
+ $cstore->request(
+ 'open-ils.cstore.json_query.atomic', $query
+ )->gather(1)
+ } ];
$cstore->disconnect;
- return $ids;
+ return $ids if not $whole_obj;
+
+ my $bresv_list = $e->search_booking_reservation([
+ {"id" => $ids},
+ {"flesh" => 1,
+ "flesh_fields" => {
+ "bresv" =>
+ [qw/target_resource current_resource target_resource_type/]
+ }
+ }]
+ );
+ return $bresv_list ? $bresv_list : [];
}
__PACKAGE__->register_method(
method => "reservation_list_by_filters",
@@ -365,12 +500,13 @@
{type => 'string', desc => 'Authentication token'},
{type => 'object', desc => 'Filter object -- see notes for details'}
],
- return => { desc => "An array of brsrc ids matching the requested filters." },
+ return => { desc => "An array of bresv ids matching the requested filters." },
},
notes => <<'NOTES'
The filter object parameter can contain the following keys:
* user => The id of a user that has requested a bookable item -- filters on bresv.usr
+ * barcode => The barcode of a user that has requested a bookable item
* type => The id of a booking resource type (brt) -- filters on bresv.target_resource_type
* resource => The id of a booking resource (brsrc) -- filters on bresv.target_resource
* attribute_values => The ids of booking resource type attribute values that the resource must have assigned to it (brav)
@@ -383,8 +519,6 @@
by the top-level filters ('user', 'type', 'resource').
NOTES
-
);
-
1;
Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm 2009-12-21 16:21:48 UTC (rev 15207)
@@ -28,7 +28,7 @@
use base qw/booking/;
__PACKAGE__->table('booking_reservation');
__PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/xact_start usr current_copy circ_lib
+__PACKAGE__->columns(Essential => qw/xact_start usr current_resource
fine_amount max_fine fine_interval xact_finish
capture_staff pickup_lib request_time start_time end_time
capture_time cancel_time pickup_time return_time
Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm 2009-12-21 16:21:48 UTC (rev 15207)
@@ -1332,7 +1332,7 @@
try {
if ($one_reservation) {
$self->method_lookup('open-ils.storage.transaction.begin')->run( $client );
- $reservations = booking::reservation->search_where( { id => $one_reservation, capture_time => undef, cancel_time => undef } );
+ $reservations = [ booking::reservation->search_where( { id => $one_reservation, capture_time => undef, cancel_time => undef } ) ];
} else {
# find all the reservations needing targeting
@@ -1351,6 +1351,7 @@
die "Could not retrieve reservation requests:\n\n$e\n";
};
+ my @successes = ();
for my $bresv (@$reservations) {
try {
#start a transaction if needed
@@ -1383,27 +1384,27 @@
die "OK\n";
}
- my $possible_resources;
+ my $possible_resources;
# find all the potential resources
if (!$bresv->target_resource) {
- my $filter = { type => $bresv->target_resource_type };
- my $attr_maps = booking::reservations_attr_value_map->search( reservation => $bresv->id );
+ my $filter = { type => $bresv->target_resource_type };
+ my $attr_maps = [ booking::reservation_attr_value_map->search( reservation => $bresv->id) ];
- $filter->{attribute_values} = [ map { $_->attr_value } @$attr_maps ] if (@$attr_maps);
+ $filter->{attribute_values} = [ map { $_->attr_value } @$attr_maps ] if (@$attr_maps);
- my $ses = OpenSRF::AppSession->create('open-ils.booking');
- $possible_resources = $ses->request('open-ils.booking.resources.filtered_id_list', $filter)->gather(1);
-
+ $filter->{available} = [$bresv->start_time, $bresv->end_time];
+ my $ses = OpenSRF::AppSession->create('open-ils.booking');
+ $possible_resources = $ses->request('open-ils.booking.resources.filtered_id_list', undef, $filter)->gather(1);
} else {
$possible_resources = $bresv->target_resource;
}
- my $all_resources = booking::resource->search( id => $possible_resources );
+ my $all_resources = [ booking::resource->search( id => $possible_resources ) ];
@$all_resources = grep { isTrue($_->type->transferable) || $_->owner.'' eq $bresv->pickup_lib.'' } @$all_resources;
- my @good_resources;
+ my @good_resources = ();
for my $res (@$all_resources) {
unless (isTrue($res->type->catalog_item)) {
push @good_resources, $res;
@@ -1495,16 +1496,16 @@
}
$self->method_lookup('open-ils.storage.transaction.commit')->run;
- $log->info("\tProcessing of hold ".$hold->id." complete.");
+ $log->info("\tProcessing of bresv ".$bresv->id." complete.");
push @successes,
- { reservation => $hold->id,
+ { reservation => $bresv->id,
current_resource => ($best ? $best->id : undef) };
} otherwise {
my $e = shift;
if ($e !~ /^OK/o) {
- $log->error("Processing of hold failed: $e");
+ $log->error("Processing of bresv failed: $e");
$self->method_lookup('open-ils.storage.transaction.rollback')->run;
throw $e if ($e =~ /IS NOT CONNECTED TO THE NETWORK/o);
}
Modified: trunk/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm 2009-12-21 16:21:48 UTC (rev 15207)
@@ -258,7 +258,7 @@
my $name = shift || 'savepoint';
return unless $self->{session} and $self->{xact_id};
$self->log(I, "setting savepoint '$name'");
- my $stat = $self->request($self->app.".savepoint.set")
+ my $stat = $self->request($self->app.".savepoint.set", $name)
or $self->log(E, "error setting savepoint '$name'");
return $stat;
}
@@ -268,7 +268,7 @@
my $name = shift || 'savepoint';
return unless $self->{session} and $self->{xact_id};
$self->log(I, "releasing savepoint '$name'");
- my $stat = $self->request($self->app.".savepoint.release")
+ my $stat = $self->request($self->app.".savepoint.release", $name)
or $self->log(E, "error releasing savepoint '$name'");
return $stat;
}
@@ -278,7 +278,7 @@
my $name = shift || 'savepoint';
return unless $self->{session} and $self->{xact_id};
$self->log(I, "rollback savepoint '$name'");
- my $stat = $self->request($self->app.".savepoint.rollback")
+ my $stat = $self->request($self->app.".savepoint.rollback", $name)
or $self->log(E, "error rolling back savepoint '$name'");
return $stat;
}
Added: trunk/Open-ILS/web/css/skin/default/booking.css
===================================================================
--- trunk/Open-ILS/web/css/skin/default/booking.css (rev 0)
+++ trunk/Open-ILS/web/css/skin/default/booking.css 2009-12-21 16:21:48 UTC (rev 15207)
@@ -0,0 +1,48 @@
+div#brsrc_available_outer {
+ width: 50%;
+ float: left;
+ border-right: 1px solid #999999;
+}
+div#bra_and_brav {
+}
+div#reserve_right_side {
+ float: right;
+ width: 49%;
+ padding-left: 4px;
+}
+div#reserve_under {
+ clear: both;
+}
+div#reserve_datetime_start {
+ padding-bottom: 6px;
+}
+div#reserve_datetime_end {
+ padding-bottom: 6px;
+ border-bottom: 1px solid #999999;
+}
+label.bra {
+ font-style: italic;
+ padding-right: 12px;
+}
+h1.booking, h2.booking {
+ margin: 0;
+ padding-top: 0;
+ padding-bottom: 8px;
+}
+select#brsrc_list {
+ width: 90%;
+}
+label.reserve_datetime {
+ font-style: italic;
+ margin-bottom: 2px;
+}
+id#patron_barcode {
+ width: 150px;
+}
+div.nice_vertical_padding {
+ padding-top: 6px;
+ padding-bottom: 6px;
+}
+span.two_buttons {
+ text-align: center;
+}
Added: trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js (rev 0)
+++ trunk/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js 2009-12-21 16:21:48 UTC (rev 15207)
@@ -0,0 +1,53 @@
+{
+ 'NO_BRT_RESULTS': "There are no bookable resource types registered.",
+ 'NO_TARG_DIV': "Could not find target div",
+ 'NO_BRA_RESULTS': "Couldn't retrieve booking resource attributes.",
+ 'SELECT_A_BRSRC_THEN': "Select a resource from the big list above.",
+ '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: ",
+ /* FIXME: Users aren't likely to be able to do anything with the following
+ * message. Figure out a way to do something more helpful.
+ */
+ 'CREATE_BRESV_OK_MISSING_TARGET': function(n, m) {
+ return "Created " + n + " reservation(s), but " + m + " of these " +
+ "couldn't target any resources.";
+ },
+ 'CREATE_BRESV_OK': function(n) {
+ return "Created " + n + " reservation" + (n == 1 ? "" : "s") + ".";
+ },
+ 'WHERES_THE_BARCODE': "Enter a patron's barcode to make a reservation.",
+ 'ACTOR_CARD_NOT_FOUND': "Patron barcode not found. Please try again.",
+ 'GET_BRESV_LIST_ERR': "Error while retrieving reservation list: ",
+ 'GET_BRESV_LIST_NO_RESULT': "No results from server " +
+ "retrieving reservation list.",
+ 'OUTSTANDING_BRESV': "Outstanding reservations for patron",
+ 'UNTARGETED': "None targeted",
+ 'GET_PATRON_NO_RESULT': "No server response after attempting to " +
+ "look up patron by barcode.",
+ 'HERE_ARE_EXISTING_BRESV': "Existing reservations for",
+ 'CXL_BRESV_SUCCESS': function(n) {
+ return ("Canceled " + n + " reservation" + (n == 1 ? "" : "s") + ".");
+ },
+ 'CXL_BRESV_FAILURE': "Error canceling reservations.",
+ 'CXL_BRESV_SELECT_SOMETHING': "You have not selected any reservations to " +
+ "cancel.",
+ 'ANY': "ANY",
+
+ 'AUTO_choose_a_brt': "Choose a Bookable Resource Type",
+ 'AUTO_i_need_this_resource': "I need this resource...",
+ 'AUTO_starting_at': "Starting at",
+ 'AUTO_ending_at': "and ending at",
+ 'AUTO_with_these_attr': "With these attributes:",
+ 'AUTO_patron_barcode': "Reserve to patron barcode:",
+ 'AUTO_ATTR_VALUE_next': "Next",
+ 'AUTO_ATTR_VALUE_reserve_brsrc': "Reserve Selected",
+ 'AUTO_ATTR_VALUE_reserve_brt': "Reserve Any",
+ 'AUTO_ATTR_VALUE_button_edit_existing': "Edit selected",
+ 'AUTO_ATTR_VALUE_button_cancel_existing': "Cancel selcted",
+ 'AUTO_bresv_grid_type': "Type",
+ 'AUTO_bresv_grid_resource': "Resource",
+ 'AUTO_bresv_grid_start_time': "Start time",
+ 'AUTO_bresv_grid_end_time': "End time"
+}
Added: trunk/Open-ILS/web/js/ui/default/booking/reservation.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/booking/reservation.js (rev 0)
+++ trunk/Open-ILS/web/js/ui/default/booking/reservation.js 2009-12-21 16:21:48 UTC (rev 15207)
@@ -0,0 +1,589 @@
+/*
+ * Details, details...
+ */
+dojo.require("fieldmapper.OrgUtils");
+dojo.require("openils.PermaCrud");
+dojo.require("dojo.data.ItemFileReadStore");
+dojo.require("dijit.form.DateTextBox");
+dojo.require("dijit.form.TimeTextBox");
+dojo.requireLocalization("openils.booking", "reservation");
+
+/*
+ * Globals; prototypes and their instances
+ */
+var localeStrings = dojo.i18n.getLocalization("openils.booking", "reservation");
+var pcrud = new openils.PermaCrud();
+var our_brt;
+var brsrc_index = {};
+var bresv_index = {};
+
+function AttrValueTable() { this.t = {}; }
+AttrValueTable.prototype.set = function(attr, value) { this.t[attr] = value; };
+AttrValueTable.prototype.update_from_selector = function(selector) {
+ var attr = selector.name.match(/_(\d+)$/)[1];
+ var value = selector.options[selector.selectedIndex].value;
+ if (attr)
+ attr_value_table.set(attr, value);
+};
+AttrValueTable.prototype.get_all_values = function() {
+ var values = [];
+ for (var k in this.t) {
+ if (this.t[k] != undefined && this.t[k] != "")
+ values.push(this.t[k]);
+ }
+ return values;
+};
+var attr_value_table = new AttrValueTable();
+
+function TimestampRange() {
+ this.start = {"date": undefined, "time": undefined};
+ this.end = {"date": undefined, "time": undefined};
+}
+TimestampRange.prototype.get_timestamp = function(when) {
+ return (this[when].date + " " + this[when].time);
+};
+TimestampRange.prototype.get_range = function() {
+ return this.is_backwards() ?
+ [this.get_timestamp("end"), this.get_timestamp("start")] :
+ [this.get_timestamp("start"), this.get_timestamp("end")];
+};
+TimestampRange.prototype.split_time = function(s) {
+ /* We're not interested in seconds for our purposes,
+ * so we floor everything to :00.
+ *
+ * Also, notice that following discards all time zone information
+ * from the timestamp string represenation. This should probably
+ * stay the way it is, even when this code is improved to support
+ * selecting time zones (it currently just assumes server's local
+ * time). The easy way to add support will be to add a drop-down
+ * selector from which the user can pick a time zone, then use
+ * that timezone literal in an "AT TIME ZONE" clause in SQL on
+ * the server side.
+ */
+ return s.split("T")[1].replace(/(\d{2}:\d{2}:)(\d{2})(.*)/, "$100");
+};
+TimestampRange.prototype.split_date = function(s) {
+ return s.split("T")[0];
+};
+TimestampRange.prototype.update_from_widget = function(widget) {
+ var when = widget.id.match(/(start|end)/)[1];
+ var which = widget.id.match(/(date|time)/)[1];
+
+ if (when && which) {
+ this[when][which] =
+ this["split_" + which](widget.serialize(widget.value));
+ }
+};
+TimestampRange.prototype.is_backwards = function() {
+ return (this.get_timestamp("start") > this.get_timestamp("end"));
+};
+var reserve_timestamp_range = new TimestampRange();
+
+function SelectorMemory(selector) {
+ this.selector = selector;
+ this.memory = {};
+}
+SelectorMemory.prototype.save = function() {
+ for (var i = 0; i < this.selector.options.length; i++) {
+ if (this.selector.options[i].selected) {
+ this.memory[this.selector.options[i].value] = true;
+ }
+ }
+};
+SelectorMemory.prototype.restore = function() {
+ for (var i = 0; i < this.selector.options.length; i++) {
+ if (this.memory[this.selector.options[i].value]) {
+ this.selector.options[i].selected = true;
+ }
+ }
+};
+
+/*
+ * Misc helper functions
+ */
+function hide_dom_element(e) { e.style.display = "none"; };
+function reveal_dom_element(e) { e.style.display = ""; };
+function get_keys(L) { var K = []; for (var k in L) K.push(k); return K; }
+function formal_name(u) {
+ var name = u.family_name() + ", " + u.first_given_name();
+ if (u.second_given_name())
+ name += (" " + u.second_given_name());
+ return name;
+}
+function humanize_timestamp_string(ts) {
+ /* For now, this discards time zones. */
+ var parts = ts.split("T");
+ var timeparts = parts[1].split("-")[0].split(":");
+ return parts[0] + " " + timeparts[0] + ":" + timeparts[1];
+}
+function set_datagrid_empty_store(grid) {
+ grid.setStore(
+ new dojo.data.ItemFileReadStore(
+ {"data": flatten_to_dojo_data([])}
+ )
+ );
+}
+function is_ils_error(e) { return (e.ilsevent != undefined); }
+function is_ils_actor_card_error(e) {
+ return (e.textcode == "ACTOR_CARD_NOT_FOUND");
+}
+function my_ils_error(header, e) {
+ var s = header + "\n";
+ var keys = [
+ "ilsevent", "desc", "textcode", "servertime", "pid", "stacktrace"
+ ];
+ for (var i in keys) {
+ if (e[keys[i]]) s += ("\t" + keys[i] + ": " + e[keys[i]] + "\n");
+ }
+ return s;
+}
+
+/*
+ * These functions communicate with the middle layer.
+ */
+function get_all_noncat_brt() {
+ return pcrud.search("brt",
+ {"id": {"!=": null}, "catalog_item": "f"},
+ {"order_by": {"brt":"name"}}
+ );
+}
+
+function get_brsrc_id_list() {
+ var options = {"type": our_brt.id()};
+
+ /* This mechanism for avoiding the passing of an empty 'attribute_values'
+ * option is essential because if you pass such an option to the
+ * middle layer API at all, it won't return any IDs for brsrcs that
+ * don't have at least one attribute of some kind.
+ */
+ var attribute_values = attr_value_table.get_all_values();
+ if (attribute_values.length > 0)
+ options.attribute_values = attribute_values;
+
+ options.available = reserve_timestamp_range.get_range();
+
+ return fieldmapper.standardRequest(
+ ["open-ils.booking", "open-ils.booking.resources.filtered_id_list"],
+ [xulG.auth.session.key, options]
+ );
+}
+
+// FIXME: We need failure checking after pcrud.retrieve()
+function sync_brsrc_index_from_ids(id_list) {
+ /* One pass to populate the cache with anything that's missing. */
+ for (var i in id_list) {
+ if (!brsrc_index[id_list[i]]) {
+ brsrc_index[id_list[i]] = pcrud.retrieve("brsrc", id_list[i]);
+ }
+ brsrc_index[id_list[i]].isdeleted(false); // See NOTE below.
+ }
+ /* A second pass to indicate any entries in the cache to be hidden. */
+ for (var i in brsrc_index) {
+ if (id_list.indexOf(Number(i)) < 0) { // Number() is important.
+ brsrc_index[i].isdeleted(true); // See NOTE below.
+ }
+ }
+ /* NOTE: We lightly abuse the isdeleted() magic attribute of the brsrcs
+ * in our cache. Because we're not going to pass back any brsrcs to
+ * the middle layer, it doesn't really matter what we set this attribute
+ * to. What we're using it for is to indicate in our little brsrc cache
+ * whether a given brsrc should be displayed in this UI's current state
+ * (based on whether it was returned by the last call to the middle layer,
+ * i.e., whether it matches the currently selected attributes).
+ */
+}
+
+function check_bresv_targeting(results) {
+ var missing = 0;
+ for (var i in results) {
+ if (!(results[i].targeting && results[i].targeting.current_resource))
+ missing++;
+ }
+ return missing;
+}
+
+function create_bresv(resource_list) {
+ var barcode = document.getElementById("patron_barcode").value;
+ if (barcode == "") {
+ alert(localeStrings.WHERES_THE_BARCODE);
+ return;
+ }
+ var results;
+ try {
+ results = fieldmapper.standardRequest(
+ ["open-ils.booking", "open-ils.booking.reservations.create"],
+ [
+ xulG.auth.session.key,
+ barcode,
+ reserve_timestamp_range.get_range(),
+ our_brt.id(),
+ resource_list,
+ attr_value_table.get_all_values()
+ ]
+ );
+ } catch (E) {
+ alert(localeStrings.CREATE_BRESV_LOCAL_ERROR + E);
+ }
+ if (results) {
+ if (is_ils_error(results)) {
+ if (is_ils_actor_card_error(results)) {
+ alert(localeStrings.ACTOR_CARD_NOT_FOUND);
+ } else {
+ alert(my_ils_error(
+ localeStrings.CREATE_BRESV_SERVER_ERROR, results
+ ));
+ }
+ } else {
+ var missing;
+ alert((missing = check_bresv_targeting(results)) ?
+ localeStrings.CREATE_BRESV_OK_MISSING_TARGET(
+ results.length, missing
+ ) :
+ localeStrings.CREATE_BRESV_OK(results.length)
+ );
+ update_brsrc_list();
+ update_bresv_grid();
+ }
+ } else {
+ alert(localeStrings.CREATE_BRESV_SERVER_NO_RESPONSE);
+ }
+}
+
+function flatten_to_dojo_data(obj_list) {
+ return {
+ "label": "id",
+ "identifier": "id",
+ "items": obj_list.map(function(o) {
+ var new_obj = {
+ "id": o.id(),
+ "type": o.target_resource_type().name(),
+ "start_time": humanize_timestamp_string(o.start_time()),
+ "end_time": humanize_timestamp_string(o.end_time()),
+ };
+
+ if (o.current_resource())
+ new_obj["resource"] = o.current_resource().barcode();
+ else if (o.target_resource())
+ new_obj["resource"] = "* " + o.target_resource().barcode();
+ else
+ new_obj["resource"] = "* " + localeStrings.UNTARGETED + " *";
+ return new_obj;
+ })
+ };
+}
+
+function create_bresv_on_brsrc() {
+ var selector = document.getElementById("brsrc_list");
+ var selected_values = [];
+ for (var i in selector.options) {
+ if (selector.options[i].selected)
+ selected_values.push(selector.options[i].value);
+ }
+ if (selected_values.length > 0)
+ create_bresv(selected_values);
+ else
+ alert(localeStrings.SELECT_A_BRSRC_THEN);
+}
+
+function create_bresv_on_brt() { create_bresv(); }
+
+function get_actor_by_barcode(barcode) {
+ var usr = fieldmapper.standardRequest(
+ ["open-ils.actor", "open-ils.actor.user.fleshed.retrieve_by_barcode"],
+ [xulG.auth.session.key, barcode]
+ );
+ if (usr == null) {
+ alert(localeStrings.GET_PATRON_NO_RESULT);
+ } else if (is_ils_error(usr)) {
+ return null; /* XXX inelegant: this function is quiet about errors
+ here because to report them would be redundant with
+ another function that gets called right after this one.
+ */
+ } else {
+ return usr;
+ }
+}
+
+function init_bresv_grid(barcode) {
+ var result = fieldmapper.standardRequest(
+ ["open-ils.booking",
+ "open-ils.booking.reservations.filtered_id_list"
+ ],
+ [xulG.auth.session.key, {
+ "user_barcode": barcode,
+ "fields": {
+ "pickup_time": null,
+ "cancel_time": null,
+ "return_time": null
+ }
+ }, /* whole_obj */ true]
+ );
+ if (result == null) {
+ set_datagrid_empty_store(bresvGrid);
+ alert(localeStrings.GET_BRESV_LIST_NO_RESULT);
+ } else if (is_ils_error(result)) {
+ set_datagrid_empty_store(bresvGrid);
+ if (is_ils_actor_card_error(result)) {
+ alert(localeStrings.ACTOR_CARD_NOT_FOUND);
+ } else {
+ alert(my_ils_error(localeStrings.GET_BRESV_LIST_ERR, result));
+ }
+ } else {
+ bresvGrid.setStore(
+ new dojo.data.ItemFileReadStore(
+ {"data": flatten_to_dojo_data(result)}
+ )
+ );
+ for (var i in result) {
+ bresv_index[result[i].id()] = result[i];
+ }
+ }
+}
+
+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);
+ }
+ }
+ );
+}
+
+/*
+ * These functions deal with interface tricks (populating widgets,
+ * changing the page, etc.).
+ */
+function provide_brt_selector(targ_div) {
+ if (!targ_div) {
+ alert(localeStrings.NO_TARG_DIV);
+ } else {
+ var brt_list = xulG.brt_list = get_all_noncat_brt();
+ if (!brt_list || brt_list.length < 1) {
+ targ_div.appendChild(
+ document.createTextNode(localeStrings.NO_BRT_RESULTS)
+ );
+ } else {
+ var selector = document.createElement("select");
+ selector.setAttribute("id", "brt_selector");
+ selector.setAttribute("name", "brt_selector");
+ /* I'm reluctantly hardcoding this "size" attribute as 8
+ * because you can't accomplish this with CSS anyway.
+ */
+ selector.setAttribute("size", 8);
+ for (var i in brt_list) {
+ var option = document.createElement("option");
+ option.setAttribute("value", brt_list[i].id());
+ option.appendChild(document.createTextNode(brt_list[i].name()));
+ selector.appendChild(option);
+ }
+ targ_div.appendChild(selector);
+ }
+ }
+}
+
+function init_reservation_interface(f) {
+ /* Hide and reveal relevant divs. */
+ var search_block = document.getElementById("brt_search_block");
+ var reserve_block = document.getElementById("brt_reserve_block");
+ hide_dom_element(search_block);
+ reveal_dom_element(reserve_block);
+
+ /* Save a global reference to the brt we're going to reserve */
+ our_brt = xulG.brt_list[f.brt_selector.selectedIndex];
+
+ /* Get a list of attributes that can apply to that brt. */
+ var bra_list = pcrud.search("bra", {"resource_type": our_brt.id()});
+ if (!bra_list) {
+ alert(localeString.NO_BRA_LIST);
+ return;
+ }
+
+ /* Get a table of values that can apply to the above attributes. */
+ var brav_by_bra = {};
+ bra_list.map(function(o) {
+ brav_by_bra[o.id()] = pcrud.search("brav", {"attr": o.id()});
+ });
+
+ /* Create DOM widgets to represent each attribute/values set. */
+ for (var i in bra_list) {
+ var bra_div = document.createElement("div");
+ bra_div.setAttribute("class", "nice_vertical_padding");
+
+ var bra_select = document.createElement("select");
+ bra_select.setAttribute("name", "bra_" + bra_list[i].id());
+ bra_select.setAttribute(
+ "onchange",
+ "attr_value_table.update_from_selector(this); update_brsrc_list();"
+ );
+
+ var bra_opt_any = document.createElement("option");
+ bra_opt_any.appendChild(document.createTextNode(localeStrings.ANY));
+ bra_opt_any.setAttribute("value", "");
+
+ bra_select.appendChild(bra_opt_any);
+
+ var bra_label = document.createElement("label");
+ bra_label.setAttribute("class", "bra");
+ bra_label.appendChild(document.createTextNode(bra_list[i].name()));
+
+ var j = bra_list[i].id();
+ for (var k in brav_by_bra[j]) {
+ var bra_opt = document.createElement("option");
+ bra_opt.setAttribute("value", brav_by_bra[j][k].id());
+ bra_opt.appendChild(
+ document.createTextNode(brav_by_bra[j][k].valid_value())
+ );
+ bra_select.appendChild(bra_opt);
+ }
+
+ bra_div.appendChild(bra_label);
+ bra_div.appendChild(bra_select);
+ document.getElementById("bra_and_brav").appendChild(bra_div);
+ }
+ /* Add a prominent label reminding the user what resource type they're
+ * asking about. */
+ document.getElementById("brsrc_list_header").innerHTML = our_brt.name();
+
+ update_brsrc_list();
+}
+
+function update_brsrc_list() {
+ var brsrc_id_list = get_brsrc_id_list();
+ sync_brsrc_index_from_ids(brsrc_id_list);
+
+ var target_selector = document.getElementById("brsrc_list");
+ var selector_memory = new SelectorMemory(target_selector);
+ selector_memory.save();
+ target_selector.innerHTML = "";
+
+ for (var i in brsrc_index) {
+ if (brsrc_index[i].isdeleted()) {
+ continue;
+ }
+ var opt = document.createElement("option");
+ opt.setAttribute("value", brsrc_index[i].id());
+ opt.appendChild(document.createTextNode(brsrc_index[i].barcode()));
+ target_selector.appendChild(opt);
+ }
+
+ selector_memory.restore();
+}
+
+function update_bresv_grid() {
+ var widg = document.getElementById("patron_barcode");
+ if (widg.value != "") {
+ setTimeout(function() {
+ var target = document.getElementById(
+ "existing_reservation_patron_line"
+ );
+ var patron = get_actor_by_barcode(widg.value);
+ if (patron) {
+ target.innerHTML = (
+ localeStrings.HERE_ARE_EXISTING_BRESV + " " +
+ formal_name(patron) + ": "
+ );
+ } else {
+ target.innerHTML = "";
+ }
+ }, 0);
+ setTimeout(function() { init_bresv_grid(widg.value); }, 0);
+
+ reveal_dom_element(document.getElementById("reserve_under"));
+ }
+}
+
+function init_timestamp_widgets() {
+ var when = ["start", "end"];
+ for (var i in when) {
+ reserve_timestamp_range.update_from_widget(
+ new dijit.form.TimeTextBox({
+ name: "reserve_time_" + when[i],
+ value: new Date(),
+ constraints: {
+ timePattern: "HH:mm",
+ clickableIncrement: "T00:15:00",
+ visibleIncrement: "T00:15:00",
+ visibleRange: "T01:30:00",
+ },
+ onChange: function() {
+ reserve_timestamp_range.update_from_widget(this);
+ update_brsrc_list();
+ }
+ }, "reserve_time_" + when[i])
+ );
+ reserve_timestamp_range.update_from_widget(
+ new dijit.form.DateTextBox({
+ name: "reserve_date_" + when[i],
+ value: new Date(),
+ onChange: function() {
+ reserve_timestamp_range.update_from_widget(this);
+ update_brsrc_list();
+ }
+ }, "reserve_date_" + when[i])
+ );
+ }
+}
+
+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]; })
+ );
+ } else {
+ alert(localeStrings.CXL_BRESV_SELECT_SOMETHING);
+ }
+}
+
+/* Quick and dirty way to localize some strings; not recommended for reuse.
+ * I'm sure dojo provides a better mechanism for this, but at the moment
+ * this is faster to implement anew than figuring out the Right way to do
+ * the same thing w/ dojo.
+ */
+function init_auto_l10n(el) {
+ function do_it(myel, cls) {
+ if (cls) {
+ var clss = cls.split(" ");
+ for (var k in clss) {
+ var parts = clss[k].match(/^AUTO_ATTR_([A-Z]+)_.+$/);
+ if (parts && localeStrings[clss[k]]) {
+ myel.setAttribute(
+ parts[1].toLowerCase(), localeStrings[clss[k]]
+ );
+ } else if (clss[k].match(/^AUTO_/) && localeStrings[clss[k]]) {
+ myel.innerHTML = localeStrings[clss[k]];
+ }
+ }
+ }
+ }
+
+ for (var i in el.attributes) {
+ if (el.attributes[i].nodeName == "class") {
+ do_it(el, el.attributes[i].value);
+ break;
+ }
+ }
+ for (var i in el.childNodes) {
+ if (el.childNodes[i].nodeType == 1) { // element node?
+ init_auto_l10n(el.childNodes[i]); // recurse!
+ }
+ }
+}
+
+/*
+ * my_init
+ */
+function my_init() {
+ hide_dom_element(document.getElementById("brt_reserve_block"));
+ reveal_dom_element(document.getElementById("brt_search_block"));
+ hide_dom_element(document.getElementById("reserve_under"));
+ provide_brt_selector(document.getElementById("brt_selector_here"));
+ init_auto_l10n(document.getElementById("auto_l10n_start_here"));
+ init_timestamp_widgets();
+}
Modified: trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
===================================================================
--- trunk/Open-ILS/web/opac/locale/en-US/lang.dtd 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/web/opac/locale/en-US/lang.dtd 2009-12-21 16:21:48 UTC (rev 15207)
@@ -273,7 +273,7 @@
<!ENTITY staff.cat.opac.undelete_record.accesskey "U">
<!ENTITY staff.cat.opac.undelete_record.label "Undelete Record">
<!ENTITY staff.cat.opac.create_brt_from_record.accesskey "T">
-<!ENTITY staff.cat.opac.create_brt_from_record.label "Create Booking Resource From Copy">
+<!ENTITY staff.cat.opac.create_brt_from_record.label "Make Item Bookable">
<!ENTITY staff.cat.opac.menu.accesskey "A">
<!ENTITY staff.cat.opac.menu.label "Actions for this Record">
<!ENTITY staff.cat.opac.opac_view.accesskey "O">
@@ -680,10 +680,6 @@
<!ENTITY staff.main.menu.admin.server_admin.booking.resource_attr_value.accesskey "V">
<!ENTITY staff.main.menu.admin.server_admin.booking.resource_attr_map.label "Resource Attribute Maps">
<!ENTITY staff.main.menu.admin.server_admin.booking.resource_attr_map.accesskey "M">
-<!ENTITY staff.main.menu.admin.server_admin.booking.reservation.label "Reservations">
-<!ENTITY staff.main.menu.admin.server_admin.booking.reservation.accesskey "N">
-<!ENTITY staff.main.menu.admin.server_admin.booking.reservation_attr_value_map.label "Reservation Attribute Value Maps">
-<!ENTITY staff.main.menu.admin.server_admin.booking.reservation_attr_value_map.accesskey "B">
<!ENTITY staff.main.menu.admin.developer.label "For developers...">
<!ENTITY staff.main.menu.admin.download_patrons.accesskey "D">
@@ -765,6 +761,15 @@
<!ENTITY staff.main.menu.acq.upload.label "Load Order Record">
<!ENTITY staff.main.menu.acq.po.label "Purchase Orders">
+<!ENTITY staff.main.menu.booking.label "Booking">
+<!ENTITY staff.main.menu.booking.accesskey "B">
+<!ENTITY staff.main.menu.booking.reservation.label "Create or Edit Reservations">
+<!ENTITY staff.main.menu.booking.reservation.accesskey "C">
+<!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">
+<!ENTITY staff.main.menu.booking.reservation_return.accesskey "R">
+
<!ENTITY staff.main.menu.acq.fund.label "Funds">
<!ENTITY staff.main.menu.acq.funding_source.label "Funding Sources">
<!ENTITY staff.main.menu.acq.provider.label "Providers">
@@ -2151,7 +2156,9 @@
<!ENTITY staff.cat.copy_browser.actions.cmd_add_items_to_buckets.accesskey "B">
<!ENTITY staff.cat.copy_browser.actions.sel_copy_details.label "Show Item Details">
<!ENTITY staff.cat.copy_browser.actions.sel_copy_details.accesskey "I">
-<!ENTITY staff.cat.copy_browser.actions.cmd_create_brt.label "Create Booking Resource Type from this Record">
+<!ENTITY staff.cat.copy_browser.actions.cmd_book_item_now.label "Book This Item">
+<!ENTITY staff.cat.copy_browser.actions.cmd_book_item_now.accesskey "K">
+<!ENTITY staff.cat.copy_browser.actions.cmd_create_brt.label "Make This Item Bookable">
<!ENTITY staff.cat.copy_browser.actions.cmd_create_brt.accesskey "Y">
<!ENTITY staff.cat.copy_browser.actions.sel_patron.label "Show Last Few Circulations">
<!ENTITY staff.cat.copy_browser.actions.sel_patron.accesskey "L">
@@ -2200,7 +2207,7 @@
<!ENTITY staff.cat.copy_browser.holdings_maintenance.add_items_to_bucket.accesskey "B">
<!ENTITY staff.cat.copy_browser.holdings_maintenance.sel_copy_details.label "Show Item Details">
<!ENTITY staff.cat.copy_browser.holdings_maintenance.sel_copy_details.accesskey "I">
-<!ENTITY staff.cat.copy_browser.holdings_maintenance.cmd_create_brt.label "Create Booking Resource Type from this Record">
+<!ENTITY staff.cat.copy_browser.holdings_maintenance.cmd_create_brt.label "Make This Item Bookable">
<!ENTITY staff.cat.copy_browser.holdings_maintenance.cmd_create_brt.accesskey "Y">
<!ENTITY staff.cat.copy_browser.holdings_maintenance.sel_patron.label "Show Last Few Circulations">
Added: trunk/Open-ILS/web/templates/default/booking/reservation.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/booking/reservation.tt2 (rev 0)
+++ trunk/Open-ILS/web/templates/default/booking/reservation.tt2 2009-12-21 16:21:48 UTC (rev 15207)
@@ -0,0 +1,93 @@
+[% WRAPPER "default/base.tt2" %]
+<script src="[% ctx.media_prefix %]/js/ui/default/booking/reservation.js"></script>
+<link rel="stylesheet" type="text/css" href="[% ctx.media_prefix %]/css/skin/[% ctx.skin %]/booking.css" />
+<script type="text/javascript">
+ dojo.require("dojox.grid.DataGrid");
+ openils.Util.addOnLoad(my_init);
+</script>
+<div id="auto_l10n_start_here">
+ <div id="brt_search_block" class="container">
+ <h1 class="booking AUTO_choose_a_brt"></h1>
+ <form onsubmit="init_reservation_interface(this); return false;">
+ <div id="brt_selector_here" class="nice_vertical_padding"></div>
+ <div class="nice_vertical_padding">
+ <input type="submit" class="AUTO_ATTR_VALUE_next" />
+ </div>
+ </form>
+ </div>
+
+ <div id="brt_reserve_block" class="container">
+ <form>
+ <div id="brsrc_available_outer">
+ <h1 class="booking" id="brsrc_list_header"></h1>
+ <!-- I'm reluctantly hardcoding the size attribute below to 12
+ since you can't get the behavior of the size attribute with
+ anything in CSS. -->
+ <select id="brsrc_list" name="brsrc_list" multiple="multiple"
+ size="12"></select>
+ <div class="nice_vertical_padding">
+ <label class="AUTO_patron_barcode"
+ for="patron_barcode" /></label>
+ <input name="patron_barcode" id="patron_barcode"
+ onchange="update_bresv_grid();" />
+ </div>
+ <div class="nice_vertical_padding">
+ <span class="two_buttons">
+ <input type="button"
+ class="AUTO_ATTR_VALUE_reserve_brsrc"
+ onclick="create_bresv_on_brsrc();" />
+
+ <input type="button"
+ class="AUTO_ATTR_VALUE_reserve_brt"
+ onclick="create_bresv_on_brt();" />
+ </span>
+ </div>
+ </div>
+ <div id="reserve_right_side">
+ <h2 class="booking AUTO_i_need_this_resource"></h2>
+ <div id="reserve_datetime_start">
+ <label class="reserve_datetime AUTO_starting_at"
+ for="reserve_date_start"></label><br />
+ <input id="reserve_date_start" />
+ <input id="reserve_time_start" />
+ </div>
+ <div id="reserve_datetime_end">
+ <label class="reserve_datetime AUTO_ending_at"
+ for="reserve_date_end"></label><br />
+ <input id="reserve_date_end" />
+ <input id="reserve_time_end" />
+ </div>
+ <h2 class="booking AUTO_with_these_attr"></h2>
+ <div id="bra_and_brav">
+ </div>
+ </div>
+ <div id="reserve_under">
+ <hr />
+ <h2 class="booking" id="existing_reservation_patron_line"></h2>
+ <table id="bresv_grid" jsId="bresvGrid"
+ dojoType="dojox.grid.DataGrid" query="{id: '*'}"
+ rowSelector="20px" autoHeight="true">
+ <thead>
+ <tr><!-- FIXME: i18n problem: init_auto_l10n() runs
+ too late to take care of the below elements. -->
+ <th field="type">Type</th>
+ <th field="resource">Resource</th>
+ <th field="start_time">Start time</th>
+ <th field="end_time">End time</th>
+ </tr>
+ </thead>
+ </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_cancel_existing"
+ class="AUTO_ATTR_VALUE_button_cancel_existing"
+ onclick="cancel_selected_bresv(bresvGrid.selection.getSelected());" />
+ </div>
+ </div>
+ </form>
+ </div>
+</div>
+[% END %]
Deleted: trunk/Open-ILS/web/templates/default/conify/global/booking/reservation.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/conify/global/booking/reservation.tt2 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/web/templates/default/conify/global/booking/reservation.tt2 2009-12-21 16:21:48 UTC (rev 15207)
@@ -1,39 +0,0 @@
-[% WRAPPER default/base.tt2 %]
-[% ctx.page_title = 'Reservations' %]
-
-<script type ="text/javascript">
- dojo.require('dijit.form.FilteringSelect');
- dojo.require('openils.widget.AutoGrid');
-
- openils.Util.addOnLoad(
- function() {
- ustGrid.loadAll({order_by:{bresv : 'name'}});
- }
- );
-</script>
-
-
-
-<div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
- <div>Reservations</div>
- <div>
- <button dojoType='dijit.form.Button' onClick='ustGrid.showCreateDialog()'>New Reservation</button>
- <button dojoType='dijit.form.Button' onClick='ustGrid.deleteSelected()'>Delete Selected</button>
- </div>
-</div>
-
-<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
- <table jsId="ustGrid"
- autoHeight='true'
- dojoType="openils.widget.AutoGrid"
- fieldOrder="['name', 'fine_interval', 'fine_amount',
- 'owner', 'catalog_item', 'transferable', 'record']"
- query="{name: '*'}"
- defaultCellWidth='"auto"'
- fmClass='bresv'
- showPaginator='true'
- editOnEnter='true'>
- </table>
- </div>
-
-[% END %]
Deleted: trunk/Open-ILS/web/templates/default/conify/global/booking/reservation_attr_value_map.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/conify/global/booking/reservation_attr_value_map.tt2 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/web/templates/default/conify/global/booking/reservation_attr_value_map.tt2 2009-12-21 16:21:48 UTC (rev 15207)
@@ -1,39 +0,0 @@
-[% WRAPPER default/base.tt2 %]
-[% ctx.page_title = 'Reservation Attribute Value Maps' %]
-
-<script type ="text/javascript">
- dojo.require('dijit.form.FilteringSelect');
- dojo.require('openils.widget.AutoGrid');
-
- openils.Util.addOnLoad(
- function() {
- ustGrid.loadAll({order_by:{bravm : 'name'}});
- }
- );
-</script>
-
-
-
-<div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
- <div>Reservation Attribute Value Maps</div>
- <div>
- <button dojoType='dijit.form.Button' onClick='ustGrid.showCreateDialog()'>New Reservation Attribute Value Map</button>
- <button dojoType='dijit.form.Button' onClick='ustGrid.deleteSelected()'>Delete Selected</button>
- </div>
-</div>
-
-<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
- <table jsId="ustGrid"
- autoHeight='true'
- dojoType="openils.widget.AutoGrid"
- fieldOrder="['name', 'fine_interval', 'fine_amount',
- 'owner', 'catalog_item', 'transferable', 'record']"
- query="{name: '*'}"
- defaultCellWidth='"auto"'
- fmClass='bravm'
- showPaginator='true'
- editOnEnter='true'>
- </table>
- </div>
-
-[% END %]
Modified: trunk/Open-ILS/web/templates/default/conify/global/booking/resource.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/conify/global/booking/resource.tt2 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/web/templates/default/conify/global/booking/resource.tt2 2009-12-21 16:21:48 UTC (rev 15207)
@@ -7,31 +7,17 @@
dojo.require('openils.widget.AutoGrid');
dojo.require('openils.XUL');
- function get_brsrc_ids() {
- var cgi = new CGI();
- var results = JSON2js(cgi.param('results'));
- if (!results) return undefined;
- var brsrc_ids = [];
- for (var i in results) {
- brsrc_ids.push(results[i][0]);
- }
- return brsrc_ids;
- }
-
openils.Util.addOnLoad(
function() {
var search = undefined; // default to all objs
- var brsrc_ids = get_brsrc_ids();
- if (brsrc_ids) {
- search = {id: brsrc_ids};
+ if (xulG && xulG.resultant_brsrc) {
+ search = {id: xulG.resultant_brsrc};
}
ustGrid.loadAll({order_by:{brsrc : 'barcode'}}, search);
}
);
</script>
-
-
<div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
<div>Resources</div>
<div>
Modified: trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js
===================================================================
--- trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/chrome/content/main/menu.js 2009-12-21 16:21:48 UTC (rev 15207)
@@ -116,7 +116,6 @@
);
}
-
var cmd_map = {
'cmd_broken' : [
['oncommand'],
@@ -646,14 +645,6 @@
['oncommand'],
function() { open_eg_web_page('conify/global/booking/resource_attr_map'); }
],
- 'cmd_server_admin_booking_reservation': [
- ['oncommand'],
- function() { open_eg_web_page('conify/global/booking/reservation'); }
- ],
- 'cmd_server_admin_booking_reservation_attr_value_map': [
- ['oncommand'],
- function() { open_eg_web_page('conify/global/booking/reservation_attr_value_map'); }
- ],
'cmd_acq_view_picklist' : [
['oncommand'],
function() { open_eg_web_page('acq/picklist/list', 'menu.cmd_acq_view_picklist.tab'); }
@@ -698,7 +689,51 @@
['oncommand'],
function() { open_eg_web_page('conify/global/acq/distribution_formula', 'menu.cmd_acq_view_distrib_formula.tab'); }
],
-
+ 'cmd_booking_reservation' : [
+ ['oncommand'],
+ function() {
+ obj.set_tab(
+ "/eg/booking/reservation",
+ {
+ "tab_name": offlineStrings.getString(
+ "menu.cmd_booking_reservation.tab"
+ ),
+ "browser": false
+ },
+ xulG
+ );
+ }
+ ],
+ 'cmd_booking_reservation_pickup' : [
+ ['oncommand'],
+ function() {
+ obj.set_tab(
+ "/eg/booking/reservation_pickup",
+ {
+ "tab_name": offlineStrings.getString(
+ "menu.cmd_booking_reservation.tab"
+ ),
+ "browser": false
+ },
+ xulG
+ );
+ }
+ ],
+ 'cmd_booking_reservation_return' : [
+ ['oncommand'],
+ function() {
+ obj.set_tab(
+ "/eg/booking/reservation_return",
+ {
+ "tab_name": offlineStrings.getString(
+ "menu.cmd_booking_reservation.tab"
+ ),
+ "browser": false
+ },
+ xulG
+ );
+ }
+ ],
'cmd_reprint' : [
['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 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul 2009-12-21 16:21:48 UTC (rev 15207)
@@ -88,7 +88,11 @@
<command id="cmd_acq_view_exchange_rate" />
<command id="cmd_acq_view_distrib_formula" />
+ <command id="cmd_booking_reservation" />
+ <command id="cmd_booking_reservation_pickup" />
+ <command id="cmd_booking_reservation_return" />
+
<!-- local admin menu commands -->
<command id="cmd_local_admin_fonts_and_sounds"/>
<command id="cmd_local_admin_printer"/>
@@ -127,8 +131,6 @@
<command id="cmd_server_admin_booking_resource_attr" />
<command id="cmd_server_admin_booking_resource_attr_value" />
<command id="cmd_server_admin_booking_resource_attr_map" />
- <command id="cmd_server_admin_booking_reservation" />
- <command id="cmd_server_admin_booking_reservation_attr_value_map" />
</commandset>
@@ -258,6 +260,14 @@
</menupopup>
</menu>
+<!-- The Booking menu on the main menu -->
+<menu id="main.menu.booking" label="&staff.main.menu.booking.label;" accesskey="&staff.main.menu.booking.accesskey;">
+ <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.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>
+</menu>
<!-- The Search menu on the main menu -->
<menu id="main.menu.search" label="&staff.main.menu.search.label;" accesskey="&staff.main.menu.search.accesskey;">
@@ -331,8 +341,6 @@
<menuitem label="&staff.main.menu.admin.server_admin.booking.resource_attr.label;" command="cmd_server_admin_booking_resource_attr" accesskey="&staff.main.menu.admin.server_admin.booking.resource_attr.accesskey;"/>
<menuitem label="&staff.main.menu.admin.server_admin.booking.resource_attr_value.label;" command="cmd_server_admin_booking_resource_attr_value" accesskey="&staff.main.menu.admin.server_admin.booking.resource_attr_value.accesskey;"/>
<menuitem label="&staff.main.menu.admin.server_admin.booking.resource_attr_map.label;" command="cmd_server_admin_booking_resource_attr_map" accesskey="&staff.main.menu.admin.server_admin.booking.resource_attr_map.accesskey;"/>
- <menuitem label="&staff.main.menu.admin.server_admin.booking.reservation.label;" command="cmd_server_admin_booking_reservation" accesskey="&staff.main.menu.admin.server_admin.booking.reservation.accesskey;"/>
- <menuitem label="&staff.main.menu.admin.server_admin.booking.reservation_attr_value_map.label;" command="cmd_server_admin_booking_reservation_attr_value_map" accesskey="&staff.main.menu.admin.server_admin.booking.reservation_attr_value_map.accesskey;"/>
</menupopup>
</menu>
</menupopup>
Modified: trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul
===================================================================
--- trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul 2009-12-21 16:21:48 UTC (rev 15207)
@@ -72,6 +72,7 @@
<menu id="main.menu.circ" />
<menu id="main.menu.cat" />
<menu id="main.menu.acq" />
+ <menu id="main.menu.booking" />
<spacer flex="1" />
<menu id="main.menu.admin" />
<!--
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 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties 2009-12-21 16:21:48 UTC (rev 15207)
@@ -232,6 +232,8 @@
menu.cmd_acq_view_currency_type.tab=Currency Types
menu.cmd_acq_view_exchange_rate.tab=Exchange Rates
menu.cmd_acq_view_distrib_formula.tab=Distribution Formulas
+menu.cmd_booking_resource.tab=Resources
+menu.cmd_booking_reservation.tab=Reservations
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
Modified: trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.js
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.js 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.js 2009-12-21 16:21:48 UTC (rev 15207)
@@ -145,64 +145,51 @@
'cmd_create_brt' : [
['command'],
function() {
- JSAN.use('util.functional');
- var cs = document.getElementById('catStrings');
- // Filter out selected rows that aren't copies.
+ JSAN.use("cat.util");
+ JSAN.use("util.functional");
+
+ /* Filter selected rows that aren"t copies. */
var list = util.functional.filter_list(
obj.sel_list,
function (o) {
- return o.split(/_/)[0] == 'acp';
+ return o.split(/_/)[0] == "acp";
}
);
- // Get the IDs of all copy rows.
- var copy_ids = util.functional.map_list(
- list, function (o) {
- return obj.map_acp[o].id();
+ var results = cat.util.make_bookable(
+ util.functional.map_list(
+ list, function (o) {
+ return obj.map_acp[o].id();
+ }
+ )
+ );
+ if (results && results["brsrc"]) {
+ cat.util.edit_new_brsrc(results["brsrc"]);
+ }
+ }
+ ],
+ 'cmd_book_item_now' : [
+ ['command'],
+ function() {
+ JSAN.use("cat.util");
+ JSAN.use("util.functional");
+
+ /* Filter selected rows that aren"t copies. */
+ var list = util.functional.filter_list(
+ obj.sel_list,
+ function (o) {
+ return o.split(/_/)[0] == "acp";
}
);
- // Ask the ML to create brt's and brsrc's.
- var results = fieldmapper.standardRequest(
- ['open-ils.booking', 'open-ils.booking.create_brt_and_brsrc_from_copies'],
- [ses(), copy_ids]
+ var results = cat.util.make_bookable(
+ util.functional.map_list(
+ list, function (o) {
+ return obj.map_acp[o].id();
+ }
+ )
);
- if (results == null) {
- alert(cs.getString('staff.cat.copy_browser.brt_and_brsrc.create_failed_silent'));
+ if (results) {
+ cat.util.edit_new_bresv(results);
}
- else if (typeof results.ilsevent != 'undefined') {
- // FIXME Isn't there a more standardized
- // way to show this error?
- alert(cs.getFormattedString(
- 'staff.cat.copy_browser.brt_and_brsrc.create_failed',
- [results.ilsevent, results.textcode,
- results.desc, results.debug]
- ));
- } else {
- // Spawn new tab to allow editing new
- // resources.
- try {
- var url = urls.XUL_BROWSER + '?url=' +
- window.escape(
- xulG.url_prefix(urls.EG_WEB_BASE) +
- '/conify/global/booking/resource?results=' +
- window.escape(js2JSON(results['brsrc']))
- );
- // Sorry about the CGI params, but I
- // don't see another choice for
- // passing data to conify pages. This
- // has the obvious problem of a
- // character length limit. FIXME
- xulG.new_tab(url,
- {'tab_name': cs.getString('staff.cat.copy_browser.brt_and_brsrc.newtab_name'),
- 'browser' : false},
- {'no_xulG' : false}
- );
- } catch(E) {
- JSAN.use('util.error');
- var error = new util.error;
- var f = error.standard_unexpected_error_alert;
- f(cs.getString('staff.cat.copy_browser.brt_and_brsrc.newtab_failed'), E);
- }
- }
}
],
'cmd_add_items' : [
Modified: trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.xul
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.xul 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/server/cat/copy_browser.xul 2009-12-21 16:21:48 UTC (rev 15207)
@@ -73,6 +73,7 @@
<command id="cmd_broken" />
<command id="sel_copy_details"/>
<command id="cmd_create_brt"/>
+ <!-- <command id="cmd_book_item_now"/> -->
<command id="sel_patron"/>
<command id="sel_clip" />
<command id="cmd_clear" />
@@ -104,6 +105,7 @@
<menuitem command="cmd_add_items_to_buckets" label="&staff.cat.copy_browser.actions.cmd_add_items_to_buckets.label;" accesskey="&staff.cat.copy_browser.actions.cmd_add_items_to_buckets.accesskey;"/>
<menuitem command="sel_copy_details" label="&staff.cat.copy_browser.actions.sel_copy_details.label;" accesskey="&staff.cat.copy_browser.actions.sel_copy_details.label;" />
<menuitem command="cmd_create_brt" label="&staff.cat.copy_browser.actions.cmd_create_brt.label;" accesskey="&staff.cat.copy_browser.actions.cmd_create_brt.accesskey;" />
+ <!-- <menuitem command="cmd_book_item_now" label="&staff.cat.copy_browser.actions.cmd_book_item_now.label;" accesskey="&staff.cat.copy_browser.actions.cmd_book_item_now.accesskey;" /> -->
<menuitem command="sel_patron" label="&staff.cat.copy_browser.actions.sel_patron.label;" accesskey="&staff.cat.copy_browser.actions.sel_patron.accesskey;"/>
<menuseparator/>
<menuitem command="cmd_edit_items" label="&staff.cat.copy_browser.actions.cmd_edit_items.label;" accesskey="&staff.cat.copy_browser.actions.cmd_edit_items.accesskey;"/>
Modified: trunk/Open-ILS/xul/staff_client/server/cat/util.js
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/cat/util.js 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/server/cat/util.js 2009-12-21 16:21:48 UTC (rev 15207)
@@ -517,4 +517,77 @@
if (error) error.standard_unexpected_error_alert('cat.util.fast_item_add',E); else alert('FIXME: ' + E);
}
}
+
+cat.util.make_bookable = function(copy_ids) {
+ var results = fieldmapper.standardRequest(
+ ["open-ils.booking", "open-ils.booking.resources.create_from_copies"],
+ [ses(), copy_ids]
+ );
+ if (results == null) {
+ alert(document.getElementById("catStrings").getString(
+ "staff.cat.copy_browser.make_bookable.create_failed_silent"
+ ));
+ }
+ else if (typeof results.ilsevent != "undefined") {
+ alert(document.getElementById("catStrings").getFormattedString(
+ "staff.cat.copy_browser.make_bookable.create_failed",
+ [results.ilsevent, results.textcode, results.desc, results.debug]
+ ));
+ }
+ return results;
+}
+
+cat.util.edit_new_brsrc = function(brsrc_list) {
+ /* Spawn new tab to allow editing new resources. */
+ try {
+ xulG.resultant_brsrc = brsrc_list.map(function(o) { return o[0]; });
+ xulG.new_tab(
+ urls.XUL_BROWSER + "?url=" + window.escape(
+ xulG.url_prefix("/eg/conify/global/booking/resource")
+ ), {
+ "tab_name": offlineStrings.getString(
+ "menu.cmd_booking_resource.tab"
+ ),
+ "browser" : true
+ }, {
+ "no_xulG": false,
+ "show_print_button": false,
+ "show_nav_buttons": true,
+ "passthru_content_params": xulG
+ }
+ );
+ } catch(E) {
+ alert(
+ document.getElementById("catStrings").getFormattedString(
+ "staff.cat.copy_browser.make_bookable.newtab_failed"
+ ), E
+ );
+ }
+}
+
+cat.util.edit_new_bresv = function(booking_results) {
+ /* Spawn new tab to allow editing new reservations. */
+ try {
+ if (xulG.auth == undefined) {
+ xulG.auth = {"session": {"key": ses()}};
+ }
+ xulG.booking_results = booking_results;
+ xulG.new_tab(
+ xulG.url_prefix("/eg/booking/reservation"),
+ {
+ "tab_name": offlineStrings.getString(
+ "menu.cmd_booking_reservation.tab"
+ ),
+ "browser" : false
+ }, xulG
+ );
+ } catch(E) {
+ alert(
+ document.getElementById("catStrings").getString(
+ "staff.cat.copy_browser.make_bookable.newtab_failed"
+ ) + E
+ );
+ }
+}
+
dump('exiting cat/util.js\n');
Modified: trunk/Open-ILS/xul/staff_client/server/locale/en-US/cat.properties
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/locale/en-US/cat.properties 2009-12-21 15:44:40 UTC (rev 15206)
+++ trunk/Open-ILS/xul/staff_client/server/locale/en-US/cat.properties 2009-12-21 16:21:48 UTC (rev 15207)
@@ -12,10 +12,10 @@
staff.cat.copy_browser.add_item.title=Add Item
staff.cat.copy_browser.add_item.error=copy browser -> add copies
staff.cat.copy_browser.add_items_bucket.error=copy browser -> add copies to bucket
-staff.cat.copy_browser.brt_and_brsrc.create_failed_silent=No response from server
-staff.cat.copy_browser.brt_and_brsrc.create_failed=Error from server: %1$d %2$s\n%3$s\n%4$s
-staff.cat.copy_browser.brt_and_brsrc.newtab_failed=Could not launch Booking Resource Editor: %1$s
-staff.cat.copy_browser.brt_and_brsrc.newtab_name=Resources
+staff.cat.copy_browser.make_bookable.create_failed_silent=No response from server
+staff.cat.copy_browser.make_bookable.create_failed=Error from server: %1$d %2$s\n%3$s\n%4$s
+staff.cat.copy_browser.make_bookable.newtab_failed=Could not open new tab
+staff.cat.copy_browser.make_bookable.newtab_name=Resources
staff.cat.copy_browser.replace_barcode.failed=Barcode %1$s not likely replaced.
staff.cat.copy_browser.replace_barcode.error=copy browser -> replace barcode
staff.cat.copy_browser.edit_items.error=Copy Browser -> Edit Items
More information about the open-ils-commits
mailing list