use base 'MARC::Record';
-# use OpenSRF::Utils::JSON;
use OpenILS::Utils::MFHD::Caption;
use OpenILS::Utils::MFHD::Holding;
values %{$self->{_mfhd_HOLDINGS}->{$field}->{$capid}};
}
+#
+# generate_predictions() is an initial attempt at a function which can be used
+# to populate an issuance table with a list of predicted issues. It accepts
+# a hash ref of options initially defined as:
+# field : the caption field to predict on (853, 854, or 855)
+# 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
+#
+# The basic method is to first convert to a single holding if compressed, then
+# increment the holding and save the resulting values to @predictions.
+#
+# returns @preditions, an array of array refs containing (link id, formatted
+# label, formatted chronology date, formatted estimated arrival date, and an
+# array ref of holding subfields as (key, value, key, value ...)) (not a hash
+# to protect order and possible duplicate keys).
+#
sub generate_predictions {
my ($self, $options) = @_;
my $field = $options->{field};
my @holdings = $self->holdings($htag, $link_id);
my $last_holding = $holdings[-1];
+ if ($last_holding->is_compressed) {
+ $last_holding->compressed_to_last; # convert to last in range
+ }
+
my $pub_date = $strp->parse_datetime($last_holding->chron_to_date);
my $date_diff = $receival_date - $pub_date;
$last_holding->notes('public', []);
+ # add a note marker for system use
$last_holding->notes('private', ['AUTOGEN']);
for (my $i = 0; $i < $num_to_predict; $i++) {
$last_holding->increment;
$pub_date = $strp->parse_datetime($last_holding->chron_to_date);
- $pub_date = $pub_date + $date_diff;
+ my $arrival_date = $pub_date + $date_diff;
push(
@predictions,
[
$link_id,
$last_holding->format,
$pub_date->strftime('%F'),
-# OpenSRF::Utils::JSON->perl2JSON(
-# [$last_holding->subfields_list]
-# )
+ $arrival_date->strftime('%F'),
+ [$last_holding->subfields_list]
]
);
}
$self->{_mfhdh_NOTES}{public} = [];
$self->{_mfhdh_NOTES}{private} = [];
$self->{_mfhdh_COPYRIGHT} = [];
- $self->{_mfhdh_COMPRESSED} = $self->indicator(2) eq '0' ? 1 : 0;
+ $self->{_mfhdh_COMPRESSED} = ($self->indicator(2) eq '0' || $self->indicator(2) eq '2') ? 1 : 0;
+ # TODO: full support for second indicators 2, 3, and 4
$self->{_mfhdh_OPEN_ENDED} = 0;
foreach my $subfield ($self->subfields) {
# than simply the MARC subfields, although in the current implementation they
# are indexed on the subfield key
#
+# TODO: this accessor should probably be replaced with methods which hide the
+# underlying structure of {_mfhdh_FIELDS} (see field_values for a start)
+#
sub fields {
my $self = shift;
# Given a field key, returns an array ref of one (for single statements)
# or two (for compressed statements) values
#
+# TODO: add setter functionality to replace direct {HOLDINGS} access in other
+# methods. It also makes sense to override some of the MARC::Field setter
+# methods (such as update()) to accomplish this level of encapsulation.
+#
sub field_values {
my ($self, $key) = @_;
return $self->{_mfhdh_SEQNO};
}
+#
+# Optionally accepts a true/false value to set the 'compressed' attribute
+# Returns 'compressed' attribute
+#
sub is_compressed {
my $self = shift;
+ my $is_compressed = shift;
+
+ if (defined($is_compressed)) {
+ if ($is_compressed) {
+ $self->{_mfhdh_COMPRESSED} = 1;
+ $self->update(ind2 => '0');
+ } else {
+ $self->{_mfhdh_COMPRESSED} = 0;
+ $self->update(ind2 => '1');
+ }
+ }
return $self->{_mfhdh_COMPRESSED};
}
return $self->{_mfhdh_CAPTION};
}
+#
+# notes: If called with no arguments, returns the public notes array ref.
+# If called with a single argument, it returns either 'public' or
+# 'private' notes based on the passed string.
+#
+# If called with more than one argument, it sets the proper note field, with
+# type being the first argument and the note value(s) as the remaining
+# argument(s).
+#
+# It is also optional to pass in an array ref of note values as the third
+# argument rather than a list.
+#
sub notes {
my $self = shift;
my $type = shift;
if (!$type) {
$type = 'public';
} elsif ($type ne 'public' && $type ne 'private') {
- carp("Notes being applied without specifiying type");
+ carp("Notes being applied without specifying type");
unshift(@notes, $type);
$type = 'public';
}
# account for possible combined issue chronology
my @chron_parts = split('/', $holdings->{$key});
for (my $i = 0; $i < @chron_parts; $i++) {
- $chron_parts[$i] = $month{$chron_parts[$i]};
+ $chron_parts[$i] = $month{$chron_parts[$i]} if exists $month{$chron_parts[$i]};
}
$chron = join('/', @chron_parts);
} else {
# Public Note
if (@{$self->notes}) {
- $formatted .= ' Note: ' . join(', ', @{$self->notes});
+ $formatted .= ' -- ' . join(', ', @{$self->notes});
}
return $formatted;
sub increment {
my $self = shift;
+ if ($self->is_open_ended) {
+ carp "Holding is open-ended, cannot increment";
+ return $self;
+ }
+
my $next = $self->next();
if ($self->is_compressed) { # expand range
}
#
+# Turns a compressed holding into the singular form of the last member
+# in the range
+#
+sub compressed_to_last {
+ my $self = shift;
+
+ if (!$self->is_compressed) {
+ carp "Holding not compressed, cannot convert to last member";
+ return $self;
+ } elsif ($self->is_open_ended) {
+ carp "Holding is open-ended, cannot convert to last member";
+ return $self;
+ }
+
+ my %changes;
+ foreach my $key (keys %{$self->fields}) {
+ my @values = @{$self->field_values($key)};
+ $self->fields->{$key}{HOLDINGS} = [$values[1]];
+ $changes{$key} = $values[1];
+ }
+
+ $self->update(%changes); # update underlying subfields
+ $self->is_compressed(0); # remove compressed state
+
+ return $self;
+}
+
+#
# Basic, working, unoptimized clone operation
#
sub clone {
@keys = ('i'..'m');
}
+ # @chron_start and @chron_end will hold the (year, month, day) values
+ # represented by the start and optional end of the chronology instance.
+ # Default to January 1 with a year of 0 as initial values.
my @chron_start = (0, 1, 1);
my @chron_end = (0, 1, 1);
my @chrons = (\@chron_start, \@chron_end);
} elsif ($capstr =~ /day/) {
($chron_start[2], $chron_end[2]) = @{$self->field_values($key)};
} elsif ($capstr =~ /season/) {
+ # chrons defined as season-only will use the astronomical season
+ # dates as a basic estimate.
my @seasons = @{$self->field_values($key)};
for (my $i = 0; $i < @seasons; $i++) {
$seasons[$i] = &_uncombine($seasons[$i], 0);
my ($combo, $pos) = @_;
if (ref($combo)) {
- carp("Function 'uncombine' is not an instance method");
+ carp("Function '_uncombine' is not an instance method");
return;
}