[open-ils-commits] r17364 - in trunk/Open-ILS: src/extras src/perlmods/OpenILS/Application web/opac/locale/en-US xul/staff_client/server/locale/en-US xul/staff_client/server/serial (senator)

svn at svn.open-ils.org svn at svn.open-ils.org
Fri Aug 27 17:50:34 EDT 2010


Author: senator
Date: 2010-08-27 17:50:28 -0400 (Fri, 27 Aug 2010)
New Revision: 17364

Modified:
   trunk/Open-ILS/src/extras/ils_events.xml
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm
   trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
   trunk/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
   trunk/Open-ILS/xul/staff_client/server/serial/batch_receive.js
   trunk/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul
Log:
Serials: closer to full working receiving in the batch receive interface

Units are actually created now, one per item. Plus misc bug fixes.
For more flexible binding of items into units, see the serial control view.



Modified: trunk/Open-ILS/src/extras/ils_events.xml
===================================================================
--- trunk/Open-ILS/src/extras/ils_events.xml	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/src/extras/ils_events.xml	2010-08-27 21:50:28 UTC (rev 17364)
@@ -972,6 +972,14 @@
         <desc xml:lang="en-US">The caption/pattern still has dependent issuances</desc>
     </event>
 
+    <event code='11101' textcode='SERIAL_DISTRIBUTION_HAS_NO_COPY_TEMPLATE'>
+        <desc xml:lang="en-US">Units cannot be created for the given item because its associated distribution does not have a copy template.</desc>
+    </event>
+
+    <event code='11102' textcode='SERIAL_DISTRIBUTION_HAS_NO_CALL_NUMBER'>
+        <desc xml:lang="en-US">Units cannot be created for the given item because its associated distribution does not have a call number.</desc>
+    </event>
+
 	<!-- ================================================================ -->
 
 </ils_events>

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Serial.pm	2010-08-27 21:50:28 UTC (rev 17364)
@@ -37,6 +37,7 @@
 use strict;
 use warnings;
 
+
 use OpenILS::Application;
 use base qw/OpenILS::Application/;
 use OpenILS::Application::AppUtils;
@@ -876,13 +877,125 @@
     return {'num_items_received' => scalar @$items, 'new_unit_id' => $new_unit_id};
 }
 
