Merge remote-tracking branch 'origin/new/bug_7781'
[koha.git] / C4 / Serials.pm
blob20ad7067b41f23cf9dcef05213a64fa33808ac76
1 package C4::Serials;
3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright 2010 Biblibre
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along
18 # with Koha; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 use strict;
22 use warnings;
23 use C4::Dates qw(format_date format_date_in_iso);
24 use Date::Calc qw(:all);
25 use POSIX qw(strftime);
26 use C4::Biblio;
27 use C4::Log; # logaction
28 use C4::Debug;
30 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
32 BEGIN {
33 $VERSION = 3.01; # set version for version checking
34 require Exporter;
35 @ISA = qw(Exporter);
36 @EXPORT = qw(
37 &NewSubscription &ModSubscription &DelSubscription &GetSubscriptions
38 &GetSubscription &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
39 &GetFullSubscriptionsFromBiblionumber &GetFullSubscription &ModSubscriptionHistory
40 &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
42 &GetNextSeq &NewIssue &ItemizeSerials &GetSerials
43 &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2
44 &ReNewSubscription &GetLateIssues &GetLateOrMissingIssues
45 &GetSerialInformation &AddItem2Serial
46 &PrepareSerialsData &GetNextExpected &ModNextExpected
48 &UpdateClaimdateIssues
49 &GetSuppliersWithLateIssues &getsupplierbyserialid
50 &GetDistributedTo &SetDistributedTo
51 &getroutinglist &delroutingmember &addroutingmember
52 &reorder_members
53 &check_routing &updateClaim &removeMissingIssue
54 &CountIssues
55 HasItems
60 =head1 NAME
62 C4::Serials - Serials Module Functions
64 =head1 SYNOPSIS
66 use C4::Serials;
68 =head1 DESCRIPTION
70 Functions for handling subscriptions, claims routing etc.
73 =head1 SUBROUTINES
75 =head2 GetSuppliersWithLateIssues
77 $supplierlist = GetSuppliersWithLateIssues()
79 this function get all suppliers with late issues.
81 return :
82 an array_ref of suppliers each entry is a hash_ref containing id and name
83 the array is in name order
85 =cut
87 sub GetSuppliersWithLateIssues {
88 my $dbh = C4::Context->dbh;
89 my $query = qq|
90 SELECT DISTINCT id, name
91 FROM subscription
92 LEFT JOIN serial ON serial.subscriptionid=subscription.subscriptionid
93 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
94 WHERE id > 0 AND ((planneddate < now() AND serial.status=1) OR serial.STATUS = 3 OR serial.STATUS = 4) ORDER BY name|;
95 return $dbh->selectall_arrayref($query, { Slice => {} });
98 =head2 GetLateIssues
100 @issuelist = GetLateIssues($supplierid)
102 this function selects late issues from the database
104 return :
105 the issuelist as an array. Each element of this array contains a hashi_ref containing
106 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
108 =cut
110 sub GetLateIssues {
111 my ($supplierid) = @_;
112 my $dbh = C4::Context->dbh;
113 my $sth;
114 if ($supplierid) {
115 my $query = qq|
116 SELECT name,title,planneddate,serialseq,serial.subscriptionid
117 FROM subscription
118 LEFT JOIN serial ON subscription.subscriptionid = serial.subscriptionid
119 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
120 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
121 WHERE ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
122 AND subscription.aqbooksellerid=?
123 ORDER BY title
125 $sth = $dbh->prepare($query);
126 $sth->execute($supplierid);
127 } else {
128 my $query = qq|
129 SELECT name,title,planneddate,serialseq,serial.subscriptionid
130 FROM subscription
131 LEFT JOIN serial ON subscription.subscriptionid = serial.subscriptionid
132 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
133 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
134 WHERE ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
135 ORDER BY title
137 $sth = $dbh->prepare($query);
138 $sth->execute;
140 my @issuelist;
141 my $last_title;
142 my $odd = 0;
143 while ( my $line = $sth->fetchrow_hashref ) {
144 $odd++ unless $line->{title} eq $last_title;
145 $line->{title} = "" if $line->{title} eq $last_title;
146 $last_title = $line->{title} if ( $line->{title} );
147 $line->{planneddate} = format_date( $line->{planneddate} );
148 push @issuelist, $line;
150 return @issuelist;
153 =head2 GetSubscriptionHistoryFromSubscriptionId
155 $sth = GetSubscriptionHistoryFromSubscriptionId()
156 this function prepares the SQL request and returns the statement handle
157 After this function, don't forget to execute it by using $sth->execute($subscriptionid)
159 =cut
161 sub GetSubscriptionHistoryFromSubscriptionId() {
162 my $dbh = C4::Context->dbh;
163 my $query = qq|
164 SELECT *
165 FROM subscriptionhistory
166 WHERE subscriptionid = ?
168 return $dbh->prepare($query);
171 =head2 GetSerialStatusFromSerialId
173 $sth = GetSerialStatusFromSerialId();
174 this function returns a statement handle
175 After this function, don't forget to execute it by using $sth->execute($serialid)
176 return :
177 $sth = $dbh->prepare($query).
179 =cut
181 sub GetSerialStatusFromSerialId() {
182 my $dbh = C4::Context->dbh;
183 my $query = qq|
184 SELECT status
185 FROM serial
186 WHERE serialid = ?
188 return $dbh->prepare($query);
191 =head2 GetSerialInformation
194 $data = GetSerialInformation($serialid);
195 returns a hash_ref containing :
196 items : items marcrecord (can be an array)
197 serial table field
198 subscription table field
199 + information about subscription expiration
201 =cut
203 sub GetSerialInformation {
204 my ($serialid) = @_;
205 my $dbh = C4::Context->dbh;
206 my $query = qq|
207 SELECT serial.*, serial.notes as sernotes, serial.status as serstatus,subscription.*,subscription.subscriptionid as subsid |;
208 if ( C4::Context->preference('IndependantBranches')
209 && C4::Context->userenv
210 && C4::Context->userenv->{'flags'} != 1
211 && C4::Context->userenv->{'branch'} ) {
212 $query .= "
213 , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
215 $query .= qq|
216 FROM serial LEFT JOIN subscription ON subscription.subscriptionid=serial.subscriptionid
217 WHERE serialid = ?
219 my $rq = $dbh->prepare($query);
220 $rq->execute($serialid);
221 my $data = $rq->fetchrow_hashref;
223 # create item information if we have serialsadditems for this subscription
224 if ( $data->{'serialsadditems'} ) {
225 my $queryitem = $dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
226 $queryitem->execute($serialid);
227 my $itemnumbers = $queryitem->fetchall_arrayref( [0] );
228 require C4::Items;
229 if ( scalar(@$itemnumbers) > 0 ) {
230 foreach my $itemnum (@$itemnumbers) {
232 #It is ASSUMED that GetMarcItem ALWAYS WORK...
233 #Maybe GetMarcItem should return values on failure
234 $debug and warn "itemnumber :$itemnum->[0], bibnum :" . $data->{'biblionumber'};
235 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, $itemnum->[0], $data );
236 $itemprocessed->{'itemnumber'} = $itemnum->[0];
237 $itemprocessed->{'itemid'} = $itemnum->[0];
238 $itemprocessed->{'serialid'} = $serialid;
239 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
240 push @{ $data->{'items'} }, $itemprocessed;
242 } else {
243 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, '', $data );
244 $itemprocessed->{'itemid'} = "N$serialid";
245 $itemprocessed->{'serialid'} = $serialid;
246 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
247 $itemprocessed->{'countitems'} = 0;
248 push @{ $data->{'items'} }, $itemprocessed;
251 $data->{ "status" . $data->{'serstatus'} } = 1;
252 $data->{'subscriptionexpired'} = HasSubscriptionExpired( $data->{'subscriptionid'} ) && $data->{'status'} == 1;
253 $data->{'abouttoexpire'} = abouttoexpire( $data->{'subscriptionid'} );
254 return $data;
257 =head2 AddItem2Serial
259 $rows = AddItem2Serial($serialid,$itemnumber);
260 Adds an itemnumber to Serial record
261 returns the number of rows affected
263 =cut
265 sub AddItem2Serial {
266 my ( $serialid, $itemnumber ) = @_;
267 my $dbh = C4::Context->dbh;
268 my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
269 $rq->execute( $serialid, $itemnumber );
270 return $rq->rows;
273 =head2 UpdateClaimdateIssues
275 UpdateClaimdateIssues($serialids,[$date]);
277 Update Claimdate for issues in @$serialids list with date $date
278 (Take Today if none)
280 =cut
282 sub UpdateClaimdateIssues {
283 my ( $serialids, $date ) = @_;
284 my $dbh = C4::Context->dbh;
285 $date = strftime( "%Y-%m-%d", localtime ) unless ($date);
286 my $query = "
287 UPDATE serial SET claimdate = ?, status = 7
288 WHERE serialid in (" . join( ",", map { '?' } @$serialids ) . ")";
289 my $rq = $dbh->prepare($query);
290 $rq->execute($date, @$serialids);
291 return $rq->rows;
294 =head2 GetSubscription
296 $subs = GetSubscription($subscriptionid)
297 this function returns the subscription which has $subscriptionid as id.
298 return :
299 a hashref. This hash containts
300 subscription, subscriptionhistory, aqbudget.bookfundid, biblio.title
302 =cut
304 sub GetSubscription {
305 my ($subscriptionid) = @_;
306 my $dbh = C4::Context->dbh;
307 my $query = qq(
308 SELECT subscription.*,
309 subscriptionhistory.*,
310 aqbooksellers.name AS aqbooksellername,
311 biblio.title AS bibliotitle,
312 subscription.biblionumber as bibnum);
313 if ( C4::Context->preference('IndependantBranches')
314 && C4::Context->userenv
315 && C4::Context->userenv->{'flags'} != 1
316 && C4::Context->userenv->{'branch'} ) {
317 $query .= "
318 , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
320 $query .= qq(
321 FROM subscription
322 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
323 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
324 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
325 WHERE subscription.subscriptionid = ?
328 # if (C4::Context->preference('IndependantBranches') &&
329 # C4::Context->userenv &&
330 # C4::Context->userenv->{'flags'} != 1){
331 # # $debug and warn "flags: ".C4::Context->userenv->{'flags'};
332 # $query.=" AND subscription.branchcode IN ('".C4::Context->userenv->{'branch'}."',\"\")";
334 $debug and warn "query : $query\nsubsid :$subscriptionid";
335 my $sth = $dbh->prepare($query);
336 $sth->execute($subscriptionid);
337 return $sth->fetchrow_hashref;
340 =head2 GetFullSubscription
342 $array_ref = GetFullSubscription($subscriptionid)
343 this function reads the serial table.
345 =cut
347 sub GetFullSubscription {
348 my ($subscriptionid) = @_;
349 my $dbh = C4::Context->dbh;
350 my $query = qq|
351 SELECT serial.serialid,
352 serial.serialseq,
353 serial.planneddate,
354 serial.publisheddate,
355 serial.status,
356 serial.notes as notes,
357 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
358 aqbooksellers.name as aqbooksellername,
359 biblio.title as bibliotitle,
360 subscription.branchcode AS branchcode,
361 subscription.subscriptionid AS subscriptionid |;
362 if ( C4::Context->preference('IndependantBranches')
363 && C4::Context->userenv
364 && C4::Context->userenv->{'flags'} != 1
365 && C4::Context->userenv->{'branch'} ) {
366 $query .= "
367 , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
369 $query .= qq|
370 FROM serial
371 LEFT JOIN subscription ON
372 (serial.subscriptionid=subscription.subscriptionid )
373 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
374 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
375 WHERE serial.subscriptionid = ?
376 ORDER BY year DESC,
377 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
378 serial.subscriptionid
380 $debug and warn "GetFullSubscription query: $query";
381 my $sth = $dbh->prepare($query);
382 $sth->execute($subscriptionid);
383 return $sth->fetchall_arrayref( {} );
386 =head2 PrepareSerialsData
388 $array_ref = PrepareSerialsData($serialinfomation)
389 where serialinformation is a hashref array
391 =cut
393 sub PrepareSerialsData {
394 my ($lines) = @_;
395 my %tmpresults;
396 my $year;
397 my @res;
398 my $startdate;
399 my $aqbooksellername;
400 my $bibliotitle;
401 my @loopissues;
402 my $first;
403 my $previousnote = "";
405 foreach my $subs (@{$lines}) {
406 for my $datefield ( qw(publisheddate planneddate) ) {
407 # handle both undef and undef returned as 0000-00-00
408 if (!defined $subs->{$datefield} or $subs->{$datefield}=~m/^00/) {
409 $subs->{$datefield} = 'XXX';
411 else {
412 $subs->{$datefield} = format_date( $subs->{$datefield} );
415 $subs->{ "status" . $subs->{'status'} } = 1;
416 $subs->{"checked"} = $subs->{'status'} =~ /1|3|4|7/;
418 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
419 $year = $subs->{'year'};
420 } else {
421 $year = "manage";
423 if ( $tmpresults{$year} ) {
424 push @{ $tmpresults{$year}->{'serials'} }, $subs;
425 } else {
426 $tmpresults{$year} = {
427 'year' => $year,
428 'aqbooksellername' => $subs->{'aqbooksellername'},
429 'bibliotitle' => $subs->{'bibliotitle'},
430 'serials' => [$subs],
431 'first' => $first,
435 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
436 push @res, $tmpresults{$key};
438 return \@res;
441 =head2 GetSubscriptionsFromBiblionumber
443 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
444 this function get the subscription list. it reads the subscription table.
445 return :
446 reference to an array of subscriptions which have the biblionumber given on input arg.
447 each element of this array is a hashref containing
448 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
450 =cut
452 sub GetSubscriptionsFromBiblionumber {
453 my ($biblionumber) = @_;
454 my $dbh = C4::Context->dbh;
455 my $query = qq(
456 SELECT subscription.*,
457 branches.branchname,
458 subscriptionhistory.*,
459 aqbooksellers.name AS aqbooksellername,
460 biblio.title AS bibliotitle
461 FROM subscription
462 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
463 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
464 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
465 LEFT JOIN branches ON branches.branchcode=subscription.branchcode
466 WHERE subscription.biblionumber = ?
468 my $sth = $dbh->prepare($query);
469 $sth->execute($biblionumber);
470 my @res;
471 while ( my $subs = $sth->fetchrow_hashref ) {
472 $subs->{startdate} = format_date( $subs->{startdate} );
473 $subs->{histstartdate} = format_date( $subs->{histstartdate} );
474 $subs->{histenddate} = format_date( $subs->{histenddate} );
475 $subs->{opacnote} =~ s/\n/\<br\/\>/g;
476 $subs->{missinglist} =~ s/\n/\<br\/\>/g;
477 $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
478 $subs->{ "periodicity" . $subs->{periodicity} } = 1;
479 $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
480 $subs->{ "status" . $subs->{'status'} } = 1;
481 $subs->{'cannotedit'} =
482 ( C4::Context->preference('IndependantBranches')
483 && C4::Context->userenv
484 && C4::Context->userenv->{flags} % 2 != 1
485 && C4::Context->userenv->{branch}
486 && $subs->{branchcode}
487 && ( C4::Context->userenv->{branch} ne $subs->{branchcode} ) );
489 if ( $subs->{enddate} eq '0000-00-00' ) {
490 $subs->{enddate} = '';
491 } else {
492 $subs->{enddate} = format_date( $subs->{enddate} );
494 $subs->{'abouttoexpire'} = abouttoexpire( $subs->{'subscriptionid'} );
495 $subs->{'subscriptionexpired'} = HasSubscriptionExpired( $subs->{'subscriptionid'} );
496 push @res, $subs;
498 return \@res;
501 =head2 GetFullSubscriptionsFromBiblionumber
503 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
504 this function reads the serial table.
506 =cut
508 sub GetFullSubscriptionsFromBiblionumber {
509 my ($biblionumber) = @_;
510 my $dbh = C4::Context->dbh;
511 my $query = qq|
512 SELECT serial.serialid,
513 serial.serialseq,
514 serial.planneddate,
515 serial.publisheddate,
516 serial.status,
517 serial.notes as notes,
518 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
519 biblio.title as bibliotitle,
520 subscription.branchcode AS branchcode,
521 subscription.subscriptionid AS subscriptionid|;
522 if ( C4::Context->preference('IndependantBranches')
523 && C4::Context->userenv
524 && C4::Context->userenv->{'flags'} != 1
525 && C4::Context->userenv->{'branch'} ) {
526 $query .= "
527 , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit ";
530 $query .= qq|
531 FROM serial
532 LEFT JOIN subscription ON
533 (serial.subscriptionid=subscription.subscriptionid)
534 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
535 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
536 WHERE subscription.biblionumber = ?
537 ORDER BY year DESC,
538 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
539 serial.subscriptionid
541 my $sth = $dbh->prepare($query);
542 $sth->execute($biblionumber);
543 return $sth->fetchall_arrayref( {} );
546 =head2 GetSubscriptions
548 @results = GetSubscriptions($title,$ISSN,$biblionumber);
549 this function gets all subscriptions which have title like $title,ISSN like $ISSN and biblionumber like $biblionumber.
550 return:
551 a table of hashref. Each hash containt the subscription.
553 =cut
555 sub GetSubscriptions {
556 my ( $string, $issn, $biblionumber ) = @_;
558 #return unless $title or $ISSN or $biblionumber;
559 my $dbh = C4::Context->dbh;
560 my $sth;
561 my $sql = qq(
562 SELECT subscription.*, subscriptionhistory.*, biblio.title,biblioitems.issn,biblio.biblionumber
563 FROM subscription
564 LEFT JOIN subscriptionhistory USING(subscriptionid)
565 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
566 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
568 my @bind_params;
569 my $sqlwhere;
570 if ($biblionumber) {
571 $sqlwhere = " WHERE biblio.biblionumber=?";
572 push @bind_params, $biblionumber;
574 if ($string) {
575 my @sqlstrings;
576 my @strings_to_search;
577 @strings_to_search = map { "%$_%" } split( / /, $string );
578 foreach my $index (qw(biblio.title subscription.callnumber subscription.location subscription.notes subscription.internalnotes)) {
579 push @bind_params, @strings_to_search;
580 my $tmpstring = "AND $index LIKE ? " x scalar(@strings_to_search);
581 $debug && warn "$tmpstring";
582 $tmpstring =~ s/^AND //;
583 push @sqlstrings, $tmpstring;
585 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
587 if ($issn) {
588 my @sqlstrings;
589 my @strings_to_search;
590 @strings_to_search = map { "%$_%" } split( / /, $issn );
591 foreach my $index ( qw(biblioitems.issn subscription.callnumber)) {
592 push @bind_params, @strings_to_search;
593 my $tmpstring = "OR $index LIKE ? " x scalar(@strings_to_search);
594 $debug && warn "$tmpstring";
595 $tmpstring =~ s/^OR //;
596 push @sqlstrings, $tmpstring;
598 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
600 $sql .= "$sqlwhere ORDER BY title";
601 $debug and warn "GetSubscriptions query: $sql params : ", join( " ", @bind_params );
602 $sth = $dbh->prepare($sql);
603 $sth->execute(@bind_params);
604 my @results;
606 while ( my $line = $sth->fetchrow_hashref ) {
607 $line->{'cannotedit'} =
608 ( C4::Context->preference('IndependantBranches')
609 && C4::Context->userenv
610 && C4::Context->userenv->{flags} % 2 != 1
611 && C4::Context->userenv->{branch}
612 && $line->{branchcode}
613 && ( C4::Context->userenv->{branch} ne $line->{branchcode} ) );
614 push @results, $line;
616 return @results;
619 =head2 GetSerials
621 ($totalissues,@serials) = GetSerials($subscriptionid);
622 this function gets every serial not arrived for a given subscription
623 as well as the number of issues registered in the database (all types)
624 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
626 FIXME: We should return \@serials.
628 =cut
630 sub GetSerials {
631 my ( $subscriptionid, $count ) = @_;
632 my $dbh = C4::Context->dbh;
634 # status = 2 is "arrived"
635 my $counter = 0;
636 $count = 5 unless ($count);
637 my @serials;
638 my $query = "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
639 FROM serial
640 WHERE subscriptionid = ? AND status NOT IN (2,4,5)
641 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
642 my $sth = $dbh->prepare($query);
643 $sth->execute($subscriptionid);
645 while ( my $line = $sth->fetchrow_hashref ) {
646 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
647 for my $datefield ( qw( planneddate publisheddate) ) {
648 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
649 $line->{$datefield} = format_date( $line->{$datefield});
650 } else {
651 $line->{$datefield} = q{};
654 push @serials, $line;
657 # OK, now add the last 5 issues arrives/missing
658 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
659 FROM serial
660 WHERE subscriptionid = ?
661 AND (status in (2,4,5))
662 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
664 $sth = $dbh->prepare($query);
665 $sth->execute($subscriptionid);
666 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
667 $counter++;
668 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
669 for my $datefield ( qw( planneddate publisheddate) ) {
670 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
671 $line->{$datefield} = format_date( $line->{$datefield});
672 } else {
673 $line->{$datefield} = q{};
677 push @serials, $line;
680 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
681 $sth = $dbh->prepare($query);
682 $sth->execute($subscriptionid);
683 my ($totalissues) = $sth->fetchrow;
684 return ( $totalissues, @serials );
687 =head2 GetSerials2
689 @serials = GetSerials2($subscriptionid,$status);
690 this function returns every serial waited for a given subscription
691 as well as the number of issues registered in the database (all types)
692 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
694 =cut
696 sub GetSerials2 {
697 my ( $subscription, $status ) = @_;
698 my $dbh = C4::Context->dbh;
699 my $query = qq|
700 SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
701 FROM serial
702 WHERE subscriptionid=$subscription AND status IN ($status)
703 ORDER BY publisheddate,serialid DESC
705 $debug and warn "GetSerials2 query: $query";
706 my $sth = $dbh->prepare($query);
707 $sth->execute;
708 my @serials;
710 while ( my $line = $sth->fetchrow_hashref ) {
711 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
712 # Format dates for display
713 for my $datefield ( qw( planneddate publisheddate ) ) {
714 if ($line->{$datefield} =~m/^00/) {
715 $line->{$datefield} = q{};
717 else {
718 $line->{$datefield} = format_date( $line->{$datefield} );
721 push @serials, $line;
723 return @serials;
726 =head2 GetLatestSerials
728 \@serials = GetLatestSerials($subscriptionid,$limit)
729 get the $limit's latest serials arrived or missing for a given subscription
730 return :
731 a ref to an array which contains all of the latest serials stored into a hash.
733 =cut
735 sub GetLatestSerials {
736 my ( $subscriptionid, $limit ) = @_;
737 my $dbh = C4::Context->dbh;
739 # status = 2 is "arrived"
740 my $strsth = "SELECT serialid,serialseq, status, planneddate, notes
741 FROM serial
742 WHERE subscriptionid = ?
743 AND (status =2 or status=4)
744 ORDER BY planneddate DESC LIMIT 0,$limit
746 my $sth = $dbh->prepare($strsth);
747 $sth->execute($subscriptionid);
748 my @serials;
749 while ( my $line = $sth->fetchrow_hashref ) {
750 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
751 $line->{"planneddate"} = format_date( $line->{"planneddate"} );
752 push @serials, $line;
755 return \@serials;
758 =head2 GetDistributedTo
760 $distributedto=GetDistributedTo($subscriptionid)
761 This function returns the field distributedto for the subscription matching subscriptionid
763 =cut
765 sub GetDistributedTo {
766 my $dbh = C4::Context->dbh;
767 my $distributedto;
768 my $subscriptionid = @_;
769 my $query = "SELECT distributedto FROM subscription WHERE subscriptionid=?";
770 my $sth = $dbh->prepare($query);
771 $sth->execute($subscriptionid);
772 return ($distributedto) = $sth->fetchrow;
775 =head2 GetNextSeq
777 GetNextSeq($val)
778 $val is a hashref containing all the attributes of the table 'subscription'
779 This function get the next issue for the subscription given on input arg
780 return:
781 a list containing all the input params updated.
783 =cut
785 # sub GetNextSeq {
786 # my ($val) =@_;
787 # my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
788 # $calculated = $val->{numberingmethod};
789 # # calculate the (expected) value of the next issue recieved.
790 # $newlastvalue1 = $val->{lastvalue1};
791 # # check if we have to increase the new value.
792 # $newinnerloop1 = $val->{innerloop1}+1;
793 # $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
794 # $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
795 # $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
796 # $calculated =~ s/\{X\}/$newlastvalue1/g;
798 # $newlastvalue2 = $val->{lastvalue2};
799 # # check if we have to increase the new value.
800 # $newinnerloop2 = $val->{innerloop2}+1;
801 # $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
802 # $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
803 # $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
804 # $calculated =~ s/\{Y\}/$newlastvalue2/g;
806 # $newlastvalue3 = $val->{lastvalue3};
807 # # check if we have to increase the new value.
808 # $newinnerloop3 = $val->{innerloop3}+1;
809 # $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
810 # $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
811 # $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
812 # $calculated =~ s/\{Z\}/$newlastvalue3/g;
813 # return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
816 sub GetNextSeq {
817 my ($val) = @_;
818 my ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
819 my $pattern = $val->{numberpattern};
820 my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
821 my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
822 $calculated = $val->{numberingmethod};
823 $newlastvalue1 = $val->{lastvalue1};
824 $newlastvalue2 = $val->{lastvalue2};
825 $newlastvalue3 = $val->{lastvalue3};
826 $newlastvalue1 = $val->{lastvalue1};
828 # check if we have to increase the new value.
829 $newinnerloop1 = $val->{innerloop1} + 1;
830 $newinnerloop1 = 0 if ( $newinnerloop1 >= $val->{every1} );
831 $newlastvalue1 += $val->{add1} if ( $newinnerloop1 < 1 ); # <1 to be true when 0 or empty.
832 $newlastvalue1 = $val->{setto1} if ( $newlastvalue1 > $val->{whenmorethan1} ); # reset counter if needed.
833 $calculated =~ s/\{X\}/$newlastvalue1/g;
835 $newlastvalue2 = $val->{lastvalue2};
837 # check if we have to increase the new value.
838 $newinnerloop2 = $val->{innerloop2} + 1;
839 $newinnerloop2 = 0 if ( $newinnerloop2 >= $val->{every2} );
840 $newlastvalue2 += $val->{add2} if ( $newinnerloop2 < 1 ); # <1 to be true when 0 or empty.
841 $newlastvalue2 = $val->{setto2} if ( $newlastvalue2 > $val->{whenmorethan2} ); # reset counter if needed.
842 if ( $pattern == 6 ) {
843 if ( $val->{hemisphere} == 2 ) {
844 my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
845 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
846 } else {
847 my $newlastvalue2seq = $seasons[$newlastvalue2];
848 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
850 } else {
851 $calculated =~ s/\{Y\}/$newlastvalue2/g;
854 $newlastvalue3 = $val->{lastvalue3};
856 # check if we have to increase the new value.
857 $newinnerloop3 = $val->{innerloop3} + 1;
858 $newinnerloop3 = 0 if ( $newinnerloop3 >= $val->{every3} );
859 $newlastvalue3 += $val->{add3} if ( $newinnerloop3 < 1 ); # <1 to be true when 0 or empty.
860 $newlastvalue3 = $val->{setto3} if ( $newlastvalue3 > $val->{whenmorethan3} ); # reset counter if needed.
861 $calculated =~ s/\{Z\}/$newlastvalue3/g;
863 return ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
866 =head2 GetSeq
868 $calculated = GetSeq($val)
869 $val is a hashref containing all the attributes of the table 'subscription'
870 this function transforms {X},{Y},{Z} to 150,0,0 for example.
871 return:
872 the sequence in integer format
874 =cut
876 sub GetSeq {
877 my ($val) = @_;
878 my $pattern = $val->{numberpattern};
879 my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
880 my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
881 my $calculated = $val->{numberingmethod};
882 my $x = $val->{'lastvalue1'};
883 $calculated =~ s/\{X\}/$x/g;
884 my $newlastvalue2 = $val->{'lastvalue2'};
886 if ( $pattern == 6 ) {
887 if ( $val->{hemisphere} == 2 ) {
888 my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
889 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
890 } else {
891 my $newlastvalue2seq = $seasons[$newlastvalue2];
892 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
894 } else {
895 $calculated =~ s/\{Y\}/$newlastvalue2/g;
897 my $z = $val->{'lastvalue3'};
898 $calculated =~ s/\{Z\}/$z/g;
899 return $calculated;
902 =head2 GetExpirationDate
904 $enddate = GetExpirationDate($subscriptionid, [$startdate])
906 this function return the next expiration date for a subscription given on input args.
908 return
909 the enddate or undef
911 =cut
913 sub GetExpirationDate {
914 my ( $subscriptionid, $startdate ) = @_;
915 my $dbh = C4::Context->dbh;
916 my $subscription = GetSubscription($subscriptionid);
917 my $enddate;
919 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
920 $enddate = $startdate || $subscription->{startdate};
921 my @date = split( /-/, $enddate );
922 return if ( scalar(@date) != 3 || not check_date(@date) );
923 if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
925 # If Not Irregular
926 if ( my $length = $subscription->{numberlength} ) {
928 #calculate the date of the last issue.
929 for ( my $i = 1 ; $i <= $length ; $i++ ) {
930 $enddate = GetNextDate( $enddate, $subscription );
932 } elsif ( $subscription->{monthlength} ) {
933 if ( $$subscription{startdate} ) {
934 my @enddate = Add_Delta_YM( $date[0], $date[1], $date[2], 0, $subscription->{monthlength} );
935 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
937 } elsif ( $subscription->{weeklength} ) {
938 if ( $$subscription{startdate} ) {
939 my @date = split( /-/, $subscription->{startdate} );
940 my @enddate = Add_Delta_Days( $date[0], $date[1], $date[2], $subscription->{weeklength} * 7 );
941 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
944 return $enddate;
945 } else {
946 return;
950 =head2 CountSubscriptionFromBiblionumber
952 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
953 this returns a count of the subscriptions for a given biblionumber
954 return :
955 the number of subscriptions
957 =cut
959 sub CountSubscriptionFromBiblionumber {
960 my ($biblionumber) = @_;
961 my $dbh = C4::Context->dbh;
962 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
963 my $sth = $dbh->prepare($query);
964 $sth->execute($biblionumber);
965 my $subscriptionsnumber = $sth->fetchrow;
966 return $subscriptionsnumber;
969 =head2 ModSubscriptionHistory
971 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
973 this function modifies the history of a subscription. Put your new values on input arg.
974 returns the number of rows affected
976 =cut
978 sub ModSubscriptionHistory {
979 my ( $subscriptionid, $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote ) = @_;
980 my $dbh = C4::Context->dbh;
981 my $query = "UPDATE subscriptionhistory
982 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
983 WHERE subscriptionid=?
985 my $sth = $dbh->prepare($query);
986 $recievedlist =~ s/^; //;
987 $missinglist =~ s/^; //;
988 $opacnote =~ s/^; //;
989 $sth->execute( $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
990 return $sth->rows;
993 =head2 ModSerialStatus
995 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
997 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
998 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1000 =cut
1002 sub ModSerialStatus {
1003 my ( $serialid, $serialseq, $planneddate, $publisheddate, $status, $notes ) = @_;
1005 #It is a usual serial
1006 # 1st, get previous status :
1007 my $dbh = C4::Context->dbh;
1008 my $query = "SELECT subscriptionid,status FROM serial WHERE serialid=?";
1009 my $sth = $dbh->prepare($query);
1010 $sth->execute($serialid);
1011 my ( $subscriptionid, $oldstatus ) = $sth->fetchrow;
1013 # change status & update subscriptionhistory
1014 my $val;
1015 if ( $status == 6 ) {
1016 DelIssue( {'serialid'=>$serialid, 'subscriptionid'=>$subscriptionid,'serialseq'=>$serialseq} );
1018 else {
1019 my $query =
1020 'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE serialid = ?';
1021 $sth = $dbh->prepare($query);
1022 $sth->execute( $serialseq, $publisheddate, $planneddate, $status, $notes, $serialid );
1023 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1024 $sth = $dbh->prepare($query);
1025 $sth->execute($subscriptionid);
1026 my $val = $sth->fetchrow_hashref;
1027 unless ( $val->{manualhistory} ) {
1028 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1029 $sth = $dbh->prepare($query);
1030 $sth->execute($subscriptionid);
1031 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1032 if ( $status == 2 ) {
1034 $recievedlist .= "; $serialseq"
1035 unless ( index( "$recievedlist", "$serialseq" ) >= 0 );
1038 # warn "missinglist : $missinglist serialseq :$serialseq, ".index("$missinglist","$serialseq");
1039 $missinglist .= "; $serialseq"
1040 if ( $status == 4
1041 and not index( "$missinglist", "$serialseq" ) >= 0 );
1042 $missinglist .= "; not issued $serialseq"
1043 if ( $status == 5
1044 and index( "$missinglist", "$serialseq" ) >= 0 );
1045 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1046 $sth = $dbh->prepare($query);
1047 $recievedlist =~ s/^; //;
1048 $missinglist =~ s/^; //;
1049 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1053 # create new waited entry if needed (ie : was a "waited" and has changed)
1054 if ( $oldstatus == 1 && $status != 1 ) {
1055 my $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1056 $sth = $dbh->prepare($query);
1057 $sth->execute($subscriptionid);
1058 my $val = $sth->fetchrow_hashref;
1060 # next issue number
1061 my (
1062 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1063 $newinnerloop1, $newinnerloop2, $newinnerloop3
1064 ) = GetNextSeq($val);
1066 # next date (calculated from actual date & frequency parameters)
1067 my $nextpublisheddate = GetNextDate( $publisheddate, $val );
1068 NewIssue( $newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpublisheddate, $nextpublisheddate );
1069 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1070 WHERE subscriptionid = ?";
1071 $sth = $dbh->prepare($query);
1072 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1074 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1075 if ( $val->{letter} && $status == 2 && $oldstatus != 2 ) {
1076 require C4::Letters;
1077 C4::Letters::SendAlerts( 'issue', $val->{subscriptionid}, $val->{letter} );
1080 return;
1083 =head2 GetNextExpected
1085 $nextexpected = GetNextExpected($subscriptionid)
1087 Get the planneddate for the current expected issue of the subscription.
1089 returns a hashref:
1091 $nextexepected = {
1092 serialid => int
1093 planneddate => C4::Dates object
1096 =cut
1098 sub GetNextExpected($) {
1099 my ($subscriptionid) = @_;
1100 my $dbh = C4::Context->dbh;
1101 my $sth = $dbh->prepare('SELECT serialid, planneddate FROM serial WHERE subscriptionid=? AND status=?');
1103 # Each subscription has only one 'expected' issue, with serial.status==1.
1104 $sth->execute( $subscriptionid, 1 );
1105 my ( $nextissue ) = $sth->fetchrow_hashref;
1106 if( !$nextissue){
1107 $sth = $dbh->prepare('SELECT serialid,planneddate FROM serial WHERE subscriptionid = ? ORDER BY planneddate DESC LIMIT 1');
1108 $sth->execute( $subscriptionid );
1109 $nextissue = $sth->fetchrow_hashref;
1111 if (!defined $nextissue->{planneddate}) {
1112 # or should this default to 1st Jan ???
1113 $nextissue->{planneddate} = strftime('%Y-%m-%d',localtime);
1115 $nextissue->{planneddate} = C4::Dates->new($nextissue->{planneddate},'iso');
1116 return $nextissue;
1120 =head2 ModNextExpected
1122 ModNextExpected($subscriptionid,$date)
1124 Update the planneddate for the current expected issue of the subscription.
1125 This will modify all future prediction results.
1127 C<$date> is a C4::Dates object.
1129 returns 0
1131 =cut
1133 sub ModNextExpected($$) {
1134 my ( $subscriptionid, $date ) = @_;
1135 my $dbh = C4::Context->dbh;
1137 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1138 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1140 # Each subscription has only one 'expected' issue, with serial.status==1.
1141 $sth->execute( $date->output('iso'), $date->output('iso'), $subscriptionid, 1 );
1142 return 0;
1146 =head2 ModSubscription
1148 this function modifies a subscription. Put all new values on input args.
1149 returns the number of rows affected
1151 =cut
1153 sub ModSubscription {
1154 my ($auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1155 $dow, $irregularity, $numberpattern, $numberlength, $weeklength, $monthlength, $add1, $every1,
1156 $whenmorethan1, $setto1, $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2,
1157 $lastvalue2, $innerloop2, $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3,
1158 $numberingmethod, $status, $biblionumber, $callnumber, $notes, $letter, $hemisphere, $manualhistory,
1159 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $subscriptionid
1160 ) = @_;
1162 # warn $irregularity;
1163 my $dbh = C4::Context->dbh;
1164 my $query = "UPDATE subscription
1165 SET librarian=?, branchcode=?,aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
1166 periodicity=?,firstacquidate=?,dow=?,irregularity=?, numberpattern=?, numberlength=?,weeklength=?,monthlength=?,
1167 add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
1168 add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
1169 add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
1170 numberingmethod=?, status=?, biblionumber=?, callnumber=?, notes=?,
1171 letter=?, hemisphere=?,manualhistory=?,internalnotes=?,serialsadditems=?,
1172 staffdisplaycount = ?,opacdisplaycount = ?, graceperiod = ?, location = ?
1173 ,enddate=?
1174 WHERE subscriptionid = ?";
1176 #warn "query :".$query;
1177 my $sth = $dbh->prepare($query);
1178 $sth->execute(
1179 $auser, $branchcode, $aqbooksellerid, $cost,
1180 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1181 $dow, "$irregularity", $numberpattern, $numberlength,
1182 $weeklength, $monthlength, $add1, $every1,
1183 $whenmorethan1, $setto1, $lastvalue1, $innerloop1,
1184 $add2, $every2, $whenmorethan2, $setto2,
1185 $lastvalue2, $innerloop2, $add3, $every3,
1186 $whenmorethan3, $setto3, $lastvalue3, $innerloop3,
1187 $numberingmethod, $status, $biblionumber, $callnumber,
1188 $notes, $letter, $hemisphere, ( $manualhistory ? $manualhistory : 0 ),
1189 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1190 $graceperiod, $location, $enddate, $subscriptionid
1192 my $rows = $sth->rows;
1194 logaction( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1195 return $rows;
1198 =head2 NewSubscription
1200 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1201 $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
1202 $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
1203 $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
1204 $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
1205 $numberingmethod, $status, $notes, $serialsadditems,
1206 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate);
1208 Create a new subscription with value given on input args.
1210 return :
1211 the id of this new subscription
1213 =cut
1215 sub NewSubscription {
1216 my ($auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber, $startdate, $periodicity,
1217 $dow, $numberlength, $weeklength, $monthlength, $add1, $every1, $whenmorethan1, $setto1,
1218 $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2, $lastvalue2, $innerloop2,
1219 $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3, $numberingmethod, $status,
1220 $notes, $letter, $firstacquidate, $irregularity, $numberpattern, $callnumber, $hemisphere, $manualhistory,
1221 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate
1222 ) = @_;
1223 my $dbh = C4::Context->dbh;
1225 #save subscription (insert into database)
1226 my $query = qq|
1227 INSERT INTO subscription
1228 (librarian,branchcode,aqbooksellerid,cost,aqbudgetid,biblionumber,
1229 startdate,periodicity,dow,numberlength,weeklength,monthlength,
1230 add1,every1,whenmorethan1,setto1,lastvalue1,innerloop1,
1231 add2,every2,whenmorethan2,setto2,lastvalue2,innerloop2,
1232 add3,every3,whenmorethan3,setto3,lastvalue3,innerloop3,
1233 numberingmethod, status, notes, letter,firstacquidate,irregularity,
1234 numberpattern, callnumber, hemisphere,manualhistory,internalnotes,serialsadditems,
1235 staffdisplaycount,opacdisplaycount,graceperiod,location,enddate)
1236 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
1238 my $sth = $dbh->prepare($query);
1239 $sth->execute(
1240 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber, $startdate, $periodicity,
1241 $dow, $numberlength, $weeklength, $monthlength, $add1, $every1, $whenmorethan1, $setto1,
1242 $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2, $lastvalue2, $innerloop2,
1243 $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3, $numberingmethod, "$status",
1244 $notes, $letter, $firstacquidate, $irregularity, $numberpattern, $callnumber, $hemisphere, $manualhistory,
1245 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate
1248 my $subscriptionid = $dbh->{'mysql_insertid'};
1249 unless ($enddate){
1250 $enddate = GetExpirationDate($subscriptionid,$startdate);
1251 $query = q|
1252 UPDATE subscription
1253 SET enddate=?
1254 WHERE subscriptionid=?
1256 $sth = $dbh->prepare($query);
1257 $sth->execute( $enddate, $subscriptionid );
1259 #then create the 1st waited number
1260 $query = qq(
1261 INSERT INTO subscriptionhistory
1262 (biblionumber, subscriptionid, histstartdate, opacnote, librariannote)
1263 VALUES (?,?,?,?,?)
1265 $sth = $dbh->prepare($query);
1266 $sth->execute( $biblionumber, $subscriptionid, $startdate, $notes, $internalnotes );
1268 # reread subscription to get a hash (for calculation of the 1st issue number)
1269 $query = qq(
1270 SELECT *
1271 FROM subscription
1272 WHERE subscriptionid = ?
1274 $sth = $dbh->prepare($query);
1275 $sth->execute($subscriptionid);
1276 my $val = $sth->fetchrow_hashref;
1278 # calculate issue number
1279 my $serialseq = GetSeq($val);
1280 $query = qq|
1281 INSERT INTO serial
1282 (serialseq,subscriptionid,biblionumber,status, planneddate, publisheddate)
1283 VALUES (?,?,?,?,?,?)
1285 $sth = $dbh->prepare($query);
1286 $sth->execute( "$serialseq", $subscriptionid, $biblionumber, 1, $firstacquidate, $firstacquidate );
1288 logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1290 #set serial flag on biblio if not already set.
1291 my ( $null, ($bib) ) = GetBiblio($biblionumber);
1292 if ( !$bib->{'serial'} ) {
1293 my $record = GetMarcBiblio($biblionumber);
1294 my ( $tag, $subf ) = GetMarcFromKohaField( 'biblio.serial', $bib->{'frameworkcode'} );
1295 if ($tag) {
1296 eval { $record->field($tag)->update( $subf => 1 ); };
1298 ModBiblio( $record, $biblionumber, $bib->{'frameworkcode'} );
1300 return $subscriptionid;
1303 =head2 ReNewSubscription
1305 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1307 this function renew a subscription with values given on input args.
1309 =cut
1311 sub ReNewSubscription {
1312 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1313 my $dbh = C4::Context->dbh;
1314 my $subscription = GetSubscription($subscriptionid);
1315 my $query = qq|
1316 SELECT *
1317 FROM biblio
1318 LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
1319 WHERE biblio.biblionumber=?
1321 my $sth = $dbh->prepare($query);
1322 $sth->execute( $subscription->{biblionumber} );
1323 my $biblio = $sth->fetchrow_hashref;
1325 if ( C4::Context->preference("RenewSerialAddsSuggestion") ) {
1326 require C4::Suggestions;
1327 C4::Suggestions::NewSuggestion(
1328 { 'suggestedby' => $user,
1329 'title' => $subscription->{bibliotitle},
1330 'author' => $biblio->{author},
1331 'publishercode' => $biblio->{publishercode},
1332 'note' => $biblio->{note},
1333 'biblionumber' => $subscription->{biblionumber}
1338 # renew subscription
1339 $query = qq|
1340 UPDATE subscription
1341 SET startdate=?,numberlength=?,weeklength=?,monthlength=?
1342 WHERE subscriptionid=?
1344 $sth = $dbh->prepare($query);
1345 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1346 my $enddate = GetExpirationDate($subscriptionid);
1347 $debug && warn "enddate :$enddate";
1348 $query = qq|
1349 UPDATE subscription
1350 SET enddate=?
1351 WHERE subscriptionid=?
1353 $sth = $dbh->prepare($query);
1354 $sth->execute( $enddate, $subscriptionid );
1355 $query = qq|
1356 UPDATE subscriptionhistory
1357 SET histenddate=?
1358 WHERE subscriptionid=?
1360 $sth = $dbh->prepare($query);
1361 $sth->execute( $enddate, $subscriptionid );
1363 logaction( "SERIAL", "RENEW", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1364 return;
1367 =head2 NewIssue
1369 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1371 Create a new issue stored on the database.
1372 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1373 returns the serial id
1375 =cut
1377 sub NewIssue {
1378 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate, $publisheddate, $notes ) = @_;
1379 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1381 my $dbh = C4::Context->dbh;
1382 my $query = qq|
1383 INSERT INTO serial
1384 (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,notes)
1385 VALUES (?,?,?,?,?,?,?)
1387 my $sth = $dbh->prepare($query);
1388 $sth->execute( $serialseq, $subscriptionid, $biblionumber, $status, $publisheddate, $planneddate, $notes );
1389 my $serialid = $dbh->{'mysql_insertid'};
1390 $query = qq|
1391 SELECT missinglist,recievedlist
1392 FROM subscriptionhistory
1393 WHERE subscriptionid=?
1395 $sth = $dbh->prepare($query);
1396 $sth->execute($subscriptionid);
1397 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1399 if ( $status == 2 ) {
1400 ### TODO Add a feature that improves recognition and description.
1401 ### As such count (serialseq) i.e. : N18,2(N19),N20
1402 ### Would use substr and index But be careful to previous presence of ()
1403 $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
1405 if ( $status == 4 ) {
1406 $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
1408 $query = qq|
1409 UPDATE subscriptionhistory
1410 SET recievedlist=?, missinglist=?
1411 WHERE subscriptionid=?
1413 $sth = $dbh->prepare($query);
1414 $recievedlist =~ s/^; //;
1415 $missinglist =~ s/^; //;
1416 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1417 return $serialid;
1420 =head2 ItemizeSerials
1422 ItemizeSerials($serialid, $info);
1423 $info is a hashref containing barcode branch, itemcallnumber, status, location
1424 $serialid the serialid
1425 return :
1426 1 if the itemize is a succes.
1427 0 and @error otherwise. @error containts the list of errors found.
1429 =cut
1431 sub ItemizeSerials {
1432 my ( $serialid, $info ) = @_;
1433 my $now = POSIX::strftime( "%Y-%m-%d", localtime );
1435 my $dbh = C4::Context->dbh;
1436 my $query = qq|
1437 SELECT *
1438 FROM serial
1439 WHERE serialid=?
1441 my $sth = $dbh->prepare($query);
1442 $sth->execute($serialid);
1443 my $data = $sth->fetchrow_hashref;
1444 if ( C4::Context->preference("RoutingSerials") ) {
1446 # check for existing biblioitem relating to serial issue
1447 my ( $count, @results ) = GetBiblioItemByBiblioNumber( $data->{'biblionumber'} );
1448 my $bibitemno = 0;
1449 for ( my $i = 0 ; $i < $count ; $i++ ) {
1450 if ( $results[$i]->{'volumeddesc'} eq $data->{'serialseq'} . ' (' . $data->{'planneddate'} . ')' ) {
1451 $bibitemno = $results[$i]->{'biblioitemnumber'};
1452 last;
1455 if ( $bibitemno == 0 ) {
1456 my $sth = $dbh->prepare( "SELECT * FROM biblioitems WHERE biblionumber = ? ORDER BY biblioitemnumber DESC" );
1457 $sth->execute( $data->{'biblionumber'} );
1458 my $biblioitem = $sth->fetchrow_hashref;
1459 $biblioitem->{'volumedate'} = $data->{planneddate};
1460 $biblioitem->{'volumeddesc'} = $data->{serialseq} . ' (' . format_date( $data->{'planneddate'} ) . ')';
1461 $biblioitem->{'dewey'} = $info->{itemcallnumber};
1465 my $fwk = GetFrameworkCode( $data->{'biblionumber'} );
1466 if ( $info->{barcode} ) {
1467 my @errors;
1468 if ( is_barcode_in_use( $info->{barcode} ) ) {
1469 push @errors, 'barcode_not_unique';
1470 } else {
1471 my $marcrecord = MARC::Record->new();
1472 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.barcode", $fwk );
1473 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{barcode} );
1474 $marcrecord->insert_fields_ordered($newField);
1475 if ( $info->{branch} ) {
1476 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.homebranch", $fwk );
1478 #warn "items.homebranch : $tag , $subfield";
1479 if ( $marcrecord->field($tag) ) {
1480 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1481 } else {
1482 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1483 $marcrecord->insert_fields_ordered($newField);
1485 ( $tag, $subfield ) = GetMarcFromKohaField( "items.holdingbranch", $fwk );
1487 #warn "items.holdingbranch : $tag , $subfield";
1488 if ( $marcrecord->field($tag) ) {
1489 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1490 } else {
1491 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1492 $marcrecord->insert_fields_ordered($newField);
1495 if ( $info->{itemcallnumber} ) {
1496 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemcallnumber", $fwk );
1498 if ( $marcrecord->field($tag) ) {
1499 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{itemcallnumber} );
1500 } else {
1501 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{itemcallnumber} );
1502 $marcrecord->insert_fields_ordered($newField);
1505 if ( $info->{notes} ) {
1506 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemnotes", $fwk );
1508 if ( $marcrecord->field($tag) ) {
1509 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{notes} );
1510 } else {
1511 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{notes} );
1512 $marcrecord->insert_fields_ordered($newField);
1515 if ( $info->{location} ) {
1516 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.location", $fwk );
1518 if ( $marcrecord->field($tag) ) {
1519 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{location} );
1520 } else {
1521 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{location} );
1522 $marcrecord->insert_fields_ordered($newField);
1525 if ( $info->{status} ) {
1526 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.notforloan", $fwk );
1528 if ( $marcrecord->field($tag) ) {
1529 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{status} );
1530 } else {
1531 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{status} );
1532 $marcrecord->insert_fields_ordered($newField);
1535 if ( C4::Context->preference("RoutingSerials") ) {
1536 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.dateaccessioned", $fwk );
1537 if ( $marcrecord->field($tag) ) {
1538 $marcrecord->field($tag)->add_subfields( "$subfield" => $now );
1539 } else {
1540 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $now );
1541 $marcrecord->insert_fields_ordered($newField);
1544 require C4::Items;
1545 C4::Items::AddItemFromMarc( $marcrecord, $data->{'biblionumber'} );
1546 return 1;
1548 return ( 0, @errors );
1552 =head2 HasSubscriptionStrictlyExpired
1554 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1556 the subscription has stricly expired when today > the end subscription date
1558 return :
1559 1 if true, 0 if false, -1 if the expiration date is not set.
1561 =cut
1563 sub HasSubscriptionStrictlyExpired {
1565 # Getting end of subscription date
1566 my ($subscriptionid) = @_;
1567 my $dbh = C4::Context->dbh;
1568 my $subscription = GetSubscription($subscriptionid);
1569 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1571 # If the expiration date is set
1572 if ( $expirationdate != 0 ) {
1573 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1575 # Getting today's date
1576 my ( $nowyear, $nowmonth, $nowday ) = Today();
1578 # if today's date > expiration date, then the subscription has stricly expired
1579 if ( Delta_Days( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1580 return 1;
1581 } else {
1582 return 0;
1584 } else {
1586 # There are some cases where the expiration date is not set
1587 # As we can't determine if the subscription has expired on a date-basis,
1588 # we return -1;
1589 return -1;
1593 =head2 HasSubscriptionExpired
1595 $has_expired = HasSubscriptionExpired($subscriptionid)
1597 the subscription has expired when the next issue to arrive is out of subscription limit.
1599 return :
1600 0 if the subscription has not expired
1601 1 if the subscription has expired
1602 2 if has subscription does not have a valid expiration date set
1604 =cut
1606 sub HasSubscriptionExpired {
1607 my ($subscriptionid) = @_;
1608 my $dbh = C4::Context->dbh;
1609 my $subscription = GetSubscription($subscriptionid);
1610 if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
1611 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1612 if (!defined $expirationdate) {
1613 $expirationdate = q{};
1615 my $query = qq|
1616 SELECT max(planneddate)
1617 FROM serial
1618 WHERE subscriptionid=?
1620 my $sth = $dbh->prepare($query);
1621 $sth->execute($subscriptionid);
1622 my ($res) = $sth->fetchrow;
1623 if (!$res || $res=~m/^0000/) {
1624 return 0;
1626 my @res = split( /-/, $res );
1627 my @endofsubscriptiondate = split( /-/, $expirationdate );
1628 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date(@res) || not check_date(@endofsubscriptiondate) );
1629 return 1
1630 if ( ( @endofsubscriptiondate && Delta_Days( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1631 || ( !$res ) );
1632 return 0;
1633 } else {
1634 if ( $subscription->{'numberlength'} ) {
1635 my $countreceived = countissuesfrom( $subscriptionid, $subscription->{'startdate'} );
1636 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1637 return 0;
1638 } else {
1639 return 0;
1642 return 0; # Notice that you'll never get here.
1645 =head2 SetDistributedto
1647 SetDistributedto($distributedto,$subscriptionid);
1648 This function update the value of distributedto for a subscription given on input arg.
1650 =cut
1652 sub SetDistributedto {
1653 my ( $distributedto, $subscriptionid ) = @_;
1654 my $dbh = C4::Context->dbh;
1655 my $query = qq|
1656 UPDATE subscription
1657 SET distributedto=?
1658 WHERE subscriptionid=?
1660 my $sth = $dbh->prepare($query);
1661 $sth->execute( $distributedto, $subscriptionid );
1662 return;
1665 =head2 DelSubscription
1667 DelSubscription($subscriptionid)
1668 this function deletes subscription which has $subscriptionid as id.
1670 =cut
1672 sub DelSubscription {
1673 my ($subscriptionid) = @_;
1674 my $dbh = C4::Context->dbh;
1675 $subscriptionid = $dbh->quote($subscriptionid);
1676 $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
1677 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
1678 $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
1680 logaction( "SERIAL", "DELETE", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1683 =head2 DelIssue
1685 DelIssue($serialseq,$subscriptionid)
1686 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1688 returns the number of rows affected
1690 =cut
1692 sub DelIssue {
1693 my ($dataissue) = @_;
1694 my $dbh = C4::Context->dbh;
1695 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1697 my $query = qq|
1698 DELETE FROM serial
1699 WHERE serialid= ?
1700 AND subscriptionid= ?
1702 my $mainsth = $dbh->prepare($query);
1703 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1705 #Delete element from subscription history
1706 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1707 my $sth = $dbh->prepare($query);
1708 $sth->execute( $dataissue->{'subscriptionid'} );
1709 my $val = $sth->fetchrow_hashref;
1710 unless ( $val->{manualhistory} ) {
1711 my $query = qq|
1712 SELECT * FROM subscriptionhistory
1713 WHERE subscriptionid= ?
1715 my $sth = $dbh->prepare($query);
1716 $sth->execute( $dataissue->{'subscriptionid'} );
1717 my $data = $sth->fetchrow_hashref;
1718 my $serialseq = $dataissue->{'serialseq'};
1719 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1720 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1721 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1722 $sth = $dbh->prepare($strsth);
1723 $sth->execute( $dataissue->{'subscriptionid'} );
1726 return $mainsth->rows;
1729 =head2 GetLateOrMissingIssues
1731 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1733 this function selects missing issues on database - where serial.status = 4 or serial.status=3 or planneddate<now
1735 return :
1736 the issuelist as an array of hash refs. Each element of this array contains
1737 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1739 =cut
1741 sub GetLateOrMissingIssues {
1742 my ( $supplierid, $serialid, $order ) = @_;
1743 my $dbh = C4::Context->dbh;
1744 my $sth;
1745 my $byserial = '';
1746 if ($serialid) {
1747 $byserial = "and serialid = " . $serialid;
1749 if ($order) {
1750 $order .= ", title";
1751 } else {
1752 $order = "title";
1754 if ($supplierid) {
1755 $sth = $dbh->prepare(
1756 "SELECT
1757 serialid, aqbooksellerid, name,
1758 biblio.title, planneddate, serialseq,
1759 serial.status, serial.subscriptionid, claimdate,
1760 subscription.branchcode
1761 FROM serial
1762 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1763 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1764 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1765 WHERE subscription.subscriptionid = serial.subscriptionid
1766 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
1767 AND subscription.aqbooksellerid=$supplierid
1768 $byserial
1769 ORDER BY $order"
1771 } else {
1772 $sth = $dbh->prepare(
1773 "SELECT
1774 serialid, aqbooksellerid, name,
1775 biblio.title, planneddate, serialseq,
1776 serial.status, serial.subscriptionid, claimdate,
1777 subscription.branchcode
1778 FROM serial
1779 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1780 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1781 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1782 WHERE subscription.subscriptionid = serial.subscriptionid
1783 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
1784 $byserial
1785 ORDER BY $order"
1788 $sth->execute;
1789 my @issuelist;
1790 while ( my $line = $sth->fetchrow_hashref ) {
1792 if ($line->{planneddate} && $line->{planneddate} !~/^0+\-/) {
1793 $line->{planneddate} = format_date( $line->{planneddate} );
1795 if ($line->{claimdate} && $line->{claimdate} !~/^0+\-/) {
1796 $line->{claimdate} = format_date( $line->{claimdate} );
1798 $line->{"status".$line->{status}} = 1;
1799 push @issuelist, $line;
1801 return @issuelist;
1804 =head2 removeMissingIssue
1806 removeMissingIssue($subscriptionid)
1808 this function removes an issue from being part of the missing string in
1809 subscriptionlist.missinglist column
1811 called when a missing issue is found from the serials-recieve.pl file
1813 =cut
1815 sub removeMissingIssue {
1816 my ( $sequence, $subscriptionid ) = @_;
1817 my $dbh = C4::Context->dbh;
1818 my $sth = $dbh->prepare("SELECT * FROM subscriptionhistory WHERE subscriptionid = ?");
1819 $sth->execute($subscriptionid);
1820 my $data = $sth->fetchrow_hashref;
1821 my $missinglist = $data->{'missinglist'};
1822 my $missinglistbefore = $missinglist;
1824 # warn $missinglist." before";
1825 $missinglist =~ s/($sequence)//;
1827 # warn $missinglist." after";
1828 if ( $missinglist ne $missinglistbefore ) {
1829 $missinglist =~ s/\|\s\|/\|/g;
1830 $missinglist =~ s/^\| //g;
1831 $missinglist =~ s/\|$//g;
1832 my $sth2 = $dbh->prepare(
1833 "UPDATE subscriptionhistory
1834 SET missinglist = ?
1835 WHERE subscriptionid = ?"
1837 $sth2->execute( $missinglist, $subscriptionid );
1839 return;
1842 =head2 updateClaim
1844 &updateClaim($serialid)
1846 this function updates the time when a claim is issued for late/missing items
1848 called from claims.pl file
1850 =cut
1852 sub updateClaim {
1853 my ($serialid) = @_;
1854 my $dbh = C4::Context->dbh;
1855 my $sth = $dbh->prepare(
1856 "UPDATE serial SET claimdate = now()
1857 WHERE serialid = ?
1860 $sth->execute($serialid);
1861 return;
1864 =head2 getsupplierbyserialid
1866 $result = getsupplierbyserialid($serialid)
1868 this function is used to find the supplier id given a serial id
1870 return :
1871 hashref containing serialid, subscriptionid, and aqbooksellerid
1873 =cut
1875 sub getsupplierbyserialid {
1876 my ($serialid) = @_;
1877 my $dbh = C4::Context->dbh;
1878 my $sth = $dbh->prepare(
1879 "SELECT serialid, serial.subscriptionid, aqbooksellerid
1880 FROM serial
1881 LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
1882 WHERE serialid = ?
1885 $sth->execute($serialid);
1886 my $line = $sth->fetchrow_hashref;
1887 my $result = $line->{'aqbooksellerid'};
1888 return $result;
1891 =head2 check_routing
1893 $result = &check_routing($subscriptionid)
1895 this function checks to see if a serial has a routing list and returns the count of routingid
1896 used to show either an 'add' or 'edit' link
1898 =cut
1900 sub check_routing {
1901 my ($subscriptionid) = @_;
1902 my $dbh = C4::Context->dbh;
1903 my $sth = $dbh->prepare(
1904 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1905 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1906 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
1909 $sth->execute($subscriptionid);
1910 my $line = $sth->fetchrow_hashref;
1911 my $result = $line->{'routingids'};
1912 return $result;
1915 =head2 addroutingmember
1917 addroutingmember($borrowernumber,$subscriptionid)
1919 this function takes a borrowernumber and subscriptionid and adds the member to the
1920 routing list for that serial subscription and gives them a rank on the list
1921 of either 1 or highest current rank + 1
1923 =cut
1925 sub addroutingmember {
1926 my ( $borrowernumber, $subscriptionid ) = @_;
1927 my $rank;
1928 my $dbh = C4::Context->dbh;
1929 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1930 $sth->execute($subscriptionid);
1931 while ( my $line = $sth->fetchrow_hashref ) {
1932 if ( $line->{'rank'} > 0 ) {
1933 $rank = $line->{'rank'} + 1;
1934 } else {
1935 $rank = 1;
1938 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1939 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1942 =head2 reorder_members
1944 reorder_members($subscriptionid,$routingid,$rank)
1946 this function is used to reorder the routing list
1948 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1949 - it gets all members on list puts their routingid's into an array
1950 - removes the one in the array that is $routingid
1951 - then reinjects $routingid at point indicated by $rank
1952 - then update the database with the routingids in the new order
1954 =cut
1956 sub reorder_members {
1957 my ( $subscriptionid, $routingid, $rank ) = @_;
1958 my $dbh = C4::Context->dbh;
1959 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1960 $sth->execute($subscriptionid);
1961 my @result;
1962 while ( my $line = $sth->fetchrow_hashref ) {
1963 push( @result, $line->{'routingid'} );
1966 # To find the matching index
1967 my $i;
1968 my $key = -1; # to allow for 0 being a valid response
1969 for ( $i = 0 ; $i < @result ; $i++ ) {
1970 if ( $routingid == $result[$i] ) {
1971 $key = $i; # save the index
1972 last;
1976 # if index exists in array then move it to new position
1977 if ( $key > -1 && $rank > 0 ) {
1978 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1979 my $moving_item = splice( @result, $key, 1 );
1980 splice( @result, $new_rank, 0, $moving_item );
1982 for ( my $j = 0 ; $j < @result ; $j++ ) {
1983 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1984 $sth->execute;
1986 return;
1989 =head2 delroutingmember
1991 delroutingmember($routingid,$subscriptionid)
1993 this function either deletes one member from routing list if $routingid exists otherwise
1994 deletes all members from the routing list
1996 =cut
1998 sub delroutingmember {
2000 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2001 my ( $routingid, $subscriptionid ) = @_;
2002 my $dbh = C4::Context->dbh;
2003 if ($routingid) {
2004 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2005 $sth->execute($routingid);
2006 reorder_members( $subscriptionid, $routingid );
2007 } else {
2008 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2009 $sth->execute($subscriptionid);
2011 return;
2014 =head2 getroutinglist
2016 @routinglist = getroutinglist($subscriptionid)
2018 this gets the info from the subscriptionroutinglist for $subscriptionid
2020 return :
2021 the routinglist as an array. Each element of the array contains a hash_ref containing
2022 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2024 =cut
2026 sub getroutinglist {
2027 my ($subscriptionid) = @_;
2028 my $dbh = C4::Context->dbh;
2029 my $sth = $dbh->prepare(
2030 'SELECT routingid, borrowernumber, ranking, biblionumber
2031 FROM subscription
2032 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2033 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2035 $sth->execute($subscriptionid);
2036 my $routinglist = $sth->fetchall_arrayref({});
2037 return @{$routinglist};
2040 =head2 countissuesfrom
2042 $result = countissuesfrom($subscriptionid,$startdate)
2044 Returns a count of serial rows matching the given subsctiptionid
2045 with published date greater than startdate
2047 =cut
2049 sub countissuesfrom {
2050 my ( $subscriptionid, $startdate ) = @_;
2051 my $dbh = C4::Context->dbh;
2052 my $query = qq|
2053 SELECT count(*)
2054 FROM serial
2055 WHERE subscriptionid=?
2056 AND serial.publisheddate>?
2058 my $sth = $dbh->prepare($query);
2059 $sth->execute( $subscriptionid, $startdate );
2060 my ($countreceived) = $sth->fetchrow;
2061 return $countreceived;
2064 =head2 CountIssues
2066 $result = CountIssues($subscriptionid)
2068 Returns a count of serial rows matching the given subsctiptionid
2070 =cut
2072 sub CountIssues {
2073 my ($subscriptionid) = @_;
2074 my $dbh = C4::Context->dbh;
2075 my $query = qq|
2076 SELECT count(*)
2077 FROM serial
2078 WHERE subscriptionid=?
2080 my $sth = $dbh->prepare($query);
2081 $sth->execute($subscriptionid);
2082 my ($countreceived) = $sth->fetchrow;
2083 return $countreceived;
2086 =head2 HasItems
2088 $result = HasItems($subscriptionid)
2090 returns a count of items from serial matching the subscriptionid
2092 =cut
2094 sub HasItems {
2095 my ($subscriptionid) = @_;
2096 my $dbh = C4::Context->dbh;
2097 my $query = q|
2098 SELECT COUNT(serialitems.itemnumber)
2099 FROM serial
2100 LEFT JOIN serialitems USING(serialid)
2101 WHERE subscriptionid=? AND serialitems.serialid IS NOT NULL
2103 my $sth=$dbh->prepare($query);
2104 $sth->execute($subscriptionid);
2105 my ($countitems)=$sth->fetchrow_array();
2106 return $countitems;
2109 =head2 abouttoexpire
2111 $result = abouttoexpire($subscriptionid)
2113 this function alerts you to the penultimate issue for a serial subscription
2115 returns 1 - if this is the penultimate issue
2116 returns 0 - if not
2118 =cut
2120 sub abouttoexpire {
2121 my ($subscriptionid) = @_;
2122 my $dbh = C4::Context->dbh;
2123 my $subscription = GetSubscription($subscriptionid);
2124 my $per = $subscription->{'periodicity'};
2125 if ($per && $per % 16 > 0){
2126 my $expirationdate = GetExpirationDate($subscriptionid);
2127 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2128 my @res;
2129 if (defined $res) {
2130 @res=split (/-/,$res);
2131 @res=Date::Calc::Today if ($res[0]*$res[1]==0);
2132 } else { # default an undefined value
2133 @res=Date::Calc::Today;
2135 my @endofsubscriptiondate=split(/-/,$expirationdate);
2136 my @per_list = (0, 7, 7, 14, 21, 31, 62, 93, 93, 190, 365, 730, 0, 124, 0, 0);
2137 my @datebeforeend;
2138 @datebeforeend = Add_Delta_Days( $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2],
2139 - (3 * $per_list[$per])) if (@endofsubscriptiondate && $endofsubscriptiondate[0]*$endofsubscriptiondate[1]*$endofsubscriptiondate[2]);
2140 return 1 if ( @res &&
2141 (@datebeforeend &&
2142 Delta_Days($res[0],$res[1],$res[2],
2143 $datebeforeend[0],$datebeforeend[1],$datebeforeend[2]) <= 0) &&
2144 (@endofsubscriptiondate &&
2145 Delta_Days($res[0],$res[1],$res[2],
2146 $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) >= 0) );
2147 return 0;
2148 } elsif ($subscription->{numberlength}>0) {
2149 return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
2151 return 0;
2154 sub in_array { # used in next sub down
2155 my ( $val, @elements ) = @_;
2156 foreach my $elem (@elements) {
2157 if ( $val == $elem ) {
2158 return 1;
2161 return 0;
2164 =head2 GetNextDate
2166 $resultdate = GetNextDate($planneddate,$subscription)
2168 this function it takes the planneddate and will return the next issue's date and will skip dates if there
2169 exists an irregularity
2170 - eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be
2171 skipped then the returned date will be 2007-05-10
2173 return :
2174 $resultdate - then next date in the sequence
2176 Return 0 if periodicity==0
2178 =cut
2180 sub GetNextDate(@) {
2181 my ( $planneddate, $subscription ) = @_;
2182 my @irreg = split( /\,/, $subscription->{irregularity} );
2184 #date supposed to be in ISO.
2186 my ( $year, $month, $day ) = split( /-/, $planneddate );
2187 $month = 1 unless ($month);
2188 $day = 1 unless ($day);
2189 my @resultdate;
2191 # warn "DOW $dayofweek";
2192 if ( $subscription->{periodicity} % 16 == 0 ) { # 'without regularity' || 'irregular'
2193 return 0;
2196 # daily : n / week
2197 # Since we're interpreting irregularity here as which days of the week to skip an issue,
2198 # renaming this pattern from 1/day to " n / week ".
2199 if ( $subscription->{periodicity} == 1 ) {
2200 my $dayofweek = eval { Day_of_Week( $year, $month, $day ) };
2201 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2202 else {
2203 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2204 $dayofweek = 0 if ( $dayofweek == 7 );
2205 if ( in_array( ( $dayofweek + 1 ), @irreg ) ) {
2206 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 1 );
2207 $dayofweek++;
2210 @resultdate = Add_Delta_Days( $year, $month, $day, 1 );
2214 # 1 week
2215 if ( $subscription->{periodicity} == 2 ) {
2216 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2217 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2218 else {
2219 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2221 #FIXME: if two consecutive irreg, do we only skip one?
2222 if ( $irreg[$i] == ( ( $wkno != 51 ) ? ( $wkno + 1 ) % 52 : 52 ) ) {
2223 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 7 );
2224 $wkno = ( ( $wkno != 51 ) ? ( $wkno + 1 ) % 52 : 52 );
2227 @resultdate = Add_Delta_Days( $year, $month, $day, 7 );
2231 # 1 / 2 weeks
2232 if ( $subscription->{periodicity} == 3 ) {
2233 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2234 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2235 else {
2236 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2237 if ( $irreg[$i] == ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 ) ) {
2238 ### BUGFIX was previously +1 ^
2239 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 14 );
2240 $wkno = ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 );
2243 @resultdate = Add_Delta_Days( $year, $month, $day, 14 );
2247 # 1 / 3 weeks
2248 if ( $subscription->{periodicity} == 4 ) {
2249 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2250 if ($@) { warn "année mois jour : $year $month $day $subscription->{subscriptionid} : $@"; }
2251 else {
2252 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2253 if ( $irreg[$i] == ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 ) ) {
2254 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 21 );
2255 $wkno = ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 );
2258 @resultdate = Add_Delta_Days( $year, $month, $day, 21 );
2261 my $tmpmonth = $month;
2262 if ( $year && $month && $day ) {
2263 if ( $subscription->{periodicity} == 5 ) {
2264 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2265 if ( $irreg[$i] == ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 ) ) {
2266 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
2267 $tmpmonth = ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 );
2270 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
2272 if ( $subscription->{periodicity} == 6 ) {
2273 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2274 if ( $irreg[$i] == ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 ) ) {
2275 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
2276 $tmpmonth = ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 );
2279 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
2281 if ( $subscription->{periodicity} == 7 ) {
2282 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2283 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2284 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2285 $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
2288 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2290 if ( $subscription->{periodicity} == 8 ) {
2291 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2292 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2293 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2294 $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
2297 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2299 if ( $subscription->{periodicity} == 13 ) {
2300 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2301 if ( $irreg[$i] == ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 ) ) {
2302 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
2303 $tmpmonth = ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 );
2306 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
2308 if ( $subscription->{periodicity} == 9 ) {
2309 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2310 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2311 ### BUFIX Seems to need more Than One ?
2312 ( $year, $month, $day ) = Add_Delta_YM( $year, $month, $day, 0, 6 );
2313 $tmpmonth = ( ( $tmpmonth != 6 ) ? ( $tmpmonth + 6 ) % 12 : 12 );
2316 @resultdate = Add_Delta_YM( $year, $month, $day, 0, 6 );
2318 if ( $subscription->{periodicity} == 10 ) {
2319 @resultdate = Add_Delta_YM( $year, $month, $day, 1, 0 );
2321 if ( $subscription->{periodicity} == 11 ) {
2322 @resultdate = Add_Delta_YM( $year, $month, $day, 2, 0 );
2325 my $resultdate = sprintf( "%04d-%02d-%02d", $resultdate[0], $resultdate[1], $resultdate[2] );
2327 return "$resultdate";
2330 =head2 is_barcode_in_use
2332 Returns number of occurence of the barcode in the items table
2333 Can be used as a boolean test of whether the barcode has
2334 been deployed as yet
2336 =cut
2338 sub is_barcode_in_use {
2339 my $barcode = shift;
2340 my $dbh = C4::Context->dbh;
2341 my $occurences = $dbh->selectall_arrayref(
2342 'SELECT itemnumber from items where barcode = ?',
2343 {}, $barcode
2347 return @{$occurences};
2351 __END__
2353 =head1 AUTHOR
2355 Koha Development Team <http://koha-community.org/>
2357 =cut