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
::AdditionalFieldValues
;
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 if ( my $mana_id = $subscription->{mana_id
} ) {
278 my $mana_subscription = Koha
::SharedContent
::get_entity_by_id
(
279 'subscription', $mana_id, {usecomments
=> 1});
280 $subscription->{comments
} = $mana_subscription->{data
}->{comments
};
283 return $subscription;
286 =head2 GetFullSubscription
288 $array_ref = GetFullSubscription($subscriptionid)
289 this function reads the serial table.
293 sub GetFullSubscription
{
294 my ($subscriptionid) = @_;
296 return unless ($subscriptionid);
298 my $dbh = C4
::Context
->dbh;
300 SELECT serial
.serialid
,
303 serial
.publisheddate
,
304 serial
.publisheddatetext
,
306 serial
.notes as notes
,
307 year
(IF
(serial
.publisheddate IS NULL
,serial
.publisheddate
,serial
.planneddate
)) as year
,
308 aqbooksellers
.name as aqbooksellername
,
309 biblio
.title as bibliotitle
,
310 subscription
.branchcode AS branchcode
,
311 subscription
.subscriptionid AS subscriptionid
313 LEFT JOIN subscription ON
314 (serial
.subscriptionid
=subscription
.subscriptionid
)
315 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
316 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
317 WHERE serial
.subscriptionid
= ?
319 IF
(serial
.publisheddate IS NULL
,serial
.publisheddate
,serial
.planneddate
) DESC
,
320 serial
.subscriptionid
322 $debug and warn "GetFullSubscription query: $query";
323 my $sth = $dbh->prepare($query);
324 $sth->execute($subscriptionid);
325 my $subscriptions = $sth->fetchall_arrayref( {} );
326 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
327 for my $subscription ( @
$subscriptions ) {
328 $subscription->{cannotedit
} = $cannotedit;
330 return $subscriptions;
333 =head2 PrepareSerialsData
335 $array_ref = PrepareSerialsData($serialinfomation)
336 where serialinformation is a hashref array
340 sub PrepareSerialsData
{
343 return unless ($lines);
349 my $aqbooksellername;
353 my $previousnote = "";
355 foreach my $subs (@
{$lines}) {
356 for my $datefield ( qw(publisheddate planneddate) ) {
357 # handle 0000-00-00 dates
358 if (defined $subs->{$datefield} and $subs->{$datefield} =~ m/^00/) {
359 $subs->{$datefield} = undef;
362 $subs->{ "status" . $subs->{'status'} } = 1;
363 if ( grep { $_ == $subs->{status
} } ( EXPECTED
, LATE
, MISSING_STATUSES
, CLAIMED
) ) {
364 $subs->{"checked"} = 1;
367 if ( $subs->{'year'} && $subs->{'year'} ne "" ) {
368 $year = $subs->{'year'};
372 if ( $tmpresults{$year} ) {
373 push @
{ $tmpresults{$year}->{'serials'} }, $subs;
375 $tmpresults{$year} = {
377 'aqbooksellername' => $subs->{'aqbooksellername'},
378 'bibliotitle' => $subs->{'bibliotitle'},
379 'serials' => [$subs],
384 foreach my $key ( sort { $b cmp $a } keys %tmpresults ) {
385 push @res, $tmpresults{$key};
390 =head2 GetSubscriptionsFromBiblionumber
392 $array_ref = GetSubscriptionsFromBiblionumber($biblionumber)
393 this function get the subscription list. it reads the subscription table.
395 reference to an array of subscriptions which have the biblionumber given on input arg.
396 each element of this array is a hashref containing
397 startdate, histstartdate,opacnote,missinglist,recievedlist,periodicity,status & enddate
401 sub GetSubscriptionsFromBiblionumber
{
402 my ($biblionumber) = @_;
404 return unless ($biblionumber);
406 my $dbh = C4
::Context
->dbh;
408 SELECT subscription
.*,
410 subscriptionhistory
.*,
411 aqbooksellers
.name AS aqbooksellername
,
412 biblio
.title AS bibliotitle
414 LEFT JOIN subscriptionhistory ON subscription
.subscriptionid
=subscriptionhistory
.subscriptionid
415 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
=aqbooksellers
.id
416 LEFT JOIN biblio ON biblio
.biblionumber
=subscription
.biblionumber
417 LEFT JOIN branches ON branches
.branchcode
=subscription
.branchcode
418 WHERE subscription
.biblionumber
= ?
420 my $sth = $dbh->prepare($query);
421 $sth->execute($biblionumber);
423 while ( my $subs = $sth->fetchrow_hashref ) {
424 $subs->{startdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{startdate
} ), dateonly
=> 1 } );
425 $subs->{histstartdate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histstartdate
} ), dateonly
=> 1 } );
426 if ( defined $subs->{histenddate
} ) {
427 $subs->{histenddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{histenddate
} ), dateonly
=> 1 } );
429 $subs->{histenddate
} = "";
431 $subs->{opacnote
} //= "";
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 IS NULL
,serial
.publisheddate
,serial
.planneddate
)) 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 IS NULL
,serial
.publisheddate
,serial
.planneddate
) 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 my @subscriptions = Koha
::Subscriptions
->filter_by_additional_fields($additional_fields);
525 return () unless @subscriptions;
527 $matching_record_ids_for_additional_fields = [ map {
534 subscription
.notes AS publicnotes
,
535 subscriptionhistory
.*,
537 biblio
.notes AS biblionotes
,
541 aqbooksellers
.name AS vendorname
,
544 LEFT JOIN subscriptionhistory USING
(subscriptionid
)
545 LEFT JOIN biblio ON biblio
.biblionumber
= subscription
.biblionumber
546 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= subscription
.biblionumber
547 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
549 $query .= q
| WHERE
1|;
552 if( $args->{biblionumber
} ) {
553 push @where_strs, "biblio.biblionumber = ?";
554 push @where_args, $args->{biblionumber
};
557 if( $args->{title
} ){
558 my @words = split / /, $args->{title
};
560 foreach my $word (@words) {
561 push @strs, "biblio.title LIKE ?";
562 push @args, "%$word%";
565 push @where_strs, '(' . join (' AND ', @strs) . ')';
566 push @where_args, @args;
570 push @where_strs, "biblioitems.issn LIKE ?";
571 push @where_args, "%$args->{issn}%";
574 push @where_strs, "biblioitems.ean LIKE ?";
575 push @where_args, "%$args->{ean}%";
577 if ( $args->{callnumber
} ) {
578 push @where_strs, "subscription.callnumber LIKE ?";
579 push @where_args, "%$args->{callnumber}%";
581 if( $args->{publisher
} ){
582 push @where_strs, "biblioitems.publishercode LIKE ?";
583 push @where_args, "%$args->{publisher}%";
585 if( $args->{bookseller
} ){
586 push @where_strs, "aqbooksellers.name LIKE ?";
587 push @where_args, "%$args->{bookseller}%";
589 if( $args->{branch
} ){
590 push @where_strs, "subscription.branchcode = ?";
591 push @where_args, "$args->{branch}";
593 if ( $args->{location
} ) {
594 push @where_strs, "subscription.location = ?";
595 push @where_args, "$args->{location}";
597 if ( $args->{expiration_date
} ) {
598 push @where_strs, "subscription.enddate <= ?";
599 push @where_args, "$args->{expiration_date}";
601 if( defined $args->{closed
} ){
602 push @where_strs, "subscription.closed = ?";
603 push @where_args, "$args->{closed}";
607 $query .= ' AND ' . join(' AND ', @where_strs);
609 if ( @
$additional_fields ) {
610 $query .= ' AND subscriptionid IN ('
611 . join( ', ', @
$matching_record_ids_for_additional_fields )
615 $query .= " ORDER BY " . $args->{orderby
} if $args->{orderby
};
617 my $dbh = C4
::Context
->dbh;
618 my $sth = $dbh->prepare($query);
619 $sth->execute(@where_args);
620 my $results = $sth->fetchall_arrayref( {} );
622 for my $subscription ( @
$results ) {
623 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
624 $subscription->{cannotdisplay
} = not can_show_subscription
( $subscription );
626 my $subscription_object = Koha
::Subscriptions
->find($subscription->{subscriptionid
});
627 $subscription->{additional_fields
} = { map { $_->field->name => $_->value }
628 $subscription_object->additional_field_values->as_list };
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 IS NULL,planneddate,publisheddate) 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 IS NULL,planneddate,publisheddate) 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 push @serials, $line;
792 =head2 GetPreviousSerialid
794 $serialid = GetPreviousSerialid($subscriptionid, $nth)
795 get the $nth's previous serial for the given subscriptionid
801 sub GetPreviousSerialid
{
802 my ( $subscriptionid, $nth ) = @_;
804 my $dbh = C4
::Context
->dbh;
808 my $strsth = "SELECT serialid
810 WHERE subscriptionid = ?
812 ORDER BY serialid DESC LIMIT $nth,1
814 my $sth = $dbh->prepare($strsth);
815 $sth->execute($subscriptionid);
817 my $line = $sth->fetchrow_hashref;
818 $return = $line->{'serialid'} if ($line);
826 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
827 $newinnerloop1, $newinnerloop2, $newinnerloop3
828 ) = GetNextSeq( $subscription, $pattern, $frequency, $planneddate );
830 $subscription is a hashref containing all the attributes of the table
832 $pattern is a hashref containing all the attributes of the table
833 'subscription_numberpatterns'.
834 $frequency is a hashref containing all the attributes of the table 'subscription_frequencies'
835 $planneddate is a date string in iso format.
836 This function get the next issue for the subscription given on input arg
841 my ($subscription, $pattern, $frequency, $planneddate) = @_;
843 return unless ($subscription and $pattern);
845 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
846 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
849 if ($subscription->{'skip_serialseq'}) {
850 my @irreg = split /;/, $subscription->{'irregularity'};
852 my $irregularities = {};
853 $irregularities->{$_} = 1 foreach(@irreg);
854 my $issueno = GetFictiveIssueNumber
($subscription, $planneddate, $frequency) + 1;
855 while($irregularities->{$issueno}) {
862 my $numberingmethod = $pattern->{numberingmethod
};
864 if ($numberingmethod) {
865 $calculated = $numberingmethod;
866 my $locale = $subscription->{locale
};
867 $newlastvalue1 = $subscription->{lastvalue1
} || 0;
868 $newlastvalue2 = $subscription->{lastvalue2
} || 0;
869 $newlastvalue3 = $subscription->{lastvalue3
} || 0;
870 $newinnerloop1 = $subscription->{innerloop1
} || 0;
871 $newinnerloop2 = $subscription->{innerloop2
} || 0;
872 $newinnerloop3 = $subscription->{innerloop3
} || 0;
875 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
878 for(my $i = 0; $i < $count; $i++) {
880 # check if we have to increase the new value.
882 if ($newinnerloop1 >= $pattern->{every1
}) {
884 $newlastvalue1 += $pattern->{add1
};
886 # reset counter if needed.
887 $newlastvalue1 = $pattern->{setto1
} if ($newlastvalue1 > $pattern->{whenmorethan1
});
890 # check if we have to increase the new value.
892 if ($newinnerloop2 >= $pattern->{every2
}) {
894 $newlastvalue2 += $pattern->{add2
};
896 # reset counter if needed.
897 $newlastvalue2 = $pattern->{setto2
} if ($newlastvalue2 > $pattern->{whenmorethan2
});
900 # check if we have to increase the new value.
902 if ($newinnerloop3 >= $pattern->{every3
}) {
904 $newlastvalue3 += $pattern->{add3
};
906 # reset counter if needed.
907 $newlastvalue3 = $pattern->{setto3
} if ($newlastvalue3 > $pattern->{whenmorethan3
});
911 my $newlastvalue1string = _numeration
( $newlastvalue1, $pattern->{numbering1
}, $locale );
912 $calculated =~ s/\{X\}/$newlastvalue1string/g;
915 my $newlastvalue2string = _numeration
( $newlastvalue2, $pattern->{numbering2
}, $locale );
916 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
919 my $newlastvalue3string = _numeration
( $newlastvalue3, $pattern->{numbering3
}, $locale );
920 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
925 $newlastvalue1, $newlastvalue2, $newlastvalue3,
926 $newinnerloop1, $newinnerloop2, $newinnerloop3);
931 $calculated = GetSeq($subscription, $pattern)
932 $subscription is a hashref containing all the attributes of the table 'subscription'
933 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
934 this function transforms {X},{Y},{Z} to 150,0,0 for example.
936 the sequence in string format
941 my ($subscription, $pattern) = @_;
943 return unless ($subscription and $pattern);
945 my $locale = $subscription->{locale
};
947 my $calculated = $pattern->{numberingmethod
};
949 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
950 $newlastvalue1 = _numeration
($newlastvalue1, $pattern->{numbering1
}, $locale) if ($pattern->{numbering1
}); # reset counter if needed.
951 $calculated =~ s/\{X\}/$newlastvalue1/g;
953 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
954 $newlastvalue2 = _numeration
($newlastvalue2, $pattern->{numbering2
}, $locale) if ($pattern->{numbering2
}); # reset counter if needed.
955 $calculated =~ s/\{Y\}/$newlastvalue2/g;
957 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
958 $newlastvalue3 = _numeration
($newlastvalue3, $pattern->{numbering3
}, $locale) if ($pattern->{numbering3
}); # reset counter if needed.
959 $calculated =~ s/\{Z\}/$newlastvalue3/g;
963 =head2 GetExpirationDate
965 $enddate = GetExpirationDate($subscriptionid, [$startdate])
967 this function return the next expiration date for a subscription given on input args.
974 sub GetExpirationDate
{
975 my ( $subscriptionid, $startdate ) = @_;
977 return unless ($subscriptionid);
979 my $dbh = C4
::Context
->dbh;
980 my $subscription = GetSubscription
($subscriptionid);
983 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
984 $enddate = $startdate || $subscription->{startdate
};
985 my @date = split( /-/, $enddate );
987 return if ( scalar(@date) != 3 || not check_date
(@date) );
989 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
990 if ( $frequency and $frequency->{unit
} ) {
993 if ( my $length = $subscription->{numberlength
} ) {
995 #calculate the date of the last issue.
996 for ( my $i = 1 ; $i <= $length ; $i++ ) {
997 $enddate = GetNextDate
( $subscription, $enddate, $frequency );
999 } elsif ( $subscription->{monthlength
} ) {
1000 if ( $$subscription{startdate
} ) {
1001 my @enddate = Add_Delta_YM
( $date[0], $date[1], $date[2], 0, $subscription->{monthlength
} );
1002 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1004 } elsif ( $subscription->{weeklength
} ) {
1005 if ( $$subscription{startdate
} ) {
1006 my @date = split( /-/, $subscription->{startdate
} );
1007 my @enddate = Add_Delta_Days
( $date[0], $date[1], $date[2], $subscription->{weeklength
} * 7 );
1008 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1011 $enddate = $subscription->{enddate
};
1015 return $subscription->{enddate
};
1019 =head2 CountSubscriptionFromBiblionumber
1021 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1022 this returns a count of the subscriptions for a given biblionumber
1024 the number of subscriptions
1028 sub CountSubscriptionFromBiblionumber
{
1029 my ($biblionumber) = @_;
1031 return unless ($biblionumber);
1033 my $dbh = C4
::Context
->dbh;
1034 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1035 my $sth = $dbh->prepare($query);
1036 $sth->execute($biblionumber);
1037 my $subscriptionsnumber = $sth->fetchrow;
1038 return $subscriptionsnumber;
1041 =head2 ModSubscriptionHistory
1043 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1045 this function modifies the history of a subscription. Put your new values on input arg.
1046 returns the number of rows affected
1050 sub ModSubscriptionHistory
{
1051 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1053 return unless ($subscriptionid);
1055 my $dbh = C4
::Context
->dbh;
1056 my $query = "UPDATE subscriptionhistory
1057 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1058 WHERE subscriptionid=?
1060 my $sth = $dbh->prepare($query);
1061 $receivedlist =~ s/^; // if $receivedlist;
1062 $missinglist =~ s/^; // if $missinglist;
1063 $opacnote =~ s/^; // if $opacnote;
1064 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1068 =head2 ModSerialStatus
1070 ModSerialStatus($serialid, $serialseq, $planneddate, $publisheddate,
1071 $publisheddatetext, $status, $notes);
1073 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1074 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1078 sub ModSerialStatus
{
1079 my ($serialid, $serialseq, $planneddate, $publisheddate, $publisheddatetext,
1080 $status, $notes) = @_;
1082 return unless ($serialid);
1084 #It is a usual serial
1085 # 1st, get previous status :
1086 my $dbh = C4
::Context
->dbh;
1087 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity,serial.routingnotes
1088 FROM serial, subscription
1089 WHERE serial.subscriptionid=subscription.subscriptionid
1091 my $sth = $dbh->prepare($query);
1092 $sth->execute($serialid);
1093 my ( $subscriptionid, $oldstatus, $periodicity, $routingnotes ) = $sth->fetchrow;
1094 my $frequency = GetSubscriptionFrequency
($periodicity);
1096 # change status & update subscriptionhistory
1098 if ( $status == DELETED
) {
1099 DelIssue
( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1103 SET serialseq = ?, publisheddate = ?, publisheddatetext = ?,
1104 planneddate = ?, status = ?, notes = ?, routingnotes = ?
1107 $sth = $dbh->prepare($query);
1108 $sth->execute( $serialseq, $publisheddate, $publisheddatetext,
1109 $planneddate, $status, $notes, $routingnotes, $serialid );
1110 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1111 $sth = $dbh->prepare($query);
1112 $sth->execute($subscriptionid);
1113 my $val = $sth->fetchrow_hashref;
1114 unless ( $val->{manualhistory
} ) {
1115 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1116 $sth = $dbh->prepare($query);
1117 $sth->execute($subscriptionid);
1118 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1120 if ( $status == ARRIVED
|| ($oldstatus == ARRIVED
&& $status != ARRIVED
) ) {
1121 $recievedlist .= "; $serialseq"
1122 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1125 # in case serial has been previously marked as missing
1126 if (grep /$status/, (EXPECTED
, ARRIVED
, LATE
, CLAIMED
)) {
1127 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1130 $missinglist .= "; $serialseq"
1131 if ( ( grep { $_ == $status } ( MISSING_STATUSES
) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1132 $missinglist .= "; not issued $serialseq"
1133 if ( $status == NOT_ISSUED
&& $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1135 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1136 $sth = $dbh->prepare($query);
1137 $recievedlist =~ s/^; //;
1138 $missinglist =~ s/^; //;
1139 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1143 # create new expected entry if needed (ie : was "expected" and has changed)
1144 my $otherIssueExpected = scalar findSerialsByStatus
(EXPECTED
, $subscriptionid);
1145 if ( !$otherIssueExpected && $oldstatus == EXPECTED
&& $status != EXPECTED
) {
1146 my $subscription = GetSubscription
($subscriptionid);
1147 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1148 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1152 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1153 $newinnerloop1, $newinnerloop2, $newinnerloop3
1155 = GetNextSeq
( $subscription, $pattern, $frequency, $publisheddate );
1157 # next date (calculated from actual date & frequency parameters)
1158 my $nextpublisheddate = GetNextDate
($subscription, $publisheddate, $frequency, 1);
1159 my $nextpubdate = $nextpublisheddate;
1160 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1161 WHERE subscriptionid = ?";
1162 $sth = $dbh->prepare($query);
1163 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1164 my $newnote = C4
::Context
->preference('PreserveSerialNotes') ?
$notes : "";
1165 NewIssue
( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate, undef, $newnote, $routingnotes );
1166 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1167 if ( $subscription->{letter
} && $status == ARRIVED
&& $oldstatus != ARRIVED
) {
1168 require C4
::Letters
;
1169 C4
::Letters
::SendAlerts
( 'issue', $serialid, $subscription->{letter
} );
1176 =head2 GetNextExpected
1178 $nextexpected = GetNextExpected($subscriptionid)
1180 Get the planneddate for the current expected issue of the subscription.
1186 planneddate => ISO date
1191 sub GetNextExpected
{
1192 my ($subscriptionid) = @_;
1194 my $dbh = C4
::Context
->dbh;
1198 WHERE subscriptionid
= ?
1202 my $sth = $dbh->prepare($query);
1204 # Each subscription has only one 'expected' issue.
1205 $sth->execute( $subscriptionid, EXPECTED
);
1206 my $nextissue = $sth->fetchrow_hashref;
1207 if ( !$nextissue ) {
1211 WHERE subscriptionid
= ?
1212 ORDER BY publisheddate DESC
1215 $sth = $dbh->prepare($query);
1216 $sth->execute($subscriptionid);
1217 $nextissue = $sth->fetchrow_hashref;
1219 foreach(qw
/planneddate publisheddate/) {
1220 if ( !defined $nextissue->{$_} ) {
1221 # or should this default to 1st Jan ???
1222 $nextissue->{$_} = strftime
( '%Y-%m-%d', localtime );
1224 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1232 =head2 ModNextExpected
1234 ModNextExpected($subscriptionid,$date)
1236 Update the planneddate for the current expected issue of the subscription.
1237 This will modify all future prediction results.
1239 C<$date> is an ISO date.
1245 sub ModNextExpected
{
1246 my ( $subscriptionid, $date ) = @_;
1247 my $dbh = C4
::Context
->dbh;
1249 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1250 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1252 # Each subscription has only one 'expected' issue.
1253 $sth->execute( $date, $date, $subscriptionid, EXPECTED
);
1258 =head2 GetSubscriptionIrregularities
1262 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1263 get the list of irregularities for a subscription
1269 sub GetSubscriptionIrregularities
{
1270 my $subscriptionid = shift;
1272 return unless $subscriptionid;
1274 my $dbh = C4
::Context
->dbh;
1278 WHERE subscriptionid
= ?
1280 my $sth = $dbh->prepare($query);
1281 $sth->execute($subscriptionid);
1283 my ($result) = $sth->fetchrow_array;
1284 my @irreg = split /;/, $result;
1289 =head2 ModSubscription
1291 this function modifies a subscription. Put all new values on input args.
1292 returns the number of rows affected
1296 sub ModSubscription
{
1298 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1299 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1300 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1301 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1302 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1303 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1304 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq,
1305 $itemtype, $previousitemtype, $mana_id
1308 my $dbh = C4
::Context
->dbh;
1309 my $query = "UPDATE subscription
1310 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1311 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1312 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1313 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1314 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1315 callnumber=?, notes=?, letter=?, manualhistory=?,
1316 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1317 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1318 skip_serialseq=?, itemtype=?, previousitemtype=?, mana_id=?
1319 WHERE subscriptionid = ?";
1321 my $sth = $dbh->prepare($query);
1323 $auser, $branchcode, $aqbooksellerid, $cost,
1324 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1325 $irregularity, $numberpattern, $locale, $numberlength,
1326 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1327 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1328 $status, $biblionumber, $callnumber, $notes,
1329 $letter, ($manualhistory ?
$manualhistory : 0),
1330 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1331 $graceperiod, $location, $enddate, $skip_serialseq,
1332 $itemtype, $previousitemtype, $mana_id,
1335 my $rows = $sth->rows;
1337 logaction
( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1341 =head2 NewSubscription
1343 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1344 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1345 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1346 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1347 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1348 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
1349 $skip_serialseq, $itemtype, $previousitemtype);
1351 Create a new subscription with value given on input args.
1354 the id of this new subscription
1358 sub NewSubscription
{
1360 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1361 $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
1362 $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
1363 $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
1364 $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
1365 $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
1366 $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype, $mana_id
1368 my $dbh = C4
::Context
->dbh;
1370 my $subscription = Koha
::Subscription
->new(
1372 librarian
=> $auser,
1373 branchcode
=> $branchcode,
1374 aqbooksellerid
=> $aqbooksellerid,
1376 aqbudgetid
=> $aqbudgetid,
1377 biblionumber
=> $biblionumber,
1378 startdate
=> $startdate,
1379 periodicity
=> $periodicity,
1380 numberlength
=> $numberlength,
1381 weeklength
=> $weeklength,
1382 monthlength
=> $monthlength,
1383 lastvalue1
=> $lastvalue1,
1384 innerloop1
=> $innerloop1,
1385 lastvalue2
=> $lastvalue2,
1386 innerloop2
=> $innerloop2,
1387 lastvalue3
=> $lastvalue3,
1388 innerloop3
=> $innerloop3,
1392 firstacquidate
=> $firstacquidate,
1393 irregularity
=> $irregularity,
1394 numberpattern
=> $numberpattern,
1396 callnumber
=> $callnumber,
1397 manualhistory
=> $manualhistory,
1398 internalnotes
=> $internalnotes,
1399 serialsadditems
=> $serialsadditems,
1400 staffdisplaycount
=> $staffdisplaycount,
1401 opacdisplaycount
=> $opacdisplaycount,
1402 graceperiod
=> $graceperiod,
1403 location
=> $location,
1404 enddate
=> $enddate,
1405 skip_serialseq
=> $skip_serialseq,
1406 itemtype
=> $itemtype,
1407 previousitemtype
=> $previousitemtype,
1408 mana_id
=> $mana_id,
1411 $subscription->discard_changes;
1412 my $subscriptionid = $subscription->subscriptionid;
1413 my ( $query, $sth );
1415 $enddate = GetExpirationDate
( $subscriptionid, $startdate );
1419 WHERE subscriptionid
=?
1421 $sth = $dbh->prepare($query);
1422 $sth->execute( $enddate, $subscriptionid );
1425 # then create the 1st expected number
1427 INSERT INTO subscriptionhistory
1428 (biblionumber
, subscriptionid
, histstartdate
, missinglist
, recievedlist
)
1429 VALUES
(?
,?
,?
, '', '')
1431 $sth = $dbh->prepare($query);
1432 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1434 # reread subscription to get a hash (for calculation of the 1st issue number)
1435 $subscription = GetSubscription
($subscriptionid); # We should not do that
1436 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1438 # calculate issue number
1439 my $serialseq = GetSeq
($subscription, $pattern) || q{};
1443 serialseq
=> $serialseq,
1444 serialseq_x
=> $subscription->{'lastvalue1'},
1445 serialseq_y
=> $subscription->{'lastvalue2'},
1446 serialseq_z
=> $subscription->{'lastvalue3'},
1447 subscriptionid
=> $subscriptionid,
1448 biblionumber
=> $biblionumber,
1450 planneddate
=> $firstacquidate,
1451 publisheddate
=> $firstacquidate,
1455 logaction
( "SERIAL", "ADD", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1457 #set serial flag on biblio if not already set.
1458 my $biblio = Koha
::Biblios
->find( $biblionumber );
1459 if ( $biblio and !$biblio->serial ) {
1460 my $record = GetMarcBiblio
({ biblionumber
=> $biblionumber });
1461 my ( $tag, $subf ) = GetMarcFromKohaField
( 'biblio.serial' );
1463 eval { $record->field($tag)->update( $subf => 1 ); };
1465 ModBiblio
( $record, $biblionumber, $biblio->frameworkcode );
1467 return $subscriptionid;
1470 =head2 ReNewSubscription
1472 ReNewSubscription($params);
1474 $params is a hashref with the following keys: subscriptionid, user, startdate, numberlength, weeklength, monthlength, note, branchcode
1476 this function renew a subscription with values given on input args.
1480 sub ReNewSubscription
{
1481 my ( $params ) = @_;
1482 my $subscriptionid = $params->{subscriptionid
};
1483 my $user = $params->{user
};
1484 my $startdate = $params->{startdate
};
1485 my $numberlength = $params->{numberlength
};
1486 my $weeklength = $params->{weeklength
};
1487 my $monthlength = $params->{monthlength
};
1488 my $note = $params->{note
};
1489 my $branchcode = $params->{branchcode
};
1491 my $dbh = C4
::Context
->dbh;
1492 my $subscription = GetSubscription
($subscriptionid);
1496 LEFT JOIN biblioitems ON biblio
.biblionumber
=biblioitems
.biblionumber
1497 WHERE biblio
.biblionumber
=?
1499 my $sth = $dbh->prepare($query);
1500 $sth->execute( $subscription->{biblionumber
} );
1501 my $biblio = $sth->fetchrow_hashref;
1503 if ( C4
::Context
->preference("RenewSerialAddsSuggestion") ) {
1504 require C4
::Suggestions
;
1505 C4
::Suggestions
::NewSuggestion
(
1506 { 'suggestedby' => $user,
1507 'title' => $subscription->{bibliotitle
},
1508 'author' => $biblio->{author
},
1509 'publishercode' => $biblio->{publishercode
},
1511 'biblionumber' => $subscription->{biblionumber
},
1512 'branchcode' => $branchcode,
1517 $numberlength ||= 0; # Should not we raise an exception instead?
1520 # renew subscription
1523 SET startdate
=?
,numberlength
=?
,weeklength
=?
,monthlength
=?
,reneweddate
=NOW
()
1524 WHERE subscriptionid
=?
1526 $sth = $dbh->prepare($query);
1527 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1528 my $enddate = GetExpirationDate
($subscriptionid);
1529 $debug && warn "enddate :$enddate";
1533 WHERE subscriptionid
=?
1535 $sth = $dbh->prepare($query);
1536 $sth->execute( $enddate, $subscriptionid );
1538 logaction
( "SERIAL", "RENEW", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1544 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes, $routingnotes)
1546 Create a new issue stored on the database.
1547 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1548 returns the serial id
1553 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate,
1554 $publisheddate, $publisheddatetext, $notes, $routingnotes ) = @_;
1555 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1557 return unless ($subscriptionid);
1559 my $schema = Koha
::Database
->new()->schema();
1561 my $subscription = Koha
::Subscriptions
->find( $subscriptionid );
1563 my $serial = Koha
::Serial
->new(
1565 serialseq
=> $serialseq,
1566 serialseq_x
=> $subscription->lastvalue1(),
1567 serialseq_y
=> $subscription->lastvalue2(),
1568 serialseq_z
=> $subscription->lastvalue3(),
1569 subscriptionid
=> $subscriptionid,
1570 biblionumber
=> $biblionumber,
1572 planneddate
=> $planneddate,
1573 publisheddate
=> $publisheddate,
1574 publisheddatetext
=> $publisheddatetext,
1576 routingnotes
=> $routingnotes
1580 my $serialid = $serial->id();
1582 my $subscription_history = Koha
::Subscription
::Histories
->find($subscriptionid);
1583 my $missinglist = $subscription_history->missinglist();
1584 my $recievedlist = $subscription_history->recievedlist();
1586 if ( $status == ARRIVED
) {
1587 ### TODO Add a feature that improves recognition and description.
1588 ### As such count (serialseq) i.e. : N18,2(N19),N20
1589 ### Would use substr and index But be careful to previous presence of ()
1590 $recievedlist .= "; $serialseq" unless ( index( $recievedlist, $serialseq ) > 0 );
1592 if ( grep { /^$status$/ } (MISSING_STATUSES
) ) {
1593 $missinglist .= "; $serialseq" unless ( index( $missinglist, $serialseq ) > 0 );
1596 $recievedlist =~ s/^; //;
1597 $missinglist =~ s/^; //;
1599 $subscription_history->recievedlist($recievedlist);
1600 $subscription_history->missinglist($missinglist);
1601 $subscription_history->store();
1606 =head2 HasSubscriptionStrictlyExpired
1608 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1610 the subscription has stricly expired when today > the end subscription date
1613 1 if true, 0 if false, -1 if the expiration date is not set.
1617 sub HasSubscriptionStrictlyExpired
{
1619 # Getting end of subscription date
1620 my ($subscriptionid) = @_;
1622 return unless ($subscriptionid);
1624 my $dbh = C4
::Context
->dbh;
1625 my $subscription = GetSubscription
($subscriptionid);
1626 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1628 # If the expiration date is set
1629 if ( $expirationdate != 0 ) {
1630 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1632 # Getting today's date
1633 my ( $nowyear, $nowmonth, $nowday ) = Today
();
1635 # if today's date > expiration date, then the subscription has stricly expired
1636 if ( Delta_Days
( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1643 # There are some cases where the expiration date is not set
1644 # As we can't determine if the subscription has expired on a date-basis,
1650 =head2 HasSubscriptionExpired
1652 $has_expired = HasSubscriptionExpired($subscriptionid)
1654 the subscription has expired when the next issue to arrive is out of subscription limit.
1657 0 if the subscription has not expired
1658 1 if the subscription has expired
1659 2 if has subscription does not have a valid expiration date set
1663 sub HasSubscriptionExpired
{
1664 my ($subscriptionid) = @_;
1666 return unless ($subscriptionid);
1668 my $dbh = C4
::Context
->dbh;
1669 my $subscription = GetSubscription
($subscriptionid);
1670 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1671 if ( $frequency and $frequency->{unit
} ) {
1672 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1673 if (!defined $expirationdate) {
1674 $expirationdate = q{};
1677 SELECT max
(planneddate
)
1679 WHERE subscriptionid
=?
1681 my $sth = $dbh->prepare($query);
1682 $sth->execute($subscriptionid);
1683 my ($res) = $sth->fetchrow;
1684 if (!$res || $res=~m/^0000/) {
1687 my @res = split( /-/, $res );
1688 my @endofsubscriptiondate = split( /-/, $expirationdate );
1689 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date
(@res) || not check_date
(@endofsubscriptiondate) );
1691 if ( ( @endofsubscriptiondate && Delta_Days
( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1696 if ( $subscription->{'numberlength'} ) {
1697 my $countreceived = countissuesfrom
( $subscriptionid, $subscription->{'startdate'} );
1698 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1704 return 0; # Notice that you'll never get here.
1707 =head2 DelSubscription
1709 DelSubscription($subscriptionid)
1710 this function deletes subscription which has $subscriptionid as id.
1714 sub DelSubscription
{
1715 my ($subscriptionid) = @_;
1716 my $dbh = C4
::Context
->dbh;
1717 $dbh->do("DELETE FROM subscription WHERE subscriptionid=?", undef, $subscriptionid);
1718 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=?", undef, $subscriptionid);
1719 $dbh->do("DELETE FROM serial WHERE subscriptionid=?", undef, $subscriptionid);
1721 Koha
::AdditionalFieldValues
->search({
1722 'field.tablename' => 'subscription',
1723 'me.record_id' => $subscriptionid,
1724 }, { join => 'field' })->delete;
1726 logaction
( "SERIAL", "DELETE", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1731 DelIssue($serialseq,$subscriptionid)
1732 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1734 returns the number of rows affected
1739 my ($dataissue) = @_;
1740 my $dbh = C4
::Context
->dbh;
1741 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1746 AND subscriptionid
= ?
1748 my $mainsth = $dbh->prepare($query);
1749 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1751 #Delete element from subscription history
1752 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1753 my $sth = $dbh->prepare($query);
1754 $sth->execute( $dataissue->{'subscriptionid'} );
1755 my $val = $sth->fetchrow_hashref;
1756 unless ( $val->{manualhistory
} ) {
1758 SELECT
* FROM subscriptionhistory
1759 WHERE subscriptionid
= ?
1761 my $sth = $dbh->prepare($query);
1762 $sth->execute( $dataissue->{'subscriptionid'} );
1763 my $data = $sth->fetchrow_hashref;
1764 my $serialseq = $dataissue->{'serialseq'};
1765 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1766 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1767 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1768 $sth = $dbh->prepare($strsth);
1769 $sth->execute( $dataissue->{'subscriptionid'} );
1772 return $mainsth->rows;
1775 =head2 GetLateOrMissingIssues
1777 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1779 this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
1782 the issuelist as an array of hash refs. Each element of this array contains
1783 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1787 sub GetLateOrMissingIssues
{
1788 my ( $supplierid, $serialid, $order ) = @_;
1790 return unless ( $supplierid or $serialid );
1792 my $dbh = C4
::Context
->dbh;
1797 $byserial = "and serialid = " . $serialid;
1800 $order .= ", title";
1804 my $missing_statuses_string = join ',', (MISSING_STATUSES
);
1806 $sth = $dbh->prepare(
1808 serialid, aqbooksellerid, name,
1809 biblio.title, biblioitems.issn, 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 biblioitems ON subscription.biblionumber=biblioitems.biblionumber
1816 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1817 WHERE subscription.subscriptionid = serial.subscriptionid
1818 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1819 AND subscription.aqbooksellerid=$supplierid
1824 $sth = $dbh->prepare(
1826 serialid, aqbooksellerid, name,
1827 biblio.title, planneddate, serialseq,
1828 serial.status, serial.subscriptionid, claimdate, claims_count,
1829 subscription.branchcode
1831 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1832 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1833 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1834 WHERE subscription.subscriptionid = serial.subscriptionid
1835 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1840 $sth->execute( EXPECTED
, LATE
, CLAIMED
);
1842 while ( my $line = $sth->fetchrow_hashref ) {
1844 if ($line->{planneddate
} && $line->{planneddate
} !~/^0+\-/) {
1845 $line->{planneddateISO
} = $line->{planneddate
};
1846 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{"planneddate"} ), dateonly
=> 1 } );
1848 if ($line->{claimdate
} && $line->{claimdate
} !~/^0+\-/) {
1849 $line->{claimdateISO
} = $line->{claimdate
};
1850 $line->{claimdate
} = output_pref
( { dt
=> dt_from_string
( $line->{"claimdate"} ), dateonly
=> 1 } );
1852 $line->{"status".$line->{status
}} = 1;
1854 my $subscription_object = Koha
::Subscriptions
->find($line->{subscriptionid
});
1855 $line->{additional_fields
} = { map { $_->field->name => $_->value }
1856 $subscription_object->additional_field_values->as_list };
1858 push @issuelist, $line;
1865 &updateClaim($serialid)
1867 this function updates the time when a claim is issued for late/missing items
1869 called from claims.pl file
1874 my ($serialids) = @_;
1875 return unless $serialids;
1876 unless ( ref $serialids ) {
1877 $serialids = [ $serialids ];
1879 my $dbh = C4
::Context
->dbh;
1882 SET claimdate
= NOW
(),
1883 claims_count
= claims_count
+ 1,
1885 WHERE serialid
in (| . join( q
|,|, (q
|?
|) x @
$serialids ) . q
|)|,
1886 {}, CLAIMED
, @
$serialids );
1889 =head2 check_routing
1891 $result = &check_routing($subscriptionid)
1893 this function checks to see if a serial has a routing list and returns the count of routingid
1894 used to show either an 'add' or 'edit' link
1899 my ($subscriptionid) = @_;
1901 return unless ($subscriptionid);
1903 my $dbh = C4
::Context
->dbh;
1904 my $sth = $dbh->prepare(
1905 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1906 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1907 WHERE subscription.subscriptionid = ? GROUP BY routingid ORDER BY ranking ASC
1910 $sth->execute($subscriptionid);
1911 my $line = $sth->fetchrow_hashref;
1912 my $result = $line->{'routingids'};
1916 =head2 addroutingmember
1918 addroutingmember($borrowernumber,$subscriptionid)
1920 this function takes a borrowernumber and subscriptionid and adds the member to the
1921 routing list for that serial subscription and gives them a rank on the list
1922 of either 1 or highest current rank + 1
1926 sub addroutingmember
{
1927 my ( $borrowernumber, $subscriptionid ) = @_;
1929 return unless ($borrowernumber and $subscriptionid);
1932 my $dbh = C4
::Context
->dbh;
1933 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1934 $sth->execute($subscriptionid);
1935 while ( my $line = $sth->fetchrow_hashref ) {
1936 if ( $line->{'rank'} > 0 ) {
1937 $rank = $line->{'rank'} + 1;
1942 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1943 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1946 =head2 reorder_members
1948 reorder_members($subscriptionid,$routingid,$rank)
1950 this function is used to reorder the routing list
1952 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1953 - it gets all members on list puts their routingid's into an array
1954 - removes the one in the array that is $routingid
1955 - then reinjects $routingid at point indicated by $rank
1956 - then update the database with the routingids in the new order
1960 sub reorder_members
{
1961 my ( $subscriptionid, $routingid, $rank ) = @_;
1962 my $dbh = C4
::Context
->dbh;
1963 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1964 $sth->execute($subscriptionid);
1966 while ( my $line = $sth->fetchrow_hashref ) {
1967 push( @result, $line->{'routingid'} );
1970 # To find the matching index
1972 my $key = -1; # to allow for 0 being a valid response
1973 for ( $i = 0 ; $i < @result ; $i++ ) {
1974 if ( $routingid == $result[$i] ) {
1975 $key = $i; # save the index
1980 # if index exists in array then move it to new position
1981 if ( $key > -1 && $rank > 0 ) {
1982 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1983 my $moving_item = splice( @result, $key, 1 );
1984 splice( @result, $new_rank, 0, $moving_item );
1986 for ( my $j = 0 ; $j < @result ; $j++ ) {
1987 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1993 =head2 delroutingmember
1995 delroutingmember($routingid,$subscriptionid)
1997 this function either deletes one member from routing list if $routingid exists otherwise
1998 deletes all members from the routing list
2002 sub delroutingmember
{
2004 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
2005 my ( $routingid, $subscriptionid ) = @_;
2006 my $dbh = C4
::Context
->dbh;
2008 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
2009 $sth->execute($routingid);
2010 reorder_members
( $subscriptionid, $routingid );
2012 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
2013 $sth->execute($subscriptionid);
2018 =head2 getroutinglist
2020 @routinglist = getroutinglist($subscriptionid)
2022 this gets the info from the subscriptionroutinglist for $subscriptionid
2025 the routinglist as an array. Each element of the array contains a hash_ref containing
2026 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2030 sub getroutinglist
{
2031 my ($subscriptionid) = @_;
2032 my $dbh = C4
::Context
->dbh;
2033 my $sth = $dbh->prepare(
2034 'SELECT routingid, borrowernumber, ranking, biblionumber
2036 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2037 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2039 $sth->execute($subscriptionid);
2040 my $routinglist = $sth->fetchall_arrayref({});
2041 return @
{$routinglist};
2044 =head2 countissuesfrom
2046 $result = countissuesfrom($subscriptionid,$startdate)
2048 Returns a count of serial rows matching the given subsctiptionid
2049 with published date greater than startdate
2053 sub countissuesfrom
{
2054 my ( $subscriptionid, $startdate ) = @_;
2055 my $dbh = C4
::Context
->dbh;
2059 WHERE subscriptionid
=?
2060 AND serial
.publisheddate
>?
2062 my $sth = $dbh->prepare($query);
2063 $sth->execute( $subscriptionid, $startdate );
2064 my ($countreceived) = $sth->fetchrow;
2065 return $countreceived;
2070 $result = CountIssues($subscriptionid)
2072 Returns a count of serial rows matching the given subsctiptionid
2077 my ($subscriptionid) = @_;
2078 my $dbh = C4
::Context
->dbh;
2082 WHERE subscriptionid
=?
2084 my $sth = $dbh->prepare($query);
2085 $sth->execute($subscriptionid);
2086 my ($countreceived) = $sth->fetchrow;
2087 return $countreceived;
2092 $result = HasItems($subscriptionid)
2094 returns a count of items from serial matching the subscriptionid
2099 my ($subscriptionid) = @_;
2100 my $dbh = C4
::Context
->dbh;
2102 SELECT COUNT
(serialitems
.itemnumber
)
2104 LEFT JOIN serialitems USING
(serialid
)
2105 WHERE subscriptionid
=? AND serialitems
.serialid IS NOT NULL
2107 my $sth=$dbh->prepare($query);
2108 $sth->execute($subscriptionid);
2109 my ($countitems)=$sth->fetchrow_array();
2113 =head2 abouttoexpire
2115 $result = abouttoexpire($subscriptionid)
2117 this function alerts you to the penultimate issue for a serial subscription
2119 returns 1 - if this is the penultimate issue
2125 my ($subscriptionid) = @_;
2126 my $dbh = C4
::Context
->dbh;
2127 my $subscription = GetSubscription
($subscriptionid);
2128 my $per = $subscription->{'periodicity'};
2129 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($per);
2130 if ($frequency and $frequency->{unit
}){
2132 my $expirationdate = GetExpirationDate
($subscriptionid);
2134 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2135 my $nextdate = GetNextDate
($subscription, $res, $frequency);
2137 # only compare dates if both dates exist.
2138 if ($nextdate and $expirationdate) {
2139 if(Date
::Calc
::Delta_Days
(
2140 split( /-/, $nextdate ),
2141 split( /-/, $expirationdate )
2147 } elsif ( $subscription->{numberlength
} && $subscription->{numberlength
}>0) {
2148 return (countissuesfrom
($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength
}-1);
2154 =head2 GetFictiveIssueNumber
2156 $issueno = GetFictiveIssueNumber($subscription, $publishedate, $frequency);
2158 Get the position of the issue published at $publisheddate, considering the
2159 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2160 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2161 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2162 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2163 depending on how many rows are in serial table.
2164 The issue number calculation is based on subscription frequency, first acquisition
2165 date, and $publisheddate.
2167 Returns undef when called for irregular frequencies.
2169 The routine is used to skip irregularities when calculating the next issue
2170 date (in GetNextDate) or the next issue number (in GetNextSeq).
2174 sub GetFictiveIssueNumber
{
2175 my ($subscription, $publisheddate, $frequency) = @_;
2177 my $unit = $frequency->{unit
} ?
lc $frequency->{'unit'} : undef;
2181 my ( $year, $month, $day ) = split /-/, $publisheddate;
2182 my ( $fa_year, $fa_month, $fa_day ) = split /-/, $subscription->{'firstacquidate'};
2183 my $delta = _delta_units
( [$fa_year, $fa_month, $fa_day], [$year, $month, $day], $unit );
2185 if( $frequency->{'unitsperissue'} == 1 ) {
2186 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2187 } else { # issuesperunit == 1
2188 $issueno = 1 + int( $delta / $frequency->{'unitsperissue'} );
2194 my ( $date1, $date2, $unit ) = @_;
2195 # date1 and date2 are array refs in the form [ yy, mm, dd ]
2197 if( $unit eq 'day' ) {
2198 return Delta_Days
( @
$date1, @
$date2 );
2199 } elsif( $unit eq 'week' ) {
2200 return int( Delta_Days
( @
$date1, @
$date2 ) / 7 );
2203 # In case of months or years, this is a wrapper around N_Delta_YMD.
2204 # Note that N_Delta_YMD returns 29 days between e.g. 22-2-72 and 22-3-72
2205 # while we expect 1 month.
2206 my @delta = N_Delta_YMD
( @
$date1, @
$date2 );
2207 if( $delta[2] > 27 ) {
2208 # Check if we could add a month
2209 my @jump = Add_Delta_YM
( @
$date1, $delta[0], 1 + $delta[1] );
2210 if( Delta_Days
( @jump, @
$date2 ) >= 0 ) {
2214 if( $delta[1] >= 12 ) {
2218 # if unit is year, we only return full years
2219 return $unit eq 'month' ?
$delta[0] * 12 + $delta[1] : $delta[0];
2222 sub _get_next_date_day
{
2223 my ($subscription, $freqdata, $year, $month, $day) = @_;
2225 my @newissue; # ( yy, mm, dd )
2226 # We do not need $delta_days here, since it would be zero where used
2228 if( $freqdata->{issuesperunit
} == 1 ) {
2230 @newissue = Add_Delta_Days
(
2231 $year, $month, $day, $freqdata->{"unitsperissue"} );
2232 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2234 @newissue = ( $year, $month, $day );
2235 $subscription->{countissuesperunit
}++;
2237 # We finished a cycle of issues within a unit.
2238 # No subtraction of zero needed, just add one day
2239 @newissue = Add_Delta_Days
( $year, $month, $day, 1 );
2240 $subscription->{countissuesperunit
} = 1;
2245 sub _get_next_date_week
{
2246 my ($subscription, $freqdata, $year, $month, $day) = @_;
2248 my @newissue; # ( yy, mm, dd )
2249 my $delta_days = int( 7 / $freqdata->{issuesperunit
} );
2251 if( $freqdata->{issuesperunit
} == 1 ) {
2252 # Add full weeks (of 7 days)
2253 @newissue = Add_Delta_Days
(
2254 $year, $month, $day, 7 * $freqdata->{"unitsperissue"} );
2255 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2256 # Add rounded number of days based on frequency.
2257 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2258 $subscription->{countissuesperunit
}++;
2260 # We finished a cycle of issues within a unit.
2261 # Subtract delta * (issues - 1), add 1 week
2262 @newissue = Add_Delta_Days
( $year, $month, $day,
2263 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2264 @newissue = Add_Delta_Days
( @newissue, 7 );
2265 $subscription->{countissuesperunit
} = 1;
2270 sub _get_next_date_month
{
2271 my ($subscription, $freqdata, $year, $month, $day) = @_;
2273 my @newissue; # ( yy, mm, dd )
2274 my $delta_days = int( 30 / $freqdata->{issuesperunit
} );
2276 if( $freqdata->{issuesperunit
} == 1 ) {
2278 @newissue = Add_Delta_YM
(
2279 $year, $month, $day, 0, $freqdata->{"unitsperissue"} );
2280 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2281 # Add rounded number of days based on frequency.
2282 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2283 $subscription->{countissuesperunit
}++;
2285 # We finished a cycle of issues within a unit.
2286 # Subtract delta * (issues - 1), add 1 month
2287 @newissue = Add_Delta_Days
( $year, $month, $day,
2288 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2289 @newissue = Add_Delta_YM
( @newissue, 0, 1 );
2290 $subscription->{countissuesperunit
} = 1;
2295 sub _get_next_date_year
{
2296 my ($subscription, $freqdata, $year, $month, $day) = @_;
2298 my @newissue; # ( yy, mm, dd )
2299 my $delta_days = int( 365 / $freqdata->{issuesperunit
} );
2301 if( $freqdata->{issuesperunit
} == 1 ) {
2303 @newissue = Add_Delta_YM
( $year, $month, $day, $freqdata->{"unitsperissue"}, 0 );
2304 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2305 # Add rounded number of days based on frequency.
2306 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2307 $subscription->{countissuesperunit
}++;
2309 # We finished a cycle of issues within a unit.
2310 # Subtract delta * (issues - 1), add 1 year
2311 @newissue = Add_Delta_Days
( $year, $month, $day, -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2312 @newissue = Add_Delta_YM
( @newissue, 1, 0 );
2313 $subscription->{countissuesperunit
} = 1;
2320 $resultdate = GetNextDate($publisheddate,$subscription,$freqdata,$updatecount)
2322 this function it takes the publisheddate and will return the next issue's date
2323 and will skip dates if there exists an irregularity.
2324 $publisheddate has to be an ISO date
2325 $subscription is a hashref containing at least 'firstacquidate', 'irregularity', and 'countissuesperunit'
2326 $frequency is a hashref containing frequency informations
2327 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2328 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2329 skipped then the returned date will be 2007-05-10
2332 $resultdate - then next date in the sequence (ISO date)
2334 Return undef if subscription is irregular
2339 my ( $subscription, $publisheddate, $freqdata, $updatecount ) = @_;
2341 return unless $subscription and $publisheddate;
2344 if ($freqdata->{'unit'}) {
2345 my ( $year, $month, $day ) = split /-/, $publisheddate;
2347 # Process an irregularity Hash
2348 # Suppose that irregularities are stored in a string with this structure
2349 # irreg1;irreg2;irreg3
2350 # where irregX is the number of issue which will not be received
2351 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2353 if ( $subscription->{irregularity
} ) {
2354 my @irreg = split /;/, $subscription->{'irregularity'} ;
2355 foreach my $irregularity (@irreg) {
2356 $irregularities{$irregularity} = 1;
2360 # Get the 'fictive' next issue number
2361 # It is used to check if next issue is an irregular issue.
2362 my $issueno = GetFictiveIssueNumber
($subscription, $publisheddate, $freqdata) + 1;
2364 # Then get the next date
2365 my $unit = lc $freqdata->{'unit'};
2366 if ($unit eq 'day') {
2367 while ($irregularities{$issueno}) {
2368 ($year, $month, $day) = _get_next_date_day
($subscription,
2369 $freqdata, $year, $month, $day);
2372 ($year, $month, $day) = _get_next_date_day
($subscription, $freqdata,
2373 $year, $month, $day);
2375 elsif ($unit eq 'week') {
2376 while ($irregularities{$issueno}) {
2377 ($year, $month, $day) = _get_next_date_week
($subscription,
2378 $freqdata, $year, $month, $day);
2381 ($year, $month, $day) = _get_next_date_week
($subscription,
2382 $freqdata, $year, $month, $day);
2384 elsif ($unit eq 'month') {
2385 while ($irregularities{$issueno}) {
2386 ($year, $month, $day) = _get_next_date_month
($subscription,
2387 $freqdata, $year, $month, $day);
2390 ($year, $month, $day) = _get_next_date_month
($subscription,
2391 $freqdata, $year, $month, $day);
2393 elsif ($unit eq 'year') {
2394 while ($irregularities{$issueno}) {
2395 ($year, $month, $day) = _get_next_date_year
($subscription,
2396 $freqdata, $year, $month, $day);
2399 ($year, $month, $day) = _get_next_date_year
($subscription,
2400 $freqdata, $year, $month, $day);
2404 my $dbh = C4
::Context
->dbh;
2407 SET countissuesperunit
= ?
2408 WHERE subscriptionid
= ?
2410 my $sth = $dbh->prepare($query);
2411 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2414 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2420 $string = &_numeration($value,$num_type,$locale);
2422 _numeration returns the string corresponding to $value in the num_type
2434 my ($value, $num_type, $locale) = @_;
2439 if ( $num_type =~ /^dayname$/ or $num_type =~ /^dayabrv$/ ) {
2440 # 1970-11-01 was a Sunday
2441 $value = $value % 7;
2442 my $dt = DateTime
->new(
2448 $string = $num_type =~ /^dayname$/
2449 ?
$dt->strftime("%A")
2450 : $dt->strftime("%a");
2451 } elsif ( $num_type =~ /^monthname$/ or $num_type =~ /^monthabrv$/ ) {
2452 $value = $value % 12;
2453 my $dt = DateTime
->new(
2455 month
=> $value + 1,
2458 $string = $num_type =~ /^monthname$/
2459 ?
$dt->strftime("%B")
2460 : $dt->strftime("%b");
2461 } elsif ( $num_type =~ /^season$/ ) {
2462 my @seasons= qw( Spring Summer Fall Winter );
2463 $value = $value % 4;
2464 $string = $seasons[$value];
2465 } elsif ( $num_type =~ /^seasonabrv$/ ) {
2466 my @seasonsabrv= qw( Spr Sum Fal Win );
2467 $value = $value % 4;
2468 $string = $seasonsabrv[$value];
2476 =head2 CloseSubscription
2478 Close a subscription given a subscriptionid
2482 sub CloseSubscription
{
2483 my ( $subscriptionid ) = @_;
2484 return unless $subscriptionid;
2485 my $dbh = C4
::Context
->dbh;
2486 my $sth = $dbh->prepare( q{
2489 WHERE subscriptionid = ?
2491 $sth->execute( $subscriptionid );
2493 # Set status = missing when status = stopped
2494 $sth = $dbh->prepare( q{
2497 WHERE subscriptionid = ?
2500 $sth->execute( STOPPED
, $subscriptionid, EXPECTED
);
2503 =head2 ReopenSubscription
2505 Reopen a subscription given a subscriptionid
2509 sub ReopenSubscription
{
2510 my ( $subscriptionid ) = @_;
2511 return unless $subscriptionid;
2512 my $dbh = C4
::Context
->dbh;
2513 my $sth = $dbh->prepare( q{
2516 WHERE subscriptionid = ?
2518 $sth->execute( $subscriptionid );
2520 # Set status = expected when status = stopped
2521 $sth = $dbh->prepare( q{
2524 WHERE subscriptionid = ?
2527 $sth->execute( EXPECTED
, $subscriptionid, STOPPED
);
2530 =head2 subscriptionCurrentlyOnOrder
2532 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2534 Return 1 if subscription is currently on order else 0.
2538 sub subscriptionCurrentlyOnOrder
{
2539 my ( $subscriptionid ) = @_;
2540 my $dbh = C4
::Context
->dbh;
2542 SELECT COUNT
(*) FROM aqorders
2543 WHERE subscriptionid
= ?
2544 AND datereceived IS NULL
2545 AND datecancellationprinted IS NULL
2547 my $sth = $dbh->prepare( $query );
2548 $sth->execute($subscriptionid);
2549 return $sth->fetchrow_array;
2552 =head2 can_claim_subscription
2554 $can = can_claim_subscription( $subscriptionid[, $userid] );
2556 Return 1 if the subscription can be claimed by the current logged user (or a given $userid), else 0.
2560 sub can_claim_subscription
{
2561 my ( $subscription, $userid ) = @_;
2562 return _can_do_on_subscription
( $subscription, $userid, 'claim_serials' );
2565 =head2 can_edit_subscription
2567 $can = can_edit_subscription( $subscriptionid[, $userid] );
2569 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2573 sub can_edit_subscription
{
2574 my ( $subscription, $userid ) = @_;
2575 return _can_do_on_subscription
( $subscription, $userid, 'edit_subscription' );
2578 =head2 can_show_subscription
2580 $can = can_show_subscription( $subscriptionid[, $userid] );
2582 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2586 sub can_show_subscription
{
2587 my ( $subscription, $userid ) = @_;
2588 return _can_do_on_subscription
( $subscription, $userid, '*' );
2591 sub _can_do_on_subscription
{
2592 my ( $subscription, $userid, $permission ) = @_;
2593 return 0 unless C4
::Context
->userenv;
2594 my $flags = C4
::Context
->userenv->{flags
};
2595 $userid ||= C4
::Context
->userenv->{'id'};
2597 if ( C4
::Context
->preference('IndependentBranches') ) {
2599 if C4
::Context
->IsSuperLibrarian()
2601 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2603 C4
::Auth
::haspermission
( $userid,
2604 { serials
=> $permission } )
2605 and ( not defined $subscription->{branchcode
}
2606 or $subscription->{branchcode
} eq ''
2607 or $subscription->{branchcode
} eq
2608 C4
::Context
->userenv->{'branch'} )
2613 if C4
::Context
->IsSuperLibrarian()
2615 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2616 or C4
::Auth
::haspermission
(
2617 $userid, { serials
=> $permission }
2624 =head2 findSerialsByStatus
2626 @serials = findSerialsByStatus($status, $subscriptionid);
2628 Returns an array of serials matching a given status and subscription id.
2632 sub findSerialsByStatus
{
2633 my ( $status, $subscriptionid ) = @_;
2634 my $dbh = C4
::Context
->dbh;
2635 my $query = q
| SELECT
* from serial
2637 AND subscriptionid
= ?
2639 my $serials = $dbh->selectall_arrayref( $query, { Slice
=> {} }, $status, $subscriptionid );
2648 Koha Development Team <http://koha-community.org/>