+__PACKAGE__->register_method(
+    method    => "receive_items_one_unit_per",
+    api_name  => "open-ils.serial.receive_items.one_unit_per",
+    stream => 1,
+    api_level => 1,
+    argc      => 1,
+    signature => {
+        desc     => "Marks items in a list as received, creates a new unit for each item if any unit is fleshed on",
+        "params" => [ {
+                 name => "items",
+                 desc => "array of serial items, possibly fleshed with units and definitely fleshed with stream->distribution",
+                 type => "array"
+            }
+        ],
+        "return" => {
+            desc => "The item ID for each item successfully received",
+            type => "int"
+        }
+    }
+);
+
+sub receive_items_one_unit_per {
+    # XXX This function may be temporary. unitize_items() would seem to aim to
+    # accomodate what this function does as well as other variations on the
+    # operation (binding multiple items into one unit, etc.?) plus generating
+    # summaries.  This is just a minimal get-it-working-now implementation.
+    # In the future, when unitize_items() is ready, perhaps any registered
+    # method names that point to this function can be repointed at
+    # unitize_items()
+
+    my ($self, $client, $auth, $items) = @_;
+
+    my $e = new_editor("authtoken" => $auth, "xact" => 1);
+    return $e->die_event unless $e->checkauth;
+
+    my $user_id = $e->requestor->id;
+
+    # Get a list of all the non-virtual field names in a serial::unit for
+    # merging given unit objects with template-built units later.
+    # XXX move this somewhere global so it isn't re-run all the time
+    my $all_unit_fields =
+        $Fieldmapper::fieldmap->{"Fieldmapper::serial::unit"}->{"fields"};
+    my @real_unit_fields = grep {
+        not $all_unit_fields->{$_}->{"virtual"}
+    } keys %$all_unit_fields;
+
+    foreach my $item (@$items) {
+        # Note that we expect a certain fleshing on the items we're getting.
+        my $sdist = $item->stream->distribution;
+
+        # Create unit if given by user
+        if (ref $item->unit) {
+            # detach from the item, as we need to create separately
+            my $user_unit = $item->unit;
+
+            # get a unit based on associated template
+            my $template_unit = _build_unit($e, $sdist, "receive");
+            if ($U->event_code($template_unit)) {
+                $e->rollback;
+                $template_unit->{"note"} = "Item ID: " . $item->id;
+                return $template_unit;
+            }
+
+            # merge built unit with provided unit from user
+            foreach (@real_unit_fields) {
+                unless ($user_unit->$_) {
+                    $user_unit->$_($template_unit->$_);
+                }
+            }
+
+            # set the incontrovertibles on the unit
+            $user_unit->edit_date("now");
+            $user_unit->create_date("now");
+            $user_unit->editor($user_id);
+            $user_unit->creator($user_id);
+
+            return $e->die_event unless $e->create_serial_unit($user_unit);
+
+            # save reference to new unit
+            $item->unit($e->data->id);
+        }
+
+        # Create notes if given by user
+        if (ref($item->notes) and @{$item->notes}) {
+            foreach my $note (@{$item->notes}) {
+                $note->creator($user_id);
+                $note->create_date("now");
+
+                return $e->die_event unless $e->create_serial_item_note($note);
+            }
+
+            $item->clear_notes; # They're saved; we no longer want them here.
+        }
+
+        # Set the incontrovertibles on the item
+        $item->date_received("now");
+        $item->edit_date("now");
+        $item->editor($user_id);
+
+        return $e->die_event unless $e->update_serial_item($item);
+
+        # send client a response
+        $client->respond($item->id);
+    }
+
+    # XXX TODO update basic/supplementary/index summaries
+
+    $e->commit or return $e->die_event;
+    undef;
+}
+
 sub _build_unit {
     my $editor = shift;
     my $sdist = shift;
     my $mode = shift;
 
     my $attr = $mode . '_unit_template';
-    my $template = $editor->retrieve_asset_copy_template($sdist->$attr);
+    my $template = $editor->retrieve_asset_copy_template($sdist->$attr) or
+        return new OpenILS::Event("SERIAL_DISTRIBUTION_HAS_NO_COPY_TEMPLATE");
 
     my @parts = qw( status location loan_duration fine_level age_protect circulate deposit ref holdable deposit_amount price circ_modifier circ_as_type alert_message opac_visible floating mint_condition );
 
@@ -897,8 +1010,12 @@
     $unit->circ_lib($sdist->holding_lib);
     $unit->creator($editor->requestor->id);
     $unit->editor($editor->requestor->id);
+
     $attr = $mode . '_call_number';
-    $unit->call_number($sdist->$attr);
+    my $cn = $sdist->$attr or
+        return new OpenILS::Event("SERIAL_DISTRIBUTION_HAS_NO_CALL_NUMBER");
+
+    $unit->call_number($cn);
     $unit->barcode('AUTO');
     $unit->sort_key('');
     $unit->summary_contents('');
@@ -1808,14 +1925,19 @@
     my $issuance_ids = $e->json_query({
         "select" => {
             "siss" => [
-                {"transform" => "distinct", "column" => "id"}
+                {"transform" => "distinct", "column" => "id"},
+                "date_published"
             ]
         },
         "from" => {"siss" => "sitem"},
         "where" => {
             "subscription" => $sub_id,
             "+sitem" => {"date_received" => undef}
+        },
+        "order_by" => {
+            "siss" => {"date_published" => {"direction" => "asc"}}
         }
+
     }) or return $e->die_event;
 
     $client->respond($e->retrieve_serial_issuance($_->{"id"}))

Modified: trunk/Open-ILS/web/opac/locale/en-US/lang.dtd
===================================================================
--- trunk/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-08-27 21:50:28 UTC (rev 17364)
@@ -1619,9 +1619,9 @@
 <!ENTITY staff.serial.batch_receive.no_items "There are no items to receive for this subscription.">
 <!ENTITY staff.serial.batch_receive.org_unit "Org Unit">
 <!ENTITY staff.serial.batch_receive.barcode "Barcode">
-<!ENTITY staff.serial.batch_receive.circ_mod "Circ Modifier">
+<!ENTITY staff.serial.batch_receive.circ_modifier "Circ Modifier">
 <!ENTITY staff.serial.batch_receive.note "Note">
-<!ENTITY staff.serial.batch_receive.copy_loc "Copy Location">
+<!ENTITY staff.serial.batch_receive.location "Copy Location">
 <!ENTITY staff.serial.batch_receive.price "Price">
 <!ENTITY staff.serial.batch_receive.receive "Receive?">
 <!ENTITY staff.serial.batch_receive.auto_generate "Auto-generate?">

Modified: trunk/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties	2010-08-27 21:50:28 UTC (rev 17364)
@@ -63,3 +63,4 @@
 batch_receive.autogen_barcodes.remove=Clear the barcodes that have already been auto-generated?
 batch_receive.none=[None]
 batch_receive.apply=Apply
+batch_receive.receive_time_note=Receive-time Note

Modified: trunk/Open-ILS/xul/staff_client/server/serial/batch_receive.js
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/serial/batch_receive.js	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/xul/staff_client/server/serial/batch_receive.js	2010-08-27 21:50:28 UTC (rev 17364)
@@ -44,8 +44,8 @@
 }
 
 function T(s) { return document.createTextNode(s); }
