Bug 11814: Fix existing tests
[koha.git] / C4 / Serials.pm
index 7aa758f..b52b7a9 100644 (file)
@@ -5,26 +5,27 @@ package C4::Serials;
 #
 # This file is part of Koha.
 #
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
 #
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 use Modern::Perl;
 
 use C4::Auth qw(haspermission);
 use C4::Context;
 use C4::Dates qw(format_date format_date_in_iso);
+use DateTime;
 use Date::Calc qw(:all);
-use POSIX qw(strftime setlocale LC_TIME);
+use POSIX qw(strftime);
 use C4::Biblio;
 use C4::Log;    # logaction
 use C4::Debug;
@@ -33,12 +34,34 @@ use C4::Serials::Numberpattern;
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
+# Define statuses
+use constant {
+    EXPECTED               => 1,
+    ARRIVED                => 2,
+    LATE                   => 3,
+    MISSING                => 4,
+    MISSING_NEVER_RECIEVED => 41,
+    MISSING_SOLD_OUT       => 42,
+    MISSING_DAMAGED        => 43,
+    MISSING_LOST           => 44,
+    NOT_ISSUED             => 5,
+    DELETED                => 6,
+    CLAIMED                => 7,
+    STOPPED                => 8,
+};
+
+use constant MISSING_STATUSES => (
+    MISSING,          MISSING_NEVER_RECIEVED,
+    MISSING_SOLD_OUT, MISSING_DAMAGED,
+    MISSING_LOST
+);
+
 BEGIN {
     $VERSION = 3.07.00.049;    # set version for version checking
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
-      &NewSubscription    &ModSubscription    &DelSubscription    &GetSubscriptions
+      &NewSubscription    &ModSubscription    &DelSubscription
       &GetSubscription    &CountSubscriptionFromBiblionumber      &GetSubscriptionsFromBiblionumber
       &SearchSubscriptions
       &GetFullSubscriptionsFromBiblionumber   &GetFullSubscription &ModSubscriptionHistory
@@ -47,7 +70,7 @@ BEGIN {
 
       &GetNextSeq &GetSeq &NewIssue           &ItemizeSerials    &GetSerials
       &GetLatestSerials   &ModSerialStatus    &GetNextDate       &GetSerials2
-      &ReNewSubscription  &GetLateIssues      &GetLateOrMissingIssues
+      &ReNewSubscription  &GetLateOrMissingIssues
       &GetSerialInformation                   &AddItem2Serial
       &PrepareSerialsData &GetNextExpected    &ModNextExpected
 
@@ -94,79 +117,22 @@ the array is in name order
 
 sub GetSuppliersWithLateIssues {
     my $dbh   = C4::Context->dbh;
+    my $statuses = join(',', ( LATE, MISSING_STATUSES, CLAIMED ) );
     my $query = qq|
-        SELECT DISTINCT id, name
+    SELECT DISTINCT id, name
     FROM            subscription
     LEFT JOIN       serial ON serial.subscriptionid=subscription.subscriptionid
     LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
     WHERE id > 0
         AND (
             (planneddate < now() AND serial.status=1)
-            OR serial.STATUS IN (3, 4, 41, 42, 43, 44)
+            OR serial.STATUS IN ( $statuses )
         )
         AND subscription.closed = 0
     ORDER BY name|;
     return $dbh->selectall_arrayref($query, { Slice => {} });
 }
 
-=head2 GetLateIssues
-
-@issuelist = GetLateIssues($supplierid)
-
-this function selects late issues from the database
-
-return :
-the issuelist as an array. Each element of this array contains a hashi_ref containing
-name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
-
-=cut
-
-sub GetLateIssues {
-    my ($supplierid) = @_;
-
-    return unless ($supplierid);
-
-    my $dbh = C4::Context->dbh;
-    my $sth;
-    if ($supplierid) {
-        my $query = qq|
-            SELECT     name,title,planneddate,serialseq,serial.subscriptionid
-            FROM       subscription
-            LEFT JOIN  serial ON subscription.subscriptionid = serial.subscriptionid
-            LEFT JOIN  biblio ON biblio.biblionumber = subscription.biblionumber
-            LEFT JOIN  aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
-            WHERE      ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
-            AND        subscription.aqbooksellerid=?
-            AND        subscription.closed = 0
-            ORDER BY   title
-        |;
-        $sth = $dbh->prepare($query);
-        $sth->execute($supplierid);
-    } else {
-        my $query = qq|
-            SELECT     name,title,planneddate,serialseq,serial.subscriptionid
-            FROM       subscription
-            LEFT JOIN  serial ON subscription.subscriptionid = serial.subscriptionid
-            LEFT JOIN  biblio ON biblio.biblionumber = subscription.biblionumber
-            LEFT JOIN  aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
-            WHERE      ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
-            AND        subscription.closed = 0
-            ORDER BY   title
-        |;
-        $sth = $dbh->prepare($query);
-        $sth->execute;
-    }
-    my @issuelist;
-    my $last_title;
-    while ( my $line = $sth->fetchrow_hashref ) {
-        $line->{title} = "" if $last_title and $line->{title} eq $last_title;
-        $last_title = $line->{title} if ( $line->{title} );
-        $line->{planneddate} = format_date( $line->{planneddate} );
-        push @issuelist, $line;
-    }
-    return @issuelist;
-}
-
 =head2 GetSubscriptionHistoryFromSubscriptionId
 
 $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
@@ -309,10 +275,14 @@ sub UpdateClaimdateIssues {
     my $dbh = C4::Context->dbh;
     $date = strftime( "%Y-%m-%d", localtime ) unless ($date);
     my $query = "
-        UPDATE serial SET claimdate = ?, status = 7
-        WHERE  serialid in (" . join( ",", map { '?' } @$serialids ) . ")";
+        UPDATE serial
+        SET claimdate = ?,
+            status = ?,
+            claims_count = claims_count + 1
+        WHERE  serialid in (" . join( ",", map { '?' } @$serialids ) . ")
+    ";
     my $rq = $dbh->prepare($query);
-    $rq->execute($date, @$serialids);
+    $rq->execute($date, CLAIMED, @$serialids);
     return $rq->rows;
 }
 
@@ -425,7 +395,7 @@ sub PrepareSerialsData {
             }
         }
         $subs->{ "status" . $subs->{'status'} } = 1;
-        if ( grep { $_ == $subs->{status} } qw( 1 3 4 41 42 43 44 7 ) ) {
+        if ( grep { $_ == $subs->{status} } ( EXPECTED, LATE, MISSING_STATUSES, CLAIMED ) ) {
             $subs->{"checked"} = 1;
         }
 
@@ -549,85 +519,6 @@ sub GetFullSubscriptionsFromBiblionumber {
     return $subscriptions;
 }
 
-=head2 GetSubscriptions
-
-@results = GetSubscriptions($title,$ISSN,$ean,$biblionumber);
-this function gets all subscriptions which have title like $title,ISSN like $ISSN,EAN like $ean and biblionumber like $biblionumber.
-return:
-a table of hashref. Each hash containt the subscription.
-
-=cut
-
-sub GetSubscriptions {
-    my ( $string, $issn, $ean, $biblionumber ) = @_;
-
-    #return unless $title or $ISSN or $biblionumber;
-    my $dbh = C4::Context->dbh;
-    my $sth;
-    my $sql = qq(
-            SELECT subscriptionhistory.*, subscription.*, biblio.title,biblioitems.issn,biblio.biblionumber
-            FROM   subscription
-            LEFT JOIN subscriptionhistory USING(subscriptionid)
-            LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
-            LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
-    );
-    my @bind_params;
-    my $sqlwhere = q{};
-    if ($biblionumber) {
-        $sqlwhere = "   WHERE biblio.biblionumber=?";
-        push @bind_params, $biblionumber;
-    }
-    if ($string) {
-        my @sqlstrings;
-        my @strings_to_search;
-        @strings_to_search = map { "%$_%" } split( / /, $string );
-        foreach my $index (qw(biblio.title subscription.callnumber subscription.location subscription.notes subscription.internalnotes)) {
-            push @bind_params, @strings_to_search;
-            my $tmpstring = "AND $index LIKE ? " x scalar(@strings_to_search);
-            $debug && warn "$tmpstring";
-            $tmpstring =~ s/^AND //;
-            push @sqlstrings, $tmpstring;
-        }
-        $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
-    }
-    if ($issn) {
-        my @sqlstrings;
-        my @strings_to_search;
-        @strings_to_search = map { "%$_%" } split( / /, $issn );
-        foreach my $index ( qw(biblioitems.issn subscription.callnumber)) {
-            push @bind_params, @strings_to_search;
-            my $tmpstring = "OR $index LIKE ? " x scalar(@strings_to_search);
-            $debug && warn "$tmpstring";
-            $tmpstring =~ s/^OR //;
-            push @sqlstrings, $tmpstring;
-        }
-        $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
-    }
-    if ($ean) {
-        my @sqlstrings;
-        my @strings_to_search;
-        @strings_to_search = map { "$_" } split( / /, $ean );
-        foreach my $index ( qw(biblioitems.ean) ) {
-            push @bind_params, @strings_to_search;
-            my $tmpstring = "OR $index = ? " x scalar(@strings_to_search);
-            $debug && warn "$tmpstring";
-            $tmpstring =~ s/^OR //;
-            push @sqlstrings, $tmpstring;
-        }
-        $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
-    }
-
-    $sql .= "$sqlwhere ORDER BY title";
-    $debug and warn "GetSubscriptions query: $sql params : ", join( " ", @bind_params );
-    $sth = $dbh->prepare($sql);
-    $sth->execute(@bind_params);
-    my $subscriptions = $sth->fetchall_arrayref( {} );
-    for my $subscription ( @$subscriptions ) {
-        $subscription->{cannotedit} = not can_edit_subscription( $subscription );
-    }
-    return @$subscriptions;
-}
-
 =head2 SearchSubscriptions
 
   @results = SearchSubscriptions($args);
@@ -657,14 +548,15 @@ subscription expiration date.
 sub SearchSubscriptions {
     my ( $args ) = @_;
 
-    my $query = qq{
+    my $query = q{
         SELECT
             subscription.notes AS publicnotes,
-            subscription.*,
             subscriptionhistory.*,
+            subscription.*,
             biblio.notes AS biblionotes,
             biblio.title,
             biblio.author,
+            biblio.biblionumber,
             biblioitems.issn
         FROM subscription
             LEFT JOIN subscriptionhistory USING(subscriptionid)
@@ -730,6 +622,8 @@ sub SearchSubscriptions {
         $query .= " WHERE " . join(" AND ", @where_strs);
     }
 
+    $query .= " ORDER BY " . $args->{orderby} if $args->{orderby};
+
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare($query);
     $sth->execute(@where_args);
@@ -767,9 +661,10 @@ sub GetSerials {
     my $counter = 0;
     $count = 5 unless ($count);
     my @serials;
+    my $statuses = join( ',', ( ARRIVED, MISSING_STATUSES, NOT_ISSUED ) );
     my $query = "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
                         FROM   serial
-                        WHERE  subscriptionid = ? AND status NOT IN (2, 4, 41, 42, 43, 44, 5)
+                        WHERE  subscriptionid = ? AND status NOT IN ( $statuses )
                         ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
     my $sth = $dbh->prepare($query);
     $sth->execute($subscriptionid);
@@ -790,7 +685,7 @@ sub GetSerials {
     $query = "SELECT   serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
        FROM     serial
        WHERE    subscriptionid = ?
-       AND      (status in (2, 4, 41, 42, 43, 44, 5))
+       AND      status IN ( $statuses )
        ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
       ";
     $sth = $dbh->prepare($query);
@@ -818,23 +713,27 @@ sub GetSerials {
 
 =head2 GetSerials2
 
-@serials = GetSerials2($subscriptionid,$status);
+@serials = GetSerials2($subscriptionid,$statuses);
 this function returns every serial waited for a given subscription
 as well as the number of issues registered in the database (all types)
 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
 
+$statuses is an arrayref of statuses and is mandatory.
+
 =cut
 
 sub GetSerials2 {
-    my ( $subscription, $status ) = @_;
+    my ( $subscription, $statuses ) = @_;
 
-    return unless ($subscription and $status);
+    return unless ($subscription and @$statuses);
+
+    my $statuses_string = join ',', @$statuses;
 
     my $dbh   = C4::Context->dbh;
     my $query = qq|
                  SELECT   serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
                  FROM     serial 
-                 WHERE    subscriptionid=$subscription AND status IN ($status)
+                 WHERE    subscriptionid=$subscription AND status IN ($statuses_string)
                  ORDER BY publisheddate,serialid DESC
                     |;
     $debug and warn "GetSerials2 query: $query";
@@ -874,11 +773,11 @@ sub GetLatestSerials {
 
     my $dbh = C4::Context->dbh;
 
-    # status = 2 is "arrived"
+    my $statuses = join( ',', ( ARRIVED, MISSING_STATUSES ) );
     my $strsth = "SELECT   serialid,serialseq, status, planneddate, publisheddate, notes
                         FROM     serial
                         WHERE    subscriptionid = ?
-                        AND      status IN (2, 4, 41, 42, 43, 44)
+                        AND      status IN ($statuses)
                         ORDER BY publisheddate DESC LIMIT 0,$limit
                 ";
     my $sth = $dbh->prepare($strsth);
@@ -1076,7 +975,9 @@ sub GetExpirationDate {
     # we don't do the same test if the subscription is based on X numbers or on X weeks/months
     $enddate = $startdate || $subscription->{startdate};
     my @date = split( /-/, $enddate );
+
     return if ( scalar(@date) != 3 || not check_date(@date) );
+
     my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
     if ( $frequency and $frequency->{unit} ) {
 
@@ -1156,50 +1057,6 @@ sub ModSubscriptionHistory {
     return $sth->rows;
 }
 
-# Update missinglist field, used by ModSerialStatus
-sub _update_missinglist {
-    my $subscriptionid = shift;
-
-    my $dbh = C4::Context->dbh;
-    my @missingserials = GetSerials2($subscriptionid, "4,41,42,43,44,5");
-    my $missinglist;
-    foreach my $missingserial (@missingserials) {
-        if ( grep { $_ == $missingserial->{status} } qw( 4 41 42 43 44 ) ) {
-            $missinglist .= $missingserial->{'serialseq'} . "; ";
-        } elsif($missingserial->{'status'} == 5) {
-            $missinglist .= "not issued " . $missingserial->{'serialseq'} . "; ";
-        }
-    }
-    $missinglist =~ s/; $//;
-    my $query = qq{
-        UPDATE subscriptionhistory
-        SET missinglist = ?
-        WHERE subscriptionid = ?
-    };
-    my $sth = $dbh->prepare($query);
-    $sth->execute($missinglist, $subscriptionid);
-}
-
-# Update recievedlist field, used by ModSerialStatus
-sub _update_receivedlist {
-    my $subscriptionid = shift;
-
-    my $dbh = C4::Context->dbh;
-    my @receivedserials = GetSerials2($subscriptionid, "2");
-    my $receivedlist;
-    foreach (@receivedserials) {
-        $receivedlist .= $_->{'serialseq'} . "; ";
-    }
-    $receivedlist =~ s/; $//;
-    my $query = qq{
-        UPDATE subscriptionhistory
-        SET recievedlist = ?
-        WHERE subscriptionid = ?
-    };
-    my $sth = $dbh->prepare($query);
-    $sth->execute($receivedlist, $subscriptionid);
-}
-
 =head2 ModSerialStatus
 
 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
@@ -1228,7 +1085,7 @@ sub ModSerialStatus {
 
     # change status & update subscriptionhistory
     my $val;
-    if ( $status == 6 ) {
+    if ( $status == DELETED ) {
         DelIssue( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
     } else {
 
@@ -1240,22 +1097,36 @@ sub ModSerialStatus {
         $sth->execute($subscriptionid);
         my $val = $sth->fetchrow_hashref;
         unless ( $val->{manualhistory} ) {
-            if ( $status == 2 || ($oldstatus == 2 && $status != 2) ) {
-                  _update_receivedlist($subscriptionid);
+            $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE  subscriptionid=?";
+            $sth   = $dbh->prepare($query);
+            $sth->execute($subscriptionid);
+            my ( $missinglist, $recievedlist ) = $sth->fetchrow;
+
+            if ( $status == ARRIVED || ($oldstatus == ARRIVED && $status != ARRIVED) ) {
+                $recievedlist .= "; $serialseq"
+                    if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
             }
-            my @missing_statuses = qw( 4 41 42 43 44 );
-            if ( (  grep { $_ == $status } ( @missing_statuses, 5 ) )
-              || (
-                  ( grep { $_ == $oldstatus } @missing_statuses )
-                  && ! ( grep { $_ == $status } @missing_statuses ) )
-              || ($oldstatus == 5 && $status != 5)) {
-                _update_missinglist($subscriptionid);
+
+            # in case serial has been previously marked as missing
+            if (grep /$status/, (EXPECTED, ARRIVED, LATE, CLAIMED)) {
+                $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
             }
+
+            $missinglist .= "; $serialseq"
+                if ( ( grep { $_ == $status } ( MISSING_STATUSES ) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
+            $missinglist .= "; not issued $serialseq"
+                if ( $status == NOT_ISSUED && $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
+
+            $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE  subscriptionid=?";
+            $sth   = $dbh->prepare($query);
+            $recievedlist =~ s/^; //;
+            $missinglist  =~ s/^; //;
+            $sth->execute( $recievedlist, $missinglist, $subscriptionid );
         }
     }
 
     # create new waited entry if needed (ie : was a "waited" and has changed)
-    if ( $oldstatus == 1 && $status != 1 ) {
+    if ( $oldstatus == EXPECTED && $status != EXPECTED ) {
         my $subscription = GetSubscription($subscriptionid);
         my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
 
@@ -1276,7 +1147,7 @@ sub ModSerialStatus {
         $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
 
         # check if an alert must be sent... (= a letter is defined & status became "arrived"
-        if ( $subscription->{letter} && $status == 2 && $oldstatus != 2 ) {
+        if ( $subscription->{letter} && $status == ARRIVED && $oldstatus != ARRIVED ) {
             require C4::Letters;
             C4::Letters::SendAlerts( 'issue', $subscription->{subscriptionid}, $subscription->{letter} );
         }
@@ -1313,8 +1184,8 @@ sub GetNextExpected {
     };
     my $sth = $dbh->prepare($query);
 
-    # Each subscription has only one 'expected' issue, with serial.status==1.
-    $sth->execute( $subscriptionid, 1 );
+    # Each subscription has only one 'expected' issue.
+    $sth->execute( $subscriptionid, EXPECTED );
     my $nextissue = $sth->fetchrow_hashref;
     if ( !$nextissue ) {
         $query = qq{
@@ -1361,8 +1232,8 @@ sub ModNextExpected {
     #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
     my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
 
-    # Each subscription has only one 'expected' issue, with serial.status==1.
-    $sth->execute( $date, $date, $subscriptionid, 1 );
+    # Each subscription has only one 'expected' issue.
+    $sth->execute( $date, $date, $subscriptionid, EXPECTED );
     return 0;
 
 }
@@ -1514,11 +1385,11 @@ sub NewSubscription {
     # then create the 1st expected number
     $query = qq(
         INSERT INTO subscriptionhistory
-            (biblionumber, subscriptionid, histstartdate,  opacnote, librariannote)
-        VALUES (?,?,?,?,?)
+            (biblionumber, subscriptionid, histstartdate)
+        VALUES (?,?,?)
         );
     $sth = $dbh->prepare($query);
-    $sth->execute( $biblionumber, $subscriptionid, $startdate, $notes, $internalnotes );
+    $sth->execute( $biblionumber, $subscriptionid, $startdate);
 
     # reread subscription to get a hash (for calculation of the 1st issue number)
     my $subscription = GetSubscription($subscriptionid);
@@ -1532,7 +1403,7 @@ sub NewSubscription {
         VALUES (?,?,?,?,?,?)
     |;
     $sth = $dbh->prepare($query);
-    $sth->execute( $serialseq, $subscriptionid, $biblionumber, 1, $firstacquidate, $firstacquidate );
+    $sth->execute( $serialseq, $subscriptionid, $biblionumber, EXPECTED, $firstacquidate, $firstacquidate );
 
     logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
 
@@ -1647,13 +1518,13 @@ sub NewIssue {
     $sth->execute($subscriptionid);
     my ( $missinglist, $recievedlist ) = $sth->fetchrow;
 
-    if ( $status == 2 ) {
+    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);
     }
-    if ( $status == 4 ) {
+    if ( grep {/^$status$/} ( MISSING_STATUSES ) ) {
         $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
     }
     $query = qq|
@@ -1992,7 +1863,7 @@ sub DelIssue {
 
 @issuelist = GetLateMissingIssues($supplierid,$serialid)
 
-this function selects missing issues on database - where serial.status = 4 or serial.status=3 or planneddate<now
+this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
 
 return :
 the issuelist as an array of hash refs. Each element of this array contains 
@@ -2016,49 +1887,52 @@ sub GetLateOrMissingIssues {
     } else {
         $order = "title";
     }
+    my $missing_statuses_string = join ',', (MISSING_STATUSES);
     if ($supplierid) {
         $sth = $dbh->prepare(
             "SELECT
                 serialid,      aqbooksellerid,        name,
                 biblio.title,  biblioitems.issn,      planneddate,    serialseq,
-                serial.status, serial.subscriptionid, claimdate,
+                serial.status, serial.subscriptionid, claimdate, claims_count,
                 subscription.branchcode
-            FROM      serial 
-                LEFT JOIN subscription  ON serial.subscriptionid=subscription.subscriptionid 
+            FROM      serial
+                LEFT JOIN subscription  ON serial.subscriptionid=subscription.subscriptionid
                 LEFT JOIN biblio        ON subscription.biblionumber=biblio.biblionumber
                 LEFT JOIN biblioitems   ON subscription.biblionumber=biblioitems.biblionumber
                 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
-                WHERE subscription.subscriptionid = serial.subscriptionid 
-                AND (serial.STATUS IN (4, 41, 42, 43, 44) OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
+                WHERE subscription.subscriptionid = serial.subscriptionid
+                AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
                 AND subscription.aqbooksellerid=$supplierid
                 $byserial
                 ORDER BY $order"
         );
     } else {
         $sth = $dbh->prepare(
-            "SELECT 
+            "SELECT
             serialid,      aqbooksellerid,         name,
             biblio.title,  planneddate,           serialseq,
-                serial.status, serial.subscriptionid, claimdate,
+                serial.status, serial.subscriptionid, claimdate, claims_count,
                 subscription.branchcode
-            FROM serial 
-                LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid 
+            FROM serial
+                LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
                 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
                 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
-                WHERE subscription.subscriptionid = serial.subscriptionid 
-                        AND (serial.STATUS IN (4, 41, 42, 43, 44) OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
+                WHERE subscription.subscriptionid = serial.subscriptionid
+                        AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
                 $byserial
                 ORDER BY $order"
         );
     }
-    $sth->execute;
+    $sth->execute( EXPECTED, LATE, CLAIMED );
     my @issuelist;
     while ( my $line = $sth->fetchrow_hashref ) {
 
         if ($line->{planneddate} && $line->{planneddate} !~/^0+\-/) {
+            $line->{planneddateISO} = $line->{planneddate};
             $line->{planneddate} = format_date( $line->{planneddate} );
         }
         if ($line->{claimdate} && $line->{claimdate} !~/^0+\-/) {
+            $line->{claimdateISO} = $line->{claimdate};
             $line->{claimdate}   = format_date( $line->{claimdate} );
         }
         $line->{"status".$line->{status}}   = 1;
@@ -2121,12 +1995,12 @@ called from claims.pl file
 sub updateClaim {
     my ($serialid) = @_;
     my $dbh        = C4::Context->dbh;
-    my $sth        = $dbh->prepare(
-        "UPDATE serial SET claimdate = now()
-                WHERE serialid = ?
-        "
-    );
-    $sth->execute($serialid);
+    $dbh->do(q|
+        UPDATE serial
+        SET claimdate = NOW(),
+            claims_count = claims_count + 1
+        WHERE serialid = ?
+    |, {}, $serialid );
     return;
 }
 
@@ -2399,18 +2273,26 @@ sub abouttoexpire {
     my $per = $subscription->{'periodicity'};
     my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($per);
     if ($frequency and $frequency->{unit}){
+
         my $expirationdate = GetExpirationDate($subscriptionid);
+
         my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
         my $nextdate = GetNextDate($subscription, $res);
-        if(Date::Calc::Delta_Days(
-            split( /-/, $nextdate ),
-            split( /-/, $expirationdate )
-        ) <= 0) {
-            return 1;
+
+        # only compare dates if both dates exist.
+        if ($nextdate and $expirationdate) {
+            if(Date::Calc::Delta_Days(
+                split( /-/, $nextdate ),
+                split( /-/, $expirationdate )
+            ) <= 0) {
+                return 1;
+            }
         }
+
     } elsif ($subscription->{numberlength}>0) {
         return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
     }
+
     return 0;
 }
 
@@ -2691,44 +2573,35 @@ num_type can take :
 sub _numeration {
     my ($value, $num_type, $locale) = @_;
     $value ||= 0;
-    my $initlocale = setlocale(LC_TIME);
-    if($locale and $locale ne $initlocale) {
-        $locale = setlocale(LC_TIME, $locale);
-    }
-    $locale ||= $initlocale;
-    my $string;
     $num_type //= '';
-    given ($num_type) {
-        when (/^dayname$/) {
-              $value = $value % 7;
-              $string = POSIX::strftime("%A",0,0,0,0,0,0,$value);
-        }
-        when (/^monthname$/) {
-              $value = $value % 12;
-              $string = POSIX::strftime("%B",0,0,0,1,$value,0,0,0,0);
-        }
-        when (/^season$/) {
-              my $seasonlocale = ($locale)
-                               ? (substr $locale,0,2)
-                               : "en";
-              my %seasons=(
-                 "en" =>
-                    [qw(Spring Summer Fall Winter)],
-                 "fr"=>
-                    [qw(Printemps Été Automne Hiver)],
-              );
-              $value = $value % 4;
-              $string = ($seasons{$seasonlocale})
-                      ? $seasons{$seasonlocale}->[$value]
-                      : $seasons{'en'}->[$value];
-        }
-        default {
-            $string = $value;
-        }
-    }
-    if($locale ne $initlocale) {
-        setlocale(LC_TIME, $initlocale);
+    $locale ||= 'en';
+    my $string;
+    if ( $num_type =~ /^dayname$/ ) {
+        # 1970-11-01 was a Sunday
+        $value = $value % 7;
+        my $dt = DateTime->new(
+            year    => 1970,
+            month   => 11,
+            day     => $value + 1,
+            locale  => $locale,
+        );
+        $string = $dt->strftime("%A");
+    } elsif ( $num_type =~ /^monthname$/ ) {
+        $value = $value % 12;
+        my $dt = DateTime->new(
+            year    => 1970,
+            month   => $value + 1,
+            locale  => $locale,
+        );
+        $string = $dt->strftime("%B");
+    } elsif ( $num_type =~ /^season$/ ) {
+        my @seasons= qw( Spring Summer Fall Winter );
+        $value = $value % 4;
+        $string = $seasons[$value];
+    } else {
+        $string = $value;
     }
+
     return $string;
 }
 
@@ -2759,7 +2632,7 @@ sub CloseSubscription {
     my ( $subscriptionid ) = @_;
     return unless $subscriptionid;
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare( qq{
+    my $sth = $dbh->prepare( q{
         UPDATE subscription
         SET closed = 1
         WHERE subscriptionid = ?
@@ -2767,13 +2640,13 @@ sub CloseSubscription {
     $sth->execute( $subscriptionid );
 
     # Set status = missing when status = stopped
-    $sth = $dbh->prepare( qq{
+    $sth = $dbh->prepare( q{
         UPDATE serial
-        SET status = 8
+        SET status = ?
         WHERE subscriptionid = ?
-        AND status = 1
+        AND status = ?
     } );
-    $sth->execute( $subscriptionid );
+    $sth->execute( STOPPED, $subscriptionid, EXPECTED );
 }
 
 =head2 ReopenSubscription
@@ -2783,7 +2656,7 @@ sub ReopenSubscription {
     my ( $subscriptionid ) = @_;
     return unless $subscriptionid;
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare( qq{
+    my $sth = $dbh->prepare( q{
         UPDATE subscription
         SET closed = 0
         WHERE subscriptionid = ?
@@ -2791,13 +2664,13 @@ sub ReopenSubscription {
     $sth->execute( $subscriptionid );
 
     # Set status = expected when status = stopped
-    $sth = $dbh->prepare( qq{
+    $sth = $dbh->prepare( q{
         UPDATE serial
-        SET status = 1
+        SET status = ?
         WHERE subscriptionid = ?
-        AND status = 8
+        AND status = ?
     } );
-    $sth->execute( $subscriptionid );
+    $sth->execute( EXPECTED, $subscriptionid, STOPPED );
 }
 
 =head2 subscriptionCurrentlyOnOrder