From 05b8e63a96819dd69c5175b1d643e3204b548351 Mon Sep 17 00:00:00 2001 From: djfiander Date: Fri, 2 Jan 2009 20:51:33 +0000 Subject: [PATCH] Beginnings of calculating date of next issue. git-svn-id: svn://svn.open-ils.org/ILS/trunk@11732 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../src/perlmods/OpenILS/Utils/MFHD/Holding.pm | 154 ++++++++++++++++++--- 1 file changed, 133 insertions(+), 21 deletions(-) diff --git a/Open-ILS/src/perlmods/OpenILS/Utils/MFHD/Holding.pm b/Open-ILS/src/perlmods/OpenILS/Utils/MFHD/Holding.pm index f0bc0a98f1..19cc4df388 100755 --- a/Open-ILS/src/perlmods/OpenILS/Utils/MFHD/Holding.pm +++ b/Open-ILS/src/perlmods/OpenILS/Utils/MFHD/Holding.pm @@ -3,6 +3,8 @@ use strict; use integer; use Carp; +use DateTime; + use Data::Dumper; use MARC::Record; @@ -19,8 +21,7 @@ sub new { $self->{SEQNO} = $seqno; $self->{HOLDING} = $holding; $self->{CAPTION} = $caption; - $self->{ENUMS} = {}; - $self->{CHRON} = {}; + $self->{SUBFIELDS} = {}; $self->{DESCR} = {}; $self->{COPY} = undef; $self->{BREAK} = undef; @@ -31,18 +32,18 @@ sub new { my ($key, $val) = @$subfield; if ($key =~ /[a-h]/) { # Enumeration details of holdings - $self->{ENUMS}->{$key} = {HOLDINGS => $val, + $self->{SUBFIELDS}->{$key} = {HOLDINGS => $val, UNIT => undef,}; $last_enum = $key; } elsif ($key =~ /[i-m]/) { - $self->{CHRON}->{$key} = $val; + $self->{SUBFIELDS}->{$key} = $val; if (!exists $caption->{CHRONS}->{$key}) { warn "Holding '$seqno' specified enumeration level '$key' not included in caption $caption->{LINK}"; } } elsif ($key eq 'o') { warn '$o specified prior to first enumeration' unless defined($last_enum); - $self->{ENUMS}->{$last_enum}->{UNIT} = $val; + $self->{SUBFIELDS}->{$last_enum}->{UNIT} = $val; $last_enum = undef; } elsif ($key =~ /[npq]/) { $self->{DESCR}->{$key} = $val; @@ -72,6 +73,12 @@ sub format_chron { '10' => 'Oct.', '11' => 'Nov.', '12' => 'Dec.', '21' => 'Spring', '22' => 'Summer', '23' => 'Autumn', '24' => 'Winter' ); + my %month = ( '01' => 'Jan.', '02' => 'Feb.', '03' => 'Mar.', + '04' => 'Apr.', '05' => 'May ', '06' => 'Jun.', + '07' => 'Jul.', '08' => 'Aug.', '09' => 'Sep.', + '10' => 'Oct.', '11' => 'Nov.', '12' => 'Dec.', + '21' => 'Spring', '22' => 'Summer', + '23' => 'Autumn', '24' => 'Winter' ); @keys = @_; foreach my $i (0 .. @keys) { @@ -91,10 +98,10 @@ sub format_chron { # If this is the second level of chronology, then it's # likely to be a month or season, so we should use the # string name rather than the number given. - if (($i == 1) && exists $month{$self->{CHRON}->{$key}}) { - $chron = $month{$self->{CHRON}->{$key}}; + if (($i == 1) && exists $month{$self->{SUBFIELDS}->{$key}}) { + $chron = $month{$self->{SUBFIELDS}->{$key}}; } else { - $chron = $self->{CHRON}->{$key}; + $chron = $self->{SUBFIELDS}->{$key}; } @@ -121,6 +128,8 @@ sub format { # Enumerations foreach my $key ('a'..'f') { my $capstr; + my $chron; + my $sep; last if !defined $caption->caption($key); @@ -131,7 +140,7 @@ sub format { # a caption enclosed in parentheses is not displayed $capstr = ''; } - $str .= ($key eq 'a' ? "" : ':') . $capstr . $self->{ENUMS}->{$key}->{HOLDINGS}; + $str .= ($key eq 'a' ? "" : ':') . $capstr . $self->{SUBFIELDS}->{$key}->{HOLDINGS}; } # Chronology @@ -145,7 +154,7 @@ sub format { # There's at least one level of alternative enumeration $str .= '='; foreach my $key ('g', 'h') { - $str .= ($key eq 'g' ? '' : ':') . $caption->caption($key) . $self->{ENUMS}->{$key}->{HOLDINGS}; + $str .= ($key eq 'g' ? '' : ':') . $caption->caption($key) . $self->{SUBFIELDS}->{$key}->{HOLDINGS}; } # This assumes that alternative chronology is only ever @@ -153,7 +162,7 @@ sub format { if (exists $caption->{CHRONS}->{m}) { # Alternative Chronology $str .= '('; - $str .= $caption->caption('m') . $self->{ENUMS}->{m}->{HOLDINGS}; + $str .= $caption->caption('m') . $self->{SUBFIELDS}->{m}->{HOLDINGS}; $str .= ')'; } } @@ -174,12 +183,102 @@ sub format { return $str; } +my %increments = { + a => {years => 1}, # annual + b => {months => 2}, # bimonthly + c => {days => 3}, # semiweekly + d => {days => 1}, # daily + e => {weeks => 2}, # biweekly + f => {months => 6}, # semiannual + g => {years => 2}, # biennial + h => {years => 3}, # triennial + i => {days => 2}, # three times / week + j => {days => 10}, # three times /month + # k => continuous + m => {months => 1}, # monthly + q => {months => 3}, # quarterly + s => {days => 15}, # semimonthly + t => {months => 4}, # three times / year + w => {weeks => 1}, # weekly + # x => completely irregular +}; + sub next_date { my $self = shift; my $next = shift; my @keys = @_; + my @cur; + my @new; + my $incr; my $caption = $self->{CAPTION}; + my $pattern = $caption->{PATTERN}; + my $frequency = $pattern->{w}; + + warn "I can't deal with publication patterns yet!" if exists $pattern->{y}; + +# print Dumper(@keys); +# print Dumper($self); + + foreach my $i (0..@keys) { + $new[$i] = $cur[$i] = $self->{SUBFIELDS}->{$keys[$i]} + if exists $self->{SUBFIELDS}->{$keys[$i]}; + } + + if (defined $frequency) { + $incr = $increments{$frequency}; + } + + if (scalar(@cur) == 1) { + # only a year is specified. Next date is easy + $new[0] += $incr->{years} || 1; + } elsif (scalar(@cur) == 2) { + # Year and month or season + if ($new[1] > 20) { + # season + $new[1] += ($incr->{months}/3) || 1; + if ($new[1] > 24) { + # carry + $new[0] += 1; + $new[1] -= 24; + } + } else { + # month + $new[1] += $incr->{months} || 1; + if ($new[1] > 12) { + # carry + $new[0] += 1; + $new[1] -= 12; + } + } + } elsif (scalar(@cur) == 3) { + # Year, Month, Day: now it gets complicated. + + if ($new[2] =~ /^[0-9]+$/) { + # A single number for the day of month, relatively simple + my $dt = DateTime->new(year => $new[0], + month=> $new[1], + day => $new[2]); + $dt->add(%{$incr}); + $new[0] = $dt->year; + $new[1] = $dt->month; + $new[2] = $dt->day; + } elsif ($new[2] =~ /^([0-9]+)\/([0-9]+)/) { + my $sdt = DateTime->new(year => $new[0], + month=> $new[1], + day => $1); + my $edt = DateTime->new(year => $new[0], + month=> $new[1], + day => $2); + $sdt->add(%{$incr}); + $edt->add(%{$incr}); + $new[0] = $sdt->year; + $new[1] = $sdt->month; + $new[2] = $sdt->day . '/' . $edt->day; + } else { + warn "I don't know how to deal with '$new[2]'"; + } + } } @@ -195,17 +294,17 @@ sub next { # Initialize $next with current enumeration & chronology, then # we can just operate on $next, based on the contents of the caption foreach my $key ('a' .. 'h') { - $next->{$key} = $self->{ENUMS}->{$key}->{HOLDINGS} - if exists $self->{ENUMS}->{$key}; + $next->{$key} = $self->{SUBFIELDS}->{$key}->{HOLDINGS} + if exists $self->{SUBFIELDS}->{$key}; } foreach my $key ('i'..'m') { - $next->{$key} = $self->{CHRON}->{$key} - if exists $self->{CHRON}->{$key}; + $next->{$key} = $self->{SUBFIELDS}->{$key} + if exists $self->{SUBFIELDS}->{$key}; } if ($caption->enumeration_is_chronology) { - $self->next_date($caption, $next, ('a'..'h')); + $self->next_date($next, ('a'..'h')); } else { # First handle any "alternative enumeration", since they're # a lot simpler, and don't depend on the the calendar @@ -278,10 +377,23 @@ sub next { } else { # Figure out date of next issue, then decide if we need # to adjust top level enumeration based on that - $self->next_date($caption, $next, ('i'..'m')); + $self->next_date($next, ('i'..'m')); } } + # The easy part is done. There are two things left to do: + # 1) Calculate the date of the next issue, if necessary + # 2) Increment the highest level of enumeration (either by date + # or because $carry is set because of the above loop + + if (!%{$caption->{CHRONS}}) { + # The simple case: if there is no chronology specified + # then just check $carry and return + $next->{'a'} += $carry; + } else { + # Complicated: figure out date of next issue + } + return($next); } @@ -303,14 +415,14 @@ sub match { # If the next smaller enumeration exists, and is numbered # continuously, then we don't need to check this one, because # gaps in issue numbering matter, not changes in volume numbering - next if (exists $self->{ENUMS}->{$nextkey} + next if (exists $self->{SUBFIELDS}->{$nextkey} && !$caption->{ENUMS}->{$nextkey}->{RESTART}); # If a subfield exists in $self but not in $pat, or vice versa # or if the field has different values, then fail - if (exists($self->{ENUMS}->{$key}) != exists($pat->{$key}) + if (exists($self->{SUBFIELDS}->{$key}) != exists($pat->{$key}) || (exists $pat->{$key} - && ($self->{ENUMS}->{$key}->{HOLDINGS} ne $pat->{$key}))) { + && ($self->{SUBFIELDS}->{$key}->{HOLDINGS} ne $pat->{$key}))) { return 0; } } @@ -324,7 +436,7 @@ sub match { sub validate { my $self = shift; - foreach my $key (keys %{$self->{ENUMS}}) { + foreach my $key (keys %{$self->{SUBFIELDS}}) { if (!exists $self->{CAPTION}->{ENUMS}->{$key}) { return 0; } -- 2.11.0