Bug 18276: (follow-up) Remove GetBiblioFromItemNumber - ILSDI
[koha.git] / C4 / Serials.pm
index 1f2cbc0..4b9ac61 100644 (file)
@@ -32,9 +32,11 @@ use C4::Serials::Frequency;
 use C4::Serials::Numberpattern;
 use Koha::AdditionalField;
 use Koha::DateUtils;
-use Koha::Database;
+use Koha::Serial;
+use Koha::Subscriptions;
+use Koha::Subscription::Histories;
 
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
 # Define statuses
 use constant {
@@ -59,7 +61,6 @@ use constant MISSING_STATUSES => (
 );
 
 BEGIN {
-    $VERSION = 3.07.00.049;    # set version for version checking
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
@@ -75,9 +76,9 @@ BEGIN {
       &ReNewSubscription  &GetLateOrMissingIssues
       &GetSerialInformation                   &AddItem2Serial
       &PrepareSerialsData &GetNextExpected    &ModNextExpected
+      &GetPreviousSerialid
 
-      &UpdateClaimdateIssues
-      &GetSuppliersWithLateIssues             &getsupplierbyserialid
+      &GetSuppliersWithLateIssues
       &GetDistributedTo   &SetDistributedTo
       &getroutinglist     &delroutingmember   &addroutingmember
       &reorder_members
@@ -184,7 +185,6 @@ sub GetSerialStatusFromSerialId {
 
 =head2 GetSerialInformation
 
-
 $data = GetSerialInformation($serialid);
 returns a hash_ref containing :
   items : items marcrecord (can be an array)
@@ -260,34 +260,6 @@ sub AddItem2Serial {
     return $rq->rows;
 }
 
-=head2 UpdateClaimdateIssues
-
-UpdateClaimdateIssues($serialids,[$date]);
-
-Update Claimdate for issues in @$serialids list with date $date
-(Take Today if none)
-
-=cut
-
-sub UpdateClaimdateIssues {
-    my ( $serialids, $date ) = @_;
-
-    return unless ($serialids);
-
-    my $dbh = C4::Context->dbh;
-    $date = strftime( "%Y-%m-%d", localtime ) unless ($date);
-    my $query = "
-        UPDATE serial
-        SET claimdate = ?,
-            status = ?,
-            claims_count = claims_count + 1
-        WHERE  serialid in (" . join( ",", map { '?' } @$serialids ) . ")
-    ";
-    my $rq = $dbh->prepare($query);
-    $rq->execute($date, CLAIMED, @$serialids);
-    return $rq->rows;
-}
-
 =head2 GetSubscription
 
 $subs = GetSubscription($subscriptionid)
@@ -371,8 +343,9 @@ sub GetFullSubscription {
     my $sth = $dbh->prepare($query);
     $sth->execute($subscriptionid);
     my $subscriptions = $sth->fetchall_arrayref( {} );
+    my $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions;
     for my $subscription ( @$subscriptions ) {
-        $subscription->{cannotedit} = not can_edit_subscription( $subscription );
+        $subscription->{cannotedit} = $cannotedit;
     }
     return $subscriptions;
 }
@@ -470,7 +443,11 @@ sub GetSubscriptionsFromBiblionumber {
     while ( my $subs = $sth->fetchrow_hashref ) {
         $subs->{startdate}     = output_pref( { dt => dt_from_string( $subs->{startdate} ),     dateonly => 1 } );
         $subs->{histstartdate} = output_pref( { dt => dt_from_string( $subs->{histstartdate} ), dateonly => 1 } );
-        $subs->{histenddate}   = output_pref( { dt => dt_from_string( $subs->{histenddate} ),   dateonly => 1 } );
+        if ( defined $subs->{histenddate} ) {
+           $subs->{histenddate}   = output_pref( { dt => dt_from_string( $subs->{histenddate} ),   dateonly => 1 } );
+        } else {
+            $subs->{histenddate} = "";
+        }
         $subs->{opacnote}     =~ s/\n/\<br\/\>/g;
         $subs->{missinglist}  =~ s/\n/\<br\/\>/g;
         $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
@@ -478,7 +455,7 @@ sub GetSubscriptionsFromBiblionumber {
         $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
         $subs->{ "status" . $subs->{'status'} }             = 1;
 
-        if ( $subs->{enddate} eq '0000-00-00' ) {
+        if (not defined $subs->{enddate} ) {
             $subs->{enddate} = '';
         } else {
             $subs->{enddate} = output_pref( { dt => dt_from_string( $subs->{enddate}), dateonly => 1 } );
@@ -526,8 +503,9 @@ sub GetFullSubscriptionsFromBiblionumber {
     my $sth = $dbh->prepare($query);
     $sth->execute($biblionumber);
     my $subscriptions = $sth->fetchall_arrayref( {} );
+    my $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions;
     for my $subscription ( @$subscriptions ) {
-        $subscription->{cannotedit} = not can_edit_subscription( $subscription );
+        $subscription->{cannotedit} = $cannotedit;
     }
     return $subscriptions;
 }
@@ -581,6 +559,7 @@ sub SearchSubscriptions {
             biblio.title,
             biblio.author,
             biblio.biblionumber,
+            aqbooksellers.name AS vendorname,
             biblioitems.issn
         FROM subscription
             LEFT JOIN subscriptionhistory USING(subscriptionid)
@@ -766,19 +745,20 @@ sub GetSerials2 {
 
     return unless ($subscription and @$statuses);
 
-    my $statuses_string = join ',', @$statuses;
-
     my $dbh   = C4::Context->dbh;
-    my $query = qq|
+    my $query = q|
                  SELECT serialid,serialseq, status, planneddate, publisheddate,
                     publisheddatetext, notes, routingnotes
                  FROM     serial 
-                 WHERE    subscriptionid=$subscription AND status IN ($statuses_string)
+                 WHERE    subscriptionid=?
+            |
+            . q| AND status IN (| . join( ",", ('?') x @$statuses ) . q|)|
+            . q|
                  ORDER BY publisheddate,serialid DESC
-                    |;
+    |;
     $debug and warn "GetSerials2 query: $query";
     my $sth = $dbh->prepare($query);
-    $sth->execute;
+    $sth->execute( $subscription, @$statuses );
     my @serials;
 
     while ( my $line = $sth->fetchrow_hashref ) {
@@ -833,6 +813,39 @@ sub GetLatestSerials {
     return \@serials;
 }
 
+=head2 GetPreviousSerialid
+
+$serialid = GetPreviousSerialid($subscriptionid, $nth)
+get the $nth's previous serial for the given subscriptionid
+return :
+the serialid
+
+=cut
+
+sub GetPreviousSerialid {
+    my ( $subscriptionid, $nth ) = @_;
+    $nth ||= 1;
+    my $dbh = C4::Context->dbh;
+    my $return = undef;
+
+    # Status 2: Arrived
+    my $strsth = "SELECT   serialid
+                        FROM     serial
+                        WHERE    subscriptionid = ?
+                        AND      status = 2
+                        ORDER BY serialid DESC LIMIT $nth,1
+                ";
+    my $sth = $dbh->prepare($strsth);
+    $sth->execute($subscriptionid);
+    my @serials;
+    my $line = $sth->fetchrow_hashref;
+    $return = $line->{'serialid'} if ($line);
+
+    return $return;
+}
+
+
+
 =head2 GetDistributedTo
 
 $distributedto=GetDistributedTo($subscriptionid)
@@ -1173,8 +1186,9 @@ sub ModSerialStatus {
         }
     }
 
-    # create new waited entry if needed (ie : was a "waited" and has changed)
-    if ( $oldstatus == EXPECTED && $status != EXPECTED ) {
+    # create new expected entry if needed (ie : was "expected" and has changed)
+    my $otherIssueExpected = scalar findSerialsByStatus(EXPECTED, $subscriptionid);
+    if ( !$otherIssueExpected && $oldstatus == EXPECTED && $status != EXPECTED ) {
         my $subscription = GetSubscription($subscriptionid);
         my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
 
@@ -1333,7 +1347,8 @@ sub ModSubscription {
     $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
     $biblionumber, $callnumber, $notes, $letter, $manualhistory,
     $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
-    $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq
+    $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq,
+    $itemtype, $previousitemtype
     ) = @_;
 
     my $dbh   = C4::Context->dbh;
@@ -1346,7 +1361,7 @@ sub ModSubscription {
             callnumber=?, notes=?, letter=?, manualhistory=?,
             internalnotes=?, serialsadditems=?, staffdisplaycount=?,
             opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
-            skip_serialseq=?
+            skip_serialseq=?, itemtype=?, previousitemtype=?
         WHERE subscriptionid = ?";
 
     my $sth = $dbh->prepare($query);
@@ -1360,6 +1375,7 @@ sub ModSubscription {
         $letter,          ($manualhistory ? $manualhistory : 0),
         $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
         $graceperiod,     $location,       $enddate,        $skip_serialseq,
+        $itemtype,        $previousitemtype,
         $subscriptionid
     );
     my $rows = $sth->rows;
@@ -1375,7 +1391,8 @@ $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbu
     $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
     $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
     $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
-    $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq);
+    $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
+    $skip_serialseq, $itemtype, $previousitemtype);
 
 Create a new subscription with value given on input args.
 
@@ -1392,7 +1409,7 @@ sub NewSubscription {
     $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
     $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
     $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
-    $location, $enddate, $skip_serialseq
+    $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype
     ) = @_;
     my $dbh = C4::Context->dbh;
 
@@ -1405,8 +1422,9 @@ sub NewSubscription {
             lastvalue3, innerloop3, status, notes, letter, firstacquidate,
             irregularity, numberpattern, locale, callnumber,
             manualhistory, internalnotes, serialsadditems, staffdisplaycount,
-            opacdisplaycount, graceperiod, location, enddate, skip_serialseq)
-        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
+            opacdisplaycount, graceperiod, location, enddate, skip_serialseq,
+            itemtype, previousitemtype)
+        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
         |;
     my $sth = $dbh->prepare($query);
     $sth->execute(
@@ -1416,7 +1434,8 @@ sub NewSubscription {
         $lastvalue3, $innerloop3, $status, $notes, $letter,
         $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
         $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
-        $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq
+        $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq,
+        $itemtype, $previousitemtype
     );
 
     my $subscriptionid = $dbh->{'mysql_insertid'};
@@ -1447,8 +1466,7 @@ sub NewSubscription {
     # calculate issue number
     my $serialseq = GetSeq($subscription, $pattern) || q{};
 
-    my $serial_rs = Koha::Database->new()->schema()->resultset('Serial');
-    $serial_rs->create(
+    Koha::Serial->new(
         {
             serialseq      => $serialseq,
             serialseq_x    => $subscription->{'lastvalue1'},
@@ -1460,7 +1478,7 @@ sub NewSubscription {
             planneddate    => $firstacquidate,
             publisheddate  => $firstacquidate,
         }
-    );
+    )->store();
 
     logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
 
@@ -1529,13 +1547,6 @@ sub ReNewSubscription {
     |;
     $sth = $dbh->prepare($query);
     $sth->execute( $enddate, $subscriptionid );
-    $query = qq|
-        UPDATE subscriptionhistory
-        SET    histenddate=?
-        WHERE  subscriptionid=?
-    |;
-    $sth = $dbh->prepare($query);
-    $sth->execute( $enddate, $subscriptionid );
 
     logaction( "SERIAL", "RENEW", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
     return;
@@ -1560,54 +1571,47 @@ sub NewIssue {
 
     my $schema = Koha::Database->new()->schema();
 
-    my $subscription = $schema->resultset('Subscription')->find( $subscriptionid );
+    my $subscription = Koha::Subscriptions->find( $subscriptionid );
 
-    my $serial = $schema->resultset('Serial')->create(
+    my $serial = Koha::Serial->new(
         {
-            serialseq      => $serialseq,
-            serialseq_x    => $subscription->lastvalue1(),
-            serialseq_y    => $subscription->lastvalue2(),
-            serialseq_z    => $subscription->lastvalue3(),
-            subscriptionid => $subscriptionid,
-            biblionumber   => $biblionumber,
-            status         => $status,
-            planneddate    => $planneddate,
-            publisheddate  => $publisheddate,
+            serialseq         => $serialseq,
+            serialseq_x       => $subscription->lastvalue1(),
+            serialseq_y       => $subscription->lastvalue2(),
+            serialseq_z       => $subscription->lastvalue3(),
+            subscriptionid    => $subscriptionid,
+            biblionumber      => $biblionumber,
+            status            => $status,
+            planneddate       => $planneddate,
+            publisheddate     => $publisheddate,
             publisheddatetext => $publisheddatetext,
-            notes => $notes,
+            notes             => $notes,
         }
-    );
+    )->store();
 
-    my $dbh   = C4::Context->dbh;
     my $serialid = $serial->id();
 
-    my $query = qq|
-        SELECT missinglist,recievedlist
-        FROM   subscriptionhistory
-        WHERE  subscriptionid=?
-    |;
-    my $sth = $dbh->prepare($query);
-    $sth->execute($subscriptionid);
-    my ( $missinglist, $recievedlist ) = $sth->fetchrow;
+    my $subscription_history = Koha::Subscription::Histories->find($subscriptionid);
+    my $missinglist = $subscription_history->missinglist();
+    my $recievedlist = $subscription_history->recievedlist();
 
     if ( $status == ARRIVED ) {
-      ### TODO Add a feature that improves recognition and description.
-      ### As such count (serialseq) i.e. : N18,2(N19),N20
-      ### Would use substr and index But be careful to previous presence of ()
-        $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
+        ### TODO Add a feature that improves recognition and description.
+        ### As such count (serialseq) i.e. : N18,2(N19),N20
+        ### Would use substr and index But be careful to previous presence of ()
+        $recievedlist .= "; $serialseq" unless ( index( $recievedlist, $serialseq ) > 0 );
     }
-    if ( grep {/^$status$/} ( MISSING_STATUSES ) ) {
-        $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
+    if ( grep { /^$status$/ } (MISSING_STATUSES) ) {
+        $missinglist .= "; $serialseq" unless ( index( $missinglist, $serialseq ) > 0 );
     }
-    $query = qq|
-        UPDATE subscriptionhistory
-        SET    recievedlist=?, missinglist=?
-        WHERE  subscriptionid=?
-    |;
-    $sth = $dbh->prepare($query);
+
     $recievedlist =~ s/^; //;
     $missinglist  =~ s/^; //;
-    $sth->execute( $recievedlist, $missinglist, $subscriptionid );
+
+    $subscription_history->recievedlist($recievedlist);
+    $subscription_history->missinglist($missinglist);
+    $subscription_history->store();
+
     return $serialid;
 }
 
@@ -1901,42 +1905,19 @@ called from claims.pl file
 =cut
 
 sub updateClaim {
-    my ($serialid) = @_;
-    my $dbh        = C4::Context->dbh;
-    $dbh->do(q|
+    my ($serialids) = @_;
+    return unless $serialids;
+    unless ( ref $serialids ) {
+        $serialids = [ $serialids ];
+    }
+    my $dbh = C4::Context->dbh;
+    return $dbh->do(q|
         UPDATE serial
         SET claimdate = NOW(),
-            claims_count = claims_count + 1
-        WHERE serialid = ?
-    |, {}, $serialid );
-    return;
-}
-
-=head2 getsupplierbyserialid
-
-$result = getsupplierbyserialid($serialid)
-
-this function is used to find the supplier id given a serial id
-
-return :
-hashref containing serialid, subscriptionid, and aqbooksellerid
-
-=cut
-
-sub getsupplierbyserialid {
-    my ($serialid) = @_;
-    my $dbh        = C4::Context->dbh;
-    my $sth        = $dbh->prepare(
-        "SELECT serialid, serial.subscriptionid, aqbooksellerid
-         FROM serial 
-            LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
-            WHERE serialid = ?
-        "
-    );
-    $sth->execute($serialid);
-    my $line   = $sth->fetchrow_hashref;
-    my $result = $line->{'aqbooksellerid'};
-    return $result;
+            claims_count = claims_count + 1,
+            status = ?
+        WHERE serialid in (| . join( q|,|, (q|?|) x @$serialids ) . q|)|,
+        {}, CLAIMED, @$serialids );
 }
 
 =head2 check_routing
@@ -2262,6 +2243,11 @@ depending on how many rows are in serial table.
 The issue number calculation is based on subscription frequency, first acquisition
 date, and $publisheddate.
 
+Returns undef when called for irregular frequencies.
+
+The routine is used to skip irregularities when calculating the next issue
+date (in GetNextDate) or the next issue number (in GetNextSeq).
+
 =cut
 
 sub GetFictiveIssueNumber {
@@ -2269,118 +2255,144 @@ sub GetFictiveIssueNumber {
 
     my $frequency = GetSubscriptionFrequency($subscription->{'periodicity'});
     my $unit = $frequency->{unit} ? lc $frequency->{'unit'} : undef;
-    my $issueno = 0;
-
-    if($unit) {
-        my ($year, $month, $day) = split /-/, $publisheddate;
-        my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{'firstacquidate'};
-        my $wkno;
-        my $delta;
-
-        if($unit eq 'day') {
-            $delta = Delta_Days($fa_year, $fa_month, $fa_day, $year, $month, $day);
-        } elsif($unit eq 'week') {
-            ($wkno, $year) = Week_of_Year($year, $month, $day);
-            my ($fa_wkno, $fa_yr) = Week_of_Year($fa_year, $fa_month, $fa_day);
-            $delta = ($fa_yr == $year) ? ($wkno - $fa_wkno) : ( ($year-$fa_yr-1)*52 + (52-$fa_wkno+$wkno) );
-        } elsif($unit eq 'month') {
-            $delta = ($fa_year == $year)
-                   ? ($month - $fa_month)
-                   : ( ($year-$fa_year-1)*12 + (12-$fa_month+$month) );
-        } elsif($unit eq 'year') {
-            $delta = $year - $fa_year;
-        }
-        if($frequency->{'unitsperissue'} == 1) {
-            $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
-        } else {
-            # Assuming issuesperunit == 1
-            $issueno = int( ($delta + $frequency->{'unitsperissue'}) / $frequency->{'unitsperissue'} );
-        }
+    return if !$unit;
+    my $issueno;
+
+    my ( $year, $month, $day ) = split /-/, $publisheddate;
+    my ( $fa_year, $fa_month, $fa_day ) = split /-/, $subscription->{'firstacquidate'};
+    my $delta = _delta_units( [$fa_year, $fa_month, $fa_day], [$year, $month, $day], $unit );
+
+    if( $frequency->{'unitsperissue'} == 1 ) {
+        $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
+    } else { # issuesperunit == 1
+        $issueno = 1 + int( $delta / $frequency->{'unitsperissue'} );
     }
     return $issueno;
 }
 
+sub _delta_units {
+    my ( $date1, $date2, $unit ) = @_;
+    # date1 and date2 are array refs in the form [ yy, mm, dd ]
+
+    if( $unit eq 'day' ) {
+        return Delta_Days( @$date1, @$date2 );
+    } elsif( $unit eq 'week' ) {
+        return int( Delta_Days( @$date1, @$date2 ) / 7 );
+    }
+
+    # In case of months or years, this is a wrapper around N_Delta_YMD.
+    # Note that N_Delta_YMD returns 29 days between e.g. 22-2-72 and 22-3-72
+    # while we expect 1 month.
+    my @delta = N_Delta_YMD( @$date1, @$date2 );
+    if( $delta[2] > 27 ) {
+        # Check if we could add a month
+        my @jump = Add_Delta_YM( @$date1, $delta[0], 1 + $delta[1] );
+        if( Delta_Days( @jump, @$date2 ) >= 0 ) {
+            $delta[1]++;
+        }
+    }
+    if( $delta[1] >= 12 ) {
+        $delta[0]++;
+        $delta[1] -= 12;
+    }
+    # if unit is year, we only return full years
+    return $unit eq 'month' ? $delta[0] * 12 + $delta[1] : $delta[0];
+}
+
 sub _get_next_date_day {
     my ($subscription, $freqdata, $year, $month, $day) = @_;
 
-    if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
-        ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{unitsperissue} );
-        $subscription->{countissuesperunit} = 1;
-    } else {
+    my @newissue; # ( yy, mm, dd )
+    # We do not need $delta_days here, since it would be zero where used
+
+    if( $freqdata->{issuesperunit} == 1 ) {
+        # Add full days
+        @newissue = Add_Delta_Days(
+            $year, $month, $day, $freqdata->{"unitsperissue"} );
+    } elsif ( $subscription->{countissuesperunit} < $freqdata->{issuesperunit} ) {
+        # Add zero days
+        @newissue = ( $year, $month, $day );
         $subscription->{countissuesperunit}++;
+    } else {
+        # We finished a cycle of issues within a unit.
+        # No subtraction of zero needed, just add one day
+        @newissue = Add_Delta_Days( $year, $month, $day, 1 );
+        $subscription->{countissuesperunit} = 1;
     }
-
-    return ($year, $month, $day);
+    return @newissue;
 }
 
 sub _get_next_date_week {
     my ($subscription, $freqdata, $year, $month, $day) = @_;
 
-    my ($wkno, $yr) = Week_of_Year($year, $month, $day);
-    my $fa_dow = Day_of_Week(split /-/, $subscription->{firstacquidate});
+    my @newissue; # ( yy, mm, dd )
+    my $delta_days = int( 7 / $freqdata->{issuesperunit} );
 
-    if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
-        $subscription->{countissuesperunit} = 1;
-        $wkno += $freqdata->{unitsperissue};
-        if($wkno > 52){
-            $wkno = $wkno % 52;
-            $yr++;
-        }
-        ($year,$month,$day) = Monday_of_Week($wkno, $yr);
-        ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $fa_dow - 1);
-    } else {
-        # Try to guess the next day of week
-        my $delta_days = int((7 - ($fa_dow - 1)) / $freqdata->{issuesperunit});
-        ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
+    if( $freqdata->{issuesperunit} == 1 ) {
+        # Add full weeks (of 7 days)
+        @newissue = Add_Delta_Days(
+            $year, $month, $day, 7 * $freqdata->{"unitsperissue"} );
+    } elsif ( $subscription->{countissuesperunit} < $freqdata->{issuesperunit} ) {
+        # Add rounded number of days based on frequency.
+        @newissue = Add_Delta_Days( $year, $month, $day, $delta_days );
         $subscription->{countissuesperunit}++;
+    } else {
+        # We finished a cycle of issues within a unit.
+        # Subtract delta * (issues - 1), add 1 week
+        @newissue = Add_Delta_Days( $year, $month, $day,
+            -$delta_days * ($freqdata->{issuesperunit} - 1) );
+        @newissue = Add_Delta_Days( @newissue, 7 );
+        $subscription->{countissuesperunit} = 1;
     }
-
-    return ($year, $month, $day);
+    return @newissue;
 }
 
 sub _get_next_date_month {
     my ($subscription, $freqdata, $year, $month, $day) = @_;
 
-    my $fa_day;
-    (undef, undef, $fa_day) = split /-/, $subscription->{firstacquidate};
+    my @newissue; # ( yy, mm, dd )
+    my $delta_days = int( 30 / $freqdata->{issuesperunit} );
 
-    if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
-        $subscription->{countissuesperunit} = 1;
-        ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,
-            $freqdata->{unitsperissue});
-        my $days_in_month = Days_in_Month($year, $month);
-        $day = $fa_day <= $days_in_month ? $fa_day : $days_in_month;
-    } else {
-        # Try to guess the next day in month
-        my $days_in_month = Days_in_Month($year, $month);
-        my $delta_days = int(($days_in_month - ($fa_day - 1)) / $freqdata->{issuesperunit});
-        ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
+    if( $freqdata->{issuesperunit} == 1 ) {
+        # Add full months
+        @newissue = Add_Delta_YM(
+            $year, $month, $day, 0, $freqdata->{"unitsperissue"} );
+    } elsif ( $subscription->{countissuesperunit} < $freqdata->{issuesperunit} ) {
+        # Add rounded number of days based on frequency.
+        @newissue = Add_Delta_Days( $year, $month, $day, $delta_days );
         $subscription->{countissuesperunit}++;
+    } else {
+        # We finished a cycle of issues within a unit.
+        # Subtract delta * (issues - 1), add 1 month
+        @newissue = Add_Delta_Days( $year, $month, $day,
+            -$delta_days * ($freqdata->{issuesperunit} - 1) );
+        @newissue = Add_Delta_YM( @newissue, 0, 1 );
+        $subscription->{countissuesperunit} = 1;
     }
-
-    return ($year, $month, $day);
+    return @newissue;
 }
 
 sub _get_next_date_year {
     my ($subscription, $freqdata, $year, $month, $day) = @_;
 
-    my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{firstacquidate};
+    my @newissue; # ( yy, mm, dd )
+    my $delta_days = int( 365 / $freqdata->{issuesperunit} );
 
-    if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
-        $subscription->{countissuesperunit} = 1;
-        ($year) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
-        $month = $fa_month;
-        my $days_in_month = Days_in_Month($year, $month);
-        $day = $fa_day <= $days_in_month ? $fa_day : $days_in_month;
-    } else {
-        # Try to guess the next day in year
-        my $days_in_year = Days_in_Year($year,12); #Sum the days of all the months of this year
-        my $delta_days = int(($days_in_year - ($fa_day - 1)) / $freqdata->{issuesperunit});
-        ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
+    if( $freqdata->{issuesperunit} == 1 ) {
+        # Add full years
+        @newissue = Add_Delta_YM( $year, $month, $day, $freqdata->{"unitsperissue"}, 0 );
+    } elsif ( $subscription->{countissuesperunit} < $freqdata->{issuesperunit} ) {
+        # Add rounded number of days based on frequency.
+        @newissue = Add_Delta_Days( $year, $month, $day, $delta_days );
         $subscription->{countissuesperunit}++;
+    } else {
+        # We finished a cycle of issues within a unit.
+        # Subtract delta * (issues - 1), add 1 year
+        @newissue = Add_Delta_Days( $year, $month, $day, -$delta_days * ($freqdata->{issuesperunit} - 1) );
+        @newissue = Add_Delta_YM( @newissue, 1, 0 );
+        $subscription->{countissuesperunit} = 1;
     }
-
-    return ($year, $month, $day);
+    return @newissue;
 }
 
 =head2 GetNextDate
@@ -2490,11 +2502,13 @@ sub GetNextDate {
 _numeration returns the string corresponding to $value in the num_type
 num_type can take :
     -dayname
+    -dayabrv
     -monthname
+    -monthabrv
     -season
-=cut
+    -seasonabrv
 
-#'
+=cut
 
 sub _numeration {
     my ($value, $num_type, $locale) = @_;
@@ -2502,7 +2516,7 @@ sub _numeration {
     $num_type //= '';
     $locale ||= 'en';
     my $string;
-    if ( $num_type =~ /^dayname$/ ) {
+    if ( $num_type =~ /^dayname$/ or $num_type =~ /^dayabrv$/ ) {
         # 1970-11-01 was a Sunday
         $value = $value % 7;
         my $dt = DateTime->new(
@@ -2511,19 +2525,27 @@ sub _numeration {
             day     => $value + 1,
             locale  => $locale,
         );
-        $string = $dt->strftime("%A");
-    } elsif ( $num_type =~ /^monthname$/ ) {
+        $string = $num_type =~ /^dayname$/
+            ? $dt->strftime("%A")
+            : $dt->strftime("%a");
+    } elsif ( $num_type =~ /^monthname$/ or $num_type =~ /^monthabrv$/ ) {
         $value = $value % 12;
         my $dt = DateTime->new(
             year    => 1970,
             month   => $value + 1,
             locale  => $locale,
         );
-        $string = $dt->strftime("%B");
+        $string = $num_type =~ /^monthname$/
+            ? $dt->strftime("%B")
+            : $dt->strftime("%b");
     } elsif ( $num_type =~ /^season$/ ) {
         my @seasons= qw( Spring Summer Fall Winter );
         $value = $value % 4;
         $string = $seasons[$value];
+    } elsif ( $num_type =~ /^seasonabrv$/ ) {
+        my @seasonsabrv= qw( Spr Sum Fal Win );
+        $value = $value % 4;
+        $string = $seasonsabrv[$value];
     } else {
         $string = $value;
     }
@@ -2552,8 +2574,11 @@ sub is_barcode_in_use {
 }
 
 =head2 CloseSubscription
+
 Close a subscription given a subscriptionid
+
 =cut
+
 sub CloseSubscription {
     my ( $subscriptionid ) = @_;
     return unless $subscriptionid;
@@ -2576,8 +2601,11 @@ sub CloseSubscription {
 }
 
 =head2 ReopenSubscription
+
 Reopen a subscription given a subscriptionid
+
 =cut
+
 sub ReopenSubscription {
     my ( $subscriptionid ) = @_;
     return unless $subscriptionid;
@@ -2693,6 +2721,25 @@ sub _can_do_on_subscription {
     return 0;
 }
 
+=head2 findSerialsByStatus
+
+    @serials = findSerialsByStatus($status, $subscriptionid);
+
+    Returns an array of serials matching a given status and subscription id.
+
+=cut
+
+sub findSerialsByStatus {
+    my ( $status, $subscriptionid ) = @_;
+    my $dbh   = C4::Context->dbh;
+    my $query = q| SELECT * from serial
+                    WHERE status = ?
+                    AND subscriptionid = ?
+                |;
+    my $serials = $dbh->selectall_arrayref( $query, { Slice => {} }, $status, $subscriptionid );
+    return @$serials;
+}
+
 1;
 __END__