Patch from Lebbeous Fogle-Weekley implementing pickup and return interfaces for booki...
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 8 Jan 2010 16:15:47 +0000 (16:15 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 8 Jan 2010 16:15:47 +0000 (16:15 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@15285 dcc99617-32d9-48b4-a31d-7c20da2025e4

18 files changed:
Open-ILS/src/perlmods/OpenILS/Application/Booking.pm
Open-ILS/src/perlmods/OpenILS/Application/Circ/Circulate.pm
Open-ILS/web/css/skin/default/booking.css
Open-ILS/web/js/dojo/openils/booking/nls/pickup_and_return.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/booking/common.js
Open-ILS/web/js/ui/default/booking/pickup.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/booking/populator.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/booking/reservation.js
Open-ILS/web/js/ui/default/booking/return.js [new file with mode: 0644]
Open-ILS/web/templates/default/booking/pickup.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/booking/return.tt2 [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/main/menu.js
Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
Open-ILS/xul/staff_client/server/patron/display.js
Open-ILS/xul/staff_client/server/patron/display.xul
Open-ILS/xul/staff_client/server/patron/display_horiz.xul
Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul
Open-ILS/xul/staff_client/server/patron/display_overlay.xul

index 1705a07..dddd7eb 100644 (file)
@@ -573,6 +573,7 @@ NOTES
 
 
 sub naive_ts_string { strftime("%F %T", localtime(shift)); }
+sub naive_start_of_day { strftime("%F", localtime(shift)) . " 00:00:00"; }
 
 # Return a list of bresv or an ilsevent on failure.
 sub get_uncaptured_bresv_for_brsrc {
@@ -1004,4 +1005,145 @@ __PACKAGE__->register_method(
 );
 
 
+sub get_captured_reservations {
+    my ($self, $client, $auth, $barcode, $which) = @_;
+
+    my $e = new_editor(xact => 1, authtoken => $auth);
+    return $e->die_event unless $e->checkauth;
+    return $e->die_event unless $e->allowed("VIEW_USER");
+    return $e->die_event unless $e->allowed("ADMIN_BOOKING_RESERVATION");
+
+    # fetch the patron for our uses in any case...
+    my $patron = $U->fetch_user_by_barcode($barcode);
+    return $patron if ref($patron) eq "HASH" and exists $patron->{"ilsevent"};
+
+    my $bresv_flesh = {
+        "flesh" => 1,
+        "flesh_fields" => {"bresv" => [
+            qw/target_resource_type current_resource/
+        ]}
+    };
+
+    my $dispatch = {
+        "patron" => sub {
+            return $patron;
+        },
+        "ready" => sub {
+            return $e->search_booking_reservation([
+                {
+                    "usr" => $patron->id,
+                    "capture_time" => {"!=" => undef},
+                    "pickup_time" => undef,
+                    "cancel_time" => undef
+                },
+                $bresv_flesh
+            ]) or $e->die_event;
+        },
+        "out" => sub {
+            return $e->search_booking_reservation([
+                {
+                    "usr" => $patron->id,
+                    "pickup_time" => {"!=" => undef},
+                    "return_time" => undef,
+                    "cancel_time" => undef
+                },
+                $bresv_flesh
+            ]) or $e->die_event;
+        },
+        "in" => sub {
+            return $e->search_booking_reservation([
+                {
+                    "usr" => $patron->id,
+                    "return_time" => {">=" => naive_start_of_day()},
+                    "cancel_time" => undef
+                },
+                $bresv_flesh
+            ]) or $e->die_event;
+        }
+    };
+
+    my $result = {};
+    foreach (@$which) {
+        my $f = $dispatch->{$_};
+        if ($f) {
+            my $r = &{$f}();
+            return $r if (ref($r) eq "HASH" and exists $r->{"ilsevent"});
+            $result->{$_} = $r;
+        }
+    }
+
+    return $result;
+}
+__PACKAGE__->register_method(
+    method   => "get_captured_reservations",
+    api_name => "open-ils.booking.reservations.get_captured",
+    argc     => 3,
+    signature=> {
+        params => [
+            {type => "string", desc => "Authentication token"},
+            {type => "string", desc => "Patron barcode"},
+            {type => "array", desc => "Parts wanted (patron, ready, out, in?)"}
+        ],
+        return => { desc => "A hash of parts." } # XXX describe more fully
+    }
+);
+
+
+sub get_bresv_by_returnable_resource_barcode {
+    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("VIEW_USER");
+    return $e->die_event unless $e->allowed("ADMIN_BOOKING_RESERVATION");
+
+    my $rows = $e->json_query({
+        "select" => {"bresv" => ["id"]},
+        "from" => {
+            "bresv" => {
+                "brsrc" => {"field" => "id", "fkey" => "current_resource"}
+            }
+        },
+        "where" => {
+            "+brsrc" => {"barcode" => $barcode},
+            "-and" => {
+                "pickup_time" => {"!=" => undef},
+                "cancel_time" => undef,
+                "return_time" => undef
+            }
+        }
+    }) or return $e->die_event;
+
+    if (@$rows < 1) {
+        return $rows;
+    } else {
+        # More than one result might be possible, but we don't want to return
+        # more than one at this time.
+        my $id = $rows->[0]->{"id"};
+        return $e->retrieve_booking_reservation([
+            $id, {
+                "flesh" => 2,
+                "flesh_fields" => {
+                    "bresv" => [qw/usr target_resource_type current_resource/],
+                    "au" => ["card"]
+                }
+            }
+        ]) or $e->die_event;
+    }
+}
+
+__PACKAGE__->register_method(
+    method   => "get_bresv_by_returnable_resource_barcode",
+    api_name => "open-ils.booking.reservations.by_returnable_resource_barcode",
+    argc     => 2,
+    signature=> {
+        params => [
+            {type => "string", desc => "Authentication token"},
+            {type => "string", desc => "Resource barcode"},
+        ],
+        return => { desc => "A fleshed bresv or an ilsevent on error" }
+    }
+);
+
+
 1;
index acc422f..939cf0f 100644 (file)
@@ -318,15 +318,8 @@ sub run_method {
         $circulator->do_checkout();
 
     } elsif( $circulator->is_res_checkin ) {
-        my ($reservation, $evt) = $U->fetch_booking_reservation($self->reservation);
-        if ($evt) {
-            $self->bail_on_events($evt);
-        } else {
-            $self->reservation( $reservation );
-            $self->generate_fines(1);
-            $circulator->do_reservation_return();
-            $circulator->do_checkin();
-        }
+        $circulator->do_reservation_return();
+        $circulator->do_checkin() if ($circulator->copy());
     } elsif( $api =~ /checkin/ ) {
         $circulator->do_checkin();
 
@@ -1452,10 +1445,10 @@ sub update_reservation {
     my $target_r = $reservation->target_resource;
     my $current_r = $reservation->current_resource;
 
-    $reservation->usr($usr->id) if $usr;
-    $reservation->target_resource_type($target_rt->id) if $target_rt;
-    $reservation->target_resource($target_r->id) if $target_r;
-    $reservation->current_resource($current_r->id) if $current_r;
+    $reservation->usr($usr->id) if ref $usr;
+    $reservation->target_resource_type($target_rt->id) if ref $target_rt;
+    $reservation->target_resource($target_r->id) if ref $target_r;
+    $reservation->current_resource($current_r->id) if ref $current_r;
 
     return $self->bail_on_events($self->editor->event)
         unless $self->editor->update_booking_reservation($self->reservation);
@@ -1789,6 +1782,7 @@ sub do_reservation_return {
     return $self->bail_on_events($evt) if $evt;
 
     $self->reservation( $reservation );
+    $self->generate_fines(1);
     $self->reservation->return_time('now');
     $self->update_reservation();
 
index f4d9f7e..2c42404 100644 (file)
@@ -24,11 +24,12 @@ label.bra {
     font-style: italic;
     padding-right: 12px;
 }
-h1.booking, h2.booking {
+h1.booking, h2.booking, h3.booking {
     margin: 0;
     padding-top: 0;
     padding-bottom: 8px;
 }
+h1.booking { font-size: 16pt; font-weight: bold; }
 select#brsrc_list {
     width: 90%;
 }
@@ -81,3 +82,8 @@ ul { list-style-type: square; }
     margin-bottom: 4px; margin-top: 4px;
 }
 span#result_display { margin-left: 12px; }
+div#contains_misc_controls { text-align:right; }
+div#patron_info { font-size: 12pt; font-weight: bold; }
+div#no_ready_bresv, div#no_out_bresv, div#no_in_bresv {
+    font-style: italic;
+}
diff --git a/Open-ILS/web/js/dojo/openils/booking/nls/pickup_and_return.js b/Open-ILS/web/js/dojo/openils/booking/nls/pickup_and_return.js
new file mode 100644 (file)
index 0000000..6d786e3
--- /dev/null
@@ -0,0 +1,38 @@
+{
+    'NO_PATRON_BARCODE': "Please enter a patron barcode.",
+    'RESERVATIONS_NO_RESPONSE':
+        "No response from server when asking for reservations.",
+    'RESERVATIONS_ERROR':
+        "Error communicating with server (asking for reservations):",
+    'PICKUP_NO_RESPONSE': "No response from server when attempting pickup.",
+    'PICKUP_ERROR': "Error communicating with server (attempting pickup):",
+    'RETURN_NO_RESPONSE': "No response from server when attempting return.",
+    'RETURN_ERROR': "Error communicating with server (attempting return):",
+    'RETURN_SUCCESS': "Return successful.",
+    'SELECT_SOMETHING': "You have not selected any reservations.",
+    'NO_SUCH_RETURNABLE_RESOURCE': "No such returnable resource.",
+    'RETURNABLE_RESOURCE_ERROR': "Error looking up returnable resource:",
+    'NOTICE_CHANGE_OF_PATRON':
+        "Note that the resource scanned was out on reservation to different\n" +
+        "patron than the last resource you scanned.  If this is not\n" +
+        "expected, stop to examine outstanding reservations for your patron\n" +
+        "or on the resource.",
+
+    'AUTO_h1': "Reservations Pickup",
+    'AUTO_return_h1': "Reservations Return",
+    'AUTO_patron_barcode': "Enter patron barcode:",
+    'AUTO_barcode_type': "Return by barcode of",
+    'AUTO_in_bresv': "Patron has returned these resources today:",
+    'AUTO_ready_bresv': "Patron has these reservations ready for pickup:",
+    'AUTO_out_bresv': "Patron currently has these reservations out:",
+    'AUTO_no_ready_bresv':
+        "Patron has no reservations ready for pickup at this time.",
+    'AUTO_no_out_bresv': "Patron has no more reservations out at this time.",
+    'AUTO_no_in_bresv': "Patron has not returned any resources today.",
+    'AUTO_patron': "Patron",
+    'AUTO_resource': "Resource",
+    'AUTO_ATTR_VALUE_go': "Go",
+    'AUTO_ATTR_VALUE_reset': "Clear / New Patron",
+    'AUTO_ATTR_VALUE_pickup': "Pick up",
+    'AUTO_ATTR_VALUE_return': "Return"
+}
index 4351166..7f46073 100644 (file)
@@ -62,3 +62,10 @@ function my_ils_error(leader, e) {
     }
     return s;
 }
+function set_datagrid_empty_store(grid, flattener) {
+    grid.setStore(
+        new dojo.data.ItemFileReadStore(
+            {"data": flattener([])}
+        )
+    );
+}
diff --git a/Open-ILS/web/js/ui/default/booking/pickup.js b/Open-ILS/web/js/ui/default/booking/pickup.js
new file mode 100644 (file)
index 0000000..fdf709e
--- /dev/null
@@ -0,0 +1,24 @@
+dojo.requireLocalization("openils.booking", "pickup_and_return");
+var localeStrings = dojo.i18n.getLocalization(
+    "openils.booking", "pickup_and_return"
+);
+var p;
+
+function my_init() {
+    p = new Populator({
+        "ready": ready_bresv,
+        "out": out_bresv,
+        "patron": document.getElementById("patron_info")
+    }, document.getElementById("patron_barcode"));
+    init_auto_l10n(document.getElementById("auto_l10n_start_here"));
+
+    /* The following would be for pass-in from the patron interface, but
+     * doesn't yet work/is cheap and needs improved anyway. */
+//    try {
+//        document.getElementById("patron_barcode").value =
+//            xulG.bresv_interface_opts.patron_barcode;
+//        document.getElementById("lookup").submit();
+//    } catch (E) {
+//        ;
+//    }
+}
diff --git a/Open-ILS/web/js/ui/default/booking/populator.js b/Open-ILS/web/js/ui/default/booking/populator.js
new file mode 100644 (file)
index 0000000..6ccb1ef
--- /dev/null
@@ -0,0 +1,274 @@
+/* This module depends on common.js being loaded, as well as the
+ * localization (Dojo/nls) for pickup and return . */
+
+dojo.require("dojo.data.ItemFileReadStore");
+
+function Populator(widgets, primary_input) {
+    this.widgets = widgets;
+
+    this.all = [];
+    for (var k in widgets) this.all.push(k);
+
+    if (primary_input) this.primary_input = primary_input;
+
+    this.prepare_cache();
+    this.prepare_empty_stores();
+    this.reset();
+}
+Populator.prototype.prepare_cache = function(data) {
+    this.cache = {};
+    for (var k in this.all) this.cache[this.all[k]] = {};
+};
+Populator.prototype.prepare_empty_stores = function(data) {
+    this.empty_stores = {};
+
+    for (var i in this.all) {
+        var name = this.all[i];
+
+        if (this.widgets[name] && this["flatten_" + name]) {
+            this.empty_stores[name] =
+                new dojo.data.ItemFileReadStore({
+                    "data": this["flatten_" + name]([])
+                });
+            this.widgets[name].setStore(this.empty_stores[name]);
+        }
+    }
+};
+Populator.prototype.flatten_ready = function(data) {
+    return {
+        "label": "id",
+        "identifier": "id",
+        "items": data.map(function(o) {
+            return {
+                "id": o.id(),
+                "type": o.target_resource_type().name(),
+                "resource": o.current_resource().barcode(),
+                "start_time": humanize_timestamp_string(o.start_time()),
+                "end_time": humanize_timestamp_string(o.end_time())
+            };
+        })
+    };
+};
+Populator.prototype.flatten_out = function(data) {
+    return {
+        "label": "id",
+        "identifier": "id",
+        "items": data.map(function(o) {
+            return {
+                "id": o.id(),
+                "type": o.target_resource_type().name(),
+                "resource": o.current_resource().barcode(),
+                "pickup_time": humanize_timestamp_string(o.pickup_time()),
+                "end_time": humanize_timestamp_string(o.end_time())
+            };
+        })
+    };
+};
+Populator.prototype.flatten_in = function(data) {
+    return {
+        "label": "id",
+        "identifier": "id",
+        "items": data.map(function(o) {
+            return {
+                "id": o.id(),
+                "type": o.target_resource_type().name(),
+                "resource": o.current_resource().barcode(),
+                "due_time": humanize_timestamp_string(o.end_time()),
+                "return_time": humanize_timestamp_string(o.return_time())
+            };
+        })
+    };
+};
+Populator.prototype.reveal_container = function(widget) {
+    var el = document.getElementById("contains_" + widget.id);
+    if (el) reveal_dom_element(el);
+};
+Populator.prototype.hide_container = function(widget) {
+    var el = document.getElementById("contains_" + widget.id);
+    if (el) hide_dom_element(el);
+};
+Populator.prototype.populate_ready = function(data) {
+    return this._populate_any_resv_grid(data, "ready");
+};
+Populator.prototype.populate_out = function(data) {
+    return this._populate_any_resv_grid(data, "out");
+};
+Populator.prototype.populate_in = function(data) {
+    return this._populate_any_resv_grid(data, "in");
+};
+Populator.prototype._populate_any_resv_grid = function(data, which) {
+    var flattener = this["flatten_" + which];
+    var widget = this.widgets[which];
+    var cache = this.cache[which];
+    var empty_store = this.empty_stores[which];
+
+    this.reveal_container(widget);
+
+    if (!data || !data.length) {
+        widget.setStore(empty_store);
+        this.toggle_anyness(false, which);
+    } else {
+        for (var i in data) cache[data[i].id()] = data[i];
+
+        widget.setStore(
+            new dojo.data.ItemFileReadStore({"data": flattener(data)})
+        );
+
+        this.toggle_anyness(true, which);
+
+        /* Arrrgh! Horrid but necessary: */
+        setTimeout(function() { widget.sort(); }, 100);
+    }
+};
+Populator.prototype.populate_patron = function(data) {
+    var h2 = document.createElement("h2");
+    h2.setAttribute("class", "booking");
+    h2.appendChild(document.createTextNode(formal_name(data)));
+
+    this.widgets.patron.innerHTML = "";
+    this.widgets.patron.appendChild(h2);
+
+    this.reveal_container(this.widgets.patron);
+    /* Maybe add patron's home OU or something here later... */
+};
+Populator.prototype.return_by_resource = function(barcode) {
+    /* XXX instead of talking to the server every time we do this, we could
+     * also check the "out" cache, iff we have one.  */
+    var r = fieldmapper.standardRequest(
+        ["open-ils.booking",
+        "open-ils.booking.reservations.by_returnable_resource_barcode"],
+        [xulG.auth.session.key, barcode]
+    );
+    if (!r) {
+        alert(localeStrings.NO_SUCH_RETURNABLE_RESOURCE);
+    } else if (is_ils_error(r)) {
+        alert(my_ils_error(localeStrings.RETURNABLE_RESOURCE_ERROR, r));
+    } else {
+        var new_barcode = r.usr().card().barcode();
+        if (this.patron_barcode && this.patron_barcode != new_barcode) {
+            /* XXX make this more subtle, i.e. flash something in background */
+            alert(localeStrings.NOTICE_CHANGE_OF_PATRON);
+        }
+        this.patron_barcode = new_barcode;
+        var ret = this.return(r);
+        if (!ret) {
+            alert(localeStrings.RETURN_NO_RESPONSE);
+        } else if (is_ils_error(ret)) {
+            alert(my_ils_error(localeStrings.RETURN_ERROR, ret));
+        } else {
+            /* XXX speedbump should go, but something has to happen else
+             * there's no indication to staff that anything happened when
+             * starting from a fresh (blank) return interface.
+             */
+            alert(localeStrings.RETURN_SUCCESS);
+        }
+        this.populate(); /* Won't recurse with no args. All is well. */
+    }
+};
+Populator.prototype.populate = function(barcode, which) {
+    if (barcode) {
+        if (barcode.patron) {
+            this.patron_barcode = barcode.patron;
+        }
+        else if (barcode.resource) { /* resource OR patron, not both */
+            if (!this.return_by_resource(barcode.resource))
+                return;
+        }
+    }
+    if (!this.patron_barcode) {
+        alert(localeStrings.NO_PATRON_BARCODE);
+        return;
+    }
+
+    if (!which) which = this.all;
+
+    var result = fieldmapper.standardRequest(
+        ["open-ils.booking", "open-ils.booking.reservations.get_captured"],
+        [xulG.auth.session.key, this.patron_barcode, which]
+    );
+
+    if (!result) {
+        this.patron_barcode = undefined;
+        alert(localeStrings.RESERVATIONS_NO_RESPONSE);
+    } else if (is_ils_error(result)) {
+        this.patron_barcode = undefined;
+        alert(my_ils_error(localeStrings.RESERVATIONS_ERROR, result));
+    } else {
+        for (var k in result)
+            this["populate_" + k](result[k]);
+    }
+};
+Populator.prototype.toggle_anyness = function(any, which) {
+    var widget = this.widgets[which].domNode;
+    var empty_alternate = document.getElementById("no_" + widget.id); 
+    var controls = document.getElementById("controls_" + widget.id); 
+    if (any) {
+        reveal_dom_element(widget);
+        if (empty_alternate) hide_dom_element(empty_alternate);
+        if (controls) reveal_dom_element(controls);
+    } else {
+        hide_dom_element(widget);
+        if (empty_alternate) reveal_dom_element(empty_alternate);
+        if (controls) hide_dom_element(controls);
+    }
+};
+Populator.prototype.pickup = function(reservation) {
+    return fieldmapper.standardRequest(
+        ["open-ils.circ", "open-ils.circ.reservation.pickup"],
+        [xulG.auth.session.key, {
+            "patron_barcode": this.patron_barcode,
+            "reservation": reservation
+        }]
+    );
+};
+Populator.prototype.return = function(reservation) {
+    return fieldmapper.standardRequest(
+        ["open-ils.circ", "open-ils.circ.reservation.return"],
+        [xulG.auth.session.key, {
+            "patron_barcode": this.patron_barcode,
+            "reservation": reservation.id()
+            /* yeah just id here ------^; lack of parallelism */
+        }]
+    );
+};
+Populator.prototype.act_on_selected = function(how, which) {
+    var widget = this.widgets[which];
+    var cache = this.cache[which];
+    var no_response_msg = localeStrings[how.toUpperCase() + "_NO_RESPONSE"];
+    var error_msg = localeStrings[how.toUpperCase() + "_ERROR"];
+
+    var selected_id_list =
+        widget.selection.getSelected().map(function(o) { return o.id[0]; });
+
+    if (!selected_id_list || !selected_id_list.length) {
+        alert(localeStrings.SELECT_SOMETHING);
+        return;
+    }
+
+    var reservations = selected_id_list.map(function(o) { return cache[o]; });
+
+    /* Do we have to process these one at a time?  I think so... */
+    for (var i in reservations) {
+        var result = this[how](reservations[i]);
+        if (!result) {
+            alert(no_response_msg);
+        } else if (is_ils_error(result)) {
+            alert(my_ils_error(error_msg, result));
+        } else {
+            continue;
+        }
+        break;
+    }
+
+    this.populate();
+};
+Populator.prototype.reset = function() {
+    for (var k in this.widgets) {
+        this.hide_container(this.widgets[k]);
+    }
+    this.patron_barcode = undefined;
+    if (this.primary_input) {
+        this.primary_input.value = "";
+        this.primary_input.focus();
+    }
+};
index 41426a6..a118777 100644 (file)
@@ -185,17 +185,6 @@ SelectorMemory.prototype.restore = function() {
 };
 
 /*
- * Misc helper functions
- */
-function set_datagrid_empty_store(grid) {
-    grid.setStore(
-        new dojo.data.ItemFileReadStore(
-            {"data": flatten_to_dojo_data([])}
-        )
-    );
-}
-
-/*
  * These functions communicate with the middle layer.
  */
 function get_all_noncat_brt() {
@@ -409,10 +398,10 @@ function init_bresv_grid(barcode) {
         }, /* whole_obj */ true]
     );
     if (result == null) {
-        set_datagrid_empty_store(bresvGrid);
+        set_datagrid_empty_store(bresvGrid, flatten_to_dojo_data);
         alert(localeStrings.GET_BRESV_LIST_NO_RESULT);
     } else if (is_ils_error(result)) {
-        set_datagrid_empty_store(bresvGrid);
+        set_datagrid_empty_store(bresvGrid, flatten_to_dojo_data);
         if (is_ils_actor_card_error(result)) {
             alert(localeStrings.ACTOR_CARD_NOT_FOUND);
         } else {
diff --git a/Open-ILS/web/js/ui/default/booking/return.js b/Open-ILS/web/js/ui/default/booking/return.js
new file mode 100644 (file)
index 0000000..4d64e3b
--- /dev/null
@@ -0,0 +1,26 @@
+dojo.requireLocalization("openils.booking", "pickup_and_return");
+var localeStrings = dojo.i18n.getLocalization(
+    "openils.booking", "pickup_and_return"
+);
+var p;
+
+function my_init() {
+    p = new Populator({
+        "out": out_bresv,
+        "in": in_bresv,
+        "patron": document.getElementById("patron_info")
+    }, document.getElementById("barcode"));
+    init_auto_l10n(document.getElementById("auto_l10n_start_here"));
+
+    /* The following would handle pass-in from the patron interface, but
+     * doesn't work (dirty solution, will come back to it, make it work,
+     * clean it up). */
+//    try {
+//        document.getElementById("barcode").value =
+//            xulG.bresv_interface_opts.patron_barcode;
+//        document.getElementById("barcode_type").selectedIndex = 1;
+//        document.getElementById("lookup").submit();
+//    } catch (E) {
+//        alert(E);
+//    }
+}
diff --git a/Open-ILS/web/templates/default/booking/pickup.tt2 b/Open-ILS/web/templates/default/booking/pickup.tt2
new file mode 100644 (file)
index 0000000..396e9eb
--- /dev/null
@@ -0,0 +1,77 @@
+[% 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/populator.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/booking/pickup.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);
+
+    function act(f) {
+        p.populate({"patron": f.patron_barcode.value});
+        return false; /* Always. */
+    }
+</script>
+<div id="auto_l10n_start_here">
+    <h1 class="booking AUTO_h1"></h1>
+    <div class="nice_vertical_padding" id="contains_barcode_control">
+        <form id="lookup" onsubmit="return act(this);">
+            <label for="patron_barcode" class="AUTO_patron_barcode"></label>
+            <input id="patron_barcode" name="patron_barcode" />
+            <input type="submit" class="AUTO_ATTR_VALUE_go" />
+        </form>
+    </div>
+    <div class="nice_vertical_padding" id="contains_patron_info">
+        <div id="patron_info"></div>
+    </div>
+    <div class="nice_vertical_padding" id="contains_ready_bresv">
+        <h3 class="booking AUTO_ready_bresv"></h3>
+        <div class="AUTO_no_ready_bresv" id="no_ready_bresv"></div>
+        <table id="ready_bresv" jsId="ready_bresv"
+            dojoType="dojox.grid.DataGrid" query="{id: '*'}"
+            rowSelector="20px" autoHeight="true" width="auto">
+            <thead>
+                <tr><!-- FIXME: i18n problem: init_auto_l10n() runs
+                        too late to take care of the below elements. -->
+                    <th width="35%" field="type">Title</th>
+                    <th width="25%" field="resource">Barcode</th>
+                    <th width="20%" field="start_time">Start time</th>
+                    <th width="20%" field="end_time">End time</th>
+                </tr>
+            </thead>
+        </table>
+        <div class="nice_vertical_padding" id="controls_ready_bresv">
+            <form>
+                <input type="button" id="pickup_button"
+                    class="AUTO_ATTR_VALUE_pickup"
+                    onclick="p.act_on_selected('pickup', 'ready');" />
+            </form>
+        </div>
+    </div>
+    <div class="nice_vertical_padding" id="contains_out_bresv">
+        <hr />
+        <h3 class="booking AUTO_out_bresv"></h3>
+        <div class="AUTO_no_out_bresv" id="no_out_bresv"></div>
+        <table id="out_bresv" jsId="out_bresv"
+            dojoType="dojox.grid.DataGrid" query="{id: '*'}"
+            rowSelector="20px" autoHeight="true" width="auto">
+            <thead>
+                <tr><!-- FIXME: i18n problem: init_auto_l10n() runs
+                        too late to take care of the below elements. -->
+                    <th width="35%" field="type">Title</th>
+                    <th width="25%" field="resource">Barcode</th>
+                    <th width="20%" field="pickup_time">Pickup time</th>
+                    <th width="20%" field="end_time">Due time</th>
+                </tr>
+            </thead>
+        </table>
+    </div>
+    <div class="nice_vertical_padding" id="contains_misc_controls">
+        <hr />
+        <form>
+            <input type="button" class="AUTO_ATTR_VALUE_reset"
+                onclick="p.reset();" />
+        </form>
+    </div>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/booking/return.tt2 b/Open-ILS/web/templates/default/booking/return.tt2
new file mode 100644 (file)
index 0000000..47bc853
--- /dev/null
@@ -0,0 +1,87 @@
+[% 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/populator.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/booking/return.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);
+
+    function act(f) {
+        var key = f.barcode_type.options[f.barcode_type.selectedIndex].value;
+        var obj = {};
+        obj[key] = f.barcode.value;
+        p.populate(obj);
+        return false; /* Always. */
+    }
+</script>
+<div id="auto_l10n_start_here">
+    <h1 class="booking AUTO_return_h1"></h1>
+    <div class="nice_vertical_padding" id="contains_barcode_control">
+        <form id="lookup" onsubmit="return act(this);">
+            <label for="barcode_type" class="AUTO_barcode_type"></label>
+            <select name="barcode_type" id="barcode_type"
+                onchange="var b = this.form.barcode; b.focus(); b.select();">
+                <option id="option_resource" value="resource"
+                    selected="selected" class="AUTO_resource"></option>
+                <option id="option_patron" value="patron"
+                    class="AUTO_patron"></option>
+            </select>
+            <input id="barcode" name="barcode" />
+            <input type="submit" class="AUTO_ATTR_VALUE_go" />
+        </form>
+    </div>
+    <div class="nice_vertical_padding" id="contains_patron_info">
+        <div id="patron_info"></div>
+    </div>
+    <div class="nice_vertical_padding" id="contains_out_bresv">
+        <h3 class="booking AUTO_out_bresv"></h3>
+        <div class="AUTO_no_out_bresv" id="no_out_bresv"></div>
+        <table id="out_bresv" jsId="out_bresv"
+            dojoType="dojox.grid.DataGrid" query="{id: '*'}"
+            rowSelector="20px" autoHeight="true" width="auto">
+            <thead>
+                <tr><!-- FIXME: i18n problem: init_auto_l10n() runs
+                        too late to take care of the below elements. -->
+                    <th width="35%" field="type">Title</th>
+                    <th width="25%" field="resource">Barcode</th>
+                    <th width="20%" field="pickup_time">Pickup time</th>
+                    <th width="20%" field="end_time">Due time</th>
+                </tr>
+            </thead>
+        </table>
+        <div class="nice_vertical_padding" id="controls_out_bresv">
+            <form>
+                <input type="button" id="return_button"
+                    class="AUTO_ATTR_VALUE_return"
+                    onclick="p.act_on_selected('return', 'out');" />
+            </form>
+        </div>
+    </div>
+    <div class="nice_vertical_padding" id="contains_in_bresv">
+        <hr />
+        <h3 class="booking AUTO_in_bresv"></h3>
+        <div class="AUTO_no_in_bresv" id="no_in_bresv"></div>
+        <table id="in_bresv" jsId="in_bresv"
+            dojoType="dojox.grid.DataGrid" query="{id: '*'}"
+            rowSelector="20px" autoHeight="true" width="auto">
+            <thead>
+                <tr><!-- FIXME: i18n problem: init_auto_l10n() runs
+                        too late to take care of the below elements. -->
+                    <th width="35%" field="type">Title</th>
+                    <th width="25%" field="resource">Barcode</th>
+                    <th width="20%" field="due_time">Due time</th>
+                    <th width="20%" field="return_time">Return time</th>
+                </tr>
+            </thead>
+        </table>
+    </div>
+    <div class="nice_vertical_padding" id="contains_misc_controls">
+        <hr />
+        <form>
+            <input type="button" class="AUTO_ATTR_VALUE_reset"
+                onclick="p.reset();" />
+        </form>
+    </div>
+</div>
+[% END %]
index c59d2be..75c81cb 100644 (file)
@@ -748,7 +748,7 @@ main.menu.prototype = {
                 ['oncommand'],
                 function() {
                     obj.set_tab(
-                        "/eg/booking/reservation_pickup",
+                        "/eg/booking/pickup",
                         {
                             "tab_name": offlineStrings.getString(
                                 "menu.cmd_booking_reservation_pickup.tab"
@@ -763,7 +763,7 @@ main.menu.prototype = {
                 ['oncommand'],
                 function() {
                     obj.set_tab(
-                        "/eg/booking/reservation_return",
+                        "/eg/booking/return",
                         {
                             "tab_name": offlineStrings.getString(
                                 "menu.cmd_booking_reservation_return.tab"
index ae96d98..15ec84c 100644 (file)
         <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"/> -->
+         <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>
 
index 42865bb..b366253 100644 (file)
@@ -387,6 +387,48 @@ patron.display.prototype = {
                             );
                         }
                     ],
+                    'cmd_patron_reservation_pickup' : [
+                        ['command'],
+                        function(ev) {
+                            if (xulG.auth == undefined) {
+                                xulG.auth = {"session": {"key": ses()}};
+                            }
+                            xulG.bresv_interface_opts = {
+                                "patron_barcode": obj.patron.card().barcode()
+                            };
+                            xulG.new_tab(
+                                "/eg/booking/pickup",
+                                {
+                                    "tab_name": offlineStrings.getString(
+                                        "menu.cmd_booking_reservation_pickup.tab"
+                                    ),
+                                    "browser": false
+                                },
+                                xulG
+                            );
+                        }
+                    ],
+                    'cmd_patron_reservation_return' : [
+                        ['command'],
+                        function(ev) {
+                            if (xulG.auth == undefined) {
+                                xulG.auth = {"session": {"key": ses()}};
+                            }
+                            xulG.bresv_interface_opts = {
+                                "patron_barcode": obj.patron.card().barcode()
+                            };
+                            xulG.new_tab(
+                                "/eg/booking/return",
+                                {
+                                    "tab_name": offlineStrings.getString(
+                                        "menu.cmd_booking_reservation_return.tab"
+                                    ),
+                                    "browser": false
+                                },
+                                xulG
+                            );
+                        }
+                    ],
                     'cmd_patron_exit' : [
                         ['command'],
                         function(ev) {
index 441cb06..5206ea1 100644 (file)
         <command id="cmd_patron_other" />
         <command id="cmd_patron_alert" />
         <command id="cmd_patron_reservation" />
+        <command id="cmd_patron_reservation_pickup" />
+        <command id="cmd_patron_reservation_return" />
         <command id="cmd_patron_exit" />
         <command id="cmd_patron_retrieve" />
         <command id="cmd_patron_merge" />
index 587c8cc..4170d5f 100644 (file)
         <command id="cmd_patron_other" />
         <command id="cmd_patron_alert" />
         <command id="cmd_patron_reservation" />
+        <command id="cmd_patron_reservation_pickup" />
+        <command id="cmd_patron_reservation_return" />
         <command id="cmd_patron_exit" />
         <command id="cmd_patron_retrieve" />
         <command id="cmd_patron_merge" />
index 60dbec0..3481ca2 100644 (file)
@@ -93,6 +93,8 @@
                                     <menuitem label="&staff.patron.info.triggered_events.label;" accesskey="&staff.patron.info.triggered_events.accesskey;" command="cmd_patron_info_triggered_events"/>
                                     <menuitem label="&staff.patron.info.stat_cats.label;" accesskey="&staff.patron.info.stat_cats.accesskey;" command="cmd_patron_info_stats"/>
                                     <menuitem label="&staff.main.menu.booking.reservation.label;" accesskey="&staff.main.menu.booking.reservation.accesskey;" command="cmd_patron_reservation" />
+                                    <menuitem label="&staff.main.menu.booking.reservation_pickup.label;" accesskey="&staff.main.menu.booking.reservation_pickup.accesskey;" command="cmd_patron_reservation_pickup" />
+                                    <menuitem label="&staff.main.menu.booking.reservation_return.label;" accesskey="&staff.main.menu.booking.reservation_return.accesskey;" command="cmd_patron_reservation_return" />
                                     <menuitem label="&staff.patron.info.surveys.label;" accesskey="&staff.patron.info.surveys.accesskey;" command="cmd_patron_info_surveys"/>
                                     <menuitem label="&staff.patron.info.group.label;" accesskey="&staff.patron.info.group.accesskey;" command="cmd_patron_info_groups"/>
                                     <menuitem label="&staff.patron_display.verify_password.label;" accesskey="&staff.patron_display.verify_password.accesskey;" command="cmd_verify_credentials"/>
index 55edb18..3137c53 100644 (file)
@@ -93,6 +93,8 @@
                                     <menuitem label="&staff.patron.info.triggered_events.label;" accesskey="&staff.patron.info.triggered_events.accesskey;" command="cmd_patron_info_triggered_events"/>
                                     <menuitem label="&staff.patron.info.stat_cats.label;" accesskey="&staff.patron.info.stat_cats.accesskey;" command="cmd_patron_info_stats"/>
                                     <menuitem label="&staff.main.menu.booking.reservation.label;" accesskey="&staff.main.menu.booking.reservation.accesskey;" command="cmd_patron_reservation" />
+                                    <menuitem label="&staff.main.menu.booking.reservation_pickup.label;" accesskey="&staff.main.menu.booking.reservation_pickup.accesskey;" command="cmd_patron_reservation_pickup" />
+                                    <menuitem label="&staff.main.menu.booking.reservation_return.label;" accesskey="&staff.main.menu.booking.reservation_return.accesskey;" command="cmd_patron_reservation_return" />
                                     <menuitem label="&staff.patron.info.surveys.label;" accesskey="&staff.patron.info.surveys.accesskey;" command="cmd_patron_info_surveys"/>
                                     <menuitem label="&staff.patron.info.group.label;" accesskey="&staff.patron.info.group.accesskey;" command="cmd_patron_info_groups"/>
                                     <menuitem label="&staff.patron_display.verify_password.label;" accesskey="&staff.patron_display.verify_password.accesskey;" command="cmd_verify_credentials"/>