Bug 8227 Fix deprecated construct compile time warning in Serials
[koha.git] / C4 / Serials.pm
blob58b6078c28255ce0ef9338c529b08b8259d526e8
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.07.00.049; # 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,$ean,$biblionumber);
549 this function gets all subscriptions which have title like $title,ISSN like $ISSN,EAN like $ean 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, $ean, $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 = q{};
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 if ($ean) {
601 my @sqlstrings;
602 my @strings_to_search;
603 @strings_to_search = map { "$_" } split( / /, $ean );
604 foreach my $index ( qw(biblioitems.ean) ) {
605 push @bind_params, @strings_to_search;
606 my $tmpstring = "OR $index = ? " x scalar(@strings_to_search);
607 $debug && warn "$tmpstring";
608 $tmpstring =~ s/^OR //;
609 push @sqlstrings, $tmpstring;
611 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
614 $sql .= "$sqlwhere ORDER BY title";
615 $debug and warn "GetSubscriptions query: $sql params : ", join( " ", @bind_params );
616 $sth = $dbh->prepare($sql);
617 $sth->execute(@bind_params);
618 my @results;
620 while ( my $line = $sth->fetchrow_hashref ) {
621 $line->{'cannotedit'} =
622 ( C4::Context->preference('IndependantBranches')
623 && C4::Context->userenv
624 && C4::Context->userenv->{flags} % 2 != 1
625 && C4::Context->userenv->{branch}
626 && $line->{branchcode}
627 && ( C4::Context->userenv->{branch} ne $line->{branchcode} ) );
628 push @results, $line;
630 return @results;
633 =head2 GetSerials
635 ($totalissues,@serials) = GetSerials($subscriptionid);
636 this function gets every serial not arrived for a given subscription
637 as well as the number of issues registered in the database (all types)
638 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
640 FIXME: We should return \@serials.
642 =cut
644 sub GetSerials {
645 my ( $subscriptionid, $count ) = @_;
646 my $dbh = C4::Context->dbh;
648 # status = 2 is "arrived"
649 my $counter = 0;
650 $count = 5 unless ($count);
651 my @serials;
652 my $query = "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
653 FROM serial
654 WHERE subscriptionid = ? AND status NOT IN (2,4,5)
655 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
656 my $sth = $dbh->prepare($query);
657 $sth->execute($subscriptionid);
659 while ( my $line = $sth->fetchrow_hashref ) {
660 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
661 for my $datefield ( qw( planneddate publisheddate) ) {
662 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
663 $line->{$datefield} = format_date( $line->{$datefield});
664 } else {
665 $line->{$datefield} = q{};
668 push @serials, $line;
671 # OK, now add the last 5 issues arrives/missing
672 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
673 FROM serial
674 WHERE subscriptionid = ?
675 AND (status in (2,4,5))
676 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
678 $sth = $dbh->prepare($query);
679 $sth->execute($subscriptionid);
680 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
681 $counter++;
682 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
683 for my $datefield ( qw( planneddate publisheddate) ) {
684 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
685 $line->{$datefield} = format_date( $line->{$datefield});
686 } else {
687 $line->{$datefield} = q{};
691 push @serials, $line;
694 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
695 $sth = $dbh->prepare($query);
696 $sth->execute($subscriptionid);
697 my ($totalissues) = $sth->fetchrow;
698 return ( $totalissues, @serials );
701 =head2 GetSerials2
703 @serials = GetSerials2($subscriptionid,$status);
704 this function returns every serial waited for a given subscription
705 as well as the number of issues registered in the database (all types)
706 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
708 =cut
710 sub GetSerials2 {
711 my ( $subscription, $status ) = @_;
712 my $dbh = C4::Context->dbh;
713 my $query = qq|
714 SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
715 FROM serial
716 WHERE subscriptionid=$subscription AND status IN ($status)
717 ORDER BY publisheddate,serialid DESC
719 $debug and warn "GetSerials2 query: $query";
720 my $sth = $dbh->prepare($query);
721 $sth->execute;
722 my @serials;
724 while ( my $line = $sth->fetchrow_hashref ) {
725 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
726 # Format dates for display
727 for my $datefield ( qw( planneddate publisheddate ) ) {
728 if ($line->{$datefield} =~m/^00/) {
729 $line->{$datefield} = q{};
731 else {
732 $line->{$datefield} = format_date( $line->{$datefield} );
735 push @serials, $line;
737 return @serials;
740 =head2 GetLatestSerials
742 \@serials = GetLatestSerials($subscriptionid,$limit)
743 get the $limit's latest serials arrived or missing for a given subscription
744 return :
745 a ref to an array which contains all of the latest serials stored into a hash.
747 =cut
749 sub GetLatestSerials {
750 my ( $subscriptionid, $limit ) = @_;
751 my $dbh = C4::Context->dbh;
753 # status = 2 is "arrived"
754 my $strsth = "SELECT serialid,serialseq, status, planneddate, notes
755 FROM serial
756 WHERE subscriptionid = ?
757 AND (status =2 or status=4)
758 ORDER BY planneddate DESC LIMIT 0,$limit
760 my $sth = $dbh->prepare($strsth);
761 $sth->execute($subscriptionid);
762 my @serials;
763 while ( my $line = $sth->fetchrow_hashref ) {
764 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
765 $line->{"planneddate"} = format_date( $line->{"planneddate"} );
766 push @serials, $line;
769 return \@serials;
772 =head2 GetDistributedTo
774 $distributedto=GetDistributedTo($subscriptionid)
775 This function returns the field distributedto for the subscription matching subscriptionid
777 =cut
779 sub GetDistributedTo {
780 my $dbh = C4::Context->dbh;
781 my $distributedto;
782 my $subscriptionid = @_;
783 my $query = "SELECT distributedto FROM subscription WHERE subscriptionid=?";
784 my $sth = $dbh->prepare($query);
785 $sth->execute($subscriptionid);
786 return ($distributedto) = $sth->fetchrow;
789 =head2 GetNextSeq
791 GetNextSeq($val)
792 $val is a hashref containing all the attributes of the table 'subscription'
793 This function get the next issue for the subscription given on input arg
794 return:
795 a list containing all the input params updated.
797 =cut
799 # sub GetNextSeq {
800 # my ($val) =@_;
801 # my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
802 # $calculated = $val->{numberingmethod};
803 # # calculate the (expected) value of the next issue recieved.
804 # $newlastvalue1 = $val->{lastvalue1};
805 # # check if we have to increase the new value.
806 # $newinnerloop1 = $val->{innerloop1}+1;
807 # $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
808 # $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
809 # $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
810 # $calculated =~ s/\{X\}/$newlastvalue1/g;
812 # $newlastvalue2 = $val->{lastvalue2};
813 # # check if we have to increase the new value.
814 # $newinnerloop2 = $val->{innerloop2}+1;
815 # $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
816 # $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
817 # $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
818 # $calculated =~ s/\{Y\}/$newlastvalue2/g;
820 # $newlastvalue3 = $val->{lastvalue3};
821 # # check if we have to increase the new value.
822 # $newinnerloop3 = $val->{innerloop3}+1;
823 # $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
824 # $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
825 # $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
826 # $calculated =~ s/\{Z\}/$newlastvalue3/g;
827 # return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
830 sub GetNextSeq {
831 my ($val) = @_;
832 my ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
833 my $pattern = $val->{numberpattern};
834 my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
835 my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
836 $calculated = $val->{numberingmethod};
837 $newlastvalue1 = $val->{lastvalue1};
838 $newlastvalue2 = $val->{lastvalue2};
839 $newlastvalue3 = $val->{lastvalue3};
840 $newlastvalue1 = $val->{lastvalue1};
842 # check if we have to increase the new value.
843 $newinnerloop1 = $val->{innerloop1} + 1;
844 $newinnerloop1 = 0 if ( $newinnerloop1 >= $val->{every1} );
845 $newlastvalue1 += $val->{add1} if ( $newinnerloop1 < 1 ); # <1 to be true when 0 or empty.
846 $newlastvalue1 = $val->{setto1} if ( $newlastvalue1 > $val->{whenmorethan1} ); # reset counter if needed.
847 $calculated =~ s/\{X\}/$newlastvalue1/g;
849 $newlastvalue2 = $val->{lastvalue2};
851 # check if we have to increase the new value.
852 $newinnerloop2 = $val->{innerloop2} + 1;
853 $newinnerloop2 = 0 if ( $newinnerloop2 >= $val->{every2} );
854 $newlastvalue2 += $val->{add2} if ( $newinnerloop2 < 1 ); # <1 to be true when 0 or empty.
855 $newlastvalue2 = $val->{setto2} if ( $newlastvalue2 > $val->{whenmorethan2} ); # reset counter if needed.
856 if ( $pattern == 6 ) {
857 if ( $val->{hemisphere} == 2 ) {
858 my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
859 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
860 } else {
861 my $newlastvalue2seq = $seasons[$newlastvalue2];
862 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
864 } else {
865 $calculated =~ s/\{Y\}/$newlastvalue2/g;
868 $newlastvalue3 = $val->{lastvalue3};
870 # check if we have to increase the new value.
871 $newinnerloop3 = $val->{innerloop3} + 1;
872 $newinnerloop3 = 0 if ( $newinnerloop3 >= $val->{every3} );
873 $newlastvalue3 += $val->{add3} if ( $newinnerloop3 < 1 ); # <1 to be true when 0 or empty.
874 $newlastvalue3 = $val->{setto3} if ( $newlastvalue3 > $val->{whenmorethan3} ); # reset counter if needed.
875 $calculated =~ s/\{Z\}/$newlastvalue3/g;
877 return ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
880 =head2 GetSeq
882 $calculated = GetSeq($val)
883 $val is a hashref containing all the attributes of the table 'subscription'
884 this function transforms {X},{Y},{Z} to 150,0,0 for example.
885 return:
886 the sequence in integer format
888 =cut
890 sub GetSeq {
891 my ($val) = @_;
892 my $pattern = $val->{numberpattern};
893 my @seasons = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
894 my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
895 my $calculated = $val->{numberingmethod};
896 my $x = $val->{'lastvalue1'};
897 $calculated =~ s/\{X\}/$x/g;
898 my $newlastvalue2 = $val->{'lastvalue2'};
900 if ( $pattern == 6 ) {
901 if ( $val->{hemisphere} == 2 ) {
902 my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
903 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
904 } else {
905 my $newlastvalue2seq = $seasons[$newlastvalue2];
906 $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
908 } else {
909 $calculated =~ s/\{Y\}/$newlastvalue2/g;
911 my $z = $val->{'lastvalue3'};
912 $calculated =~ s/\{Z\}/$z/g;
913 return $calculated;
916 =head2 GetExpirationDate
918 $enddate = GetExpirationDate($subscriptionid, [$startdate])
920 this function return the next expiration date for a subscription given on input args.
922 return
923 the enddate or undef
925 =cut
927 sub GetExpirationDate {
928 my ( $subscriptionid, $startdate ) = @_;
929 my $dbh = C4::Context->dbh;
930 my $subscription = GetSubscription($subscriptionid);
931 my $enddate;
933 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
934 $enddate = $startdate || $subscription->{startdate};
935 my @date = split( /-/, $enddate );
936 return if ( scalar(@date) != 3 || not check_date(@date) );
937 if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
939 # If Not Irregular
940 if ( my $length = $subscription->{numberlength} ) {
942 #calculate the date of the last issue.
943 for ( my $i = 1 ; $i <= $length ; $i++ ) {
944 $enddate = GetNextDate( $enddate, $subscription );
946 } elsif ( $subscription->{monthlength} ) {
947 if ( $$subscription{startdate} ) {
948 my @enddate = Add_Delta_YM( $date[0], $date[1], $date[2], 0, $subscription->{monthlength} );
949 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
951 } elsif ( $subscription->{weeklength} ) {
952 if ( $$subscription{startdate} ) {
953 my @date = split( /-/, $subscription->{startdate} );
954 my @enddate = Add_Delta_Days( $date[0], $date[1], $date[2], $subscription->{weeklength} * 7 );
955 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
958 return $enddate;
959 } else {
960 return;
964 =head2 CountSubscriptionFromBiblionumber
966 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
967 this returns a count of the subscriptions for a given biblionumber
968 return :
969 the number of subscriptions
971 =cut
973 sub CountSubscriptionFromBiblionumber {
974 my ($biblionumber) = @_;
975 my $dbh = C4::Context->dbh;
976 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
977 my $sth = $dbh->prepare($query);
978 $sth->execute($biblionumber);
979 my $subscriptionsnumber = $sth->fetchrow;
980 return $subscriptionsnumber;
983 =head2 ModSubscriptionHistory
985 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
987 this function modifies the history of a subscription. Put your new values on input arg.
988 returns the number of rows affected
990 =cut
992 sub ModSubscriptionHistory {
993 my ( $subscriptionid, $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote ) = @_;
994 my $dbh = C4::Context->dbh;
995 my $query = "UPDATE subscriptionhistory
996 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
997 WHERE subscriptionid=?
999 my $sth = $dbh->prepare($query);
1000 $recievedlist =~ s/^; //;
1001 $missinglist =~ s/^; //;
1002 $opacnote =~ s/^; //;
1003 $sth->execute( $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1004 return $sth->rows;
1007 =head2 ModSerialStatus
1009 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
1011 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1012 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1014 =cut
1016 sub ModSerialStatus {
1017 my ( $serialid, $serialseq, $planneddate, $publisheddate, $status, $notes ) = @_;
1019 #It is a usual serial
1020 # 1st, get previous status :
1021 my $dbh = C4::Context->dbh;
1022 my $query = "SELECT subscriptionid,status FROM serial WHERE serialid=?";
1023 my $sth = $dbh->prepare($query);
1024 $sth->execute($serialid);
1025 my ( $subscriptionid, $oldstatus ) = $sth->fetchrow;
1027 # change status & update subscriptionhistory
1028 my $val;
1029 if ( $status == 6 ) {
1030 DelIssue( {'serialid'=>$serialid, 'subscriptionid'=>$subscriptionid,'serialseq'=>$serialseq} );
1032 else {
1033 my $query =
1034 'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE serialid = ?';
1035 $sth = $dbh->prepare($query);
1036 $sth->execute( $serialseq, $publisheddate, $planneddate, $status, $notes, $serialid );
1037 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1038 $sth = $dbh->prepare($query);
1039 $sth->execute($subscriptionid);
1040 my $val = $sth->fetchrow_hashref;
1041 unless ( $val->{manualhistory} ) {
1042 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1043 $sth = $dbh->prepare($query);
1044 $sth->execute($subscriptionid);
1045 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1046 if ( $status == 2 ) {
1048 $recievedlist .= "; $serialseq"
1049 unless ( index( "$recievedlist", "$serialseq" ) >= 0 );
1052 # warn "missinglist : $missinglist serialseq :$serialseq, ".index("$missinglist","$serialseq");
1053 $missinglist .= "; $serialseq"
1054 if ( $status == 4
1055 and not index( "$missinglist", "$serialseq" ) >= 0 );
1056 $missinglist .= "; not issued $serialseq"
1057 if ( $status == 5
1058 and index( "$missinglist", "$serialseq" ) >= 0 );
1059 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1060 $sth = $dbh->prepare($query);
1061 $recievedlist =~ s/^; //;
1062 $missinglist =~ s/^; //;
1063 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1067 # create new waited entry if needed (ie : was a "waited" and has changed)
1068 if ( $oldstatus == 1 && $status != 1 ) {
1069 my $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1070 $sth = $dbh->prepare($query);
1071 $sth->execute($subscriptionid);
1072 my $val = $sth->fetchrow_hashref;
1074 # next issue number
1075 my (
1076 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1077 $newinnerloop1, $newinnerloop2, $newinnerloop3
1078 ) = GetNextSeq($val);
1080 # next date (calculated from actual date & frequency parameters)
1081 my $nextpublisheddate = GetNextDate( $publisheddate, $val );
1082 NewIssue( $newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpublisheddate, $nextpublisheddate );
1083 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1084 WHERE subscriptionid = ?";
1085 $sth = $dbh->prepare($query);
1086 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1088 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1089 if ( $val->{letter} && $status == 2 && $oldstatus != 2 ) {
1090 require C4::Letters;
1091 C4::Letters::SendAlerts( 'issue', $val->{subscriptionid}, $val->{letter} );
1094 return;
1097 =head2 GetNextExpected
1099 $nextexpected = GetNextExpected($subscriptionid)
1101 Get the planneddate for the current expected issue of the subscription.
1103 returns a hashref:
1105 $nextexepected = {
1106 serialid => int
1107 planneddate => C4::Dates object
1110 =cut
1112 sub GetNextExpected($) {
1113 my ($subscriptionid) = @_;
1114 my $dbh = C4::Context->dbh;
1115 my $sth = $dbh->prepare('SELECT serialid, planneddate FROM serial WHERE subscriptionid=? AND status=?');
1117 # Each subscription has only one 'expected' issue, with serial.status==1.
1118 $sth->execute( $subscriptionid, 1 );
1119 my ( $nextissue ) = $sth->fetchrow_hashref;
1120 if( !$nextissue){
1121 $sth = $dbh->prepare('SELECT serialid,planneddate FROM serial WHERE subscriptionid = ? ORDER BY planneddate DESC LIMIT 1');
1122 $sth->execute( $subscriptionid );
1123 $nextissue = $sth->fetchrow_hashref;
1125 if (!defined $nextissue->{planneddate}) {
1126 # or should this default to 1st Jan ???
1127 $nextissue->{planneddate} = strftime('%Y-%m-%d',localtime);
1129 $nextissue->{planneddate} = C4::Dates->new($nextissue->{planneddate},'iso');
1130 return $nextissue;
1134 =head2 ModNextExpected
1136 ModNextExpected($subscriptionid,$date)
1138 Update the planneddate for the current expected issue of the subscription.
1139 This will modify all future prediction results.
1141 C<$date> is a C4::Dates object.
1143 returns 0
1145 =cut
1147 sub ModNextExpected($$) {
1148 my ( $subscriptionid, $date ) = @_;
1149 my $dbh = C4::Context->dbh;
1151 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1152 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1154 # Each subscription has only one 'expected' issue, with serial.status==1.
1155 $sth->execute( $date->output('iso'), $date->output('iso'), $subscriptionid, 1 );
1156 return 0;
1160 =head2 ModSubscription
1162 this function modifies a subscription. Put all new values on input args.
1163 returns the number of rows affected
1165 =cut
1167 sub ModSubscription {
1168 my ($auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1169 $dow, $irregularity, $numberpattern, $numberlength, $weeklength, $monthlength, $add1, $every1,
1170 $whenmorethan1, $setto1, $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2,
1171 $lastvalue2, $innerloop2, $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3,
1172 $numberingmethod, $status, $biblionumber, $callnumber, $notes, $letter, $hemisphere, $manualhistory,
1173 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $subscriptionid
1174 ) = @_;
1176 # warn $irregularity;
1177 my $dbh = C4::Context->dbh;
1178 my $query = "UPDATE subscription
1179 SET librarian=?, branchcode=?,aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
1180 periodicity=?,firstacquidate=?,dow=?,irregularity=?, numberpattern=?, numberlength=?,weeklength=?,monthlength=?,
1181 add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
1182 add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
1183 add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
1184 numberingmethod=?, status=?, biblionumber=?, callnumber=?, notes=?,
1185 letter=?, hemisphere=?,manualhistory=?,internalnotes=?,serialsadditems=?,
1186 staffdisplaycount = ?,opacdisplaycount = ?, graceperiod = ?, location = ?
1187 ,enddate=?
1188 WHERE subscriptionid = ?";
1190 #warn "query :".$query;
1191 my $sth = $dbh->prepare($query);
1192 $sth->execute(
1193 $auser, $branchcode, $aqbooksellerid, $cost,
1194 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1195 $dow, "$irregularity", $numberpattern, $numberlength,
1196 $weeklength, $monthlength, $add1, $every1,
1197 $whenmorethan1, $setto1, $lastvalue1, $innerloop1,
1198 $add2, $every2, $whenmorethan2, $setto2,
1199 $lastvalue2, $innerloop2, $add3, $every3,
1200 $whenmorethan3, $setto3, $lastvalue3, $innerloop3,
1201 $numberingmethod, $status, $biblionumber, $callnumber,
1202 $notes, $letter, $hemisphere, ( $manualhistory ? $manualhistory : 0 ),
1203 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1204 $graceperiod, $location, $enddate, $subscriptionid
1206 my $rows = $sth->rows;
1208 logaction( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1209 return $rows;
1212 =head2 NewSubscription
1214 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1215 $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
1216 $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
1217 $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
1218 $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
1219 $numberingmethod, $status, $notes, $serialsadditems,
1220 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate);
1222 Create a new subscription with value given on input args.
1224 return :
1225 the id of this new subscription
1227 =cut
1229 sub NewSubscription {
1230 my ($auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber, $startdate, $periodicity,
1231 $dow, $numberlength, $weeklength, $monthlength, $add1, $every1, $whenmorethan1, $setto1,
1232 $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2, $lastvalue2, $innerloop2,
1233 $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3, $numberingmethod, $status,
1234 $notes, $letter, $firstacquidate, $irregularity, $numberpattern, $callnumber, $hemisphere, $manualhistory,
1235 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate
1236 ) = @_;
1237 my $dbh = C4::Context->dbh;
1239 #save subscription (insert into database)
1240 my $query = qq|
1241 INSERT INTO subscription
1242 (librarian,branchcode,aqbooksellerid,cost,aqbudgetid,biblionumber,
1243 startdate,periodicity,dow,numberlength,weeklength,monthlength,
1244 add1,every1,whenmorethan1,setto1,lastvalue1,innerloop1,
1245 add2,every2,whenmorethan2,setto2,lastvalue2,innerloop2,
1246 add3,every3,whenmorethan3,setto3,lastvalue3,innerloop3,
1247 numberingmethod, status, notes, letter,firstacquidate,irregularity,
1248 numberpattern, callnumber, hemisphere,manualhistory,internalnotes,serialsadditems,
1249 staffdisplaycount,opacdisplaycount,graceperiod,location,enddate)
1250 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
1252 my $sth = $dbh->prepare($query);
1253 $sth->execute(
1254 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber, $startdate, $periodicity,
1255 $dow, $numberlength, $weeklength, $monthlength, $add1, $every1, $whenmorethan1, $setto1,
1256 $lastvalue1, $innerloop1, $add2, $every2, $whenmorethan2, $setto2, $lastvalue2, $innerloop2,
1257 $add3, $every3, $whenmorethan3, $setto3, $lastvalue3, $innerloop3, $numberingmethod, "$status",
1258 $notes, $letter, $firstacquidate, $irregularity, $numberpattern, $callnumber, $hemisphere, $manualhistory,
1259 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate
1262 my $subscriptionid = $dbh->{'mysql_insertid'};
1263 unless ($enddate){
1264 $enddate = GetExpirationDate($subscriptionid,$startdate);
1265 $query = q|
1266 UPDATE subscription
1267 SET enddate=?
1268 WHERE subscriptionid=?
1270 $sth = $dbh->prepare($query);
1271 $sth->execute( $enddate, $subscriptionid );
1273 #then create the 1st waited number
1274 $query = qq(
1275 INSERT INTO subscriptionhistory
1276 (biblionumber, subscriptionid, histstartdate, opacnote, librariannote)
1277 VALUES (?,?,?,?,?)
1279 $sth = $dbh->prepare($query);
1280 $sth->execute( $biblionumber, $subscriptionid, $startdate, $notes, $internalnotes );
1282 # reread subscription to get a hash (for calculation of the 1st issue number)
1283 $query = qq(
1284 SELECT *
1285 FROM subscription
1286 WHERE subscriptionid = ?
1288 $sth = $dbh->prepare($query);
1289 $sth->execute($subscriptionid);
1290 my $val = $sth->fetchrow_hashref;
1292 # calculate issue number
1293 my $serialseq = GetSeq($val);
1294 $query = qq|
1295 INSERT INTO serial
1296 (serialseq,subscriptionid,biblionumber,status, planneddate, publisheddate)
1297 VALUES (?,?,?,?,?,?)
1299 $sth = $dbh->prepare($query);
1300 $sth->execute( "$serialseq", $subscriptionid, $biblionumber, 1, $firstacquidate, $firstacquidate );
1302 logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1304 #set serial flag on biblio if not already set.
1305 my ( $null, ($bib) ) = GetBiblio($biblionumber);
1306 if ( !$bib->{'serial'} ) {
1307 my $record = GetMarcBiblio($biblionumber);
1308 my ( $tag, $subf ) = GetMarcFromKohaField( 'biblio.serial', $bib->{'frameworkcode'} );
1309 if ($tag) {
1310 eval { $record->field($tag)->update( $subf => 1 ); };
1312 ModBiblio( $record, $biblionumber, $bib->{'frameworkcode'} );
1314 return $subscriptionid;
1317 =head2 ReNewSubscription
1319 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1321 this function renew a subscription with values given on input args.
1323 =cut
1325 sub ReNewSubscription {
1326 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1327 my $dbh = C4::Context->dbh;
1328 my $subscription = GetSubscription($subscriptionid);
1329 my $query = qq|
1330 SELECT *
1331 FROM biblio
1332 LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
1333 WHERE biblio.biblionumber=?
1335 my $sth = $dbh->prepare($query);
1336 $sth->execute( $subscription->{biblionumber} );
1337 my $biblio = $sth->fetchrow_hashref;
1339 if ( C4::Context->preference("RenewSerialAddsSuggestion") ) {
1340 require C4::Suggestions;
1341 C4::Suggestions::NewSuggestion(
1342 { 'suggestedby' => $user,
1343 'title' => $subscription->{bibliotitle},
1344 'author' => $biblio->{author},
1345 'publishercode' => $biblio->{publishercode},
1346 'note' => $biblio->{note},
1347 'biblionumber' => $subscription->{biblionumber}
1352 # renew subscription
1353 $query = qq|
1354 UPDATE subscription
1355 SET startdate=?,numberlength=?,weeklength=?,monthlength=?
1356 WHERE subscriptionid=?
1358 $sth = $dbh->prepare($query);
1359 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1360 my $enddate = GetExpirationDate($subscriptionid);
1361 $debug && warn "enddate :$enddate";
1362 $query = qq|
1363 UPDATE subscription
1364 SET enddate=?
1365 WHERE subscriptionid=?
1367 $sth = $dbh->prepare($query);
1368 $sth->execute( $enddate, $subscriptionid );
1369 $query = qq|
1370 UPDATE subscriptionhistory
1371 SET histenddate=?
1372 WHERE subscriptionid=?
1374 $sth = $dbh->prepare($query);
1375 $sth->execute( $enddate, $subscriptionid );
1377 logaction( "SERIAL", "RENEW", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1378 return;
1381 =head2 NewIssue
1383 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1385 Create a new issue stored on the database.
1386 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1387 returns the serial id
1389 =cut
1391 sub NewIssue {
1392 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate, $publisheddate, $notes ) = @_;
1393 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1395 my $dbh = C4::Context->dbh;
1396 my $query = qq|
1397 INSERT INTO serial
1398 (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,notes)
1399 VALUES (?,?,?,?,?,?,?)
1401 my $sth = $dbh->prepare($query);
1402 $sth->execute( $serialseq, $subscriptionid, $biblionumber, $status, $publisheddate, $planneddate, $notes );
1403 my $serialid = $dbh->{'mysql_insertid'};
1404 $query = qq|
1405 SELECT missinglist,recievedlist
1406 FROM subscriptionhistory
1407 WHERE subscriptionid=?
1409 $sth = $dbh->prepare($query);
1410 $sth->execute($subscriptionid);
1411 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1413 if ( $status == 2 ) {
1414 ### TODO Add a feature that improves recognition and description.
1415 ### As such count (serialseq) i.e. : N18,2(N19),N20
1416 ### Would use substr and index But be careful to previous presence of ()
1417 $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
1419 if ( $status == 4 ) {
1420 $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
1422 $query = qq|
1423 UPDATE subscriptionhistory
1424 SET recievedlist=?, missinglist=?
1425 WHERE subscriptionid=?
1427 $sth = $dbh->prepare($query);
1428 $recievedlist =~ s/^; //;
1429 $missinglist =~ s/^; //;
1430 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1431 return $serialid;
1434 =head2 ItemizeSerials
1436 ItemizeSerials($serialid, $info);
1437 $info is a hashref containing barcode branch, itemcallnumber, status, location
1438 $serialid the serialid
1439 return :
1440 1 if the itemize is a succes.
1441 0 and @error otherwise. @error containts the list of errors found.
1443 =cut
1445 sub ItemizeSerials {
1446 my ( $serialid, $info ) = @_;
1447 my $now = POSIX::strftime( "%Y-%m-%d", localtime );
1449 my $dbh = C4::Context->dbh;
1450 my $query = qq|
1451 SELECT *
1452 FROM serial
1453 WHERE serialid=?
1455 my $sth = $dbh->prepare($query);
1456 $sth->execute($serialid);
1457 my $data = $sth->fetchrow_hashref;
1458 if ( C4::Context->preference("RoutingSerials") ) {
1460 # check for existing biblioitem relating to serial issue
1461 my ( $count, @results ) = GetBiblioItemByBiblioNumber( $data->{'biblionumber'} );
1462 my $bibitemno = 0;
1463 for ( my $i = 0 ; $i < $count ; $i++ ) {
1464 if ( $results[$i]->{'volumeddesc'} eq $data->{'serialseq'} . ' (' . $data->{'planneddate'} . ')' ) {
1465 $bibitemno = $results[$i]->{'biblioitemnumber'};
1466 last;
1469 if ( $bibitemno == 0 ) {
1470 my $sth = $dbh->prepare( "SELECT * FROM biblioitems WHERE biblionumber = ? ORDER BY biblioitemnumber DESC" );
1471 $sth->execute( $data->{'biblionumber'} );
1472 my $biblioitem = $sth->fetchrow_hashref;
1473 $biblioitem->{'volumedate'} = $data->{planneddate};
1474 $biblioitem->{'volumeddesc'} = $data->{serialseq} . ' (' . format_date( $data->{'planneddate'} ) . ')';
1475 $biblioitem->{'dewey'} = $info->{itemcallnumber};
1479 my $fwk = GetFrameworkCode( $data->{'biblionumber'} );
1480 if ( $info->{barcode} ) {
1481 my @errors;
1482 if ( is_barcode_in_use( $info->{barcode} ) ) {
1483 push @errors, 'barcode_not_unique';
1484 } else {
1485 my $marcrecord = MARC::Record->new();
1486 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.barcode", $fwk );
1487 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{barcode} );
1488 $marcrecord->insert_fields_ordered($newField);
1489 if ( $info->{branch} ) {
1490 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.homebranch", $fwk );
1492 #warn "items.homebranch : $tag , $subfield";
1493 if ( $marcrecord->field($tag) ) {
1494 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1495 } else {
1496 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1497 $marcrecord->insert_fields_ordered($newField);
1499 ( $tag, $subfield ) = GetMarcFromKohaField( "items.holdingbranch", $fwk );
1501 #warn "items.holdingbranch : $tag , $subfield";
1502 if ( $marcrecord->field($tag) ) {
1503 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1504 } else {
1505 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1506 $marcrecord->insert_fields_ordered($newField);
1509 if ( $info->{itemcallnumber} ) {
1510 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemcallnumber", $fwk );
1512 if ( $marcrecord->field($tag) ) {
1513 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{itemcallnumber} );
1514 } else {
1515 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{itemcallnumber} );
1516 $marcrecord->insert_fields_ordered($newField);
1519 if ( $info->{notes} ) {
1520 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemnotes", $fwk );
1522 if ( $marcrecord->field($tag) ) {
1523 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{notes} );
1524 } else {
1525 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{notes} );
1526 $marcrecord->insert_fields_ordered($newField);
1529 if ( $info->{location} ) {
1530 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.location", $fwk );
1532 if ( $marcrecord->field($tag) ) {
1533 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{location} );
1534 } else {
1535 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{location} );
1536 $marcrecord->insert_fields_ordered($newField);
1539 if ( $info->{status} ) {
1540 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.notforloan", $fwk );
1542 if ( $marcrecord->field($tag) ) {
1543 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{status} );
1544 } else {
1545 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{status} );
1546 $marcrecord->insert_fields_ordered($newField);
1549 if ( C4::Context->preference("RoutingSerials") ) {
1550 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.dateaccessioned", $fwk );
1551 if ( $marcrecord->field($tag) ) {
1552 $marcrecord->field($tag)->add_subfields( "$subfield" => $now );
1553 } else {
1554 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $now );
1555 $marcrecord->insert_fields_ordered($newField);
1558 require C4::Items;
1559 C4::Items::AddItemFromMarc( $marcrecord, $data->{'biblionumber'} );
1560 return 1;
1562 return ( 0, @errors );
1566 =head2 HasSubscriptionStrictlyExpired
1568 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1570 the subscription has stricly expired when today > the end subscription date
1572 return :
1573 1 if true, 0 if false, -1 if the expiration date is not set.
1575 =cut
1577 sub HasSubscriptionStrictlyExpired {
1579 # Getting end of subscription date
1580 my ($subscriptionid) = @_;
1581 my $dbh = C4::Context->dbh;
1582 my $subscription = GetSubscription($subscriptionid);
1583 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1585 # If the expiration date is set
1586 if ( $expirationdate != 0 ) {
1587 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1589 # Getting today's date
1590 my ( $nowyear, $nowmonth, $nowday ) = Today();
1592 # if today's date > expiration date, then the subscription has stricly expired
1593 if ( Delta_Days( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1594 return 1;
1595 } else {
1596 return 0;
1598 } else {
1600 # There are some cases where the expiration date is not set
1601 # As we can't determine if the subscription has expired on a date-basis,
1602 # we return -1;
1603 return -1;
1607 =head2 HasSubscriptionExpired
1609 $has_expired = HasSubscriptionExpired($subscriptionid)
1611 the subscription has expired when the next issue to arrive is out of subscription limit.
1613 return :
1614 0 if the subscription has not expired
1615 1 if the subscription has expired
1616 2 if has subscription does not have a valid expiration date set
1618 =cut
1620 sub HasSubscriptionExpired {
1621 my ($subscriptionid) = @_;
1622 my $dbh = C4::Context->dbh;
1623 my $subscription = GetSubscription($subscriptionid);
1624 if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
1625 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1626 if (!defined $expirationdate) {
1627 $expirationdate = q{};
1629 my $query = qq|
1630 SELECT max(planneddate)
1631 FROM serial
1632 WHERE subscriptionid=?
1634 my $sth = $dbh->prepare($query);
1635 $sth->execute($subscriptionid);
1636 my ($res) = $sth->fetchrow;
1637 if (!$res || $res=~m/^0000/) {
1638 return 0;
1640 my @res = split( /-/, $res );
1641 my @endofsubscriptiondate = split( /-/, $expirationdate );
1642 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date(@res) || not check_date(@endofsubscriptiondate) );
1643 return 1
1644 if ( ( @endofsubscriptiondate && Delta_Days( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1645 || ( !$res ) );
1646 return 0;
1647 } else {
1648 if ( $subscription->{'numberlength'} ) {
1649 my $countreceived = countissuesfrom( $subscriptionid, $subscription->{'startdate'} );
1650 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1651 return 0;
1652 } else {
1653 return 0;
1656 return 0; # Notice that you'll never get here.
1659 =head2 SetDistributedto
1661 SetDistributedto($distributedto,$subscriptionid);
1662 This function update the value of distributedto for a subscription given on input arg.
1664 =cut
1666 sub SetDistributedto {
1667 my ( $distributedto, $subscriptionid ) = @_;
1668 my $dbh = C4::Context->dbh;
1669 my $query = qq|
1670 UPDATE subscription
1671 SET distributedto=?
1672 WHERE subscriptionid=?
1674 my $sth = $dbh->prepare($query);
1675 $sth->execute( $distributedto, $subscriptionid );
1676 return;
1679 =head2 DelSubscription
1681 DelSubscription($subscriptionid)
1682 this function deletes subscription which has $subscriptionid as id.
1684 =cut
1686 sub DelSubscription {
1687 my ($subscriptionid) = @_;
1688 my $dbh = C4::Context->dbh;
1689 $subscriptionid = $dbh->quote($subscriptionid);
1690 $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
1691 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
1692 $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
1694 logaction( "SERIAL", "DELETE", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1697 =head2 DelIssue
1699 DelIssue($serialseq,$subscriptionid)
1700 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1702 returns the number of rows affected
1704 =cut
1706 sub DelIssue {
1707 my ($dataissue) = @_;
1708 my $dbh = C4::Context->dbh;
1709 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1711 my $query = qq|
1712 DELETE FROM serial
1713 WHERE serialid= ?
1714 AND subscriptionid= ?
1716 my $mainsth = $dbh->prepare($query);
1717 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1719 #Delete element from subscription history
1720 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1721 my $sth = $dbh->prepare($query);
1722 $sth->execute( $dataissue->{'subscriptionid'} );
1723 my $val = $sth->fetchrow_hashref;
1724 unless ( $val->{manualhistory} ) {
1725 my $query = qq|
1726 SELECT * FROM subscriptionhistory
1727 WHERE subscriptionid= ?
1729 my $sth = $dbh->prepare($query);
1730 $sth->execute( $dataissue->{'subscriptionid'} );
1731 my $data = $sth->fetchrow_hashref;
1732 my $serialseq = $dataissue->{'serialseq'};
1733 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1734 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1735 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1736 $sth = $dbh->prepare($strsth);
1737 $sth->execute( $dataissue->{'subscriptionid'} );
1740 return $mainsth->rows;
1743 =head2 GetLateOrMissingIssues
1745 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1747 this function selects missing issues on database - where serial.status = 4 or serial.status=3 or planneddate<now
1749 return :
1750 the issuelist as an array of hash refs. Each element of this array contains
1751 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1753 =cut
1755 sub GetLateOrMissingIssues {
1756 my ( $supplierid, $serialid, $order ) = @_;
1757 my $dbh = C4::Context->dbh;
1758 my $sth;
1759 my $byserial = '';
1760 if ($serialid) {
1761 $byserial = "and serialid = " . $serialid;
1763 if ($order) {
1764 $order .= ", title";
1765 } else {
1766 $order = "title";
1768 if ($supplierid) {
1769 $sth = $dbh->prepare(
1770 "SELECT
1771 serialid, aqbooksellerid, name,
1772 biblio.title, planneddate, serialseq,
1773 serial.status, serial.subscriptionid, claimdate,
1774 subscription.branchcode
1775 FROM serial
1776 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1777 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1778 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1779 WHERE subscription.subscriptionid = serial.subscriptionid
1780 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
1781 AND subscription.aqbooksellerid=$supplierid
1782 $byserial
1783 ORDER BY $order"
1785 } else {
1786 $sth = $dbh->prepare(
1787 "SELECT
1788 serialid, aqbooksellerid, name,
1789 biblio.title, planneddate, serialseq,
1790 serial.status, serial.subscriptionid, claimdate,
1791 subscription.branchcode
1792 FROM serial
1793 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1794 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1795 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1796 WHERE subscription.subscriptionid = serial.subscriptionid
1797 AND (serial.STATUS = 4 OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
1798 $byserial
1799 ORDER BY $order"
1802 $sth->execute;
1803 my @issuelist;
1804 while ( my $line = $sth->fetchrow_hashref ) {
1806 if ($line->{planneddate} && $line->{planneddate} !~/^0+\-/) {
1807 $line->{planneddate} = format_date( $line->{planneddate} );
1809 if ($line->{claimdate} && $line->{claimdate} !~/^0+\-/) {
1810 $line->{claimdate} = format_date( $line->{claimdate} );
1812 $line->{"status".$line->{status}} = 1;
1813 push @issuelist, $line;
1815 return @issuelist;
1818 =head2 removeMissingIssue
1820 removeMissingIssue($subscriptionid)
1822 this function removes an issue from being part of the missing string in
1823 subscriptionlist.missinglist column
1825 called when a missing issue is found from the serials-recieve.pl file
1827 =cut
1829 sub removeMissingIssue {
1830 my ( $sequence, $subscriptionid ) = @_;
1831 my $dbh = C4::Context->dbh;
1832 my $sth = $dbh->prepare("SELECT * FROM subscriptionhistory WHERE subscriptionid = ?");
1833 $sth->execute($subscriptionid);
1834 my $data = $sth->fetchrow_hashref;
1835 my $missinglist = $data->{'missinglist'};
1836 my $missinglistbefore = $missinglist;
1838 # warn $missinglist." before";
1839 $missinglist =~ s/($sequence)//;
1841 # warn $missinglist." after";
1842 if ( $missinglist ne $missinglistbefore ) {
1843 $missinglist =~ s/\|\s\|/\|/g;
1844 $missinglist =~ s/^\| //g;
1845 $missinglist =~ s/\|$//g;
1846 my $sth2 = $dbh->prepare(
1847 "UPDATE subscriptionhistory
1848 SET missinglist = ?
1849 WHERE subscriptionid = ?"
1851 $sth2->execute( $missinglist, $subscriptionid );
1853 return;
1856 =head2 updateClaim
1858 &updateClaim($serialid)
1860 this function updates the time when a claim is issued for late/missing items
1862 called from claims.pl file
1864 =cut
1866 sub updateClaim {
1867 my ($serialid) = @_;
1868 my $dbh = C4::Context->dbh;
1869 my $sth = $dbh->prepare(
1870 "UPDATE serial SET claimdate = now()
1871 WHERE serialid = ?
1874 $sth->execute($serialid);
1875 return;
1878 =head2 getsupplierbyserialid
1880 $result = getsupplierbyserialid($serialid)
1882 this function is used to find the supplier id given a serial id
1884 return :
1885 hashref containing serialid, subscriptionid, and aqbooksellerid
1887 =cut
1889 sub getsupplierbyserialid {
1890 my ($serialid) = @_;
1891 my $dbh = C4::Context->dbh;
1892 my $sth = $dbh->prepare(
1893 "SELECT serialid, serial.subscriptionid, aqbooksellerid
1894 FROM serial
1895 LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
1896 WHERE serialid = ?
1899 $sth->execute($serialid);
1900 my $line = $sth->fetchrow_hashref;
1901 my $result = $line->{'aqbooksellerid'};
1902 return $result;
1905 =head2 check_routing
1907 $result = &check_routing($subscriptionid)
1909 this function checks to see if a serial has a routing list and returns the count of routingid
1910 used to show either an 'add' or 'edit' link
1912 =cut
1914 sub check_routing {
1915 my ($subscriptionid) = @_;
1916 my $dbh = C4::Context->dbh;
1917 my $sth = $dbh->prepare(
1918 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1919 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1920 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
1923 $sth->execute($subscriptionid);
1924 my $line = $sth->fetchrow_hashref;
1925 my $result = $line->{'routingids'};
1926 return $result;
1929 =head2 addroutingmember
1931 addroutingmember($borrowernumber,$subscriptionid)
1933 this function takes a borrowernumber and subscriptionid and adds the member to the
1934 routing list for that serial subscription and gives them a rank on the list
1935 of either 1 or highest current rank + 1
1937 =cut
1939 sub addroutingmember {
1940 my ( $borrowernumber, $subscriptionid ) = @_;
1941 my $rank;
1942 my $dbh = C4::Context->dbh;
1943 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1944 $sth->execute($subscriptionid);
1945 while ( my $line = $sth->fetchrow_hashref ) {
1946 if ( $line->{'rank'} > 0 ) {
1947 $rank = $line->{'rank'} + 1;
1948 } else {
1949 $rank = 1;
1952 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1953 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1956 =head2 reorder_members
1958 reorder_members($subscriptionid,$routingid,$rank)
1960 this function is used to reorder the routing list
1962 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1963 - it gets all members on list puts their routingid's into an array
1964 - removes the one in the array that is $routingid
1965 - then reinjects $routingid at point indicated by $rank
1966 - then update the database with the routingids in the new order
1968 =cut
1970 sub reorder_members {
1971 my ( $subscriptionid, $routingid, $rank ) = @_;
1972 my $dbh = C4::Context->dbh;
1973 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1974 $sth->execute($subscriptionid);
1975 my @result;
1976 while ( my $line = $sth->fetchrow_hashref ) {
1977 push( @result, $line->{'routingid'} );
1980 # To find the matching index
1981 my $i;
1982 my $key = -1; # to allow for 0 being a valid response
1983 for ( $i = 0 ; $i < @result ; $i++ ) {
1984 if ( $routingid == $result[$i] ) {
1985 $key = $i; # save the index
1986 last;
1990 # if index exists in array then move it to new position
1991 if ( $key > -1 && $rank > 0 ) {
1992 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1993 my $moving_item = splice( @result, $key, 1 );
1994 splice( @result, $new_rank, 0, $moving_item );
1996 for ( my $j = 0 ; $j < @result ; $j++ ) {
1997 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1998 $sth->execute;
2000 return;
2003 =head2 delroutingmember
2005 delroutingmember($routingid,$subscriptionid)
2007 this function either deletes one member from routing list if $routingid exists otherwise
2008 deletes all members from the routing list
2010 =cut
2012 sub delroutingmember {
2014 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2015 my ( $routingid, $subscriptionid ) = @_;
2016 my $dbh = C4::Context->dbh;
2017 if ($routingid) {
2018 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2019 $sth->execute($routingid);
2020 reorder_members( $subscriptionid, $routingid );
2021 } else {
2022 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2023 $sth->execute($subscriptionid);
2025 return;
2028 =head2 getroutinglist
2030 @routinglist = getroutinglist($subscriptionid)
2032 this gets the info from the subscriptionroutinglist for $subscriptionid
2034 return :
2035 the routinglist as an array. Each element of the array contains a hash_ref containing
2036 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2038 =cut
2040 sub getroutinglist {
2041 my ($subscriptionid) = @_;
2042 my $dbh = C4::Context->dbh;
2043 my $sth = $dbh->prepare(
2044 'SELECT routingid, borrowernumber, ranking, biblionumber
2045 FROM subscription
2046 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2047 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2049 $sth->execute($subscriptionid);
2050 my $routinglist = $sth->fetchall_arrayref({});
2051 return @{$routinglist};
2054 =head2 countissuesfrom
2056 $result = countissuesfrom($subscriptionid,$startdate)
2058 Returns a count of serial rows matching the given subsctiptionid
2059 with published date greater than startdate
2061 =cut
2063 sub countissuesfrom {
2064 my ( $subscriptionid, $startdate ) = @_;
2065 my $dbh = C4::Context->dbh;
2066 my $query = qq|
2067 SELECT count(*)
2068 FROM serial
2069 WHERE subscriptionid=?
2070 AND serial.publisheddate>?
2072 my $sth = $dbh->prepare($query);
2073 $sth->execute( $subscriptionid, $startdate );
2074 my ($countreceived) = $sth->fetchrow;
2075 return $countreceived;
2078 =head2 CountIssues
2080 $result = CountIssues($subscriptionid)
2082 Returns a count of serial rows matching the given subsctiptionid
2084 =cut
2086 sub CountIssues {
2087 my ($subscriptionid) = @_;
2088 my $dbh = C4::Context->dbh;
2089 my $query = qq|
2090 SELECT count(*)
2091 FROM serial
2092 WHERE subscriptionid=?
2094 my $sth = $dbh->prepare($query);
2095 $sth->execute($subscriptionid);
2096 my ($countreceived) = $sth->fetchrow;
2097 return $countreceived;
2100 =head2 HasItems
2102 $result = HasItems($subscriptionid)
2104 returns a count of items from serial matching the subscriptionid
2106 =cut
2108 sub HasItems {
2109 my ($subscriptionid) = @_;
2110 my $dbh = C4::Context->dbh;
2111 my $query = q|
2112 SELECT COUNT(serialitems.itemnumber)
2113 FROM serial
2114 LEFT JOIN serialitems USING(serialid)
2115 WHERE subscriptionid=? AND serialitems.serialid IS NOT NULL
2117 my $sth=$dbh->prepare($query);
2118 $sth->execute($subscriptionid);
2119 my ($countitems)=$sth->fetchrow_array();
2120 return $countitems;
2123 =head2 abouttoexpire
2125 $result = abouttoexpire($subscriptionid)
2127 this function alerts you to the penultimate issue for a serial subscription
2129 returns 1 - if this is the penultimate issue
2130 returns 0 - if not
2132 =cut
2134 sub abouttoexpire {
2135 my ($subscriptionid) = @_;
2136 my $dbh = C4::Context->dbh;
2137 my $subscription = GetSubscription($subscriptionid);
2138 my $per = $subscription->{'periodicity'};
2139 if ($per && $per % 16 > 0){
2140 my $expirationdate = GetExpirationDate($subscriptionid);
2141 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2142 my @res;
2143 if (defined $res) {
2144 @res=split (/-/,$res);
2145 @res=Date::Calc::Today if ($res[0]*$res[1]==0);
2146 } else { # default an undefined value
2147 @res=Date::Calc::Today;
2149 my @endofsubscriptiondate=split(/-/,$expirationdate);
2150 my @per_list = (0, 7, 7, 14, 21, 31, 62, 93, 93, 190, 365, 730, 0, 124, 0, 0);
2151 my @datebeforeend;
2152 @datebeforeend = Add_Delta_Days( $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2],
2153 - (3 * $per_list[$per])) if (@endofsubscriptiondate && $endofsubscriptiondate[0]*$endofsubscriptiondate[1]*$endofsubscriptiondate[2]);
2154 return 1 if ( @res &&
2155 (@datebeforeend &&
2156 Delta_Days($res[0],$res[1],$res[2],
2157 $datebeforeend[0],$datebeforeend[1],$datebeforeend[2]) <= 0) &&
2158 (@endofsubscriptiondate &&
2159 Delta_Days($res[0],$res[1],$res[2],
2160 $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) >= 0) );
2161 return 0;
2162 } elsif ($subscription->{numberlength}>0) {
2163 return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
2165 return 0;
2168 sub in_array { # used in next sub down
2169 my ( $val, @elements ) = @_;
2170 foreach my $elem (@elements) {
2171 if ( $val == $elem ) {
2172 return 1;
2175 return 0;
2178 =head2 GetNextDate
2180 $resultdate = GetNextDate($planneddate,$subscription)
2182 this function it takes the planneddate and will return the next issue's date and will skip dates if there
2183 exists an irregularity
2184 - eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be
2185 skipped then the returned date will be 2007-05-10
2187 return :
2188 $resultdate - then next date in the sequence
2190 Return 0 if periodicity==0
2192 =cut
2194 sub GetNextDate(@) {
2195 my ( $planneddate, $subscription ) = @_;
2196 my @irreg = split( /\,/, $subscription->{irregularity} );
2198 #date supposed to be in ISO.
2200 my ( $year, $month, $day ) = split( /-/, $planneddate );
2201 $month = 1 unless ($month);
2202 $day = 1 unless ($day);
2203 my @resultdate;
2205 # warn "DOW $dayofweek";
2206 if ( $subscription->{periodicity} % 16 == 0 ) { # 'without regularity' || 'irregular'
2207 return 0;
2210 # daily : n / week
2211 # Since we're interpreting irregularity here as which days of the week to skip an issue,
2212 # renaming this pattern from 1/day to " n / week ".
2213 if ( $subscription->{periodicity} == 1 ) {
2214 my $dayofweek = eval { Day_of_Week( $year, $month, $day ) };
2215 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2216 else {
2217 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2218 $dayofweek = 0 if ( $dayofweek == 7 );
2219 if ( in_array( ( $dayofweek + 1 ), @irreg ) ) {
2220 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 1 );
2221 $dayofweek++;
2224 @resultdate = Add_Delta_Days( $year, $month, $day, 1 );
2228 # 1 week
2229 if ( $subscription->{periodicity} == 2 ) {
2230 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2231 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2232 else {
2233 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2235 #FIXME: if two consecutive irreg, do we only skip one?
2236 if ( $irreg[$i] == ( ( $wkno != 51 ) ? ( $wkno + 1 ) % 52 : 52 ) ) {
2237 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 7 );
2238 $wkno = ( ( $wkno != 51 ) ? ( $wkno + 1 ) % 52 : 52 );
2241 @resultdate = Add_Delta_Days( $year, $month, $day, 7 );
2245 # 1 / 2 weeks
2246 if ( $subscription->{periodicity} == 3 ) {
2247 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2248 if ($@) { warn "year month day : $year $month $day $subscription->{subscriptionid} : $@"; }
2249 else {
2250 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2251 if ( $irreg[$i] == ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 ) ) {
2252 ### BUGFIX was previously +1 ^
2253 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 14 );
2254 $wkno = ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 );
2257 @resultdate = Add_Delta_Days( $year, $month, $day, 14 );
2261 # 1 / 3 weeks
2262 if ( $subscription->{periodicity} == 4 ) {
2263 my ( $wkno, $year ) = eval { Week_of_Year( $year, $month, $day ) };
2264 if ($@) { warn "année mois jour : $year $month $day $subscription->{subscriptionid} : $@"; }
2265 else {
2266 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2267 if ( $irreg[$i] == ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 ) ) {
2268 ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 21 );
2269 $wkno = ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 );
2272 @resultdate = Add_Delta_Days( $year, $month, $day, 21 );
2275 my $tmpmonth = $month;
2276 if ( $year && $month && $day ) {
2277 if ( $subscription->{periodicity} == 5 ) {
2278 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2279 if ( $irreg[$i] == ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 ) ) {
2280 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
2281 $tmpmonth = ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 );
2284 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
2286 if ( $subscription->{periodicity} == 6 ) {
2287 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2288 if ( $irreg[$i] == ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 ) ) {
2289 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
2290 $tmpmonth = ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 );
2293 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
2295 if ( $subscription->{periodicity} == 7 ) {
2296 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2297 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2298 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2299 $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
2302 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2304 if ( $subscription->{periodicity} == 8 ) {
2305 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2306 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2307 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2308 $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
2311 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
2313 if ( $subscription->{periodicity} == 13 ) {
2314 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2315 if ( $irreg[$i] == ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 ) ) {
2316 ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
2317 $tmpmonth = ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 );
2320 @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
2322 if ( $subscription->{periodicity} == 9 ) {
2323 for ( my $i = 0 ; $i < @irreg ; $i++ ) {
2324 if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
2325 ### BUFIX Seems to need more Than One ?
2326 ( $year, $month, $day ) = Add_Delta_YM( $year, $month, $day, 0, 6 );
2327 $tmpmonth = ( ( $tmpmonth != 6 ) ? ( $tmpmonth + 6 ) % 12 : 12 );
2330 @resultdate = Add_Delta_YM( $year, $month, $day, 0, 6 );
2332 if ( $subscription->{periodicity} == 10 ) {
2333 @resultdate = Add_Delta_YM( $year, $month, $day, 1, 0 );
2335 if ( $subscription->{periodicity} == 11 ) {
2336 @resultdate = Add_Delta_YM( $year, $month, $day, 2, 0 );
2339 my $resultdate = sprintf( "%04d-%02d-%02d", $resultdate[0], $resultdate[1], $resultdate[2] );
2341 return "$resultdate";
2344 =head2 is_barcode_in_use
2346 Returns number of occurence of the barcode in the items table
2347 Can be used as a boolean test of whether the barcode has
2348 been deployed as yet
2350 =cut
2352 sub is_barcode_in_use {
2353 my $barcode = shift;
2354 my $dbh = C4::Context->dbh;
2355 my $occurences = $dbh->selectall_arrayref(
2356 'SELECT itemnumber from items where barcode = ?',
2357 {}, $barcode
2361 return @{$occurences};
2365 __END__
2367 =head1 AUTHOR
2369 Koha Development Team <http://koha-community.org/>
2371 =cut