Better Prediction for Incomplete Chronologies
authorDan Wells <dbw2@calvin.edu>
Fri, 13 Apr 2012 13:53:32 +0000 (09:53 -0400)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 17 Apr 2012 15:11:22 +0000 (11:11 -0400)
While relatively rare, some journals record only the year on the
cover, even if they come out monthly or weekly.  This commit
expands our previous support for serials with no chronology at
all to cover serials with partial chronology.

Signed-off-by: Dan Wells <dbw2@calvin.edu>
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm

index 4c19954..8333f3b 100644 (file)
@@ -886,10 +886,13 @@ sub make_predictions {
     foreach my $scap (@$scaps) {
         my $caption_field = _revive_caption($scap);
         $caption_field->update('8' => $link_id);
-        my $using_fake_chron = 0;
-        # if we have no chronology, add one for prediction puposes
-        if (!$caption_field->subfield('i') and !$caption_field->enumeration_is_chronology) {
-            $using_fake_chron = 1;
+        my $fake_chron_needed = 0;
+        # if we have missing chron pieces, we will add them later for prediction purposes
+        if (!$caption_field->enumeration_is_chronology) {
+            if (!$caption_field->subfield('i') # no year
+                or !$caption_field->subfield('j')) { # we had a year, but no month or season
+                $fake_chron_needed = '1';
+            }
         }
         $mfhd->append_fields($caption_field);
         my $options = {
@@ -899,9 +902,9 @@ sub make_predictions {
                 'end_date' => defined $args->{end_date} ?
                     $_strp_date->parse_datetime($args->{end_date}) : undef
                 };
+        my $predict_from_siss;
         if ($args->{base_issuance}) { # predict from a given issuance
-            $options->{predict_from} = _revive_holding($args->{base_issuance}->holding_code, $caption_field, 1); # fresh MFHD Record, so we simply default to 1 for seqno
-            $options->{faked_chron_date} = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($args->{base_issuance}->date_published)) if $using_fake_chron;
+            $predict_from_siss = $args->{base_issuance}->holding_code;
         } else { # default to predicting from last published
             my $last_published = $editor->search_serial_issuance([
                     {'caption_and_pattern' => $scap->id,
@@ -909,8 +912,8 @@ sub make_predictions {
                 {limit => 1, order_by => { siss => "date_published DESC" }}]
                 );
             if ($last_published->[0]) {
-                my $last_siss = $last_published->[0];
-                unless ($last_siss->holding_code) {
+                $predict_from_siss = $last_published->[0];
+                unless ($predict_from_siss->holding_code) {
                     $editor->disconnect;
                     # XXX TODO new event type
                     return new OpenILS::Event(
@@ -918,8 +921,6 @@ sub make_predictions {
                             "Last issuance has no holding code. Can't predict."
                     );
                 }
-                $options->{predict_from} = _revive_holding($last_siss->holding_code, $caption_field, 1);
-                $options->{faked_chron_date} = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($last_siss->date_published)) if $using_fake_chron;
             } else {
                 $editor->disconnect;
                 # XXX TODO make a new event type instead of hijacking this one
@@ -928,6 +929,10 @@ sub make_predictions {
                 );
             }
         }
+        $options->{predict_from} = _revive_holding($predict_from_siss->holding_code, $caption_field, 1); # fresh MFHD Record, so we simply default to 1 for seqno
+        if ($fake_chron_needed) {
+            $options->{faked_chron_date} = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($predict_from_siss->date_published));
+        }
         push( @predictions, _generate_issuance_values($mfhd, $options) );
         $link_id++;
     }
@@ -991,8 +996,8 @@ sub _generate_issuance_values {
     my $scap_id = $options->{scap_id};
     my $num_to_predict = $options->{num_to_predict};
     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 $predict_from = $options->{predict_from};   # MFHD::Holding to predict from
+    my $faked_chron_date = $options->{faked_chron_date};   # serial does not have a (complete) chronology caption, so add one (temporarily) based on this date 
 
 
 # Only needed for 'real' MFHD records, not our temp records
@@ -1015,14 +1020,24 @@ sub _generate_issuance_values {
     $predict_from->notes('private', ['AUTOGEN']);
 
     # our basic method for dealing with 'faked' chronologies will be to add it in, do the predicting, then take it back out
-    my $orig_caption;
-    my $faked_caption;
+    my @faked_subfield_chars;
     if ($faked_chron_date) {
-        $orig_caption = $predict_from->caption;
+        my $faked_caption = new MARC::Field($caption->tag, $caption->indicator(1), $caption->indicator(2), $caption->subfields_list);
+
+        my %mfhd_chron_labels = ('i' => 'year', 'j' => 'month', 'k' => 'day');
+        foreach my $subfield_char ('i', 'j', 'k') {
+            if (!$caption->subfield($subfield_char)) { # if we are missing a piece, add it
+                push(@faked_subfield_chars, $subfield_char);
+                my $chron_name = $mfhd_chron_labels{$subfield_char};
+                $faked_caption->add_subfields($subfield_char => "($chron_name)");
+                my $method = $mfhd_chron_labels{$subfield_char};
+                $predict_from->add_subfields($subfield_char => $faked_chron_date->$chron_name);
+            }
+        }
         # because of the way MFHD::Caption and Holding work, it is simplest
         # to recreate rather than try to update
-        $faked_caption = new MFHD::Caption(new MARC::Field($orig_caption->tag, $orig_caption->indicator(1), $orig_caption->indicator(2), $orig_caption->subfields_list, 'i' => '(year)', 'j' => '(month)', 'k' => '(day)'));
-        $predict_from = new MFHD::Holding($predict_from->seqno, new MARC::Field($predict_from->tag, $predict_from->indicator(1), $predict_from->indicator(2), $predict_from->subfields_list, 'i' => $faked_chron_date->year, 'j' => $faked_chron_date->month, 'k' => $faked_chron_date->day), $faked_caption);
+        $faked_caption = new MFHD::Caption($faked_caption);
+        $predict_from = new MFHD::Holding($predict_from->seqno, new MARC::Field($predict_from->tag, $predict_from->indicator(1), $predict_from->indicator(2), $predict_from->subfields_list), $faked_caption);
     }
 
     my @predictions = $mfhd->generate_predictions({'base_holding' => $predict_from, 'num_to_predict' => $num_to_predict, 'end_date' => $end_date});
@@ -1032,8 +1047,8 @@ sub _generate_issuance_values {
     foreach my $prediction (@predictions) {
         $pub_date = $_strp_date->parse_datetime($prediction->chron_to_date);
         if ($faked_chron_date) { # get rid of the chronology portions and restore original caption
-            $prediction->delete_subfield(code => ['i', 'j', 'k']);
-            $prediction = new MFHD::Holding($prediction->seqno, new MARC::Field($prediction->tag, $prediction->indicator(1), $prediction->indicator(2), $prediction->subfields_list), $orig_caption);
+            $prediction->delete_subfield(code => \@faked_subfield_chars);
+            $prediction = new MFHD::Holding($prediction->seqno, new MARC::Field($prediction->tag, $prediction->indicator(1), $prediction->indicator(2), $prediction->subfields_list), $caption);
         }
         push(
                 @issuance_values,