Bug 3316 - Improve last 3 issues displayed on OPAC detail page
[koha.git] / C4 / Serials.pm
1 package C4::Serials;    #assumes C4/Serials.pm
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20
21 use strict;
22 use C4::Dates qw(format_date format_date_in_iso);
23 use Date::Calc qw(:all);
24 use POSIX qw(strftime);
25 use C4::Suggestions;
26 use C4::Koha;
27 use C4::Biblio;
28 use C4::Items;
29 use C4::Search;
30 use C4::Letters;
31 use C4::Log; # logaction
32 use C4::Debug;
33
34 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
35
36 BEGIN {
37         $VERSION = 3.01;        # set version for version checking
38         require Exporter;
39         @ISA    = qw(Exporter);
40         @EXPORT = qw(
41     &NewSubscription    &ModSubscription    &DelSubscription    &GetSubscriptions
42     &GetSubscription    &CountSubscriptionFromBiblionumber      &GetSubscriptionsFromBiblionumber
43     &GetFullSubscriptionsFromBiblionumber   &GetFullSubscription &ModSubscriptionHistory
44     &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
45     
46     &GetNextSeq         &NewIssue           &ItemizeSerials    &GetSerials
47     &GetLatestSerials   &ModSerialStatus    &GetNextDate       &GetSerials2
48     &ReNewSubscription  &GetLateIssues      &GetLateOrMissingIssues
49     &GetSerialInformation                   &AddItem2Serial
50     &PrepareSerialsData &GetNextExpected    &ModNextExpected
51     
52     &UpdateClaimdateIssues
53     &GetSuppliersWithLateIssues             &getsupplierbyserialid
54     &getroutinglist     &delroutingmember   &addroutingmember
55     &reorder_members
56     &check_routing &updateClaim &removeMissingIssue
57     
58     &old_newsubscription &old_modsubscription &old_getserials
59         );
60 }
61
62 =head2 GetSuppliersWithLateIssues
63
64 =head1 NAME
65
66 C4::Serials - Give functions for serializing.
67
68 =head1 SYNOPSIS
69
70   use C4::Serials;
71
72 =head1 DESCRIPTION
73
74 Give all XYZ functions
75
76 =head1 FUNCTIONS
77
78 =over 4
79
80 %supplierlist = &GetSuppliersWithLateIssues
81
82 this function get all suppliers with late issues.
83
84 return :
85 the supplierlist into a hash. this hash containts id & name of the supplier
86
87 =back
88
89 =cut
90
91 sub GetSuppliersWithLateIssues {
92     my $dbh   = C4::Context->dbh;
93     my $query = qq|
94         SELECT DISTINCT id, name
95         FROM            subscription 
96         LEFT JOIN       serial ON serial.subscriptionid=subscription.subscriptionid
97         LEFT JOIN       aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
98         WHERE           subscription.subscriptionid = serial.subscriptionid
99         AND             (planneddate < now() OR serial.STATUS = 3 OR serial.STATUS = 4)
100         ORDER BY name
101     |;
102     my $sth = $dbh->prepare($query);
103     $sth->execute;
104     my %supplierlist;
105     while ( my ( $id, $name ) = $sth->fetchrow ) {
106         $supplierlist{$id} = $name;
107     }
108     return %supplierlist;
109 }
110
111 =head2 GetLateIssues
112
113 =over 4
114
115 @issuelist = &GetLateIssues($supplierid)
116
117 this function select late issues on database
118
119 return :
120 the issuelist into an table. Each line of this table containts a ref to a hash which it containts
121 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
122
123 =back
124
125 =cut
126
127 sub GetLateIssues {
128     my ($supplierid) = @_;
129     my $dbh = C4::Context->dbh;
130     my $sth;
131     if ($supplierid) {
132         my $query = qq|
133             SELECT     name,title,planneddate,serialseq,serial.subscriptionid
134             FROM       subscription
135             LEFT JOIN  serial ON subscription.subscriptionid = serial.subscriptionid
136             LEFT JOIN  biblio ON biblio.biblionumber = subscription.biblionumber
137             LEFT JOIN  aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
138             WHERE      ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
139             AND        subscription.aqbooksellerid=$supplierid
140             ORDER BY   title
141         |;
142         $sth = $dbh->prepare($query);
143     }
144     else {
145         my $query = qq|
146             SELECT     name,title,planneddate,serialseq,serial.subscriptionid
147             FROM       subscription
148             LEFT JOIN  serial ON subscription.subscriptionid = serial.subscriptionid
149             LEFT JOIN  biblio ON biblio.biblionumber = subscription.biblionumber
150             LEFT JOIN  aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
151             WHERE      ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
152             ORDER BY   title
153         |;
154         $sth = $dbh->prepare($query);
155     }
156     $sth->execute;
157     my @issuelist;
158     my $last_title;
159     my $odd   = 0;
160     my $count = 0;
161     while ( my $line = $sth->fetchrow_hashref ) {
162         $odd++ unless $line->{title} eq $last_title;
163         $line->{title} = "" if $line->{title} eq $last_title;
164         $last_title = $line->{title} if ( $line->{title} );
165         $line->{planneddate} = format_date( $line->{planneddate} );
166         $count++;
167         push @issuelist, $line;
168     }
169     return $count, @issuelist;
170 }
171
172 =head2 GetSubscriptionHistoryFromSubscriptionId
173
174 =over 4
175
176 $sth = GetSubscriptionHistoryFromSubscriptionId()
177 this function just prepare the SQL request.
178 After this function, don't forget to execute it by using $sth->execute($subscriptionid)
179 return :
180 $sth = $dbh->prepare($query).
181
182 =back
183
184 =cut
185
186 sub GetSubscriptionHistoryFromSubscriptionId() {
187     my $dbh   = C4::Context->dbh;
188     my $query = qq|
189         SELECT *
190         FROM   subscriptionhistory
191         WHERE  subscriptionid = ?
192     |;
193     return $dbh->prepare($query);
194 }
195
196 =head2 GetSerialStatusFromSerialId
197
198 =over 4
199
200 $sth = GetSerialStatusFromSerialId();
201 this function just prepare the SQL request.
202 After this function, don't forget to execute it by using $sth->execute($serialid)
203 return :
204 $sth = $dbh->prepare($query).
205
206 =back
207
208 =cut
209
210 sub GetSerialStatusFromSerialId() {
211     my $dbh   = C4::Context->dbh;
212     my $query = qq|
213         SELECT status
214         FROM   serial
215         WHERE  serialid = ?
216     |;
217     return $dbh->prepare($query);
218 }
219
220 =head2 GetSerialInformation
221
222 =over 4
223
224 $data = GetSerialInformation($serialid);
225 returns a hash containing :
226   items : items marcrecord (can be an array)
227   serial table field
228   subscription table field
229   + information about subscription expiration
230   
231 =back
232
233 =cut
234
235 sub GetSerialInformation {
236     my ($serialid) = @_;
237     my $dbh        = C4::Context->dbh;
238     my $query      = qq|
239         SELECT serial.*, serial.notes as sernotes, serial.status as serstatus,subscription.*,subscription.subscriptionid as subsid |;
240        if (C4::Context->preference('IndependantBranches') && 
241               C4::Context->userenv && 
242               C4::Context->userenv->{'flags'} != 1 && C4::Context->userenv->{'branch'}){
243                 $query.="
244       , ((subscription.branchcode <>\"".C4::Context->userenv->{'branch'}."\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
245         }
246             $query .= qq|             
247         FROM   serial LEFT JOIN subscription ON subscription.subscriptionid=serial.subscriptionid
248         WHERE  serialid = ?
249     |;
250     my $rq = $dbh->prepare($query);
251     $rq->execute($serialid);
252     my $data = $rq->fetchrow_hashref;
253     # create item information if we have serialsadditems for this subscription
254     if ( $data->{'serialsadditems'} ) {
255         my $queryitem=$dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
256         $queryitem->execute($serialid);
257         my $itemnumbers=$queryitem->fetchall_arrayref([0]);
258         if (scalar(@$itemnumbers)>0){
259             foreach my $itemnum (@$itemnumbers) {
260                 #It is ASSUMED that GetMarcItem ALWAYS WORK...
261                 #Maybe GetMarcItem should return values on failure
262                 $debug and warn "itemnumber :$itemnum->[0], bibnum :".$data->{'biblionumber'};
263                 my $itemprocessed =
264                   PrepareItemrecordDisplay( $data->{'biblionumber'}, $itemnum->[0] , $data );
265                 $itemprocessed->{'itemnumber'}   = $itemnum->[0];
266                 $itemprocessed->{'itemid'}       = $itemnum->[0];
267                 $itemprocessed->{'serialid'}     = $serialid;
268                 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
269                 push @{ $data->{'items'} }, $itemprocessed;
270             }
271         }
272         else {
273             my $itemprocessed =
274               PrepareItemrecordDisplay( $data->{'biblionumber'}, '', $data );
275             $itemprocessed->{'itemid'}       = "N$serialid";
276             $itemprocessed->{'serialid'}     = $serialid;
277             $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
278             $itemprocessed->{'countitems'}   = 0;
279             push @{ $data->{'items'} }, $itemprocessed;
280         }
281     }
282     $data->{ "status" . $data->{'serstatus'} } = 1;
283     $data->{'subscriptionexpired'} =
284       HasSubscriptionExpired( $data->{'subscriptionid'} ) && $data->{'status'}==1;
285     $data->{'abouttoexpire'} =
286       abouttoexpire( $data->{'subscriptionid'} );
287     return $data;
288 }
289
290 =head2 AddItem2Serial
291
292 =over 4
293
294 $data = AddItem2Serial($serialid,$itemnumber);
295 Adds an itemnumber to Serial record
296
297 =back
298
299 =cut
300
301 sub AddItem2Serial {
302     my ( $serialid, $itemnumber ) = @_;
303     my $dbh   = C4::Context->dbh;
304     my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
305     $rq->execute($serialid, $itemnumber);
306     return $rq->rows;
307 }
308
309 =head2 UpdateClaimdateIssues
310
311 =over 4
312
313 UpdateClaimdateIssues($serialids,[$date]);
314
315 Update Claimdate for issues in @$serialids list with date $date 
316 (Take Today if none)
317
318 =back
319
320 =cut
321
322 sub UpdateClaimdateIssues {
323     my ( $serialids, $date ) = @_;
324     my $dbh   = C4::Context->dbh;
325     $date = strftime("%Y-%m-%d",localtime) unless ($date);
326     my $query = "
327         UPDATE serial SET claimdate=$date,status=7
328         WHERE  serialid in ".join (",",@$serialids);
329     ;
330     my $rq = $dbh->prepare($query);
331     $rq->execute;
332     return $rq->rows;
333 }
334
335 =head2 GetSubscription
336
337 =over 4
338
339 $subs = GetSubscription($subscriptionid)
340 this function get the subscription which has $subscriptionid as id.
341 return :
342 a hashref. This hash containts
343 subscription, subscriptionhistory, aqbudget.bookfundid, biblio.title
344
345 =back
346
347 =cut
348
349 sub GetSubscription {
350     my ($subscriptionid) = @_;
351     my $dbh              = C4::Context->dbh;
352     my $query            = qq(
353         SELECT  subscription.*,
354                 subscriptionhistory.*,
355                 subscriptionhistory.enddate as histenddate,
356                 aqbudget.bookfundid,
357                 aqbooksellers.name AS aqbooksellername,
358                 biblio.title AS bibliotitle,
359                 subscription.biblionumber as bibnum);
360        if (C4::Context->preference('IndependantBranches') && 
361               C4::Context->userenv && 
362               C4::Context->userenv->{'flags'} != 1 && C4::Context->userenv->{'branch'}){
363                 $query.="
364       , ((subscription.branchcode <>\"".C4::Context->userenv->{'branch'}."\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
365         }
366             $query .= qq(             
367        FROM subscription
368        LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
369        LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
370        LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
371        LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
372        WHERE subscription.subscriptionid = ?
373     );
374 #     if (C4::Context->preference('IndependantBranches') && 
375 #         C4::Context->userenv && 
376 #         C4::Context->userenv->{'flags'} != 1){
377 # #       $debug and warn "flags: ".C4::Context->userenv->{'flags'};
378 #       $query.=" AND subscription.branchcode IN ('".C4::Context->userenv->{'branch'}."',\"\")";
379 #     }
380         $debug and warn "query : $query\nsubsid :$subscriptionid";
381     my $sth = $dbh->prepare($query);
382     $sth->execute($subscriptionid);
383     return $sth->fetchrow_hashref;
384 }
385
386 =head2 GetFullSubscription
387
388 =over 4
389
390    \@res = GetFullSubscription($subscriptionid)
391    this function read on serial table.
392
393 =back
394
395 =cut
396
397 sub GetFullSubscription {
398     my ($subscriptionid) = @_;
399     my $dbh            = C4::Context->dbh;
400     my $query          = qq|
401   SELECT    serial.serialid,
402             serial.serialseq,
403             serial.planneddate, 
404             serial.publisheddate, 
405             serial.status, 
406             serial.notes as notes,
407             year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
408             aqbudget.bookfundid,aqbooksellers.name as aqbooksellername,
409             biblio.title as bibliotitle,
410             subscription.branchcode AS branchcode,
411             subscription.subscriptionid AS subscriptionid |;
412     if (C4::Context->preference('IndependantBranches') && 
413         C4::Context->userenv && 
414         C4::Context->userenv->{'flags'} != 1 && C4::Context->userenv->{'branch'}){
415       $query.="
416       , ((subscription.branchcode <>\"".C4::Context->userenv->{'branch'}."\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
417     }
418     $query.=qq|
419   FROM      serial 
420   LEFT JOIN subscription ON 
421           (serial.subscriptionid=subscription.subscriptionid )
422   LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid 
423   LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id 
424   LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber 
425   WHERE     serial.subscriptionid = ? 
426   ORDER BY year DESC,
427           IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
428           serial.subscriptionid
429           |;
430         $debug and warn "GetFullSubscription query: $query";   
431     my $sth = $dbh->prepare($query);
432     $sth->execute($subscriptionid);
433     return $sth->fetchall_arrayref({});
434 }
435
436
437 =head2 PrepareSerialsData
438
439 =over 4
440
441    \@res = PrepareSerialsData($serialinfomation)
442    where serialinformation is a hashref array
443
444 =back
445
446 =cut
447
448 sub PrepareSerialsData{
449     my ($lines)=@_;
450     my %tmpresults;
451     my $year;
452     my @res;
453     my $startdate;
454     my $aqbooksellername;
455     my $bibliotitle;
456     my @loopissues;
457     my $first;
458     my $previousnote = "";
459     
460     foreach  my $subs ( @$lines ) {
461         $subs->{'publisheddate'} =
462           ( $subs->{'publisheddate'}
463             ? format_date( $subs->{'publisheddate'} )
464             : "XXX" );
465         $subs->{'planneddate'} = format_date( $subs->{'planneddate'} );
466         $subs->{ "status" . $subs->{'status'} } = 1;
467
468 #         $subs->{'notes'} = $subs->{'notes'} eq $previousnote?"":$subs->{notes};
469         if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
470             $year = $subs->{'year'};
471         }
472         else {
473             $year = "manage";
474         }
475         if ( $tmpresults{$year} ) {
476             push @{ $tmpresults{$year}->{'serials'} }, $subs;
477         }
478         else {
479             $tmpresults{$year} = {
480                 'year' => $year,
481
482                 #               'startdate'=>format_date($subs->{'startdate'}),
483                 'aqbooksellername' => $subs->{'aqbooksellername'},
484                 'bibliotitle'      => $subs->{'bibliotitle'},
485                 'serials'          => [$subs],
486                 'first'            => $first,
487 #                 'branchcode'       => $subs->{'branchcode'},
488 #                 'subscriptionid'   => $subs->{'subscriptionid'},
489             };
490         }
491
492         #         $previousnote=$subs->{notes};
493     }
494     foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
495         push @res, $tmpresults{$key};
496     }
497     $res[0]->{'first'}=1;  
498     return \@res;
499 }
500
501 =head2 GetSubscriptionsFromBiblionumber
502
503 \@res = GetSubscriptionsFromBiblionumber($biblionumber)
504 this function get the subscription list. it reads on subscription table.
505 return :
506 table of subscription which has the biblionumber given on input arg.
507 each line of this table is a hashref. All hashes containt
508 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
509
510 =cut
511
512 sub GetSubscriptionsFromBiblionumber {
513     my ($biblionumber) = @_;
514     my $dbh            = C4::Context->dbh;
515     my $query          = qq(
516         SELECT subscription.*,
517                branches.branchname,
518                subscriptionhistory.*,
519                subscriptionhistory.enddate as histenddate, 
520                aqbudget.bookfundid,
521                aqbooksellers.name AS aqbooksellername,
522                biblio.title AS bibliotitle
523        FROM subscription
524        LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
525        LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
526        LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
527        LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
528        LEFT JOIN branches ON branches.branchcode=subscription.branchcode
529        WHERE subscription.biblionumber = ?
530     );
531 #     if (C4::Context->preference('IndependantBranches') && 
532 #         C4::Context->userenv && 
533 #         C4::Context->userenv->{'flags'} != 1){
534 #        $query.=" AND subscription.branchcode IN ('".C4::Context->userenv->{'branch'}."',\"\")";
535 #     }
536     my $sth = $dbh->prepare($query);
537     $sth->execute($biblionumber);
538     my @res;
539     while ( my $subs = $sth->fetchrow_hashref ) {
540         $subs->{startdate}     = format_date( $subs->{startdate} );
541         $subs->{histstartdate} = format_date( $subs->{histstartdate} );
542         $subs->{histenddate} = format_date( $subs->{histenddate} );
543         $subs->{opacnote}     =~ s/\n/\<br\/\>/g;
544         $subs->{missinglist}  =~ s/\n/\<br\/\>/g;
545         $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
546         $subs->{ "periodicity" . $subs->{periodicity} } = 1;
547         $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
548         $subs->{ "status" . $subs->{'status'} } = 1;
549         $subs->{'cannotedit'}=(C4::Context->preference('IndependantBranches') && 
550                 C4::Context->userenv && 
551                 C4::Context->userenv->{flags} % 2 !=1  && 
552                 C4::Context->userenv->{branch} && $subs->{branchcode} &&
553                 (C4::Context->userenv->{branch} ne $subs->{branchcode}));
554         if ( $subs->{enddate} eq '0000-00-00' ) {
555             $subs->{enddate} = '';
556         }
557         else {
558             $subs->{enddate} = format_date( $subs->{enddate} );
559         }
560         $subs->{'abouttoexpire'}=abouttoexpire($subs->{'subscriptionid'});
561         $subs->{'subscriptionexpired'}=HasSubscriptionExpired($subs->{'subscriptionid'});
562         push @res, $subs;
563     }
564     return \@res;
565 }
566
567 =head2 GetFullSubscriptionsFromBiblionumber
568
569 =over 4
570
571    \@res = GetFullSubscriptionsFromBiblionumber($biblionumber)
572    this function read on serial table.
573
574 =back
575
576 =cut
577
578 sub GetFullSubscriptionsFromBiblionumber {
579     my ($biblionumber) = @_;
580     my $dbh            = C4::Context->dbh;
581     my $query          = qq|
582   SELECT    serial.serialid,
583             serial.serialseq,
584             serial.planneddate, 
585             serial.publisheddate, 
586             serial.status, 
587             serial.notes as notes,
588             year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
589             aqbudget.bookfundid,aqbooksellers.name as aqbooksellername,
590             biblio.title as bibliotitle,
591             subscription.branchcode AS branchcode,
592             subscription.subscriptionid AS subscriptionid|;
593      if (C4::Context->preference('IndependantBranches') && 
594         C4::Context->userenv && 
595         C4::Context->userenv->{'flags'} != 1 && C4::Context->userenv->{'branch'}){
596       $query.="
597       , ((subscription.branchcode <>\"".C4::Context->userenv->{'branch'}."\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
598      }
599       
600      $query.=qq|      
601   FROM      serial 
602   LEFT JOIN subscription ON 
603           (serial.subscriptionid=subscription.subscriptionid)
604   LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid 
605   LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id 
606   LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber 
607   WHERE     subscription.biblionumber = ? 
608   ORDER BY year DESC,
609           IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
610           serial.subscriptionid
611           |;
612     my $sth = $dbh->prepare($query);
613     $sth->execute($biblionumber);
614     return $sth->fetchall_arrayref({});
615 }
616
617 =head2 GetSubscriptions
618
619 =over 4
620
621 @results = GetSubscriptions($title,$ISSN,$biblionumber);
622 this function get all subscriptions which has title like $title,ISSN like $ISSN and biblionumber like $biblionumber.
623 return:
624 a table of hashref. Each hash containt the subscription.
625
626 =back
627
628 =cut
629
630 sub GetSubscriptions {
631     my ( $title, $ISSN, $biblionumber ) = @_;
632     #return unless $title or $ISSN or $biblionumber;
633     my $dbh = C4::Context->dbh;
634     my $sth;
635     if ($biblionumber) {
636         my $query = qq(
637             SELECT subscription.*,biblio.title,biblioitems.issn,biblio.biblionumber
638             FROM   subscription
639             LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
640             LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
641             WHERE biblio.biblionumber=?
642         );
643         $query.=" ORDER BY title";
644         $debug and warn "GetSubscriptions query: $query";
645         $sth = $dbh->prepare($query);
646         $sth->execute($biblionumber);
647     }
648     else {
649         if ( $ISSN and $title ) {
650             my $query = qq|
651                 SELECT subscription.*,biblio.title,biblioitems.issn,biblio.biblionumber        
652                 FROM   subscription
653                 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
654                 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
655                 WHERE (biblioitems.issn = ? or|. join('and ',map{"biblio.title LIKE \"%$_%\""}split (" ",$title))." )";
656             $query.=" ORDER BY title";
657                 $debug and warn "GetSubscriptions query: $query";
658             $sth = $dbh->prepare($query);
659             $sth->execute( $ISSN );
660         }
661         else {
662             if ($ISSN) {
663                 my $query = qq(
664                     SELECT subscription.*,biblio.title,biblioitems.issn,biblio.biblionumber
665                     FROM   subscription
666                     LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
667                     LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
668                     WHERE biblioitems.issn LIKE ?
669                 );
670                 $query.=" ORDER BY title";
671                         $debug and warn "GetSubscriptions query: $query";
672                 $sth = $dbh->prepare($query);
673                 $sth->execute( "%" . $ISSN . "%" );
674             }
675             else {
676                 my $query = qq(
677                     SELECT subscription.*,biblio.title,biblioitems.issn,biblio.biblionumber
678                     FROM   subscription
679                     LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
680                     LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
681                     WHERE 1
682                     ).($title?" and ":""). join('and ',map{"biblio.title LIKE \"%$_%\""} split (" ",$title) );
683                 
684                 $query.=" ORDER BY title";
685                         $debug and warn "GetSubscriptions query: $query";
686                 $sth = $dbh->prepare($query);
687                 $sth->execute;
688             }
689         }
690     }
691     my @results;
692     my $previoustitle = "";
693     my $odd           = 1;
694     while ( my $line = $sth->fetchrow_hashref ) {
695         if ( $previoustitle eq $line->{title} ) {
696             $line->{title}  = "";
697             $line->{issn}   = "";
698         }
699         else {
700             $previoustitle = $line->{title};
701             $odd           = -$odd;
702         }
703         $line->{toggle} = 1 if $odd == 1;
704         $line->{'cannotedit'}=(C4::Context->preference('IndependantBranches') && 
705                 C4::Context->userenv && 
706                 C4::Context->userenv->{flags} % 2 !=1  && 
707                 C4::Context->userenv->{branch} && $line->{branchcode} &&
708                 (C4::Context->userenv->{branch} ne $line->{branchcode}));
709         push @results, $line;
710     }
711     return @results;
712 }
713
714 =head2 GetSerials
715
716 =over 4
717
718 ($totalissues,@serials) = GetSerials($subscriptionid);
719 this function get every serial not arrived for a given subscription
720 as well as the number of issues registered in the database (all types)
721 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
722
723 FIXME: We should return \@serials.
724
725 =back
726
727 =cut
728
729 sub GetSerials {
730     my ($subscriptionid,$count) = @_;
731     my $dbh = C4::Context->dbh;
732
733     # status = 2 is "arrived"
734     my $counter = 0;
735     $count=5 unless ($count);
736     my @serials;
737     my $query =
738       "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
739                         FROM   serial
740                         WHERE  subscriptionid = ? AND status NOT IN (2,4,5) 
741                         ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
742     my $sth = $dbh->prepare($query);
743     $sth->execute($subscriptionid);
744     while ( my $line = $sth->fetchrow_hashref ) {
745         $line->{ "status" . $line->{status} } =
746           1;    # fills a "statusX" value, used for template status select list
747         $line->{"publisheddate"} = format_date( $line->{"publisheddate"} );
748         $line->{"planneddate"}   = format_date( $line->{"planneddate"} );
749         push @serials, $line;
750     }
751     # OK, now add the last 5 issues arrives/missing
752     $query =
753       "SELECT   serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
754        FROM     serial
755        WHERE    subscriptionid = ?
756        AND      (status in (2,4,5))
757        ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
758       ";
759     $sth = $dbh->prepare($query);
760     $sth->execute($subscriptionid);
761     while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
762         $counter++;
763         $line->{ "status" . $line->{status} } =
764           1;    # fills a "statusX" value, used for template status select list
765         $line->{"planneddate"}   = format_date( $line->{"planneddate"} );
766         $line->{"publisheddate"} = format_date( $line->{"publisheddate"} );
767         push @serials, $line;
768     }
769
770     $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
771     $sth = $dbh->prepare($query);
772     $sth->execute($subscriptionid);
773     my ($totalissues) = $sth->fetchrow;
774     return ( $totalissues, @serials );
775 }
776
777 =head2 GetSerials2
778
779 =over 4
780
781 ($totalissues,@serials) = GetSerials2($subscriptionid,$status);
782 this function get every serial waited for a given subscription
783 as well as the number of issues registered in the database (all types)
784 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
785
786 =back
787
788 =cut
789 sub GetSerials2 {
790     my ($subscription,$status) = @_;
791     my $dbh = C4::Context->dbh;
792     my $query = qq|
793                  SELECT   serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
794                  FROM     serial 
795                  WHERE    subscriptionid=$subscription AND status IN ($status)
796                  ORDER BY publisheddate,serialid DESC
797                     |;
798         $debug and warn "GetSerials2 query: $query";
799     my $sth=$dbh->prepare($query);
800     $sth->execute;
801     my @serials;
802     while(my $line = $sth->fetchrow_hashref) {
803         $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
804         $line->{"planneddate"} = format_date($line->{"planneddate"});
805         $line->{"publisheddate"} = format_date($line->{"publisheddate"});
806         push @serials,$line;
807     }
808     my ($totalissues) = scalar(@serials);
809     return ($totalissues,@serials);
810 }
811
812 =head2 GetLatestSerials
813
814 =over 4
815
816 \@serials = GetLatestSerials($subscriptionid,$limit)
817 get the $limit's latest serials arrived or missing for a given subscription
818 return :
819 a ref to a table which it containts all of the latest serials stored into a hash.
820
821 =back
822
823 =cut
824
825 sub GetLatestSerials {
826     my ( $subscriptionid, $limit ) = @_;
827     my $dbh = C4::Context->dbh;
828
829     # status = 2 is "arrived"
830     my $strsth = "SELECT   serialid,serialseq, status, planneddate, notes
831                         FROM     serial
832                         WHERE    subscriptionid = ?
833                         AND      (status =2 or status=4)
834                         ORDER BY publisheddate DESC LIMIT 0,$limit
835                 ";
836     my $sth = $dbh->prepare($strsth);
837     $sth->execute($subscriptionid);
838     my @serials;
839     while ( my $line = $sth->fetchrow_hashref ) {
840         $line->{ "status" . $line->{status} } =
841           1;    # fills a "statusX" value, used for template status select list
842         $line->{"planneddate"} = format_date( $line->{"planneddate"} );
843         push @serials, $line;
844     }
845
846     #     my $query = qq|
847     #         SELECT count(*)
848     #         FROM   serial
849     #         WHERE  subscriptionid=?
850     #     |;
851     #     $sth=$dbh->prepare($query);
852     #     $sth->execute($subscriptionid);
853     #     my ($totalissues) = $sth->fetchrow;
854     return \@serials;
855 }
856
857 =head2 GetNextSeq
858
859 =over 4
860
861 GetNextSeq($val)
862 $val is a hashref containing all the attributes of the table 'subscription'
863 This function get the next issue for the subscription given on input arg
864 return:
865 all the input params updated.
866
867 =back
868
869 =cut
870
871 # sub GetNextSeq {
872 #     my ($val) =@_;
873 #     my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
874 #     $calculated = $val->{numberingmethod};
875 # # calculate the (expected) value of the next issue recieved.
876 #     $newlastvalue1 = $val->{lastvalue1};
877 # # check if we have to increase the new value.
878 #     $newinnerloop1 = $val->{innerloop1}+1;
879 #     $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
880 #     $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
881 #     $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
882 #     $calculated =~ s/\{X\}/$newlastvalue1/g;
883 #
884 #     $newlastvalue2 = $val->{lastvalue2};
885 # # check if we have to increase the new value.
886 #     $newinnerloop2 = $val->{innerloop2}+1;
887 #     $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
888 #     $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
889 #     $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
890 #     $calculated =~ s/\{Y\}/$newlastvalue2/g;
891 #
892 #     $newlastvalue3 = $val->{lastvalue3};
893 # # check if we have to increase the new value.
894 #     $newinnerloop3 = $val->{innerloop3}+1;
895 #     $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
896 #     $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
897 #     $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
898 #     $calculated =~ s/\{Z\}/$newlastvalue3/g;
899 #     return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
900 # }
901
902 sub GetNextSeq {
903     my ($val) = @_;
904     my (
905         $calculated,    $newlastvalue1, $newlastvalue2, $newlastvalue3,
906         $newinnerloop1, $newinnerloop2, $newinnerloop3
907     );
908     my $pattern = $val->{numberpattern};
909     my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
910     my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
911     $calculated    = $val->{numberingmethod};
912     $newlastvalue1 = $val->{lastvalue1};
913     $newlastvalue2 = $val->{lastvalue2};
914     $newlastvalue3 = $val->{lastvalue3};
915   $newlastvalue1 = $val->{lastvalue1};
916   # check if we have to increase the new value.
917   $newinnerloop1 = $val->{innerloop1} + 1;
918   $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
919   $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
920   $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
921   $calculated =~ s/\{X\}/$newlastvalue1/g;
922   
923   $newlastvalue2 = $val->{lastvalue2};
924   # check if we have to increase the new value.
925   $newinnerloop2 = $val->{innerloop2} + 1;
926   $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
927   $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
928   $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
929   if ( $pattern == 6 ) {
930     if ( $val->{hemisphere} == 2 ) {
931        my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
932        $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
933     }
934     else {
935        my $newlastvalue2seq = $seasons[$newlastvalue2];
936        $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
937     }
938   }
939   else {
940     $calculated =~ s/\{Y\}/$newlastvalue2/g;
941   }
942   
943   
944   $newlastvalue3 = $val->{lastvalue3};
945   # check if we have to increase the new value.
946   $newinnerloop3 = $val->{innerloop3} + 1;
947   $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
948   $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
949   $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
950   $calculated =~ s/\{Z\}/$newlastvalue3/g;
951     
952   return ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3 ,
953            $newinnerloop1, $newinnerloop2, $newinnerloop3);
954 }
955
956 =head2 GetSeq
957
958 =over 4
959
960 $calculated = GetSeq($val)
961 $val is a hashref containing all the attributes of the table 'subscription'
962 this function transforms {X},{Y},{Z} to 150,0,0 for example.
963 return:
964 the sequence in integer format
965
966 =back
967
968 =cut
969
970 sub GetSeq {
971     my ($val)      = @_;
972     my $pattern = $val->{numberpattern};
973     my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
974     my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
975     my $calculated = $val->{numberingmethod};
976     my $x          = $val->{'lastvalue1'};
977     $calculated =~ s/\{X\}/$x/g;
978     my $newlastvalue2 = $val->{'lastvalue2'};
979     if ( $pattern == 6 ) {
980         if ( $val->{hemisphere} == 2 ) {
981             my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
982             $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
983         }
984         else {
985             my $newlastvalue2seq = $seasons[$newlastvalue2];
986             $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
987         }
988     }
989     else {
990         $calculated =~ s/\{Y\}/$newlastvalue2/g;
991     }
992     my $z = $val->{'lastvalue3'};
993     $calculated =~ s/\{Z\}/$z/g;
994     return $calculated;
995 }
996
997 =head2 GetExpirationDate
998
999 $sensddate = GetExpirationDate($subscriptionid)
1000
1001 this function return the expiration date for a subscription given on input args.
1002
1003 return
1004 the enddate
1005
1006 =cut
1007
1008 sub GetExpirationDate {
1009     my ($subscriptionid) = @_;
1010     my $dbh              = C4::Context->dbh;
1011     my $subscription     = GetSubscription($subscriptionid);
1012     my $enddate          = $subscription->{startdate};
1013
1014 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
1015     if (($subscription->{periodicity} % 16) >0){
1016       if ( $subscription->{numberlength} ) {
1017           #calculate the date of the last issue.
1018           my $length = $subscription->{numberlength};
1019           for ( my $i = 1 ; $i <= $length ; $i++ ) {
1020               $enddate = GetNextDate( $enddate, $subscription );
1021           }
1022       }
1023       elsif ( $subscription->{monthlength} ){
1024           my @date=split (/-/,$subscription->{startdate});
1025           my @enddate = Add_Delta_YM($date[0],$date[1],$date[2],0,$subscription->{monthlength});
1026           $enddate=sprintf("%04d-%02d-%02d",$enddate[0],$enddate[1],$enddate[2]);
1027       } elsif ( $subscription->{weeklength} ){
1028           my @date=split (/-/,$subscription->{startdate});
1029           my @enddate = Add_Delta_Days($date[0],$date[1],$date[2],$subscription->{weeklength}*7);
1030           $enddate=sprintf("%04d-%02d-%02d",$enddate[0],$enddate[1],$enddate[2]);
1031       }
1032       return $enddate;
1033     } else {
1034       return 0;  
1035     }  
1036 }
1037
1038 =head2 CountSubscriptionFromBiblionumber
1039
1040 =over 4
1041
1042 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1043 this count the number of subscription for a biblionumber given.
1044 return :
1045 the number of subscriptions with biblionumber given on input arg.
1046
1047 =back
1048
1049 =cut
1050
1051 sub CountSubscriptionFromBiblionumber {
1052     my ($biblionumber) = @_;
1053     my $dbh = C4::Context->dbh;
1054     my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1055     my $sth   = $dbh->prepare($query);
1056     $sth->execute($biblionumber);
1057     my $subscriptionsnumber = $sth->fetchrow;
1058     return $subscriptionsnumber;
1059 }
1060
1061 =head2 ModSubscriptionHistory
1062
1063 =over 4
1064
1065 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1066
1067 this function modify the history of a subscription. Put your new values on input arg.
1068
1069 =back
1070
1071 =cut
1072
1073 sub ModSubscriptionHistory {
1074     my (
1075         $subscriptionid, $histstartdate, $enddate, $recievedlist,
1076         $missinglist,    $opacnote,      $librariannote
1077     ) = @_;
1078     my $dbh   = C4::Context->dbh;
1079     my $query = "UPDATE subscriptionhistory 
1080                     SET histstartdate=?,enddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1081                     WHERE subscriptionid=?
1082                 ";
1083     my $sth = $dbh->prepare($query);
1084     $recievedlist =~ s/^; //;
1085     $missinglist  =~ s/^; //;
1086     $opacnote     =~ s/^; //;
1087     $sth->execute(
1088         $histstartdate, $enddate,       $recievedlist, $missinglist,
1089         $opacnote,      $librariannote, $subscriptionid
1090     );
1091     return $sth->rows;
1092 }
1093
1094 =head2 ModSerialStatus
1095
1096 =over 4
1097
1098 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
1099
1100 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1101 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1102
1103 =back
1104
1105 =cut
1106
1107 sub ModSerialStatus {
1108     my ( $serialid, $serialseq,  $planneddate,$publisheddate, $status, $notes )
1109       = @_;
1110
1111     #It is a usual serial
1112     # 1st, get previous status :
1113     my $dbh   = C4::Context->dbh;
1114     my $query = "SELECT subscriptionid,status FROM serial WHERE  serialid=?";
1115     my $sth   = $dbh->prepare($query);
1116     $sth->execute($serialid);
1117     my ( $subscriptionid, $oldstatus ) = $sth->fetchrow;
1118
1119     # change status & update subscriptionhistory
1120     my $val;
1121     if ( $status eq 6 ) {
1122         DelIssue( {'serialid'=>$serialid, 'subscriptionid'=>$subscriptionid,'serialseq'=>$serialseq} );
1123     }
1124     else {
1125         my $query =
1126 "UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE  serialid = ?";
1127         $sth = $dbh->prepare($query);
1128         $sth->execute( $serialseq, $publisheddate, $planneddate, $status,
1129             $notes, $serialid );
1130         $query = "SELECT * FROM   subscription WHERE  subscriptionid = ?";
1131         $sth = $dbh->prepare($query);
1132         $sth->execute($subscriptionid);
1133         my $val = $sth->fetchrow_hashref;
1134         unless ( $val->{manualhistory} ) {
1135             $query =
1136 "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE  subscriptionid=?";
1137             $sth = $dbh->prepare($query);
1138             $sth->execute($subscriptionid);
1139             my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1140             if ( $status eq 2 ) {
1141
1142                 $recievedlist .= "; $serialseq"
1143                   unless ( index( "$recievedlist", "$serialseq" ) >= 0 );
1144             }
1145
1146 #         warn "missinglist : $missinglist serialseq :$serialseq, ".index("$missinglist","$serialseq");
1147             $missinglist .= "; $serialseq"
1148               if ( $status eq 4
1149                 and not index( "$missinglist", "$serialseq" ) >= 0 );
1150             $missinglist .= "; not issued $serialseq"
1151               if ( $status eq 5
1152                 and index( "$missinglist", "$serialseq" ) >= 0 );
1153             $query =
1154 "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE  subscriptionid=?";
1155             $sth = $dbh->prepare($query);
1156             $recievedlist =~ s/^; //;
1157             $missinglist  =~ s/^; //;
1158             $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1159         }
1160     }
1161
1162     # create new waited entry if needed (ie : was a "waited" and has changed)
1163     if ( $oldstatus eq 1 && $status ne 1 ) {
1164         my $query = "SELECT * FROM   subscription WHERE  subscriptionid = ?";
1165         $sth = $dbh->prepare($query);
1166         $sth->execute($subscriptionid);
1167         my $val = $sth->fetchrow_hashref;
1168
1169         # next issue number
1170 #     warn "Next Seq";    
1171         my (
1172             $newserialseq,  $newlastvalue1, $newlastvalue2, $newlastvalue3,
1173             $newinnerloop1, $newinnerloop2, $newinnerloop3
1174         ) = GetNextSeq($val);
1175 #     warn "Next Seq End";    
1176
1177         # next date (calculated from actual date & frequency parameters)
1178 #         warn "publisheddate :$publisheddate ";
1179         my $nextpublisheddate = GetNextDate( $publisheddate, $val );
1180         NewIssue( $newserialseq, $subscriptionid, $val->{'biblionumber'},
1181             1, $nextpublisheddate, $nextpublisheddate );
1182         $query =
1183 "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1184                     WHERE  subscriptionid = ?";
1185         $sth = $dbh->prepare($query);
1186         $sth->execute(
1187             $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1,
1188             $newinnerloop2, $newinnerloop3, $subscriptionid
1189         );
1190
1191 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1192         if ( $val->{letter} && $status eq 2 && $oldstatus ne 2 ) {
1193             SendAlerts( 'issue', $val->{subscriptionid}, $val->{letter} );
1194         }
1195     }
1196 }
1197
1198 =head2 GetNextExpected
1199
1200 =over 4
1201
1202 $nextexpected = GetNextExpected($subscriptionid)
1203
1204 Get the planneddate for the current expected issue of the subscription.
1205
1206 returns a hashref:
1207
1208 $nextexepected = {
1209     serialid => int
1210     planneddate => C4::Dates object
1211     }
1212
1213 =back
1214
1215 =cut
1216
1217 sub GetNextExpected($) {
1218     my ($subscriptionid) = @_;
1219     my $dbh = C4::Context->dbh;
1220     my $sth = $dbh->prepare('SELECT serialid, planneddate FROM serial WHERE subscriptionid=? AND status=?');
1221     # Each subscription has only one 'expected' issue, with serial.status==1.
1222     $sth->execute( $subscriptionid, 1 );
1223     my ( $nextissue ) = $sth->fetchrow_hashref;
1224     if(not $nextissue){
1225          $sth = $dbh->prepare('SELECT serialid,planneddate FROM serial WHERE subscriptionid  = ? ORDER BY planneddate DESC LIMIT 1');
1226          $sth->execute( $subscriptionid );  
1227          $nextissue = $sth->fetchrow_hashref;       
1228     }
1229     $nextissue->{planneddate} = C4::Dates->new($nextissue->{planneddate},'iso');
1230     return $nextissue;
1231     
1232 }
1233 =head2 ModNextExpected
1234
1235 =over 4
1236
1237 ModNextExpected($subscriptionid,$date)
1238
1239 Update the planneddate for the current expected issue of the subscription.
1240 This will modify all future prediction results.  
1241
1242 C<$date> is a C4::Dates object.
1243
1244 =back
1245
1246 =cut
1247
1248 sub ModNextExpected($$) {
1249     my ($subscriptionid,$date) = @_;
1250     my $dbh = C4::Context->dbh;
1251     #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1252     my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1253     # Each subscription has only one 'expected' issue, with serial.status==1.
1254     $sth->execute( $date->output('iso'),$date->output('iso'), $subscriptionid, 1);
1255     return 0;
1256
1257 }
1258
1259 =head2 ModSubscription
1260
1261 =over 4
1262
1263 this function modify a subscription. Put all new values on input args.
1264
1265 =back
1266
1267 =cut
1268
1269 sub ModSubscription {
1270     my (
1271         $auser,           $branchcode,   $aqbooksellerid, $cost,
1272         $aqbudgetid,      $startdate,    $periodicity,    $firstacquidate,
1273         $dow,             $irregularity, $numberpattern,  $numberlength,
1274         $weeklength,      $monthlength,  $add1,           $every1,
1275         $whenmorethan1,   $setto1,       $lastvalue1,     $innerloop1,
1276         $add2,            $every2,       $whenmorethan2,  $setto2,
1277         $lastvalue2,      $innerloop2,   $add3,           $every3,
1278         $whenmorethan3,   $setto3,       $lastvalue3,     $innerloop3,
1279         $numberingmethod, $status,       $biblionumber,   $callnumber,
1280         $notes,           $letter,       $hemisphere,     $manualhistory,
1281         $internalnotes,   $serialsadditems,$subscriptionid,
1282         $staffdisplaycount,$opacdisplaycount, $graceperiod, $location
1283     ) = @_;
1284 #     warn $irregularity;
1285     my $dbh   = C4::Context->dbh;
1286     my $query = "UPDATE subscription
1287                     SET librarian=?, branchcode=?,aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
1288                         periodicity=?,firstacquidate=?,dow=?,irregularity=?, numberpattern=?, numberlength=?,weeklength=?,monthlength=?,
1289                         add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
1290                         add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
1291                         add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
1292                         numberingmethod=?, status=?, biblionumber=?, callnumber=?, notes=?, letter=?, hemisphere=?,manualhistory=?,internalnotes=?,serialsadditems=?,staffdisplaycount = ?,opacdisplaycount = ?, graceperiod = ?, location = ?
1293                     WHERE subscriptionid = ?";
1294      #warn "query :".$query;
1295     my $sth = $dbh->prepare($query);
1296     $sth->execute(
1297         $auser,           $branchcode,   $aqbooksellerid, $cost,
1298         $aqbudgetid,      $startdate,    $periodicity,    $firstacquidate,
1299         $dow,             "$irregularity", $numberpattern,  $numberlength,
1300         $weeklength,      $monthlength,  $add1,           $every1,
1301         $whenmorethan1,   $setto1,       $lastvalue1,     $innerloop1,
1302         $add2,            $every2,       $whenmorethan2,  $setto2,
1303         $lastvalue2,      $innerloop2,   $add3,           $every3,
1304         $whenmorethan3,   $setto3,       $lastvalue3,     $innerloop3,
1305         $numberingmethod, $status,       $biblionumber,   $callnumber,
1306         $notes,           $letter,       $hemisphere,     ($manualhistory?$manualhistory:0),
1307         $internalnotes,   $serialsadditems,
1308         $staffdisplaycount, $opacdisplaycount, $graceperiod, $location,
1309         $subscriptionid
1310     );
1311     my $rows=$sth->rows;
1312     $sth->finish;
1313     
1314     logaction("SERIAL", "MODIFY", $subscriptionid, "") if C4::Context->preference("SubscriptionLog");
1315     return $rows;
1316 }
1317
1318 =head2 NewSubscription
1319
1320 =over 4
1321
1322 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1323     $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
1324     $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
1325     $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
1326     $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
1327     $numberingmethod, $status, $notes, $serialsadditems,
1328     $staffdisplaycount, $opacdisplaycount, $graceperiod, $location);
1329
1330 Create a new subscription with value given on input args.
1331
1332 return :
1333 the id of this new subscription
1334
1335 =back
1336
1337 =cut
1338
1339 sub NewSubscription {
1340     my (
1341         $auser,         $branchcode,   $aqbooksellerid,  $cost,
1342         $aqbudgetid,    $biblionumber, $startdate,       $periodicity,
1343         $dow,           $numberlength, $weeklength,      $monthlength,
1344         $add1,          $every1,       $whenmorethan1,   $setto1,
1345         $lastvalue1,    $innerloop1,   $add2,            $every2,
1346         $whenmorethan2, $setto2,       $lastvalue2,      $innerloop2,
1347         $add3,          $every3,       $whenmorethan3,   $setto3,
1348         $lastvalue3,    $innerloop3,   $numberingmethod, $status,
1349         $notes,         $letter,       $firstacquidate,  $irregularity,
1350         $numberpattern, $callnumber,   $hemisphere,      $manualhistory,
1351         $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1352         $graceperiod, $location
1353     ) = @_;
1354     my $dbh = C4::Context->dbh;
1355
1356     #save subscription (insert into database)
1357     my $query = qq|
1358         INSERT INTO subscription
1359             (librarian,branchcode,aqbooksellerid,cost,aqbudgetid,biblionumber,
1360             startdate,periodicity,dow,numberlength,weeklength,monthlength,
1361             add1,every1,whenmorethan1,setto1,lastvalue1,innerloop1,
1362             add2,every2,whenmorethan2,setto2,lastvalue2,innerloop2,
1363             add3,every3,whenmorethan3,setto3,lastvalue3,innerloop3,
1364             numberingmethod, status, notes, letter,firstacquidate,irregularity,
1365             numberpattern, callnumber, hemisphere,manualhistory,internalnotes,serialsadditems,
1366             staffdisplaycount,opacdisplaycount,graceperiod,location)
1367         VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
1368         |;
1369     my $sth = $dbh->prepare($query);
1370     $sth->execute(
1371         $auser,                         $branchcode,
1372         $aqbooksellerid,                $cost,
1373         $aqbudgetid,                    $biblionumber,
1374         format_date_in_iso($startdate), $periodicity,
1375         $dow,                           $numberlength,
1376         $weeklength,                    $monthlength,
1377         $add1,                          $every1,
1378         $whenmorethan1,                 $setto1,
1379         $lastvalue1,                    $innerloop1,
1380         $add2,                          $every2,
1381         $whenmorethan2,                 $setto2,
1382         $lastvalue2,                    $innerloop2,
1383         $add3,                          $every3,
1384         $whenmorethan3,                 $setto3,
1385         $lastvalue3,                    $innerloop3,
1386         $numberingmethod,               "$status",
1387         $notes,                         $letter,
1388         format_date_in_iso($firstacquidate),                $irregularity,
1389         $numberpattern,                 $callnumber,
1390         $hemisphere,                    $manualhistory,
1391         $internalnotes,                 $serialsadditems,
1392                 $staffdisplaycount,                             $opacdisplaycount,
1393         $graceperiod,                   $location,
1394     );
1395
1396     #then create the 1st waited number
1397     my $subscriptionid = $dbh->{'mysql_insertid'};
1398     $query             = qq(
1399         INSERT INTO subscriptionhistory
1400             (biblionumber, subscriptionid, histstartdate,  opacnote, librariannote)
1401         VALUES (?,?,?,?,?)
1402         );
1403     $sth = $dbh->prepare($query);
1404     $sth->execute( $biblionumber, $subscriptionid,
1405         format_date_in_iso($startdate),
1406         $notes,$internalnotes );
1407
1408    # reread subscription to get a hash (for calculation of the 1st issue number)
1409     $query = qq(
1410         SELECT *
1411         FROM   subscription
1412         WHERE  subscriptionid = ?
1413     );
1414     $sth = $dbh->prepare($query);
1415     $sth->execute($subscriptionid);
1416     my $val = $sth->fetchrow_hashref;
1417
1418     # calculate issue number
1419     my $serialseq = GetSeq($val);
1420     $query     = qq|
1421         INSERT INTO serial
1422             (serialseq,subscriptionid,biblionumber,status, planneddate, publisheddate)
1423         VALUES (?,?,?,?,?,?)
1424     |;
1425     $sth = $dbh->prepare($query);
1426     $sth->execute(
1427         "$serialseq", $subscriptionid, $biblionumber, 1,
1428         format_date_in_iso($firstacquidate),
1429         format_date_in_iso($firstacquidate)
1430     );
1431     
1432     logaction("SERIAL", "ADD", $subscriptionid, "") if C4::Context->preference("SubscriptionLog");
1433     
1434 #set serial flag on biblio if not already set.
1435     my ($null, ($bib)) = GetBiblio($biblionumber);
1436     if( ! $bib->{'serial'} ) {
1437         my $record = GetMarcBiblio($biblionumber);
1438         my ($tag,$subf) = GetMarcFromKohaField('biblio.serial',$bib->{'frameworkcode'});
1439         if($tag) {
1440             eval {
1441             $record->field($tag)->update( $subf => 1 );
1442             };
1443         }
1444         ModBiblio($record,$biblionumber,$bib->{'frameworkcode'});
1445     }    
1446     return $subscriptionid;
1447 }
1448
1449 =head2 ReNewSubscription
1450
1451 =over 4
1452
1453 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1454
1455 this function renew a subscription with values given on input args.
1456
1457 =back
1458
1459 =cut
1460
1461 sub ReNewSubscription {
1462     my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength,
1463         $monthlength, $note )
1464       = @_;
1465     my $dbh          = C4::Context->dbh;
1466     my $subscription = GetSubscription($subscriptionid);
1467      my $query        = qq|
1468          SELECT *
1469          FROM   biblio 
1470          LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
1471          WHERE    biblio.biblionumber=?
1472      |;
1473      my $sth = $dbh->prepare($query);
1474      $sth->execute( $subscription->{biblionumber} );
1475      my $biblio = $sth->fetchrow_hashref;
1476      if (C4::Context->preference("RenewSerialAddsSuggestion")){
1477         NewSuggestion(
1478             $user,             $subscription->{bibliotitle},
1479             $biblio->{author}, $biblio->{publishercode},
1480             $biblio->{note},   '',
1481             '',                '',
1482             '',                '',
1483             $subscription->{biblionumber}
1484         );
1485     }
1486
1487     # renew subscription
1488     $query = qq|
1489         UPDATE subscription
1490         SET    startdate=?,numberlength=?,weeklength=?,monthlength=?
1491         WHERE  subscriptionid=?
1492     |;
1493     $sth = $dbh->prepare($query);
1494     $sth->execute( format_date_in_iso($startdate),
1495         $numberlength, $weeklength, $monthlength, $subscriptionid );
1496         
1497     logaction("SERIAL", "RENEW", $subscriptionid, "") if C4::Context->preference("SubscriptionLog");
1498 }
1499
1500 =head2 NewIssue
1501
1502 =over 4
1503
1504 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate,  $notes)
1505
1506 Create a new issue stored on the database.
1507 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1508
1509 =back
1510
1511 =cut
1512
1513 sub NewIssue {
1514     my ( $serialseq, $subscriptionid, $biblionumber, $status, 
1515         $planneddate, $publisheddate, $notes )
1516       = @_;
1517     ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1518     
1519     my $dbh   = C4::Context->dbh;
1520     my $query = qq|
1521         INSERT INTO serial
1522             (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,notes)
1523         VALUES (?,?,?,?,?,?,?)
1524     |;
1525     my $sth = $dbh->prepare($query);
1526     $sth->execute( $serialseq, $subscriptionid, $biblionumber, $status,
1527         $publisheddate, $planneddate,$notes );
1528     my $serialid=$dbh->{'mysql_insertid'};
1529     $query = qq|
1530         SELECT missinglist,recievedlist
1531         FROM   subscriptionhistory
1532         WHERE  subscriptionid=?
1533     |;
1534     $sth = $dbh->prepare($query);
1535     $sth->execute($subscriptionid);
1536     my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1537
1538     if ( $status eq 2 ) {
1539       ### TODO Add a feature that improves recognition and description.
1540       ### As such count (serialseq) i.e. : N18,2(N19),N20
1541       ### Would use substr and index But be careful to previous presence of ()
1542         $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
1543     }
1544     if ( $status eq 4 ) {
1545         $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
1546     }
1547     $query = qq|
1548         UPDATE subscriptionhistory
1549         SET    recievedlist=?, missinglist=?
1550         WHERE  subscriptionid=?
1551     |;
1552     $sth = $dbh->prepare($query);
1553     $recievedlist =~ s/^; //;
1554     $missinglist  =~ s/^; //;
1555     $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1556     return $serialid;
1557 }
1558
1559 =head2 ItemizeSerials
1560
1561 =over 4
1562
1563 ItemizeSerials($serialid, $info);
1564 $info is a hashref containing  barcode branch, itemcallnumber, status, location
1565 $serialid the serialid
1566 return :
1567 1 if the itemize is a succes.
1568 0 and @error else. @error containts the list of errors found.
1569
1570 =back
1571
1572 =cut
1573
1574 sub ItemizeSerials {
1575     my ( $serialid, $info ) = @_;
1576     my $now = POSIX::strftime( "%Y-%m-%d",localtime );
1577
1578     my $dbh   = C4::Context->dbh;
1579     my $query = qq|
1580         SELECT *
1581         FROM   serial
1582         WHERE  serialid=?
1583     |;
1584     my $sth = $dbh->prepare($query);
1585     $sth->execute($serialid);
1586     my $data = $sth->fetchrow_hashref;
1587     if ( C4::Context->preference("RoutingSerials") ) {
1588
1589         # check for existing biblioitem relating to serial issue
1590         my ( $count, @results ) =
1591           GetBiblioItemByBiblioNumber( $data->{'biblionumber'} );
1592         my $bibitemno = 0;
1593         for ( my $i = 0 ; $i < $count ; $i++ ) {
1594             if (  $results[$i]->{'volumeddesc'} eq $data->{'serialseq'} . ' ('
1595                 . $data->{'planneddate'}
1596                 . ')' )
1597             {
1598                 $bibitemno = $results[$i]->{'biblioitemnumber'};
1599                 last;
1600             }
1601         }
1602         if ( $bibitemno == 0 ) {
1603
1604     # warn "need to add new biblioitem so copy last one and make minor changes";
1605             my $sth =
1606               $dbh->prepare(
1607 "SELECT * FROM biblioitems WHERE biblionumber = ? ORDER BY biblioitemnumber DESC"
1608               );
1609             $sth->execute( $data->{'biblionumber'} );
1610             my $biblioitem = $sth->fetchrow_hashref;
1611             $biblioitem->{'volumedate'} =
1612               format_date_in_iso( $data->{planneddate} );
1613             $biblioitem->{'volumeddesc'} =
1614               $data->{serialseq} . ' ('
1615               . format_date( $data->{'planneddate'} ) . ')';
1616             $biblioitem->{'dewey'} = $info->{itemcallnumber};
1617
1618             #FIXME  HDL : I don't understand why you need to call newbiblioitem, as the biblioitem should already be somewhere.
1619             # so I comment it, we can speak of it when you want
1620             # newbiblioitems has been removed from Biblio.pm, as it has a deprecated API now
1621 #             if ( $info->{barcode} )
1622 #             {    # only make biblioitem if we are going to make item also
1623 #                 $bibitemno = newbiblioitem($biblioitem);
1624 #             }
1625         }
1626     }
1627
1628     my $fwk = GetFrameworkCode( $data->{'biblionumber'} );
1629     if ( $info->{barcode} ) {
1630         my @errors;
1631         my $exists = itemdata( $info->{'barcode'} );
1632         push @errors, "barcode_not_unique" if ($exists);
1633         unless ($exists) {
1634             my $marcrecord = MARC::Record->new();
1635             my ( $tag, $subfield ) =
1636               GetMarcFromKohaField( "items.barcode", $fwk );
1637             my $newField =
1638               MARC::Field->new( "$tag", '', '',
1639                 "$subfield" => $info->{barcode} );
1640             $marcrecord->insert_fields_ordered($newField);
1641             if ( $info->{branch} ) {
1642                 my ( $tag, $subfield ) =
1643                   GetMarcFromKohaField( "items.homebranch",
1644                     $fwk );
1645
1646                 #warn "items.homebranch : $tag , $subfield";
1647                 if ( $marcrecord->field($tag) ) {
1648                     $marcrecord->field($tag)
1649                       ->add_subfields( "$subfield" => $info->{branch} );
1650                 }
1651                 else {
1652                     my $newField =
1653                       MARC::Field->new( "$tag", '', '',
1654                         "$subfield" => $info->{branch} );
1655                     $marcrecord->insert_fields_ordered($newField);
1656                 }
1657                 ( $tag, $subfield ) =
1658                   GetMarcFromKohaField( "items.holdingbranch",
1659                     $fwk );
1660
1661                 #warn "items.holdingbranch : $tag , $subfield";
1662                 if ( $marcrecord->field($tag) ) {
1663                     $marcrecord->field($tag)
1664                       ->add_subfields( "$subfield" => $info->{branch} );
1665                 }
1666                 else {
1667                     my $newField =
1668                       MARC::Field->new( "$tag", '', '',
1669                         "$subfield" => $info->{branch} );
1670                     $marcrecord->insert_fields_ordered($newField);
1671                 }
1672             }
1673             if ( $info->{itemcallnumber} ) {
1674                 my ( $tag, $subfield ) =
1675                   GetMarcFromKohaField( "items.itemcallnumber",
1676                     $fwk );
1677
1678                 #warn "items.itemcallnumber : $tag , $subfield";
1679                 if ( $marcrecord->field($tag) ) {
1680                     $marcrecord->field($tag)
1681                       ->add_subfields( "$subfield" => $info->{itemcallnumber} );
1682                 }
1683                 else {
1684                     my $newField =
1685                       MARC::Field->new( "$tag", '', '',
1686                         "$subfield" => $info->{itemcallnumber} );
1687                     $marcrecord->insert_fields_ordered($newField);
1688                 }
1689             }
1690             if ( $info->{notes} ) {
1691                 my ( $tag, $subfield ) =
1692                   GetMarcFromKohaField( "items.itemnotes", $fwk );
1693
1694                 # warn "items.itemnotes : $tag , $subfield";
1695                 if ( $marcrecord->field($tag) ) {
1696                     $marcrecord->field($tag)
1697                       ->add_subfields( "$subfield" => $info->{notes} );
1698                 }
1699                 else {
1700                     my $newField =
1701                       MARC::Field->new( "$tag", '', '',
1702                         "$subfield" => $info->{notes} );
1703                     $marcrecord->insert_fields_ordered($newField);
1704                 }
1705             }
1706             if ( $info->{location} ) {
1707                 my ( $tag, $subfield ) =
1708                   GetMarcFromKohaField( "items.location", $fwk );
1709
1710                 # warn "items.location : $tag , $subfield";
1711                 if ( $marcrecord->field($tag) ) {
1712                     $marcrecord->field($tag)
1713                       ->add_subfields( "$subfield" => $info->{location} );
1714                 }
1715                 else {
1716                     my $newField =
1717                       MARC::Field->new( "$tag", '', '',
1718                         "$subfield" => $info->{location} );
1719                     $marcrecord->insert_fields_ordered($newField);
1720                 }
1721             }
1722             if ( $info->{status} ) {
1723                 my ( $tag, $subfield ) =
1724                   GetMarcFromKohaField( "items.notforloan",
1725                     $fwk );
1726
1727                 # warn "items.notforloan : $tag , $subfield";
1728                 if ( $marcrecord->field($tag) ) {
1729                     $marcrecord->field($tag)
1730                       ->add_subfields( "$subfield" => $info->{status} );
1731                 }
1732                 else {
1733                     my $newField =
1734                       MARC::Field->new( "$tag", '', '',
1735                         "$subfield" => $info->{status} );
1736                     $marcrecord->insert_fields_ordered($newField);
1737                 }
1738             }
1739             if ( C4::Context->preference("RoutingSerials") ) {
1740                 my ( $tag, $subfield ) =
1741                   GetMarcFromKohaField( "items.dateaccessioned",
1742                     $fwk );
1743                 if ( $marcrecord->field($tag) ) {
1744                     $marcrecord->field($tag)
1745                       ->add_subfields( "$subfield" => $now );
1746                 }
1747                 else {
1748                     my $newField =
1749                       MARC::Field->new( "$tag", '', '', "$subfield" => $now );
1750                     $marcrecord->insert_fields_ordered($newField);
1751                 }
1752             }
1753             AddItemFromMarc( $marcrecord, $data->{'biblionumber'} );
1754             return 1;
1755         }
1756         return ( 0, @errors );
1757     }
1758 }
1759
1760 =head2 HasSubscriptionExpired
1761
1762 =over 4
1763
1764 $has_expired = HasSubscriptionExpired($subscriptionid)
1765
1766 the subscription has expired when the next issue to arrive is out of subscription limit.
1767
1768 return :
1769 0 if the subscription has not expired
1770 1 if the subscription has expired
1771 2 if has subscription does not have a valid expiration date set
1772
1773 =back
1774
1775 =cut
1776
1777 sub HasSubscriptionExpired {
1778     my ($subscriptionid) = @_;
1779     my $dbh              = C4::Context->dbh;
1780     my $subscription     = GetSubscription($subscriptionid);
1781     if (($subscription->{periodicity} % 16)>0){
1782       my $expirationdate   = GetExpirationDate($subscriptionid);
1783       my $query = qq|
1784             SELECT max(planneddate)
1785             FROM   serial
1786             WHERE  subscriptionid=?
1787       |;
1788       my $sth = $dbh->prepare($query);
1789       $sth->execute($subscriptionid);
1790       my ($res) = $sth->fetchrow  ;
1791           return 0 unless $res;
1792       my @res=split (/-/,$res);
1793       my @endofsubscriptiondate=split(/-/,$expirationdate);
1794       return 2 if (scalar(@res)!=3 || scalar(@endofsubscriptiondate)!=3||not check_date(@res) || not check_date(@endofsubscriptiondate));
1795       return 1 if ( (@endofsubscriptiondate && Delta_Days($res[0],$res[1],$res[2],
1796                   $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) <= 0)
1797                   || (!$res));
1798       return 0;
1799     } else {
1800       if ($subscription->{'numberlength'}){
1801         my $countreceived=countissuesfrom($subscriptionid,$subscription->{'startdate'});
1802         return 1 if ($countreceived >$subscription->{'numberlength'});
1803               return 0;
1804       } else {
1805               return 0;
1806       }
1807     }
1808     return 0;   # Notice that you'll never get here.
1809 }
1810
1811 =head2 DelSubscription
1812
1813 =over 4
1814
1815 DelSubscription($subscriptionid)
1816 this function delete the subscription which has $subscriptionid as id.
1817
1818 =back
1819
1820 =cut
1821
1822 sub DelSubscription {
1823     my ($subscriptionid) = @_;
1824     my $dbh = C4::Context->dbh;
1825     $subscriptionid = $dbh->quote($subscriptionid);
1826     $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
1827     $dbh->do(
1828         "DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
1829     $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
1830     
1831     logaction("SERIAL", "DELETE", $subscriptionid, "") if C4::Context->preference("SubscriptionLog");
1832 }
1833
1834 =head2 DelIssue
1835
1836 =over 4
1837
1838 DelIssue($serialseq,$subscriptionid)
1839 this function delete an issue which has $serialseq and $subscriptionid given on input arg.
1840
1841 =back
1842
1843 =cut
1844
1845 sub DelIssue {
1846     my ( $dataissue) = @_;
1847     my $dbh   = C4::Context->dbh;
1848     ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1849     
1850     my $query = qq|
1851         DELETE FROM serial
1852         WHERE       serialid= ?
1853         AND         subscriptionid= ?
1854     |;
1855     my $mainsth = $dbh->prepare($query);
1856     $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'});
1857
1858     #Delete element from subscription history
1859     $query = "SELECT * FROM   subscription WHERE  subscriptionid = ?";
1860     my $sth   = $dbh->prepare($query);
1861     $sth->execute($dataissue->{'subscriptionid'});
1862     my $val = $sth->fetchrow_hashref;
1863     unless ( $val->{manualhistory} ) {
1864         my $query = qq|
1865           SELECT * FROM subscriptionhistory
1866           WHERE       subscriptionid= ?
1867       |;
1868         my $sth = $dbh->prepare($query);
1869         $sth->execute($dataissue->{'subscriptionid'});
1870         my $data = $sth->fetchrow_hashref;
1871         my $serialseq= $dataissue->{'serialseq'};
1872         $data->{'missinglist'}  =~ s/\b$serialseq\b//;
1873         $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1874         my $strsth = "UPDATE subscriptionhistory SET "
1875           . join( ",",
1876             map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data )
1877           . " WHERE subscriptionid=?";
1878         $sth = $dbh->prepare($strsth);
1879         $sth->execute($dataissue->{'subscriptionid'});
1880     }
1881     
1882     return $mainsth->rows;
1883 }
1884
1885 =head2 GetLateOrMissingIssues
1886
1887 =over 4
1888
1889 ($count,@issuelist) = &GetLateMissingIssues($supplierid,$serialid)
1890
1891 this function select missing issues on database - where serial.status = 4 or serial.status=3 or planneddate<now
1892
1893 return :
1894 a count of the number of missing issues
1895 the issuelist into a table. Each line of this table containts a ref to a hash which it containts
1896 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1897
1898 =back
1899
1900 =cut
1901
1902 sub GetLateOrMissingIssues {
1903     my ( $supplierid, $serialid,$order ) = @_;
1904     my $dbh = C4::Context->dbh;
1905     my $sth;
1906     my $byserial = '';
1907     if ($serialid) {
1908         $byserial = "and serialid = " . $serialid;
1909     }
1910     if ($order){
1911       $order.=", title";
1912     } else {
1913       $order="title";
1914     }
1915     if ($supplierid) {
1916         $sth = $dbh->prepare(
1917 "SELECT
1918    serialid,
1919    aqbooksellerid,
1920    name,
1921    biblio.title,
1922    planneddate,
1923    serialseq,
1924    serial.status,
1925    serial.subscriptionid,
1926    claimdate
1927 FROM      serial 
1928 LEFT JOIN subscription  ON serial.subscriptionid=subscription.subscriptionid 
1929 LEFT JOIN biblio        ON subscription.biblionumber=biblio.biblionumber
1930 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1931 WHERE subscription.subscriptionid = serial.subscriptionid 
1932 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3))
1933 AND subscription.aqbooksellerid=$supplierid
1934 $byserial
1935 ORDER BY $order"
1936         );
1937     }
1938     else {
1939         $sth = $dbh->prepare(
1940 "SELECT 
1941    serialid,
1942    aqbooksellerid,
1943    name,
1944    biblio.title,
1945    planneddate,
1946    serialseq,
1947    serial.status,
1948    serial.subscriptionid,
1949    claimdate
1950 FROM serial 
1951 LEFT JOIN subscription 
1952 ON serial.subscriptionid=subscription.subscriptionid 
1953 LEFT JOIN biblio 
1954 ON subscription.biblionumber=biblio.biblionumber
1955 LEFT JOIN aqbooksellers 
1956 ON subscription.aqbooksellerid = aqbooksellers.id
1957 WHERE 
1958    subscription.subscriptionid = serial.subscriptionid 
1959 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3))
1960 $byserial
1961 ORDER BY $order"
1962         );
1963     }
1964     $sth->execute;
1965     my @issuelist;
1966     my $last_title;
1967     my $odd   = 0;
1968     my $count = 0;
1969     while ( my $line = $sth->fetchrow_hashref ) {
1970         $odd++ unless $line->{title} eq $last_title;
1971         $last_title = $line->{title} if ( $line->{title} );
1972         $line->{planneddate} = format_date( $line->{planneddate} );
1973         $line->{claimdate}   = format_date( $line->{claimdate} );
1974         $line->{"status".$line->{status}}   = 1;
1975         $line->{'odd'} = 1 if $odd % 2;
1976         $count++;
1977         push @issuelist, $line;
1978     }
1979     return $count, @issuelist;
1980 }
1981
1982 =head2 removeMissingIssue
1983
1984 =over 4
1985
1986 removeMissingIssue($subscriptionid)
1987
1988 this function removes an issue from being part of the missing string in 
1989 subscriptionlist.missinglist column
1990
1991 called when a missing issue is found from the serials-recieve.pl file
1992
1993 =back
1994
1995 =cut
1996
1997 sub removeMissingIssue {
1998     my ( $sequence, $subscriptionid ) = @_;
1999     my $dbh = C4::Context->dbh;
2000     my $sth =
2001       $dbh->prepare(
2002         "SELECT * FROM subscriptionhistory WHERE subscriptionid = ?");
2003     $sth->execute($subscriptionid);
2004     my $data              = $sth->fetchrow_hashref;
2005     my $missinglist       = $data->{'missinglist'};
2006     my $missinglistbefore = $missinglist;
2007
2008     # warn $missinglist." before";
2009     $missinglist =~ s/($sequence)//;
2010
2011     # warn $missinglist." after";
2012     if ( $missinglist ne $missinglistbefore ) {
2013         $missinglist =~ s/\|\s\|/\|/g;
2014         $missinglist =~ s/^\| //g;
2015         $missinglist =~ s/\|$//g;
2016         my $sth2 = $dbh->prepare(
2017             "UPDATE subscriptionhistory
2018                                        SET missinglist = ?
2019                                        WHERE subscriptionid = ?"
2020         );
2021         $sth2->execute( $missinglist, $subscriptionid );
2022     }
2023 }
2024
2025 =head2 updateClaim
2026
2027 =over 4
2028
2029 &updateClaim($serialid)
2030
2031 this function updates the time when a claim is issued for late/missing items
2032
2033 called from claims.pl file
2034
2035 =back
2036
2037 =cut
2038
2039 sub updateClaim {
2040     my ($serialid) = @_;
2041     my $dbh        = C4::Context->dbh;
2042     my $sth        = $dbh->prepare(
2043         "UPDATE serial SET claimdate = now()
2044                                    WHERE serialid = ?
2045                                    "
2046     );
2047     $sth->execute($serialid);
2048 }
2049
2050 =head2 getsupplierbyserialid
2051
2052 =over 4
2053
2054 ($result) = &getsupplierbyserialid($serialid)
2055
2056 this function is used to find the supplier id given a serial id
2057
2058 return :
2059 hashref containing serialid, subscriptionid, and aqbooksellerid
2060
2061 =back
2062
2063 =cut
2064
2065 sub getsupplierbyserialid {
2066     my ($serialid) = @_;
2067     my $dbh        = C4::Context->dbh;
2068     my $sth        = $dbh->prepare(
2069         "SELECT serialid, serial.subscriptionid, aqbooksellerid
2070          FROM serial 
2071          LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
2072          WHERE serialid = ?
2073                                    "
2074     );
2075     $sth->execute($serialid);
2076     my $line   = $sth->fetchrow_hashref;
2077     my $result = $line->{'aqbooksellerid'};
2078     return $result;
2079 }
2080
2081 =head2 check_routing
2082
2083 =over 4
2084
2085 ($result) = &check_routing($subscriptionid)
2086
2087 this function checks to see if a serial has a routing list and returns the count of routingid
2088 used to show either an 'add' or 'edit' link
2089
2090 =back
2091
2092 =cut
2093
2094 sub check_routing {
2095     my ($subscriptionid) = @_;
2096     my $dbh              = C4::Context->dbh;
2097     my $sth              = $dbh->prepare(
2098 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist 
2099                               ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2100                               WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
2101                               "
2102     );
2103     $sth->execute($subscriptionid);
2104     my $line   = $sth->fetchrow_hashref;
2105     my $result = $line->{'routingids'};
2106     return $result;
2107 }
2108
2109 =head2 addroutingmember
2110
2111 =over 4
2112
2113 &addroutingmember($borrowernumber,$subscriptionid)
2114
2115 this function takes a borrowernumber and subscriptionid and add the member to the
2116 routing list for that serial subscription and gives them a rank on the list
2117 of either 1 or highest current rank + 1
2118
2119 =back
2120
2121 =cut
2122
2123 sub addroutingmember {
2124     my ( $borrowernumber, $subscriptionid ) = @_;
2125     my $rank;
2126     my $dbh = C4::Context->dbh;
2127     my $sth =
2128       $dbh->prepare(
2129 "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?"
2130       );
2131     $sth->execute($subscriptionid);
2132     while ( my $line = $sth->fetchrow_hashref ) {
2133         if ( $line->{'rank'} > 0 ) {
2134             $rank = $line->{'rank'} + 1;
2135         }
2136         else {
2137             $rank = 1;
2138         }
2139     }
2140     $sth =
2141       $dbh->prepare(
2142 "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)"
2143       );
2144     $sth->execute( $subscriptionid, $borrowernumber, $rank );
2145 }
2146
2147 =head2 reorder_members
2148
2149 =over 4
2150
2151 &reorder_members($subscriptionid,$routingid,$rank)
2152
2153 this function is used to reorder the routing list
2154
2155 it takes the routingid of the member one wants to re-rank and the rank it is to move to
2156 - it gets all members on list puts their routingid's into an array
2157 - removes the one in the array that is $routingid
2158 - then reinjects $routingid at point indicated by $rank
2159 - then update the database with the routingids in the new order
2160
2161 =back
2162
2163 =cut
2164
2165 sub reorder_members {
2166     my ( $subscriptionid, $routingid, $rank ) = @_;
2167     my $dbh = C4::Context->dbh;
2168     my $sth =
2169       $dbh->prepare(
2170 "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC"
2171       );
2172     $sth->execute($subscriptionid);
2173     my @result;
2174     while ( my $line = $sth->fetchrow_hashref ) {
2175         push( @result, $line->{'routingid'} );
2176     }
2177
2178     # To find the matching index
2179     my $i;
2180     my $key = -1;    # to allow for 0 being a valid response
2181     for ( $i = 0 ; $i < @result ; $i++ ) {
2182         if ( $routingid == $result[$i] ) {
2183             $key = $i;    # save the index
2184             last;
2185         }
2186     }
2187
2188     # if index exists in array then move it to new position
2189     if ( $key > -1 && $rank > 0 ) {
2190         my $new_rank = $rank -
2191           1;    # $new_rank is what you want the new index to be in the array
2192         my $moving_item = splice( @result, $key, 1 );
2193         splice( @result, $new_rank, 0, $moving_item );
2194     }
2195     for ( my $j = 0 ; $j < @result ; $j++ ) {
2196         my $sth =
2197           $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '"
2198               . ( $j + 1 )
2199               . "' WHERE routingid = '"
2200               . $result[$j]
2201               . "'" );
2202         $sth->execute;
2203     }
2204 }
2205
2206 =head2 delroutingmember
2207
2208 =over 4
2209
2210 &delroutingmember($routingid,$subscriptionid)
2211
2212 this function either deletes one member from routing list if $routingid exists otherwise
2213 deletes all members from the routing list
2214
2215 =back
2216
2217 =cut
2218
2219 sub delroutingmember {
2220
2221 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2222     my ( $routingid, $subscriptionid ) = @_;
2223     my $dbh = C4::Context->dbh;
2224     if ($routingid) {
2225         my $sth =
2226           $dbh->prepare(
2227             "DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2228         $sth->execute($routingid);
2229         reorder_members( $subscriptionid, $routingid );
2230     }
2231     else {
2232         my $sth =
2233           $dbh->prepare(
2234             "DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2235         $sth->execute($subscriptionid);
2236     }
2237 }
2238
2239 =head2 getroutinglist
2240
2241 =over 4
2242
2243 ($count,@routinglist) = &getroutinglist($subscriptionid)
2244
2245 this gets the info from the subscriptionroutinglist for $subscriptionid
2246
2247 return :
2248 a count of the number of members on routinglist
2249 the routinglist into a table. Each line of this table containts a ref to a hash which containts
2250 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2251
2252 =back
2253
2254 =cut
2255
2256 sub getroutinglist {
2257     my ($subscriptionid) = @_;
2258     my $dbh              = C4::Context->dbh;
2259     my $sth              = $dbh->prepare(
2260         "SELECT routingid, borrowernumber,
2261                               ranking, biblionumber 
2262          FROM subscription 
2263          LEFT JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2264          WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
2265                               "
2266     );
2267     $sth->execute($subscriptionid);
2268     my @routinglist;
2269     my $count = 0;
2270     while ( my $line = $sth->fetchrow_hashref ) {
2271         $count++;
2272         push( @routinglist, $line );
2273     }
2274     return ( $count, @routinglist );
2275 }
2276
2277 =head2 countissuesfrom
2278
2279 =over 4
2280
2281 $result = &countissuesfrom($subscriptionid,$startdate)
2282
2283
2284 =back
2285
2286 =cut
2287
2288 sub countissuesfrom {
2289     my ($subscriptionid,$startdate) = @_;
2290     my $dbh              = C4::Context->dbh;
2291     my $query = qq|
2292             SELECT count(*)
2293             FROM   serial
2294             WHERE  subscriptionid=?
2295             AND serial.publisheddate>?
2296         |;
2297     my $sth=$dbh->prepare($query);
2298     $sth->execute($subscriptionid, $startdate);
2299     my ($countreceived)=$sth->fetchrow;
2300     return $countreceived;  
2301 }
2302
2303 =head2 abouttoexpire
2304
2305 =over 4
2306
2307 $result = &abouttoexpire($subscriptionid)
2308
2309 this function alerts you to the penultimate issue for a serial subscription
2310
2311 returns 1 - if this is the penultimate issue
2312 returns 0 - if not
2313
2314 =back
2315
2316 =cut
2317
2318 sub abouttoexpire {
2319     my ($subscriptionid) = @_;
2320     my $dbh              = C4::Context->dbh;
2321     my $subscription     = GetSubscription($subscriptionid);
2322     my $per = $subscription->{'periodicity'};
2323     if ($per % 16>0){
2324       my $expirationdate   = GetExpirationDate($subscriptionid);
2325       my $sth =
2326         $dbh->prepare(
2327           "select max(planneddate) from serial where subscriptionid=?");
2328       $sth->execute($subscriptionid);
2329       my ($res) = $sth->fetchrow ;
2330 #        warn "date expiration : ".$expirationdate." date courante ".$res;
2331       my @res=split (/-/,$res);
2332       @res=Date::Calc::Today if ($res[0]*$res[1]==0);
2333       my @endofsubscriptiondate=split(/-/,$expirationdate);
2334       my $x;
2335       if ( $per == 1 ) {$x=7;}
2336       if ( $per == 2 ) {$x=7; }
2337       if ( $per == 3 ) {$x=14;}
2338       if ( $per == 4 ) { $x = 21; }
2339       if ( $per == 5 ) { $x = 31; }
2340       if ( $per == 6 ) { $x = 62; }
2341       if ( $per == 7 || $per == 8 ) { $x = 93; }
2342       if ( $per == 9 )  { $x = 190; }
2343       if ( $per == 10 ) { $x = 365; }
2344       if ( $per == 11 ) { $x = 730; }
2345       my @datebeforeend=Add_Delta_Days(  $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2],
2346                     - (3 * $x)) if (@endofsubscriptiondate && $endofsubscriptiondate[0]*$endofsubscriptiondate[1]*$endofsubscriptiondate[2]);
2347               # warn "DATE BEFORE END: $datebeforeend";
2348       return 1 if ( @res && 
2349                     (@datebeforeend && 
2350                         Delta_Days($res[0],$res[1],$res[2],
2351                         $datebeforeend[0],$datebeforeend[1],$datebeforeend[2]) <= 0) && 
2352                     (@endofsubscriptiondate && 
2353                         Delta_Days($res[0],$res[1],$res[2],
2354                         $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) >= 0) );
2355     return 0;
2356    } elsif ($subscription->{numberlength}>0) {
2357     return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
2358    } else {return 0}
2359 }
2360
2361 =head2 old_newsubscription
2362
2363 =over 4
2364
2365 ($subscriptionid) = &old_newsubscription($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
2366                         $startdate,$periodicity,$firstacquidate,$dow,$irregularity,$numberpattern,$numberlength,$weeklength,$monthlength,
2367                         $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
2368                         $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
2369                         $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
2370                         $numberingmethod, $status, $callnumber, $notes, $hemisphere)
2371
2372 this function is similar to the NewSubscription subroutine but has a few different
2373 values passed in 
2374 $firstacquidate - date of first serial issue to arrive
2375 $irregularity - the issues not expected separated by a '|'
2376 - eg. monthly issue but not expecting issue for june and july would have $irregularity of '6|7'
2377 $numberpattern - the number for an array of labels to reconstruct the javascript correctly in the 
2378    subscription-add.tmpl file
2379 $callnumber - display the callnumber of the serial
2380 $hemisphere - either 2 = southern hemisphere or 1 = northern hemisphere - used for quarterly serials
2381
2382 return :
2383 the $subscriptionid number of the new subscription
2384
2385 =back
2386
2387 =cut
2388
2389 sub old_newsubscription {
2390     my (
2391         $auser,         $aqbooksellerid,  $cost,          $aqbudgetid,
2392         $biblionumber,  $startdate,       $periodicity,   $firstacquidate,
2393         $dow,           $irregularity,    $numberpattern, $numberlength,
2394         $weeklength,    $monthlength,     $add1,          $every1,
2395         $whenmorethan1, $setto1,          $lastvalue1,    $add2,
2396         $every2,        $whenmorethan2,   $setto2,        $lastvalue2,
2397         $add3,          $every3,          $whenmorethan3, $setto3,
2398         $lastvalue3,    $numberingmethod, $status,        $callnumber,
2399         $notes,         $hemisphere
2400     ) = @_;
2401     my $dbh = C4::Context->dbh;
2402
2403     #save subscription
2404     my $sth = $dbh->prepare(
2405 "insert into subscription (librarian,aqbooksellerid,cost,aqbudgetid,biblionumber,
2406                                                         startdate,periodicity,firstacquidate,dow,irregularity,numberpattern,numberlength,weeklength,monthlength,
2407                                                                 add1,every1,whenmorethan1,setto1,lastvalue1,
2408                                                                 add2,every2,whenmorethan2,setto2,lastvalue2,
2409                                                                 add3,every3,whenmorethan3,setto3,lastvalue3,
2410                                                                 numberingmethod, status, callnumber, notes, hemisphere) values
2411                                                           (?,?,?,?,?,?,?,?,?,?,?,
2412                                                                                            ?,?,?,?,?,?,?,?,?,?,?,
2413                                                                                            ?,?,?,?,?,?,?,?,?,?,?,?)"
2414     );
2415     $sth->execute(
2416         $auser,         $aqbooksellerid,
2417         $cost,          $aqbudgetid,
2418         $biblionumber,  format_date_in_iso($startdate),
2419         $periodicity,   format_date_in_iso($firstacquidate),
2420         $dow,           $irregularity,
2421         $numberpattern, $numberlength,
2422         $weeklength,    $monthlength,
2423         $add1,          $every1,
2424         $whenmorethan1, $setto1,
2425         $lastvalue1,    $add2,
2426         $every2,        $whenmorethan2,
2427         $setto2,        $lastvalue2,
2428         $add3,          $every3,
2429         $whenmorethan3, $setto3,
2430         $lastvalue3,    $numberingmethod,
2431         $status,        $callnumber,
2432         $notes,         $hemisphere
2433     );
2434
2435     #then create the 1st waited number
2436     my $subscriptionid = $dbh->{'mysql_insertid'};
2437     my $enddate        = GetExpirationDate($subscriptionid);
2438
2439     $sth =
2440       $dbh->prepare(
2441 "insert into subscriptionhistory (biblionumber, subscriptionid, histstartdate, enddate, missinglist, recievedlist, opacnote, librariannote) values (?,?,?,?,?,?,?,?)"
2442       );
2443     $sth->execute(
2444         $biblionumber, $subscriptionid,
2445         format_date_in_iso($startdate),
2446         format_date_in_iso($enddate),
2447         "", "", "", $notes
2448     );
2449
2450    # reread subscription to get a hash (for calculation of the 1st issue number)
2451     $sth =
2452       $dbh->prepare("select * from subscription where subscriptionid = ? ");
2453     $sth->execute($subscriptionid);
2454     my $val = $sth->fetchrow_hashref;
2455
2456     # calculate issue number
2457     my $serialseq = GetSeq($val);
2458     $sth =
2459       $dbh->prepare(
2460 "insert into serial (serialseq,subscriptionid,biblionumber,status, planneddate) values (?,?,?,?,?)"
2461       );
2462     $sth->execute( $serialseq, $subscriptionid, $val->{'biblionumber'},
2463         1, format_date_in_iso($startdate) );
2464     return $subscriptionid;
2465 }
2466
2467 =head2 old_modsubscription
2468
2469 =over 4
2470
2471 ($subscriptionid) = &old_modsubscription($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
2472                         $startdate,$periodicity,$firstacquidate,$dow,$irregularity,$numberpattern,$numberlength,$weeklength,$monthlength,
2473                         $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
2474                         $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
2475                         $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
2476                         $numberingmethod, $status, $callnumber, $notes, $hemisphere, $subscriptionid)
2477
2478 this function is similar to the ModSubscription subroutine but has a few different
2479 values passed in 
2480 $firstacquidate - date of first serial issue to arrive
2481 $irregularity - the issues not expected separated by a '|'
2482 - eg. monthly issue but not expecting issue for june and july would have $irregularity of '6|7'
2483 $numberpattern - the number for an array of labels to reconstruct the javascript correctly in the 
2484    subscription-add.tmpl file
2485 $callnumber - display the callnumber of the serial
2486 $hemisphere - either 2 = southern hemisphere or 1 = northern hemisphere - used for quarterly serials
2487
2488 =back
2489
2490 =cut
2491
2492 sub old_modsubscription {
2493     my (
2494         $auser,        $aqbooksellerid, $cost,           $aqbudgetid,
2495         $startdate,    $periodicity,    $firstacquidate, $dow,
2496         $irregularity, $numberpattern,  $numberlength,   $weeklength,
2497         $monthlength,  $add1,           $every1,         $whenmorethan1,
2498         $setto1,       $lastvalue1,     $innerloop1,     $add2,
2499         $every2,       $whenmorethan2,  $setto2,         $lastvalue2,
2500         $innerloop2,   $add3,           $every3,         $whenmorethan3,
2501         $setto3,       $lastvalue3,     $innerloop3,     $numberingmethod,
2502         $status,       $biblionumber,   $callnumber,     $notes,
2503         $hemisphere,   $subscriptionid
2504     ) = @_;
2505     my $dbh = C4::Context->dbh;
2506     my $sth = $dbh->prepare(
2507 "update subscription set librarian=?, aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
2508                                                    periodicity=?,firstacquidate=?,dow=?,irregularity=?,numberpattern=?,numberlength=?,weeklength=?,monthlength=?,
2509                                                   add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
2510                                                   add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
2511                                                   add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
2512                                                   numberingmethod=?, status=?, biblionumber=?, callnumber=?, notes=?, hemisphere=? where subscriptionid = ?"
2513     );
2514     $sth->execute(
2515         $auser,        $aqbooksellerid, $cost,           $aqbudgetid,
2516         $startdate,    $periodicity,    $firstacquidate, $dow,
2517         $irregularity, $numberpattern,  $numberlength,   $weeklength,
2518         $monthlength,  $add1,           $every1,         $whenmorethan1,
2519         $setto1,       $lastvalue1,     $innerloop1,     $add2,
2520         $every2,       $whenmorethan2,  $setto2,         $lastvalue2,
2521         $innerloop2,   $add3,           $every3,         $whenmorethan3,
2522         $setto3,       $lastvalue3,     $innerloop3,     $numberingmethod,
2523         $status,       $biblionumber,   $callnumber,     $notes,
2524         $hemisphere,   $subscriptionid
2525     );
2526     $sth->finish;
2527
2528     $sth =
2529       $dbh->prepare("select * from subscription where subscriptionid = ? ");
2530     $sth->execute($subscriptionid);
2531     my $val = $sth->fetchrow_hashref;
2532
2533     # calculate issue number
2534     my $serialseq = Get_Seq($val);
2535     $sth =
2536       $dbh->prepare("UPDATE serial SET serialseq = ? WHERE subscriptionid = ?");
2537     $sth->execute( $serialseq, $subscriptionid );
2538
2539     my $enddate = subscriptionexpirationdate($subscriptionid);
2540     $sth = $dbh->prepare("update subscriptionhistory set enddate=?");
2541     $sth->execute( format_date_in_iso($enddate) );
2542 }
2543
2544 =head2 old_getserials
2545
2546 =over 4
2547
2548 ($totalissues,@serials) = &old_getserials($subscriptionid)
2549
2550 this function get a hashref of serials and the total count of them
2551
2552 return :
2553 $totalissues - number of serial lines
2554 the serials into a table. Each line of this table containts a ref to a hash which it containts
2555 serialid, serialseq, status,planneddate,notes,routingnotes  from tables : serial where status is not 2, 4, or 5
2556
2557 =back
2558
2559 =cut
2560
2561 sub old_getserials {
2562     my ($subscriptionid) = @_;
2563     my $dbh = C4::Context->dbh;
2564
2565     # status = 2 is "arrived"
2566     my $sth =
2567       $dbh->prepare(
2568 "select serialid,serialseq, status, planneddate,notes,routingnotes from serial where subscriptionid = ? and status <>2 and status <>4 and status <>5"
2569       );
2570     $sth->execute($subscriptionid);
2571     my @serials;
2572     my $num = 1;
2573     while ( my $line = $sth->fetchrow_hashref ) {
2574         $line->{ "status" . $line->{status} } =
2575           1;    # fills a "statusX" value, used for template status select list
2576         $line->{"planneddate"} = format_date( $line->{"planneddate"} );
2577         $line->{"num"}         = $num;
2578         $num++;
2579         push @serials, $line;
2580     }
2581     $sth = $dbh->prepare("select count(*) from serial where subscriptionid=?");
2582     $sth->execute($subscriptionid);
2583     my ($totalissues) = $sth->fetchrow;
2584     return ( $totalissues, @serials );
2585 }
2586
2587 =head2 GetNextDate
2588
2589 ($resultdate) = &GetNextDate($planneddate,$subscription)
2590
2591 this function is an extension of GetNextDate which allows for checking for irregularity
2592
2593 it takes the planneddate and will return the next issue's date and will skip dates if there
2594 exists an irregularity
2595 - eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be 
2596 skipped then the returned date will be 2007-05-10
2597
2598 return :
2599 $resultdate - then next date in the sequence
2600
2601 Return 0 if periodicity==0
2602
2603 =cut
2604 sub in_array { # used in next sub down
2605   my ($val,@elements) = @_;
2606   foreach my $elem(@elements) {
2607     if($val == $elem) {
2608             return 1;
2609     }
2610   }
2611   return 0;
2612 }
2613
2614 sub GetNextDate(@) {
2615     my ( $planneddate, $subscription ) = @_;
2616     my @irreg = split( /\,/, $subscription->{irregularity} );
2617
2618     #date supposed to be in ISO.
2619     
2620     my ( $year, $month, $day ) = split(/-/, $planneddate);
2621     $month=1 unless ($month);
2622     $day=1 unless ($day);
2623     my @resultdate;
2624
2625     #       warn "DOW $dayofweek";
2626     if ( $subscription->{periodicity} % 16 == 0 ) {  # 'without regularity' || 'irregular'
2627       return 0;
2628     }  
2629     #   daily : n / week
2630     #   Since we're interpreting irregularity here as which days of the week to skip an issue,
2631     #   renaming this pattern from 1/day to " n / week ".
2632     if ( $subscription->{periodicity} == 1 ) {  
2633         my $dayofweek = eval{Day_of_Week( $year,$month, $day )};
2634         if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";}
2635         else {    
2636           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2637               $dayofweek = 0 if ( $dayofweek == 7 ); 
2638               if ( in_array( ($dayofweek + 1), @irreg ) ) {
2639                   ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 1 );
2640                   $dayofweek++;
2641               }
2642           }
2643           @resultdate = Add_Delta_Days($year,$month, $day , 1 );
2644         }    
2645     }
2646     #   1  week
2647     if ( $subscription->{periodicity} == 2 ) {
2648         my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )};
2649         if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";}
2650         else {    
2651           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2652           #FIXME: if two consecutive irreg, do we only skip one?
2653               if ( $irreg[$i] == (($wkno!=51)?($wkno +1) % 52 :52)) {
2654                   ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 7 );
2655                   $wkno=(($wkno!=51)?($wkno +1) % 52 :52);
2656               }
2657           }
2658           @resultdate = Add_Delta_Days( $year,$month, $day, 7);
2659         }        
2660     }
2661     #   1 / 2 weeks
2662     if ( $subscription->{periodicity} == 3 ) {        
2663         my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )};
2664         if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";}
2665         else {    
2666           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2667               if ( $irreg[$i] == (($wkno!=50)?($wkno +2) % 52 :52)) {
2668               ### BUGFIX was previously +1 ^
2669                   ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 14 );
2670                   $wkno=(($wkno!=50)?($wkno +2) % 52 :52);
2671               }
2672           }
2673           @resultdate = Add_Delta_Days($year,$month, $day , 14 );
2674         }        
2675     }
2676     #   1 / 3 weeks
2677     if ( $subscription->{periodicity} == 4 ) {
2678         my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )};
2679         if ($@){warn "annĂ©e mois jour : $year $month $day $subscription->{subscriptionid} : $@";}
2680         else {    
2681           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2682               if ( $irreg[$i] == (($wkno!=49)?($wkno +3) % 52 :52)) {
2683                   ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 21 );
2684                   $wkno=(($wkno!=49)?($wkno +3) % 52 :52);
2685               }
2686           }
2687           @resultdate = Add_Delta_Days($year,$month, $day , 21 );
2688         }        
2689     }
2690     my $tmpmonth=$month;
2691     if ($year && $month && $day){
2692     if ( $subscription->{periodicity} == 5 ) {
2693           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2694               if ( $irreg[$i] == (($tmpmonth!=11)?($tmpmonth +1) % 12 :12)) {
2695                   ($year,$month,$day) = Add_Delta_YMD($year,$month, $day ,0,1,0 );
2696                   $tmpmonth=(($tmpmonth!=11)?($tmpmonth +1) % 12 :12);
2697               }
2698           }        
2699           @resultdate = Add_Delta_YMD($year,$month, $day ,0,1,0 );
2700     }
2701     if ( $subscription->{periodicity} == 6 ) {
2702           for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2703               if ( $irreg[$i] == (($tmpmonth!=10)?($tmpmonth +2) % 12 :12)) {
2704                   ($year,$month,$day) = Add_Delta_YMD($year,$month, $day ,0,2,0 );
2705                   $tmpmonth=(($tmpmonth!=10)?($tmpmonth + 2) % 12 :12);
2706               }
2707           }
2708           @resultdate = Add_Delta_YMD($year,$month, $day, 0, 2,0 );
2709     }
2710     if ( $subscription->{periodicity} == 7 ) {
2711         for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2712             if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
2713                 ($year,$month,$day) = Add_Delta_YMD($year,$month, $day, 0, 3,0 );
2714                 $tmpmonth=(($tmpmonth!=9)?($tmpmonth + 3) % 12 :12);
2715             }
2716         }
2717         @resultdate = Add_Delta_YMD($year,$month, $day, 0, 3, 0);
2718     }
2719     if ( $subscription->{periodicity} == 8 ) {
2720         for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2721             if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
2722                 ($year,$month,$day) = Add_Delta_YMD($year,$month, $day, 0, 3,0 );
2723                 $tmpmonth=(($tmpmonth!=9)?($tmpmonth + 3) % 12 :12);
2724             }
2725         }
2726         @resultdate = Add_Delta_YMD($year,$month, $day, 0, 3, 0);
2727     }
2728     if ( $subscription->{periodicity} == 9 ) {
2729         for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2730             if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
2731             ### BUFIX Seems to need more Than One ?
2732                 ($year,$month,$day) = Add_Delta_YM($year,$month, $day, 0, 6 );
2733                 $tmpmonth=(($tmpmonth!=6)?($tmpmonth + 6) % 12 :12);
2734             }
2735         }
2736         @resultdate = Add_Delta_YM($year,$month, $day, 0, 6);
2737     }
2738     if ( $subscription->{periodicity} == 10 ) {
2739         @resultdate = Add_Delta_YM($year,$month, $day, 1, 0 );
2740     }
2741     if ( $subscription->{periodicity} == 11 ) {
2742         @resultdate = Add_Delta_YM($year,$month, $day, 2, 0 );
2743     }
2744     }  
2745     my $resultdate=sprintf("%04d-%02d-%02d",$resultdate[0],$resultdate[1],$resultdate[2]);
2746       
2747 #     warn "dateNEXTSEQ : ".$resultdate;
2748     return "$resultdate";
2749 }
2750
2751 =head2 itemdata
2752
2753   $item = &itemdata($barcode);
2754
2755 Looks up the item with the given barcode, and returns a
2756 reference-to-hash containing information about that item. The keys of
2757 the hash are the fields from the C<items> and C<biblioitems> tables in
2758 the Koha database.
2759
2760 =cut
2761
2762 #'
2763 sub itemdata {
2764     my ($barcode) = @_;
2765     my $dbh       = C4::Context->dbh;
2766     my $sth       = $dbh->prepare(
2767         "Select * from items LEFT JOIN biblioitems ON items.biblioitemnumber=biblioitems.biblioitemnumber 
2768         WHERE barcode=?"
2769     );
2770     $sth->execute($barcode);
2771     my $data = $sth->fetchrow_hashref;
2772     $sth->finish;
2773     return ($data);
2774 }
2775
2776 1;
2777 __END__
2778
2779 =head1 AUTHOR
2780
2781 Koha Developement team <info@koha.org>
2782
2783 =cut