-function D(s) {return s ? openils.Util.timeStamp(s, {"selector":"date"}) : "";}
-function node_by_name(s, ctx) {return dojo.query("[name='" + s + "']", ctx)[0];}
+function D(s) {return s ? openils.Util.timeStamp(s,{"selector":"date"}) : "";}
+function node_by_name(s, ctx) {return dojo.query("[name='"+ s +"']",ctx)[0];}
 
 function num_sort(a, b) {
     [a, b] = [Number(a), Number(b)];
@@ -80,13 +80,20 @@
 
         this._clear_entry_batch_row();
 
-        this._copy_loc_by_lib = {};
+        this._location_by_lib = {};
 
         /* empty the entry receiving table if we're starting over */
         if (this.item_cache) {
-            for (var id in this.item_cache)
+            for (var id in this.item_cache) {
                 this.finish_receipt(this.item_cache[id]);
+                hard_empty(this.entry_tbody);
+            }
+            /* XXX incredibly, running hard_empty() more than once seems to be
+             * good and necessary.  There's a bug under the covers somewhere,
+             * but this keeps it out of sight for the moment. */
+             hard_empty(this.entry_tbody);
         }
+        hard_empty(this.entry_tbody);
 
         this.rows = {};
         this.item_cache = {};
@@ -174,8 +181,8 @@
         return issuances;
     };
 
