Add support for sre/distribution summary methods (including merge), advanced receivin...
authordbwells <dbwells@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 2 May 2011 20:57:01 +0000 (20:57 +0000)
committerdbwells <dbwells@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 2 May 2011 20:57:01 +0000 (20:57 +0000)
This commit includes three new minor features for the Serial Control interface.  First, you are now able to set the latent 'summary_method' field on distributions, with the most significant new setting being 'merge with sre'.  This setting effectively combines the sre marc with the generated holdings to form a single unified statement.  Second, the previous 'receive' functionality has been renamed to 'advanced receive', and 'receive' will now show items from an entire subscription, but not allow you to receive directly into a specific unit (you can still receive into new/auto units).  Third, a basic menu entry has been added for receving into 'no unit', allowing items to be received not forcing them to be unitized.

git-svn-id: svn://svn.open-ils.org/ILS/trunk@20378 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Serial.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm
Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHDParser.pm
Open-ILS/web/opac/locale/en-US/lang.dtd
Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
Open-ILS/xul/staff_client/server/serial/manage_items.js
Open-ILS/xul/staff_client/server/serial/manage_items.xul
Open-ILS/xul/staff_client/server/serial/sdist_editor.js

index 06d2f63..a08a8c3 100644 (file)
@@ -125,8 +125,12 @@ sub bib_to_svr {
        my $mfhd_parser = OpenILS::Utils::MFHDParser->new();
        foreach (@$sdists) {
         my $svr;
-        if (ref $_->record_entry) {
-            $svr = $mfhd_parser->generate_svr($_->record_entry->id, $_->record_entry->marc, $_->record_entry->owning_lib);
+        if (ref $_->record_entry and $_->summary_method ne 'use_sdist_only') {
+            my $skip_all_computable = 0;
+            if ($_->summary_method eq 'merge_with_sre') { # 'computable' (85x/86x combos) are handled by generated_coverage when attempting to merge
+                $skip_all_computable = 1;
+            }
+            $svr = $mfhd_parser->generate_svr($_->record_entry->id, $_->record_entry->marc, $_->record_entry->owning_lib, $skip_all_computable);
         } else {
             $svr = Fieldmapper::serial::virtual_record->new;
             $svr->sre_id(-1);
@@ -142,28 +146,30 @@ sub bib_to_svr {
             $svr->missing([]);
             $svr->incomplete([]);
         }
-        if (ref $_->basic_summary) { #TODO: 'show-generated' boolean on summaries
-            if ($_->basic_summary->generated_coverage) {
-                push(@{$svr->basic_holdings}, $_->basic_summary->generated_coverage);
-            }
-            if ($_->basic_summary->textual_holdings) {
-                push(@{$svr->basic_holdings_add}, $_->basic_summary->textual_holdings);
-            }
-        }
-        if (ref $_->supplement_summary) {
-            if ($_->supplement_summary->generated_coverage) {
-                push(@{$svr->supplement_holdings}, $_->supplement_summary->generated_coverage);
-            }
-            if ($_->supplement_summary->textual_holdings) {
-                push(@{$svr->supplement_holdings_add}, $_->supplement_summary->textual_holdings);
+        if ($_->summary_method ne 'use_sre_only') {
+            if (ref $_->basic_summary) { #TODO: 'show-generated' boolean on summaries
+                if ($_->basic_summary->generated_coverage) {
+                    push(@{$svr->basic_holdings}, $_->basic_summary->generated_coverage);
+                }
+                if ($_->basic_summary->textual_holdings) {
+                    push(@{$svr->basic_holdings_add}, $_->basic_summary->textual_holdings);
+                }
             }
-        }
-        if (ref $_->index_summary) {
-            if ($_->index_summary->generated_coverage) {
-                push(@{$svr->index_holdings}, $_->index_summary->generated_coverage);
+            if (ref $_->supplement_summary) {
+                if ($_->supplement_summary->generated_coverage) {
+                    push(@{$svr->supplement_holdings}, $_->supplement_summary->generated_coverage);
+                }
+                if ($_->supplement_summary->textual_holdings) {
+                    push(@{$svr->supplement_holdings_add}, $_->supplement_summary->textual_holdings);
+                }
             }
-            if ($_->index_summary->textual_holdings) {
-                push(@{$svr->index_holdings_add}, $_->index_summary->textual_holdings);
+            if (ref $_->index_summary) {
+                if ($_->index_summary->generated_coverage) {
+                    push(@{$svr->index_holdings}, $_->index_summary->generated_coverage);
+                }
+                if ($_->index_summary->textual_holdings) {
+                    push(@{$svr->index_holdings_add}, $_->index_summary->textual_holdings);
+                }
             }
         }
         push(@$svrs, $svr);
index 2ee5cba..d81275f 100644 (file)
@@ -932,8 +932,6 @@ sub make_predictions {
 # a hash ref of options initially defined as:
 # caption : the caption field to predict on
 # num_to_predict : the number of issues you wish to predict
-# last_rec_date : the date of the last received issue, to be used as an offset
-#                 for predicting future issues
 # faked_chron_date : if the serial does not actually have a chronology caption (but we need one for prediction's sake), base predictions on this date
 #
 # The basic method is to first convert to a single holding if compressed, then
@@ -952,7 +950,6 @@ sub _generate_issuance_values {
     my $end_date = $options->{end_date};
     my $predict_from = $options->{predict_from};   # issuance to predict from
     my $faked_chron_date = $options->{faked_chron_date};   # serial does not have a chronology caption, so add one (temporarily) based on this date 
-    #my $last_rec_date = $options->{last_rec_date};   # expected or actual
 
 
 # Only needed for 'real' MFHD records, not our temp records
@@ -1040,6 +1037,8 @@ sub _revive_holding {
 
     # build MFHD::Holding
     return new MFHD::Holding($seqno, $holding_field, $caption_field);
+
+    # TODO(?) the underlying MARC and the Holding object end up in conflict concerning subfield '8'
 }
 
 __PACKAGE__->register_method(
@@ -1237,11 +1236,13 @@ sub unitize_items {
 
         $found_stream_ids{$stream_id} = 1;
 
-        if (defined($unit_id)) {
+        if (defined($unit_id) and $unit_id ne '') {
             $found_unit_ids{$unit_id} = 1;
             # save the stream_id for this unit_id
             # TODO: prevent items from different streams in same unit? (perhaps in interface)
             $stream_ids_by_unit_id{$unit_id} = $stream_id;
+        } else {
+            $item->clear_unit;
         }
 
         my $evt = _update_sitem($editor, undef, $item);
@@ -1324,6 +1325,7 @@ sub unitize_items {
             } else {
                 $sdist = $editor->search_serial_distribution([{"+sstr" => {"id" => $stream_id}}, { "join" => {"sstr" => {}} }]);
                 $sdist = $sdist->[0];
+                $sdist_by_stream_id{$stream_id} = $sdist;
             }
             my $streams;
             if (!exists($streams_by_sdist{$sdist->id})) {
@@ -1344,7 +1346,7 @@ sub unitize_items {
             foreach my $type (keys %{$found_types{$stream_id}}) {
                 my $issuances = $editor->search_serial_issuance([ {"+sitem" => {"stream" => $stream_id, "status" => "Received"}, "+scap" => {"type" => $type}}, {"join" => {"sitem" => {}, "scap" => {}}, "order_by" => {"siss" => "date_published"}} ]);
                 #TODO: evt on search failure
-                my $evt = _prepare_summaries($editor, $issuances, $sdist_id, $type);
+                my $evt = _prepare_summaries($editor, $issuances, $sdist_by_stream_id{$stream_id}, $type);
                 if ($U->event_code($evt)) {
                     $editor->rollback;
                     return $evt;
@@ -1459,12 +1461,12 @@ sub _prepare_unit {
 # type ('basic', 'index', 'supplement') for a given distribution.
 # It also creates the summary if it doesn't yet exist.
 sub _prepare_summaries {
-    my ($e, $issuances, $dist_id, $type) = @_;
+    my ($e, $issuances, $sdist, $type) = @_;
 
-    my ($mfhd, $formatted_parts) = _summarize_contents($e, $issuances);
+    my ($mfhd, $formatted_parts) = _summarize_contents($e, $issuances, $sdist);
 
     my $search_method = "search_serial_${type}_summary";
-    my $summary = $e->$search_method([{"distribution" => $dist_id}]);
+    my $summary = $e->$search_method([{"distribution" => $sdist->id}]);
 
     my $cu_method = "update";
 
@@ -1473,7 +1475,7 @@ sub _prepare_summaries {
     } else {
         my $class = "Fieldmapper::serial::${type}_summary";
         $summary = $class->new;
-        $summary->distribution($dist_id);
+        $summary->distribution($sdist->id);
         $cu_method = "create";
     }
 
@@ -1660,7 +1662,7 @@ sub receive_items_one_unit_per {
             unless (grep { $_->id == $item->issuance->id } @$issuances_received) {
                 push @$issuances_received, $item->issuance;
             }
-            $evt = _prepare_summaries($e, $issuances_received, $item->stream->distribution->id, $item->issuance->holding_type);
+            $evt = _prepare_summaries($e, $issuances_received, $item->stream->distribution, $item->issuance->holding_type);
             if ($U->event_code($evt)) {
                 $e->rollback;
                 return $evt;
@@ -1751,14 +1753,32 @@ sub _build_unit {
 sub _summarize_contents {
     my $editor = shift;
     my $issuances = shift;
+    my $sdist = shift;
+
+    # create or lookup MFHD record
+    my $mfhd;
+    if ($sdist and defined($sdist->record_entry) and $sdist->summary_method eq 'merge_with_sre') {
+        my $sre;
+        if (ref $sdist->record_entry) {
+            $sre = $sdist->record_entry; 
+        } else {
+            $sre = $editor->retrieve_serial_record_entry($sdist->record_entry);
+        }
+        $mfhd = MFHD->new(MARC::Record->new_from_xml($sre->marc)); 
+    } else {
+        $logger->info($sdist);
+        $mfhd = MFHD->new(MARC::Record->new());
+    }
 
-    # create MFHD record
-    my $mfhd = MFHD->new(MARC::Record->new());
     my %scaps;
     my %scap_fields;
-    my @scap_fields_ordered;
     my $seqno = 1;
-    my $link_id = 1;
+    # We keep track of these separately to avoid link_id contamination,
+    # e.g. a basic issuance, followed by a merging supplement, followed by
+    # another basic.  If we could be sure that they were not mixed, one
+    # value could suffice.
+    my %link_ids = ('basic' => 10000, 'index' => 10000, 'supplement' => 10000);
+    my %first_scap = ('basic' => 1, 'index' => 1, 'supplement' => 1);
     foreach my $issuance (@$issuances) {
         my $scap_id = $issuance->caption_and_pattern;
         next if (!$scap_id); # skip issuances with no caption/pattern
@@ -1770,13 +1790,35 @@ sub _summarize_contents {
             $scaps{$scap_id} = $editor->retrieve_serial_caption_and_pattern($scap_id);
             $scap = $scaps{$scap_id};
             $scap_field = _revive_caption($scap);
+            my $did_merge = 0;
+            if ($first_scap{$scap->type}) { # special merge processing
+                $first_scap{$MFHD_TAGS_BY_NAME{$scap->type}} = 0;
+                if ($sdist and $sdist->summary_method eq 'merge_with_sre') {
+                    # MFHD Caption objects do not yet have a built-in compare (TODO), so let's do a basic one
+                    my @field_85xs = $mfhd->field($MFHD_TAGS_BY_NAME{$scap->type});
+                    if (@field_85xs) {
+                        my $last_caption_field = $field_85xs[-1];
+                        my $last_link_id = $last_caption_field->subfield('8');
+                        # set the link id to match, temporarily, for comparison
+                        $last_caption_field->update('8' => $scap_field->subfield('8'));
+                        my $last_caption_json = OpenSRF::Utils::JSON->perl2JSON([$last_caption_field->indicator(1), $last_caption_field->indicator(2), $last_caption_field->subfields_list]);
+                        if ($last_caption_json eq $scap->pattern_code) { # merge is possible, they match
+                            # restore link id
+                            $link_ids{$scap->type} = $last_link_id;
+                            # set scap_field to last field
+                            $scap_field = $last_caption_field;
+                            $did_merge = 1;
+                        }
+                    }
+                }
+            }
             $scap_fields{$scap_id} = $scap_field;
-            push(@scap_fields_ordered, $scap_field);
-            $scap_field->update('8' => $link_id);
-            $mfhd->append_fields($scap_field);
-            $link_id++;
+            $scap_field->update('8' => $link_ids{$scap->type});
+            # TODO: make MFHD/Caption smarter about this
+            $scap_field->{_mfhdc_LINK_ID} = $link_ids{$scap->type};
+            $mfhd->append_fields($scap_field) if !$did_merge;
+            $link_ids{$scap->type}++;
         } else {
-            $scap = $scaps{$scap_id};
             $scap_field = $scap_fields{$scap_id};
         }
 
@@ -1785,6 +1827,7 @@ sub _summarize_contents {
     }
 
     my @formatted_parts;
+    my @scap_fields_ordered = $mfhd->field('85[345]');
     foreach my $scap_field (@scap_fields_ordered) { #TODO: use generic MFHD "summarize" method, once available
        my @updated_holdings = $mfhd->get_compressed_holdings($scap_field);
        foreach my $holding (@updated_holdings) {
index 7a191dd..0540e35 100644 (file)
@@ -54,7 +54,7 @@ Returns a Perl hash containing fields of interest from the MFHD record
 =cut
 
 sub mfhd_to_hash {
-    my ($self, $mfhd_xml) = @_;
+    my ($self, $mfhd_xml, $skip_all_computable) = @_;
 
     my $marc;
     my $mfhd;
@@ -142,55 +142,57 @@ sub mfhd_to_hash {
             }
         }
 
-        if (!exists($skip_computable{'basic'})) {
-            foreach my $cap_id ($mfhd->caption_link_ids('853')) {
-                my @holdings = $mfhd->holdings('863', $cap_id);
-                next unless scalar @holdings;
-                foreach (@holdings) {
-                    push @$basic_holdings, $_->format();
+        if (!$skip_all_computable) {
+            if (!exists($skip_computable{'basic'})) {
+                foreach my $cap_id ($mfhd->caption_link_ids('853')) {
+                    my @holdings = $mfhd->holdings('863', $cap_id);
+                    next unless scalar @holdings;
+                    foreach (@holdings) {
+                        push @$basic_holdings, $_->format();
+                    }
                 }
-            }
-            if (!@$basic_holdings) { # no computed holdings found
+                if (!@$basic_holdings) { # no computed holdings found
+                    $basic_holdings = $basic_holdings_add;
+                    $basic_holdings_add = [];
+                }
+            } else { # textual are non additional, but primary
                 $basic_holdings = $basic_holdings_add;
                 $basic_holdings_add = [];
             }
-        } else { # textual are non additional, but primary
-            $basic_holdings = $basic_holdings_add;
-            $basic_holdings_add = [];
-        }
 
-        if (!exists($skip_computable{'supplement'})) {
-            foreach my $cap_id ($mfhd->caption_link_ids('854')) {
-                my @supplements = $mfhd->holdings('864', $cap_id);
-                next unless scalar @supplements;
-                foreach (@supplements) {
-                    push @$supplement_holdings, $_->format();
+            if (!exists($skip_computable{'supplement'})) {
+                foreach my $cap_id ($mfhd->caption_link_ids('854')) {
+                    my @supplements = $mfhd->holdings('864', $cap_id);
+                    next unless scalar @supplements;
+                    foreach (@supplements) {
+                        push @$supplement_holdings, $_->format();
+                    }
                 }
-            }
-            if (!@$supplement_holdings) { # no computed holdings found
+                if (!@$supplement_holdings) { # no computed holdings found
+                    $supplement_holdings = $supplement_holdings_add;
+                    $supplement_holdings_add = [];
+                }
+            } else { # textual are non additional, but primary
                 $supplement_holdings = $supplement_holdings_add;
                 $supplement_holdings_add = [];
             }
-        } else { # textual are non additional, but primary
-            $supplement_holdings = $supplement_holdings_add;
-            $supplement_holdings_add = [];
-        }
 
-        if (!exists($skip_computable{'index'})) {
-            foreach my $cap_id ($mfhd->caption_link_ids('855')) {
-                my @indexes = $mfhd->holdings('865', $cap_id);
-                next unless scalar @indexes;
-                foreach (@indexes) {
-                    push @$index_holdings, $_->format();
+            if (!exists($skip_computable{'index'})) {
+                foreach my $cap_id ($mfhd->caption_link_ids('855')) {
+                    my @indexes = $mfhd->holdings('865', $cap_id);
+                    next unless scalar @indexes;
+                    foreach (@indexes) {
+                        push @$index_holdings, $_->format();
+                    }
                 }
-            }
-            if (!@$index_holdings) { # no computed holdings found
+                if (!@$index_holdings) { # no computed holdings found
+                    $index_holdings = $index_holdings_add;
+                    $index_holdings_add = [];
+                }
+            } else { # textual are non additional, but primary
                 $index_holdings = $index_holdings_add;
                 $index_holdings_add = [];
             }
-        } else { # textual are non additional, but primary
-            $index_holdings = $index_holdings_add;
-            $index_holdings_add = [];
         }
 
         # Laurentian extensions
@@ -271,14 +273,14 @@ Given an MFHD record, return a populated svr instance
 =cut
 
 sub generate_svr {
-    my ($self, $id, $mfhd, $owning_lib) = @_;
+    my ($self, $id, $mfhd, $owning_lib, $skip_all_computable) = @_;
 
     if (!$mfhd) {
         return undef;
     }
 
     my $record   = init_holdings_virtual_record();
-    my $holdings = $self->mfhd_to_hash($mfhd);
+    my $holdings = $self->mfhd_to_hash($mfhd, $skip_all_computable);
 
     $record->sre_id($id);
     $record->owning_lib($owning_lib);
index 405dcca..920db0d 100644 (file)
 <!ENTITY staff.serial.manage_items.mode "Mode:">
 <!ENTITY staff.serial.manage_items.bind.label "Bind">
 <!ENTITY staff.serial.manage_items.receive.label "Receive">
+<!ENTITY staff.serial.manage_items.advanced_receive.label "Adv. Receive">
 <!ENTITY staff.serial.manage_items.show_all.label "Show All">
 <!ENTITY staff.serial.manage_items.receive_move.label "Receive/Move Selected &#8595;">
 <!ENTITY staff.serial.manage_items.set_current_unit.label "Set Current Unit">
 <!ENTITY staff.serial.manage_items.auto_per_item.label "Auto per Item">
 <!ENTITY staff.serial.manage_items.new_unit.label "New Unit">
+<!ENTITY staff.serial.manage_items.no_unit.label "No Unit">
 <!ENTITY staff.serial.manage_items.recent.label "Recent">
 <!ENTITY staff.serial.manage_items.other_unit.label "Other...">
+<!ENTITY staff.serial.manage_items.context.label "Context:">
 
 <!ENTITY staff.serial.batch_receive "Batch Receive">
 <!ENTITY staff.serial.batch_receive.bib_search_term.label "Enter an identifier for a bibliographic record:">
index b0453b6..12463fe 100644 (file)
@@ -26,6 +26,10 @@ staff.serial.sdist_editor.create.accesskey=C
 staff.serial.sdist_editor.modify.label=Modify Distribution(s)
 staff.serial.sdist_editor.modify.accesskey=M
 staff.serial.sdist_editor.notes=Distribution Notes
+staff.serial.sdist_editor.add_to_sre.label=Add to record entry
+staff.serial.sdist_editor.merge_with_sre.label=Merge with record entry
+staff.serial.sdist_editor.use_sre_only.label=Use record entry only
+staff.serial.sdist_editor.use_sdist_only.label=Do not use record entry
 staff.serial.siss_editor.count=1 issuance
 staff.serial.siss_editor.count.plural=%1$s issuances
 staff.serial.siss_editor.create.label=Create Issuance(s)
@@ -59,6 +63,8 @@ staff.serial.manage_dists.delete_sstr.confirm=Are you sure you would like to del
 staff.serial.manage_dists.delete_sstr.confirm.plural=Are you sure you would like to delete these %1$s streams?
 staff.serial.manage_dists.delete_sstr.title=Delete Streams?
 staff.serial.manage_dists.delete_sstr.override=Override Delete Failure? Doing so will delete all attached items as well!
+staff.serial.manage_items.subscriber.label=Subscriber
+staff.serial.manage_items.holder.label=Holder
 staff.serial.manage_subs.add.error=error adding object in manage_subs.js:
 staff.serial.manage_subs.delete.error=error deleting object in manage_subs.js:
 staff.serial.manage_subs.delete_scap.confirm=Are you sure you would like to delete this caption and pattern?
index b7cfc3e..1072ad4 100644 (file)
@@ -22,11 +22,17 @@ serial.manage_items.prototype = {
                var obj = this;
 
         try {
-            obj.holding_lib = $('serial_item_lib_menu').value;
+            obj.lib = $('serial_item_lib_menu').value;
+            var sdist_retrieve_params = {"+ssub":{"record_entry" : obj.docid}};
+            if (obj.mode == 'receive') {
+                sdist_retrieve_params["+ssub"].owning_lib = obj.lib;
+            } else {
+                sdist_retrieve_params.holding_lib = obj.lib;
+            }
             var robj = obj.network.request(
                 'open-ils.pcrud',
                 'open-ils.pcrud.id_list.sdist',
-                [ ses(), {"holding_lib" : obj.holding_lib, "+ssub":{"record_entry" : obj.docid}}, {"join":"ssub"} ]
+                [ ses(), sdist_retrieve_params, {"join":"ssub"} ]
             );
             if (robj != null) {
                 if (typeof robj.ilsevent != 'undefined') throw(robj);
@@ -105,8 +111,10 @@ serial.manage_items.prototype = {
         // deal with mode radio selectedIndex, as load_attributes is setting a "read-only" value
         if ($('mode_receive').getAttribute('selected')) {
             $('serial_manage_items_mode').selectedIndex = 0;
-        } else {
+        } else if ($('mode_advanced_receive').getAttribute('selected')) {
             $('serial_manage_items_mode').selectedIndex = 1;
+        } else {
+            $('serial_manage_items_mode').selectedIndex = 2;
         }
 
         // setup recent sunits list
@@ -298,16 +306,7 @@ serial.manage_items.prototype = {
                         function(evt) {
                             try {
                                 var target = evt.explicitOriginalTarget;
-                                var label = target.label;
-                                var sunit_id = target.getAttribute('sunit_id');
-                                var sdist_id = target.getAttribute('sdist_id');
-                                var sstr_id = target.getAttribute('sstr_id');
-                                obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
-                                obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
-                                if (obj.mode == 'bind') {
-                                    obj.refresh_list('main');
-                                    obj.refresh_list('workarea');
-                                }
+                                obj.process_unit_selection(target);
                             } catch(E) {
                                 obj.error.standard_unexpected_error_alert('cmd_set_sunit failed!',E);
                             }
@@ -348,7 +347,7 @@ serial.manage_items.prototype = {
                                     );
 
                                 var method; var success_label;
-                                if (obj.mode == 'receive') {
+                                if (obj.mode == 'receive' || obj.mode == 'advanced_receive') {
                                     method = 'open-ils.serial.receive_items';
                                     success_label = 'received';
                                 } else { // bind mode
@@ -359,7 +358,7 @@ serial.manage_items.prototype = {
                                 // deal with barcodes and call numbers for *NEW* units
                                 var barcodes = {};
                                 var call_numbers = {};
-                                var call_numbers_by_issuance_id = {};
+                                var call_numbers_by_siss_and_sdist = {};
 
                                 if (obj.current_sunit_id < 0) { // **AUTO** or **NEW** units
                                     var new_unit_barcode = '';
@@ -388,16 +387,24 @@ serial.manage_items.prototype = {
                                             alert('Invalid barcode entered, defaulting to system-generated.');
                                             barcode = '@@AUTO';
                                         } else {
+                                            // disable alarm sound temporarily
+                                            var sound_setting = obj.data.no_sound;
+                                            if (!sound_setting) { // undefined or false
+                                                obj.data.no_sound = true; obj.data.stash('no_sound');
+                                            }
                                             var test = obj.network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ barcode ]);
                                             if (typeof test.ilsevent == 'undefined') {
                                                 alert('Another copy has barcode "' + barcode + '", defaulting to system-generated.');
                                                 barcode = '@@AUTO';
                                             }
+                                            if (!sound_setting) {
+                                                obj.data.no_sound = sound_setting; obj.data.stash('no_sound');
+                                            }
                                         }
                                         barcodes[item.id()] = barcode;
 
                                         // now call numbers
-                                        if (typeof call_numbers_by_issuance_id[item.issuance().id()] == 'undefined') {
+                                        if (typeof call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution().id()] == 'undefined') {
                                             var default_cn = 'DEFAULT';
                                             // if they defined a *_call_number, honor it as the default
                                             var preset_cn_id = item.stream().distribution()[obj.mode + '_call_number']();
@@ -412,11 +419,10 @@ serial.manage_items.prototype = {
                                                 }
                                             } else {
                                                 // for now, let's default to the last created call number if there is one
-                                                // TODO: make this distribution specific
                                                 var acn_list = obj.network.request(
                                                         'open-ils.pcrud',
                                                         'open-ils.pcrud.search.acn',
-                                                        [ ses(), {"record" : obj.docid, "owning_lib" : obj.holding_lib, "deleted" : 'f' }, {"order_by" : {"acn" : "create_date DESC"}, "limit" : "1" } ]
+                                                        [ ses(), {"record" : obj.docid, "owning_lib" : item.stream().distribution().holding_lib(), "deleted" : 'f' }, {"order_by" : {"acn" : "create_date DESC"}, "limit" : "1" } ]
                                                 );
 
                                                 if (acn_list) {
@@ -433,10 +439,10 @@ serial.manage_items.prototype = {
                                                 call_number = 'DEFAULT'; //TODO: real default by setting
                                             }
                                             call_numbers[item.id()] = call_number;
-                                            call_numbers_by_issuance_id[item.issuance().id()] = call_number;
+                                            call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution().id()] = call_number;
                                         } else {
-                                            // we have already seen this same issuance, so use the same call number
-                                            call_numbers[item.id()] = call_numbers_by_issuance_id[item.issuance().id()];
+                                            // we have already seen this same issuance and distribution combo, so use the same call number
+                                            call_numbers[item.id()] = call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution().id()];
                                         }
 
                                         if (obj.current_sunit_id == -2) {
@@ -531,6 +537,7 @@ serial.manage_items.prototype = {
 
        'rebuild_current_sunit' : function(sdist_label, sdist_id, sstr_id) {
                var obj = this;
+        if (!obj.current_sunit_id) return; // current sunit is NONE
                try {
             var robj = obj.network.request(
                 'open-ils.pcrud',
@@ -553,7 +560,7 @@ serial.manage_items.prototype = {
             obj.current_sunit_id = sunit_id;
             obj.current_sunit_sdist_id = sdist_id;
             obj.current_sunit_sstr_id = sstr_id;
-            if (sunit_id < 0) {
+            if (sunit_id < 0  || sunit_id === '') {
                 $('serial_workarea_sunit_desc').firstChild.nodeValue = '**' + label + '**';
             } else {
                 $('serial_workarea_sunit_desc').firstChild.nodeValue = label;
@@ -653,7 +660,9 @@ serial.manage_items.prototype = {
             obj.mode = mode;
         }
 
-        if (mode == 'receive') {
+        obj.set_sdist_ids();
+
+        if (mode == 'receive' || mode == 'advanced_receive') {
             $('serial_workarea_mode_label').value = 'Recently Received';
             if ($('serial_manage_items_show_all').checked) {
                 obj.lists.main.sitem_retrieve_params = {};
@@ -664,8 +673,20 @@ serial.manage_items.prototype = {
 
             obj.lists.workarea.sitem_retrieve_params = {'date_received' : {"!=" : null}};
             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}, 'limit' : 30};
+            if (mode == 'receive') {
+                $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.subscriber.label') + ':';
+                $('cmd_set_other_sunit').setAttribute('disabled','true');
+                $('serial_items_recent_sunits').disabled = true;
+                obj.process_unit_selection($('serial_items_auto_per_item_menuitem'));
+                //obj.set_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
+            } else {
+                $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.holder.label') + ':';
+                $('cmd_set_other_sunit').setAttribute('disabled','false');
+                $('serial_items_recent_sunits').disabled = false;
+            }    
         } else { // bind mode
             $('serial_workarea_mode_label').value = 'Bound Items in Current Working Unit';
+            $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.holder.label') + ':';
             if ($('serial_manage_items_show_all').checked) {
                 obj.lists.main.sitem_retrieve_params = {};
             } else {
@@ -676,6 +697,8 @@ serial.manage_items.prototype = {
             obj.lists.workarea.sitem_retrieve_params = {}; // unit set dynamically in 'retrieve'
             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}};
 
+            $('cmd_set_other_sunit').setAttribute('disabled','false');
+            $('serial_items_recent_sunits').disabled = false;
             // default to **NEW UNIT**
             // For now, keep the unit static.  TODO: Eventually, keep track of and store the last used unit value for both receive and bind separately
             // obj.set_sunit(-2, 'New Unit', '', '');
@@ -686,7 +709,7 @@ serial.manage_items.prototype = {
                var obj = this;
 
         JSAN.use('util.file'); var file = new util.file('serial_items_prefs.'+obj.data.server_unadorned);
-        util.widgets.save_attributes(file, { 'serial_item_lib_menu' : [ 'value' ], 'mode_receive' : [ 'selected' ], 'mode_bind' : [ 'selected' ], 'serial_manage_items_show_all' : [ 'checked' ] });
+        util.widgets.save_attributes(file, { 'serial_item_lib_menu' : [ 'value' ], 'mode_receive' : [ 'selected' ], 'mode_advanced_receive' : [ 'selected' ], 'mode_bind' : [ 'selected' ], 'serial_manage_items_show_all' : [ 'checked' ] });
     },
 
        'init_lists' : function() {
@@ -846,7 +869,22 @@ serial.manage_items.prototype = {
                obj.controller.view.sel_mark_items_missing.setAttribute('disabled','false');*/
 
                obj.retrieve_ids = list;
-       }
+       },
+
+    'process_unit_selection' : function(menuitem) {
+        var obj = this;
+
+        var label = menuitem.label;
+        var sunit_id = menuitem.getAttribute('sunit_id');
+        var sdist_id = menuitem.getAttribute('sdist_id');
+        var sstr_id = menuitem.getAttribute('sstr_id');
+        obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
+        obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
+        if (obj.mode == 'bind') {
+            obj.refresh_list('main');
+            obj.refresh_list('workarea');
+        }
+    }
 }
 
 function item_columns(modify,params) {
@@ -881,6 +919,14 @@ function item_columns(modify,params) {
             'hidden' : false,
             'persist' : 'hidden width ordinal',
             'render' : function(my) { return my.sitem.stream().distribution().label(); }
+        },        {
+            'id' : 'distribution_ou',
+            'label' : $('serialStrings').getString('staff.serial.manage_items.holder.label'),
+            'flex' : 1,
+            'primary' : false,
+            'hidden' : false,
+            'persist' : 'hidden width ordinal',
+            'render' : function(my) { return data.hash.aou[ my.sitem.stream().distribution().holding_lib() ].shortname(); }
         },
         {
             'id' : 'stream_id',
index 97ae1f1..c5bedca 100644 (file)
@@ -47,8 +47,9 @@ vim:noet:sw=4:ts=4:
     </popupset>
     <tabpanel id="serial_manage_items" orient="vertical" flex="1">
         <hbox align="center">
+            <label id="serial_manage_items_context" style="font-weight: bold" value="&staff.serial.manage_items.context.label;"/>
             <hbox id="serial_item_lib_menu_box"/>
-            <label value="&staff.serial.manage_items.mode;" control="mode_receive"/><radiogroup id="serial_manage_items_mode" orient="horizontal"><radio id="mode_receive" label="&staff.serial.manage_items.receive.label;"/><radio id="mode_bind" label="&staff.serial.manage_items.bind.label;"/></radiogroup><checkbox id="serial_manage_items_show_all" label="&staff.serial.manage_items.show_all.label;" />
+            <label value="&staff.serial.manage_items.mode;" control="mode_receive"/><radiogroup id="serial_manage_items_mode" orient="horizontal"><radio id="mode_receive" label="&staff.serial.manage_items.receive.label;"/><radio id="mode_advanced_receive" label="&staff.serial.manage_items.advanced_receive.label;"/><radio id="mode_bind" label="&staff.serial.manage_items.bind.label;"/></radiogroup><checkbox id="serial_manage_items_show_all" label="&staff.serial.manage_items.show_all.label;" />
             <button id="refresh_button" label="&staff.cat.copy_browser.holdings_maintenance.refresh_button.label;" command="cmd_refresh_list" />
             <spacer flex="1"/>
             <menubar>
@@ -100,7 +101,8 @@ vim:noet:sw=4:ts=4:
                 <menu label="&staff.serial.manage_items.set_current_unit.label;" id="serial_items_current_sunit" sunit_id="-1" sunit_label="&staff.serial.manage_items.auto_per_item.label;" sdist_id="" sstr_id="">
                     <menupopup>
                         <menuitem command="cmd_set_sunit" label="&staff.serial.manage_items.new_unit.label;" sunit_id="-2" sdist_id="" sstr_id=""/>
-                        <menuitem command="cmd_set_sunit" label="&staff.serial.manage_items.auto_per_item.label;" sunit_id="-1" sdist_id="" sstr_id=""/>
+                        <menuitem id="serial_items_auto_per_item_menuitem" command="cmd_set_sunit" label="&staff.serial.manage_items.auto_per_item.label;" sunit_id="-1" sdist_id="" sstr_id=""/>
+                        <menuitem command="cmd_set_sunit" label="&staff.serial.manage_items.no_unit.label;" sunit_id="" sdist_id="" sstr_id=""/>
                         <menu label="&staff.serial.manage_items.recent.label;" id="serial_items_recent_sunits" sunit_json='[]'/>
                         <menuitem command="cmd_set_other_sunit" label="&staff.serial.manage_items.other_unit.label;"/>
                     </menupopup>
index 142899e..0045f46 100644 (file)
@@ -159,6 +159,15 @@ serial.sdist_editor.prototype = {
                 }
             ],
             [
+                'summary_method',
+                {
+                    render: 'obj.summary_methods[fm.summary_method()]',
+                    input: 'c = function(v){ obj.apply("summary_method",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_object_to_list( obj.summary_methods, function(obj,i) { return [ obj[i], i ]; })); x.setAttribute("value",obj.editor_values.summary_method); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
+                    value_key: 'summary_method',
+                    dropdown_key: 'fm.summary_method() == null ? null : fm.summary_method()'
+                }
+            ],
+            [
                 'unit_label_prefix',
                 {
                     input: 'c = function(v){ obj.apply("unit_label_prefix",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.setAttribute("value",obj.editor_values.unit_label_prefix); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
@@ -390,8 +399,14 @@ serial.sdist_editor.prototype = {
             obj.error.standard_unexpected_error_alert('get_act_list',E);
             return [];
         }
+    },
+    /******************************************************************************************************/
+    'summary_methods' : {
+        "add_to_sre" : $('serialStrings').getString('staff.serial.sdist_editor.add_to_sre.label'),
+        "merge_with_sre" : $('serialStrings').getString('staff.serial.sdist_editor.merge_with_sre.label'),
+        "use_sre_only" : $('serialStrings').getString('staff.serial.sdist_editor.use_sre_only.label'),
+        "use_sdist_only" : $('serialStrings').getString('staff.serial.sdist_editor.use_sdist_only.label'),
     }
-
 };
 
 dump('exiting serial/sdist_editor.js\n');