Bug 14585: Fixing up online help on main page
[koha.git] / C4 / Serials.pm
blobb2cd15865c2b2fb7373c2192c902d5cefac89951
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
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21 use Modern::Perl;
23 use C4::Auth qw(haspermission);
24 use C4::Context;
25 use C4::Dates qw(format_date format_date_in_iso);
26 use DateTime;
27 use Date::Calc qw(:all);
28 use POSIX qw(strftime);
29 use C4::Biblio;
30 use C4::Log; # logaction
31 use C4::Debug;
32 use C4::Serials::Frequency;
33 use C4::Serials::Numberpattern;
35 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
37 BEGIN {
38 $VERSION = 3.07.00.049; # set version for version checking
39 require Exporter;
40 @ISA = qw(Exporter);
41 @EXPORT = qw(
42 &NewSubscription &ModSubscription &DelSubscription &GetSubscriptions
43 &GetSubscription &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
44 &SearchSubscriptions
45 &GetFullSubscriptionsFromBiblionumber &GetFullSubscription &ModSubscriptionHistory
46 &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
47 &GetSubscriptionHistoryFromSubscriptionId
49 &GetNextSeq &GetSeq &NewIssue &ItemizeSerials &GetSerials
50 &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2
51 &ReNewSubscription &GetLateIssues &GetLateOrMissingIssues
52 &GetSerialInformation &AddItem2Serial
53 &PrepareSerialsData &GetNextExpected &ModNextExpected
55 &UpdateClaimdateIssues
56 &GetSuppliersWithLateIssues &getsupplierbyserialid
57 &GetDistributedTo &SetDistributedTo
58 &getroutinglist &delroutingmember &addroutingmember
59 &reorder_members
60 &check_routing &updateClaim
61 &CountIssues
62 HasItems
63 &GetSubscriptionsFromBorrower
64 &subscriptionCurrentlyOnOrder
69 =head1 NAME
71 C4::Serials - Serials Module Functions
73 =head1 SYNOPSIS
75 use C4::Serials;
77 =head1 DESCRIPTION
79 Functions for handling subscriptions, claims routing etc.
82 =head1 SUBROUTINES
84 =head2 GetSuppliersWithLateIssues
86 $supplierlist = GetSuppliersWithLateIssues()
88 this function get all suppliers with late issues.
90 return :
91 an array_ref of suppliers each entry is a hash_ref containing id and name
92 the array is in name order
94 =cut
96 sub GetSuppliersWithLateIssues {
97 my $dbh = C4::Context->dbh;
98 my $query = qq|
99 SELECT DISTINCT id, name
100 FROM subscription
101 LEFT JOIN serial ON serial.subscriptionid=subscription.subscriptionid
102 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
103 WHERE id > 0
104 AND (
105 (planneddate < now() AND serial.status=1)
106 OR serial.STATUS IN (3, 4, 41, 42, 43, 44, 7)
108 AND subscription.closed = 0
109 ORDER BY name|;
110 return $dbh->selectall_arrayref($query, { Slice => {} });
113 =head2 GetLateIssues
115 @issuelist = GetLateIssues($supplierid)
117 this function selects late issues from the database
119 return :
120 the issuelist as an array. Each element of this array contains a hashi_ref containing
121 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
123 =cut
125 sub GetLateIssues {
126 my ($supplierid) = @_;
128 return unless ($supplierid);
130 my $dbh = C4::Context->dbh;
131 my $sth;
132 if ($supplierid) {
133 my $query = qq|
134 SELECT name,title,planneddate,serialseq,serial.subscriptionid
135 FROM subscription
136 LEFT JOIN serial ON subscription.subscriptionid = serial.subscriptionid
137 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
138 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
139 WHERE ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
140 AND subscription.aqbooksellerid=?
141 AND subscription.closed = 0
142 ORDER BY title
144 $sth = $dbh->prepare($query);
145 $sth->execute($supplierid);
146 } else {
147 my $query = qq|
148 SELECT name,title,planneddate,serialseq,serial.subscriptionid
149 FROM subscription
150 LEFT JOIN serial ON subscription.subscriptionid = serial.subscriptionid
151 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
152 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
153 WHERE ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
154 AND subscription.closed = 0
155 ORDER BY title
157 $sth = $dbh->prepare($query);
158 $sth->execute;
160 my @issuelist;
161 my $last_title;
162 while ( my $line = $sth->fetchrow_hashref ) {
163 $line->{title} = "" if $last_title and $line->{title} eq $last_title;
164 $last_title = $line->{title} if ( $line->{title} );
165 $line->{planneddate} = format_date( $line->{planneddate} );
166 push @issuelist, $line;
168 return @issuelist;
171 =head2 GetSubscriptionHistoryFromSubscriptionId
173 $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
175 This function returns the subscription history as a hashref
177 =cut
179 sub GetSubscriptionHistoryFromSubscriptionId {
180 my ($subscriptionid) = @_;
182 return unless $subscriptionid;
184 my $dbh = C4::Context->dbh;
185 my $query = qq|
186 SELECT *
187 FROM subscriptionhistory
188 WHERE subscriptionid = ?
190 my $sth = $dbh->prepare($query);
191 $sth->execute($subscriptionid);
192 my $results = $sth->fetchrow_hashref;
193 $sth->finish;
195 return $results;
198 =head2 GetSerialStatusFromSerialId
200 $sth = GetSerialStatusFromSerialId();
201 this function returns a statement handle
202 After this function, don't forget to execute it by using $sth->execute($serialid)
203 return :
204 $sth = $dbh->prepare($query).
206 =cut
208 sub GetSerialStatusFromSerialId {
209 my $dbh = C4::Context->dbh;
210 my $query = qq|
211 SELECT status
212 FROM serial
213 WHERE serialid = ?
215 return $dbh->prepare($query);
218 =head2 GetSerialInformation
221 $data = GetSerialInformation($serialid);
222 returns a hash_ref containing :
223 items : items marcrecord (can be an array)
224 serial table field
225 subscription table field
226 + information about subscription expiration
228 =cut
230 sub GetSerialInformation {
231 my ($serialid) = @_;
232 my $dbh = C4::Context->dbh;
233 my $query = qq|
234 SELECT serial.*, serial.notes as sernotes, serial.status as serstatus,subscription.*,subscription.subscriptionid as subsid
235 FROM serial LEFT JOIN subscription ON subscription.subscriptionid=serial.subscriptionid
236 WHERE serialid = ?
238 my $rq = $dbh->prepare($query);
239 $rq->execute($serialid);
240 my $data = $rq->fetchrow_hashref;
242 # create item information if we have serialsadditems for this subscription
243 if ( $data->{'serialsadditems'} ) {
244 my $queryitem = $dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
245 $queryitem->execute($serialid);
246 my $itemnumbers = $queryitem->fetchall_arrayref( [0] );
247 require C4::Items;
248 if ( scalar(@$itemnumbers) > 0 ) {
249 foreach my $itemnum (@$itemnumbers) {
251 #It is ASSUMED that GetMarcItem ALWAYS WORK...
252 #Maybe GetMarcItem should return values on failure
253 $debug and warn "itemnumber :$itemnum->[0], bibnum :" . $data->{'biblionumber'};
254 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, $itemnum->[0], $data );
255 $itemprocessed->{'itemnumber'} = $itemnum->[0];
256 $itemprocessed->{'itemid'} = $itemnum->[0];
257 $itemprocessed->{'serialid'} = $serialid;
258 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
259 push @{ $data->{'items'} }, $itemprocessed;
261 } else {
262 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, '', $data );
263 $itemprocessed->{'itemid'} = "N$serialid";
264 $itemprocessed->{'serialid'} = $serialid;
265 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
266 $itemprocessed->{'countitems'} = 0;
267 push @{ $data->{'items'} }, $itemprocessed;
270 $data->{ "status" . $data->{'serstatus'} } = 1;
271 $data->{'subscriptionexpired'} = HasSubscriptionExpired( $data->{'subscriptionid'} ) && $data->{'status'} == 1;
272 $data->{'abouttoexpire'} = abouttoexpire( $data->{'subscriptionid'} );
273 $data->{cannotedit} = not can_edit_subscription( $data );
274 return $data;
277 =head2 AddItem2Serial
279 $rows = AddItem2Serial($serialid,$itemnumber);
280 Adds an itemnumber to Serial record
281 returns the number of rows affected
283 =cut
285 sub AddItem2Serial {
286 my ( $serialid, $itemnumber ) = @_;
288 return unless ($serialid and $itemnumber);
290 my $dbh = C4::Context->dbh;
291 my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
292 $rq->execute( $serialid, $itemnumber );
293 return $rq->rows;
296 =head2 UpdateClaimdateIssues
298 UpdateClaimdateIssues($serialids,[$date]);
300 Update Claimdate for issues in @$serialids list with date $date
301 (Take Today if none)
303 =cut
305 sub UpdateClaimdateIssues {
306 my ( $serialids, $date ) = @_;
308 return unless ($serialids);
310 my $dbh = C4::Context->dbh;
311 $date = strftime( "%Y-%m-%d", localtime ) unless ($date);
312 my $query = "
313 UPDATE serial
314 SET claimdate = ?,
315 status = 7,
316 claims_count = claims_count + 1
317 WHERE serialid in (" . join( ",", map { '?' } @$serialids ) . ")
319 my $rq = $dbh->prepare($query);
320 $rq->execute($date, @$serialids);
321 return $rq->rows;
324 =head2 GetSubscription
326 $subs = GetSubscription($subscriptionid)
327 this function returns the subscription which has $subscriptionid as id.
328 return :
329 a hashref. This hash containts
330 subscription, subscriptionhistory, aqbooksellers.name, biblio.title
332 =cut
334 sub GetSubscription {
335 my ($subscriptionid) = @_;
336 my $dbh = C4::Context->dbh;
337 my $query = qq(
338 SELECT subscription.*,
339 subscriptionhistory.*,
340 aqbooksellers.name AS aqbooksellername,
341 biblio.title AS bibliotitle,
342 subscription.biblionumber as bibnum
343 FROM subscription
344 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
345 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
346 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
347 WHERE subscription.subscriptionid = ?
350 $debug and warn "query : $query\nsubsid :$subscriptionid";
351 my $sth = $dbh->prepare($query);
352 $sth->execute($subscriptionid);
353 my $subscription = $sth->fetchrow_hashref;
354 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
355 return $subscription;
358 =head2 GetFullSubscription
360 $array_ref = GetFullSubscription($subscriptionid)
361 this function reads the serial table.
363 =cut
365 sub GetFullSubscription {
366 my ($subscriptionid) = @_;
368 return unless ($subscriptionid);
370 my $dbh = C4::Context->dbh;
371 my $query = qq|
372 SELECT serial.serialid,
373 serial.serialseq,
374 serial.planneddate,
375 serial.publisheddate,
376 serial.status,
377 serial.notes as notes,
378 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
379 aqbooksellers.name as aqbooksellername,
380 biblio.title as bibliotitle,
381 subscription.branchcode AS branchcode,
382 subscription.subscriptionid AS subscriptionid
383 FROM serial
384 LEFT JOIN subscription ON
385 (serial.subscriptionid=subscription.subscriptionid )
386 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
387 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
388 WHERE serial.subscriptionid = ?
389 ORDER BY year DESC,
390 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
391 serial.subscriptionid
393 $debug and warn "GetFullSubscription query: $query";
394 my $sth = $dbh->prepare($query);
395 $sth->execute($subscriptionid);
396 my $subscriptions = $sth->fetchall_arrayref( {} );
397 for my $subscription ( @$subscriptions ) {
398 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
400 return $subscriptions;
403 =head2 PrepareSerialsData
405 $array_ref = PrepareSerialsData($serialinfomation)
406 where serialinformation is a hashref array
408 =cut
410 sub PrepareSerialsData {
411 my ($lines) = @_;
413 return unless ($lines);
415 my %tmpresults;
416 my $year;
417 my @res;
418 my $startdate;
419 my $aqbooksellername;
420 my $bibliotitle;
421 my @loopissues;
422 my $first;
423 my $previousnote = "";
425 foreach my $subs (@{$lines}) {
426 for my $datefield ( qw(publisheddate planneddate) ) {
427 # handle 0000-00-00 dates
428 if (defined $subs->{$datefield} and $subs->{$datefield} =~ m/^00/) {
429 $subs->{$datefield} = undef;
432 $subs->{ "status" . $subs->{'status'} } = 1;
433 if ( grep { $_ == $subs->{status} } qw( 1 3 4 41 42 43 44 7 ) ) {
434 $subs->{"checked"} = 1;
437 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
438 $year = $subs->{'year'};
439 } else {
440 $year = "manage";
442 if ( $tmpresults{$year} ) {
443 push @{ $tmpresults{$year}->{'serials'} }, $subs;
444 } else {
445 $tmpresults{$year} = {
446 'year' => $year,
447 'aqbooksellername' => $subs->{'aqbooksellername'},
448 'bibliotitle' => $subs->{'bibliotitle'},
449 'serials' => [$subs],
450 'first' => $first,
454 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
455 push @res, $tmpresults{$key};
457 return \@res;
460 =head2 GetSubscriptionsFromBiblionumber
462 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
463 this function get the subscription list. it reads the subscription table.
464 return :
465 reference to an array of subscriptions which have the biblionumber given on input arg.
466 each element of this array is a hashref containing
467 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
469 =cut
471 sub GetSubscriptionsFromBiblionumber {
472 my ($biblionumber) = @_;
474 return unless ($biblionumber);
476 my $dbh = C4::Context->dbh;
477 my $query = qq(
478 SELECT subscription.*,
479 branches.branchname,
480 subscriptionhistory.*,
481 aqbooksellers.name AS aqbooksellername,
482 biblio.title AS bibliotitle
483 FROM subscription
484 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
485 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
486 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
487 LEFT JOIN branches ON branches.branchcode=subscription.branchcode
488 WHERE subscription.biblionumber = ?
490 my $sth = $dbh->prepare($query);
491 $sth->execute($biblionumber);
492 my @res;
493 while ( my $subs = $sth->fetchrow_hashref ) {
494 $subs->{startdate} = format_date( $subs->{startdate} );
495 $subs->{histstartdate} = format_date( $subs->{histstartdate} );
496 $subs->{histenddate} = format_date( $subs->{histenddate} );
497 $subs->{opacnote} =~ s/\n/\<br\/\>/g;
498 $subs->{missinglist} =~ s/\n/\<br\/\>/g;
499 $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
500 $subs->{ "periodicity" . $subs->{periodicity} } = 1;
501 $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
502 $subs->{ "status" . $subs->{'status'} } = 1;
504 if ( $subs->{enddate} eq '0000-00-00' ) {
505 $subs->{enddate} = '';
506 } else {
507 $subs->{enddate} = format_date( $subs->{enddate} );
509 $subs->{'abouttoexpire'} = abouttoexpire( $subs->{'subscriptionid'} );
510 $subs->{'subscriptionexpired'} = HasSubscriptionExpired( $subs->{'subscriptionid'} );
511 $subs->{cannotedit} = not can_edit_subscription( $subs );
512 push @res, $subs;
514 return \@res;
517 =head2 GetFullSubscriptionsFromBiblionumber
519 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
520 this function reads the serial table.
522 =cut
524 sub GetFullSubscriptionsFromBiblionumber {
525 my ($biblionumber) = @_;
526 my $dbh = C4::Context->dbh;
527 my $query = qq|
528 SELECT serial.serialid,
529 serial.serialseq,
530 serial.planneddate,
531 serial.publisheddate,
532 serial.status,
533 serial.notes as notes,
534 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
535 biblio.title as bibliotitle,
536 subscription.branchcode AS branchcode,
537 subscription.subscriptionid AS subscriptionid
538 FROM serial
539 LEFT JOIN subscription ON
540 (serial.subscriptionid=subscription.subscriptionid)
541 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
542 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
543 WHERE subscription.biblionumber = ?
544 ORDER BY year DESC,
545 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
546 serial.subscriptionid
548 my $sth = $dbh->prepare($query);
549 $sth->execute($biblionumber);
550 my $subscriptions = $sth->fetchall_arrayref( {} );
551 for my $subscription ( @$subscriptions ) {
552 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
554 return $subscriptions;
557 =head2 GetSubscriptions
559 @results = GetSubscriptions($title,$ISSN,$ean,$biblionumber);
560 this function gets all subscriptions which have title like $title,ISSN like $ISSN,EAN like $ean and biblionumber like $biblionumber.
561 return:
562 a table of hashref. Each hash containt the subscription.
564 =cut
566 sub GetSubscriptions {
567 my ( $string, $issn, $ean, $biblionumber ) = @_;
569 #return unless $title or $ISSN or $biblionumber;
570 my $dbh = C4::Context->dbh;
571 my $sth;
572 my $sql = qq(
573 SELECT subscriptionhistory.*, subscription.*, biblio.title,biblioitems.issn,biblio.biblionumber
574 FROM subscription
575 LEFT JOIN subscriptionhistory USING(subscriptionid)
576 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
577 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
579 my @bind_params;
580 my $sqlwhere = q{};
581 if ($biblionumber) {
582 $sqlwhere = " WHERE biblio.biblionumber=?";
583 push @bind_params, $biblionumber;
585 if ($string) {
586 my @sqlstrings;
587 my @strings_to_search;
588 @strings_to_search = map { "%$_%" } split( / /, $string );
589 foreach my $index (qw(biblio.title subscription.callnumber subscription.location subscription.notes subscription.internalnotes)) {
590 push @bind_params, @strings_to_search;
591 my $tmpstring = "AND $index LIKE ? " x scalar(@strings_to_search);
592 $debug && warn "$tmpstring";
593 $tmpstring =~ s/^AND //;
594 push @sqlstrings, $tmpstring;
596 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
598 if ($issn) {
599 my @sqlstrings;
600 my @strings_to_search;
601 @strings_to_search = map { "%$_%" } split( / /, $issn );
602 foreach my $index ( qw(biblioitems.issn subscription.callnumber)) {
603 push @bind_params, @strings_to_search;
604 my $tmpstring = "OR $index LIKE ? " x scalar(@strings_to_search);
605 $debug && warn "$tmpstring";
606 $tmpstring =~ s/^OR //;
607 push @sqlstrings, $tmpstring;
609 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
611 if ($ean) {
612 my @sqlstrings;
613 my @strings_to_search;
614 @strings_to_search = map { "$_" } split( / /, $ean );
615 foreach my $index ( qw(biblioitems.ean) ) {
616 push @bind_params, @strings_to_search;
617 my $tmpstring = "OR $index = ? " x scalar(@strings_to_search);
618 $debug && warn "$tmpstring";
619 $tmpstring =~ s/^OR //;
620 push @sqlstrings, $tmpstring;
622 $sqlwhere .= ( $sqlwhere ? " AND " : " WHERE " ) . "((" . join( ") OR (", @sqlstrings ) . "))";
625 $sql .= "$sqlwhere ORDER BY title";
626 $debug and warn "GetSubscriptions query: $sql params : ", join( " ", @bind_params );
627 $sth = $dbh->prepare($sql);
628 $sth->execute(@bind_params);
629 my $subscriptions = $sth->fetchall_arrayref( {} );
630 for my $subscription ( @$subscriptions ) {
631 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
633 return @$subscriptions;
636 =head2 SearchSubscriptions
638 @results = SearchSubscriptions($args);
640 This function returns a list of hashrefs, one for each subscription
641 that meets the conditions specified by the $args hashref.
643 The valid search fields are:
645 biblionumber
646 title
647 issn
649 callnumber
650 location
651 publisher
652 bookseller
653 branch
654 expiration_date
655 closed
657 The expiration_date search field is special; it specifies the maximum
658 subscription expiration date.
660 =cut
662 sub SearchSubscriptions {
663 my ( $args ) = @_;
665 my $query = qq{
666 SELECT
667 subscription.notes AS publicnotes,
668 subscription.*,
669 subscriptionhistory.*,
670 biblio.notes AS biblionotes,
671 biblio.title,
672 biblio.author,
673 biblioitems.issn
674 FROM subscription
675 LEFT JOIN subscriptionhistory USING(subscriptionid)
676 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
677 LEFT JOIN biblioitems ON biblioitems.biblionumber = subscription.biblionumber
678 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
680 my @where_strs;
681 my @where_args;
682 if( $args->{biblionumber} ) {
683 push @where_strs, "biblio.biblionumber = ?";
684 push @where_args, $args->{biblionumber};
686 if( $args->{title} ){
687 my @words = split / /, $args->{title};
688 my (@strs, @args);
689 foreach my $word (@words) {
690 push @strs, "biblio.title LIKE ?";
691 push @args, "%$word%";
693 if (@strs) {
694 push @where_strs, '(' . join (' AND ', @strs) . ')';
695 push @where_args, @args;
698 if( $args->{issn} ){
699 push @where_strs, "biblioitems.issn LIKE ?";
700 push @where_args, "%$args->{issn}%";
702 if( $args->{ean} ){
703 push @where_strs, "biblioitems.ean LIKE ?";
704 push @where_args, "%$args->{ean}%";
706 if ( $args->{callnumber} ) {
707 push @where_strs, "subscription.callnumber LIKE ?";
708 push @where_args, "%$args->{callnumber}%";
710 if( $args->{publisher} ){
711 push @where_strs, "biblioitems.publishercode LIKE ?";
712 push @where_args, "%$args->{publisher}%";
714 if( $args->{bookseller} ){
715 push @where_strs, "aqbooksellers.name LIKE ?";
716 push @where_args, "%$args->{bookseller}%";
718 if( $args->{branch} ){
719 push @where_strs, "subscription.branchcode = ?";
720 push @where_args, "$args->{branch}";
722 if ( $args->{location} ) {
723 push @where_strs, "subscription.location = ?";
724 push @where_args, "$args->{location}";
726 if ( $args->{expiration_date} ) {
727 push @where_strs, "subscription.enddate <= ?";
728 push @where_args, "$args->{expiration_date}";
730 if( defined $args->{closed} ){
731 push @where_strs, "subscription.closed = ?";
732 push @where_args, "$args->{closed}";
734 if(@where_strs){
735 $query .= " WHERE " . join(" AND ", @where_strs);
738 my $dbh = C4::Context->dbh;
739 my $sth = $dbh->prepare($query);
740 $sth->execute(@where_args);
741 my $results = $sth->fetchall_arrayref( {} );
742 $sth->finish;
744 for my $subscription ( @$results ) {
745 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
746 $subscription->{cannotdisplay} = not can_show_subscription( $subscription );
749 return @$results;
753 =head2 GetSerials
755 ($totalissues,@serials) = GetSerials($subscriptionid);
756 this function gets every serial not arrived for a given subscription
757 as well as the number of issues registered in the database (all types)
758 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
760 FIXME: We should return \@serials.
762 =cut
764 sub GetSerials {
765 my ( $subscriptionid, $count ) = @_;
767 return unless $subscriptionid;
769 my $dbh = C4::Context->dbh;
771 # status = 2 is "arrived"
772 my $counter = 0;
773 $count = 5 unless ($count);
774 my @serials;
775 my $query = "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
776 FROM serial
777 WHERE subscriptionid = ? AND status NOT IN (2, 4, 41, 42, 43, 44, 5)
778 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
779 my $sth = $dbh->prepare($query);
780 $sth->execute($subscriptionid);
782 while ( my $line = $sth->fetchrow_hashref ) {
783 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
784 for my $datefield ( qw( planneddate publisheddate) ) {
785 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
786 $line->{$datefield} = format_date( $line->{$datefield});
787 } else {
788 $line->{$datefield} = q{};
791 push @serials, $line;
794 # OK, now add the last 5 issues arrives/missing
795 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
796 FROM serial
797 WHERE subscriptionid = ?
798 AND (status in (2, 4, 41, 42, 43, 44, 5))
799 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
801 $sth = $dbh->prepare($query);
802 $sth->execute($subscriptionid);
803 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
804 $counter++;
805 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
806 for my $datefield ( qw( planneddate publisheddate) ) {
807 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
808 $line->{$datefield} = format_date( $line->{$datefield});
809 } else {
810 $line->{$datefield} = q{};
814 push @serials, $line;
817 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
818 $sth = $dbh->prepare($query);
819 $sth->execute($subscriptionid);
820 my ($totalissues) = $sth->fetchrow;
821 return ( $totalissues, @serials );
824 =head2 GetSerials2
826 @serials = GetSerials2($subscriptionid,$status);
827 this function returns every serial waited for a given subscription
828 as well as the number of issues registered in the database (all types)
829 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
831 =cut
833 sub GetSerials2 {
834 my ( $subscription, $status ) = @_;
836 return unless ($subscription and $status);
838 my $dbh = C4::Context->dbh;
839 my $query = qq|
840 SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
841 FROM serial
842 WHERE subscriptionid=$subscription AND status IN ($status)
843 ORDER BY publisheddate,serialid DESC
845 $debug and warn "GetSerials2 query: $query";
846 my $sth = $dbh->prepare($query);
847 $sth->execute;
848 my @serials;
850 while ( my $line = $sth->fetchrow_hashref ) {
851 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
852 # Format dates for display
853 for my $datefield ( qw( planneddate publisheddate ) ) {
854 if (!defined($line->{$datefield}) || $line->{$datefield} =~m/^00/) {
855 $line->{$datefield} = q{};
857 else {
858 $line->{$datefield} = format_date( $line->{$datefield} );
861 push @serials, $line;
863 return @serials;
866 =head2 GetLatestSerials
868 \@serials = GetLatestSerials($subscriptionid,$limit)
869 get the $limit's latest serials arrived or missing for a given subscription
870 return :
871 a ref to an array which contains all of the latest serials stored into a hash.
873 =cut
875 sub GetLatestSerials {
876 my ( $subscriptionid, $limit ) = @_;
878 return unless ($subscriptionid and $limit);
880 my $dbh = C4::Context->dbh;
882 # status = 2 is "arrived"
883 my $strsth = "SELECT serialid,serialseq, status, planneddate, publisheddate, notes
884 FROM serial
885 WHERE subscriptionid = ?
886 AND status IN (2, 4, 41, 42, 43, 44)
887 ORDER BY publisheddate DESC LIMIT 0,$limit
889 my $sth = $dbh->prepare($strsth);
890 $sth->execute($subscriptionid);
891 my @serials;
892 while ( my $line = $sth->fetchrow_hashref ) {
893 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
894 $line->{"planneddate"} = format_date( $line->{"planneddate"} );
895 $line->{"publisheddate"} = format_date( $line->{"publisheddate"} );
896 push @serials, $line;
899 return \@serials;
902 =head2 GetDistributedTo
904 $distributedto=GetDistributedTo($subscriptionid)
905 This function returns the field distributedto for the subscription matching subscriptionid
907 =cut
909 sub GetDistributedTo {
910 my $dbh = C4::Context->dbh;
911 my $distributedto;
912 my ($subscriptionid) = @_;
914 return unless ($subscriptionid);
916 my $query = "SELECT distributedto FROM subscription WHERE subscriptionid=?";
917 my $sth = $dbh->prepare($query);
918 $sth->execute($subscriptionid);
919 return ($distributedto) = $sth->fetchrow;
922 =head2 GetNextSeq
924 my (
925 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
926 $newinnerloop1, $newinnerloop2, $newinnerloop3
927 ) = GetNextSeq( $subscription, $pattern, $planneddate );
929 $subscription is a hashref containing all the attributes of the table
930 'subscription'.
931 $pattern is a hashref containing all the attributes of the table
932 'subscription_numberpatterns'.
933 $planneddate is a C4::Dates object.
934 This function get the next issue for the subscription given on input arg
936 =cut
938 sub GetNextSeq {
939 my ($subscription, $pattern, $planneddate) = @_;
941 return unless ($subscription and $pattern);
943 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
944 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
945 my $count = 1;
947 if ($subscription->{'skip_serialseq'}) {
948 my @irreg = split /;/, $subscription->{'irregularity'};
949 if(@irreg > 0) {
950 my $irregularities = {};
951 $irregularities->{$_} = 1 foreach(@irreg);
952 my $issueno = GetFictiveIssueNumber($subscription, $planneddate) + 1;
953 while($irregularities->{$issueno}) {
954 $count++;
955 $issueno++;
960 my $numberingmethod = $pattern->{numberingmethod};
961 my $calculated = "";
962 if ($numberingmethod) {
963 $calculated = $numberingmethod;
964 my $locale = $subscription->{locale};
965 $newlastvalue1 = $subscription->{lastvalue1} || 0;
966 $newlastvalue2 = $subscription->{lastvalue2} || 0;
967 $newlastvalue3 = $subscription->{lastvalue3} || 0;
968 $newinnerloop1 = $subscription->{innerloop1} || 0;
969 $newinnerloop2 = $subscription->{innerloop2} || 0;
970 $newinnerloop3 = $subscription->{innerloop3} || 0;
971 my %calc;
972 foreach(qw/X Y Z/) {
973 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
976 for(my $i = 0; $i < $count; $i++) {
977 if($calc{'X'}) {
978 # check if we have to increase the new value.
979 $newinnerloop1 += 1;
980 if ($newinnerloop1 >= $pattern->{every1}) {
981 $newinnerloop1 = 0;
982 $newlastvalue1 += $pattern->{add1};
984 # reset counter if needed.
985 $newlastvalue1 = $pattern->{setto1} if ($newlastvalue1 > $pattern->{whenmorethan1});
987 if($calc{'Y'}) {
988 # check if we have to increase the new value.
989 $newinnerloop2 += 1;
990 if ($newinnerloop2 >= $pattern->{every2}) {
991 $newinnerloop2 = 0;
992 $newlastvalue2 += $pattern->{add2};
994 # reset counter if needed.
995 $newlastvalue2 = $pattern->{setto2} if ($newlastvalue2 > $pattern->{whenmorethan2});
997 if($calc{'Z'}) {
998 # check if we have to increase the new value.
999 $newinnerloop3 += 1;
1000 if ($newinnerloop3 >= $pattern->{every3}) {
1001 $newinnerloop3 = 0;
1002 $newlastvalue3 += $pattern->{add3};
1004 # reset counter if needed.
1005 $newlastvalue3 = $pattern->{setto3} if ($newlastvalue3 > $pattern->{whenmorethan3});
1008 if($calc{'X'}) {
1009 my $newlastvalue1string = _numeration( $newlastvalue1, $pattern->{numbering1}, $locale );
1010 $calculated =~ s/\{X\}/$newlastvalue1string/g;
1012 if($calc{'Y'}) {
1013 my $newlastvalue2string = _numeration( $newlastvalue2, $pattern->{numbering2}, $locale );
1014 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
1016 if($calc{'Z'}) {
1017 my $newlastvalue3string = _numeration( $newlastvalue3, $pattern->{numbering3}, $locale );
1018 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
1022 return ($calculated,
1023 $newlastvalue1, $newlastvalue2, $newlastvalue3,
1024 $newinnerloop1, $newinnerloop2, $newinnerloop3);
1027 =head2 GetSeq
1029 $calculated = GetSeq($subscription, $pattern)
1030 $subscription is a hashref containing all the attributes of the table 'subscription'
1031 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
1032 this function transforms {X},{Y},{Z} to 150,0,0 for example.
1033 return:
1034 the sequence in string format
1036 =cut
1038 sub GetSeq {
1039 my ($subscription, $pattern) = @_;
1041 return unless ($subscription and $pattern);
1043 my $locale = $subscription->{locale};
1045 my $calculated = $pattern->{numberingmethod};
1047 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
1048 $newlastvalue1 = _numeration($newlastvalue1, $pattern->{numbering1}, $locale) if ($pattern->{numbering1}); # reset counter if needed.
1049 $calculated =~ s/\{X\}/$newlastvalue1/g;
1051 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
1052 $newlastvalue2 = _numeration($newlastvalue2, $pattern->{numbering2}, $locale) if ($pattern->{numbering2}); # reset counter if needed.
1053 $calculated =~ s/\{Y\}/$newlastvalue2/g;
1055 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
1056 $newlastvalue3 = _numeration($newlastvalue3, $pattern->{numbering3}, $locale) if ($pattern->{numbering3}); # reset counter if needed.
1057 $calculated =~ s/\{Z\}/$newlastvalue3/g;
1058 return $calculated;
1061 =head2 GetExpirationDate
1063 $enddate = GetExpirationDate($subscriptionid, [$startdate])
1065 this function return the next expiration date for a subscription given on input args.
1067 return
1068 the enddate or undef
1070 =cut
1072 sub GetExpirationDate {
1073 my ( $subscriptionid, $startdate ) = @_;
1075 return unless ($subscriptionid);
1077 my $dbh = C4::Context->dbh;
1078 my $subscription = GetSubscription($subscriptionid);
1079 my $enddate;
1081 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
1082 $enddate = $startdate || $subscription->{startdate};
1083 my @date = split( /-/, $enddate );
1085 return if ( scalar(@date) != 3 || not check_date(@date) );
1087 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
1088 if ( $frequency and $frequency->{unit} ) {
1090 # If Not Irregular
1091 if ( my $length = $subscription->{numberlength} ) {
1093 #calculate the date of the last issue.
1094 for ( my $i = 1 ; $i <= $length ; $i++ ) {
1095 $enddate = GetNextDate( $subscription, $enddate );
1097 } elsif ( $subscription->{monthlength} ) {
1098 if ( $$subscription{startdate} ) {
1099 my @enddate = Add_Delta_YM( $date[0], $date[1], $date[2], 0, $subscription->{monthlength} );
1100 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1102 } elsif ( $subscription->{weeklength} ) {
1103 if ( $$subscription{startdate} ) {
1104 my @date = split( /-/, $subscription->{startdate} );
1105 my @enddate = Add_Delta_Days( $date[0], $date[1], $date[2], $subscription->{weeklength} * 7 );
1106 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1108 } else {
1109 $enddate = $subscription->{enddate};
1111 return $enddate;
1112 } else {
1113 return $subscription->{enddate};
1117 =head2 CountSubscriptionFromBiblionumber
1119 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1120 this returns a count of the subscriptions for a given biblionumber
1121 return :
1122 the number of subscriptions
1124 =cut
1126 sub CountSubscriptionFromBiblionumber {
1127 my ($biblionumber) = @_;
1129 return unless ($biblionumber);
1131 my $dbh = C4::Context->dbh;
1132 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1133 my $sth = $dbh->prepare($query);
1134 $sth->execute($biblionumber);
1135 my $subscriptionsnumber = $sth->fetchrow;
1136 return $subscriptionsnumber;
1139 =head2 ModSubscriptionHistory
1141 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1143 this function modifies the history of a subscription. Put your new values on input arg.
1144 returns the number of rows affected
1146 =cut
1148 sub ModSubscriptionHistory {
1149 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1151 return unless ($subscriptionid);
1153 my $dbh = C4::Context->dbh;
1154 my $query = "UPDATE subscriptionhistory
1155 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1156 WHERE subscriptionid=?
1158 my $sth = $dbh->prepare($query);
1159 $receivedlist =~ s/^; // if $receivedlist;
1160 $missinglist =~ s/^; // if $missinglist;
1161 $opacnote =~ s/^; // if $opacnote;
1162 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1163 return $sth->rows;
1166 =head2 ModSerialStatus
1168 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
1170 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1171 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1173 =cut
1175 sub ModSerialStatus {
1176 my ( $serialid, $serialseq, $planneddate, $publisheddate, $status, $notes ) = @_;
1178 return unless ($serialid);
1180 #It is a usual serial
1181 # 1st, get previous status :
1182 my $dbh = C4::Context->dbh;
1183 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
1184 FROM serial, subscription
1185 WHERE serial.subscriptionid=subscription.subscriptionid
1186 AND serialid=?";
1187 my $sth = $dbh->prepare($query);
1188 $sth->execute($serialid);
1189 my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
1190 my $frequency = GetSubscriptionFrequency($periodicity);
1192 # change status & update subscriptionhistory
1193 my $val;
1194 if ( $status == 6 ) {
1195 DelIssue( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1196 } else {
1198 my $query = 'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE serialid = ?';
1199 $sth = $dbh->prepare($query);
1200 $sth->execute( $serialseq, $publisheddate, $planneddate, $status, $notes, $serialid );
1201 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1202 $sth = $dbh->prepare($query);
1203 $sth->execute($subscriptionid);
1204 my $val = $sth->fetchrow_hashref;
1205 unless ( $val->{manualhistory} ) {
1206 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1207 $sth = $dbh->prepare($query);
1208 $sth->execute($subscriptionid);
1209 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1211 if ( $status == 2 || ($oldstatus == 2 && $status != 2) ) {
1212 $recievedlist .= "; $serialseq"
1213 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1216 # in case serial has been previously marked as missing
1217 if (grep /$status/, (1,2,3,7)) {
1218 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1221 my @missing_statuses = qw( 4 41 42 43 44 );
1222 $missinglist .= "; $serialseq"
1223 if ( ( grep { $_ == $status } @missing_statuses ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1224 $missinglist .= "; not issued $serialseq"
1225 if ( $status == 5 && $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1227 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1228 $sth = $dbh->prepare($query);
1229 $recievedlist =~ s/^; //;
1230 $missinglist =~ s/^; //;
1231 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1235 # create new waited entry if needed (ie : was a "waited" and has changed)
1236 if ( $oldstatus == 1 && $status != 1 ) {
1237 my $subscription = GetSubscription($subscriptionid);
1238 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
1240 # next issue number
1241 my (
1242 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1243 $newinnerloop1, $newinnerloop2, $newinnerloop3
1245 = GetNextSeq( $subscription, $pattern, $publisheddate );
1247 # next date (calculated from actual date & frequency parameters)
1248 my $nextpublisheddate = GetNextDate($subscription, $publisheddate, 1);
1249 my $nextpubdate = $nextpublisheddate;
1250 NewIssue( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
1251 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1252 WHERE subscriptionid = ?";
1253 $sth = $dbh->prepare($query);
1254 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1256 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1257 if ( $subscription->{letter} && $status == 2 && $oldstatus != 2 ) {
1258 require C4::Letters;
1259 C4::Letters::SendAlerts( 'issue', $subscription->{subscriptionid}, $subscription->{letter} );
1263 return;
1266 =head2 GetNextExpected
1268 $nextexpected = GetNextExpected($subscriptionid)
1270 Get the planneddate for the current expected issue of the subscription.
1272 returns a hashref:
1274 $nextexepected = {
1275 serialid => int
1276 planneddate => ISO date
1279 =cut
1281 sub GetNextExpected {
1282 my ($subscriptionid) = @_;
1284 my $dbh = C4::Context->dbh;
1285 my $query = qq{
1286 SELECT *
1287 FROM serial
1288 WHERE subscriptionid = ?
1289 AND status = ?
1290 LIMIT 1
1292 my $sth = $dbh->prepare($query);
1294 # Each subscription has only one 'expected' issue, with serial.status==1.
1295 $sth->execute( $subscriptionid, 1 );
1296 my $nextissue = $sth->fetchrow_hashref;
1297 if ( !$nextissue ) {
1298 $query = qq{
1299 SELECT *
1300 FROM serial
1301 WHERE subscriptionid = ?
1302 ORDER BY publisheddate DESC
1303 LIMIT 1
1305 $sth = $dbh->prepare($query);
1306 $sth->execute($subscriptionid);
1307 $nextissue = $sth->fetchrow_hashref;
1309 foreach(qw/planneddate publisheddate/) {
1310 if ( !defined $nextissue->{$_} ) {
1311 # or should this default to 1st Jan ???
1312 $nextissue->{$_} = strftime( '%Y-%m-%d', localtime );
1314 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1315 ? $nextissue->{$_}
1316 : undef;
1319 return $nextissue;
1322 =head2 ModNextExpected
1324 ModNextExpected($subscriptionid,$date)
1326 Update the planneddate for the current expected issue of the subscription.
1327 This will modify all future prediction results.
1329 C<$date> is an ISO date.
1331 returns 0
1333 =cut
1335 sub ModNextExpected {
1336 my ( $subscriptionid, $date ) = @_;
1337 my $dbh = C4::Context->dbh;
1339 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1340 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1342 # Each subscription has only one 'expected' issue, with serial.status==1.
1343 $sth->execute( $date, $date, $subscriptionid, 1 );
1344 return 0;
1348 =head2 GetSubscriptionIrregularities
1350 =over 4
1352 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1353 get the list of irregularities for a subscription
1355 =back
1357 =cut
1359 sub GetSubscriptionIrregularities {
1360 my $subscriptionid = shift;
1362 return unless $subscriptionid;
1364 my $dbh = C4::Context->dbh;
1365 my $query = qq{
1366 SELECT irregularity
1367 FROM subscription
1368 WHERE subscriptionid = ?
1370 my $sth = $dbh->prepare($query);
1371 $sth->execute($subscriptionid);
1373 my ($result) = $sth->fetchrow_array;
1374 my @irreg = split /;/, $result;
1376 return @irreg;
1379 =head2 ModSubscription
1381 this function modifies a subscription. Put all new values on input args.
1382 returns the number of rows affected
1384 =cut
1386 sub ModSubscription {
1387 my (
1388 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1389 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1390 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1391 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1392 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1393 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1394 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq
1395 ) = @_;
1397 my $dbh = C4::Context->dbh;
1398 my $query = "UPDATE subscription
1399 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1400 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1401 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1402 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1403 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1404 callnumber=?, notes=?, letter=?, manualhistory=?,
1405 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1406 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1407 skip_serialseq=?
1408 WHERE subscriptionid = ?";
1410 my $sth = $dbh->prepare($query);
1411 $sth->execute(
1412 $auser, $branchcode, $aqbooksellerid, $cost,
1413 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1414 $irregularity, $numberpattern, $locale, $numberlength,
1415 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1416 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1417 $status, $biblionumber, $callnumber, $notes,
1418 $letter, ($manualhistory ? $manualhistory : 0),
1419 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1420 $graceperiod, $location, $enddate, $skip_serialseq,
1421 $subscriptionid
1423 my $rows = $sth->rows;
1425 logaction( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1426 return $rows;
1429 =head2 NewSubscription
1431 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1432 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1433 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1434 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1435 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1436 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq);
1438 Create a new subscription with value given on input args.
1440 return :
1441 the id of this new subscription
1443 =cut
1445 sub NewSubscription {
1446 my (
1447 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1448 $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
1449 $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
1450 $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
1451 $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
1452 $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
1453 $location, $enddate, $skip_serialseq
1454 ) = @_;
1455 my $dbh = C4::Context->dbh;
1457 #save subscription (insert into database)
1458 my $query = qq|
1459 INSERT INTO subscription
1460 (librarian, branchcode, aqbooksellerid, cost, aqbudgetid,
1461 biblionumber, startdate, periodicity, numberlength, weeklength,
1462 monthlength, lastvalue1, innerloop1, lastvalue2, innerloop2,
1463 lastvalue3, innerloop3, status, notes, letter, firstacquidate,
1464 irregularity, numberpattern, locale, callnumber,
1465 manualhistory, internalnotes, serialsadditems, staffdisplaycount,
1466 opacdisplaycount, graceperiod, location, enddate, skip_serialseq)
1467 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
1469 my $sth = $dbh->prepare($query);
1470 $sth->execute(
1471 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1472 $startdate, $periodicity, $numberlength, $weeklength,
1473 $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
1474 $lastvalue3, $innerloop3, $status, $notes, $letter,
1475 $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
1476 $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
1477 $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq
1480 my $subscriptionid = $dbh->{'mysql_insertid'};
1481 unless ($enddate) {
1482 $enddate = GetExpirationDate( $subscriptionid, $startdate );
1483 $query = qq|
1484 UPDATE subscription
1485 SET enddate=?
1486 WHERE subscriptionid=?
1488 $sth = $dbh->prepare($query);
1489 $sth->execute( $enddate, $subscriptionid );
1492 # then create the 1st expected number
1493 $query = qq(
1494 INSERT INTO subscriptionhistory
1495 (biblionumber, subscriptionid, histstartdate)
1496 VALUES (?,?,?)
1498 $sth = $dbh->prepare($query);
1499 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1501 # reread subscription to get a hash (for calculation of the 1st issue number)
1502 my $subscription = GetSubscription($subscriptionid);
1503 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
1505 # calculate issue number
1506 my $serialseq = GetSeq($subscription, $pattern) || q{};
1507 $query = qq|
1508 INSERT INTO serial
1509 (serialseq,subscriptionid,biblionumber,status, planneddate, publisheddate)
1510 VALUES (?,?,?,?,?,?)
1512 $sth = $dbh->prepare($query);
1513 $sth->execute( $serialseq, $subscriptionid, $biblionumber, 1, $firstacquidate, $firstacquidate );
1515 logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1517 #set serial flag on biblio if not already set.
1518 my $bib = GetBiblio($biblionumber);
1519 if ( $bib and !$bib->{'serial'} ) {
1520 my $record = GetMarcBiblio($biblionumber);
1521 my ( $tag, $subf ) = GetMarcFromKohaField( 'biblio.serial', $bib->{'frameworkcode'} );
1522 if ($tag) {
1523 eval { $record->field($tag)->update( $subf => 1 ); };
1525 ModBiblio( $record, $biblionumber, $bib->{'frameworkcode'} );
1527 return $subscriptionid;
1530 =head2 ReNewSubscription
1532 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1534 this function renew a subscription with values given on input args.
1536 =cut
1538 sub ReNewSubscription {
1539 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1540 my $dbh = C4::Context->dbh;
1541 my $subscription = GetSubscription($subscriptionid);
1542 my $query = qq|
1543 SELECT *
1544 FROM biblio
1545 LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
1546 WHERE biblio.biblionumber=?
1548 my $sth = $dbh->prepare($query);
1549 $sth->execute( $subscription->{biblionumber} );
1550 my $biblio = $sth->fetchrow_hashref;
1552 if ( C4::Context->preference("RenewSerialAddsSuggestion") ) {
1553 require C4::Suggestions;
1554 C4::Suggestions::NewSuggestion(
1555 { 'suggestedby' => $user,
1556 'title' => $subscription->{bibliotitle},
1557 'author' => $biblio->{author},
1558 'publishercode' => $biblio->{publishercode},
1559 'note' => $biblio->{note},
1560 'biblionumber' => $subscription->{biblionumber}
1565 # renew subscription
1566 $query = qq|
1567 UPDATE subscription
1568 SET startdate=?,numberlength=?,weeklength=?,monthlength=?,reneweddate=NOW()
1569 WHERE subscriptionid=?
1571 $sth = $dbh->prepare($query);
1572 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1573 my $enddate = GetExpirationDate($subscriptionid);
1574 $debug && warn "enddate :$enddate";
1575 $query = qq|
1576 UPDATE subscription
1577 SET enddate=?
1578 WHERE subscriptionid=?
1580 $sth = $dbh->prepare($query);
1581 $sth->execute( $enddate, $subscriptionid );
1582 $query = qq|
1583 UPDATE subscriptionhistory
1584 SET histenddate=?
1585 WHERE subscriptionid=?
1587 $sth = $dbh->prepare($query);
1588 $sth->execute( $enddate, $subscriptionid );
1590 logaction( "SERIAL", "RENEW", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1591 return;
1594 =head2 NewIssue
1596 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1598 Create a new issue stored on the database.
1599 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1600 returns the serial id
1602 =cut
1604 sub NewIssue {
1605 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate, $publisheddate, $notes ) = @_;
1606 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1608 return unless ($subscriptionid);
1610 my $dbh = C4::Context->dbh;
1611 my $query = qq|
1612 INSERT INTO serial
1613 (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,notes)
1614 VALUES (?,?,?,?,?,?,?)
1616 my $sth = $dbh->prepare($query);
1617 $sth->execute( $serialseq, $subscriptionid, $biblionumber, $status, $publisheddate, $planneddate, $notes );
1618 my $serialid = $dbh->{'mysql_insertid'};
1619 $query = qq|
1620 SELECT missinglist,recievedlist
1621 FROM subscriptionhistory
1622 WHERE subscriptionid=?
1624 $sth = $dbh->prepare($query);
1625 $sth->execute($subscriptionid);
1626 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1628 if ( $status == 2 ) {
1629 ### TODO Add a feature that improves recognition and description.
1630 ### As such count (serialseq) i.e. : N18,2(N19),N20
1631 ### Would use substr and index But be careful to previous presence of ()
1632 $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
1634 if ( $status == 4 ) {
1635 $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
1637 $query = qq|
1638 UPDATE subscriptionhistory
1639 SET recievedlist=?, missinglist=?
1640 WHERE subscriptionid=?
1642 $sth = $dbh->prepare($query);
1643 $recievedlist =~ s/^; //;
1644 $missinglist =~ s/^; //;
1645 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1646 return $serialid;
1649 =head2 ItemizeSerials
1651 ItemizeSerials($serialid, $info);
1652 $info is a hashref containing barcode branch, itemcallnumber, status, location
1653 $serialid the serialid
1654 return :
1655 1 if the itemize is a succes.
1656 0 and @error otherwise. @error containts the list of errors found.
1658 =cut
1660 sub ItemizeSerials {
1661 my ( $serialid, $info ) = @_;
1663 return unless ($serialid);
1665 my $now = POSIX::strftime( "%Y-%m-%d", localtime );
1667 my $dbh = C4::Context->dbh;
1668 my $query = qq|
1669 SELECT *
1670 FROM serial
1671 WHERE serialid=?
1673 my $sth = $dbh->prepare($query);
1674 $sth->execute($serialid);
1675 my $data = $sth->fetchrow_hashref;
1676 if ( C4::Context->preference("RoutingSerials") ) {
1678 # check for existing biblioitem relating to serial issue
1679 my ( $count, @results ) = GetBiblioItemByBiblioNumber( $data->{'biblionumber'} );
1680 my $bibitemno = 0;
1681 for ( my $i = 0 ; $i < $count ; $i++ ) {
1682 if ( $results[$i]->{'volumeddesc'} eq $data->{'serialseq'} . ' (' . $data->{'planneddate'} . ')' ) {
1683 $bibitemno = $results[$i]->{'biblioitemnumber'};
1684 last;
1687 if ( $bibitemno == 0 ) {
1688 my $sth = $dbh->prepare( "SELECT * FROM biblioitems WHERE biblionumber = ? ORDER BY biblioitemnumber DESC" );
1689 $sth->execute( $data->{'biblionumber'} );
1690 my $biblioitem = $sth->fetchrow_hashref;
1691 $biblioitem->{'volumedate'} = $data->{planneddate};
1692 $biblioitem->{'volumeddesc'} = $data->{serialseq} . ' (' . format_date( $data->{'planneddate'} ) . ')';
1693 $biblioitem->{'dewey'} = $info->{itemcallnumber};
1697 my $fwk = GetFrameworkCode( $data->{'biblionumber'} );
1698 if ( $info->{barcode} ) {
1699 my @errors;
1700 if ( is_barcode_in_use( $info->{barcode} ) ) {
1701 push @errors, 'barcode_not_unique';
1702 } else {
1703 my $marcrecord = MARC::Record->new();
1704 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.barcode", $fwk );
1705 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{barcode} );
1706 $marcrecord->insert_fields_ordered($newField);
1707 if ( $info->{branch} ) {
1708 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.homebranch", $fwk );
1710 #warn "items.homebranch : $tag , $subfield";
1711 if ( $marcrecord->field($tag) ) {
1712 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1713 } else {
1714 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1715 $marcrecord->insert_fields_ordered($newField);
1717 ( $tag, $subfield ) = GetMarcFromKohaField( "items.holdingbranch", $fwk );
1719 #warn "items.holdingbranch : $tag , $subfield";
1720 if ( $marcrecord->field($tag) ) {
1721 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1722 } else {
1723 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1724 $marcrecord->insert_fields_ordered($newField);
1727 if ( $info->{itemcallnumber} ) {
1728 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemcallnumber", $fwk );
1730 if ( $marcrecord->field($tag) ) {
1731 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{itemcallnumber} );
1732 } else {
1733 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{itemcallnumber} );
1734 $marcrecord->insert_fields_ordered($newField);
1737 if ( $info->{notes} ) {
1738 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemnotes", $fwk );
1740 if ( $marcrecord->field($tag) ) {
1741 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{notes} );
1742 } else {
1743 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{notes} );
1744 $marcrecord->insert_fields_ordered($newField);
1747 if ( $info->{location} ) {
1748 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.location", $fwk );
1750 if ( $marcrecord->field($tag) ) {
1751 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{location} );
1752 } else {
1753 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{location} );
1754 $marcrecord->insert_fields_ordered($newField);
1757 if ( $info->{status} ) {
1758 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.notforloan", $fwk );
1760 if ( $marcrecord->field($tag) ) {
1761 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{status} );
1762 } else {
1763 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{status} );
1764 $marcrecord->insert_fields_ordered($newField);
1767 if ( C4::Context->preference("RoutingSerials") ) {
1768 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.dateaccessioned", $fwk );
1769 if ( $marcrecord->field($tag) ) {
1770 $marcrecord->field($tag)->add_subfields( "$subfield" => $now );
1771 } else {
1772 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $now );
1773 $marcrecord->insert_fields_ordered($newField);
1776 require C4::Items;
1777 C4::Items::AddItemFromMarc( $marcrecord, $data->{'biblionumber'} );
1778 return 1;
1780 return ( 0, @errors );
1784 =head2 HasSubscriptionStrictlyExpired
1786 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1788 the subscription has stricly expired when today > the end subscription date
1790 return :
1791 1 if true, 0 if false, -1 if the expiration date is not set.
1793 =cut
1795 sub HasSubscriptionStrictlyExpired {
1797 # Getting end of subscription date
1798 my ($subscriptionid) = @_;
1800 return unless ($subscriptionid);
1802 my $dbh = C4::Context->dbh;
1803 my $subscription = GetSubscription($subscriptionid);
1804 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1806 # If the expiration date is set
1807 if ( $expirationdate != 0 ) {
1808 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1810 # Getting today's date
1811 my ( $nowyear, $nowmonth, $nowday ) = Today();
1813 # if today's date > expiration date, then the subscription has stricly expired
1814 if ( Delta_Days( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1815 return 1;
1816 } else {
1817 return 0;
1819 } else {
1821 # There are some cases where the expiration date is not set
1822 # As we can't determine if the subscription has expired on a date-basis,
1823 # we return -1;
1824 return -1;
1828 =head2 HasSubscriptionExpired
1830 $has_expired = HasSubscriptionExpired($subscriptionid)
1832 the subscription has expired when the next issue to arrive is out of subscription limit.
1834 return :
1835 0 if the subscription has not expired
1836 1 if the subscription has expired
1837 2 if has subscription does not have a valid expiration date set
1839 =cut
1841 sub HasSubscriptionExpired {
1842 my ($subscriptionid) = @_;
1844 return unless ($subscriptionid);
1846 my $dbh = C4::Context->dbh;
1847 my $subscription = GetSubscription($subscriptionid);
1848 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
1849 if ( $frequency and $frequency->{unit} ) {
1850 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1851 if (!defined $expirationdate) {
1852 $expirationdate = q{};
1854 my $query = qq|
1855 SELECT max(planneddate)
1856 FROM serial
1857 WHERE subscriptionid=?
1859 my $sth = $dbh->prepare($query);
1860 $sth->execute($subscriptionid);
1861 my ($res) = $sth->fetchrow;
1862 if (!$res || $res=~m/^0000/) {
1863 return 0;
1865 my @res = split( /-/, $res );
1866 my @endofsubscriptiondate = split( /-/, $expirationdate );
1867 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date(@res) || not check_date(@endofsubscriptiondate) );
1868 return 1
1869 if ( ( @endofsubscriptiondate && Delta_Days( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1870 || ( !$res ) );
1871 return 0;
1872 } else {
1873 # Irregular
1874 if ( $subscription->{'numberlength'} ) {
1875 my $countreceived = countissuesfrom( $subscriptionid, $subscription->{'startdate'} );
1876 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1877 return 0;
1878 } else {
1879 return 0;
1882 return 0; # Notice that you'll never get here.
1885 =head2 SetDistributedto
1887 SetDistributedto($distributedto,$subscriptionid);
1888 This function update the value of distributedto for a subscription given on input arg.
1890 =cut
1892 sub SetDistributedto {
1893 my ( $distributedto, $subscriptionid ) = @_;
1894 my $dbh = C4::Context->dbh;
1895 my $query = qq|
1896 UPDATE subscription
1897 SET distributedto=?
1898 WHERE subscriptionid=?
1900 my $sth = $dbh->prepare($query);
1901 $sth->execute( $distributedto, $subscriptionid );
1902 return;
1905 =head2 DelSubscription
1907 DelSubscription($subscriptionid)
1908 this function deletes subscription which has $subscriptionid as id.
1910 =cut
1912 sub DelSubscription {
1913 my ($subscriptionid) = @_;
1914 my $dbh = C4::Context->dbh;
1915 $subscriptionid = $dbh->quote($subscriptionid);
1916 $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
1917 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
1918 $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
1920 logaction( "SERIAL", "DELETE", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1923 =head2 DelIssue
1925 DelIssue($serialseq,$subscriptionid)
1926 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1928 returns the number of rows affected
1930 =cut
1932 sub DelIssue {
1933 my ($dataissue) = @_;
1934 my $dbh = C4::Context->dbh;
1935 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1937 my $query = qq|
1938 DELETE FROM serial
1939 WHERE serialid= ?
1940 AND subscriptionid= ?
1942 my $mainsth = $dbh->prepare($query);
1943 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1945 #Delete element from subscription history
1946 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1947 my $sth = $dbh->prepare($query);
1948 $sth->execute( $dataissue->{'subscriptionid'} );
1949 my $val = $sth->fetchrow_hashref;
1950 unless ( $val->{manualhistory} ) {
1951 my $query = qq|
1952 SELECT * FROM subscriptionhistory
1953 WHERE subscriptionid= ?
1955 my $sth = $dbh->prepare($query);
1956 $sth->execute( $dataissue->{'subscriptionid'} );
1957 my $data = $sth->fetchrow_hashref;
1958 my $serialseq = $dataissue->{'serialseq'};
1959 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1960 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1961 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1962 $sth = $dbh->prepare($strsth);
1963 $sth->execute( $dataissue->{'subscriptionid'} );
1966 return $mainsth->rows;
1969 =head2 GetLateOrMissingIssues
1971 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1973 this function selects missing issues on database - where serial.status = 4 or serial.status=3 or planneddate<now
1975 return :
1976 the issuelist as an array of hash refs. Each element of this array contains
1977 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1979 =cut
1981 sub GetLateOrMissingIssues {
1982 my ( $supplierid, $serialid, $order ) = @_;
1984 return unless ( $supplierid or $serialid );
1986 my $dbh = C4::Context->dbh;
1987 my $sth;
1988 my $byserial = '';
1989 if ($serialid) {
1990 $byserial = "and serialid = " . $serialid;
1992 if ($order) {
1993 $order .= ", title";
1994 } else {
1995 $order = "title";
1997 if ($supplierid) {
1998 $sth = $dbh->prepare(
1999 "SELECT
2000 serialid, aqbooksellerid, name,
2001 biblio.title, biblioitems.issn, planneddate, serialseq,
2002 serial.status, serial.subscriptionid, claimdate, claims_count,
2003 subscription.branchcode
2004 FROM serial
2005 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
2006 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
2007 LEFT JOIN biblioitems ON subscription.biblionumber=biblioitems.biblionumber
2008 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
2009 WHERE subscription.subscriptionid = serial.subscriptionid
2010 AND (serial.STATUS IN (4, 41, 42, 43, 44) OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
2011 AND subscription.aqbooksellerid=$supplierid
2012 $byserial
2013 ORDER BY $order"
2015 } else {
2016 $sth = $dbh->prepare(
2017 "SELECT
2018 serialid, aqbooksellerid, name,
2019 biblio.title, planneddate, serialseq,
2020 serial.status, serial.subscriptionid, claimdate, claims_count,
2021 subscription.branchcode
2022 FROM serial
2023 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
2024 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
2025 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
2026 WHERE subscription.subscriptionid = serial.subscriptionid
2027 AND (serial.STATUS IN (4, 41, 42, 43, 44) OR ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3 OR serial.STATUS = 7))
2028 $byserial
2029 ORDER BY $order"
2032 $sth->execute;
2033 my @issuelist;
2034 while ( my $line = $sth->fetchrow_hashref ) {
2036 if ($line->{planneddate} && $line->{planneddate} !~/^0+\-/) {
2037 $line->{planneddateISO} = $line->{planneddate};
2038 $line->{planneddate} = format_date( $line->{planneddate} );
2040 if ($line->{claimdate} && $line->{claimdate} !~/^0+\-/) {
2041 $line->{claimdateISO} = $line->{claimdate};
2042 $line->{claimdate} = format_date( $line->{claimdate} );
2044 $line->{"status".$line->{status}} = 1;
2045 push @issuelist, $line;
2047 return @issuelist;
2050 =head2 updateClaim
2052 &updateClaim($serialid)
2054 this function updates the time when a claim is issued for late/missing items
2056 called from claims.pl file
2058 =cut
2060 sub updateClaim {
2061 my ($serialid) = @_;
2062 my $dbh = C4::Context->dbh;
2063 $dbh->do(q|
2064 UPDATE serial
2065 SET claimdate = NOW(),
2066 claims_count = claims_count + 1
2067 WHERE serialid = ?
2068 |, {}, $serialid );
2069 return;
2072 =head2 getsupplierbyserialid
2074 $result = getsupplierbyserialid($serialid)
2076 this function is used to find the supplier id given a serial id
2078 return :
2079 hashref containing serialid, subscriptionid, and aqbooksellerid
2081 =cut
2083 sub getsupplierbyserialid {
2084 my ($serialid) = @_;
2085 my $dbh = C4::Context->dbh;
2086 my $sth = $dbh->prepare(
2087 "SELECT serialid, serial.subscriptionid, aqbooksellerid
2088 FROM serial
2089 LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
2090 WHERE serialid = ?
2093 $sth->execute($serialid);
2094 my $line = $sth->fetchrow_hashref;
2095 my $result = $line->{'aqbooksellerid'};
2096 return $result;
2099 =head2 check_routing
2101 $result = &check_routing($subscriptionid)
2103 this function checks to see if a serial has a routing list and returns the count of routingid
2104 used to show either an 'add' or 'edit' link
2106 =cut
2108 sub check_routing {
2109 my ($subscriptionid) = @_;
2111 return unless ($subscriptionid);
2113 my $dbh = C4::Context->dbh;
2114 my $sth = $dbh->prepare(
2115 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
2116 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2117 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
2120 $sth->execute($subscriptionid);
2121 my $line = $sth->fetchrow_hashref;
2122 my $result = $line->{'routingids'};
2123 return $result;
2126 =head2 addroutingmember
2128 addroutingmember($borrowernumber,$subscriptionid)
2130 this function takes a borrowernumber and subscriptionid and adds the member to the
2131 routing list for that serial subscription and gives them a rank on the list
2132 of either 1 or highest current rank + 1
2134 =cut
2136 sub addroutingmember {
2137 my ( $borrowernumber, $subscriptionid ) = @_;
2139 return unless ($borrowernumber and $subscriptionid);
2141 my $rank;
2142 my $dbh = C4::Context->dbh;
2143 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
2144 $sth->execute($subscriptionid);
2145 while ( my $line = $sth->fetchrow_hashref ) {
2146 if ( $line->{'rank'} > 0 ) {
2147 $rank = $line->{'rank'} + 1;
2148 } else {
2149 $rank = 1;
2152 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
2153 $sth->execute( $subscriptionid, $borrowernumber, $rank );
2156 =head2 reorder_members
2158 reorder_members($subscriptionid,$routingid,$rank)
2160 this function is used to reorder the routing list
2162 it takes the routingid of the member one wants to re-rank and the rank it is to move to
2163 - it gets all members on list puts their routingid's into an array
2164 - removes the one in the array that is $routingid
2165 - then reinjects $routingid at point indicated by $rank
2166 - then update the database with the routingids in the new order
2168 =cut
2170 sub reorder_members {
2171 my ( $subscriptionid, $routingid, $rank ) = @_;
2172 my $dbh = C4::Context->dbh;
2173 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
2174 $sth->execute($subscriptionid);
2175 my @result;
2176 while ( my $line = $sth->fetchrow_hashref ) {
2177 push( @result, $line->{'routingid'} );
2180 # To find the matching index
2181 my $i;
2182 my $key = -1; # to allow for 0 being a valid response
2183 for ( $i = 0 ; $i < @result ; $i++ ) {
2184 if ( $routingid == $result[$i] ) {
2185 $key = $i; # save the index
2186 last;
2190 # if index exists in array then move it to new position
2191 if ( $key > -1 && $rank > 0 ) {
2192 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
2193 my $moving_item = splice( @result, $key, 1 );
2194 splice( @result, $new_rank, 0, $moving_item );
2196 for ( my $j = 0 ; $j < @result ; $j++ ) {
2197 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
2198 $sth->execute;
2200 return;
2203 =head2 delroutingmember
2205 delroutingmember($routingid,$subscriptionid)
2207 this function either deletes one member from routing list if $routingid exists otherwise
2208 deletes all members from the routing list
2210 =cut
2212 sub delroutingmember {
2214 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2215 my ( $routingid, $subscriptionid ) = @_;
2216 my $dbh = C4::Context->dbh;
2217 if ($routingid) {
2218 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2219 $sth->execute($routingid);
2220 reorder_members( $subscriptionid, $routingid );
2221 } else {
2222 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2223 $sth->execute($subscriptionid);
2225 return;
2228 =head2 getroutinglist
2230 @routinglist = getroutinglist($subscriptionid)
2232 this gets the info from the subscriptionroutinglist for $subscriptionid
2234 return :
2235 the routinglist as an array. Each element of the array contains a hash_ref containing
2236 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2238 =cut
2240 sub getroutinglist {
2241 my ($subscriptionid) = @_;
2242 my $dbh = C4::Context->dbh;
2243 my $sth = $dbh->prepare(
2244 'SELECT routingid, borrowernumber, ranking, biblionumber
2245 FROM subscription
2246 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2247 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2249 $sth->execute($subscriptionid);
2250 my $routinglist = $sth->fetchall_arrayref({});
2251 return @{$routinglist};
2254 =head2 countissuesfrom
2256 $result = countissuesfrom($subscriptionid,$startdate)
2258 Returns a count of serial rows matching the given subsctiptionid
2259 with published date greater than startdate
2261 =cut
2263 sub countissuesfrom {
2264 my ( $subscriptionid, $startdate ) = @_;
2265 my $dbh = C4::Context->dbh;
2266 my $query = qq|
2267 SELECT count(*)
2268 FROM serial
2269 WHERE subscriptionid=?
2270 AND serial.publisheddate>?
2272 my $sth = $dbh->prepare($query);
2273 $sth->execute( $subscriptionid, $startdate );
2274 my ($countreceived) = $sth->fetchrow;
2275 return $countreceived;
2278 =head2 CountIssues
2280 $result = CountIssues($subscriptionid)
2282 Returns a count of serial rows matching the given subsctiptionid
2284 =cut
2286 sub CountIssues {
2287 my ($subscriptionid) = @_;
2288 my $dbh = C4::Context->dbh;
2289 my $query = qq|
2290 SELECT count(*)
2291 FROM serial
2292 WHERE subscriptionid=?
2294 my $sth = $dbh->prepare($query);
2295 $sth->execute($subscriptionid);
2296 my ($countreceived) = $sth->fetchrow;
2297 return $countreceived;
2300 =head2 HasItems
2302 $result = HasItems($subscriptionid)
2304 returns a count of items from serial matching the subscriptionid
2306 =cut
2308 sub HasItems {
2309 my ($subscriptionid) = @_;
2310 my $dbh = C4::Context->dbh;
2311 my $query = q|
2312 SELECT COUNT(serialitems.itemnumber)
2313 FROM serial
2314 LEFT JOIN serialitems USING(serialid)
2315 WHERE subscriptionid=? AND serialitems.serialid IS NOT NULL
2317 my $sth=$dbh->prepare($query);
2318 $sth->execute($subscriptionid);
2319 my ($countitems)=$sth->fetchrow_array();
2320 return $countitems;
2323 =head2 abouttoexpire
2325 $result = abouttoexpire($subscriptionid)
2327 this function alerts you to the penultimate issue for a serial subscription
2329 returns 1 - if this is the penultimate issue
2330 returns 0 - if not
2332 =cut
2334 sub abouttoexpire {
2335 my ($subscriptionid) = @_;
2336 my $dbh = C4::Context->dbh;
2337 my $subscription = GetSubscription($subscriptionid);
2338 my $per = $subscription->{'periodicity'};
2339 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($per);
2340 if ($frequency and $frequency->{unit}){
2342 my $expirationdate = GetExpirationDate($subscriptionid);
2344 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2345 my $nextdate = GetNextDate($subscription, $res);
2347 # only compare dates if both dates exist.
2348 if ($nextdate and $expirationdate) {
2349 if(Date::Calc::Delta_Days(
2350 split( /-/, $nextdate ),
2351 split( /-/, $expirationdate )
2352 ) <= 0) {
2353 return 1;
2357 } elsif ($subscription->{numberlength}>0) {
2358 return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
2361 return 0;
2364 sub in_array { # used in next sub down
2365 my ( $val, @elements ) = @_;
2366 foreach my $elem (@elements) {
2367 if ( $val == $elem ) {
2368 return 1;
2371 return 0;
2374 =head2 GetSubscriptionsFromBorrower
2376 ($count,@routinglist) = GetSubscriptionsFromBorrower($borrowernumber)
2378 this gets the info from subscriptionroutinglist for each $subscriptionid
2380 return :
2381 a count of the serial subscription routing lists to which a patron belongs,
2382 with the titles of those serial subscriptions as an array. Each element of the array
2383 contains a hash_ref with subscriptionID and title of subscription.
2385 =cut
2387 sub GetSubscriptionsFromBorrower {
2388 my ($borrowernumber) = @_;
2389 my $dbh = C4::Context->dbh;
2390 my $sth = $dbh->prepare(
2391 "SELECT subscription.subscriptionid, biblio.title
2392 FROM subscription
2393 JOIN biblio ON biblio.biblionumber = subscription.biblionumber
2394 JOIN subscriptionroutinglist USING (subscriptionid)
2395 WHERE subscriptionroutinglist.borrowernumber = ? ORDER BY title ASC
2398 $sth->execute($borrowernumber);
2399 my @routinglist;
2400 my $count = 0;
2401 while ( my $line = $sth->fetchrow_hashref ) {
2402 $count++;
2403 push( @routinglist, $line );
2405 return ( $count, @routinglist );
2409 =head2 GetFictiveIssueNumber
2411 $issueno = GetFictiveIssueNumber($subscription, $publishedate);
2413 Get the position of the issue published at $publisheddate, considering the
2414 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2415 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2416 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2417 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2418 depending on how many rows are in serial table.
2419 The issue number calculation is based on subscription frequency, first acquisition
2420 date, and $publisheddate.
2422 =cut
2424 sub GetFictiveIssueNumber {
2425 my ($subscription, $publisheddate) = @_;
2427 my $frequency = GetSubscriptionFrequency($subscription->{'periodicity'});
2428 my $unit = $frequency->{unit} ? lc $frequency->{'unit'} : undef;
2429 my $issueno = 0;
2431 if($unit) {
2432 my ($year, $month, $day) = split /-/, $publisheddate;
2433 my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{'firstacquidate'};
2434 my $wkno;
2435 my $delta;
2437 if($unit eq 'day') {
2438 $delta = Delta_Days($fa_year, $fa_month, $fa_day, $year, $month, $day);
2439 } elsif($unit eq 'week') {
2440 ($wkno, $year) = Week_of_Year($year, $month, $day);
2441 my ($fa_wkno, $fa_yr) = Week_of_Year($fa_year, $fa_month, $fa_day);
2442 $delta = ($fa_yr == $year) ? ($wkno - $fa_wkno) : ( ($year-$fa_yr-1)*52 + (52-$fa_wkno+$wkno) );
2443 } elsif($unit eq 'month') {
2444 $delta = ($fa_year == $year)
2445 ? ($month - $fa_month)
2446 : ( ($year-$fa_year-1)*12 + (12-$fa_month+$month) );
2447 } elsif($unit eq 'year') {
2448 $delta = $year - $fa_year;
2450 if($frequency->{'unitsperissue'} == 1) {
2451 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2452 } else {
2453 # Assuming issuesperunit == 1
2454 $issueno = int( ($delta + $frequency->{'unitsperissue'}) / $frequency->{'unitsperissue'} );
2457 return $issueno;
2460 =head2 GetNextDate
2462 $resultdate = GetNextDate($publisheddate,$subscription)
2464 this function it takes the publisheddate and will return the next issue's date
2465 and will skip dates if there exists an irregularity.
2466 $publisheddate has to be an ISO date
2467 $subscription is a hashref containing at least 'periodicity', 'firstacquidate', 'irregularity', and 'countissuesperunit'
2468 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2469 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2470 skipped then the returned date will be 2007-05-10
2472 return :
2473 $resultdate - then next date in the sequence (ISO date)
2475 Return undef if subscription is irregular
2477 =cut
2479 sub GetNextDate {
2480 my ( $subscription, $publisheddate, $updatecount ) = @_;
2482 return unless $subscription and $publisheddate;
2484 my $freqdata = GetSubscriptionFrequency($subscription->{'periodicity'});
2486 if ($freqdata->{'unit'}) {
2487 my ( $year, $month, $day ) = split /-/, $publisheddate;
2489 # Process an irregularity Hash
2490 # Suppose that irregularities are stored in a string with this structure
2491 # irreg1;irreg2;irreg3
2492 # where irregX is the number of issue which will not be received
2493 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2494 my %irregularities;
2495 if ( $subscription->{irregularity} ) {
2496 my @irreg = split /;/, $subscription->{'irregularity'} ;
2497 foreach my $irregularity (@irreg) {
2498 $irregularities{$irregularity} = 1;
2502 # Get the 'fictive' next issue number
2503 # It is used to check if next issue is an irregular issue.
2504 my $issueno = GetFictiveIssueNumber($subscription, $publisheddate) + 1;
2506 # Then get the next date
2507 my $unit = lc $freqdata->{'unit'};
2508 if ($unit eq 'day') {
2509 while ($irregularities{$issueno}) {
2510 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2511 ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{'unitsperissue'} );
2512 $subscription->{'countissuesperunit'} = 1;
2513 } else {
2514 $subscription->{'countissuesperunit'}++;
2516 $issueno++;
2518 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2519 ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{"unitsperissue"} );
2520 $subscription->{'countissuesperunit'} = 1;
2521 } else {
2522 $subscription->{'countissuesperunit'}++;
2525 elsif ($unit eq 'week') {
2526 my ($wkno, $yr) = Week_of_Year($year, $month, $day);
2527 while ($irregularities{$issueno}) {
2528 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2529 $subscription->{'countissuesperunit'} = 1;
2530 $wkno += $freqdata->{"unitsperissue"};
2531 if($wkno > 52){
2532 $wkno = $wkno % 52;
2533 $yr++;
2535 my $dow = Day_of_Week($year, $month, $day);
2536 ($year,$month,$day) = Monday_of_Week($wkno, $yr);
2537 if($freqdata->{'issuesperunit'} == 1) {
2538 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $dow - 1);
2540 } else {
2541 $subscription->{'countissuesperunit'}++;
2543 $issueno++;
2545 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2546 $subscription->{'countissuesperunit'} = 1;
2547 $wkno += $freqdata->{"unitsperissue"};
2548 if($wkno > 52){
2549 $wkno = $wkno % 52 ;
2550 $yr++;
2552 my $dow = Day_of_Week($year, $month, $day);
2553 ($year,$month,$day) = Monday_of_Week($wkno, $yr);
2554 if($freqdata->{'issuesperunit'} == 1) {
2555 ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $dow - 1);
2557 } else {
2558 $subscription->{'countissuesperunit'}++;
2561 elsif ($unit eq 'month') {
2562 while ($irregularities{$issueno}) {
2563 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2564 $subscription->{'countissuesperunit'} = 1;
2565 ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,$freqdata->{"unitsperissue"});
2566 unless($freqdata->{'issuesperunit'} == 1) {
2567 $day = 1; # Jumping to the first day of month, because we don't know what day is expected
2569 } else {
2570 $subscription->{'countissuesperunit'}++;
2572 $issueno++;
2574 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2575 $subscription->{'countissuesperunit'} = 1;
2576 ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,$freqdata->{"unitsperissue"});
2577 unless($freqdata->{'issuesperunit'} == 1) {
2578 $day = 1; # Jumping to the first day of month, because we don't know what day is expected
2580 } else {
2581 $subscription->{'countissuesperunit'}++;
2584 elsif ($unit eq 'year') {
2585 while ($irregularities{$issueno}) {
2586 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2587 $subscription->{'countissuesperunit'} = 1;
2588 ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
2589 unless($freqdata->{'issuesperunit'} == 1) {
2590 # Jumping to the first day of year, because we don't know what day is expected
2591 $month = 1;
2592 $day = 1;
2594 } else {
2595 $subscription->{'countissuesperunit'}++;
2597 $issueno++;
2599 if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
2600 $subscription->{'countissuesperunit'} = 1;
2601 ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
2602 unless($freqdata->{'issuesperunit'} == 1) {
2603 # Jumping to the first day of year, because we don't know what day is expected
2604 $month = 1;
2605 $day = 1;
2607 } else {
2608 $subscription->{'countissuesperunit'}++;
2611 if ($updatecount){
2612 my $dbh = C4::Context->dbh;
2613 my $query = qq{
2614 UPDATE subscription
2615 SET countissuesperunit = ?
2616 WHERE subscriptionid = ?
2618 my $sth = $dbh->prepare($query);
2619 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2621 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2625 =head2 _numeration
2627 $string = &_numeration($value,$num_type,$locale);
2629 _numeration returns the string corresponding to $value in the num_type
2630 num_type can take :
2631 -dayname
2632 -monthname
2633 -season
2634 =cut
2638 sub _numeration {
2639 my ($value, $num_type, $locale) = @_;
2640 $value ||= 0;
2641 $num_type //= '';
2642 $locale ||= 'en';
2643 my $string;
2644 if ( $num_type =~ /^dayname$/ ) {
2645 # 1970-11-01 was a Sunday
2646 $value = $value % 7;
2647 my $dt = DateTime->new(
2648 year => 1970,
2649 month => 11,
2650 day => $value + 1,
2651 locale => $locale,
2653 $string = $dt->strftime("%A");
2654 } elsif ( $num_type =~ /^monthname$/ ) {
2655 $value = $value % 12;
2656 my $dt = DateTime->new(
2657 year => 1970,
2658 month => $value + 1,
2659 locale => $locale,
2661 $string = $dt->strftime("%B");
2662 } elsif ( $num_type =~ /^season$/ ) {
2663 my @seasons= qw( Spring Summer Fall Winter );
2664 $value = $value % 4;
2665 $string = $seasons[$value];
2666 } else {
2667 $string = $value;
2670 return $string;
2673 =head2 is_barcode_in_use
2675 Returns number of occurence of the barcode in the items table
2676 Can be used as a boolean test of whether the barcode has
2677 been deployed as yet
2679 =cut
2681 sub is_barcode_in_use {
2682 my $barcode = shift;
2683 my $dbh = C4::Context->dbh;
2684 my $occurences = $dbh->selectall_arrayref(
2685 'SELECT itemnumber from items where barcode = ?',
2686 {}, $barcode
2690 return @{$occurences};
2693 =head2 CloseSubscription
2694 Close a subscription given a subscriptionid
2695 =cut
2696 sub CloseSubscription {
2697 my ( $subscriptionid ) = @_;
2698 return unless $subscriptionid;
2699 my $dbh = C4::Context->dbh;
2700 my $sth = $dbh->prepare( qq{
2701 UPDATE subscription
2702 SET closed = 1
2703 WHERE subscriptionid = ?
2704 } );
2705 $sth->execute( $subscriptionid );
2707 # Set status = missing when status = stopped
2708 $sth = $dbh->prepare( qq{
2709 UPDATE serial
2710 SET status = 8
2711 WHERE subscriptionid = ?
2712 AND status = 1
2713 } );
2714 $sth->execute( $subscriptionid );
2717 =head2 ReopenSubscription
2718 Reopen a subscription given a subscriptionid
2719 =cut
2720 sub ReopenSubscription {
2721 my ( $subscriptionid ) = @_;
2722 return unless $subscriptionid;
2723 my $dbh = C4::Context->dbh;
2724 my $sth = $dbh->prepare( qq{
2725 UPDATE subscription
2726 SET closed = 0
2727 WHERE subscriptionid = ?
2728 } );
2729 $sth->execute( $subscriptionid );
2731 # Set status = expected when status = stopped
2732 $sth = $dbh->prepare( qq{
2733 UPDATE serial
2734 SET status = 1
2735 WHERE subscriptionid = ?
2736 AND status = 8
2737 } );
2738 $sth->execute( $subscriptionid );
2741 =head2 subscriptionCurrentlyOnOrder
2743 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2745 Return 1 if subscription is currently on order else 0.
2747 =cut
2749 sub subscriptionCurrentlyOnOrder {
2750 my ( $subscriptionid ) = @_;
2751 my $dbh = C4::Context->dbh;
2752 my $query = qq|
2753 SELECT COUNT(*) FROM aqorders
2754 WHERE subscriptionid = ?
2755 AND datereceived IS NULL
2756 AND datecancellationprinted IS NULL
2758 my $sth = $dbh->prepare( $query );
2759 $sth->execute($subscriptionid);
2760 return $sth->fetchrow_array;
2763 =head2 can_edit_subscription
2765 $can = can_edit_subscription( $subscriptionid[, $userid] );
2767 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2769 =cut
2771 sub can_edit_subscription {
2772 my ( $subscription, $userid ) = @_;
2773 return _can_do_on_subscription( $subscription, $userid, 'edit_subscription' );
2776 =head2 can_show_subscription
2778 $can = can_show_subscription( $subscriptionid[, $userid] );
2780 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2782 =cut
2784 sub can_show_subscription {
2785 my ( $subscription, $userid ) = @_;
2786 return _can_do_on_subscription( $subscription, $userid, '*' );
2789 sub _can_do_on_subscription {
2790 my ( $subscription, $userid, $permission ) = @_;
2791 return 0 unless C4::Context->userenv;
2792 my $flags = C4::Context->userenv->{flags};
2793 $userid ||= C4::Context->userenv->{'id'};
2795 if ( C4::Context->preference('IndependentBranches') ) {
2796 return 1
2797 if C4::Context->IsSuperLibrarian()
2799 C4::Auth::haspermission( $userid, { serials => 'superserials' } )
2800 or (
2801 C4::Auth::haspermission( $userid,
2802 { serials => $permission } )
2803 and ( not defined $subscription->{branchcode}
2804 or $subscription->{branchcode} eq ''
2805 or $subscription->{branchcode} eq
2806 C4::Context->userenv->{'branch'} )
2809 else {
2810 return 1
2811 if C4::Context->IsSuperLibrarian()
2813 C4::Auth::haspermission( $userid, { serials => 'superserials' } )
2814 or C4::Auth::haspermission(
2815 $userid, { serials => $permission }
2819 return 0;
2823 __END__
2825 =head1 AUTHOR
2827 Koha Development Team <http://koha-community.org/>
2829 =cut