Bug 10855: Search subscriptions by additional fields on the claim page
[koha.git] / C4 / Serials.pm
blob2216a4520695ee0c7f670b22749251b8a5aa6b87
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;
34 use Koha::AdditionalField;
36 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
38 # Define statuses
39 use constant {
40 EXPECTED => 1,
41 ARRIVED => 2,
42 LATE => 3,
43 MISSING => 4,
44 MISSING_NEVER_RECIEVED => 41,
45 MISSING_SOLD_OUT => 42,
46 MISSING_DAMAGED => 43,
47 MISSING_LOST => 44,
48 NOT_ISSUED => 5,
49 DELETED => 6,
50 CLAIMED => 7,
51 STOPPED => 8,
54 use constant MISSING_STATUSES => (
55 MISSING, MISSING_NEVER_RECIEVED,
56 MISSING_SOLD_OUT, MISSING_DAMAGED,
57 MISSING_LOST
60 BEGIN {
61 $VERSION = 3.07.00.049; # set version for version checking
62 require Exporter;
63 @ISA = qw(Exporter);
64 @EXPORT = qw(
65 &NewSubscription &ModSubscription &DelSubscription
66 &GetSubscription &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
67 &SearchSubscriptions
68 &GetFullSubscriptionsFromBiblionumber &GetFullSubscription &ModSubscriptionHistory
69 &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
70 &GetSubscriptionHistoryFromSubscriptionId
72 &GetNextSeq &GetSeq &NewIssue &ItemizeSerials &GetSerials
73 &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2
74 &ReNewSubscription &GetLateOrMissingIssues
75 &GetSerialInformation &AddItem2Serial
76 &PrepareSerialsData &GetNextExpected &ModNextExpected
78 &UpdateClaimdateIssues
79 &GetSuppliersWithLateIssues &getsupplierbyserialid
80 &GetDistributedTo &SetDistributedTo
81 &getroutinglist &delroutingmember &addroutingmember
82 &reorder_members
83 &check_routing &updateClaim
84 &CountIssues
85 HasItems
86 &GetSubscriptionsFromBorrower
87 &subscriptionCurrentlyOnOrder
92 =head1 NAME
94 C4::Serials - Serials Module Functions
96 =head1 SYNOPSIS
98 use C4::Serials;
100 =head1 DESCRIPTION
102 Functions for handling subscriptions, claims routing etc.
105 =head1 SUBROUTINES
107 =head2 GetSuppliersWithLateIssues
109 $supplierlist = GetSuppliersWithLateIssues()
111 this function get all suppliers with late issues.
113 return :
114 an array_ref of suppliers each entry is a hash_ref containing id and name
115 the array is in name order
117 =cut
119 sub GetSuppliersWithLateIssues {
120 my $dbh = C4::Context->dbh;
121 my $statuses = join(',', ( LATE, MISSING_STATUSES, CLAIMED ) );
122 my $query = qq|
123 SELECT DISTINCT id, name
124 FROM subscription
125 LEFT JOIN serial ON serial.subscriptionid=subscription.subscriptionid
126 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
127 WHERE id > 0
128 AND (
129 (planneddate < now() AND serial.status=1)
130 OR serial.STATUS IN ( $statuses )
132 AND subscription.closed = 0
133 ORDER BY name|;
134 return $dbh->selectall_arrayref($query, { Slice => {} });
137 =head2 GetSubscriptionHistoryFromSubscriptionId
139 $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
141 This function returns the subscription history as a hashref
143 =cut
145 sub GetSubscriptionHistoryFromSubscriptionId {
146 my ($subscriptionid) = @_;
148 return unless $subscriptionid;
150 my $dbh = C4::Context->dbh;
151 my $query = qq|
152 SELECT *
153 FROM subscriptionhistory
154 WHERE subscriptionid = ?
156 my $sth = $dbh->prepare($query);
157 $sth->execute($subscriptionid);
158 my $results = $sth->fetchrow_hashref;
159 $sth->finish;
161 return $results;
164 =head2 GetSerialStatusFromSerialId
166 $sth = GetSerialStatusFromSerialId();
167 this function returns a statement handle
168 After this function, don't forget to execute it by using $sth->execute($serialid)
169 return :
170 $sth = $dbh->prepare($query).
172 =cut
174 sub GetSerialStatusFromSerialId {
175 my $dbh = C4::Context->dbh;
176 my $query = qq|
177 SELECT status
178 FROM serial
179 WHERE serialid = ?
181 return $dbh->prepare($query);
184 =head2 GetSerialInformation
187 $data = GetSerialInformation($serialid);
188 returns a hash_ref containing :
189 items : items marcrecord (can be an array)
190 serial table field
191 subscription table field
192 + information about subscription expiration
194 =cut
196 sub GetSerialInformation {
197 my ($serialid) = @_;
198 my $dbh = C4::Context->dbh;
199 my $query = qq|
200 SELECT serial.*, serial.notes as sernotes, serial.status as serstatus,subscription.*,subscription.subscriptionid as subsid
201 FROM serial LEFT JOIN subscription ON subscription.subscriptionid=serial.subscriptionid
202 WHERE serialid = ?
204 my $rq = $dbh->prepare($query);
205 $rq->execute($serialid);
206 my $data = $rq->fetchrow_hashref;
208 # create item information if we have serialsadditems for this subscription
209 if ( $data->{'serialsadditems'} ) {
210 my $queryitem = $dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
211 $queryitem->execute($serialid);
212 my $itemnumbers = $queryitem->fetchall_arrayref( [0] );
213 require C4::Items;
214 if ( scalar(@$itemnumbers) > 0 ) {
215 foreach my $itemnum (@$itemnumbers) {
217 #It is ASSUMED that GetMarcItem ALWAYS WORK...
218 #Maybe GetMarcItem should return values on failure
219 $debug and warn "itemnumber :$itemnum->[0], bibnum :" . $data->{'biblionumber'};
220 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, $itemnum->[0], $data );
221 $itemprocessed->{'itemnumber'} = $itemnum->[0];
222 $itemprocessed->{'itemid'} = $itemnum->[0];
223 $itemprocessed->{'serialid'} = $serialid;
224 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
225 push @{ $data->{'items'} }, $itemprocessed;
227 } else {
228 my $itemprocessed = C4::Items::PrepareItemrecordDisplay( $data->{'biblionumber'}, '', $data );
229 $itemprocessed->{'itemid'} = "N$serialid";
230 $itemprocessed->{'serialid'} = $serialid;
231 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
232 $itemprocessed->{'countitems'} = 0;
233 push @{ $data->{'items'} }, $itemprocessed;
236 $data->{ "status" . $data->{'serstatus'} } = 1;
237 $data->{'subscriptionexpired'} = HasSubscriptionExpired( $data->{'subscriptionid'} ) && $data->{'status'} == 1;
238 $data->{'abouttoexpire'} = abouttoexpire( $data->{'subscriptionid'} );
239 $data->{cannotedit} = not can_edit_subscription( $data );
240 return $data;
243 =head2 AddItem2Serial
245 $rows = AddItem2Serial($serialid,$itemnumber);
246 Adds an itemnumber to Serial record
247 returns the number of rows affected
249 =cut
251 sub AddItem2Serial {
252 my ( $serialid, $itemnumber ) = @_;
254 return unless ($serialid and $itemnumber);
256 my $dbh = C4::Context->dbh;
257 my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
258 $rq->execute( $serialid, $itemnumber );
259 return $rq->rows;
262 =head2 UpdateClaimdateIssues
264 UpdateClaimdateIssues($serialids,[$date]);
266 Update Claimdate for issues in @$serialids list with date $date
267 (Take Today if none)
269 =cut
271 sub UpdateClaimdateIssues {
272 my ( $serialids, $date ) = @_;
274 return unless ($serialids);
276 my $dbh = C4::Context->dbh;
277 $date = strftime( "%Y-%m-%d", localtime ) unless ($date);
278 my $query = "
279 UPDATE serial
280 SET claimdate = ?,
281 status = ?,
282 claims_count = claims_count + 1
283 WHERE serialid in (" . join( ",", map { '?' } @$serialids ) . ")
285 my $rq = $dbh->prepare($query);
286 $rq->execute($date, CLAIMED, @$serialids);
287 return $rq->rows;
290 =head2 GetSubscription
292 $subs = GetSubscription($subscriptionid)
293 this function returns the subscription which has $subscriptionid as id.
294 return :
295 a hashref. This hash containts
296 subscription, subscriptionhistory, aqbooksellers.name, biblio.title
298 =cut
300 sub GetSubscription {
301 my ($subscriptionid) = @_;
302 my $dbh = C4::Context->dbh;
303 my $query = qq(
304 SELECT subscription.*,
305 subscriptionhistory.*,
306 aqbooksellers.name AS aqbooksellername,
307 biblio.title AS bibliotitle,
308 subscription.biblionumber as bibnum
309 FROM subscription
310 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
311 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
312 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
313 WHERE subscription.subscriptionid = ?
316 $debug and warn "query : $query\nsubsid :$subscriptionid";
317 my $sth = $dbh->prepare($query);
318 $sth->execute($subscriptionid);
319 my $subscription = $sth->fetchrow_hashref;
321 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
323 # Add additional fields to the subscription into a new key "additional_fields"
324 my $additional_field_values = Koha::AdditionalField->fetch_all_values({
325 tablename => 'subscription',
326 record_id => $subscriptionid,
328 $subscription->{additional_fields} = $additional_field_values->{$subscriptionid};
330 return $subscription;
333 =head2 GetFullSubscription
335 $array_ref = GetFullSubscription($subscriptionid)
336 this function reads the serial table.
338 =cut
340 sub GetFullSubscription {
341 my ($subscriptionid) = @_;
343 return unless ($subscriptionid);
345 my $dbh = C4::Context->dbh;
346 my $query = qq|
347 SELECT serial.serialid,
348 serial.serialseq,
349 serial.planneddate,
350 serial.publisheddate,
351 serial.status,
352 serial.notes as notes,
353 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
354 aqbooksellers.name as aqbooksellername,
355 biblio.title as bibliotitle,
356 subscription.branchcode AS branchcode,
357 subscription.subscriptionid AS subscriptionid
358 FROM serial
359 LEFT JOIN subscription ON
360 (serial.subscriptionid=subscription.subscriptionid )
361 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
362 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
363 WHERE serial.subscriptionid = ?
364 ORDER BY year DESC,
365 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
366 serial.subscriptionid
368 $debug and warn "GetFullSubscription query: $query";
369 my $sth = $dbh->prepare($query);
370 $sth->execute($subscriptionid);
371 my $subscriptions = $sth->fetchall_arrayref( {} );
372 for my $subscription ( @$subscriptions ) {
373 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
375 return $subscriptions;
378 =head2 PrepareSerialsData
380 $array_ref = PrepareSerialsData($serialinfomation)
381 where serialinformation is a hashref array
383 =cut
385 sub PrepareSerialsData {
386 my ($lines) = @_;
388 return unless ($lines);
390 my %tmpresults;
391 my $year;
392 my @res;
393 my $startdate;
394 my $aqbooksellername;
395 my $bibliotitle;
396 my @loopissues;
397 my $first;
398 my $previousnote = "";
400 foreach my $subs (@{$lines}) {
401 for my $datefield ( qw(publisheddate planneddate) ) {
402 # handle 0000-00-00 dates
403 if (defined $subs->{$datefield} and $subs->{$datefield} =~ m/^00/) {
404 $subs->{$datefield} = undef;
407 $subs->{ "status" . $subs->{'status'} } = 1;
408 if ( grep { $_ == $subs->{status} } ( EXPECTED, LATE, MISSING_STATUSES, CLAIMED ) ) {
409 $subs->{"checked"} = 1;
412 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
413 $year = $subs->{'year'};
414 } else {
415 $year = "manage";
417 if ( $tmpresults{$year} ) {
418 push @{ $tmpresults{$year}->{'serials'} }, $subs;
419 } else {
420 $tmpresults{$year} = {
421 'year' => $year,
422 'aqbooksellername' => $subs->{'aqbooksellername'},
423 'bibliotitle' => $subs->{'bibliotitle'},
424 'serials' => [$subs],
425 'first' => $first,
429 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
430 push @res, $tmpresults{$key};
432 return \@res;
435 =head2 GetSubscriptionsFromBiblionumber
437 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
438 this function get the subscription list. it reads the subscription table.
439 return :
440 reference to an array of subscriptions which have the biblionumber given on input arg.
441 each element of this array is a hashref containing
442 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
444 =cut
446 sub GetSubscriptionsFromBiblionumber {
447 my ($biblionumber) = @_;
449 return unless ($biblionumber);
451 my $dbh = C4::Context->dbh;
452 my $query = qq(
453 SELECT subscription.*,
454 branches.branchname,
455 subscriptionhistory.*,
456 aqbooksellers.name AS aqbooksellername,
457 biblio.title AS bibliotitle
458 FROM subscription
459 LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
460 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
461 LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
462 LEFT JOIN branches ON branches.branchcode=subscription.branchcode
463 WHERE subscription.biblionumber = ?
465 my $sth = $dbh->prepare($query);
466 $sth->execute($biblionumber);
467 my @res;
468 while ( my $subs = $sth->fetchrow_hashref ) {
469 $subs->{startdate} = format_date( $subs->{startdate} );
470 $subs->{histstartdate} = format_date( $subs->{histstartdate} );
471 $subs->{histenddate} = format_date( $subs->{histenddate} );
472 $subs->{opacnote} =~ s/\n/\<br\/\>/g;
473 $subs->{missinglist} =~ s/\n/\<br\/\>/g;
474 $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
475 $subs->{ "periodicity" . $subs->{periodicity} } = 1;
476 $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
477 $subs->{ "status" . $subs->{'status'} } = 1;
479 if ( $subs->{enddate} eq '0000-00-00' ) {
480 $subs->{enddate} = '';
481 } else {
482 $subs->{enddate} = format_date( $subs->{enddate} );
484 $subs->{'abouttoexpire'} = abouttoexpire( $subs->{'subscriptionid'} );
485 $subs->{'subscriptionexpired'} = HasSubscriptionExpired( $subs->{'subscriptionid'} );
486 $subs->{cannotedit} = not can_edit_subscription( $subs );
487 push @res, $subs;
489 return \@res;
492 =head2 GetFullSubscriptionsFromBiblionumber
494 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
495 this function reads the serial table.
497 =cut
499 sub GetFullSubscriptionsFromBiblionumber {
500 my ($biblionumber) = @_;
501 my $dbh = C4::Context->dbh;
502 my $query = qq|
503 SELECT serial.serialid,
504 serial.serialseq,
505 serial.planneddate,
506 serial.publisheddate,
507 serial.status,
508 serial.notes as notes,
509 year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year,
510 biblio.title as bibliotitle,
511 subscription.branchcode AS branchcode,
512 subscription.subscriptionid AS subscriptionid
513 FROM serial
514 LEFT JOIN subscription ON
515 (serial.subscriptionid=subscription.subscriptionid)
516 LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
517 LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
518 WHERE subscription.biblionumber = ?
519 ORDER BY year DESC,
520 IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate) DESC,
521 serial.subscriptionid
523 my $sth = $dbh->prepare($query);
524 $sth->execute($biblionumber);
525 my $subscriptions = $sth->fetchall_arrayref( {} );
526 for my $subscription ( @$subscriptions ) {
527 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
529 return $subscriptions;
532 =head2 SearchSubscriptions
534 @results = SearchSubscriptions($args);
536 This function returns a list of hashrefs, one for each subscription
537 that meets the conditions specified by the $args hashref.
539 The valid search fields are:
541 biblionumber
542 title
543 issn
545 callnumber
546 location
547 publisher
548 bookseller
549 branch
550 expiration_date
551 closed
553 The expiration_date search field is special; it specifies the maximum
554 subscription expiration date.
556 =cut
558 sub SearchSubscriptions {
559 my ( $args ) = @_;
561 my $additional_fields = $args->{additional_fields} // [];
562 my $matching_record_ids_for_additional_fields = [];
563 if ( @$additional_fields ) {
564 $matching_record_ids_for_additional_fields = Koha::AdditionalField->get_matching_record_ids({
565 fields => $args->{additional_fields},
566 tablename => 'subscription',
568 return () unless @$matching_record_ids_for_additional_fields;
571 my $query = q|
572 SELECT
573 subscription.notes AS publicnotes,
574 subscriptionhistory.*,
575 subscription.*,
576 biblio.notes AS biblionotes,
577 biblio.title,
578 biblio.author,
579 biblio.biblionumber,
580 biblioitems.issn
581 FROM subscription
582 LEFT JOIN subscriptionhistory USING(subscriptionid)
583 LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
584 LEFT JOIN biblioitems ON biblioitems.biblionumber = subscription.biblionumber
585 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
587 $query .= q| WHERE 1|;
588 my @where_strs;
589 my @where_args;
590 if( $args->{biblionumber} ) {
591 push @where_strs, "biblio.biblionumber = ?";
592 push @where_args, $args->{biblionumber};
595 if( $args->{title} ){
596 my @words = split / /, $args->{title};
597 my (@strs, @args);
598 foreach my $word (@words) {
599 push @strs, "biblio.title LIKE ?";
600 push @args, "%$word%";
602 if (@strs) {
603 push @where_strs, '(' . join (' AND ', @strs) . ')';
604 push @where_args, @args;
607 if( $args->{issn} ){
608 push @where_strs, "biblioitems.issn LIKE ?";
609 push @where_args, "%$args->{issn}%";
611 if( $args->{ean} ){
612 push @where_strs, "biblioitems.ean LIKE ?";
613 push @where_args, "%$args->{ean}%";
615 if ( $args->{callnumber} ) {
616 push @where_strs, "subscription.callnumber LIKE ?";
617 push @where_args, "%$args->{callnumber}%";
619 if( $args->{publisher} ){
620 push @where_strs, "biblioitems.publishercode LIKE ?";
621 push @where_args, "%$args->{publisher}%";
623 if( $args->{bookseller} ){
624 push @where_strs, "aqbooksellers.name LIKE ?";
625 push @where_args, "%$args->{bookseller}%";
627 if( $args->{branch} ){
628 push @where_strs, "subscription.branchcode = ?";
629 push @where_args, "$args->{branch}";
631 if ( $args->{location} ) {
632 push @where_strs, "subscription.location = ?";
633 push @where_args, "$args->{location}";
635 if ( $args->{expiration_date} ) {
636 push @where_strs, "subscription.enddate <= ?";
637 push @where_args, "$args->{expiration_date}";
639 if( defined $args->{closed} ){
640 push @where_strs, "subscription.closed = ?";
641 push @where_args, "$args->{closed}";
644 if(@where_strs){
645 $query .= ' AND ' . join(' AND ', @where_strs);
647 if ( @$additional_fields ) {
648 $query .= ' AND subscriptionid IN ('
649 . join( ', ', @$matching_record_ids_for_additional_fields )
650 . ')';
653 $query .= " ORDER BY " . $args->{orderby} if $args->{orderby};
655 my $dbh = C4::Context->dbh;
656 my $sth = $dbh->prepare($query);
657 $sth->execute(@where_args);
658 my $results = $sth->fetchall_arrayref( {} );
660 for my $subscription ( @$results ) {
661 $subscription->{cannotedit} = not can_edit_subscription( $subscription );
662 $subscription->{cannotdisplay} = not can_show_subscription( $subscription );
664 my $additional_field_values = Koha::AdditionalField->fetch_all_values({
665 record_id => $subscription->{subscriptionid},
666 tablename => 'subscription'
668 $subscription->{addition_fields} = $additional_field_values->{$subscription->{subscriptionid}};
671 return @$results;
675 =head2 GetSerials
677 ($totalissues,@serials) = GetSerials($subscriptionid);
678 this function gets every serial not arrived for a given subscription
679 as well as the number of issues registered in the database (all types)
680 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
682 FIXME: We should return \@serials.
684 =cut
686 sub GetSerials {
687 my ( $subscriptionid, $count ) = @_;
689 return unless $subscriptionid;
691 my $dbh = C4::Context->dbh;
693 # status = 2 is "arrived"
694 my $counter = 0;
695 $count = 5 unless ($count);
696 my @serials;
697 my $statuses = join( ',', ( ARRIVED, MISSING_STATUSES, NOT_ISSUED ) );
698 my $query = "SELECT serialid,serialseq, status, publisheddate, planneddate,notes, routingnotes
699 FROM serial
700 WHERE subscriptionid = ? AND status NOT IN ( $statuses )
701 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
702 my $sth = $dbh->prepare($query);
703 $sth->execute($subscriptionid);
705 while ( my $line = $sth->fetchrow_hashref ) {
706 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
707 for my $datefield ( qw( planneddate publisheddate) ) {
708 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
709 $line->{$datefield} = format_date( $line->{$datefield});
710 } else {
711 $line->{$datefield} = q{};
714 push @serials, $line;
717 # OK, now add the last 5 issues arrives/missing
718 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
719 FROM serial
720 WHERE subscriptionid = ?
721 AND status IN ( $statuses )
722 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
724 $sth = $dbh->prepare($query);
725 $sth->execute($subscriptionid);
726 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
727 $counter++;
728 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
729 for my $datefield ( qw( planneddate publisheddate) ) {
730 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
731 $line->{$datefield} = format_date( $line->{$datefield});
732 } else {
733 $line->{$datefield} = q{};
737 push @serials, $line;
740 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
741 $sth = $dbh->prepare($query);
742 $sth->execute($subscriptionid);
743 my ($totalissues) = $sth->fetchrow;
744 return ( $totalissues, @serials );
747 =head2 GetSerials2
749 @serials = GetSerials2($subscriptionid,$statuses);
750 this function returns every serial waited for a given subscription
751 as well as the number of issues registered in the database (all types)
752 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
754 $statuses is an arrayref of statuses and is mandatory.
756 =cut
758 sub GetSerials2 {
759 my ( $subscription, $statuses ) = @_;
761 return unless ($subscription and @$statuses);
763 my $statuses_string = join ',', @$statuses;
765 my $dbh = C4::Context->dbh;
766 my $query = qq|
767 SELECT serialid,serialseq, status, planneddate, publisheddate,notes, routingnotes
768 FROM serial
769 WHERE subscriptionid=$subscription AND status IN ($statuses_string)
770 ORDER BY publisheddate,serialid DESC
772 $debug and warn "GetSerials2 query: $query";
773 my $sth = $dbh->prepare($query);
774 $sth->execute;
775 my @serials;
777 while ( my $line = $sth->fetchrow_hashref ) {
778 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
779 # Format dates for display
780 for my $datefield ( qw( planneddate publisheddate ) ) {
781 if (!defined($line->{$datefield}) || $line->{$datefield} =~m/^00/) {
782 $line->{$datefield} = q{};
784 else {
785 $line->{$datefield} = format_date( $line->{$datefield} );
788 push @serials, $line;
790 return @serials;
793 =head2 GetLatestSerials
795 \@serials = GetLatestSerials($subscriptionid,$limit)
796 get the $limit's latest serials arrived or missing for a given subscription
797 return :
798 a ref to an array which contains all of the latest serials stored into a hash.
800 =cut
802 sub GetLatestSerials {
803 my ( $subscriptionid, $limit ) = @_;
805 return unless ($subscriptionid and $limit);
807 my $dbh = C4::Context->dbh;
809 my $statuses = join( ',', ( ARRIVED, MISSING_STATUSES ) );
810 my $strsth = "SELECT serialid,serialseq, status, planneddate, publisheddate, notes
811 FROM serial
812 WHERE subscriptionid = ?
813 AND status IN ($statuses)
814 ORDER BY publisheddate DESC LIMIT 0,$limit
816 my $sth = $dbh->prepare($strsth);
817 $sth->execute($subscriptionid);
818 my @serials;
819 while ( my $line = $sth->fetchrow_hashref ) {
820 $line->{ "status" . $line->{status} } = 1; # fills a "statusX" value, used for template status select list
821 $line->{"planneddate"} = format_date( $line->{"planneddate"} );
822 $line->{"publisheddate"} = format_date( $line->{"publisheddate"} );
823 push @serials, $line;
826 return \@serials;
829 =head2 GetDistributedTo
831 $distributedto=GetDistributedTo($subscriptionid)
832 This function returns the field distributedto for the subscription matching subscriptionid
834 =cut
836 sub GetDistributedTo {
837 my $dbh = C4::Context->dbh;
838 my $distributedto;
839 my ($subscriptionid) = @_;
841 return unless ($subscriptionid);
843 my $query = "SELECT distributedto FROM subscription WHERE subscriptionid=?";
844 my $sth = $dbh->prepare($query);
845 $sth->execute($subscriptionid);
846 return ($distributedto) = $sth->fetchrow;
849 =head2 GetNextSeq
851 my (
852 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
853 $newinnerloop1, $newinnerloop2, $newinnerloop3
854 ) = GetNextSeq( $subscription, $pattern, $planneddate );
856 $subscription is a hashref containing all the attributes of the table
857 'subscription'.
858 $pattern is a hashref containing all the attributes of the table
859 'subscription_numberpatterns'.
860 $planneddate is a C4::Dates object.
861 This function get the next issue for the subscription given on input arg
863 =cut
865 sub GetNextSeq {
866 my ($subscription, $pattern, $planneddate) = @_;
868 return unless ($subscription and $pattern);
870 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
871 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
872 my $count = 1;
874 if ($subscription->{'skip_serialseq'}) {
875 my @irreg = split /;/, $subscription->{'irregularity'};
876 if(@irreg > 0) {
877 my $irregularities = {};
878 $irregularities->{$_} = 1 foreach(@irreg);
879 my $issueno = GetFictiveIssueNumber($subscription, $planneddate) + 1;
880 while($irregularities->{$issueno}) {
881 $count++;
882 $issueno++;
887 my $numberingmethod = $pattern->{numberingmethod};
888 my $calculated = "";
889 if ($numberingmethod) {
890 $calculated = $numberingmethod;
891 my $locale = $subscription->{locale};
892 $newlastvalue1 = $subscription->{lastvalue1} || 0;
893 $newlastvalue2 = $subscription->{lastvalue2} || 0;
894 $newlastvalue3 = $subscription->{lastvalue3} || 0;
895 $newinnerloop1 = $subscription->{innerloop1} || 0;
896 $newinnerloop2 = $subscription->{innerloop2} || 0;
897 $newinnerloop3 = $subscription->{innerloop3} || 0;
898 my %calc;
899 foreach(qw/X Y Z/) {
900 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
903 for(my $i = 0; $i < $count; $i++) {
904 if($calc{'X'}) {
905 # check if we have to increase the new value.
906 $newinnerloop1 += 1;
907 if ($newinnerloop1 >= $pattern->{every1}) {
908 $newinnerloop1 = 0;
909 $newlastvalue1 += $pattern->{add1};
911 # reset counter if needed.
912 $newlastvalue1 = $pattern->{setto1} if ($newlastvalue1 > $pattern->{whenmorethan1});
914 if($calc{'Y'}) {
915 # check if we have to increase the new value.
916 $newinnerloop2 += 1;
917 if ($newinnerloop2 >= $pattern->{every2}) {
918 $newinnerloop2 = 0;
919 $newlastvalue2 += $pattern->{add2};
921 # reset counter if needed.
922 $newlastvalue2 = $pattern->{setto2} if ($newlastvalue2 > $pattern->{whenmorethan2});
924 if($calc{'Z'}) {
925 # check if we have to increase the new value.
926 $newinnerloop3 += 1;
927 if ($newinnerloop3 >= $pattern->{every3}) {
928 $newinnerloop3 = 0;
929 $newlastvalue3 += $pattern->{add3};
931 # reset counter if needed.
932 $newlastvalue3 = $pattern->{setto3} if ($newlastvalue3 > $pattern->{whenmorethan3});
935 if($calc{'X'}) {
936 my $newlastvalue1string = _numeration( $newlastvalue1, $pattern->{numbering1}, $locale );
937 $calculated =~ s/\{X\}/$newlastvalue1string/g;
939 if($calc{'Y'}) {
940 my $newlastvalue2string = _numeration( $newlastvalue2, $pattern->{numbering2}, $locale );
941 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
943 if($calc{'Z'}) {
944 my $newlastvalue3string = _numeration( $newlastvalue3, $pattern->{numbering3}, $locale );
945 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
949 return ($calculated,
950 $newlastvalue1, $newlastvalue2, $newlastvalue3,
951 $newinnerloop1, $newinnerloop2, $newinnerloop3);
954 =head2 GetSeq
956 $calculated = GetSeq($subscription, $pattern)
957 $subscription is a hashref containing all the attributes of the table 'subscription'
958 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
959 this function transforms {X},{Y},{Z} to 150,0,0 for example.
960 return:
961 the sequence in string format
963 =cut
965 sub GetSeq {
966 my ($subscription, $pattern) = @_;
968 return unless ($subscription and $pattern);
970 my $locale = $subscription->{locale};
972 my $calculated = $pattern->{numberingmethod};
974 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
975 $newlastvalue1 = _numeration($newlastvalue1, $pattern->{numbering1}, $locale) if ($pattern->{numbering1}); # reset counter if needed.
976 $calculated =~ s/\{X\}/$newlastvalue1/g;
978 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
979 $newlastvalue2 = _numeration($newlastvalue2, $pattern->{numbering2}, $locale) if ($pattern->{numbering2}); # reset counter if needed.
980 $calculated =~ s/\{Y\}/$newlastvalue2/g;
982 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
983 $newlastvalue3 = _numeration($newlastvalue3, $pattern->{numbering3}, $locale) if ($pattern->{numbering3}); # reset counter if needed.
984 $calculated =~ s/\{Z\}/$newlastvalue3/g;
985 return $calculated;
988 =head2 GetExpirationDate
990 $enddate = GetExpirationDate($subscriptionid, [$startdate])
992 this function return the next expiration date for a subscription given on input args.
994 return
995 the enddate or undef
997 =cut
999 sub GetExpirationDate {
1000 my ( $subscriptionid, $startdate ) = @_;
1002 return unless ($subscriptionid);
1004 my $dbh = C4::Context->dbh;
1005 my $subscription = GetSubscription($subscriptionid);
1006 my $enddate;
1008 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
1009 $enddate = $startdate || $subscription->{startdate};
1010 my @date = split( /-/, $enddate );
1012 return if ( scalar(@date) != 3 || not check_date(@date) );
1014 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
1015 if ( $frequency and $frequency->{unit} ) {
1017 # If Not Irregular
1018 if ( my $length = $subscription->{numberlength} ) {
1020 #calculate the date of the last issue.
1021 for ( my $i = 1 ; $i <= $length ; $i++ ) {
1022 $enddate = GetNextDate( $subscription, $enddate );
1024 } elsif ( $subscription->{monthlength} ) {
1025 if ( $$subscription{startdate} ) {
1026 my @enddate = Add_Delta_YM( $date[0], $date[1], $date[2], 0, $subscription->{monthlength} );
1027 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1029 } elsif ( $subscription->{weeklength} ) {
1030 if ( $$subscription{startdate} ) {
1031 my @date = split( /-/, $subscription->{startdate} );
1032 my @enddate = Add_Delta_Days( $date[0], $date[1], $date[2], $subscription->{weeklength} * 7 );
1033 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1035 } else {
1036 $enddate = $subscription->{enddate};
1038 return $enddate;
1039 } else {
1040 return $subscription->{enddate};
1044 =head2 CountSubscriptionFromBiblionumber
1046 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1047 this returns a count of the subscriptions for a given biblionumber
1048 return :
1049 the number of subscriptions
1051 =cut
1053 sub CountSubscriptionFromBiblionumber {
1054 my ($biblionumber) = @_;
1056 return unless ($biblionumber);
1058 my $dbh = C4::Context->dbh;
1059 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1060 my $sth = $dbh->prepare($query);
1061 $sth->execute($biblionumber);
1062 my $subscriptionsnumber = $sth->fetchrow;
1063 return $subscriptionsnumber;
1066 =head2 ModSubscriptionHistory
1068 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1070 this function modifies the history of a subscription. Put your new values on input arg.
1071 returns the number of rows affected
1073 =cut
1075 sub ModSubscriptionHistory {
1076 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1078 return unless ($subscriptionid);
1080 my $dbh = C4::Context->dbh;
1081 my $query = "UPDATE subscriptionhistory
1082 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1083 WHERE subscriptionid=?
1085 my $sth = $dbh->prepare($query);
1086 $receivedlist =~ s/^; // if $receivedlist;
1087 $missinglist =~ s/^; // if $missinglist;
1088 $opacnote =~ s/^; // if $opacnote;
1089 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1090 return $sth->rows;
1093 =head2 ModSerialStatus
1095 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
1097 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1098 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1100 =cut
1102 sub ModSerialStatus {
1103 my ( $serialid, $serialseq, $planneddate, $publisheddate, $status, $notes ) = @_;
1105 return unless ($serialid);
1107 #It is a usual serial
1108 # 1st, get previous status :
1109 my $dbh = C4::Context->dbh;
1110 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
1111 FROM serial, subscription
1112 WHERE serial.subscriptionid=subscription.subscriptionid
1113 AND serialid=?";
1114 my $sth = $dbh->prepare($query);
1115 $sth->execute($serialid);
1116 my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
1117 my $frequency = GetSubscriptionFrequency($periodicity);
1119 # change status & update subscriptionhistory
1120 my $val;
1121 if ( $status == DELETED ) {
1122 DelIssue( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1123 } else {
1125 my $query = 'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE serialid = ?';
1126 $sth = $dbh->prepare($query);
1127 $sth->execute( $serialseq, $publisheddate, $planneddate, $status, $notes, $serialid );
1128 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1129 $sth = $dbh->prepare($query);
1130 $sth->execute($subscriptionid);
1131 my $val = $sth->fetchrow_hashref;
1132 unless ( $val->{manualhistory} ) {
1133 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1134 $sth = $dbh->prepare($query);
1135 $sth->execute($subscriptionid);
1136 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1138 if ( $status == ARRIVED || ($oldstatus == ARRIVED && $status != ARRIVED) ) {
1139 $recievedlist .= "; $serialseq"
1140 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1143 # in case serial has been previously marked as missing
1144 if (grep /$status/, (EXPECTED, ARRIVED, LATE, CLAIMED)) {
1145 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1148 $missinglist .= "; $serialseq"
1149 if ( ( grep { $_ == $status } ( MISSING_STATUSES ) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1150 $missinglist .= "; not issued $serialseq"
1151 if ( $status == NOT_ISSUED && $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1153 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1154 $sth = $dbh->prepare($query);
1155 $recievedlist =~ s/^; //;
1156 $missinglist =~ s/^; //;
1157 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1161 # create new waited entry if needed (ie : was a "waited" and has changed)
1162 if ( $oldstatus == EXPECTED && $status != EXPECTED ) {
1163 my $subscription = GetSubscription($subscriptionid);
1164 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
1166 # next issue number
1167 my (
1168 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1169 $newinnerloop1, $newinnerloop2, $newinnerloop3
1171 = GetNextSeq( $subscription, $pattern, $publisheddate );
1173 # next date (calculated from actual date & frequency parameters)
1174 my $nextpublisheddate = GetNextDate($subscription, $publisheddate, 1);
1175 my $nextpubdate = $nextpublisheddate;
1176 NewIssue( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
1177 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1178 WHERE subscriptionid = ?";
1179 $sth = $dbh->prepare($query);
1180 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1182 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1183 if ( $subscription->{letter} && $status == ARRIVED && $oldstatus != ARRIVED ) {
1184 require C4::Letters;
1185 C4::Letters::SendAlerts( 'issue', $serialid, $subscription->{letter} );
1189 return;
1192 =head2 GetNextExpected
1194 $nextexpected = GetNextExpected($subscriptionid)
1196 Get the planneddate for the current expected issue of the subscription.
1198 returns a hashref:
1200 $nextexepected = {
1201 serialid => int
1202 planneddate => ISO date
1205 =cut
1207 sub GetNextExpected {
1208 my ($subscriptionid) = @_;
1210 my $dbh = C4::Context->dbh;
1211 my $query = qq{
1212 SELECT *
1213 FROM serial
1214 WHERE subscriptionid = ?
1215 AND status = ?
1216 LIMIT 1
1218 my $sth = $dbh->prepare($query);
1220 # Each subscription has only one 'expected' issue.
1221 $sth->execute( $subscriptionid, EXPECTED );
1222 my $nextissue = $sth->fetchrow_hashref;
1223 if ( !$nextissue ) {
1224 $query = qq{
1225 SELECT *
1226 FROM serial
1227 WHERE subscriptionid = ?
1228 ORDER BY publisheddate DESC
1229 LIMIT 1
1231 $sth = $dbh->prepare($query);
1232 $sth->execute($subscriptionid);
1233 $nextissue = $sth->fetchrow_hashref;
1235 foreach(qw/planneddate publisheddate/) {
1236 if ( !defined $nextissue->{$_} ) {
1237 # or should this default to 1st Jan ???
1238 $nextissue->{$_} = strftime( '%Y-%m-%d', localtime );
1240 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1241 ? $nextissue->{$_}
1242 : undef;
1245 return $nextissue;
1248 =head2 ModNextExpected
1250 ModNextExpected($subscriptionid,$date)
1252 Update the planneddate for the current expected issue of the subscription.
1253 This will modify all future prediction results.
1255 C<$date> is an ISO date.
1257 returns 0
1259 =cut
1261 sub ModNextExpected {
1262 my ( $subscriptionid, $date ) = @_;
1263 my $dbh = C4::Context->dbh;
1265 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1266 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1268 # Each subscription has only one 'expected' issue.
1269 $sth->execute( $date, $date, $subscriptionid, EXPECTED );
1270 return 0;
1274 =head2 GetSubscriptionIrregularities
1276 =over 4
1278 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1279 get the list of irregularities for a subscription
1281 =back
1283 =cut
1285 sub GetSubscriptionIrregularities {
1286 my $subscriptionid = shift;
1288 return unless $subscriptionid;
1290 my $dbh = C4::Context->dbh;
1291 my $query = qq{
1292 SELECT irregularity
1293 FROM subscription
1294 WHERE subscriptionid = ?
1296 my $sth = $dbh->prepare($query);
1297 $sth->execute($subscriptionid);
1299 my ($result) = $sth->fetchrow_array;
1300 my @irreg = split /;/, $result;
1302 return @irreg;
1305 =head2 ModSubscription
1307 this function modifies a subscription. Put all new values on input args.
1308 returns the number of rows affected
1310 =cut
1312 sub ModSubscription {
1313 my (
1314 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1315 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1316 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1317 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1318 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1319 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1320 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq
1321 ) = @_;
1323 my $dbh = C4::Context->dbh;
1324 my $query = "UPDATE subscription
1325 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1326 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1327 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1328 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1329 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1330 callnumber=?, notes=?, letter=?, manualhistory=?,
1331 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1332 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1333 skip_serialseq=?
1334 WHERE subscriptionid = ?";
1336 my $sth = $dbh->prepare($query);
1337 $sth->execute(
1338 $auser, $branchcode, $aqbooksellerid, $cost,
1339 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1340 $irregularity, $numberpattern, $locale, $numberlength,
1341 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1342 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1343 $status, $biblionumber, $callnumber, $notes,
1344 $letter, ($manualhistory ? $manualhistory : 0),
1345 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1346 $graceperiod, $location, $enddate, $skip_serialseq,
1347 $subscriptionid
1349 my $rows = $sth->rows;
1351 logaction( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1352 return $rows;
1355 =head2 NewSubscription
1357 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1358 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1359 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1360 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1361 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1362 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq);
1364 Create a new subscription with value given on input args.
1366 return :
1367 the id of this new subscription
1369 =cut
1371 sub NewSubscription {
1372 my (
1373 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1374 $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
1375 $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
1376 $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
1377 $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
1378 $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
1379 $location, $enddate, $skip_serialseq
1380 ) = @_;
1381 my $dbh = C4::Context->dbh;
1383 #save subscription (insert into database)
1384 my $query = qq|
1385 INSERT INTO subscription
1386 (librarian, branchcode, aqbooksellerid, cost, aqbudgetid,
1387 biblionumber, startdate, periodicity, numberlength, weeklength,
1388 monthlength, lastvalue1, innerloop1, lastvalue2, innerloop2,
1389 lastvalue3, innerloop3, status, notes, letter, firstacquidate,
1390 irregularity, numberpattern, locale, callnumber,
1391 manualhistory, internalnotes, serialsadditems, staffdisplaycount,
1392 opacdisplaycount, graceperiod, location, enddate, skip_serialseq)
1393 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
1395 my $sth = $dbh->prepare($query);
1396 $sth->execute(
1397 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1398 $startdate, $periodicity, $numberlength, $weeklength,
1399 $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
1400 $lastvalue3, $innerloop3, $status, $notes, $letter,
1401 $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
1402 $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
1403 $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq
1406 my $subscriptionid = $dbh->{'mysql_insertid'};
1407 unless ($enddate) {
1408 $enddate = GetExpirationDate( $subscriptionid, $startdate );
1409 $query = qq|
1410 UPDATE subscription
1411 SET enddate=?
1412 WHERE subscriptionid=?
1414 $sth = $dbh->prepare($query);
1415 $sth->execute( $enddate, $subscriptionid );
1418 # then create the 1st expected number
1419 $query = qq(
1420 INSERT INTO subscriptionhistory
1421 (biblionumber, subscriptionid, histstartdate)
1422 VALUES (?,?,?)
1424 $sth = $dbh->prepare($query);
1425 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1427 # reread subscription to get a hash (for calculation of the 1st issue number)
1428 my $subscription = GetSubscription($subscriptionid);
1429 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
1431 # calculate issue number
1432 my $serialseq = GetSeq($subscription, $pattern) || q{};
1433 $query = qq|
1434 INSERT INTO serial
1435 (serialseq,subscriptionid,biblionumber,status, planneddate, publisheddate)
1436 VALUES (?,?,?,?,?,?)
1438 $sth = $dbh->prepare($query);
1439 $sth->execute( $serialseq, $subscriptionid, $biblionumber, EXPECTED, $firstacquidate, $firstacquidate );
1441 logaction( "SERIAL", "ADD", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1443 #set serial flag on biblio if not already set.
1444 my $bib = GetBiblio($biblionumber);
1445 if ( $bib and !$bib->{'serial'} ) {
1446 my $record = GetMarcBiblio($biblionumber);
1447 my ( $tag, $subf ) = GetMarcFromKohaField( 'biblio.serial', $bib->{'frameworkcode'} );
1448 if ($tag) {
1449 eval { $record->field($tag)->update( $subf => 1 ); };
1451 ModBiblio( $record, $biblionumber, $bib->{'frameworkcode'} );
1453 return $subscriptionid;
1456 =head2 ReNewSubscription
1458 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1460 this function renew a subscription with values given on input args.
1462 =cut
1464 sub ReNewSubscription {
1465 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1466 my $dbh = C4::Context->dbh;
1467 my $subscription = GetSubscription($subscriptionid);
1468 my $query = qq|
1469 SELECT *
1470 FROM biblio
1471 LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
1472 WHERE biblio.biblionumber=?
1474 my $sth = $dbh->prepare($query);
1475 $sth->execute( $subscription->{biblionumber} );
1476 my $biblio = $sth->fetchrow_hashref;
1478 if ( C4::Context->preference("RenewSerialAddsSuggestion") ) {
1479 require C4::Suggestions;
1480 C4::Suggestions::NewSuggestion(
1481 { 'suggestedby' => $user,
1482 'title' => $subscription->{bibliotitle},
1483 'author' => $biblio->{author},
1484 'publishercode' => $biblio->{publishercode},
1485 'note' => $biblio->{note},
1486 'biblionumber' => $subscription->{biblionumber}
1491 # renew subscription
1492 $query = qq|
1493 UPDATE subscription
1494 SET startdate=?,numberlength=?,weeklength=?,monthlength=?,reneweddate=NOW()
1495 WHERE subscriptionid=?
1497 $sth = $dbh->prepare($query);
1498 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1499 my $enddate = GetExpirationDate($subscriptionid);
1500 $debug && warn "enddate :$enddate";
1501 $query = qq|
1502 UPDATE subscription
1503 SET enddate=?
1504 WHERE subscriptionid=?
1506 $sth = $dbh->prepare($query);
1507 $sth->execute( $enddate, $subscriptionid );
1508 $query = qq|
1509 UPDATE subscriptionhistory
1510 SET histenddate=?
1511 WHERE subscriptionid=?
1513 $sth = $dbh->prepare($query);
1514 $sth->execute( $enddate, $subscriptionid );
1516 logaction( "SERIAL", "RENEW", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1517 return;
1520 =head2 NewIssue
1522 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1524 Create a new issue stored on the database.
1525 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1526 returns the serial id
1528 =cut
1530 sub NewIssue {
1531 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate, $publisheddate, $notes ) = @_;
1532 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1534 return unless ($subscriptionid);
1536 my $dbh = C4::Context->dbh;
1537 my $query = qq|
1538 INSERT INTO serial
1539 (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,notes)
1540 VALUES (?,?,?,?,?,?,?)
1542 my $sth = $dbh->prepare($query);
1543 $sth->execute( $serialseq, $subscriptionid, $biblionumber, $status, $publisheddate, $planneddate, $notes );
1544 my $serialid = $dbh->{'mysql_insertid'};
1545 $query = qq|
1546 SELECT missinglist,recievedlist
1547 FROM subscriptionhistory
1548 WHERE subscriptionid=?
1550 $sth = $dbh->prepare($query);
1551 $sth->execute($subscriptionid);
1552 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1554 if ( $status == ARRIVED ) {
1555 ### TODO Add a feature that improves recognition and description.
1556 ### As such count (serialseq) i.e. : N18,2(N19),N20
1557 ### Would use substr and index But be careful to previous presence of ()
1558 $recievedlist .= "; $serialseq" unless (index($recievedlist,$serialseq)>0);
1560 if ( grep {/^$status$/} ( MISSING_STATUSES ) ) {
1561 $missinglist .= "; $serialseq" unless (index($missinglist,$serialseq)>0);
1563 $query = qq|
1564 UPDATE subscriptionhistory
1565 SET recievedlist=?, missinglist=?
1566 WHERE subscriptionid=?
1568 $sth = $dbh->prepare($query);
1569 $recievedlist =~ s/^; //;
1570 $missinglist =~ s/^; //;
1571 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1572 return $serialid;
1575 =head2 ItemizeSerials
1577 ItemizeSerials($serialid, $info);
1578 $info is a hashref containing barcode branch, itemcallnumber, status, location
1579 $serialid the serialid
1580 return :
1581 1 if the itemize is a succes.
1582 0 and @error otherwise. @error containts the list of errors found.
1584 =cut
1586 sub ItemizeSerials {
1587 my ( $serialid, $info ) = @_;
1589 return unless ($serialid);
1591 my $now = POSIX::strftime( "%Y-%m-%d", localtime );
1593 my $dbh = C4::Context->dbh;
1594 my $query = qq|
1595 SELECT *
1596 FROM serial
1597 WHERE serialid=?
1599 my $sth = $dbh->prepare($query);
1600 $sth->execute($serialid);
1601 my $data = $sth->fetchrow_hashref;
1602 if ( C4::Context->preference("RoutingSerials") ) {
1604 # check for existing biblioitem relating to serial issue
1605 my ( $count, @results ) = GetBiblioItemByBiblioNumber( $data->{'biblionumber'} );
1606 my $bibitemno = 0;
1607 for ( my $i = 0 ; $i < $count ; $i++ ) {
1608 if ( $results[$i]->{'volumeddesc'} eq $data->{'serialseq'} . ' (' . $data->{'planneddate'} . ')' ) {
1609 $bibitemno = $results[$i]->{'biblioitemnumber'};
1610 last;
1613 if ( $bibitemno == 0 ) {
1614 my $sth = $dbh->prepare( "SELECT * FROM biblioitems WHERE biblionumber = ? ORDER BY biblioitemnumber DESC" );
1615 $sth->execute( $data->{'biblionumber'} );
1616 my $biblioitem = $sth->fetchrow_hashref;
1617 $biblioitem->{'volumedate'} = $data->{planneddate};
1618 $biblioitem->{'volumeddesc'} = $data->{serialseq} . ' (' . format_date( $data->{'planneddate'} ) . ')';
1619 $biblioitem->{'dewey'} = $info->{itemcallnumber};
1623 my $fwk = GetFrameworkCode( $data->{'biblionumber'} );
1624 if ( $info->{barcode} ) {
1625 my @errors;
1626 if ( is_barcode_in_use( $info->{barcode} ) ) {
1627 push @errors, 'barcode_not_unique';
1628 } else {
1629 my $marcrecord = MARC::Record->new();
1630 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.barcode", $fwk );
1631 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{barcode} );
1632 $marcrecord->insert_fields_ordered($newField);
1633 if ( $info->{branch} ) {
1634 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.homebranch", $fwk );
1636 #warn "items.homebranch : $tag , $subfield";
1637 if ( $marcrecord->field($tag) ) {
1638 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1639 } else {
1640 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1641 $marcrecord->insert_fields_ordered($newField);
1643 ( $tag, $subfield ) = GetMarcFromKohaField( "items.holdingbranch", $fwk );
1645 #warn "items.holdingbranch : $tag , $subfield";
1646 if ( $marcrecord->field($tag) ) {
1647 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{branch} );
1648 } else {
1649 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{branch} );
1650 $marcrecord->insert_fields_ordered($newField);
1653 if ( $info->{itemcallnumber} ) {
1654 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemcallnumber", $fwk );
1656 if ( $marcrecord->field($tag) ) {
1657 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{itemcallnumber} );
1658 } else {
1659 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{itemcallnumber} );
1660 $marcrecord->insert_fields_ordered($newField);
1663 if ( $info->{notes} ) {
1664 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.itemnotes", $fwk );
1666 if ( $marcrecord->field($tag) ) {
1667 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{notes} );
1668 } else {
1669 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{notes} );
1670 $marcrecord->insert_fields_ordered($newField);
1673 if ( $info->{location} ) {
1674 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.location", $fwk );
1676 if ( $marcrecord->field($tag) ) {
1677 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{location} );
1678 } else {
1679 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{location} );
1680 $marcrecord->insert_fields_ordered($newField);
1683 if ( $info->{status} ) {
1684 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.notforloan", $fwk );
1686 if ( $marcrecord->field($tag) ) {
1687 $marcrecord->field($tag)->add_subfields( "$subfield" => $info->{status} );
1688 } else {
1689 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $info->{status} );
1690 $marcrecord->insert_fields_ordered($newField);
1693 if ( C4::Context->preference("RoutingSerials") ) {
1694 my ( $tag, $subfield ) = GetMarcFromKohaField( "items.dateaccessioned", $fwk );
1695 if ( $marcrecord->field($tag) ) {
1696 $marcrecord->field($tag)->add_subfields( "$subfield" => $now );
1697 } else {
1698 my $newField = MARC::Field->new( "$tag", '', '', "$subfield" => $now );
1699 $marcrecord->insert_fields_ordered($newField);
1702 require C4::Items;
1703 C4::Items::AddItemFromMarc( $marcrecord, $data->{'biblionumber'} );
1704 return 1;
1706 return ( 0, @errors );
1710 =head2 HasSubscriptionStrictlyExpired
1712 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1714 the subscription has stricly expired when today > the end subscription date
1716 return :
1717 1 if true, 0 if false, -1 if the expiration date is not set.
1719 =cut
1721 sub HasSubscriptionStrictlyExpired {
1723 # Getting end of subscription date
1724 my ($subscriptionid) = @_;
1726 return unless ($subscriptionid);
1728 my $dbh = C4::Context->dbh;
1729 my $subscription = GetSubscription($subscriptionid);
1730 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1732 # If the expiration date is set
1733 if ( $expirationdate != 0 ) {
1734 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1736 # Getting today's date
1737 my ( $nowyear, $nowmonth, $nowday ) = Today();
1739 # if today's date > expiration date, then the subscription has stricly expired
1740 if ( Delta_Days( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1741 return 1;
1742 } else {
1743 return 0;
1745 } else {
1747 # There are some cases where the expiration date is not set
1748 # As we can't determine if the subscription has expired on a date-basis,
1749 # we return -1;
1750 return -1;
1754 =head2 HasSubscriptionExpired
1756 $has_expired = HasSubscriptionExpired($subscriptionid)
1758 the subscription has expired when the next issue to arrive is out of subscription limit.
1760 return :
1761 0 if the subscription has not expired
1762 1 if the subscription has expired
1763 2 if has subscription does not have a valid expiration date set
1765 =cut
1767 sub HasSubscriptionExpired {
1768 my ($subscriptionid) = @_;
1770 return unless ($subscriptionid);
1772 my $dbh = C4::Context->dbh;
1773 my $subscription = GetSubscription($subscriptionid);
1774 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
1775 if ( $frequency and $frequency->{unit} ) {
1776 my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
1777 if (!defined $expirationdate) {
1778 $expirationdate = q{};
1780 my $query = qq|
1781 SELECT max(planneddate)
1782 FROM serial
1783 WHERE subscriptionid=?
1785 my $sth = $dbh->prepare($query);
1786 $sth->execute($subscriptionid);
1787 my ($res) = $sth->fetchrow;
1788 if (!$res || $res=~m/^0000/) {
1789 return 0;
1791 my @res = split( /-/, $res );
1792 my @endofsubscriptiondate = split( /-/, $expirationdate );
1793 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date(@res) || not check_date(@endofsubscriptiondate) );
1794 return 1
1795 if ( ( @endofsubscriptiondate && Delta_Days( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1796 || ( !$res ) );
1797 return 0;
1798 } else {
1799 # Irregular
1800 if ( $subscription->{'numberlength'} ) {
1801 my $countreceived = countissuesfrom( $subscriptionid, $subscription->{'startdate'} );
1802 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1803 return 0;
1804 } else {
1805 return 0;
1808 return 0; # Notice that you'll never get here.
1811 =head2 SetDistributedto
1813 SetDistributedto($distributedto,$subscriptionid);
1814 This function update the value of distributedto for a subscription given on input arg.
1816 =cut
1818 sub SetDistributedto {
1819 my ( $distributedto, $subscriptionid ) = @_;
1820 my $dbh = C4::Context->dbh;
1821 my $query = qq|
1822 UPDATE subscription
1823 SET distributedto=?
1824 WHERE subscriptionid=?
1826 my $sth = $dbh->prepare($query);
1827 $sth->execute( $distributedto, $subscriptionid );
1828 return;
1831 =head2 DelSubscription
1833 DelSubscription($subscriptionid)
1834 this function deletes subscription which has $subscriptionid as id.
1836 =cut
1838 sub DelSubscription {
1839 my ($subscriptionid) = @_;
1840 my $dbh = C4::Context->dbh;
1841 $subscriptionid = $dbh->quote($subscriptionid);
1842 $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
1843 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
1844 $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
1846 logaction( "SERIAL", "DELETE", $subscriptionid, "" ) if C4::Context->preference("SubscriptionLog");
1849 =head2 DelIssue
1851 DelIssue($serialseq,$subscriptionid)
1852 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1854 returns the number of rows affected
1856 =cut
1858 sub DelIssue {
1859 my ($dataissue) = @_;
1860 my $dbh = C4::Context->dbh;
1861 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1863 my $query = qq|
1864 DELETE FROM serial
1865 WHERE serialid= ?
1866 AND subscriptionid= ?
1868 my $mainsth = $dbh->prepare($query);
1869 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1871 #Delete element from subscription history
1872 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1873 my $sth = $dbh->prepare($query);
1874 $sth->execute( $dataissue->{'subscriptionid'} );
1875 my $val = $sth->fetchrow_hashref;
1876 unless ( $val->{manualhistory} ) {
1877 my $query = qq|
1878 SELECT * FROM subscriptionhistory
1879 WHERE subscriptionid= ?
1881 my $sth = $dbh->prepare($query);
1882 $sth->execute( $dataissue->{'subscriptionid'} );
1883 my $data = $sth->fetchrow_hashref;
1884 my $serialseq = $dataissue->{'serialseq'};
1885 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1886 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1887 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1888 $sth = $dbh->prepare($strsth);
1889 $sth->execute( $dataissue->{'subscriptionid'} );
1892 return $mainsth->rows;
1895 =head2 GetLateOrMissingIssues
1897 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1899 this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
1901 return :
1902 the issuelist as an array of hash refs. Each element of this array contains
1903 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1905 =cut
1907 sub GetLateOrMissingIssues {
1908 my ( $supplierid, $serialid, $order ) = @_;
1910 return unless ( $supplierid or $serialid );
1912 my $dbh = C4::Context->dbh;
1914 my $sth;
1915 my $byserial = '';
1916 if ($serialid) {
1917 $byserial = "and serialid = " . $serialid;
1919 if ($order) {
1920 $order .= ", title";
1921 } else {
1922 $order = "title";
1924 my $missing_statuses_string = join ',', (MISSING_STATUSES);
1925 if ($supplierid) {
1926 $sth = $dbh->prepare(
1927 "SELECT
1928 serialid, aqbooksellerid, name,
1929 biblio.title, biblioitems.issn, planneddate, serialseq,
1930 serial.status, serial.subscriptionid, claimdate, claims_count,
1931 subscription.branchcode
1932 FROM serial
1933 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1934 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1935 LEFT JOIN biblioitems ON subscription.biblionumber=biblioitems.biblionumber
1936 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1937 WHERE subscription.subscriptionid = serial.subscriptionid
1938 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1939 AND subscription.aqbooksellerid=$supplierid
1940 $byserial
1941 ORDER BY $order"
1943 } else {
1944 $sth = $dbh->prepare(
1945 "SELECT
1946 serialid, aqbooksellerid, name,
1947 biblio.title, planneddate, serialseq,
1948 serial.status, serial.subscriptionid, claimdate, claims_count,
1949 subscription.branchcode
1950 FROM serial
1951 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1952 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1953 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1954 WHERE subscription.subscriptionid = serial.subscriptionid
1955 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1956 $byserial
1957 ORDER BY $order"
1960 $sth->execute( EXPECTED, LATE, CLAIMED );
1961 my @issuelist;
1962 while ( my $line = $sth->fetchrow_hashref ) {
1964 if ($line->{planneddate} && $line->{planneddate} !~/^0+\-/) {
1965 $line->{planneddateISO} = $line->{planneddate};
1966 $line->{planneddate} = format_date( $line->{planneddate} );
1968 if ($line->{claimdate} && $line->{claimdate} !~/^0+\-/) {
1969 $line->{claimdateISO} = $line->{claimdate};
1970 $line->{claimdate} = format_date( $line->{claimdate} );
1972 $line->{"status".$line->{status}} = 1;
1974 my $additional_field_values = Koha::AdditionalField->fetch_all_values({
1975 record_id => $line->{subscriptionid},
1976 tablename => 'subscription'
1978 %$line = ( %$line, additional_fields => $additional_field_values->{$line->{subscriptionid}} );
1980 push @issuelist, $line;
1982 return @issuelist;
1985 =head2 updateClaim
1987 &updateClaim($serialid)
1989 this function updates the time when a claim is issued for late/missing items
1991 called from claims.pl file
1993 =cut
1995 sub updateClaim {
1996 my ($serialid) = @_;
1997 my $dbh = C4::Context->dbh;
1998 $dbh->do(q|
1999 UPDATE serial
2000 SET claimdate = NOW(),
2001 claims_count = claims_count + 1
2002 WHERE serialid = ?
2003 |, {}, $serialid );
2004 return;
2007 =head2 getsupplierbyserialid
2009 $result = getsupplierbyserialid($serialid)
2011 this function is used to find the supplier id given a serial id
2013 return :
2014 hashref containing serialid, subscriptionid, and aqbooksellerid
2016 =cut
2018 sub getsupplierbyserialid {
2019 my ($serialid) = @_;
2020 my $dbh = C4::Context->dbh;
2021 my $sth = $dbh->prepare(
2022 "SELECT serialid, serial.subscriptionid, aqbooksellerid
2023 FROM serial
2024 LEFT JOIN subscription ON serial.subscriptionid = subscription.subscriptionid
2025 WHERE serialid = ?
2028 $sth->execute($serialid);
2029 my $line = $sth->fetchrow_hashref;
2030 my $result = $line->{'aqbooksellerid'};
2031 return $result;
2034 =head2 check_routing
2036 $result = &check_routing($subscriptionid)
2038 this function checks to see if a serial has a routing list and returns the count of routingid
2039 used to show either an 'add' or 'edit' link
2041 =cut
2043 sub check_routing {
2044 my ($subscriptionid) = @_;
2046 return unless ($subscriptionid);
2048 my $dbh = C4::Context->dbh;
2049 my $sth = $dbh->prepare(
2050 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
2051 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2052 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
2055 $sth->execute($subscriptionid);
2056 my $line = $sth->fetchrow_hashref;
2057 my $result = $line->{'routingids'};
2058 return $result;
2061 =head2 addroutingmember
2063 addroutingmember($borrowernumber,$subscriptionid)
2065 this function takes a borrowernumber and subscriptionid and adds the member to the
2066 routing list for that serial subscription and gives them a rank on the list
2067 of either 1 or highest current rank + 1
2069 =cut
2071 sub addroutingmember {
2072 my ( $borrowernumber, $subscriptionid ) = @_;
2074 return unless ($borrowernumber and $subscriptionid);
2076 my $rank;
2077 my $dbh = C4::Context->dbh;
2078 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
2079 $sth->execute($subscriptionid);
2080 while ( my $line = $sth->fetchrow_hashref ) {
2081 if ( $line->{'rank'} > 0 ) {
2082 $rank = $line->{'rank'} + 1;
2083 } else {
2084 $rank = 1;
2087 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
2088 $sth->execute( $subscriptionid, $borrowernumber, $rank );
2091 =head2 reorder_members
2093 reorder_members($subscriptionid,$routingid,$rank)
2095 this function is used to reorder the routing list
2097 it takes the routingid of the member one wants to re-rank and the rank it is to move to
2098 - it gets all members on list puts their routingid's into an array
2099 - removes the one in the array that is $routingid
2100 - then reinjects $routingid at point indicated by $rank
2101 - then update the database with the routingids in the new order
2103 =cut
2105 sub reorder_members {
2106 my ( $subscriptionid, $routingid, $rank ) = @_;
2107 my $dbh = C4::Context->dbh;
2108 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
2109 $sth->execute($subscriptionid);
2110 my @result;
2111 while ( my $line = $sth->fetchrow_hashref ) {
2112 push( @result, $line->{'routingid'} );
2115 # To find the matching index
2116 my $i;
2117 my $key = -1; # to allow for 0 being a valid response
2118 for ( $i = 0 ; $i < @result ; $i++ ) {
2119 if ( $routingid == $result[$i] ) {
2120 $key = $i; # save the index
2121 last;
2125 # if index exists in array then move it to new position
2126 if ( $key > -1 && $rank > 0 ) {
2127 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
2128 my $moving_item = splice( @result, $key, 1 );
2129 splice( @result, $new_rank, 0, $moving_item );
2131 for ( my $j = 0 ; $j < @result ; $j++ ) {
2132 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
2133 $sth->execute;
2135 return;
2138 =head2 delroutingmember
2140 delroutingmember($routingid,$subscriptionid)
2142 this function either deletes one member from routing list if $routingid exists otherwise
2143 deletes all members from the routing list
2145 =cut
2147 sub delroutingmember {
2149 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2150 my ( $routingid, $subscriptionid ) = @_;
2151 my $dbh = C4::Context->dbh;
2152 if ($routingid) {
2153 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2154 $sth->execute($routingid);
2155 reorder_members( $subscriptionid, $routingid );
2156 } else {
2157 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2158 $sth->execute($subscriptionid);
2160 return;
2163 =head2 getroutinglist
2165 @routinglist = getroutinglist($subscriptionid)
2167 this gets the info from the subscriptionroutinglist for $subscriptionid
2169 return :
2170 the routinglist as an array. Each element of the array contains a hash_ref containing
2171 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2173 =cut
2175 sub getroutinglist {
2176 my ($subscriptionid) = @_;
2177 my $dbh = C4::Context->dbh;
2178 my $sth = $dbh->prepare(
2179 'SELECT routingid, borrowernumber, ranking, biblionumber
2180 FROM subscription
2181 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2182 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2184 $sth->execute($subscriptionid);
2185 my $routinglist = $sth->fetchall_arrayref({});
2186 return @{$routinglist};
2189 =head2 countissuesfrom
2191 $result = countissuesfrom($subscriptionid,$startdate)
2193 Returns a count of serial rows matching the given subsctiptionid
2194 with published date greater than startdate
2196 =cut
2198 sub countissuesfrom {
2199 my ( $subscriptionid, $startdate ) = @_;
2200 my $dbh = C4::Context->dbh;
2201 my $query = qq|
2202 SELECT count(*)
2203 FROM serial
2204 WHERE subscriptionid=?
2205 AND serial.publisheddate>?
2207 my $sth = $dbh->prepare($query);
2208 $sth->execute( $subscriptionid, $startdate );
2209 my ($countreceived) = $sth->fetchrow;
2210 return $countreceived;
2213 =head2 CountIssues
2215 $result = CountIssues($subscriptionid)
2217 Returns a count of serial rows matching the given subsctiptionid
2219 =cut
2221 sub CountIssues {
2222 my ($subscriptionid) = @_;
2223 my $dbh = C4::Context->dbh;
2224 my $query = qq|
2225 SELECT count(*)
2226 FROM serial
2227 WHERE subscriptionid=?
2229 my $sth = $dbh->prepare($query);
2230 $sth->execute($subscriptionid);
2231 my ($countreceived) = $sth->fetchrow;
2232 return $countreceived;
2235 =head2 HasItems
2237 $result = HasItems($subscriptionid)
2239 returns a count of items from serial matching the subscriptionid
2241 =cut
2243 sub HasItems {
2244 my ($subscriptionid) = @_;
2245 my $dbh = C4::Context->dbh;
2246 my $query = q|
2247 SELECT COUNT(serialitems.itemnumber)
2248 FROM serial
2249 LEFT JOIN serialitems USING(serialid)
2250 WHERE subscriptionid=? AND serialitems.serialid IS NOT NULL
2252 my $sth=$dbh->prepare($query);
2253 $sth->execute($subscriptionid);
2254 my ($countitems)=$sth->fetchrow_array();
2255 return $countitems;
2258 =head2 abouttoexpire
2260 $result = abouttoexpire($subscriptionid)
2262 this function alerts you to the penultimate issue for a serial subscription
2264 returns 1 - if this is the penultimate issue
2265 returns 0 - if not
2267 =cut
2269 sub abouttoexpire {
2270 my ($subscriptionid) = @_;
2271 my $dbh = C4::Context->dbh;
2272 my $subscription = GetSubscription($subscriptionid);
2273 my $per = $subscription->{'periodicity'};
2274 my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($per);
2275 if ($frequency and $frequency->{unit}){
2277 my $expirationdate = GetExpirationDate($subscriptionid);
2279 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2280 my $nextdate = GetNextDate($subscription, $res);
2282 # only compare dates if both dates exist.
2283 if ($nextdate and $expirationdate) {
2284 if(Date::Calc::Delta_Days(
2285 split( /-/, $nextdate ),
2286 split( /-/, $expirationdate )
2287 ) <= 0) {
2288 return 1;
2292 } elsif ($subscription->{numberlength}>0) {
2293 return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
2296 return 0;
2299 sub in_array { # used in next sub down
2300 my ( $val, @elements ) = @_;
2301 foreach my $elem (@elements) {
2302 if ( $val == $elem ) {
2303 return 1;
2306 return 0;
2309 =head2 GetSubscriptionsFromBorrower
2311 ($count,@routinglist) = GetSubscriptionsFromBorrower($borrowernumber)
2313 this gets the info from subscriptionroutinglist for each $subscriptionid
2315 return :
2316 a count of the serial subscription routing lists to which a patron belongs,
2317 with the titles of those serial subscriptions as an array. Each element of the array
2318 contains a hash_ref with subscriptionID and title of subscription.
2320 =cut
2322 sub GetSubscriptionsFromBorrower {
2323 my ($borrowernumber) = @_;
2324 my $dbh = C4::Context->dbh;
2325 my $sth = $dbh->prepare(
2326 "SELECT subscription.subscriptionid, biblio.title
2327 FROM subscription
2328 JOIN biblio ON biblio.biblionumber = subscription.biblionumber
2329 JOIN subscriptionroutinglist USING (subscriptionid)
2330 WHERE subscriptionroutinglist.borrowernumber = ? ORDER BY title ASC
2333 $sth->execute($borrowernumber);
2334 my @routinglist;
2335 my $count = 0;
2336 while ( my $line = $sth->fetchrow_hashref ) {
2337 $count++;
2338 push( @routinglist, $line );
2340 return ( $count, @routinglist );
2344 =head2 GetFictiveIssueNumber
2346 $issueno = GetFictiveIssueNumber($subscription, $publishedate);
2348 Get the position of the issue published at $publisheddate, considering the
2349 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2350 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2351 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2352 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2353 depending on how many rows are in serial table.
2354 The issue number calculation is based on subscription frequency, first acquisition
2355 date, and $publisheddate.
2357 =cut
2359 sub GetFictiveIssueNumber {
2360 my ($subscription, $publisheddate) = @_;
2362 my $frequency = GetSubscriptionFrequency($subscription->{'periodicity'});
2363 my $unit = $frequency->{unit} ? lc $frequency->{'unit'} : undef;
2364 my $issueno = 0;
2366 if($unit) {
2367 my ($year, $month, $day) = split /-/, $publisheddate;
2368 my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{'firstacquidate'};
2369 my $wkno;
2370 my $delta;
2372 if($unit eq 'day') {
2373 $delta = Delta_Days($fa_year, $fa_month, $fa_day, $year, $month, $day);
2374 } elsif($unit eq 'week') {
2375 ($wkno, $year) = Week_of_Year($year, $month, $day);
2376 my ($fa_wkno, $fa_yr) = Week_of_Year($fa_year, $fa_month, $fa_day);
2377 $delta = ($fa_yr == $year) ? ($wkno - $fa_wkno) : ( ($year-$fa_yr-1)*52 + (52-$fa_wkno+$wkno) );
2378 } elsif($unit eq 'month') {
2379 $delta = ($fa_year == $year)
2380 ? ($month - $fa_month)
2381 : ( ($year-$fa_year-1)*12 + (12-$fa_month+$month) );
2382 } elsif($unit eq 'year') {
2383 $delta = $year - $fa_year;
2385 if($frequency->{'unitsperissue'} == 1) {
2386 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2387 } else {
2388 # Assuming issuesperunit == 1
2389 $issueno = int( ($delta + $frequency->{'unitsperissue'}) / $frequency->{'unitsperissue'} );
2392 return $issueno;
2395 sub _get_next_date_day {
2396 my ($subscription, $freqdata, $year, $month, $day) = @_;
2398 if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
2399 ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{unitsperissue} );
2400 $subscription->{countissuesperunit} = 1;
2401 } else {
2402 $subscription->{countissuesperunit}++;
2405 return ($year, $month, $day);
2408 sub _get_next_date_week {
2409 my ($subscription, $freqdata, $year, $month, $day) = @_;
2411 my ($wkno, $yr) = Week_of_Year($year, $month, $day);
2412 my $fa_dow = Day_of_Week(split /-/, $subscription->{firstacquidate});
2414 if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
2415 $subscription->{countissuesperunit} = 1;
2416 $wkno += $freqdata->{unitsperissue};
2417 if($wkno > 52){
2418 $wkno = $wkno % 52;
2419 $yr++;
2421 ($year,$month,$day) = Monday_of_Week($wkno, $yr);
2422 ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $fa_dow - 1);
2423 } else {
2424 # Try to guess the next day of week
2425 my $delta_days = int((7 - ($fa_dow - 1)) / $freqdata->{issuesperunit});
2426 ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
2427 $subscription->{countissuesperunit}++;
2430 return ($year, $month, $day);
2433 sub _get_next_date_month {
2434 my ($subscription, $freqdata, $year, $month, $day) = @_;
2436 my $fa_day;
2437 (undef, undef, $fa_day) = split /-/, $subscription->{firstacquidate};
2439 if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
2440 $subscription->{countissuesperunit} = 1;
2441 ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,
2442 $freqdata->{unitsperissue});
2443 my $days_in_month = Days_in_Month($year, $month);
2444 $day = $fa_day <= $days_in_month ? $fa_day : $days_in_month;
2445 } else {
2446 # Try to guess the next day in month
2447 my $days_in_month = Days_in_Month($year, $month);
2448 my $delta_days = int(($days_in_month - ($fa_day - 1)) / $freqdata->{issuesperunit});
2449 ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
2450 $subscription->{countissuesperunit}++;
2453 return ($year, $month, $day);
2456 sub _get_next_date_year {
2457 my ($subscription, $freqdata, $year, $month, $day) = @_;
2459 my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{firstacquidate};
2461 if ($subscription->{countissuesperunit} + 1 > $freqdata->{issuesperunit}){
2462 $subscription->{countissuesperunit} = 1;
2463 ($year) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
2464 $month = $fa_month;
2465 my $days_in_month = Days_in_Month($year, $month);
2466 $day = $fa_day <= $days_in_month ? $fa_day : $days_in_month;
2467 } else {
2468 # Try to guess the next day in year
2469 my $days_in_year = Days_in_Year($year,12); #Sum the days of all the months of this year
2470 my $delta_days = int(($days_in_year - ($fa_day - 1)) / $freqdata->{issuesperunit});
2471 ($year,$month,$day) = Add_Delta_Days($year, $month, $day, $delta_days);
2472 $subscription->{countissuesperunit}++;
2475 return ($year, $month, $day);
2478 =head2 GetNextDate
2480 $resultdate = GetNextDate($publisheddate,$subscription)
2482 this function it takes the publisheddate and will return the next issue's date
2483 and will skip dates if there exists an irregularity.
2484 $publisheddate has to be an ISO date
2485 $subscription is a hashref containing at least 'periodicity', 'firstacquidate', 'irregularity', and 'countissuesperunit'
2486 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2487 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2488 skipped then the returned date will be 2007-05-10
2490 return :
2491 $resultdate - then next date in the sequence (ISO date)
2493 Return undef if subscription is irregular
2495 =cut
2497 sub GetNextDate {
2498 my ( $subscription, $publisheddate, $updatecount ) = @_;
2500 return unless $subscription and $publisheddate;
2502 my $freqdata = GetSubscriptionFrequency($subscription->{'periodicity'});
2504 if ($freqdata->{'unit'}) {
2505 my ( $year, $month, $day ) = split /-/, $publisheddate;
2507 # Process an irregularity Hash
2508 # Suppose that irregularities are stored in a string with this structure
2509 # irreg1;irreg2;irreg3
2510 # where irregX is the number of issue which will not be received
2511 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2512 my %irregularities;
2513 if ( $subscription->{irregularity} ) {
2514 my @irreg = split /;/, $subscription->{'irregularity'} ;
2515 foreach my $irregularity (@irreg) {
2516 $irregularities{$irregularity} = 1;
2520 # Get the 'fictive' next issue number
2521 # It is used to check if next issue is an irregular issue.
2522 my $issueno = GetFictiveIssueNumber($subscription, $publisheddate) + 1;
2524 # Then get the next date
2525 my $unit = lc $freqdata->{'unit'};
2526 if ($unit eq 'day') {
2527 while ($irregularities{$issueno}) {
2528 ($year, $month, $day) = _get_next_date_day($subscription,
2529 $freqdata, $year, $month, $day);
2530 $issueno++;
2532 ($year, $month, $day) = _get_next_date_day($subscription, $freqdata,
2533 $year, $month, $day);
2535 elsif ($unit eq 'week') {
2536 while ($irregularities{$issueno}) {
2537 ($year, $month, $day) = _get_next_date_week($subscription,
2538 $freqdata, $year, $month, $day);
2539 $issueno++;
2541 ($year, $month, $day) = _get_next_date_week($subscription,
2542 $freqdata, $year, $month, $day);
2544 elsif ($unit eq 'month') {
2545 while ($irregularities{$issueno}) {
2546 ($year, $month, $day) = _get_next_date_month($subscription,
2547 $freqdata, $year, $month, $day);
2548 $issueno++;
2550 ($year, $month, $day) = _get_next_date_month($subscription,
2551 $freqdata, $year, $month, $day);
2553 elsif ($unit eq 'year') {
2554 while ($irregularities{$issueno}) {
2555 ($year, $month, $day) = _get_next_date_year($subscription,
2556 $freqdata, $year, $month, $day);
2557 $issueno++;
2559 ($year, $month, $day) = _get_next_date_year($subscription,
2560 $freqdata, $year, $month, $day);
2563 if ($updatecount){
2564 my $dbh = C4::Context->dbh;
2565 my $query = qq{
2566 UPDATE subscription
2567 SET countissuesperunit = ?
2568 WHERE subscriptionid = ?
2570 my $sth = $dbh->prepare($query);
2571 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2574 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2578 =head2 _numeration
2580 $string = &_numeration($value,$num_type,$locale);
2582 _numeration returns the string corresponding to $value in the num_type
2583 num_type can take :
2584 -dayname
2585 -monthname
2586 -season
2587 =cut
2591 sub _numeration {
2592 my ($value, $num_type, $locale) = @_;
2593 $value ||= 0;
2594 $num_type //= '';
2595 $locale ||= 'en';
2596 my $string;
2597 if ( $num_type =~ /^dayname$/ ) {
2598 # 1970-11-01 was a Sunday
2599 $value = $value % 7;
2600 my $dt = DateTime->new(
2601 year => 1970,
2602 month => 11,
2603 day => $value + 1,
2604 locale => $locale,
2606 $string = $dt->strftime("%A");
2607 } elsif ( $num_type =~ /^monthname$/ ) {
2608 $value = $value % 12;
2609 my $dt = DateTime->new(
2610 year => 1970,
2611 month => $value + 1,
2612 locale => $locale,
2614 $string = $dt->strftime("%B");
2615 } elsif ( $num_type =~ /^season$/ ) {
2616 my @seasons= qw( Spring Summer Fall Winter );
2617 $value = $value % 4;
2618 $string = $seasons[$value];
2619 } else {
2620 $string = $value;
2623 return $string;
2626 =head2 is_barcode_in_use
2628 Returns number of occurrences of the barcode in the items table
2629 Can be used as a boolean test of whether the barcode has
2630 been deployed as yet
2632 =cut
2634 sub is_barcode_in_use {
2635 my $barcode = shift;
2636 my $dbh = C4::Context->dbh;
2637 my $occurrences = $dbh->selectall_arrayref(
2638 'SELECT itemnumber from items where barcode = ?',
2639 {}, $barcode
2643 return @{$occurrences};
2646 =head2 CloseSubscription
2647 Close a subscription given a subscriptionid
2648 =cut
2649 sub CloseSubscription {
2650 my ( $subscriptionid ) = @_;
2651 return unless $subscriptionid;
2652 my $dbh = C4::Context->dbh;
2653 my $sth = $dbh->prepare( q{
2654 UPDATE subscription
2655 SET closed = 1
2656 WHERE subscriptionid = ?
2657 } );
2658 $sth->execute( $subscriptionid );
2660 # Set status = missing when status = stopped
2661 $sth = $dbh->prepare( q{
2662 UPDATE serial
2663 SET status = ?
2664 WHERE subscriptionid = ?
2665 AND status = ?
2666 } );
2667 $sth->execute( STOPPED, $subscriptionid, EXPECTED );
2670 =head2 ReopenSubscription
2671 Reopen a subscription given a subscriptionid
2672 =cut
2673 sub ReopenSubscription {
2674 my ( $subscriptionid ) = @_;
2675 return unless $subscriptionid;
2676 my $dbh = C4::Context->dbh;
2677 my $sth = $dbh->prepare( q{
2678 UPDATE subscription
2679 SET closed = 0
2680 WHERE subscriptionid = ?
2681 } );
2682 $sth->execute( $subscriptionid );
2684 # Set status = expected when status = stopped
2685 $sth = $dbh->prepare( q{
2686 UPDATE serial
2687 SET status = ?
2688 WHERE subscriptionid = ?
2689 AND status = ?
2690 } );
2691 $sth->execute( EXPECTED, $subscriptionid, STOPPED );
2694 =head2 subscriptionCurrentlyOnOrder
2696 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2698 Return 1 if subscription is currently on order else 0.
2700 =cut
2702 sub subscriptionCurrentlyOnOrder {
2703 my ( $subscriptionid ) = @_;
2704 my $dbh = C4::Context->dbh;
2705 my $query = qq|
2706 SELECT COUNT(*) FROM aqorders
2707 WHERE subscriptionid = ?
2708 AND datereceived IS NULL
2709 AND datecancellationprinted IS NULL
2711 my $sth = $dbh->prepare( $query );
2712 $sth->execute($subscriptionid);
2713 return $sth->fetchrow_array;
2716 =head2 can_edit_subscription
2718 $can = can_edit_subscription( $subscriptionid[, $userid] );
2720 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2722 =cut
2724 sub can_edit_subscription {
2725 my ( $subscription, $userid ) = @_;
2726 return _can_do_on_subscription( $subscription, $userid, 'edit_subscription' );
2729 =head2 can_show_subscription
2731 $can = can_show_subscription( $subscriptionid[, $userid] );
2733 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2735 =cut
2737 sub can_show_subscription {
2738 my ( $subscription, $userid ) = @_;
2739 return _can_do_on_subscription( $subscription, $userid, '*' );
2742 sub _can_do_on_subscription {
2743 my ( $subscription, $userid, $permission ) = @_;
2744 return 0 unless C4::Context->userenv;
2745 my $flags = C4::Context->userenv->{flags};
2746 $userid ||= C4::Context->userenv->{'id'};
2748 if ( C4::Context->preference('IndependentBranches') ) {
2749 return 1
2750 if C4::Context->IsSuperLibrarian()
2752 C4::Auth::haspermission( $userid, { serials => 'superserials' } )
2753 or (
2754 C4::Auth::haspermission( $userid,
2755 { serials => $permission } )
2756 and ( not defined $subscription->{branchcode}
2757 or $subscription->{branchcode} eq ''
2758 or $subscription->{branchcode} eq
2759 C4::Context->userenv->{'branch'} )
2762 else {
2763 return 1
2764 if C4::Context->IsSuperLibrarian()
2766 C4::Auth::haspermission( $userid, { serials => 'superserials' } )
2767 or C4::Auth::haspermission(
2768 $userid, { serials => $permission }
2772 return 0;
2776 __END__
2778 =head1 AUTHOR
2780 Koha Development Team <http://koha-community.org/>
2782 =cut