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
;
39 use vars
qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
47 MISSING_NEVER_RECIEVED => 41,
48 MISSING_SOLD_OUT => 42,
49 MISSING_DAMAGED => 43,
57 use constant MISSING_STATUSES => (
58 MISSING, MISSING_NEVER_RECIEVED,
59 MISSING_SOLD_OUT, MISSING_DAMAGED,
67 &NewSubscription &ModSubscription &DelSubscription
68 &GetSubscription &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
70 &GetFullSubscriptionsFromBiblionumber &GetFullSubscription &ModSubscriptionHistory
71 &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
72 &GetSubscriptionHistoryFromSubscriptionId
74 &GetNextSeq &GetSeq &NewIssue &GetSerials
75 &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2
76 &ReNewSubscription &GetLateOrMissingIssues
77 &GetSerialInformation &AddItem2Serial
78 &PrepareSerialsData &GetNextExpected &ModNextExpected
81 &GetSuppliersWithLateIssues
82 &getroutinglist &delroutingmember &addroutingmember
84 &check_routing &updateClaim
87 &subscriptionCurrentlyOnOrder
94 C4::Serials - Serials Module Functions
102 Functions for handling subscriptions, claims routing etc.
107 =head2 GetSuppliersWithLateIssues
109 $supplierlist = GetSuppliersWithLateIssues()
111 this function get all suppliers with late issues.
114 an array_ref of suppliers each entry is a hash_ref containing id and name
115 the array is in name order
119 sub GetSuppliersWithLateIssues
{
120 my $dbh = C4
::Context
->dbh;
121 my $statuses = join(',', ( LATE
, MISSING_STATUSES
, CLAIMED
) );
123 SELECT DISTINCT id
, name
125 LEFT JOIN serial ON serial
.subscriptionid
=subscription
.subscriptionid
126 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
129 (planneddate
< now
() AND serial
.status
=1)
130 OR serial
.STATUS IN
( $statuses )
132 AND subscription
.closed
= 0
134 return $dbh->selectall_arrayref($query, { Slice
=> {} });
137 =head2 GetSubscriptionHistoryFromSubscriptionId
139 $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
141 This function returns the subscription history as a hashref
145 sub GetSubscriptionHistoryFromSubscriptionId
{
146 my ($subscriptionid) = @_;
148 return unless $subscriptionid;
150 my $dbh = C4
::Context
->dbh;
153 FROM subscriptionhistory
154 WHERE subscriptionid
= ?
156 my $sth = $dbh->prepare($query);
157 $sth->execute($subscriptionid);
158 my $results = $sth->fetchrow_hashref;
164 =head2 GetSerialInformation
166 $data = GetSerialInformation($serialid);
167 returns a hash_ref containing :
168 items : items marcrecord (can be an array)
170 subscription table field
171 + information about subscription expiration
175 sub GetSerialInformation
{
177 my $dbh = C4
::Context
->dbh;
179 SELECT serial
.*, serial
.notes as sernotes
, serial
.status as serstatus
,subscription
.*,subscription
.subscriptionid as subsid
180 FROM serial LEFT JOIN subscription ON subscription
.subscriptionid
=serial
.subscriptionid
183 my $rq = $dbh->prepare($query);
184 $rq->execute($serialid);
185 my $data = $rq->fetchrow_hashref;
187 # create item information if we have serialsadditems for this subscription
188 if ( $data->{'serialsadditems'} ) {
189 my $queryitem = $dbh->prepare("SELECT itemnumber from serialitems where serialid=?");
190 $queryitem->execute($serialid);
191 my $itemnumbers = $queryitem->fetchall_arrayref( [0] );
193 if ( scalar(@
$itemnumbers) > 0 ) {
194 foreach my $itemnum (@
$itemnumbers) {
196 #It is ASSUMED that GetMarcItem ALWAYS WORK...
197 #Maybe GetMarcItem should return values on failure
198 $debug and warn "itemnumber :$itemnum->[0], bibnum :" . $data->{'biblionumber'};
199 my $itemprocessed = C4
::Items
::PrepareItemrecordDisplay
( $data->{'biblionumber'}, $itemnum->[0], $data );
200 $itemprocessed->{'itemnumber'} = $itemnum->[0];
201 $itemprocessed->{'itemid'} = $itemnum->[0];
202 $itemprocessed->{'serialid'} = $serialid;
203 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
204 push @
{ $data->{'items'} }, $itemprocessed;
207 my $itemprocessed = C4
::Items
::PrepareItemrecordDisplay
( $data->{'biblionumber'}, '', $data );
208 $itemprocessed->{'itemid'} = "N$serialid";
209 $itemprocessed->{'serialid'} = $serialid;
210 $itemprocessed->{'biblionumber'} = $data->{'biblionumber'};
211 $itemprocessed->{'countitems'} = 0;
212 push @
{ $data->{'items'} }, $itemprocessed;
215 $data->{ "status" . $data->{'serstatus'} } = 1;
216 $data->{'subscriptionexpired'} = HasSubscriptionExpired
( $data->{'subscriptionid'} ) && $data->{'status'} == 1;
217 $data->{'abouttoexpire'} = abouttoexpire
( $data->{'subscriptionid'} );
218 $data->{cannotedit
} = not can_edit_subscription
( $data );
222 =head2 AddItem2Serial
224 $rows = AddItem2Serial($serialid,$itemnumber);
225 Adds an itemnumber to Serial record
226 returns the number of rows affected
231 my ( $serialid, $itemnumber ) = @_;
233 return unless ($serialid and $itemnumber);
235 my $dbh = C4
::Context
->dbh;
236 my $rq = $dbh->prepare("INSERT INTO `serialitems` SET serialid=? , itemnumber=?");
237 $rq->execute( $serialid, $itemnumber );
241 =head2 GetSubscription
243 $subs = GetSubscription($subscriptionid)
244 this function returns the subscription which has $subscriptionid as id.
246 a hashref. This hash contains
247 subscription, subscriptionhistory, aqbooksellers.name, biblio.title
251 sub GetSubscription
{
252 my ($subscriptionid) = @_;
253 my $dbh = C4
::Context
->dbh;
255 SELECT subscription
.*,
256 subscriptionhistory
.*,
257 aqbooksellers
.name AS aqbooksellername
,
258 biblio
.title AS bibliotitle
,
259 subscription
.biblionumber as bibnum
261 LEFT JOIN subscriptionhistory ON subscription
.subscriptionid
=subscriptionhistory
.subscriptionid
262 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
=aqbooksellers
.id
263 LEFT JOIN biblio ON biblio
.biblionumber
=subscription
.biblionumber
264 WHERE subscription
.subscriptionid
= ?
267 $debug and warn "query : $query\nsubsid :$subscriptionid";
268 my $sth = $dbh->prepare($query);
269 $sth->execute($subscriptionid);
270 my $subscription = $sth->fetchrow_hashref;
272 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
274 # Add additional fields to the subscription into a new key "additional_fields"
275 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
276 tablename
=> 'subscription',
277 record_id
=> $subscriptionid,
279 $subscription->{additional_fields
} = $additional_field_values->{$subscriptionid};
281 return $subscription;
284 =head2 GetFullSubscription
286 $array_ref = GetFullSubscription($subscriptionid)
287 this function reads the serial table.
291 sub GetFullSubscription
{
292 my ($subscriptionid) = @_;
294 return unless ($subscriptionid);
296 my $dbh = C4
::Context
->dbh;
298 SELECT serial
.serialid
,
301 serial
.publisheddate
,
302 serial
.publisheddatetext
,
304 serial
.notes as notes
,
305 year
(IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) as year
,
306 aqbooksellers
.name as aqbooksellername
,
307 biblio
.title as bibliotitle
,
308 subscription
.branchcode AS branchcode
,
309 subscription
.subscriptionid AS subscriptionid
311 LEFT JOIN subscription ON
312 (serial
.subscriptionid
=subscription
.subscriptionid
)
313 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
314 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
315 WHERE serial
.subscriptionid
= ?
317 IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) DESC
,
318 serial
.subscriptionid
320 $debug and warn "GetFullSubscription query: $query";
321 my $sth = $dbh->prepare($query);
322 $sth->execute($subscriptionid);
323 my $subscriptions = $sth->fetchall_arrayref( {} );
324 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
325 for my $subscription ( @
$subscriptions ) {
326 $subscription->{cannotedit
} = $cannotedit;
328 return $subscriptions;
331 =head2 PrepareSerialsData
333 $array_ref = PrepareSerialsData($serialinfomation)
334 where serialinformation is a hashref array
338 sub PrepareSerialsData
{
341 return unless ($lines);
347 my $aqbooksellername;
351 my $previousnote = "";
353 foreach my $subs (@
{$lines}) {
354 for my $datefield ( qw(publisheddate planneddate) ) {
355 # handle 0000-00-00 dates
356 if (defined $subs->{$datefield} and $subs->{$datefield} =~ m/^00/) {
357 $subs->{$datefield} = undef;
360 $subs->{ "status" . $subs->{'status'} } = 1;
361 if ( grep { $_ == $subs->{status
} } ( EXPECTED
, LATE
, MISSING_STATUSES
, CLAIMED
) ) {
362 $subs->{"checked"} = 1;
365 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
366 $year = $subs->{'year'};
370 if ( $tmpresults{$year} ) {
371 push @
{ $tmpresults{$year}->{'serials'} }, $subs;
373 $tmpresults{$year} = {
375 'aqbooksellername' => $subs->{'aqbooksellername'},
376 'bibliotitle' => $subs->{'bibliotitle'},
377 'serials' => [$subs],
382 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
383 push @res, $tmpresults{$key};
388 =head2 GetSubscriptionsFromBiblionumber
390 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
391 this function get the subscription list. it reads the subscription table.
393 reference to an array of subscriptions which have the biblionumber given on input arg.
394 each element of this array is a hashref containing
395 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
399 sub GetSubscriptionsFromBiblionumber
{
400 my ($biblionumber) = @_;
402 return unless ($biblionumber);
404 my $dbh = C4
::Context
->dbh;
406 SELECT subscription
.*,
408 subscriptionhistory
.*,
409 aqbooksellers
.name AS aqbooksellername
,
410 biblio
.title AS bibliotitle
412 LEFT JOIN subscriptionhistory ON subscription
.subscriptionid
=subscriptionhistory
.subscriptionid
413 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
=aqbooksellers
.id
414 LEFT JOIN biblio ON biblio
.biblionumber
=subscription
.biblionumber
415 LEFT JOIN branches ON branches
.branchcode
=subscription
.branchcode
416 WHERE subscription
.biblionumber
= ?
418 my $sth = $dbh->prepare($query);
419 $sth->execute($biblionumber);
421 while ( my $subs = $sth->fetchrow_hashref ) {
422 $subs->{startdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{startdate
} ), dateonly
=> 1 } );
423 $subs->{histstartdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histstartdate
} ), dateonly
=> 1 } );
424 if ( defined $subs->{histenddate
} ) {
425 $subs->{histenddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histenddate
} ), dateonly
=> 1 } );
427 $subs->{histenddate
} = "";
429 $subs->{opacnote
} =~ s/\n/\<br\/\
>/g
;
430 $subs->{missinglist
} =~ s/\n/\<br\/\
>/g
;
431 $subs->{recievedlist
} =~ s/\n/\<br\/\
>/g
;
432 $subs->{ "periodicity" . $subs->{periodicity
} } = 1;
433 $subs->{ "numberpattern" . $subs->{numberpattern
} } = 1;
434 $subs->{ "status" . $subs->{'status'} } = 1;
436 if (not defined $subs->{enddate
} ) {
437 $subs->{enddate
} = '';
439 $subs->{enddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{enddate
}), dateonly
=> 1 } );
441 $subs->{'abouttoexpire'} = abouttoexpire
( $subs->{'subscriptionid'} );
442 $subs->{'subscriptionexpired'} = HasSubscriptionExpired
( $subs->{'subscriptionid'} );
443 $subs->{cannotedit
} = not can_edit_subscription
( $subs );
449 =head2 GetFullSubscriptionsFromBiblionumber
451 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
452 this function reads the serial table.
456 sub GetFullSubscriptionsFromBiblionumber
{
457 my ($biblionumber) = @_;
458 my $dbh = C4
::Context
->dbh;
460 SELECT serial
.serialid
,
463 serial
.publisheddate
,
464 serial
.publisheddatetext
,
466 serial
.notes as notes
,
467 year
(IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) as year
,
468 biblio
.title as bibliotitle
,
469 subscription
.branchcode AS branchcode
,
470 subscription
.subscriptionid AS subscriptionid
472 LEFT JOIN subscription ON
473 (serial
.subscriptionid
=subscription
.subscriptionid
)
474 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
475 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
476 WHERE subscription
.biblionumber
= ?
478 IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) DESC
,
479 serial
.subscriptionid
481 my $sth = $dbh->prepare($query);
482 $sth->execute($biblionumber);
483 my $subscriptions = $sth->fetchall_arrayref( {} );
484 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
485 for my $subscription ( @
$subscriptions ) {
486 $subscription->{cannotedit
} = $cannotedit;
488 return $subscriptions;
491 =head2 SearchSubscriptions
493 @results = SearchSubscriptions($args);
495 This function returns a list of hashrefs, one for each subscription
496 that meets the conditions specified by the $args hashref.
498 The valid search fields are:
512 The expiration_date search field is special; it specifies the maximum
513 subscription expiration date.
517 sub SearchSubscriptions
{
520 my $additional_fields = $args->{additional_fields
} // [];
521 my $matching_record_ids_for_additional_fields = [];
522 if ( @
$additional_fields ) {
523 $matching_record_ids_for_additional_fields = Koha
::AdditionalField
->get_matching_record_ids({
524 fields
=> $additional_fields,
525 tablename
=> 'subscription',
528 return () unless @
$matching_record_ids_for_additional_fields;
533 subscription
.notes AS publicnotes
,
534 subscriptionhistory
.*,
536 biblio
.notes AS biblionotes
,
540 aqbooksellers
.name AS vendorname
,
543 LEFT JOIN subscriptionhistory USING
(subscriptionid
)
544 LEFT JOIN biblio ON biblio
.biblionumber
= subscription
.biblionumber
545 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= subscription
.biblionumber
546 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
548 $query .= q
| WHERE
1|;
551 if( $args->{biblionumber
} ) {
552 push @where_strs, "biblio.biblionumber = ?";
553 push @where_args, $args->{biblionumber
};
556 if( $args->{title
} ){
557 my @words = split / /, $args->{title
};
559 foreach my $word (@words) {
560 push @strs, "biblio.title LIKE ?";
561 push @args, "%$word%";
564 push @where_strs, '(' . join (' AND ', @strs) . ')';
565 push @where_args, @args;
569 push @where_strs, "biblioitems.issn LIKE ?";
570 push @where_args, "%$args->{issn}%";
573 push @where_strs, "biblioitems.ean LIKE ?";
574 push @where_args, "%$args->{ean}%";
576 if ( $args->{callnumber
} ) {
577 push @where_strs, "subscription.callnumber LIKE ?";
578 push @where_args, "%$args->{callnumber}%";
580 if( $args->{publisher
} ){
581 push @where_strs, "biblioitems.publishercode LIKE ?";
582 push @where_args, "%$args->{publisher}%";
584 if( $args->{bookseller
} ){
585 push @where_strs, "aqbooksellers.name LIKE ?";
586 push @where_args, "%$args->{bookseller}%";
588 if( $args->{branch
} ){
589 push @where_strs, "subscription.branchcode = ?";
590 push @where_args, "$args->{branch}";
592 if ( $args->{location
} ) {
593 push @where_strs, "subscription.location = ?";
594 push @where_args, "$args->{location}";
596 if ( $args->{expiration_date
} ) {
597 push @where_strs, "subscription.enddate <= ?";
598 push @where_args, "$args->{expiration_date}";
600 if( defined $args->{closed
} ){
601 push @where_strs, "subscription.closed = ?";
602 push @where_args, "$args->{closed}";
606 $query .= ' AND ' . join(' AND ', @where_strs);
608 if ( @
$additional_fields ) {
609 $query .= ' AND subscriptionid IN ('
610 . join( ', ', @
$matching_record_ids_for_additional_fields )
614 $query .= " ORDER BY " . $args->{orderby
} if $args->{orderby
};
616 my $dbh = C4
::Context
->dbh;
617 my $sth = $dbh->prepare($query);
618 $sth->execute(@where_args);
619 my $results = $sth->fetchall_arrayref( {} );
621 for my $subscription ( @
$results ) {
622 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
623 $subscription->{cannotdisplay
} = not can_show_subscription
( $subscription );
625 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
626 record_id
=> $subscription->{subscriptionid
},
627 tablename
=> 'subscription'
629 $subscription->{additional_fields
} = $additional_field_values->{$subscription->{subscriptionid
}};
638 ($totalissues,@serials) = GetSerials($subscriptionid);
639 this function gets every serial not arrived for a given subscription
640 as well as the number of issues registered in the database (all types)
641 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
643 FIXME: We should return \@serials.
648 my ( $subscriptionid, $count ) = @_;
650 return unless $subscriptionid;
652 my $dbh = C4
::Context
->dbh;
654 # status = 2 is "arrived"
656 $count = 5 unless ($count);
658 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
, NOT_ISSUED
) );
659 my $query = "SELECT serialid,serialseq, status, publisheddate,
660 publisheddatetext, planneddate,notes, routingnotes
662 WHERE subscriptionid = ? AND status NOT IN ( $statuses )
663 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
664 my $sth = $dbh->prepare($query);
665 $sth->execute($subscriptionid);
667 while ( my $line = $sth->fetchrow_hashref ) {
668 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
669 for my $datefield ( qw( planneddate publisheddate) ) {
670 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
671 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
673 $line->{$datefield} = q{};
676 push @serials, $line;
679 # OK, now add the last 5 issues arrives/missing
680 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,
681 publisheddatetext, notes, routingnotes
683 WHERE subscriptionid = ?
684 AND status IN ( $statuses )
685 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
687 $sth = $dbh->prepare($query);
688 $sth->execute($subscriptionid);
689 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
691 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
692 for my $datefield ( qw( planneddate publisheddate) ) {
693 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
694 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
696 $line->{$datefield} = q{};
700 push @serials, $line;
703 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
704 $sth = $dbh->prepare($query);
705 $sth->execute($subscriptionid);
706 my ($totalissues) = $sth->fetchrow;
707 return ( $totalissues, @serials );
712 @serials = GetSerials2($subscriptionid,$statuses);
713 this function returns every serial waited for a given subscription
714 as well as the number of issues registered in the database (all types)
715 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
717 $statuses is an arrayref of statuses and is mandatory.
722 my ( $subscription, $statuses ) = @_;
724 return unless ($subscription and @
$statuses);
726 my $dbh = C4
::Context
->dbh;
728 SELECT serialid
,serialseq
, status
, planneddate
, publisheddate
,
729 publisheddatetext
, notes
, routingnotes
731 WHERE subscriptionid
=?
733 . q
| AND status IN
(| . join( ",", ('?') x @
$statuses ) . q
|)|
735 ORDER BY publisheddate
,serialid DESC
737 $debug and warn "GetSerials2 query: $query";
738 my $sth = $dbh->prepare($query);
739 $sth->execute( $subscription, @
$statuses );
742 while ( my $line = $sth->fetchrow_hashref ) {
743 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
744 # Format dates for display
745 for my $datefield ( qw( planneddate publisheddate ) ) {
746 if (!defined($line->{$datefield}) || $line->{$datefield} =~m/^00/) {
747 $line->{$datefield} = q{};
750 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
753 push @serials, $line;
758 =head2 GetLatestSerials
760 \@serials = GetLatestSerials($subscriptionid,$limit)
761 get the $limit's latest serials arrived or missing for a given subscription
763 a ref to an array which contains all of the latest serials stored into a hash.
767 sub GetLatestSerials
{
768 my ( $subscriptionid, $limit ) = @_;
770 return unless ($subscriptionid and $limit);
772 my $dbh = C4
::Context
->dbh;
774 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
) );
775 my $strsth = "SELECT serialid,serialseq, status, planneddate, publisheddate, notes
777 WHERE subscriptionid = ?
778 AND status IN ($statuses)
779 ORDER BY publisheddate DESC LIMIT 0,$limit
781 my $sth = $dbh->prepare($strsth);
782 $sth->execute($subscriptionid);
784 while ( my $line = $sth->fetchrow_hashref ) {
785 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
786 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{planneddate
} ), dateonly
=> 1 } );
787 $line->{publisheddate
} = output_pref
( { dt
=> dt_from_string
( $line->{publisheddate
} ), dateonly
=> 1 } );
788 push @serials, $line;
794 =head2 GetPreviousSerialid
796 $serialid = GetPreviousSerialid($subscriptionid, $nth)
797 get the $nth's previous serial for the given subscriptionid
803 sub GetPreviousSerialid
{
804 my ( $subscriptionid, $nth ) = @_;
806 my $dbh = C4
::Context
->dbh;
810 my $strsth = "SELECT serialid
812 WHERE subscriptionid = ?
814 ORDER BY serialid DESC LIMIT $nth,1
816 my $sth = $dbh->prepare($strsth);
817 $sth->execute($subscriptionid);
819 my $line = $sth->fetchrow_hashref;
820 $return = $line->{'serialid'} if ($line);
828 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
829 $newinnerloop1, $newinnerloop2, $newinnerloop3
830 ) = GetNextSeq( $subscription, $pattern, $planneddate );
832 $subscription is a hashref containing all the attributes of the table
834 $pattern is a hashref containing all the attributes of the table
835 'subscription_numberpatterns'.
836 $planneddate is a date string in iso format.
837 This function get the next issue for the subscription given on input arg
842 my ($subscription, $pattern, $planneddate) = @_;
844 return unless ($subscription and $pattern);
846 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
847 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
850 if ($subscription->{'skip_serialseq'}) {
851 my @irreg = split /;/, $subscription->{'irregularity'};
853 my $irregularities = {};
854 $irregularities->{$_} = 1 foreach(@irreg);
855 my $issueno = GetFictiveIssueNumber
($subscription, $planneddate) + 1;
856 while($irregularities->{$issueno}) {
863 my $numberingmethod = $pattern->{numberingmethod
};
865 if ($numberingmethod) {
866 $calculated = $numberingmethod;
867 my $locale = $subscription->{locale
};
868 $newlastvalue1 = $subscription->{lastvalue1
} || 0;
869 $newlastvalue2 = $subscription->{lastvalue2
} || 0;
870 $newlastvalue3 = $subscription->{lastvalue3
} || 0;
871 $newinnerloop1 = $subscription->{innerloop1
} || 0;
872 $newinnerloop2 = $subscription->{innerloop2
} || 0;
873 $newinnerloop3 = $subscription->{innerloop3
} || 0;
876 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
879 for(my $i = 0; $i < $count; $i++) {
881 # check if we have to increase the new value.
883 if ($newinnerloop1 >= $pattern->{every1
}) {
885 $newlastvalue1 += $pattern->{add1
};
887 # reset counter if needed.
888 $newlastvalue1 = $pattern->{setto1
} if ($newlastvalue1 > $pattern->{whenmorethan1
});
891 # check if we have to increase the new value.
893 if ($newinnerloop2 >= $pattern->{every2
}) {
895 $newlastvalue2 += $pattern->{add2
};
897 # reset counter if needed.
898 $newlastvalue2 = $pattern->{setto2
} if ($newlastvalue2 > $pattern->{whenmorethan2
});
901 # check if we have to increase the new value.
903 if ($newinnerloop3 >= $pattern->{every3
}) {
905 $newlastvalue3 += $pattern->{add3
};
907 # reset counter if needed.
908 $newlastvalue3 = $pattern->{setto3
} if ($newlastvalue3 > $pattern->{whenmorethan3
});
912 my $newlastvalue1string = _numeration
( $newlastvalue1, $pattern->{numbering1
}, $locale );
913 $calculated =~ s/\{X\}/$newlastvalue1string/g;
916 my $newlastvalue2string = _numeration
( $newlastvalue2, $pattern->{numbering2
}, $locale );
917 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
920 my $newlastvalue3string = _numeration
( $newlastvalue3, $pattern->{numbering3
}, $locale );
921 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
926 $newlastvalue1, $newlastvalue2, $newlastvalue3,
927 $newinnerloop1, $newinnerloop2, $newinnerloop3);
932 $calculated = GetSeq($subscription, $pattern)
933 $subscription is a hashref containing all the attributes of the table 'subscription'
934 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
935 this function transforms {X},{Y},{Z} to 150,0,0 for example.
937 the sequence in string format
942 my ($subscription, $pattern) = @_;
944 return unless ($subscription and $pattern);
946 my $locale = $subscription->{locale
};
948 my $calculated = $pattern->{numberingmethod
};
950 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
951 $newlastvalue1 = _numeration
($newlastvalue1, $pattern->{numbering1
}, $locale) if ($pattern->{numbering1
}); # reset counter if needed.
952 $calculated =~ s/\{X\}/$newlastvalue1/g;
954 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
955 $newlastvalue2 = _numeration
($newlastvalue2, $pattern->{numbering2
}, $locale) if ($pattern->{numbering2
}); # reset counter if needed.
956 $calculated =~ s/\{Y\}/$newlastvalue2/g;
958 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
959 $newlastvalue3 = _numeration
($newlastvalue3, $pattern->{numbering3
}, $locale) if ($pattern->{numbering3
}); # reset counter if needed.
960 $calculated =~ s/\{Z\}/$newlastvalue3/g;
964 =head2 GetExpirationDate
966 $enddate = GetExpirationDate($subscriptionid, [$startdate])
968 this function return the next expiration date for a subscription given on input args.
975 sub GetExpirationDate
{
976 my ( $subscriptionid, $startdate ) = @_;
978 return unless ($subscriptionid);
980 my $dbh = C4
::Context
->dbh;
981 my $subscription = GetSubscription
($subscriptionid);
984 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
985 $enddate = $startdate || $subscription->{startdate
};
986 my @date = split( /-/, $enddate );
988 return if ( scalar(@date) != 3 || not check_date
(@date) );
990 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
991 if ( $frequency and $frequency->{unit
} ) {
994 if ( my $length = $subscription->{numberlength
} ) {
996 #calculate the date of the last issue.
997 for ( my $i = 1 ; $i <= $length ; $i++ ) {
998 $enddate = GetNextDate
( $subscription, $enddate );
1000 } elsif ( $subscription->{monthlength
} ) {
1001 if ( $$subscription{startdate
} ) {
1002 my @enddate = Add_Delta_YM
( $date[0], $date[1], $date[2], 0, $subscription->{monthlength
} );
1003 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1005 } elsif ( $subscription->{weeklength
} ) {
1006 if ( $$subscription{startdate
} ) {
1007 my @date = split( /-/, $subscription->{startdate
} );
1008 my @enddate = Add_Delta_Days
( $date[0], $date[1], $date[2], $subscription->{weeklength
} * 7 );
1009 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1012 $enddate = $subscription->{enddate
};
1016 return $subscription->{enddate
};
1020 =head2 CountSubscriptionFromBiblionumber
1022 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1023 this returns a count of the subscriptions for a given biblionumber
1025 the number of subscriptions
1029 sub CountSubscriptionFromBiblionumber
{
1030 my ($biblionumber) = @_;
1032 return unless ($biblionumber);
1034 my $dbh = C4
::Context
->dbh;
1035 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1036 my $sth = $dbh->prepare($query);
1037 $sth->execute($biblionumber);
1038 my $subscriptionsnumber = $sth->fetchrow;
1039 return $subscriptionsnumber;
1042 =head2 ModSubscriptionHistory
1044 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1046 this function modifies the history of a subscription. Put your new values on input arg.
1047 returns the number of rows affected
1051 sub ModSubscriptionHistory
{
1052 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1054 return unless ($subscriptionid);
1056 my $dbh = C4
::Context
->dbh;
1057 my $query = "UPDATE subscriptionhistory
1058 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1059 WHERE subscriptionid=?
1061 my $sth = $dbh->prepare($query);
1062 $receivedlist =~ s/^; // if $receivedlist;
1063 $missinglist =~ s/^; // if $missinglist;
1064 $opacnote =~ s/^; // if $opacnote;
1065 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1069 =head2 ModSerialStatus
1071 ModSerialStatus($serialid, $serialseq, $planneddate, $publisheddate,
1072 $publisheddatetext, $status, $notes);
1074 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1075 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1079 sub ModSerialStatus
{
1080 my ($serialid, $serialseq, $planneddate, $publisheddate, $publisheddatetext,
1081 $status, $notes) = @_;
1083 return unless ($serialid);
1085 #It is a usual serial
1086 # 1st, get previous status :
1087 my $dbh = C4
::Context
->dbh;
1088 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
1089 FROM serial, subscription
1090 WHERE serial.subscriptionid=subscription.subscriptionid
1092 my $sth = $dbh->prepare($query);
1093 $sth->execute($serialid);
1094 my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
1095 my $frequency = GetSubscriptionFrequency
($periodicity);
1097 # change status & update subscriptionhistory
1099 if ( $status == DELETED
) {
1100 DelIssue
( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1105 SET serialseq = ?, publisheddate = ?, publisheddatetext = ?,
1106 planneddate = ?, status = ?, notes = ?
1109 $sth = $dbh->prepare($query);
1110 $sth->execute( $serialseq, $publisheddate, $publisheddatetext,
1111 $planneddate, $status, $notes, $serialid );
1112 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1113 $sth = $dbh->prepare($query);
1114 $sth->execute($subscriptionid);
1115 my $val = $sth->fetchrow_hashref;
1116 unless ( $val->{manualhistory
} ) {
1117 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1118 $sth = $dbh->prepare($query);
1119 $sth->execute($subscriptionid);
1120 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1122 if ( $status == ARRIVED
|| ($oldstatus == ARRIVED
&& $status != ARRIVED
) ) {
1123 $recievedlist .= "; $serialseq"
1124 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1127 # in case serial has been previously marked as missing
1128 if (grep /$status/, (EXPECTED
, ARRIVED
, LATE
, CLAIMED
)) {
1129 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1132 $missinglist .= "; $serialseq"
1133 if ( ( grep { $_ == $status } ( MISSING_STATUSES
) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1134 $missinglist .= "; not issued $serialseq"
1135 if ( $status == NOT_ISSUED
&& $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1137 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1138 $sth = $dbh->prepare($query);
1139 $recievedlist =~ s/^; //;
1140 $missinglist =~ s/^; //;
1141 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1145 # create new expected entry if needed (ie : was "expected" and has changed)
1146 my $otherIssueExpected = scalar findSerialsByStatus
(EXPECTED
, $subscriptionid);
1147 if ( !$otherIssueExpected && $oldstatus == EXPECTED
&& $status != EXPECTED
) {
1148 my $subscription = GetSubscription
($subscriptionid);
1149 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1153 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1154 $newinnerloop1, $newinnerloop2, $newinnerloop3
1156 = GetNextSeq
( $subscription, $pattern, $publisheddate );
1158 # next date (calculated from actual date & frequency parameters)
1159 my $nextpublisheddate = GetNextDate
($subscription, $publisheddate, 1);
1160 my $nextpubdate = $nextpublisheddate;
1161 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1162 WHERE subscriptionid = ?";
1163 $sth = $dbh->prepare($query);
1164 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1166 NewIssue
( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
1168 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1169 if ( $subscription->{letter
} && $status == ARRIVED
&& $oldstatus != ARRIVED
) {
1170 require C4
::Letters
;
1171 C4
::Letters
::SendAlerts
( 'issue', $serialid, $subscription->{letter
} );
1178 =head2 GetNextExpected
1180 $nextexpected = GetNextExpected($subscriptionid)
1182 Get the planneddate for the current expected issue of the subscription.
1188 planneddate => ISO date
1193 sub GetNextExpected
{
1194 my ($subscriptionid) = @_;
1196 my $dbh = C4
::Context
->dbh;
1200 WHERE subscriptionid
= ?
1204 my $sth = $dbh->prepare($query);
1206 # Each subscription has only one 'expected' issue.
1207 $sth->execute( $subscriptionid, EXPECTED
);
1208 my $nextissue = $sth->fetchrow_hashref;
1209 if ( !$nextissue ) {
1213 WHERE subscriptionid
= ?
1214 ORDER BY publisheddate DESC
1217 $sth = $dbh->prepare($query);
1218 $sth->execute($subscriptionid);
1219 $nextissue = $sth->fetchrow_hashref;
1221 foreach(qw
/planneddate publisheddate/) {
1222 if ( !defined $nextissue->{$_} ) {
1223 # or should this default to 1st Jan ???
1224 $nextissue->{$_} = strftime
( '%Y-%m-%d', localtime );
1226 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1234 =head2 ModNextExpected
1236 ModNextExpected($subscriptionid,$date)
1238 Update the planneddate for the current expected issue of the subscription.
1239 This will modify all future prediction results.
1241 C<$date> is an ISO date.
1247 sub ModNextExpected
{
1248 my ( $subscriptionid, $date ) = @_;
1249 my $dbh = C4
::Context
->dbh;
1251 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1252 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1254 # Each subscription has only one 'expected' issue.
1255 $sth->execute( $date, $date, $subscriptionid, EXPECTED
);
1260 =head2 GetSubscriptionIrregularities
1264 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1265 get the list of irregularities for a subscription
1271 sub GetSubscriptionIrregularities
{
1272 my $subscriptionid = shift;
1274 return unless $subscriptionid;
1276 my $dbh = C4
::Context
->dbh;
1280 WHERE subscriptionid
= ?
1282 my $sth = $dbh->prepare($query);
1283 $sth->execute($subscriptionid);
1285 my ($result) = $sth->fetchrow_array;
1286 my @irreg = split /;/, $result;
1291 =head2 ModSubscription
1293 this function modifies a subscription. Put all new values on input args.
1294 returns the number of rows affected
1298 sub ModSubscription
{
1300 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1301 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1302 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1303 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1304 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1305 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1306 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq,
1307 $itemtype, $previousitemtype
1310 my $dbh = C4
::Context
->dbh;
1311 my $query = "UPDATE subscription
1312 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1313 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1314 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1315 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1316 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1317 callnumber=?, notes=?, letter=?, manualhistory=?,
1318 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1319 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1320 skip_serialseq=?, itemtype=?, previousitemtype=?
1321 WHERE subscriptionid = ?";
1323 my $sth = $dbh->prepare($query);
1325 $auser, $branchcode, $aqbooksellerid, $cost,
1326 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1327 $irregularity, $numberpattern, $locale, $numberlength,
1328 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1329 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1330 $status, $biblionumber, $callnumber, $notes,
1331 $letter, ($manualhistory ?
$manualhistory : 0),
1332 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1333 $graceperiod, $location, $enddate, $skip_serialseq,
1334 $itemtype, $previousitemtype,
1337 my $rows = $sth->rows;
1339 logaction
( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1343 =head2 NewSubscription
1345 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1346 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1347 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1348 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1349 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1350 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
1351 $skip_serialseq, $itemtype, $previousitemtype);
1353 Create a new subscription with value given on input args.
1356 the id of this new subscription
1360 sub NewSubscription
{
1362 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1363 $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
1364 $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
1365 $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
1366 $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
1367 $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
1368 $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype
1370 my $dbh = C4
::Context
->dbh;
1372 #save subscription (insert into database)
1374 INSERT INTO subscription
1375 (librarian
, branchcode
, aqbooksellerid
, cost
, aqbudgetid
,
1376 biblionumber
, startdate
, periodicity
, numberlength
, weeklength
,
1377 monthlength
, lastvalue1
, innerloop1
, lastvalue2
, innerloop2
,
1378 lastvalue3
, innerloop3
, status
, notes
, letter
, firstacquidate
,
1379 irregularity
, numberpattern
, locale
, callnumber
,
1380 manualhistory
, internalnotes
, serialsadditems
, staffdisplaycount
,
1381 opacdisplaycount
, graceperiod
, location
, enddate
, skip_serialseq
,
1382 itemtype
, previousitemtype
)
1383 VALUES
(?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
)
1385 my $sth = $dbh->prepare($query);
1387 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1388 $startdate, $periodicity, $numberlength, $weeklength,
1389 $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
1390 $lastvalue3, $innerloop3, $status, $notes, $letter,
1391 $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
1392 $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
1393 $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq,
1394 $itemtype, $previousitemtype
1397 my $subscriptionid = $dbh->{'mysql_insertid'};
1399 $enddate = GetExpirationDate
( $subscriptionid, $startdate );
1403 WHERE subscriptionid
=?
1405 $sth = $dbh->prepare($query);
1406 $sth->execute( $enddate, $subscriptionid );
1409 # then create the 1st expected number
1411 INSERT INTO subscriptionhistory
1412 (biblionumber
, subscriptionid
, histstartdate
, missinglist
, recievedlist
)
1413 VALUES
(?
,?
,?
, '', '')
1415 $sth = $dbh->prepare($query);
1416 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1418 # reread subscription to get a hash (for calculation of the 1st issue number)
1419 my $subscription = GetSubscription
($subscriptionid);
1420 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1422 # calculate issue number
1423 my $serialseq = GetSeq
($subscription, $pattern) || q{};
1427 serialseq
=> $serialseq,
1428 serialseq_x
=> $subscription->{'lastvalue1'},
1429 serialseq_y
=> $subscription->{'lastvalue2'},
1430 serialseq_z
=> $subscription->{'lastvalue3'},
1431 subscriptionid
=> $subscriptionid,
1432 biblionumber
=> $biblionumber,
1434 planneddate
=> $firstacquidate,
1435 publisheddate
=> $firstacquidate,
1439 logaction
( "SERIAL", "ADD", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1441 #set serial flag on biblio if not already set.
1442 my $biblio = Koha
::Biblios
->find( $biblionumber );
1443 if ( $biblio and !$biblio->serial ) {
1444 my $record = GetMarcBiblio
({ biblionumber
=> $biblionumber });
1445 my ( $tag, $subf ) = GetMarcFromKohaField
( 'biblio.serial', $biblio->frameworkcode );
1447 eval { $record->field($tag)->update( $subf => 1 ); };
1449 ModBiblio
( $record, $biblionumber, $biblio->frameworkcode );
1451 return $subscriptionid;
1454 =head2 ReNewSubscription
1456 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1458 this function renew a subscription with values given on input args.
1462 sub ReNewSubscription
{
1463 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1464 my $dbh = C4
::Context
->dbh;
1465 my $subscription = GetSubscription
($subscriptionid);
1469 LEFT JOIN biblioitems ON biblio
.biblionumber
=biblioitems
.biblionumber
1470 WHERE biblio
.biblionumber
=?
1472 my $sth = $dbh->prepare($query);
1473 $sth->execute( $subscription->{biblionumber
} );
1474 my $biblio = $sth->fetchrow_hashref;
1476 if ( C4
::Context
->preference("RenewSerialAddsSuggestion") ) {
1477 require C4
::Suggestions
;
1478 C4
::Suggestions
::NewSuggestion
(
1479 { 'suggestedby' => $user,
1480 'title' => $subscription->{bibliotitle
},
1481 'author' => $biblio->{author
},
1482 'publishercode' => $biblio->{publishercode
},
1483 'note' => $biblio->{note
},
1484 'biblionumber' => $subscription->{biblionumber
}
1489 $numberlength ||= 0; # Should not we raise an exception instead?
1492 # renew subscription
1495 SET startdate
=?
,numberlength
=?
,weeklength
=?
,monthlength
=?
,reneweddate
=NOW
()
1496 WHERE subscriptionid
=?
1498 $sth = $dbh->prepare($query);
1499 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1500 my $enddate = GetExpirationDate
($subscriptionid);
1501 $debug && warn "enddate :$enddate";
1505 WHERE subscriptionid
=?
1507 $sth = $dbh->prepare($query);
1508 $sth->execute( $enddate, $subscriptionid );
1510 logaction
( "SERIAL", "RENEW", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1516 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1518 Create a new issue stored on the database.
1519 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1520 returns the serial id
1525 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate,
1526 $publisheddate, $publisheddatetext, $notes ) = @_;
1527 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1529 return unless ($subscriptionid);
1531 my $schema = Koha
::Database
->new()->schema();
1533 my $subscription = Koha
::Subscriptions
->find( $subscriptionid );
1535 my $serial = Koha
::Serial
->new(
1537 serialseq
=> $serialseq,
1538 serialseq_x
=> $subscription->lastvalue1(),
1539 serialseq_y
=> $subscription->lastvalue2(),
1540 serialseq_z
=> $subscription->lastvalue3(),
1541 subscriptionid
=> $subscriptionid,
1542 biblionumber
=> $biblionumber,
1544 planneddate
=> $planneddate,
1545 publisheddate
=> $publisheddate,
1546 publisheddatetext
=> $publisheddatetext,
1551 my $serialid = $serial->id();
1553 my $subscription_history = Koha
::Subscription
::Histories
->find($subscriptionid);
1554 my $missinglist = $subscription_history->missinglist();
1555 my $recievedlist = $subscription_history->recievedlist();
1557 if ( $status == ARRIVED
) {
1558 ### TODO Add a feature that improves recognition and description.
1559 ### As such count (serialseq) i.e. : N18,2(N19),N20
1560 ### Would use substr and index But be careful to previous presence of ()
1561 $recievedlist .= "; $serialseq" unless ( index( $recievedlist, $serialseq ) > 0 );
1563 if ( grep { /^$status$/ } (MISSING_STATUSES
) ) {
1564 $missinglist .= "; $serialseq" unless ( index( $missinglist, $serialseq ) > 0 );
1567 $recievedlist =~ s/^; //;
1568 $missinglist =~ s/^; //;
1570 $subscription_history->recievedlist($recievedlist);
1571 $subscription_history->missinglist($missinglist);
1572 $subscription_history->store();
1577 =head2 HasSubscriptionStrictlyExpired
1579 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1581 the subscription has stricly expired when today > the end subscription date
1584 1 if true, 0 if false, -1 if the expiration date is not set.
1588 sub HasSubscriptionStrictlyExpired
{
1590 # Getting end of subscription date
1591 my ($subscriptionid) = @_;
1593 return unless ($subscriptionid);
1595 my $dbh = C4
::Context
->dbh;
1596 my $subscription = GetSubscription
($subscriptionid);
1597 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1599 # If the expiration date is set
1600 if ( $expirationdate != 0 ) {
1601 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1603 # Getting today's date
1604 my ( $nowyear, $nowmonth, $nowday ) = Today
();
1606 # if today's date > expiration date, then the subscription has stricly expired
1607 if ( Delta_Days
( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1614 # There are some cases where the expiration date is not set
1615 # As we can't determine if the subscription has expired on a date-basis,
1621 =head2 HasSubscriptionExpired
1623 $has_expired = HasSubscriptionExpired($subscriptionid)
1625 the subscription has expired when the next issue to arrive is out of subscription limit.
1628 0 if the subscription has not expired
1629 1 if the subscription has expired
1630 2 if has subscription does not have a valid expiration date set
1634 sub HasSubscriptionExpired
{
1635 my ($subscriptionid) = @_;
1637 return unless ($subscriptionid);
1639 my $dbh = C4
::Context
->dbh;
1640 my $subscription = GetSubscription
($subscriptionid);
1641 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1642 if ( $frequency and $frequency->{unit
} ) {
1643 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1644 if (!defined $expirationdate) {
1645 $expirationdate = q{};
1648 SELECT max
(planneddate
)
1650 WHERE subscriptionid
=?
1652 my $sth = $dbh->prepare($query);
1653 $sth->execute($subscriptionid);
1654 my ($res) = $sth->fetchrow;
1655 if (!$res || $res=~m/^0000/) {
1658 my @res = split( /-/, $res );
1659 my @endofsubscriptiondate = split( /-/, $expirationdate );
1660 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date
(@res) || not check_date
(@endofsubscriptiondate) );
1662 if ( ( @endofsubscriptiondate && Delta_Days
( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1667 if ( $subscription->{'numberlength'} ) {
1668 my $countreceived = countissuesfrom
( $subscriptionid, $subscription->{'startdate'} );
1669 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1675 return 0; # Notice that you'll never get here.
1678 =head2 DelSubscription
1680 DelSubscription($subscriptionid)
1681 this function deletes subscription which has $subscriptionid as id.
1685 sub DelSubscription
{
1686 my ($subscriptionid) = @_;
1687 my $dbh = C4
::Context
->dbh;
1688 $dbh->do("DELETE FROM subscription WHERE subscriptionid=?", undef, $subscriptionid);
1689 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=?", undef, $subscriptionid);
1690 $dbh->do("DELETE FROM serial WHERE subscriptionid=?", undef, $subscriptionid);
1692 my $afs = Koha
::AdditionalField
->all({tablename
=> 'subscription'});
1693 foreach my $af (@
$afs) {
1694 $af->delete_values({record_id
=> $subscriptionid});
1697 logaction
( "SERIAL", "DELETE", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1702 DelIssue($serialseq,$subscriptionid)
1703 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1705 returns the number of rows affected
1710 my ($dataissue) = @_;
1711 my $dbh = C4
::Context
->dbh;
1712 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1717 AND subscriptionid
= ?
1719 my $mainsth = $dbh->prepare($query);
1720 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1722 #Delete element from subscription history
1723 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1724 my $sth = $dbh->prepare($query);
1725 $sth->execute( $dataissue->{'subscriptionid'} );
1726 my $val = $sth->fetchrow_hashref;
1727 unless ( $val->{manualhistory
} ) {
1729 SELECT
* FROM subscriptionhistory
1730 WHERE subscriptionid
= ?
1732 my $sth = $dbh->prepare($query);
1733 $sth->execute( $dataissue->{'subscriptionid'} );
1734 my $data = $sth->fetchrow_hashref;
1735 my $serialseq = $dataissue->{'serialseq'};
1736 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1737 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1738 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1739 $sth = $dbh->prepare($strsth);
1740 $sth->execute( $dataissue->{'subscriptionid'} );
1743 return $mainsth->rows;
1746 =head2 GetLateOrMissingIssues
1748 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1750 this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
1753 the issuelist as an array of hash refs. Each element of this array contains
1754 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1758 sub GetLateOrMissingIssues
{
1759 my ( $supplierid, $serialid, $order ) = @_;
1761 return unless ( $supplierid or $serialid );
1763 my $dbh = C4
::Context
->dbh;
1768 $byserial = "and serialid = " . $serialid;
1771 $order .= ", title";
1775 my $missing_statuses_string = join ',', (MISSING_STATUSES
);
1777 $sth = $dbh->prepare(
1779 serialid, aqbooksellerid, name,
1780 biblio.title, biblioitems.issn, planneddate, serialseq,
1781 serial.status, serial.subscriptionid, claimdate, claims_count,
1782 subscription.branchcode
1784 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1785 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1786 LEFT JOIN biblioitems ON subscription.biblionumber=biblioitems.biblionumber
1787 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1788 WHERE subscription.subscriptionid = serial.subscriptionid
1789 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1790 AND subscription.aqbooksellerid=$supplierid
1795 $sth = $dbh->prepare(
1797 serialid, aqbooksellerid, name,
1798 biblio.title, planneddate, serialseq,
1799 serial.status, serial.subscriptionid, claimdate, claims_count,
1800 subscription.branchcode
1802 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1803 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1804 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1805 WHERE subscription.subscriptionid = serial.subscriptionid
1806 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1811 $sth->execute( EXPECTED
, LATE
, CLAIMED
);
1813 while ( my $line = $sth->fetchrow_hashref ) {
1815 if ($line->{planneddate
} && $line->{planneddate
} !~/^0+\-/) {
1816 $line->{planneddateISO
} = $line->{planneddate
};
1817 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{"planneddate"} ), dateonly
=> 1 } );
1819 if ($line->{claimdate
} && $line->{claimdate
} !~/^0+\-/) {
1820 $line->{claimdateISO
} = $line->{claimdate
};
1821 $line->{claimdate
} = output_pref
( { dt
=> dt_from_string
( $line->{"claimdate"} ), dateonly
=> 1 } );
1823 $line->{"status".$line->{status
}} = 1;
1825 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
1826 record_id
=> $line->{subscriptionid
},
1827 tablename
=> 'subscription'
1829 %$line = ( %$line, additional_fields
=> $additional_field_values->{$line->{subscriptionid
}} );
1831 push @issuelist, $line;
1838 &updateClaim($serialid)
1840 this function updates the time when a claim is issued for late/missing items
1842 called from claims.pl file
1847 my ($serialids) = @_;
1848 return unless $serialids;
1849 unless ( ref $serialids ) {
1850 $serialids = [ $serialids ];
1852 my $dbh = C4
::Context
->dbh;
1855 SET claimdate
= NOW
(),
1856 claims_count
= claims_count
+ 1,
1858 WHERE serialid
in (| . join( q
|,|, (q
|?
|) x @
$serialids ) . q
|)|,
1859 {}, CLAIMED
, @
$serialids );
1862 =head2 check_routing
1864 $result = &check_routing($subscriptionid)
1866 this function checks to see if a serial has a routing list and returns the count of routingid
1867 used to show either an 'add' or 'edit' link
1872 my ($subscriptionid) = @_;
1874 return unless ($subscriptionid);
1876 my $dbh = C4
::Context
->dbh;
1877 my $sth = $dbh->prepare(
1878 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1879 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1880 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
1883 $sth->execute($subscriptionid);
1884 my $line = $sth->fetchrow_hashref;
1885 my $result = $line->{'routingids'};
1889 =head2 addroutingmember
1891 addroutingmember($borrowernumber,$subscriptionid)
1893 this function takes a borrowernumber and subscriptionid and adds the member to the
1894 routing list for that serial subscription and gives them a rank on the list
1895 of either 1 or highest current rank + 1
1899 sub addroutingmember
{
1900 my ( $borrowernumber, $subscriptionid ) = @_;
1902 return unless ($borrowernumber and $subscriptionid);
1905 my $dbh = C4
::Context
->dbh;
1906 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1907 $sth->execute($subscriptionid);
1908 while ( my $line = $sth->fetchrow_hashref ) {
1909 if ( $line->{'rank'} > 0 ) {
1910 $rank = $line->{'rank'} + 1;
1915 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1916 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1919 =head2 reorder_members
1921 reorder_members($subscriptionid,$routingid,$rank)
1923 this function is used to reorder the routing list
1925 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1926 - it gets all members on list puts their routingid's into an array
1927 - removes the one in the array that is $routingid
1928 - then reinjects $routingid at point indicated by $rank
1929 - then update the database with the routingids in the new order
1933 sub reorder_members
{
1934 my ( $subscriptionid, $routingid, $rank ) = @_;
1935 my $dbh = C4
::Context
->dbh;
1936 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1937 $sth->execute($subscriptionid);
1939 while ( my $line = $sth->fetchrow_hashref ) {
1940 push( @result, $line->{'routingid'} );
1943 # To find the matching index
1945 my $key = -1; # to allow for 0 being a valid response
1946 for ( $i = 0 ; $i < @result ; $i++ ) {
1947 if ( $routingid == $result[$i] ) {
1948 $key = $i; # save the index
1953 # if index exists in array then move it to new position
1954 if ( $key > -1 && $rank > 0 ) {
1955 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1956 my $moving_item = splice( @result, $key, 1 );
1957 splice( @result, $new_rank, 0, $moving_item );
1959 for ( my $j = 0 ; $j < @result ; $j++ ) {
1960 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1966 =head2 delroutingmember
1968 delroutingmember($routingid,$subscriptionid)
1970 this function either deletes one member from routing list if $routingid exists otherwise
1971 deletes all members from the routing list
1975 sub delroutingmember
{
1977 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
1978 my ( $routingid, $subscriptionid ) = @_;
1979 my $dbh = C4
::Context
->dbh;
1981 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
1982 $sth->execute($routingid);
1983 reorder_members
( $subscriptionid, $routingid );
1985 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
1986 $sth->execute($subscriptionid);
1991 =head2 getroutinglist
1993 @routinglist = getroutinglist($subscriptionid)
1995 this gets the info from the subscriptionroutinglist for $subscriptionid
1998 the routinglist as an array. Each element of the array contains a hash_ref containing
1999 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2003 sub getroutinglist
{
2004 my ($subscriptionid) = @_;
2005 my $dbh = C4
::Context
->dbh;
2006 my $sth = $dbh->prepare(
2007 'SELECT routingid, borrowernumber, ranking, biblionumber
2009 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2010 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2012 $sth->execute($subscriptionid);
2013 my $routinglist = $sth->fetchall_arrayref({});
2014 return @
{$routinglist};
2017 =head2 countissuesfrom
2019 $result = countissuesfrom($subscriptionid,$startdate)
2021 Returns a count of serial rows matching the given subsctiptionid
2022 with published date greater than startdate
2026 sub countissuesfrom
{
2027 my ( $subscriptionid, $startdate ) = @_;
2028 my $dbh = C4
::Context
->dbh;
2032 WHERE subscriptionid
=?
2033 AND serial
.publisheddate
>?
2035 my $sth = $dbh->prepare($query);
2036 $sth->execute( $subscriptionid, $startdate );
2037 my ($countreceived) = $sth->fetchrow;
2038 return $countreceived;
2043 $result = CountIssues($subscriptionid)
2045 Returns a count of serial rows matching the given subsctiptionid
2050 my ($subscriptionid) = @_;
2051 my $dbh = C4
::Context
->dbh;
2055 WHERE subscriptionid
=?
2057 my $sth = $dbh->prepare($query);
2058 $sth->execute($subscriptionid);
2059 my ($countreceived) = $sth->fetchrow;
2060 return $countreceived;
2065 $result = HasItems($subscriptionid)
2067 returns a count of items from serial matching the subscriptionid
2072 my ($subscriptionid) = @_;
2073 my $dbh = C4
::Context
->dbh;
2075 SELECT COUNT
(serialitems
.itemnumber
)
2077 LEFT JOIN serialitems USING
(serialid
)
2078 WHERE subscriptionid
=? AND serialitems
.serialid IS NOT NULL
2080 my $sth=$dbh->prepare($query);
2081 $sth->execute($subscriptionid);
2082 my ($countitems)=$sth->fetchrow_array();
2086 =head2 abouttoexpire
2088 $result = abouttoexpire($subscriptionid)
2090 this function alerts you to the penultimate issue for a serial subscription
2092 returns 1 - if this is the penultimate issue
2098 my ($subscriptionid) = @_;
2099 my $dbh = C4
::Context
->dbh;
2100 my $subscription = GetSubscription
($subscriptionid);
2101 my $per = $subscription->{'periodicity'};
2102 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($per);
2103 if ($frequency and $frequency->{unit
}){
2105 my $expirationdate = GetExpirationDate
($subscriptionid);
2107 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2108 my $nextdate = GetNextDate
($subscription, $res);
2110 # only compare dates if both dates exist.
2111 if ($nextdate and $expirationdate) {
2112 if(Date
::Calc
::Delta_Days
(
2113 split( /-/, $nextdate ),
2114 split( /-/, $expirationdate )
2120 } elsif ($subscription->{numberlength
}>0) {
2121 return (countissuesfrom
($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength
}-1);
2127 =head2 GetFictiveIssueNumber
2129 $issueno = GetFictiveIssueNumber($subscription, $publishedate);
2131 Get the position of the issue published at $publisheddate, considering the
2132 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2133 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2134 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2135 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2136 depending on how many rows are in serial table.
2137 The issue number calculation is based on subscription frequency, first acquisition
2138 date, and $publisheddate.
2140 Returns undef when called for irregular frequencies.
2142 The routine is used to skip irregularities when calculating the next issue
2143 date (in GetNextDate) or the next issue number (in GetNextSeq).
2147 sub GetFictiveIssueNumber
{
2148 my ($subscription, $publisheddate) = @_;
2150 my $frequency = GetSubscriptionFrequency
($subscription->{'periodicity'});
2151 my $unit = $frequency->{unit
} ?
lc $frequency->{'unit'} : undef;
2155 my ( $year, $month, $day ) = split /-/, $publisheddate;
2156 my ( $fa_year, $fa_month, $fa_day ) = split /-/, $subscription->{'firstacquidate'};
2157 my $delta = _delta_units
( [$fa_year, $fa_month, $fa_day], [$year, $month, $day], $unit );
2159 if( $frequency->{'unitsperissue'} == 1 ) {
2160 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2161 } else { # issuesperunit == 1
2162 $issueno = 1 + int( $delta / $frequency->{'unitsperissue'} );
2168 my ( $date1, $date2, $unit ) = @_;
2169 # date1 and date2 are array refs in the form [ yy, mm, dd ]
2171 if( $unit eq 'day' ) {
2172 return Delta_Days
( @
$date1, @
$date2 );
2173 } elsif( $unit eq 'week' ) {
2174 return int( Delta_Days
( @
$date1, @
$date2 ) / 7 );
2177 # In case of months or years, this is a wrapper around N_Delta_YMD.
2178 # Note that N_Delta_YMD returns 29 days between e.g. 22-2-72 and 22-3-72
2179 # while we expect 1 month.
2180 my @delta = N_Delta_YMD
( @
$date1, @
$date2 );
2181 if( $delta[2] > 27 ) {
2182 # Check if we could add a month
2183 my @jump = Add_Delta_YM
( @
$date1, $delta[0], 1 + $delta[1] );
2184 if( Delta_Days
( @jump, @
$date2 ) >= 0 ) {
2188 if( $delta[1] >= 12 ) {
2192 # if unit is year, we only return full years
2193 return $unit eq 'month' ?
$delta[0] * 12 + $delta[1] : $delta[0];
2196 sub _get_next_date_day
{
2197 my ($subscription, $freqdata, $year, $month, $day) = @_;
2199 my @newissue; # ( yy, mm, dd )
2200 # We do not need $delta_days here, since it would be zero where used
2202 if( $freqdata->{issuesperunit
} == 1 ) {
2204 @newissue = Add_Delta_Days
(
2205 $year, $month, $day, $freqdata->{"unitsperissue"} );
2206 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2208 @newissue = ( $year, $month, $day );
2209 $subscription->{countissuesperunit
}++;
2211 # We finished a cycle of issues within a unit.
2212 # No subtraction of zero needed, just add one day
2213 @newissue = Add_Delta_Days
( $year, $month, $day, 1 );
2214 $subscription->{countissuesperunit
} = 1;
2219 sub _get_next_date_week
{
2220 my ($subscription, $freqdata, $year, $month, $day) = @_;
2222 my @newissue; # ( yy, mm, dd )
2223 my $delta_days = int( 7 / $freqdata->{issuesperunit
} );
2225 if( $freqdata->{issuesperunit
} == 1 ) {
2226 # Add full weeks (of 7 days)
2227 @newissue = Add_Delta_Days
(
2228 $year, $month, $day, 7 * $freqdata->{"unitsperissue"} );
2229 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2230 # Add rounded number of days based on frequency.
2231 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2232 $subscription->{countissuesperunit
}++;
2234 # We finished a cycle of issues within a unit.
2235 # Subtract delta * (issues - 1), add 1 week
2236 @newissue = Add_Delta_Days
( $year, $month, $day,
2237 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2238 @newissue = Add_Delta_Days
( @newissue, 7 );
2239 $subscription->{countissuesperunit
} = 1;
2244 sub _get_next_date_month
{
2245 my ($subscription, $freqdata, $year, $month, $day) = @_;
2247 my @newissue; # ( yy, mm, dd )
2248 my $delta_days = int( 30 / $freqdata->{issuesperunit
} );
2250 if( $freqdata->{issuesperunit
} == 1 ) {
2252 @newissue = Add_Delta_YM
(
2253 $year, $month, $day, 0, $freqdata->{"unitsperissue"} );
2254 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2255 # Add rounded number of days based on frequency.
2256 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2257 $subscription->{countissuesperunit
}++;
2259 # We finished a cycle of issues within a unit.
2260 # Subtract delta * (issues - 1), add 1 month
2261 @newissue = Add_Delta_Days
( $year, $month, $day,
2262 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2263 @newissue = Add_Delta_YM
( @newissue, 0, 1 );
2264 $subscription->{countissuesperunit
} = 1;
2269 sub _get_next_date_year
{
2270 my ($subscription, $freqdata, $year, $month, $day) = @_;
2272 my @newissue; # ( yy, mm, dd )
2273 my $delta_days = int( 365 / $freqdata->{issuesperunit
} );
2275 if( $freqdata->{issuesperunit
} == 1 ) {
2277 @newissue = Add_Delta_YM
( $year, $month, $day, $freqdata->{"unitsperissue"}, 0 );
2278 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2279 # Add rounded number of days based on frequency.
2280 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2281 $subscription->{countissuesperunit
}++;
2283 # We finished a cycle of issues within a unit.
2284 # Subtract delta * (issues - 1), add 1 year
2285 @newissue = Add_Delta_Days
( $year, $month, $day, -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2286 @newissue = Add_Delta_YM
( @newissue, 1, 0 );
2287 $subscription->{countissuesperunit
} = 1;
2294 $resultdate = GetNextDate($publisheddate,$subscription)
2296 this function it takes the publisheddate and will return the next issue's date
2297 and will skip dates if there exists an irregularity.
2298 $publisheddate has to be an ISO date
2299 $subscription is a hashref containing at least 'periodicity', 'firstacquidate', 'irregularity', and 'countissuesperunit'
2300 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2301 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2302 skipped then the returned date will be 2007-05-10
2305 $resultdate - then next date in the sequence (ISO date)
2307 Return undef if subscription is irregular
2312 my ( $subscription, $publisheddate, $updatecount ) = @_;
2314 return unless $subscription and $publisheddate;
2316 my $freqdata = GetSubscriptionFrequency
($subscription->{'periodicity'});
2318 if ($freqdata->{'unit'}) {
2319 my ( $year, $month, $day ) = split /-/, $publisheddate;
2321 # Process an irregularity Hash
2322 # Suppose that irregularities are stored in a string with this structure
2323 # irreg1;irreg2;irreg3
2324 # where irregX is the number of issue which will not be received
2325 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2327 if ( $subscription->{irregularity
} ) {
2328 my @irreg = split /;/, $subscription->{'irregularity'} ;
2329 foreach my $irregularity (@irreg) {
2330 $irregularities{$irregularity} = 1;
2334 # Get the 'fictive' next issue number
2335 # It is used to check if next issue is an irregular issue.
2336 my $issueno = GetFictiveIssueNumber
($subscription, $publisheddate) + 1;
2338 # Then get the next date
2339 my $unit = lc $freqdata->{'unit'};
2340 if ($unit eq 'day') {
2341 while ($irregularities{$issueno}) {
2342 ($year, $month, $day) = _get_next_date_day
($subscription,
2343 $freqdata, $year, $month, $day);
2346 ($year, $month, $day) = _get_next_date_day
($subscription, $freqdata,
2347 $year, $month, $day);
2349 elsif ($unit eq 'week') {
2350 while ($irregularities{$issueno}) {
2351 ($year, $month, $day) = _get_next_date_week
($subscription,
2352 $freqdata, $year, $month, $day);
2355 ($year, $month, $day) = _get_next_date_week
($subscription,
2356 $freqdata, $year, $month, $day);
2358 elsif ($unit eq 'month') {
2359 while ($irregularities{$issueno}) {
2360 ($year, $month, $day) = _get_next_date_month
($subscription,
2361 $freqdata, $year, $month, $day);
2364 ($year, $month, $day) = _get_next_date_month
($subscription,
2365 $freqdata, $year, $month, $day);
2367 elsif ($unit eq 'year') {
2368 while ($irregularities{$issueno}) {
2369 ($year, $month, $day) = _get_next_date_year
($subscription,
2370 $freqdata, $year, $month, $day);
2373 ($year, $month, $day) = _get_next_date_year
($subscription,
2374 $freqdata, $year, $month, $day);
2378 my $dbh = C4
::Context
->dbh;
2381 SET countissuesperunit
= ?
2382 WHERE subscriptionid
= ?
2384 my $sth = $dbh->prepare($query);
2385 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2388 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2394 $string = &_numeration($value,$num_type,$locale);
2396 _numeration returns the string corresponding to $value in the num_type
2408 my ($value, $num_type, $locale) = @_;
2413 if ( $num_type =~ /^dayname$/ or $num_type =~ /^dayabrv$/ ) {
2414 # 1970-11-01 was a Sunday
2415 $value = $value % 7;
2416 my $dt = DateTime
->new(
2422 $string = $num_type =~ /^dayname$/
2423 ?
$dt->strftime("%A")
2424 : $dt->strftime("%a");
2425 } elsif ( $num_type =~ /^monthname$/ or $num_type =~ /^monthabrv$/ ) {
2426 $value = $value % 12;
2427 my $dt = DateTime
->new(
2429 month
=> $value + 1,
2432 $string = $num_type =~ /^monthname$/
2433 ?
$dt->strftime("%B")
2434 : $dt->strftime("%b");
2435 } elsif ( $num_type =~ /^season$/ ) {
2436 my @seasons= qw( Spring Summer Fall Winter );
2437 $value = $value % 4;
2438 $string = $seasons[$value];
2439 } elsif ( $num_type =~ /^seasonabrv$/ ) {
2440 my @seasonsabrv= qw( Spr Sum Fal Win );
2441 $value = $value % 4;
2442 $string = $seasonsabrv[$value];
2450 =head2 CloseSubscription
2452 Close a subscription given a subscriptionid
2456 sub CloseSubscription
{
2457 my ( $subscriptionid ) = @_;
2458 return unless $subscriptionid;
2459 my $dbh = C4
::Context
->dbh;
2460 my $sth = $dbh->prepare( q{
2463 WHERE subscriptionid = ?
2465 $sth->execute( $subscriptionid );
2467 # Set status = missing when status = stopped
2468 $sth = $dbh->prepare( q{
2471 WHERE subscriptionid = ?
2474 $sth->execute( STOPPED
, $subscriptionid, EXPECTED
);
2477 =head2 ReopenSubscription
2479 Reopen a subscription given a subscriptionid
2483 sub ReopenSubscription
{
2484 my ( $subscriptionid ) = @_;
2485 return unless $subscriptionid;
2486 my $dbh = C4
::Context
->dbh;
2487 my $sth = $dbh->prepare( q{
2490 WHERE subscriptionid = ?
2492 $sth->execute( $subscriptionid );
2494 # Set status = expected when status = stopped
2495 $sth = $dbh->prepare( q{
2498 WHERE subscriptionid = ?
2501 $sth->execute( EXPECTED
, $subscriptionid, STOPPED
);
2504 =head2 subscriptionCurrentlyOnOrder
2506 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2508 Return 1 if subscription is currently on order else 0.
2512 sub subscriptionCurrentlyOnOrder
{
2513 my ( $subscriptionid ) = @_;
2514 my $dbh = C4
::Context
->dbh;
2516 SELECT COUNT
(*) FROM aqorders
2517 WHERE subscriptionid
= ?
2518 AND datereceived IS NULL
2519 AND datecancellationprinted IS NULL
2521 my $sth = $dbh->prepare( $query );
2522 $sth->execute($subscriptionid);
2523 return $sth->fetchrow_array;
2526 =head2 can_claim_subscription
2528 $can = can_claim_subscription( $subscriptionid[, $userid] );
2530 Return 1 if the subscription can be claimed by the current logged user (or a given $userid), else 0.
2534 sub can_claim_subscription
{
2535 my ( $subscription, $userid ) = @_;
2536 return _can_do_on_subscription
( $subscription, $userid, 'claim_serials' );
2539 =head2 can_edit_subscription
2541 $can = can_edit_subscription( $subscriptionid[, $userid] );
2543 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2547 sub can_edit_subscription
{
2548 my ( $subscription, $userid ) = @_;
2549 return _can_do_on_subscription
( $subscription, $userid, 'edit_subscription' );
2552 =head2 can_show_subscription
2554 $can = can_show_subscription( $subscriptionid[, $userid] );
2556 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2560 sub can_show_subscription
{
2561 my ( $subscription, $userid ) = @_;
2562 return _can_do_on_subscription
( $subscription, $userid, '*' );
2565 sub _can_do_on_subscription
{
2566 my ( $subscription, $userid, $permission ) = @_;
2567 return 0 unless C4
::Context
->userenv;
2568 my $flags = C4
::Context
->userenv->{flags
};
2569 $userid ||= C4
::Context
->userenv->{'id'};
2571 if ( C4
::Context
->preference('IndependentBranches') ) {
2573 if C4
::Context
->IsSuperLibrarian()
2575 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2577 C4
::Auth
::haspermission
( $userid,
2578 { serials
=> $permission } )
2579 and ( not defined $subscription->{branchcode
}
2580 or $subscription->{branchcode
} eq ''
2581 or $subscription->{branchcode
} eq
2582 C4
::Context
->userenv->{'branch'} )
2587 if C4
::Context
->IsSuperLibrarian()
2589 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2590 or C4
::Auth
::haspermission
(
2591 $userid, { serials
=> $permission }
2598 =head2 findSerialsByStatus
2600 @serials = findSerialsByStatus($status, $subscriptionid);
2602 Returns an array of serials matching a given status and subscription id.
2606 sub findSerialsByStatus
{
2607 my ( $status, $subscriptionid ) = @_;
2608 my $dbh = C4
::Context
->dbh;
2609 my $query = q
| SELECT
* from serial
2611 AND subscriptionid
= ?
2613 my $serials = $dbh->selectall_arrayref( $query, { Slice
=> {} }, $status, $subscriptionid );
2622 Koha Development Team <http://koha-community.org/>