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>.
23 use C4
::Auth
qw(haspermission);
26 use Date
::Calc
qw(:all);
27 use POSIX
qw(strftime);
29 use C4
::Log
; # logaction
31 use C4
::Serials
::Frequency
;
32 use C4
::Serials
::Numberpattern
;
33 use Koha
::AdditionalField
;
36 use Koha
::Subscriptions
;
37 use Koha
::Subscription
::Histories
;
38 use Koha
::SharedContent
;
40 use vars
qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
48 MISSING_NEVER_RECIEVED => 41,
49 MISSING_SOLD_OUT => 42,
50 MISSING_DAMAGED => 43,
58 use constant MISSING_STATUSES => (
59 MISSING, MISSING_NEVER_RECIEVED,
60 MISSING_SOLD_OUT, MISSING_DAMAGED,
68 &NewSubscription &ModSubscription &DelSubscription
69 &GetSubscription &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
71 &GetFullSubscriptionsFromBiblionumber &GetFullSubscription &ModSubscriptionHistory
72 &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
73 &GetSubscriptionHistoryFromSubscriptionId
75 &GetNextSeq &GetSeq &NewIssue &GetSerials
76 &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2
77 &ReNewSubscription &GetLateOrMissingIssues
78 &GetSerialInformation &AddItem2Serial
79 &PrepareSerialsData &GetNextExpected &ModNextExpected
82 &GetSuppliersWithLateIssues
83 &getroutinglist &delroutingmember &addroutingmember
85 &check_routing &updateClaim
88 &subscriptionCurrentlyOnOrder
95 C4::Serials - Serials Module Functions
103 Functions for handling subscriptions, claims routing etc.
108 =head2 GetSuppliersWithLateIssues
110 $supplierlist = GetSuppliersWithLateIssues()
112 this function get all suppliers with late issues.
115 an array_ref of suppliers each entry is a hash_ref containing id and name
116 the array is in name order
120 sub GetSuppliersWithLateIssues
{
121 my $dbh = C4
::Context
->dbh;
122 my $statuses = join(',', ( LATE
, MISSING_STATUSES
, CLAIMED
) );
124 SELECT DISTINCT id
, name
126 LEFT JOIN serial ON serial
.subscriptionid
=subscription
.subscriptionid
127 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
130 (planneddate
< now
() AND serial
.status
=1)
131 OR serial
.STATUS IN
( $statuses )
133 AND subscription
.closed
= 0
135 return $dbh->selectall_arrayref($query, { Slice
=> {} });
138 =head2 GetSubscriptionHistoryFromSubscriptionId
140 $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
142 This function returns the subscription history as a hashref
146 sub GetSubscriptionHistoryFromSubscriptionId
{
147 my ($subscriptionid) = @_;
149 return unless $subscriptionid;
151 my $dbh = C4
::Context
->dbh;
154 FROM subscriptionhistory
155 WHERE subscriptionid
= ?
157 my $sth = $dbh->prepare($query);
158 $sth->execute($subscriptionid);
159 my $results = $sth->fetchrow_hashref;
165 =head2 GetSerialInformation
167 $data = GetSerialInformation($serialid);
168 returns a hash_ref containing :
169 items : items marcrecord (can be an array)
171 subscription table field
172 + information about subscription expiration
176 sub GetSerialInformation
{
178 my $dbh = C4
::Context
->dbh;
180 SELECT serial
.*, serial
.notes as sernotes
, serial
.status as serstatus
,subscription
.*,subscription
.subscriptionid as subsid
181 FROM serial LEFT JOIN subscription ON subscription
.subscriptionid
=serial
.subscriptionid
184 my $rq = $dbh->prepare($query);
185 $rq->execute($serialid);
186 my $data = $rq->fetchrow_hashref;
188 # create item information if we have serialsadditems for this subscription
189 if ( $data->{'serialsadditems'} ) {
190 my $queryitem = $dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
191 $queryitem->execute($serialid);
192 my $itemnumbers = $queryitem->fetchall_arrayref( [0] );
194 if ( scalar(@
$itemnumbers) > 0 ) {
195 foreach my $itemnum (@
$itemnumbers) {
197 #It is ASSUMED that GetMarcItem ALWAYS WORK...
198 #Maybe GetMarcItem should return values on failure
199 $debug and warn "itemnumber :$itemnum->[0], bibnum :" . $data->{'biblionumber'};
200 my $itemprocessed = C4
::Items
::PrepareItemrecordDisplay
( $data->{'biblionumber'}, $itemnum->[0], $data );
201 $itemprocessed->{'itemnumber'} = $itemnum->[0];
202 $itemprocessed->{'itemid'} = $itemnum->[0];
203 $itemprocessed->{'serialid'} = $serialid;
204 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
205 push @
{ $data->{'items'} }, $itemprocessed;
208 my $itemprocessed = C4
::Items
::PrepareItemrecordDisplay
( $data->{'biblionumber'}, '', $data );
209 $itemprocessed->{'itemid'} = "N$serialid";
210 $itemprocessed->{'serialid'} = $serialid;
211 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
212 $itemprocessed->{'countitems'} = 0;
213 push @
{ $data->{'items'} }, $itemprocessed;
216 $data->{ "status" . $data->{'serstatus'} } = 1;
217 $data->{'subscriptionexpired'} = HasSubscriptionExpired
( $data->{'subscriptionid'} ) && $data->{'status'} == 1;
218 $data->{'abouttoexpire'} = abouttoexpire
( $data->{'subscriptionid'} );
219 $data->{cannotedit
} = not can_edit_subscription
( $data );
223 =head2 AddItem2Serial
225 $rows = AddItem2Serial($serialid,$itemnumber);
226 Adds an itemnumber to Serial record
227 returns the number of rows affected
232 my ( $serialid, $itemnumber ) = @_;
234 return unless ($serialid and $itemnumber);
236 my $dbh = C4
::Context
->dbh;
237 my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
238 $rq->execute( $serialid, $itemnumber );
242 =head2 GetSubscription
244 $subs = GetSubscription($subscriptionid)
245 this function returns the subscription which has $subscriptionid as id.
247 a hashref. This hash contains
248 subscription, subscriptionhistory, aqbooksellers.name, biblio.title
252 sub GetSubscription
{
253 my ($subscriptionid) = @_;
254 my $dbh = C4
::Context
->dbh;
256 SELECT subscription
.*,
257 subscriptionhistory
.*,
258 aqbooksellers
.name AS aqbooksellername
,
259 biblio
.title AS bibliotitle
,
260 subscription
.biblionumber as bibnum
262 LEFT JOIN subscriptionhistory ON subscription
.subscriptionid
=subscriptionhistory
.subscriptionid
263 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
=aqbooksellers
.id
264 LEFT JOIN biblio ON biblio
.biblionumber
=subscription
.biblionumber
265 WHERE subscription
.subscriptionid
= ?
268 $debug and warn "query : $query\nsubsid :$subscriptionid";
269 my $sth = $dbh->prepare($query);
270 $sth->execute($subscriptionid);
271 my $subscription = $sth->fetchrow_hashref;
273 return unless $subscription;
275 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
277 # Add additional fields to the subscription into a new key "additional_fields"
278 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
279 tablename
=> 'subscription',
280 record_id
=> $subscriptionid,
282 $subscription->{additional_fields
} = $additional_field_values->{$subscriptionid};
284 if ( my $mana_id = $subscription->{mana_id
} ) {
285 my $mana_subscription = Koha
::SharedContent
::get_entity_by_id
(
286 'subscription', $mana_id, {usecomments
=> 1});
287 $subscription->{comments
} = $mana_subscription->{data
}->{comments
};
290 return $subscription;
293 =head2 GetFullSubscription
295 $array_ref = GetFullSubscription($subscriptionid)
296 this function reads the serial table.
300 sub GetFullSubscription
{
301 my ($subscriptionid) = @_;
303 return unless ($subscriptionid);
305 my $dbh = C4
::Context
->dbh;
307 SELECT serial
.serialid
,
310 serial
.publisheddate
,
311 serial
.publisheddatetext
,
313 serial
.notes as notes
,
314 year
(IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) as year
,
315 aqbooksellers
.name as aqbooksellername
,
316 biblio
.title as bibliotitle
,
317 subscription
.branchcode AS branchcode
,
318 subscription
.subscriptionid AS subscriptionid
320 LEFT JOIN subscription ON
321 (serial
.subscriptionid
=subscription
.subscriptionid
)
322 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
323 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
324 WHERE serial
.subscriptionid
= ?
326 IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) DESC
,
327 serial
.subscriptionid
329 $debug and warn "GetFullSubscription query: $query";
330 my $sth = $dbh->prepare($query);
331 $sth->execute($subscriptionid);
332 my $subscriptions = $sth->fetchall_arrayref( {} );
333 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
334 for my $subscription ( @
$subscriptions ) {
335 $subscription->{cannotedit
} = $cannotedit;
337 return $subscriptions;
340 =head2 PrepareSerialsData
342 $array_ref = PrepareSerialsData($serialinfomation)
343 where serialinformation is a hashref array
347 sub PrepareSerialsData
{
350 return unless ($lines);
356 my $aqbooksellername;
360 my $previousnote = "";
362 foreach my $subs (@
{$lines}) {
363 for my $datefield ( qw(publisheddate planneddate) ) {
364 # handle 0000-00-00 dates
365 if (defined $subs->{$datefield} and $subs->{$datefield} =~ m/^00/) {
366 $subs->{$datefield} = undef;
369 $subs->{ "status" . $subs->{'status'} } = 1;
370 if ( grep { $_ == $subs->{status
} } ( EXPECTED
, LATE
, MISSING_STATUSES
, CLAIMED
) ) {
371 $subs->{"checked"} = 1;
374 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
375 $year = $subs->{'year'};
379 if ( $tmpresults{$year} ) {
380 push @
{ $tmpresults{$year}->{'serials'} }, $subs;
382 $tmpresults{$year} = {
384 'aqbooksellername' => $subs->{'aqbooksellername'},
385 'bibliotitle' => $subs->{'bibliotitle'},
386 'serials' => [$subs],
391 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
392 push @res, $tmpresults{$key};
397 =head2 GetSubscriptionsFromBiblionumber
399 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
400 this function get the subscription list. it reads the subscription table.
402 reference to an array of subscriptions which have the biblionumber given on input arg.
403 each element of this array is a hashref containing
404 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
408 sub GetSubscriptionsFromBiblionumber
{
409 my ($biblionumber) = @_;
411 return unless ($biblionumber);
413 my $dbh = C4
::Context
->dbh;
415 SELECT subscription
.*,
417 subscriptionhistory
.*,
418 aqbooksellers
.name AS aqbooksellername
,
419 biblio
.title AS bibliotitle
421 LEFT JOIN subscriptionhistory ON subscription
.subscriptionid
=subscriptionhistory
.subscriptionid
422 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
=aqbooksellers
.id
423 LEFT JOIN biblio ON biblio
.biblionumber
=subscription
.biblionumber
424 LEFT JOIN branches ON branches
.branchcode
=subscription
.branchcode
425 WHERE subscription
.biblionumber
= ?
427 my $sth = $dbh->prepare($query);
428 $sth->execute($biblionumber);
430 while ( my $subs = $sth->fetchrow_hashref ) {
431 $subs->{startdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{startdate
} ), dateonly
=> 1 } );
432 $subs->{histstartdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histstartdate
} ), dateonly
=> 1 } );
433 if ( defined $subs->{histenddate
} ) {
434 $subs->{histenddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histenddate
} ), dateonly
=> 1 } );
436 $subs->{histenddate
} = "";
438 $subs->{opacnote
} =~ s/\n/\<br\/\
>/g
;
439 $subs->{missinglist
} =~ s/\n/\<br\/\
>/g
;
440 $subs->{recievedlist
} =~ s/\n/\<br\/\
>/g
;
441 $subs->{ "periodicity" . $subs->{periodicity
} } = 1;
442 $subs->{ "numberpattern" . $subs->{numberpattern
} } = 1;
443 $subs->{ "status" . $subs->{'status'} } = 1;
445 if (not defined $subs->{enddate
} ) {
446 $subs->{enddate
} = '';
448 $subs->{enddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{enddate
}), dateonly
=> 1 } );
450 $subs->{'abouttoexpire'} = abouttoexpire
( $subs->{'subscriptionid'} );
451 $subs->{'subscriptionexpired'} = HasSubscriptionExpired
( $subs->{'subscriptionid'} );
452 $subs->{cannotedit
} = not can_edit_subscription
( $subs );
458 =head2 GetFullSubscriptionsFromBiblionumber
460 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
461 this function reads the serial table.
465 sub GetFullSubscriptionsFromBiblionumber
{
466 my ($biblionumber) = @_;
467 my $dbh = C4
::Context
->dbh;
469 SELECT serial
.serialid
,
472 serial
.publisheddate
,
473 serial
.publisheddatetext
,
475 serial
.notes as notes
,
476 year
(IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) as year
,
477 biblio
.title as bibliotitle
,
478 subscription
.branchcode AS branchcode
,
479 subscription
.subscriptionid AS subscriptionid
481 LEFT JOIN subscription ON
482 (serial
.subscriptionid
=subscription
.subscriptionid
)
483 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
484 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
485 WHERE subscription
.biblionumber
= ?
487 IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) DESC
,
488 serial
.subscriptionid
490 my $sth = $dbh->prepare($query);
491 $sth->execute($biblionumber);
492 my $subscriptions = $sth->fetchall_arrayref( {} );
493 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
494 for my $subscription ( @
$subscriptions ) {
495 $subscription->{cannotedit
} = $cannotedit;
497 return $subscriptions;
500 =head2 SearchSubscriptions
502 @results = SearchSubscriptions($args);
504 This function returns a list of hashrefs, one for each subscription
505 that meets the conditions specified by the $args hashref.
507 The valid search fields are:
521 The expiration_date search field is special; it specifies the maximum
522 subscription expiration date.
526 sub SearchSubscriptions
{
529 my $additional_fields = $args->{additional_fields
} // [];
530 my $matching_record_ids_for_additional_fields = [];
531 if ( @
$additional_fields ) {
532 $matching_record_ids_for_additional_fields = Koha
::AdditionalField
->get_matching_record_ids({
533 fields
=> $additional_fields,
534 tablename
=> 'subscription',
537 return () unless @
$matching_record_ids_for_additional_fields;
542 subscription
.notes AS publicnotes
,
543 subscriptionhistory
.*,
545 biblio
.notes AS biblionotes
,
549 aqbooksellers
.name AS vendorname
,
552 LEFT JOIN subscriptionhistory USING
(subscriptionid
)
553 LEFT JOIN biblio ON biblio
.biblionumber
= subscription
.biblionumber
554 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= subscription
.biblionumber
555 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
557 $query .= q
| WHERE
1|;
560 if( $args->{biblionumber
} ) {
561 push @where_strs, "biblio.biblionumber = ?";
562 push @where_args, $args->{biblionumber
};
565 if( $args->{title
} ){
566 my @words = split / /, $args->{title
};
568 foreach my $word (@words) {
569 push @strs, "biblio.title LIKE ?";
570 push @args, "%$word%";
573 push @where_strs, '(' . join (' AND ', @strs) . ')';
574 push @where_args, @args;
578 push @where_strs, "biblioitems.issn LIKE ?";
579 push @where_args, "%$args->{issn}%";
582 push @where_strs, "biblioitems.ean LIKE ?";
583 push @where_args, "%$args->{ean}%";
585 if ( $args->{callnumber
} ) {
586 push @where_strs, "subscription.callnumber LIKE ?";
587 push @where_args, "%$args->{callnumber}%";
589 if( $args->{publisher
} ){
590 push @where_strs, "biblioitems.publishercode LIKE ?";
591 push @where_args, "%$args->{publisher}%";
593 if( $args->{bookseller
} ){
594 push @where_strs, "aqbooksellers.name LIKE ?";
595 push @where_args, "%$args->{bookseller}%";
597 if( $args->{branch
} ){
598 push @where_strs, "subscription.branchcode = ?";
599 push @where_args, "$args->{branch}";
601 if ( $args->{location
} ) {
602 push @where_strs, "subscription.location = ?";
603 push @where_args, "$args->{location}";
605 if ( $args->{expiration_date
} ) {
606 push @where_strs, "subscription.enddate <= ?";
607 push @where_args, "$args->{expiration_date}";
609 if( defined $args->{closed
} ){
610 push @where_strs, "subscription.closed = ?";
611 push @where_args, "$args->{closed}";
615 $query .= ' AND ' . join(' AND ', @where_strs);
617 if ( @
$additional_fields ) {
618 $query .= ' AND subscriptionid IN ('
619 . join( ', ', @
$matching_record_ids_for_additional_fields )
623 $query .= " ORDER BY " . $args->{orderby
} if $args->{orderby
};
625 my $dbh = C4
::Context
->dbh;
626 my $sth = $dbh->prepare($query);
627 $sth->execute(@where_args);
628 my $results = $sth->fetchall_arrayref( {} );
630 for my $subscription ( @
$results ) {
631 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
632 $subscription->{cannotdisplay
} = not can_show_subscription
( $subscription );
634 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
635 record_id
=> $subscription->{subscriptionid
},
636 tablename
=> 'subscription'
638 $subscription->{additional_fields
} = $additional_field_values->{$subscription->{subscriptionid
}};
647 ($totalissues,@serials) = GetSerials($subscriptionid);
648 this function gets every serial not arrived for a given subscription
649 as well as the number of issues registered in the database (all types)
650 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
652 FIXME: We should return \@serials.
657 my ( $subscriptionid, $count ) = @_;
659 return unless $subscriptionid;
661 my $dbh = C4
::Context
->dbh;
663 # status = 2 is "arrived"
665 $count = 5 unless ($count);
667 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
, NOT_ISSUED
) );
668 my $query = "SELECT serialid,serialseq, status, publisheddate,
669 publisheddatetext, planneddate,notes, routingnotes
671 WHERE subscriptionid = ? AND status NOT IN ( $statuses )
672 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
673 my $sth = $dbh->prepare($query);
674 $sth->execute($subscriptionid);
676 while ( my $line = $sth->fetchrow_hashref ) {
677 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
678 for my $datefield ( qw( planneddate publisheddate) ) {
679 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
680 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
682 $line->{$datefield} = q{};
685 push @serials, $line;
688 # OK, now add the last 5 issues arrives/missing
689 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,
690 publisheddatetext, notes, routingnotes
692 WHERE subscriptionid = ?
693 AND status IN ( $statuses )
694 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
696 $sth = $dbh->prepare($query);
697 $sth->execute($subscriptionid);
698 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
700 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
701 for my $datefield ( qw( planneddate publisheddate) ) {
702 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
703 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
705 $line->{$datefield} = q{};
709 push @serials, $line;
712 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
713 $sth = $dbh->prepare($query);
714 $sth->execute($subscriptionid);
715 my ($totalissues) = $sth->fetchrow;
716 return ( $totalissues, @serials );
721 @serials = GetSerials2($subscriptionid,$statuses);
722 this function returns every serial waited for a given subscription
723 as well as the number of issues registered in the database (all types)
724 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
726 $statuses is an arrayref of statuses and is mandatory.
731 my ( $subscription, $statuses ) = @_;
733 return unless ($subscription and @
$statuses);
735 my $dbh = C4
::Context
->dbh;
737 SELECT serialid
,serialseq
, status
, planneddate
, publisheddate
,
738 publisheddatetext
, notes
, routingnotes
740 WHERE subscriptionid
=?
742 . q
| AND status IN
(| . join( ",", ('?') x @
$statuses ) . q
|)|
744 ORDER BY publisheddate
,serialid DESC
746 $debug and warn "GetSerials2 query: $query";
747 my $sth = $dbh->prepare($query);
748 $sth->execute( $subscription, @
$statuses );
751 while ( my $line = $sth->fetchrow_hashref ) {
752 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
753 # Format dates for display
754 for my $datefield ( qw( planneddate publisheddate ) ) {
755 if (!defined($line->{$datefield}) || $line->{$datefield} =~m/^00/) {
756 $line->{$datefield} = q{};
759 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
762 push @serials, $line;
767 =head2 GetLatestSerials
769 \@serials = GetLatestSerials($subscriptionid,$limit)
770 get the $limit's latest serials arrived or missing for a given subscription
772 a ref to an array which contains all of the latest serials stored into a hash.
776 sub GetLatestSerials
{
777 my ( $subscriptionid, $limit ) = @_;
779 return unless ($subscriptionid and $limit);
781 my $dbh = C4
::Context
->dbh;
783 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
) );
784 my $strsth = "SELECT serialid,serialseq, status, planneddate, publisheddate, notes
786 WHERE subscriptionid = ?
787 AND status IN ($statuses)
788 ORDER BY publisheddate DESC LIMIT 0,$limit
790 my $sth = $dbh->prepare($strsth);
791 $sth->execute($subscriptionid);
793 while ( my $line = $sth->fetchrow_hashref ) {
794 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
795 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{planneddate
} ), dateonly
=> 1 } );
796 $line->{publisheddate
} = output_pref
( { dt
=> dt_from_string
( $line->{publisheddate
} ), dateonly
=> 1 } );
797 push @serials, $line;
803 =head2 GetPreviousSerialid
805 $serialid = GetPreviousSerialid($subscriptionid, $nth)
806 get the $nth's previous serial for the given subscriptionid
812 sub GetPreviousSerialid
{
813 my ( $subscriptionid, $nth ) = @_;
815 my $dbh = C4
::Context
->dbh;
819 my $strsth = "SELECT serialid
821 WHERE subscriptionid = ?
823 ORDER BY serialid DESC LIMIT $nth,1
825 my $sth = $dbh->prepare($strsth);
826 $sth->execute($subscriptionid);
828 my $line = $sth->fetchrow_hashref;
829 $return = $line->{'serialid'} if ($line);
837 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
838 $newinnerloop1, $newinnerloop2, $newinnerloop3
839 ) = GetNextSeq( $subscription, $pattern, $frequency, $planneddate );
841 $subscription is a hashref containing all the attributes of the table
843 $pattern is a hashref containing all the attributes of the table
844 'subscription_numberpatterns'.
845 $frequency is a hashref containing all the attributes of the table 'subscription_frequencies'
846 $planneddate is a date string in iso format.
847 This function get the next issue for the subscription given on input arg
852 my ($subscription, $pattern, $frequency, $planneddate) = @_;
854 return unless ($subscription and $pattern);
856 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
857 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
860 if ($subscription->{'skip_serialseq'}) {
861 my @irreg = split /;/, $subscription->{'irregularity'};
863 my $irregularities = {};
864 $irregularities->{$_} = 1 foreach(@irreg);
865 my $issueno = GetFictiveIssueNumber
($subscription, $planneddate, $frequency) + 1;
866 while($irregularities->{$issueno}) {
873 my $numberingmethod = $pattern->{numberingmethod
};
875 if ($numberingmethod) {
876 $calculated = $numberingmethod;
877 my $locale = $subscription->{locale
};
878 $newlastvalue1 = $subscription->{lastvalue1
} || 0;
879 $newlastvalue2 = $subscription->{lastvalue2
} || 0;
880 $newlastvalue3 = $subscription->{lastvalue3
} || 0;
881 $newinnerloop1 = $subscription->{innerloop1
} || 0;
882 $newinnerloop2 = $subscription->{innerloop2
} || 0;
883 $newinnerloop3 = $subscription->{innerloop3
} || 0;
886 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
889 for(my $i = 0; $i < $count; $i++) {
891 # check if we have to increase the new value.
893 if ($newinnerloop1 >= $pattern->{every1
}) {
895 $newlastvalue1 += $pattern->{add1
};
897 # reset counter if needed.
898 $newlastvalue1 = $pattern->{setto1
} if ($newlastvalue1 > $pattern->{whenmorethan1
});
901 # check if we have to increase the new value.
903 if ($newinnerloop2 >= $pattern->{every2
}) {
905 $newlastvalue2 += $pattern->{add2
};
907 # reset counter if needed.
908 $newlastvalue2 = $pattern->{setto2
} if ($newlastvalue2 > $pattern->{whenmorethan2
});
911 # check if we have to increase the new value.
913 if ($newinnerloop3 >= $pattern->{every3
}) {
915 $newlastvalue3 += $pattern->{add3
};
917 # reset counter if needed.
918 $newlastvalue3 = $pattern->{setto3
} if ($newlastvalue3 > $pattern->{whenmorethan3
});
922 my $newlastvalue1string = _numeration
( $newlastvalue1, $pattern->{numbering1
}, $locale );
923 $calculated =~ s/\{X\}/$newlastvalue1string/g;
926 my $newlastvalue2string = _numeration
( $newlastvalue2, $pattern->{numbering2
}, $locale );
927 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
930 my $newlastvalue3string = _numeration
( $newlastvalue3, $pattern->{numbering3
}, $locale );
931 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
936 $newlastvalue1, $newlastvalue2, $newlastvalue3,
937 $newinnerloop1, $newinnerloop2, $newinnerloop3);
942 $calculated = GetSeq($subscription, $pattern)
943 $subscription is a hashref containing all the attributes of the table 'subscription'
944 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
945 this function transforms {X},{Y},{Z} to 150,0,0 for example.
947 the sequence in string format
952 my ($subscription, $pattern) = @_;
954 return unless ($subscription and $pattern);
956 my $locale = $subscription->{locale
};
958 my $calculated = $pattern->{numberingmethod
};
960 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
961 $newlastvalue1 = _numeration
($newlastvalue1, $pattern->{numbering1
}, $locale) if ($pattern->{numbering1
}); # reset counter if needed.
962 $calculated =~ s/\{X\}/$newlastvalue1/g;
964 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
965 $newlastvalue2 = _numeration
($newlastvalue2, $pattern->{numbering2
}, $locale) if ($pattern->{numbering2
}); # reset counter if needed.
966 $calculated =~ s/\{Y\}/$newlastvalue2/g;
968 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
969 $newlastvalue3 = _numeration
($newlastvalue3, $pattern->{numbering3
}, $locale) if ($pattern->{numbering3
}); # reset counter if needed.
970 $calculated =~ s/\{Z\}/$newlastvalue3/g;
974 =head2 GetExpirationDate
976 $enddate = GetExpirationDate($subscriptionid, [$startdate])
978 this function return the next expiration date for a subscription given on input args.
985 sub GetExpirationDate
{
986 my ( $subscriptionid, $startdate ) = @_;
988 return unless ($subscriptionid);
990 my $dbh = C4
::Context
->dbh;
991 my $subscription = GetSubscription
($subscriptionid);
994 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
995 $enddate = $startdate || $subscription->{startdate
};
996 my @date = split( /-/, $enddate );
998 return if ( scalar(@date) != 3 || not check_date
(@date) );
1000 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1001 if ( $frequency and $frequency->{unit
} ) {
1004 if ( my $length = $subscription->{numberlength
} ) {
1006 #calculate the date of the last issue.
1007 for ( my $i = 1 ; $i <= $length ; $i++ ) {
1008 $enddate = GetNextDate
( $subscription, $enddate, $frequency );
1010 } elsif ( $subscription->{monthlength
} ) {
1011 if ( $$subscription{startdate
} ) {
1012 my @enddate = Add_Delta_YM
( $date[0], $date[1], $date[2], 0, $subscription->{monthlength
} );
1013 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1015 } elsif ( $subscription->{weeklength
} ) {
1016 if ( $$subscription{startdate
} ) {
1017 my @date = split( /-/, $subscription->{startdate
} );
1018 my @enddate = Add_Delta_Days
( $date[0], $date[1], $date[2], $subscription->{weeklength
} * 7 );
1019 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1022 $enddate = $subscription->{enddate
};
1026 return $subscription->{enddate
};
1030 =head2 CountSubscriptionFromBiblionumber
1032 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1033 this returns a count of the subscriptions for a given biblionumber
1035 the number of subscriptions
1039 sub CountSubscriptionFromBiblionumber
{
1040 my ($biblionumber) = @_;
1042 return unless ($biblionumber);
1044 my $dbh = C4
::Context
->dbh;
1045 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1046 my $sth = $dbh->prepare($query);
1047 $sth->execute($biblionumber);
1048 my $subscriptionsnumber = $sth->fetchrow;
1049 return $subscriptionsnumber;
1052 =head2 ModSubscriptionHistory
1054 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1056 this function modifies the history of a subscription. Put your new values on input arg.
1057 returns the number of rows affected
1061 sub ModSubscriptionHistory
{
1062 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1064 return unless ($subscriptionid);
1066 my $dbh = C4
::Context
->dbh;
1067 my $query = "UPDATE subscriptionhistory
1068 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1069 WHERE subscriptionid=?
1071 my $sth = $dbh->prepare($query);
1072 $receivedlist =~ s/^; // if $receivedlist;
1073 $missinglist =~ s/^; // if $missinglist;
1074 $opacnote =~ s/^; // if $opacnote;
1075 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1079 =head2 ModSerialStatus
1081 ModSerialStatus($serialid, $serialseq, $planneddate, $publisheddate,
1082 $publisheddatetext, $status, $notes);
1084 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1085 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1089 sub ModSerialStatus
{
1090 my ($serialid, $serialseq, $planneddate, $publisheddate, $publisheddatetext,
1091 $status, $notes) = @_;
1093 return unless ($serialid);
1095 #It is a usual serial
1096 # 1st, get previous status :
1097 my $dbh = C4
::Context
->dbh;
1098 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
1099 FROM serial, subscription
1100 WHERE serial.subscriptionid=subscription.subscriptionid
1102 my $sth = $dbh->prepare($query);
1103 $sth->execute($serialid);
1104 my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
1105 my $frequency = GetSubscriptionFrequency
($periodicity);
1107 # change status & update subscriptionhistory
1109 if ( $status == DELETED
) {
1110 DelIssue
( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1115 SET serialseq = ?, publisheddate = ?, publisheddatetext = ?,
1116 planneddate = ?, status = ?, notes = ?
1119 $sth = $dbh->prepare($query);
1120 $sth->execute( $serialseq, $publisheddate, $publisheddatetext,
1121 $planneddate, $status, $notes, $serialid );
1122 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1123 $sth = $dbh->prepare($query);
1124 $sth->execute($subscriptionid);
1125 my $val = $sth->fetchrow_hashref;
1126 unless ( $val->{manualhistory
} ) {
1127 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1128 $sth = $dbh->prepare($query);
1129 $sth->execute($subscriptionid);
1130 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1132 if ( $status == ARRIVED
|| ($oldstatus == ARRIVED
&& $status != ARRIVED
) ) {
1133 $recievedlist .= "; $serialseq"
1134 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1137 # in case serial has been previously marked as missing
1138 if (grep /$status/, (EXPECTED
, ARRIVED
, LATE
, CLAIMED
)) {
1139 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1142 $missinglist .= "; $serialseq"
1143 if ( ( grep { $_ == $status } ( MISSING_STATUSES
) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1144 $missinglist .= "; not issued $serialseq"
1145 if ( $status == NOT_ISSUED
&& $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1147 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1148 $sth = $dbh->prepare($query);
1149 $recievedlist =~ s/^; //;
1150 $missinglist =~ s/^; //;
1151 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1155 # create new expected entry if needed (ie : was "expected" and has changed)
1156 my $otherIssueExpected = scalar findSerialsByStatus
(EXPECTED
, $subscriptionid);
1157 if ( !$otherIssueExpected && $oldstatus == EXPECTED
&& $status != EXPECTED
) {
1158 my $subscription = GetSubscription
($subscriptionid);
1159 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1160 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1164 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1165 $newinnerloop1, $newinnerloop2, $newinnerloop3
1167 = GetNextSeq
( $subscription, $pattern, $frequency, $publisheddate );
1169 # next date (calculated from actual date & frequency parameters)
1170 my $nextpublisheddate = GetNextDate
($subscription, $publisheddate, $frequency, 1);
1171 my $nextpubdate = $nextpublisheddate;
1172 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1173 WHERE subscriptionid = ?";
1174 $sth = $dbh->prepare($query);
1175 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1177 NewIssue
( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
1179 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1180 if ( $subscription->{letter
} && $status == ARRIVED
&& $oldstatus != ARRIVED
) {
1181 require C4
::Letters
;
1182 C4
::Letters
::SendAlerts
( 'issue', $serialid, $subscription->{letter
} );
1189 =head2 GetNextExpected
1191 $nextexpected = GetNextExpected($subscriptionid)
1193 Get the planneddate for the current expected issue of the subscription.
1199 planneddate => ISO date
1204 sub GetNextExpected
{
1205 my ($subscriptionid) = @_;
1207 my $dbh = C4
::Context
->dbh;
1211 WHERE subscriptionid
= ?
1215 my $sth = $dbh->prepare($query);
1217 # Each subscription has only one 'expected' issue.
1218 $sth->execute( $subscriptionid, EXPECTED
);
1219 my $nextissue = $sth->fetchrow_hashref;
1220 if ( !$nextissue ) {
1224 WHERE subscriptionid
= ?
1225 ORDER BY publisheddate DESC
1228 $sth = $dbh->prepare($query);
1229 $sth->execute($subscriptionid);
1230 $nextissue = $sth->fetchrow_hashref;
1232 foreach(qw
/planneddate publisheddate/) {
1233 if ( !defined $nextissue->{$_} ) {
1234 # or should this default to 1st Jan ???
1235 $nextissue->{$_} = strftime
( '%Y-%m-%d', localtime );
1237 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1245 =head2 ModNextExpected
1247 ModNextExpected($subscriptionid,$date)
1249 Update the planneddate for the current expected issue of the subscription.
1250 This will modify all future prediction results.
1252 C<$date> is an ISO date.
1258 sub ModNextExpected
{
1259 my ( $subscriptionid, $date ) = @_;
1260 my $dbh = C4
::Context
->dbh;
1262 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1263 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1265 # Each subscription has only one 'expected' issue.
1266 $sth->execute( $date, $date, $subscriptionid, EXPECTED
);
1271 =head2 GetSubscriptionIrregularities
1275 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1276 get the list of irregularities for a subscription
1282 sub GetSubscriptionIrregularities
{
1283 my $subscriptionid = shift;
1285 return unless $subscriptionid;
1287 my $dbh = C4
::Context
->dbh;
1291 WHERE subscriptionid
= ?
1293 my $sth = $dbh->prepare($query);
1294 $sth->execute($subscriptionid);
1296 my ($result) = $sth->fetchrow_array;
1297 my @irreg = split /;/, $result;
1302 =head2 ModSubscription
1304 this function modifies a subscription. Put all new values on input args.
1305 returns the number of rows affected
1309 sub ModSubscription
{
1311 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1312 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1313 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1314 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1315 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1316 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1317 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq,
1318 $itemtype, $previousitemtype
1321 my $dbh = C4
::Context
->dbh;
1322 my $query = "UPDATE subscription
1323 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1324 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1325 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1326 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1327 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1328 callnumber=?, notes=?, letter=?, manualhistory=?,
1329 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1330 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1331 skip_serialseq=?, itemtype=?, previousitemtype=?
1332 WHERE subscriptionid = ?";
1334 my $sth = $dbh->prepare($query);
1336 $auser, $branchcode, $aqbooksellerid, $cost,
1337 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1338 $irregularity, $numberpattern, $locale, $numberlength,
1339 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1340 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1341 $status, $biblionumber, $callnumber, $notes,
1342 $letter, ($manualhistory ?
$manualhistory : 0),
1343 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1344 $graceperiod, $location, $enddate, $skip_serialseq,
1345 $itemtype, $previousitemtype,
1348 my $rows = $sth->rows;
1350 logaction
( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1354 =head2 NewSubscription
1356 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1357 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1358 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1359 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1360 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1361 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
1362 $skip_serialseq, $itemtype, $previousitemtype);
1364 Create a new subscription with value given on input args.
1367 the id of this new subscription
1371 sub NewSubscription
{
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, $itemtype, $previousitemtype, $mana_id
1381 my $dbh = C4
::Context
->dbh;
1383 #save subscription (insert into database)
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 itemtype
, previousitemtype
, mana_id
)
1394 VALUES
(?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
, ?
)
1396 my $sth = $dbh->prepare($query);
1398 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1399 $startdate, $periodicity, $numberlength, $weeklength,
1400 $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
1401 $lastvalue3, $innerloop3, $status, $notes, $letter,
1402 $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
1403 $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
1404 $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq,
1405 $itemtype, $previousitemtype, $mana_id
1408 my $subscriptionid = $dbh->{'mysql_insertid'};
1410 $enddate = GetExpirationDate
( $subscriptionid, $startdate );
1414 WHERE subscriptionid
=?
1416 $sth = $dbh->prepare($query);
1417 $sth->execute( $enddate, $subscriptionid );
1420 # then create the 1st expected number
1422 INSERT INTO subscriptionhistory
1423 (biblionumber
, subscriptionid
, histstartdate
, missinglist
, recievedlist
)
1424 VALUES
(?
,?
,?
, '', '')
1426 $sth = $dbh->prepare($query);
1427 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1429 # reread subscription to get a hash (for calculation of the 1st issue number)
1430 my $subscription = GetSubscription
($subscriptionid);
1431 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1433 # calculate issue number
1434 my $serialseq = GetSeq
($subscription, $pattern) || q{};
1438 serialseq
=> $serialseq,
1439 serialseq_x
=> $subscription->{'lastvalue1'},
1440 serialseq_y
=> $subscription->{'lastvalue2'},
1441 serialseq_z
=> $subscription->{'lastvalue3'},
1442 subscriptionid
=> $subscriptionid,
1443 biblionumber
=> $biblionumber,
1445 planneddate
=> $firstacquidate,
1446 publisheddate
=> $firstacquidate,
1450 logaction
( "SERIAL", "ADD", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1452 #set serial flag on biblio if not already set.
1453 my $biblio = Koha
::Biblios
->find( $biblionumber );
1454 if ( $biblio and !$biblio->serial ) {
1455 my $record = GetMarcBiblio
({ biblionumber
=> $biblionumber });
1456 my ( $tag, $subf ) = GetMarcFromKohaField
( 'biblio.serial', $biblio->frameworkcode );
1458 eval { $record->field($tag)->update( $subf => 1 ); };
1460 ModBiblio
( $record, $biblionumber, $biblio->frameworkcode );
1462 return $subscriptionid;
1465 =head2 ReNewSubscription
1467 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1469 this function renew a subscription with values given on input args.
1473 sub ReNewSubscription
{
1474 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1475 my $dbh = C4
::Context
->dbh;
1476 my $subscription = GetSubscription
($subscriptionid);
1480 LEFT JOIN biblioitems ON biblio
.biblionumber
=biblioitems
.biblionumber
1481 WHERE biblio
.biblionumber
=?
1483 my $sth = $dbh->prepare($query);
1484 $sth->execute( $subscription->{biblionumber
} );
1485 my $biblio = $sth->fetchrow_hashref;
1487 if ( C4
::Context
->preference("RenewSerialAddsSuggestion") ) {
1488 require C4
::Suggestions
;
1489 C4
::Suggestions
::NewSuggestion
(
1490 { 'suggestedby' => $user,
1491 'title' => $subscription->{bibliotitle
},
1492 'author' => $biblio->{author
},
1493 'publishercode' => $biblio->{publishercode
},
1494 'note' => $biblio->{note
},
1495 'biblionumber' => $subscription->{biblionumber
}
1500 $numberlength ||= 0; # Should not we raise an exception instead?
1503 # renew subscription
1506 SET startdate
=?
,numberlength
=?
,weeklength
=?
,monthlength
=?
,reneweddate
=NOW
()
1507 WHERE subscriptionid
=?
1509 $sth = $dbh->prepare($query);
1510 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1511 my $enddate = GetExpirationDate
($subscriptionid);
1512 $debug && warn "enddate :$enddate";
1516 WHERE subscriptionid
=?
1518 $sth = $dbh->prepare($query);
1519 $sth->execute( $enddate, $subscriptionid );
1521 logaction
( "SERIAL", "RENEW", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1527 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1529 Create a new issue stored on the database.
1530 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1531 returns the serial id
1536 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate,
1537 $publisheddate, $publisheddatetext, $notes ) = @_;
1538 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1540 return unless ($subscriptionid);
1542 my $schema = Koha
::Database
->new()->schema();
1544 my $subscription = Koha
::Subscriptions
->find( $subscriptionid );
1546 my $serial = Koha
::Serial
->new(
1548 serialseq
=> $serialseq,
1549 serialseq_x
=> $subscription->lastvalue1(),
1550 serialseq_y
=> $subscription->lastvalue2(),
1551 serialseq_z
=> $subscription->lastvalue3(),
1552 subscriptionid
=> $subscriptionid,
1553 biblionumber
=> $biblionumber,
1555 planneddate
=> $planneddate,
1556 publisheddate
=> $publisheddate,
1557 publisheddatetext
=> $publisheddatetext,
1562 my $serialid = $serial->id();
1564 my $subscription_history = Koha
::Subscription
::Histories
->find($subscriptionid);
1565 my $missinglist = $subscription_history->missinglist();
1566 my $recievedlist = $subscription_history->recievedlist();
1568 if ( $status == ARRIVED
) {
1569 ### TODO Add a feature that improves recognition and description.
1570 ### As such count (serialseq) i.e. : N18,2(N19),N20
1571 ### Would use substr and index But be careful to previous presence of ()
1572 $recievedlist .= "; $serialseq" unless ( index( $recievedlist, $serialseq ) > 0 );
1574 if ( grep { /^$status$/ } (MISSING_STATUSES
) ) {
1575 $missinglist .= "; $serialseq" unless ( index( $missinglist, $serialseq ) > 0 );
1578 $recievedlist =~ s/^; //;
1579 $missinglist =~ s/^; //;
1581 $subscription_history->recievedlist($recievedlist);
1582 $subscription_history->missinglist($missinglist);
1583 $subscription_history->store();
1588 =head2 HasSubscriptionStrictlyExpired
1590 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1592 the subscription has stricly expired when today > the end subscription date
1595 1 if true, 0 if false, -1 if the expiration date is not set.
1599 sub HasSubscriptionStrictlyExpired
{
1601 # Getting end of subscription date
1602 my ($subscriptionid) = @_;
1604 return unless ($subscriptionid);
1606 my $dbh = C4
::Context
->dbh;
1607 my $subscription = GetSubscription
($subscriptionid);
1608 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1610 # If the expiration date is set
1611 if ( $expirationdate != 0 ) {
1612 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1614 # Getting today's date
1615 my ( $nowyear, $nowmonth, $nowday ) = Today
();
1617 # if today's date > expiration date, then the subscription has stricly expired
1618 if ( Delta_Days
( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1625 # There are some cases where the expiration date is not set
1626 # As we can't determine if the subscription has expired on a date-basis,
1632 =head2 HasSubscriptionExpired
1634 $has_expired = HasSubscriptionExpired($subscriptionid)
1636 the subscription has expired when the next issue to arrive is out of subscription limit.
1639 0 if the subscription has not expired
1640 1 if the subscription has expired
1641 2 if has subscription does not have a valid expiration date set
1645 sub HasSubscriptionExpired
{
1646 my ($subscriptionid) = @_;
1648 return unless ($subscriptionid);
1650 my $dbh = C4
::Context
->dbh;
1651 my $subscription = GetSubscription
($subscriptionid);
1652 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1653 if ( $frequency and $frequency->{unit
} ) {
1654 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1655 if (!defined $expirationdate) {
1656 $expirationdate = q{};
1659 SELECT max
(planneddate
)
1661 WHERE subscriptionid
=?
1663 my $sth = $dbh->prepare($query);
1664 $sth->execute($subscriptionid);
1665 my ($res) = $sth->fetchrow;
1666 if (!$res || $res=~m/^0000/) {
1669 my @res = split( /-/, $res );
1670 my @endofsubscriptiondate = split( /-/, $expirationdate );
1671 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date
(@res) || not check_date
(@endofsubscriptiondate) );
1673 if ( ( @endofsubscriptiondate && Delta_Days
( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1678 if ( $subscription->{'numberlength'} ) {
1679 my $countreceived = countissuesfrom
( $subscriptionid, $subscription->{'startdate'} );
1680 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1686 return 0; # Notice that you'll never get here.
1689 =head2 DelSubscription
1691 DelSubscription($subscriptionid)
1692 this function deletes subscription which has $subscriptionid as id.
1696 sub DelSubscription
{
1697 my ($subscriptionid) = @_;
1698 my $dbh = C4
::Context
->dbh;
1699 $dbh->do("DELETE FROM subscription WHERE subscriptionid=?", undef, $subscriptionid);
1700 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=?", undef, $subscriptionid);
1701 $dbh->do("DELETE FROM serial WHERE subscriptionid=?", undef, $subscriptionid);
1703 my $afs = Koha
::AdditionalField
->all({tablename
=> 'subscription'});
1704 foreach my $af (@
$afs) {
1705 $af->delete_values({record_id
=> $subscriptionid});
1708 logaction
( "SERIAL", "DELETE", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1713 DelIssue($serialseq,$subscriptionid)
1714 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1716 returns the number of rows affected
1721 my ($dataissue) = @_;
1722 my $dbh = C4
::Context
->dbh;
1723 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1728 AND subscriptionid
= ?
1730 my $mainsth = $dbh->prepare($query);
1731 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1733 #Delete element from subscription history
1734 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1735 my $sth = $dbh->prepare($query);
1736 $sth->execute( $dataissue->{'subscriptionid'} );
1737 my $val = $sth->fetchrow_hashref;
1738 unless ( $val->{manualhistory
} ) {
1740 SELECT
* FROM subscriptionhistory
1741 WHERE subscriptionid
= ?
1743 my $sth = $dbh->prepare($query);
1744 $sth->execute( $dataissue->{'subscriptionid'} );
1745 my $data = $sth->fetchrow_hashref;
1746 my $serialseq = $dataissue->{'serialseq'};
1747 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1748 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1749 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1750 $sth = $dbh->prepare($strsth);
1751 $sth->execute( $dataissue->{'subscriptionid'} );
1754 return $mainsth->rows;
1757 =head2 GetLateOrMissingIssues
1759 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1761 this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
1764 the issuelist as an array of hash refs. Each element of this array contains
1765 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1769 sub GetLateOrMissingIssues
{
1770 my ( $supplierid, $serialid, $order ) = @_;
1772 return unless ( $supplierid or $serialid );
1774 my $dbh = C4
::Context
->dbh;
1779 $byserial = "and serialid = " . $serialid;
1782 $order .= ", title";
1786 my $missing_statuses_string = join ',', (MISSING_STATUSES
);
1788 $sth = $dbh->prepare(
1790 serialid, aqbooksellerid, name,
1791 biblio.title, biblioitems.issn, planneddate, serialseq,
1792 serial.status, serial.subscriptionid, claimdate, claims_count,
1793 subscription.branchcode
1795 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1796 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1797 LEFT JOIN biblioitems ON subscription.biblionumber=biblioitems.biblionumber
1798 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1799 WHERE subscription.subscriptionid = serial.subscriptionid
1800 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1801 AND subscription.aqbooksellerid=$supplierid
1806 $sth = $dbh->prepare(
1808 serialid, aqbooksellerid, name,
1809 biblio.title, planneddate, serialseq,
1810 serial.status, serial.subscriptionid, claimdate, claims_count,
1811 subscription.branchcode
1813 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1814 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1815 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1816 WHERE subscription.subscriptionid = serial.subscriptionid
1817 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1822 $sth->execute( EXPECTED
, LATE
, CLAIMED
);
1824 while ( my $line = $sth->fetchrow_hashref ) {
1826 if ($line->{planneddate
} && $line->{planneddate
} !~/^0+\-/) {
1827 $line->{planneddateISO
} = $line->{planneddate
};
1828 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{"planneddate"} ), dateonly
=> 1 } );
1830 if ($line->{claimdate
} && $line->{claimdate
} !~/^0+\-/) {
1831 $line->{claimdateISO
} = $line->{claimdate
};
1832 $line->{claimdate
} = output_pref
( { dt
=> dt_from_string
( $line->{"claimdate"} ), dateonly
=> 1 } );
1834 $line->{"status".$line->{status
}} = 1;
1836 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
1837 record_id
=> $line->{subscriptionid
},
1838 tablename
=> 'subscription'
1840 %$line = ( %$line, additional_fields
=> $additional_field_values->{$line->{subscriptionid
}} );
1842 push @issuelist, $line;
1849 &updateClaim($serialid)
1851 this function updates the time when a claim is issued for late/missing items
1853 called from claims.pl file
1858 my ($serialids) = @_;
1859 return unless $serialids;
1860 unless ( ref $serialids ) {
1861 $serialids = [ $serialids ];
1863 my $dbh = C4
::Context
->dbh;
1866 SET claimdate
= NOW
(),
1867 claims_count
= claims_count
+ 1,
1869 WHERE serialid
in (| . join( q
|,|, (q
|?
|) x @
$serialids ) . q
|)|,
1870 {}, CLAIMED
, @
$serialids );
1873 =head2 check_routing
1875 $result = &check_routing($subscriptionid)
1877 this function checks to see if a serial has a routing list and returns the count of routingid
1878 used to show either an 'add' or 'edit' link
1883 my ($subscriptionid) = @_;
1885 return unless ($subscriptionid);
1887 my $dbh = C4
::Context
->dbh;
1888 my $sth = $dbh->prepare(
1889 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1890 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1891 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
1894 $sth->execute($subscriptionid);
1895 my $line = $sth->fetchrow_hashref;
1896 my $result = $line->{'routingids'};
1900 =head2 addroutingmember
1902 addroutingmember($borrowernumber,$subscriptionid)
1904 this function takes a borrowernumber and subscriptionid and adds the member to the
1905 routing list for that serial subscription and gives them a rank on the list
1906 of either 1 or highest current rank + 1
1910 sub addroutingmember
{
1911 my ( $borrowernumber, $subscriptionid ) = @_;
1913 return unless ($borrowernumber and $subscriptionid);
1916 my $dbh = C4
::Context
->dbh;
1917 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1918 $sth->execute($subscriptionid);
1919 while ( my $line = $sth->fetchrow_hashref ) {
1920 if ( $line->{'rank'} > 0 ) {
1921 $rank = $line->{'rank'} + 1;
1926 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1927 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1930 =head2 reorder_members
1932 reorder_members($subscriptionid,$routingid,$rank)
1934 this function is used to reorder the routing list
1936 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1937 - it gets all members on list puts their routingid's into an array
1938 - removes the one in the array that is $routingid
1939 - then reinjects $routingid at point indicated by $rank
1940 - then update the database with the routingids in the new order
1944 sub reorder_members
{
1945 my ( $subscriptionid, $routingid, $rank ) = @_;
1946 my $dbh = C4
::Context
->dbh;
1947 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1948 $sth->execute($subscriptionid);
1950 while ( my $line = $sth->fetchrow_hashref ) {
1951 push( @result, $line->{'routingid'} );
1954 # To find the matching index
1956 my $key = -1; # to allow for 0 being a valid response
1957 for ( $i = 0 ; $i < @result ; $i++ ) {
1958 if ( $routingid == $result[$i] ) {
1959 $key = $i; # save the index
1964 # if index exists in array then move it to new position
1965 if ( $key > -1 && $rank > 0 ) {
1966 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1967 my $moving_item = splice( @result, $key, 1 );
1968 splice( @result, $new_rank, 0, $moving_item );
1970 for ( my $j = 0 ; $j < @result ; $j++ ) {
1971 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1977 =head2 delroutingmember
1979 delroutingmember($routingid,$subscriptionid)
1981 this function either deletes one member from routing list if $routingid exists otherwise
1982 deletes all members from the routing list
1986 sub delroutingmember
{
1988 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
1989 my ( $routingid, $subscriptionid ) = @_;
1990 my $dbh = C4
::Context
->dbh;
1992 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
1993 $sth->execute($routingid);
1994 reorder_members
( $subscriptionid, $routingid );
1996 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
1997 $sth->execute($subscriptionid);
2002 =head2 getroutinglist
2004 @routinglist = getroutinglist($subscriptionid)
2006 this gets the info from the subscriptionroutinglist for $subscriptionid
2009 the routinglist as an array. Each element of the array contains a hash_ref containing
2010 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2014 sub getroutinglist
{
2015 my ($subscriptionid) = @_;
2016 my $dbh = C4
::Context
->dbh;
2017 my $sth = $dbh->prepare(
2018 'SELECT routingid, borrowernumber, ranking, biblionumber
2020 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2021 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2023 $sth->execute($subscriptionid);
2024 my $routinglist = $sth->fetchall_arrayref({});
2025 return @
{$routinglist};
2028 =head2 countissuesfrom
2030 $result = countissuesfrom($subscriptionid,$startdate)
2032 Returns a count of serial rows matching the given subsctiptionid
2033 with published date greater than startdate
2037 sub countissuesfrom
{
2038 my ( $subscriptionid, $startdate ) = @_;
2039 my $dbh = C4
::Context
->dbh;
2043 WHERE subscriptionid
=?
2044 AND serial
.publisheddate
>?
2046 my $sth = $dbh->prepare($query);
2047 $sth->execute( $subscriptionid, $startdate );
2048 my ($countreceived) = $sth->fetchrow;
2049 return $countreceived;
2054 $result = CountIssues($subscriptionid)
2056 Returns a count of serial rows matching the given subsctiptionid
2061 my ($subscriptionid) = @_;
2062 my $dbh = C4
::Context
->dbh;
2066 WHERE subscriptionid
=?
2068 my $sth = $dbh->prepare($query);
2069 $sth->execute($subscriptionid);
2070 my ($countreceived) = $sth->fetchrow;
2071 return $countreceived;
2076 $result = HasItems($subscriptionid)
2078 returns a count of items from serial matching the subscriptionid
2083 my ($subscriptionid) = @_;
2084 my $dbh = C4
::Context
->dbh;
2086 SELECT COUNT
(serialitems
.itemnumber
)
2088 LEFT JOIN serialitems USING
(serialid
)
2089 WHERE subscriptionid
=? AND serialitems
.serialid IS NOT NULL
2091 my $sth=$dbh->prepare($query);
2092 $sth->execute($subscriptionid);
2093 my ($countitems)=$sth->fetchrow_array();
2097 =head2 abouttoexpire
2099 $result = abouttoexpire($subscriptionid)
2101 this function alerts you to the penultimate issue for a serial subscription
2103 returns 1 - if this is the penultimate issue
2109 my ($subscriptionid) = @_;
2110 my $dbh = C4
::Context
->dbh;
2111 my $subscription = GetSubscription
($subscriptionid);
2112 my $per = $subscription->{'periodicity'};
2113 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($per);
2114 if ($frequency and $frequency->{unit
}){
2116 my $expirationdate = GetExpirationDate
($subscriptionid);
2118 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2119 my $nextdate = GetNextDate
($subscription, $res, $frequency);
2121 # only compare dates if both dates exist.
2122 if ($nextdate and $expirationdate) {
2123 if(Date
::Calc
::Delta_Days
(
2124 split( /-/, $nextdate ),
2125 split( /-/, $expirationdate )
2131 } elsif ($subscription->{numberlength
}>0) {
2132 return (countissuesfrom
($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength
}-1);
2138 =head2 GetFictiveIssueNumber
2140 $issueno = GetFictiveIssueNumber($subscription, $publishedate, $frequency);
2142 Get the position of the issue published at $publisheddate, considering the
2143 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2144 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2145 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2146 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2147 depending on how many rows are in serial table.
2148 The issue number calculation is based on subscription frequency, first acquisition
2149 date, and $publisheddate.
2151 Returns undef when called for irregular frequencies.
2153 The routine is used to skip irregularities when calculating the next issue
2154 date (in GetNextDate) or the next issue number (in GetNextSeq).
2158 sub GetFictiveIssueNumber
{
2159 my ($subscription, $publisheddate, $frequency) = @_;
2161 my $unit = $frequency->{unit
} ?
lc $frequency->{'unit'} : undef;
2165 my ( $year, $month, $day ) = split /-/, $publisheddate;
2166 my ( $fa_year, $fa_month, $fa_day ) = split /-/, $subscription->{'firstacquidate'};
2167 my $delta = _delta_units
( [$fa_year, $fa_month, $fa_day], [$year, $month, $day], $unit );
2169 if( $frequency->{'unitsperissue'} == 1 ) {
2170 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2171 } else { # issuesperunit == 1
2172 $issueno = 1 + int( $delta / $frequency->{'unitsperissue'} );
2178 my ( $date1, $date2, $unit ) = @_;
2179 # date1 and date2 are array refs in the form [ yy, mm, dd ]
2181 if( $unit eq 'day' ) {
2182 return Delta_Days
( @
$date1, @
$date2 );
2183 } elsif( $unit eq 'week' ) {
2184 return int( Delta_Days
( @
$date1, @
$date2 ) / 7 );
2187 # In case of months or years, this is a wrapper around N_Delta_YMD.
2188 # Note that N_Delta_YMD returns 29 days between e.g. 22-2-72 and 22-3-72
2189 # while we expect 1 month.
2190 my @delta = N_Delta_YMD
( @
$date1, @
$date2 );
2191 if( $delta[2] > 27 ) {
2192 # Check if we could add a month
2193 my @jump = Add_Delta_YM
( @
$date1, $delta[0], 1 + $delta[1] );
2194 if( Delta_Days
( @jump, @
$date2 ) >= 0 ) {
2198 if( $delta[1] >= 12 ) {
2202 # if unit is year, we only return full years
2203 return $unit eq 'month' ?
$delta[0] * 12 + $delta[1] : $delta[0];
2206 sub _get_next_date_day
{
2207 my ($subscription, $freqdata, $year, $month, $day) = @_;
2209 my @newissue; # ( yy, mm, dd )
2210 # We do not need $delta_days here, since it would be zero where used
2212 if( $freqdata->{issuesperunit
} == 1 ) {
2214 @newissue = Add_Delta_Days
(
2215 $year, $month, $day, $freqdata->{"unitsperissue"} );
2216 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2218 @newissue = ( $year, $month, $day );
2219 $subscription->{countissuesperunit
}++;
2221 # We finished a cycle of issues within a unit.
2222 # No subtraction of zero needed, just add one day
2223 @newissue = Add_Delta_Days
( $year, $month, $day, 1 );
2224 $subscription->{countissuesperunit
} = 1;
2229 sub _get_next_date_week
{
2230 my ($subscription, $freqdata, $year, $month, $day) = @_;
2232 my @newissue; # ( yy, mm, dd )
2233 my $delta_days = int( 7 / $freqdata->{issuesperunit
} );
2235 if( $freqdata->{issuesperunit
} == 1 ) {
2236 # Add full weeks (of 7 days)
2237 @newissue = Add_Delta_Days
(
2238 $year, $month, $day, 7 * $freqdata->{"unitsperissue"} );
2239 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2240 # Add rounded number of days based on frequency.
2241 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2242 $subscription->{countissuesperunit
}++;
2244 # We finished a cycle of issues within a unit.
2245 # Subtract delta * (issues - 1), add 1 week
2246 @newissue = Add_Delta_Days
( $year, $month, $day,
2247 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2248 @newissue = Add_Delta_Days
( @newissue, 7 );
2249 $subscription->{countissuesperunit
} = 1;
2254 sub _get_next_date_month
{
2255 my ($subscription, $freqdata, $year, $month, $day) = @_;
2257 my @newissue; # ( yy, mm, dd )
2258 my $delta_days = int( 30 / $freqdata->{issuesperunit
} );
2260 if( $freqdata->{issuesperunit
} == 1 ) {
2262 @newissue = Add_Delta_YM
(
2263 $year, $month, $day, 0, $freqdata->{"unitsperissue"} );
2264 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2265 # Add rounded number of days based on frequency.
2266 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2267 $subscription->{countissuesperunit
}++;
2269 # We finished a cycle of issues within a unit.
2270 # Subtract delta * (issues - 1), add 1 month
2271 @newissue = Add_Delta_Days
( $year, $month, $day,
2272 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2273 @newissue = Add_Delta_YM
( @newissue, 0, 1 );
2274 $subscription->{countissuesperunit
} = 1;
2279 sub _get_next_date_year
{
2280 my ($subscription, $freqdata, $year, $month, $day) = @_;
2282 my @newissue; # ( yy, mm, dd )
2283 my $delta_days = int( 365 / $freqdata->{issuesperunit
} );
2285 if( $freqdata->{issuesperunit
} == 1 ) {
2287 @newissue = Add_Delta_YM
( $year, $month, $day, $freqdata->{"unitsperissue"}, 0 );
2288 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2289 # Add rounded number of days based on frequency.
2290 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2291 $subscription->{countissuesperunit
}++;
2293 # We finished a cycle of issues within a unit.
2294 # Subtract delta * (issues - 1), add 1 year
2295 @newissue = Add_Delta_Days
( $year, $month, $day, -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2296 @newissue = Add_Delta_YM
( @newissue, 1, 0 );
2297 $subscription->{countissuesperunit
} = 1;
2304 $resultdate = GetNextDate($publisheddate,$subscription,$freqdata,$updatecount)
2306 this function it takes the publisheddate and will return the next issue's date
2307 and will skip dates if there exists an irregularity.
2308 $publisheddate has to be an ISO date
2309 $subscription is a hashref containing at least 'firstacquidate', 'irregularity', and 'countissuesperunit'
2310 $frequency is a hashref containing frequency informations
2311 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2312 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2313 skipped then the returned date will be 2007-05-10
2316 $resultdate - then next date in the sequence (ISO date)
2318 Return undef if subscription is irregular
2323 my ( $subscription, $publisheddate, $freqdata, $updatecount ) = @_;
2325 return unless $subscription and $publisheddate;
2328 if ($freqdata->{'unit'}) {
2329 my ( $year, $month, $day ) = split /-/, $publisheddate;
2331 # Process an irregularity Hash
2332 # Suppose that irregularities are stored in a string with this structure
2333 # irreg1;irreg2;irreg3
2334 # where irregX is the number of issue which will not be received
2335 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2337 if ( $subscription->{irregularity
} ) {
2338 my @irreg = split /;/, $subscription->{'irregularity'} ;
2339 foreach my $irregularity (@irreg) {
2340 $irregularities{$irregularity} = 1;
2344 # Get the 'fictive' next issue number
2345 # It is used to check if next issue is an irregular issue.
2346 my $issueno = GetFictiveIssueNumber
($subscription, $publisheddate, $freqdata) + 1;
2348 # Then get the next date
2349 my $unit = lc $freqdata->{'unit'};
2350 if ($unit eq 'day') {
2351 while ($irregularities{$issueno}) {
2352 ($year, $month, $day) = _get_next_date_day
($subscription,
2353 $freqdata, $year, $month, $day);
2356 ($year, $month, $day) = _get_next_date_day
($subscription, $freqdata,
2357 $year, $month, $day);
2359 elsif ($unit eq 'week') {
2360 while ($irregularities{$issueno}) {
2361 ($year, $month, $day) = _get_next_date_week
($subscription,
2362 $freqdata, $year, $month, $day);
2365 ($year, $month, $day) = _get_next_date_week
($subscription,
2366 $freqdata, $year, $month, $day);
2368 elsif ($unit eq 'month') {
2369 while ($irregularities{$issueno}) {
2370 ($year, $month, $day) = _get_next_date_month
($subscription,
2371 $freqdata, $year, $month, $day);
2374 ($year, $month, $day) = _get_next_date_month
($subscription,
2375 $freqdata, $year, $month, $day);
2377 elsif ($unit eq 'year') {
2378 while ($irregularities{$issueno}) {
2379 ($year, $month, $day) = _get_next_date_year
($subscription,
2380 $freqdata, $year, $month, $day);
2383 ($year, $month, $day) = _get_next_date_year
($subscription,
2384 $freqdata, $year, $month, $day);
2388 my $dbh = C4
::Context
->dbh;
2391 SET countissuesperunit
= ?
2392 WHERE subscriptionid
= ?
2394 my $sth = $dbh->prepare($query);
2395 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2398 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2404 $string = &_numeration($value,$num_type,$locale);
2406 _numeration returns the string corresponding to $value in the num_type
2418 my ($value, $num_type, $locale) = @_;
2423 if ( $num_type =~ /^dayname$/ or $num_type =~ /^dayabrv$/ ) {
2424 # 1970-11-01 was a Sunday
2425 $value = $value % 7;
2426 my $dt = DateTime
->new(
2432 $string = $num_type =~ /^dayname$/
2433 ?
$dt->strftime("%A")
2434 : $dt->strftime("%a");
2435 } elsif ( $num_type =~ /^monthname$/ or $num_type =~ /^monthabrv$/ ) {
2436 $value = $value % 12;
2437 my $dt = DateTime
->new(
2439 month
=> $value + 1,
2442 $string = $num_type =~ /^monthname$/
2443 ?
$dt->strftime("%B")
2444 : $dt->strftime("%b");
2445 } elsif ( $num_type =~ /^season$/ ) {
2446 my @seasons= qw( Spring Summer Fall Winter );
2447 $value = $value % 4;
2448 $string = $seasons[$value];
2449 } elsif ( $num_type =~ /^seasonabrv$/ ) {
2450 my @seasonsabrv= qw( Spr Sum Fal Win );
2451 $value = $value % 4;
2452 $string = $seasonsabrv[$value];
2460 =head2 CloseSubscription
2462 Close a subscription given a subscriptionid
2466 sub CloseSubscription
{
2467 my ( $subscriptionid ) = @_;
2468 return unless $subscriptionid;
2469 my $dbh = C4
::Context
->dbh;
2470 my $sth = $dbh->prepare( q{
2473 WHERE subscriptionid = ?
2475 $sth->execute( $subscriptionid );
2477 # Set status = missing when status = stopped
2478 $sth = $dbh->prepare( q{
2481 WHERE subscriptionid = ?
2484 $sth->execute( STOPPED
, $subscriptionid, EXPECTED
);
2487 =head2 ReopenSubscription
2489 Reopen a subscription given a subscriptionid
2493 sub ReopenSubscription
{
2494 my ( $subscriptionid ) = @_;
2495 return unless $subscriptionid;
2496 my $dbh = C4
::Context
->dbh;
2497 my $sth = $dbh->prepare( q{
2500 WHERE subscriptionid = ?
2502 $sth->execute( $subscriptionid );
2504 # Set status = expected when status = stopped
2505 $sth = $dbh->prepare( q{
2508 WHERE subscriptionid = ?
2511 $sth->execute( EXPECTED
, $subscriptionid, STOPPED
);
2514 =head2 subscriptionCurrentlyOnOrder
2516 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2518 Return 1 if subscription is currently on order else 0.
2522 sub subscriptionCurrentlyOnOrder
{
2523 my ( $subscriptionid ) = @_;
2524 my $dbh = C4
::Context
->dbh;
2526 SELECT COUNT
(*) FROM aqorders
2527 WHERE subscriptionid
= ?
2528 AND datereceived IS NULL
2529 AND datecancellationprinted IS NULL
2531 my $sth = $dbh->prepare( $query );
2532 $sth->execute($subscriptionid);
2533 return $sth->fetchrow_array;
2536 =head2 can_claim_subscription
2538 $can = can_claim_subscription( $subscriptionid[, $userid] );
2540 Return 1 if the subscription can be claimed by the current logged user (or a given $userid), else 0.
2544 sub can_claim_subscription
{
2545 my ( $subscription, $userid ) = @_;
2546 return _can_do_on_subscription
( $subscription, $userid, 'claim_serials' );
2549 =head2 can_edit_subscription
2551 $can = can_edit_subscription( $subscriptionid[, $userid] );
2553 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2557 sub can_edit_subscription
{
2558 my ( $subscription, $userid ) = @_;
2559 return _can_do_on_subscription
( $subscription, $userid, 'edit_subscription' );
2562 =head2 can_show_subscription
2564 $can = can_show_subscription( $subscriptionid[, $userid] );
2566 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2570 sub can_show_subscription
{
2571 my ( $subscription, $userid ) = @_;
2572 return _can_do_on_subscription
( $subscription, $userid, '*' );
2575 sub _can_do_on_subscription
{
2576 my ( $subscription, $userid, $permission ) = @_;
2577 return 0 unless C4
::Context
->userenv;
2578 my $flags = C4
::Context
->userenv->{flags
};
2579 $userid ||= C4
::Context
->userenv->{'id'};
2581 if ( C4
::Context
->preference('IndependentBranches') ) {
2583 if C4
::Context
->IsSuperLibrarian()
2585 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2587 C4
::Auth
::haspermission
( $userid,
2588 { serials
=> $permission } )
2589 and ( not defined $subscription->{branchcode
}
2590 or $subscription->{branchcode
} eq ''
2591 or $subscription->{branchcode
} eq
2592 C4
::Context
->userenv->{'branch'} )
2597 if C4
::Context
->IsSuperLibrarian()
2599 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2600 or C4
::Auth
::haspermission
(
2601 $userid, { serials
=> $permission }
2608 =head2 findSerialsByStatus
2610 @serials = findSerialsByStatus($status, $subscriptionid);
2612 Returns an array of serials matching a given status and subscription id.
2616 sub findSerialsByStatus
{
2617 my ( $status, $subscriptionid ) = @_;
2618 my $dbh = C4
::Context
->dbh;
2619 my $query = q
| SELECT
* from serial
2621 AND subscriptionid
= ?
2623 my $serials = $dbh->selectall_arrayref( $query, { Slice
=> {} }, $status, $subscriptionid );
2632 Koha Development Team <http://koha-community.org/>