-    this._build_circ_mod_dropdown = function() {
-        if (!this._built_circ_mod_dropdown) {
+    this._build_circ_modifier_dropdown = function() {
+        if (!this._built_circ_modifier_dropdown) {
             var menulist = dojo.create("menulist");
             var menupopup = dojo.create("menupopup", null, menulist, "only");
             dojo.create(
@@ -185,16 +192,24 @@
 
             var mods = [];
             fieldmapper.standardRequest(
-                ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"], {
-                    "params": [],
+                ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"],{
+                    "params": [{"full": true}],
                     "async": false,
                     "onresponse": function(r) {
                         if (mods = openils.Util.readResponse(r)) {
-                            mods.forEach(
+                            mods.sort(
+                                function(a,b) {
+                                    return a.code() > b.code() ? 1 :
+                                        b.code() > a.code() ? -1 :
+                                        0;
+                                }
+                            ).forEach(
                                 function(mod) {
                                     dojo.create(
                                         "menuitem", {
-                                            "value": mod, "label": mod
+                                            "value": mod.code(),
+                                            /* XXX use format string */
+                                            "label": mod.code()+" "+mod.name()
                                         }, menupopup, "last"
                                     );
                                 }
@@ -205,17 +220,17 @@
             );
             if (!mods.length) {
                 /* in this case, discard menulist and menupopup */
-                this._built_circ_mod_dropdown =
+                this._built_circ_modifier_dropdown =
                     dojo.create("description", {"value": "-"});
             } else {
-                this._built_circ_mod_dropdown = menulist;
+                this._built_circ_modifier_dropdown = menulist;
             }
         }
 
-        return dojo.clone(this._built_circ_mod_dropdown);
+        return dojo.clone(this._built_circ_modifier_dropdown);
     };
 
-    this._extend_circ_mod_for_batch = function(control) {
+    this._extend_circ_modifier_for_batch = function(control) {
         dojo.create(
             "menuitem", {"value": -1, "label": "---"},
             dojo.query("menupopup", control)[0],
@@ -224,7 +239,7 @@
         return control;
     };
 
-    this._build_copy_loc_dropdown = function(locs, add_unset_value) {
+    this._build_location_dropdown = function(locs, add_unset_value) {
         var menulist = dojo.create("menulist");
         var menupopup = dojo.create("menupopup", null, menulist, "only");
 
@@ -249,21 +264,21 @@
         return menulist;
     };
 
-    this._get_copy_locs_for_lib = function(lib) {
-        if (!this._copy_loc_by_lib[lib]) {
+    this._get_locations_for_lib = function(lib) {
+        if (!this._location_by_lib[lib]) {
             fieldmapper.standardRequest(
-                ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"], {
+                ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"],{
                     "params": [lib, false, true],
                     "async": false,
                     "onresponse": function(r) {
                         if (locs = openils.Util.readResponse(r))
-                            self._copy_loc_by_lib[lib] = locs;
+                            self._location_by_lib[lib] = locs;
                     }
                 }
             );
         }
 
-        return this._copy_loc_by_lib[lib];
+        return this._location_by_lib[lib];
     };
 
     this._build_receive_toggle = function(item) {
@@ -384,8 +399,8 @@
                 ],
                 "async": false,
                 "oncomplete": function(r) {
-                    /* These two things better come before readResponse(), which
-                     * can throw exceptions. */
+                    /* These two things better come before readResponse(),
+                     * which can throw exceptions. */
                     busy(false);
                     dojo.byId("bib_lookup_submit").disabled = false;
 
@@ -472,8 +487,8 @@
 
             this.issuances.sort(
                 function(a, b) {
-                    if (a.date_published() > b.date_published()) return 1;
-                    else if (b.date_published() > a.date_published()) return -1;
+                    if (a.date_published()>b.date_published()) return 1;
+                    else if (b.date_published()>a.date_published()) return -1;
                     else return 0;
                 }
             ).forEach(
@@ -557,18 +572,21 @@
             this.batch_controls.note = dojo.create("textbox", {"size": 20})
         );
 
-        node_by_name("copy_loc", row).appendChild(
-            this.batch_controls.copy_loc = this._build_copy_loc_dropdown(
-                /* XXX is 1 really the right value below? */
-                this._get_copy_locs_for_lib(1),
+        node_by_name("location", row).appendChild(
+            this.batch_controls.location = this._build_location_dropdown(
+                /* XXX TODO build a smarter list. rather than all copy locs
+                 * under OU #1, try building a list of copy locs available to
+                 * all OUs represented in actual items */
+                this._get_locations_for_lib(1),
                 true /* add_unset_value */
             )
         );
 
-        node_by_name("circ_mod", row).appendChild(
-            this.batch_controls.circ_mod = this._extend_circ_mod_for_batch(
-                this._build_circ_mod_dropdown()
-            )
+        node_by_name("circ_modifier", row).appendChild(
+            this.batch_controls.circ_modifier =
+                this._extend_circ_modifier_for_batch(
+                    this._build_circ_modifier_dropdown()
+                )
         );
 
         node_by_name("price", row).appendChild(
@@ -615,16 +633,16 @@
             )
         );
 
-        n("copy_loc").appendChild(
-            this._build_copy_loc_dropdown(
-                this._get_copy_locs_for_lib(
+        n("location").appendChild(
+            this._build_location_dropdown(
+                this._get_locations_for_lib(
                     item.stream().distribution().holding_lib().id()
                 )
             )
         );
 
         n("note").appendChild(dojo.create("textbox", {"size": 20}));
-        n("circ_mod").appendChild(this._build_circ_mod_dropdown());
+        n("circ_modifier").appendChild(this._build_circ_modifier_dropdown());
         n("price").appendChild(dojo.create("textbox", {"size": 9}));
         n("receive").appendChild(this._build_receive_toggle(item));
 
@@ -632,22 +650,52 @@
     };
 
     this.receive = function() {
-        var recv_ids = [];
+        var items = [];
         for (var id in this.rows) {
-            /* XXX TODO: get field values, send to ML,
-             * and yes do trimming here. */
-            if (!this._row_disabled(id)) recv_ids.push(id);
+            if (this._row_disabled(id)) 
+                continue;
+
+            var item = this.item_cache[id];
+
+            var barcode = this._row_field_value(id, "barcode");
+            if (barcode) {
+                var unit = new sunit();
+                unit.barcode(barcode);
+
+                ["price", "location", "circ_modifier"].forEach(
+                    function(field) {
+                        var value = self._row_field_value(id, field).trim();
+                        if (value) unit[field](value);
+                    }
+                );
+
+
+                item.unit(unit);
+            }
+
+            var note_value = this._row_field_value(id, "note").trim();
+            if (note_value) {
+                var note = new sin();
+                note.item(id);
+                note.pub(false);
+                note.title(S("receive_time_note"));
+                note.value(note_value);
+
+                item.notes([note]);
+            }
+
+            items.push(item);
         }
 
         busy(true);
         fieldmapper.standardRequest(
-            ["open-ils.serial", "open-ils.serial.items.receive_by_id"], {
-                "params": [authtoken, recv_ids],
+            ["open-ils.serial", "open-ils.serial.receive_items.one_unit_per"],{
+                "params": [authtoken, items],
                 "async": true,
                 "oncomplete": function(r) {
                     try {
-                        while (item = openils.Util.readResponse(r))
-                            self.finish_receipt(item);
+                        while (item_id = openils.Util.readResponse(r))
+                            self.finish_receipt(item_id);
                     } catch (E) {
                         alert(E);
                     }
@@ -657,10 +705,11 @@
         );
     };
 
-    this.finish_receipt = function(item) {
-        dojo.destroy(this.rows[item.id()]);
-        delete this.rows[item.id()];
-        delete this.item_cache[item.id()];
+    this.finish_receipt = function(item_id) {
+        hard_empty(this.rows[item_id]);
+        dojo.destroy(this.rows[item_id]);
+        delete this.rows[item_id];
+        delete this.item_cache[item_id];
     };
 
     this.autogen_if_appropriate = function(textbox, item_id) {

Modified: trunk/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul
===================================================================
--- trunk/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul	2010-08-27 21:11:05 UTC (rev 17363)
+++ trunk/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul	2010-08-27 21:50:28 UTC (rev 17364)
@@ -93,13 +93,13 @@
                                     &staff.serial.batch_receive.barcode;
                                 </h:th>
                                 <h:th>
-                                    &staff.serial.batch_receive.circ_mod;
+                                    &staff.serial.batch_receive.circ_modifier;
                                 </h:th>
                                 <h:th>
                                     &staff.serial.batch_receive.note;
                                 </h:th>
                                 <h:th>
-                                    &staff.serial.batch_receive.copy_loc;
+                                    &staff.serial.batch_receive.location;
                                 </h:th>
                                 <h:th>
                                     &staff.serial.batch_receive.price;
@@ -117,9 +117,9 @@
                                         id="autogen_barcodes"
                                         label="&staff.serial.batch_receive.auto_generate;" />
                                 </h:td>
-                                <h:td name="circ_mod" align="center"></h:td>
+                                <h:td name="circ_modifier" align="center"></h:td>
                                 <h:td name="note"></h:td>
-                                <h:td name="copy_loc" align="center"></h:td>
+                                <h:td name="location" align="center"></h:td>
                                 <h:td name="price"></h:td>
                                 <h:td name="receive"></h:td>
                                 <h:td name="apply"></h:td>
@@ -134,9 +134,9 @@
                             <h:tr id="entry_template">
                                 <h:td name="holding_lib" align="center"></h:td>
                                 <h:td name="barcode"></h:td>
-                                <h:td name="circ_mod" align="center"></h:td>
+                                <h:td name="circ_modifier" align="center"></h:td>
                                 <h:td name="note"></h:td>
-                                <h:td name="copy_loc" align="center"></h:td>
+                                <h:td name="location" align="center"></h:td>
                                 <h:td name="price"></h:td>
                                 <h:td name="receive" align="center"></h:td>
                             </h:tr>



More information about the open-ils-commits mailing list