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 return unless $subscription;
274 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
276 # Add additional fields to the subscription into a new key "additional_fields"
277 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
278 tablename
=> 'subscription',
279 record_id
=> $subscriptionid,
281 $subscription->{additional_fields
} = $additional_field_values->{$subscriptionid};
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
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) 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
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) 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
} =~ s/\n/\<br\/\
>/g
;
432 $subs->{missinglist
} =~ s/\n/\<br\/\
>/g
;
433 $subs->{recievedlist
} =~ s/\n/\<br\/\
>/g
;
434 $subs->{ "periodicity" . $subs->{periodicity
} } = 1;
435 $subs->{ "numberpattern" . $subs->{numberpattern
} } = 1;
436 $subs->{ "status" . $subs->{'status'} } = 1;
438 if (not defined $subs->{enddate
} ) {
439 $subs->{enddate
} = '';
441 $subs->{enddate
} = output_pref
( { dt
=> dt_from_string
( $subs->{enddate
}), dateonly
=> 1 } );
443 $subs->{'abouttoexpire'} = abouttoexpire
( $subs->{'subscriptionid'} );
444 $subs->{'subscriptionexpired'} = HasSubscriptionExpired
( $subs->{'subscriptionid'} );
445 $subs->{cannotedit
} = not can_edit_subscription
( $subs );
451 =head2 GetFullSubscriptionsFromBiblionumber
453 $array_ref = GetFullSubscriptionsFromBiblionumber($biblionumber)
454 this function reads the serial table.
458 sub GetFullSubscriptionsFromBiblionumber
{
459 my ($biblionumber) = @_;
460 my $dbh = C4
::Context
->dbh;
462 SELECT serial
.serialid
,
465 serial
.publisheddate
,
466 serial
.publisheddatetext
,
468 serial
.notes as notes
,
469 year
(IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
)) as year
,
470 biblio
.title as bibliotitle
,
471 subscription
.branchcode AS branchcode
,
472 subscription
.subscriptionid AS subscriptionid
474 LEFT JOIN subscription ON
475 (serial
.subscriptionid
=subscription
.subscriptionid
)
476 LEFT JOIN aqbooksellers on subscription
.aqbooksellerid
=aqbooksellers
.id
477 LEFT JOIN biblio on biblio
.biblionumber
=subscription
.biblionumber
478 WHERE subscription
.biblionumber
= ?
480 IF
(serial
.publisheddate
="00-00-0000",serial
.planneddate
,serial
.publisheddate
) DESC
,
481 serial
.subscriptionid
483 my $sth = $dbh->prepare($query);
484 $sth->execute($biblionumber);
485 my $subscriptions = $sth->fetchall_arrayref( {} );
486 my $cannotedit = not can_edit_subscription
( $subscriptions->[0] ) if scalar @
$subscriptions;
487 for my $subscription ( @
$subscriptions ) {
488 $subscription->{cannotedit
} = $cannotedit;
490 return $subscriptions;
493 =head2 SearchSubscriptions
495 @results = SearchSubscriptions($args);
497 This function returns a list of hashrefs, one for each subscription
498 that meets the conditions specified by the $args hashref.
500 The valid search fields are:
514 The expiration_date search field is special; it specifies the maximum
515 subscription expiration date.
519 sub SearchSubscriptions
{
522 my $additional_fields = $args->{additional_fields
} // [];
523 my $matching_record_ids_for_additional_fields = [];
524 if ( @
$additional_fields ) {
525 $matching_record_ids_for_additional_fields = Koha
::AdditionalField
->get_matching_record_ids({
526 fields
=> $additional_fields,
527 tablename
=> 'subscription',
530 return () unless @
$matching_record_ids_for_additional_fields;
535 subscription
.notes AS publicnotes
,
536 subscriptionhistory
.*,
538 biblio
.notes AS biblionotes
,
542 aqbooksellers
.name AS vendorname
,
545 LEFT JOIN subscriptionhistory USING
(subscriptionid
)
546 LEFT JOIN biblio ON biblio
.biblionumber
= subscription
.biblionumber
547 LEFT JOIN biblioitems ON biblioitems
.biblionumber
= subscription
.biblionumber
548 LEFT JOIN aqbooksellers ON subscription
.aqbooksellerid
= aqbooksellers
.id
550 $query .= q
| WHERE
1|;
553 if( $args->{biblionumber
} ) {
554 push @where_strs, "biblio.biblionumber = ?";
555 push @where_args, $args->{biblionumber
};
558 if( $args->{title
} ){
559 my @words = split / /, $args->{title
};
561 foreach my $word (@words) {
562 push @strs, "biblio.title LIKE ?";
563 push @args, "%$word%";
566 push @where_strs, '(' . join (' AND ', @strs) . ')';
567 push @where_args, @args;
571 push @where_strs, "biblioitems.issn LIKE ?";
572 push @where_args, "%$args->{issn}%";
575 push @where_strs, "biblioitems.ean LIKE ?";
576 push @where_args, "%$args->{ean}%";
578 if ( $args->{callnumber
} ) {
579 push @where_strs, "subscription.callnumber LIKE ?";
580 push @where_args, "%$args->{callnumber}%";
582 if( $args->{publisher
} ){
583 push @where_strs, "biblioitems.publishercode LIKE ?";
584 push @where_args, "%$args->{publisher}%";
586 if( $args->{bookseller
} ){
587 push @where_strs, "aqbooksellers.name LIKE ?";
588 push @where_args, "%$args->{bookseller}%";
590 if( $args->{branch
} ){
591 push @where_strs, "subscription.branchcode = ?";
592 push @where_args, "$args->{branch}";
594 if ( $args->{location
} ) {
595 push @where_strs, "subscription.location = ?";
596 push @where_args, "$args->{location}";
598 if ( $args->{expiration_date
} ) {
599 push @where_strs, "subscription.enddate <= ?";
600 push @where_args, "$args->{expiration_date}";
602 if( defined $args->{closed
} ){
603 push @where_strs, "subscription.closed = ?";
604 push @where_args, "$args->{closed}";
608 $query .= ' AND ' . join(' AND ', @where_strs);
610 if ( @
$additional_fields ) {
611 $query .= ' AND subscriptionid IN ('
612 . join( ', ', @
$matching_record_ids_for_additional_fields )
616 $query .= " ORDER BY " . $args->{orderby
} if $args->{orderby
};
618 my $dbh = C4
::Context
->dbh;
619 my $sth = $dbh->prepare($query);
620 $sth->execute(@where_args);
621 my $results = $sth->fetchall_arrayref( {} );
623 for my $subscription ( @
$results ) {
624 $subscription->{cannotedit
} = not can_edit_subscription
( $subscription );
625 $subscription->{cannotdisplay
} = not can_show_subscription
( $subscription );
627 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
628 record_id
=> $subscription->{subscriptionid
},
629 tablename
=> 'subscription'
631 $subscription->{additional_fields
} = $additional_field_values->{$subscription->{subscriptionid
}};
640 ($totalissues,@serials) = GetSerials($subscriptionid);
641 this function gets every serial not arrived for a given subscription
642 as well as the number of issues registered in the database (all types)
643 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
645 FIXME: We should return \@serials.
650 my ( $subscriptionid, $count ) = @_;
652 return unless $subscriptionid;
654 my $dbh = C4
::Context
->dbh;
656 # status = 2 is "arrived"
658 $count = 5 unless ($count);
660 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
, NOT_ISSUED
) );
661 my $query = "SELECT serialid,serialseq, status, publisheddate,
662 publisheddatetext, planneddate,notes, routingnotes
664 WHERE subscriptionid = ? AND status NOT IN ( $statuses )
665 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC";
666 my $sth = $dbh->prepare($query);
667 $sth->execute($subscriptionid);
669 while ( my $line = $sth->fetchrow_hashref ) {
670 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
671 for my $datefield ( qw( planneddate publisheddate) ) {
672 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
673 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
675 $line->{$datefield} = q{};
678 push @serials, $line;
681 # OK, now add the last 5 issues arrives/missing
682 $query = "SELECT serialid,serialseq, status, planneddate, publisheddate,
683 publisheddatetext, notes, routingnotes
685 WHERE subscriptionid = ?
686 AND status IN ( $statuses )
687 ORDER BY IF(publisheddate<>'0000-00-00',publisheddate,planneddate) DESC
689 $sth = $dbh->prepare($query);
690 $sth->execute($subscriptionid);
691 while ( ( my $line = $sth->fetchrow_hashref ) && $counter < $count ) {
693 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
694 for my $datefield ( qw( planneddate publisheddate) ) {
695 if ($line->{$datefield} && $line->{$datefield}!~m/^00/) {
696 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
698 $line->{$datefield} = q{};
702 push @serials, $line;
705 $query = "SELECT count(*) FROM serial WHERE subscriptionid=?";
706 $sth = $dbh->prepare($query);
707 $sth->execute($subscriptionid);
708 my ($totalissues) = $sth->fetchrow;
709 return ( $totalissues, @serials );
714 @serials = GetSerials2($subscriptionid,$statuses);
715 this function returns every serial waited for a given subscription
716 as well as the number of issues registered in the database (all types)
717 this number is used to see if a subscription can be deleted (=it must have only 1 issue)
719 $statuses is an arrayref of statuses and is mandatory.
724 my ( $subscription, $statuses ) = @_;
726 return unless ($subscription and @
$statuses);
728 my $dbh = C4
::Context
->dbh;
730 SELECT serialid
,serialseq
, status
, planneddate
, publisheddate
,
731 publisheddatetext
, notes
, routingnotes
733 WHERE subscriptionid
=?
735 . q
| AND status IN
(| . join( ",", ('?') x @
$statuses ) . q
|)|
737 ORDER BY publisheddate
,serialid DESC
739 $debug and warn "GetSerials2 query: $query";
740 my $sth = $dbh->prepare($query);
741 $sth->execute( $subscription, @
$statuses );
744 while ( my $line = $sth->fetchrow_hashref ) {
745 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
746 # Format dates for display
747 for my $datefield ( qw( planneddate publisheddate ) ) {
748 if (!defined($line->{$datefield}) || $line->{$datefield} =~m/^00/) {
749 $line->{$datefield} = q{};
752 $line->{$datefield} = output_pref
( { dt
=> dt_from_string
( $line->{$datefield} ), dateonly
=> 1 } );
755 push @serials, $line;
760 =head2 GetLatestSerials
762 \@serials = GetLatestSerials($subscriptionid,$limit)
763 get the $limit's latest serials arrived or missing for a given subscription
765 a ref to an array which contains all of the latest serials stored into a hash.
769 sub GetLatestSerials
{
770 my ( $subscriptionid, $limit ) = @_;
772 return unless ($subscriptionid and $limit);
774 my $dbh = C4
::Context
->dbh;
776 my $statuses = join( ',', ( ARRIVED
, MISSING_STATUSES
) );
777 my $strsth = "SELECT serialid,serialseq, status, planneddate, publisheddate, notes
779 WHERE subscriptionid = ?
780 AND status IN ($statuses)
781 ORDER BY publisheddate DESC LIMIT 0,$limit
783 my $sth = $dbh->prepare($strsth);
784 $sth->execute($subscriptionid);
786 while ( my $line = $sth->fetchrow_hashref ) {
787 $line->{ "status" . $line->{status
} } = 1; # fills a "statusX" value, used for template status select list
788 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{planneddate
} ), dateonly
=> 1 } );
789 $line->{publisheddate
} = output_pref
( { dt
=> dt_from_string
( $line->{publisheddate
} ), dateonly
=> 1 } );
790 push @serials, $line;
796 =head2 GetPreviousSerialid
798 $serialid = GetPreviousSerialid($subscriptionid, $nth)
799 get the $nth's previous serial for the given subscriptionid
805 sub GetPreviousSerialid
{
806 my ( $subscriptionid, $nth ) = @_;
808 my $dbh = C4
::Context
->dbh;
812 my $strsth = "SELECT serialid
814 WHERE subscriptionid = ?
816 ORDER BY serialid DESC LIMIT $nth,1
818 my $sth = $dbh->prepare($strsth);
819 $sth->execute($subscriptionid);
821 my $line = $sth->fetchrow_hashref;
822 $return = $line->{'serialid'} if ($line);
830 $nextseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
831 $newinnerloop1, $newinnerloop2, $newinnerloop3
832 ) = GetNextSeq( $subscription, $pattern, $planneddate );
834 $subscription is a hashref containing all the attributes of the table
836 $pattern is a hashref containing all the attributes of the table
837 'subscription_numberpatterns'.
838 $planneddate is a date string in iso format.
839 This function get the next issue for the subscription given on input arg
844 my ($subscription, $pattern, $planneddate) = @_;
846 return unless ($subscription and $pattern);
848 my ( $newlastvalue1, $newlastvalue2, $newlastvalue3,
849 $newinnerloop1, $newinnerloop2, $newinnerloop3 );
852 if ($subscription->{'skip_serialseq'}) {
853 my @irreg = split /;/, $subscription->{'irregularity'};
855 my $irregularities = {};
856 $irregularities->{$_} = 1 foreach(@irreg);
857 my $issueno = GetFictiveIssueNumber
($subscription, $planneddate) + 1;
858 while($irregularities->{$issueno}) {
865 my $numberingmethod = $pattern->{numberingmethod
};
867 if ($numberingmethod) {
868 $calculated = $numberingmethod;
869 my $locale = $subscription->{locale
};
870 $newlastvalue1 = $subscription->{lastvalue1
} || 0;
871 $newlastvalue2 = $subscription->{lastvalue2
} || 0;
872 $newlastvalue3 = $subscription->{lastvalue3
} || 0;
873 $newinnerloop1 = $subscription->{innerloop1
} || 0;
874 $newinnerloop2 = $subscription->{innerloop2
} || 0;
875 $newinnerloop3 = $subscription->{innerloop3
} || 0;
878 $calc{$_} = 1 if ($numberingmethod =~ /\{$_\}/);
881 for(my $i = 0; $i < $count; $i++) {
883 # check if we have to increase the new value.
885 if ($newinnerloop1 >= $pattern->{every1
}) {
887 $newlastvalue1 += $pattern->{add1
};
889 # reset counter if needed.
890 $newlastvalue1 = $pattern->{setto1
} if ($newlastvalue1 > $pattern->{whenmorethan1
});
893 # check if we have to increase the new value.
895 if ($newinnerloop2 >= $pattern->{every2
}) {
897 $newlastvalue2 += $pattern->{add2
};
899 # reset counter if needed.
900 $newlastvalue2 = $pattern->{setto2
} if ($newlastvalue2 > $pattern->{whenmorethan2
});
903 # check if we have to increase the new value.
905 if ($newinnerloop3 >= $pattern->{every3
}) {
907 $newlastvalue3 += $pattern->{add3
};
909 # reset counter if needed.
910 $newlastvalue3 = $pattern->{setto3
} if ($newlastvalue3 > $pattern->{whenmorethan3
});
914 my $newlastvalue1string = _numeration
( $newlastvalue1, $pattern->{numbering1
}, $locale );
915 $calculated =~ s/\{X\}/$newlastvalue1string/g;
918 my $newlastvalue2string = _numeration
( $newlastvalue2, $pattern->{numbering2
}, $locale );
919 $calculated =~ s/\{Y\}/$newlastvalue2string/g;
922 my $newlastvalue3string = _numeration
( $newlastvalue3, $pattern->{numbering3
}, $locale );
923 $calculated =~ s/\{Z\}/$newlastvalue3string/g;
928 $newlastvalue1, $newlastvalue2, $newlastvalue3,
929 $newinnerloop1, $newinnerloop2, $newinnerloop3);
934 $calculated = GetSeq($subscription, $pattern)
935 $subscription is a hashref containing all the attributes of the table 'subscription'
936 $pattern is a hashref containing all the attributes of the table 'subscription_numberpatterns'
937 this function transforms {X},{Y},{Z} to 150,0,0 for example.
939 the sequence in string format
944 my ($subscription, $pattern) = @_;
946 return unless ($subscription and $pattern);
948 my $locale = $subscription->{locale
};
950 my $calculated = $pattern->{numberingmethod
};
952 my $newlastvalue1 = $subscription->{'lastvalue1'} || 0;
953 $newlastvalue1 = _numeration
($newlastvalue1, $pattern->{numbering1
}, $locale) if ($pattern->{numbering1
}); # reset counter if needed.
954 $calculated =~ s/\{X\}/$newlastvalue1/g;
956 my $newlastvalue2 = $subscription->{'lastvalue2'} || 0;
957 $newlastvalue2 = _numeration
($newlastvalue2, $pattern->{numbering2
}, $locale) if ($pattern->{numbering2
}); # reset counter if needed.
958 $calculated =~ s/\{Y\}/$newlastvalue2/g;
960 my $newlastvalue3 = $subscription->{'lastvalue3'} || 0;
961 $newlastvalue3 = _numeration
($newlastvalue3, $pattern->{numbering3
}, $locale) if ($pattern->{numbering3
}); # reset counter if needed.
962 $calculated =~ s/\{Z\}/$newlastvalue3/g;
966 =head2 GetExpirationDate
968 $enddate = GetExpirationDate($subscriptionid, [$startdate])
970 this function return the next expiration date for a subscription given on input args.
977 sub GetExpirationDate
{
978 my ( $subscriptionid, $startdate ) = @_;
980 return unless ($subscriptionid);
982 my $dbh = C4
::Context
->dbh;
983 my $subscription = GetSubscription
($subscriptionid);
986 # we don't do the same test if the subscription is based on X numbers or on X weeks/months
987 $enddate = $startdate || $subscription->{startdate
};
988 my @date = split( /-/, $enddate );
990 return if ( scalar(@date) != 3 || not check_date
(@date) );
992 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
993 if ( $frequency and $frequency->{unit
} ) {
996 if ( my $length = $subscription->{numberlength
} ) {
998 #calculate the date of the last issue.
999 for ( my $i = 1 ; $i <= $length ; $i++ ) {
1000 $enddate = GetNextDate
( $subscription, $enddate );
1002 } elsif ( $subscription->{monthlength
} ) {
1003 if ( $$subscription{startdate
} ) {
1004 my @enddate = Add_Delta_YM
( $date[0], $date[1], $date[2], 0, $subscription->{monthlength
} );
1005 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1007 } elsif ( $subscription->{weeklength
} ) {
1008 if ( $$subscription{startdate
} ) {
1009 my @date = split( /-/, $subscription->{startdate
} );
1010 my @enddate = Add_Delta_Days
( $date[0], $date[1], $date[2], $subscription->{weeklength
} * 7 );
1011 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
1014 $enddate = $subscription->{enddate
};
1018 return $subscription->{enddate
};
1022 =head2 CountSubscriptionFromBiblionumber
1024 $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
1025 this returns a count of the subscriptions for a given biblionumber
1027 the number of subscriptions
1031 sub CountSubscriptionFromBiblionumber
{
1032 my ($biblionumber) = @_;
1034 return unless ($biblionumber);
1036 my $dbh = C4
::Context
->dbh;
1037 my $query = "SELECT count(*) FROM subscription WHERE biblionumber=?";
1038 my $sth = $dbh->prepare($query);
1039 $sth->execute($biblionumber);
1040 my $subscriptionsnumber = $sth->fetchrow;
1041 return $subscriptionsnumber;
1044 =head2 ModSubscriptionHistory
1046 ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$recievedlist,$missinglist,$opacnote,$librariannote);
1048 this function modifies the history of a subscription. Put your new values on input arg.
1049 returns the number of rows affected
1053 sub ModSubscriptionHistory
{
1054 my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
1056 return unless ($subscriptionid);
1058 my $dbh = C4
::Context
->dbh;
1059 my $query = "UPDATE subscriptionhistory
1060 SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
1061 WHERE subscriptionid=?
1063 my $sth = $dbh->prepare($query);
1064 $receivedlist =~ s/^; // if $receivedlist;
1065 $missinglist =~ s/^; // if $missinglist;
1066 $opacnote =~ s/^; // if $opacnote;
1067 $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
1071 =head2 ModSerialStatus
1073 ModSerialStatus($serialid, $serialseq, $planneddate, $publisheddate,
1074 $publisheddatetext, $status, $notes);
1076 This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
1077 Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
1081 sub ModSerialStatus
{
1082 my ($serialid, $serialseq, $planneddate, $publisheddate, $publisheddatetext,
1083 $status, $notes) = @_;
1085 return unless ($serialid);
1087 #It is a usual serial
1088 # 1st, get previous status :
1089 my $dbh = C4
::Context
->dbh;
1090 my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
1091 FROM serial, subscription
1092 WHERE serial.subscriptionid=subscription.subscriptionid
1094 my $sth = $dbh->prepare($query);
1095 $sth->execute($serialid);
1096 my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
1097 my $frequency = GetSubscriptionFrequency
($periodicity);
1099 # change status & update subscriptionhistory
1101 if ( $status == DELETED
) {
1102 DelIssue
( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
1107 SET serialseq = ?, publisheddate = ?, publisheddatetext = ?,
1108 planneddate = ?, status = ?, notes = ?
1111 $sth = $dbh->prepare($query);
1112 $sth->execute( $serialseq, $publisheddate, $publisheddatetext,
1113 $planneddate, $status, $notes, $serialid );
1114 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1115 $sth = $dbh->prepare($query);
1116 $sth->execute($subscriptionid);
1117 my $val = $sth->fetchrow_hashref;
1118 unless ( $val->{manualhistory
} ) {
1119 $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE subscriptionid=?";
1120 $sth = $dbh->prepare($query);
1121 $sth->execute($subscriptionid);
1122 my ( $missinglist, $recievedlist ) = $sth->fetchrow;
1124 if ( $status == ARRIVED
|| ($oldstatus == ARRIVED
&& $status != ARRIVED
) ) {
1125 $recievedlist .= "; $serialseq"
1126 if ($recievedlist !~ /(^|;)\s*$serialseq(?=;|$)/);
1129 # in case serial has been previously marked as missing
1130 if (grep /$status/, (EXPECTED
, ARRIVED
, LATE
, CLAIMED
)) {
1131 $missinglist=~ s/(^|;)\s*$serialseq(?=;|$)//g;
1134 $missinglist .= "; $serialseq"
1135 if ( ( grep { $_ == $status } ( MISSING_STATUSES
) ) && ( $missinglist !~/(^|;)\s*$serialseq(?=;|$)/ ) );
1136 $missinglist .= "; not issued $serialseq"
1137 if ( $status == NOT_ISSUED
&& $missinglist !~ /(^|;)\s*$serialseq(?=;|$)/ );
1139 $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE subscriptionid=?";
1140 $sth = $dbh->prepare($query);
1141 $recievedlist =~ s/^; //;
1142 $missinglist =~ s/^; //;
1143 $sth->execute( $recievedlist, $missinglist, $subscriptionid );
1147 # create new expected entry if needed (ie : was "expected" and has changed)
1148 my $otherIssueExpected = scalar findSerialsByStatus
(EXPECTED
, $subscriptionid);
1149 if ( !$otherIssueExpected && $oldstatus == EXPECTED
&& $status != EXPECTED
) {
1150 my $subscription = GetSubscription
($subscriptionid);
1151 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1155 $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3,
1156 $newinnerloop1, $newinnerloop2, $newinnerloop3
1158 = GetNextSeq
( $subscription, $pattern, $publisheddate );
1160 # next date (calculated from actual date & frequency parameters)
1161 my $nextpublisheddate = GetNextDate
($subscription, $publisheddate, 1);
1162 my $nextpubdate = $nextpublisheddate;
1163 $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
1164 WHERE subscriptionid = ?";
1165 $sth = $dbh->prepare($query);
1166 $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
1168 NewIssue
( $newserialseq, $subscriptionid, $subscription->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
1170 # check if an alert must be sent... (= a letter is defined & status became "arrived"
1171 if ( $subscription->{letter
} && $status == ARRIVED
&& $oldstatus != ARRIVED
) {
1172 require C4
::Letters
;
1173 C4
::Letters
::SendAlerts
( 'issue', $serialid, $subscription->{letter
} );
1180 =head2 GetNextExpected
1182 $nextexpected = GetNextExpected($subscriptionid)
1184 Get the planneddate for the current expected issue of the subscription.
1190 planneddate => ISO date
1195 sub GetNextExpected
{
1196 my ($subscriptionid) = @_;
1198 my $dbh = C4
::Context
->dbh;
1202 WHERE subscriptionid
= ?
1206 my $sth = $dbh->prepare($query);
1208 # Each subscription has only one 'expected' issue.
1209 $sth->execute( $subscriptionid, EXPECTED
);
1210 my $nextissue = $sth->fetchrow_hashref;
1211 if ( !$nextissue ) {
1215 WHERE subscriptionid
= ?
1216 ORDER BY publisheddate DESC
1219 $sth = $dbh->prepare($query);
1220 $sth->execute($subscriptionid);
1221 $nextissue = $sth->fetchrow_hashref;
1223 foreach(qw
/planneddate publisheddate/) {
1224 if ( !defined $nextissue->{$_} ) {
1225 # or should this default to 1st Jan ???
1226 $nextissue->{$_} = strftime
( '%Y-%m-%d', localtime );
1228 $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
1236 =head2 ModNextExpected
1238 ModNextExpected($subscriptionid,$date)
1240 Update the planneddate for the current expected issue of the subscription.
1241 This will modify all future prediction results.
1243 C<$date> is an ISO date.
1249 sub ModNextExpected
{
1250 my ( $subscriptionid, $date ) = @_;
1251 my $dbh = C4
::Context
->dbh;
1253 #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here
1254 my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?');
1256 # Each subscription has only one 'expected' issue.
1257 $sth->execute( $date, $date, $subscriptionid, EXPECTED
);
1262 =head2 GetSubscriptionIrregularities
1266 =item @irreg = &GetSubscriptionIrregularities($subscriptionid);
1267 get the list of irregularities for a subscription
1273 sub GetSubscriptionIrregularities
{
1274 my $subscriptionid = shift;
1276 return unless $subscriptionid;
1278 my $dbh = C4
::Context
->dbh;
1282 WHERE subscriptionid
= ?
1284 my $sth = $dbh->prepare($query);
1285 $sth->execute($subscriptionid);
1287 my ($result) = $sth->fetchrow_array;
1288 my @irreg = split /;/, $result;
1293 =head2 ModSubscription
1295 this function modifies a subscription. Put all new values on input args.
1296 returns the number of rows affected
1300 sub ModSubscription
{
1302 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
1303 $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
1304 $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
1305 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
1306 $biblionumber, $callnumber, $notes, $letter, $manualhistory,
1307 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1308 $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq,
1309 $itemtype, $previousitemtype
1312 my $dbh = C4
::Context
->dbh;
1313 my $query = "UPDATE subscription
1314 SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
1315 startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
1316 numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
1317 lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
1318 lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
1319 callnumber=?, notes=?, letter=?, manualhistory=?,
1320 internalnotes=?, serialsadditems=?, staffdisplaycount=?,
1321 opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
1322 skip_serialseq=?, itemtype=?, previousitemtype=?
1323 WHERE subscriptionid = ?";
1325 my $sth = $dbh->prepare($query);
1327 $auser, $branchcode, $aqbooksellerid, $cost,
1328 $aqbudgetid, $startdate, $periodicity, $firstacquidate,
1329 $irregularity, $numberpattern, $locale, $numberlength,
1330 $weeklength, $monthlength, $lastvalue1, $innerloop1,
1331 $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
1332 $status, $biblionumber, $callnumber, $notes,
1333 $letter, ($manualhistory ?
$manualhistory : 0),
1334 $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
1335 $graceperiod, $location, $enddate, $skip_serialseq,
1336 $itemtype, $previousitemtype,
1339 my $rows = $sth->rows;
1341 logaction
( "SERIAL", "MODIFY", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1345 =head2 NewSubscription
1347 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
1348 $startdate,$periodicity,$numberlength,$weeklength,$monthlength,
1349 $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
1350 $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
1351 $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems,
1352 $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
1353 $skip_serialseq, $itemtype, $previousitemtype);
1355 Create a new subscription with value given on input args.
1358 the id of this new subscription
1362 sub NewSubscription
{
1364 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1365 $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
1366 $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
1367 $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
1368 $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
1369 $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
1370 $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype
1372 my $dbh = C4
::Context
->dbh;
1374 #save subscription (insert into database)
1376 INSERT INTO subscription
1377 (librarian
, branchcode
, aqbooksellerid
, cost
, aqbudgetid
,
1378 biblionumber
, startdate
, periodicity
, numberlength
, weeklength
,
1379 monthlength
, lastvalue1
, innerloop1
, lastvalue2
, innerloop2
,
1380 lastvalue3
, innerloop3
, status
, notes
, letter
, firstacquidate
,
1381 irregularity
, numberpattern
, locale
, callnumber
,
1382 manualhistory
, internalnotes
, serialsadditems
, staffdisplaycount
,
1383 opacdisplaycount
, graceperiod
, location
, enddate
, skip_serialseq
,
1384 itemtype
, previousitemtype
)
1385 VALUES
(?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
,?
)
1387 my $sth = $dbh->prepare($query);
1389 $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
1390 $startdate, $periodicity, $numberlength, $weeklength,
1391 $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
1392 $lastvalue3, $innerloop3, $status, $notes, $letter,
1393 $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
1394 $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
1395 $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq,
1396 $itemtype, $previousitemtype
1399 my $subscriptionid = $dbh->{'mysql_insertid'};
1401 $enddate = GetExpirationDate
( $subscriptionid, $startdate );
1405 WHERE subscriptionid
=?
1407 $sth = $dbh->prepare($query);
1408 $sth->execute( $enddate, $subscriptionid );
1411 # then create the 1st expected number
1413 INSERT INTO subscriptionhistory
1414 (biblionumber
, subscriptionid
, histstartdate
, missinglist
, recievedlist
)
1415 VALUES
(?
,?
,?
, '', '')
1417 $sth = $dbh->prepare($query);
1418 $sth->execute( $biblionumber, $subscriptionid, $startdate);
1420 # reread subscription to get a hash (for calculation of the 1st issue number)
1421 my $subscription = GetSubscription
($subscriptionid);
1422 my $pattern = C4
::Serials
::Numberpattern
::GetSubscriptionNumberpattern
($subscription->{numberpattern
});
1424 # calculate issue number
1425 my $serialseq = GetSeq
($subscription, $pattern) || q{};
1429 serialseq
=> $serialseq,
1430 serialseq_x
=> $subscription->{'lastvalue1'},
1431 serialseq_y
=> $subscription->{'lastvalue2'},
1432 serialseq_z
=> $subscription->{'lastvalue3'},
1433 subscriptionid
=> $subscriptionid,
1434 biblionumber
=> $biblionumber,
1436 planneddate
=> $firstacquidate,
1437 publisheddate
=> $firstacquidate,
1441 logaction
( "SERIAL", "ADD", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1443 #set serial flag on biblio if not already set.
1444 my $biblio = Koha
::Biblios
->find( $biblionumber );
1445 if ( $biblio and !$biblio->serial ) {
1446 my $record = GetMarcBiblio
({ biblionumber
=> $biblionumber });
1447 my ( $tag, $subf ) = GetMarcFromKohaField
( 'biblio.serial', $biblio->frameworkcode );
1449 eval { $record->field($tag)->update( $subf => 1 ); };
1451 ModBiblio
( $record, $biblionumber, $biblio->frameworkcode );
1453 return $subscriptionid;
1456 =head2 ReNewSubscription
1458 ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
1460 this function renew a subscription with values given on input args.
1464 sub ReNewSubscription
{
1465 my ( $subscriptionid, $user, $startdate, $numberlength, $weeklength, $monthlength, $note ) = @_;
1466 my $dbh = C4
::Context
->dbh;
1467 my $subscription = GetSubscription
($subscriptionid);
1471 LEFT JOIN biblioitems ON biblio
.biblionumber
=biblioitems
.biblionumber
1472 WHERE biblio
.biblionumber
=?
1474 my $sth = $dbh->prepare($query);
1475 $sth->execute( $subscription->{biblionumber
} );
1476 my $biblio = $sth->fetchrow_hashref;
1478 if ( C4
::Context
->preference("RenewSerialAddsSuggestion") ) {
1479 require C4
::Suggestions
;
1480 C4
::Suggestions
::NewSuggestion
(
1481 { 'suggestedby' => $user,
1482 'title' => $subscription->{bibliotitle
},
1483 'author' => $biblio->{author
},
1484 'publishercode' => $biblio->{publishercode
},
1485 'note' => $biblio->{note
},
1486 'biblionumber' => $subscription->{biblionumber
}
1491 $numberlength ||= 0; # Should not we raise an exception instead?
1494 # renew subscription
1497 SET startdate
=?
,numberlength
=?
,weeklength
=?
,monthlength
=?
,reneweddate
=NOW
()
1498 WHERE subscriptionid
=?
1500 $sth = $dbh->prepare($query);
1501 $sth->execute( $startdate, $numberlength, $weeklength, $monthlength, $subscriptionid );
1502 my $enddate = GetExpirationDate
($subscriptionid);
1503 $debug && warn "enddate :$enddate";
1507 WHERE subscriptionid
=?
1509 $sth = $dbh->prepare($query);
1510 $sth->execute( $enddate, $subscriptionid );
1512 logaction
( "SERIAL", "RENEW", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1518 NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $planneddate, $publisheddate, $notes)
1520 Create a new issue stored on the database.
1521 Note : we have to update the recievedlist and missinglist on subscriptionhistory for this subscription.
1522 returns the serial id
1527 my ( $serialseq, $subscriptionid, $biblionumber, $status, $planneddate,
1528 $publisheddate, $publisheddatetext, $notes ) = @_;
1529 ### FIXME biblionumber CAN be provided by subscriptionid. So Do we STILL NEED IT ?
1531 return unless ($subscriptionid);
1533 my $schema = Koha
::Database
->new()->schema();
1535 my $subscription = Koha
::Subscriptions
->find( $subscriptionid );
1537 my $serial = Koha
::Serial
->new(
1539 serialseq
=> $serialseq,
1540 serialseq_x
=> $subscription->lastvalue1(),
1541 serialseq_y
=> $subscription->lastvalue2(),
1542 serialseq_z
=> $subscription->lastvalue3(),
1543 subscriptionid
=> $subscriptionid,
1544 biblionumber
=> $biblionumber,
1546 planneddate
=> $planneddate,
1547 publisheddate
=> $publisheddate,
1548 publisheddatetext
=> $publisheddatetext,
1553 my $serialid = $serial->id();
1555 my $subscription_history = Koha
::Subscription
::Histories
->find($subscriptionid);
1556 my $missinglist = $subscription_history->missinglist();
1557 my $recievedlist = $subscription_history->recievedlist();
1559 if ( $status == ARRIVED
) {
1560 ### TODO Add a feature that improves recognition and description.
1561 ### As such count (serialseq) i.e. : N18,2(N19),N20
1562 ### Would use substr and index But be careful to previous presence of ()
1563 $recievedlist .= "; $serialseq" unless ( index( $recievedlist, $serialseq ) > 0 );
1565 if ( grep { /^$status$/ } (MISSING_STATUSES
) ) {
1566 $missinglist .= "; $serialseq" unless ( index( $missinglist, $serialseq ) > 0 );
1569 $recievedlist =~ s/^; //;
1570 $missinglist =~ s/^; //;
1572 $subscription_history->recievedlist($recievedlist);
1573 $subscription_history->missinglist($missinglist);
1574 $subscription_history->store();
1579 =head2 HasSubscriptionStrictlyExpired
1581 1 or 0 = HasSubscriptionStrictlyExpired($subscriptionid)
1583 the subscription has stricly expired when today > the end subscription date
1586 1 if true, 0 if false, -1 if the expiration date is not set.
1590 sub HasSubscriptionStrictlyExpired
{
1592 # Getting end of subscription date
1593 my ($subscriptionid) = @_;
1595 return unless ($subscriptionid);
1597 my $dbh = C4
::Context
->dbh;
1598 my $subscription = GetSubscription
($subscriptionid);
1599 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1601 # If the expiration date is set
1602 if ( $expirationdate != 0 ) {
1603 my ( $endyear, $endmonth, $endday ) = split( '-', $expirationdate );
1605 # Getting today's date
1606 my ( $nowyear, $nowmonth, $nowday ) = Today
();
1608 # if today's date > expiration date, then the subscription has stricly expired
1609 if ( Delta_Days
( $nowyear, $nowmonth, $nowday, $endyear, $endmonth, $endday ) < 0 ) {
1616 # There are some cases where the expiration date is not set
1617 # As we can't determine if the subscription has expired on a date-basis,
1623 =head2 HasSubscriptionExpired
1625 $has_expired = HasSubscriptionExpired($subscriptionid)
1627 the subscription has expired when the next issue to arrive is out of subscription limit.
1630 0 if the subscription has not expired
1631 1 if the subscription has expired
1632 2 if has subscription does not have a valid expiration date set
1636 sub HasSubscriptionExpired
{
1637 my ($subscriptionid) = @_;
1639 return unless ($subscriptionid);
1641 my $dbh = C4
::Context
->dbh;
1642 my $subscription = GetSubscription
($subscriptionid);
1643 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($subscription->{periodicity
});
1644 if ( $frequency and $frequency->{unit
} ) {
1645 my $expirationdate = $subscription->{enddate
} || GetExpirationDate
($subscriptionid);
1646 if (!defined $expirationdate) {
1647 $expirationdate = q{};
1650 SELECT max
(planneddate
)
1652 WHERE subscriptionid
=?
1654 my $sth = $dbh->prepare($query);
1655 $sth->execute($subscriptionid);
1656 my ($res) = $sth->fetchrow;
1657 if (!$res || $res=~m/^0000/) {
1660 my @res = split( /-/, $res );
1661 my @endofsubscriptiondate = split( /-/, $expirationdate );
1662 return 2 if ( scalar(@res) != 3 || scalar(@endofsubscriptiondate) != 3 || not check_date
(@res) || not check_date
(@endofsubscriptiondate) );
1664 if ( ( @endofsubscriptiondate && Delta_Days
( $res[0], $res[1], $res[2], $endofsubscriptiondate[0], $endofsubscriptiondate[1], $endofsubscriptiondate[2] ) <= 0 )
1669 if ( $subscription->{'numberlength'} ) {
1670 my $countreceived = countissuesfrom
( $subscriptionid, $subscription->{'startdate'} );
1671 return 1 if ( $countreceived > $subscription->{'numberlength'} );
1677 return 0; # Notice that you'll never get here.
1680 =head2 DelSubscription
1682 DelSubscription($subscriptionid)
1683 this function deletes subscription which has $subscriptionid as id.
1687 sub DelSubscription
{
1688 my ($subscriptionid) = @_;
1689 my $dbh = C4
::Context
->dbh;
1690 $dbh->do("DELETE FROM subscription WHERE subscriptionid=?", undef, $subscriptionid);
1691 $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=?", undef, $subscriptionid);
1692 $dbh->do("DELETE FROM serial WHERE subscriptionid=?", undef, $subscriptionid);
1694 my $afs = Koha
::AdditionalField
->all({tablename
=> 'subscription'});
1695 foreach my $af (@
$afs) {
1696 $af->delete_values({record_id
=> $subscriptionid});
1699 logaction
( "SERIAL", "DELETE", $subscriptionid, "" ) if C4
::Context
->preference("SubscriptionLog");
1704 DelIssue($serialseq,$subscriptionid)
1705 this function deletes an issue which has $serialseq and $subscriptionid given on input arg.
1707 returns the number of rows affected
1712 my ($dataissue) = @_;
1713 my $dbh = C4
::Context
->dbh;
1714 ### TODO Add itemdeletion. Would need to get itemnumbers. Should be in a pref ?
1719 AND subscriptionid
= ?
1721 my $mainsth = $dbh->prepare($query);
1722 $mainsth->execute( $dataissue->{'serialid'}, $dataissue->{'subscriptionid'} );
1724 #Delete element from subscription history
1725 $query = "SELECT * FROM subscription WHERE subscriptionid = ?";
1726 my $sth = $dbh->prepare($query);
1727 $sth->execute( $dataissue->{'subscriptionid'} );
1728 my $val = $sth->fetchrow_hashref;
1729 unless ( $val->{manualhistory
} ) {
1731 SELECT
* FROM subscriptionhistory
1732 WHERE subscriptionid
= ?
1734 my $sth = $dbh->prepare($query);
1735 $sth->execute( $dataissue->{'subscriptionid'} );
1736 my $data = $sth->fetchrow_hashref;
1737 my $serialseq = $dataissue->{'serialseq'};
1738 $data->{'missinglist'} =~ s/\b$serialseq\b//;
1739 $data->{'recievedlist'} =~ s/\b$serialseq\b//;
1740 my $strsth = "UPDATE subscriptionhistory SET " . join( ",", map { join( "=", $_, $dbh->quote( $data->{$_} ) ) } keys %$data ) . " WHERE subscriptionid=?";
1741 $sth = $dbh->prepare($strsth);
1742 $sth->execute( $dataissue->{'subscriptionid'} );
1745 return $mainsth->rows;
1748 =head2 GetLateOrMissingIssues
1750 @issuelist = GetLateMissingIssues($supplierid,$serialid)
1752 this function selects missing issues on database - where serial.status = MISSING* or serial.status = LATE or planneddate<now
1755 the issuelist as an array of hash refs. Each element of this array contains
1756 name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
1760 sub GetLateOrMissingIssues
{
1761 my ( $supplierid, $serialid, $order ) = @_;
1763 return unless ( $supplierid or $serialid );
1765 my $dbh = C4
::Context
->dbh;
1770 $byserial = "and serialid = " . $serialid;
1773 $order .= ", title";
1777 my $missing_statuses_string = join ',', (MISSING_STATUSES
);
1779 $sth = $dbh->prepare(
1781 serialid, aqbooksellerid, name,
1782 biblio.title, biblioitems.issn, planneddate, serialseq,
1783 serial.status, serial.subscriptionid, claimdate, claims_count,
1784 subscription.branchcode
1786 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1787 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1788 LEFT JOIN biblioitems ON subscription.biblionumber=biblioitems.biblionumber
1789 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1790 WHERE subscription.subscriptionid = serial.subscriptionid
1791 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1792 AND subscription.aqbooksellerid=$supplierid
1797 $sth = $dbh->prepare(
1799 serialid, aqbooksellerid, name,
1800 biblio.title, planneddate, serialseq,
1801 serial.status, serial.subscriptionid, claimdate, claims_count,
1802 subscription.branchcode
1804 LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
1805 LEFT JOIN biblio ON subscription.biblionumber=biblio.biblionumber
1806 LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
1807 WHERE subscription.subscriptionid = serial.subscriptionid
1808 AND (serial.STATUS IN ($missing_statuses_string) OR ((planneddate < now() AND serial.STATUS = ?) OR serial.STATUS = ? OR serial.STATUS = ?))
1813 $sth->execute( EXPECTED
, LATE
, CLAIMED
);
1815 while ( my $line = $sth->fetchrow_hashref ) {
1817 if ($line->{planneddate
} && $line->{planneddate
} !~/^0+\-/) {
1818 $line->{planneddateISO
} = $line->{planneddate
};
1819 $line->{planneddate
} = output_pref
( { dt
=> dt_from_string
( $line->{"planneddate"} ), dateonly
=> 1 } );
1821 if ($line->{claimdate
} && $line->{claimdate
} !~/^0+\-/) {
1822 $line->{claimdateISO
} = $line->{claimdate
};
1823 $line->{claimdate
} = output_pref
( { dt
=> dt_from_string
( $line->{"claimdate"} ), dateonly
=> 1 } );
1825 $line->{"status".$line->{status
}} = 1;
1827 my $additional_field_values = Koha
::AdditionalField
->fetch_all_values({
1828 record_id
=> $line->{subscriptionid
},
1829 tablename
=> 'subscription'
1831 %$line = ( %$line, additional_fields
=> $additional_field_values->{$line->{subscriptionid
}} );
1833 push @issuelist, $line;
1840 &updateClaim($serialid)
1842 this function updates the time when a claim is issued for late/missing items
1844 called from claims.pl file
1849 my ($serialids) = @_;
1850 return unless $serialids;
1851 unless ( ref $serialids ) {
1852 $serialids = [ $serialids ];
1854 my $dbh = C4
::Context
->dbh;
1857 SET claimdate
= NOW
(),
1858 claims_count
= claims_count
+ 1,
1860 WHERE serialid
in (| . join( q
|,|, (q
|?
|) x @
$serialids ) . q
|)|,
1861 {}, CLAIMED
, @
$serialids );
1864 =head2 check_routing
1866 $result = &check_routing($subscriptionid)
1868 this function checks to see if a serial has a routing list and returns the count of routingid
1869 used to show either an 'add' or 'edit' link
1874 my ($subscriptionid) = @_;
1876 return unless ($subscriptionid);
1878 my $dbh = C4
::Context
->dbh;
1879 my $sth = $dbh->prepare(
1880 "SELECT count(routingid) routingids FROM subscription LEFT JOIN subscriptionroutinglist
1881 ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
1882 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC
1885 $sth->execute($subscriptionid);
1886 my $line = $sth->fetchrow_hashref;
1887 my $result = $line->{'routingids'};
1891 =head2 addroutingmember
1893 addroutingmember($borrowernumber,$subscriptionid)
1895 this function takes a borrowernumber and subscriptionid and adds the member to the
1896 routing list for that serial subscription and gives them a rank on the list
1897 of either 1 or highest current rank + 1
1901 sub addroutingmember
{
1902 my ( $borrowernumber, $subscriptionid ) = @_;
1904 return unless ($borrowernumber and $subscriptionid);
1907 my $dbh = C4
::Context
->dbh;
1908 my $sth = $dbh->prepare( "SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?" );
1909 $sth->execute($subscriptionid);
1910 while ( my $line = $sth->fetchrow_hashref ) {
1911 if ( $line->{'rank'} > 0 ) {
1912 $rank = $line->{'rank'} + 1;
1917 $sth = $dbh->prepare( "INSERT INTO subscriptionroutinglist (subscriptionid,borrowernumber,ranking) VALUES (?,?,?)" );
1918 $sth->execute( $subscriptionid, $borrowernumber, $rank );
1921 =head2 reorder_members
1923 reorder_members($subscriptionid,$routingid,$rank)
1925 this function is used to reorder the routing list
1927 it takes the routingid of the member one wants to re-rank and the rank it is to move to
1928 - it gets all members on list puts their routingid's into an array
1929 - removes the one in the array that is $routingid
1930 - then reinjects $routingid at point indicated by $rank
1931 - then update the database with the routingids in the new order
1935 sub reorder_members
{
1936 my ( $subscriptionid, $routingid, $rank ) = @_;
1937 my $dbh = C4
::Context
->dbh;
1938 my $sth = $dbh->prepare( "SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC" );
1939 $sth->execute($subscriptionid);
1941 while ( my $line = $sth->fetchrow_hashref ) {
1942 push( @result, $line->{'routingid'} );
1945 # To find the matching index
1947 my $key = -1; # to allow for 0 being a valid response
1948 for ( $i = 0 ; $i < @result ; $i++ ) {
1949 if ( $routingid == $result[$i] ) {
1950 $key = $i; # save the index
1955 # if index exists in array then move it to new position
1956 if ( $key > -1 && $rank > 0 ) {
1957 my $new_rank = $rank - 1; # $new_rank is what you want the new index to be in the array
1958 my $moving_item = splice( @result, $key, 1 );
1959 splice( @result, $new_rank, 0, $moving_item );
1961 for ( my $j = 0 ; $j < @result ; $j++ ) {
1962 my $sth = $dbh->prepare( "UPDATE subscriptionroutinglist SET ranking = '" . ( $j + 1 ) . "' WHERE routingid = '" . $result[$j] . "'" );
1968 =head2 delroutingmember
1970 delroutingmember($routingid,$subscriptionid)
1972 this function either deletes one member from routing list if $routingid exists otherwise
1973 deletes all members from the routing list
1977 sub delroutingmember
{
1979 # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
1980 my ( $routingid, $subscriptionid ) = @_;
1981 my $dbh = C4
::Context
->dbh;
1983 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
1984 $sth->execute($routingid);
1985 reorder_members
( $subscriptionid, $routingid );
1987 my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
1988 $sth->execute($subscriptionid);
1993 =head2 getroutinglist
1995 @routinglist = getroutinglist($subscriptionid)
1997 this gets the info from the subscriptionroutinglist for $subscriptionid
2000 the routinglist as an array. Each element of the array contains a hash_ref containing
2001 routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
2005 sub getroutinglist
{
2006 my ($subscriptionid) = @_;
2007 my $dbh = C4
::Context
->dbh;
2008 my $sth = $dbh->prepare(
2009 'SELECT routingid, borrowernumber, ranking, biblionumber
2011 JOIN subscriptionroutinglist ON subscription.subscriptionid = subscriptionroutinglist.subscriptionid
2012 WHERE subscription.subscriptionid = ? ORDER BY ranking ASC'
2014 $sth->execute($subscriptionid);
2015 my $routinglist = $sth->fetchall_arrayref({});
2016 return @
{$routinglist};
2019 =head2 countissuesfrom
2021 $result = countissuesfrom($subscriptionid,$startdate)
2023 Returns a count of serial rows matching the given subsctiptionid
2024 with published date greater than startdate
2028 sub countissuesfrom
{
2029 my ( $subscriptionid, $startdate ) = @_;
2030 my $dbh = C4
::Context
->dbh;
2034 WHERE subscriptionid
=?
2035 AND serial
.publisheddate
>?
2037 my $sth = $dbh->prepare($query);
2038 $sth->execute( $subscriptionid, $startdate );
2039 my ($countreceived) = $sth->fetchrow;
2040 return $countreceived;
2045 $result = CountIssues($subscriptionid)
2047 Returns a count of serial rows matching the given subsctiptionid
2052 my ($subscriptionid) = @_;
2053 my $dbh = C4
::Context
->dbh;
2057 WHERE subscriptionid
=?
2059 my $sth = $dbh->prepare($query);
2060 $sth->execute($subscriptionid);
2061 my ($countreceived) = $sth->fetchrow;
2062 return $countreceived;
2067 $result = HasItems($subscriptionid)
2069 returns a count of items from serial matching the subscriptionid
2074 my ($subscriptionid) = @_;
2075 my $dbh = C4
::Context
->dbh;
2077 SELECT COUNT
(serialitems
.itemnumber
)
2079 LEFT JOIN serialitems USING
(serialid
)
2080 WHERE subscriptionid
=? AND serialitems
.serialid IS NOT NULL
2082 my $sth=$dbh->prepare($query);
2083 $sth->execute($subscriptionid);
2084 my ($countitems)=$sth->fetchrow_array();
2088 =head2 abouttoexpire
2090 $result = abouttoexpire($subscriptionid)
2092 this function alerts you to the penultimate issue for a serial subscription
2094 returns 1 - if this is the penultimate issue
2100 my ($subscriptionid) = @_;
2101 my $dbh = C4
::Context
->dbh;
2102 my $subscription = GetSubscription
($subscriptionid);
2103 my $per = $subscription->{'periodicity'};
2104 my $frequency = C4
::Serials
::Frequency
::GetSubscriptionFrequency
($per);
2105 if ($frequency and $frequency->{unit
}){
2107 my $expirationdate = GetExpirationDate
($subscriptionid);
2109 my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
2110 my $nextdate = GetNextDate
($subscription, $res);
2112 # only compare dates if both dates exist.
2113 if ($nextdate and $expirationdate) {
2114 if(Date
::Calc
::Delta_Days
(
2115 split( /-/, $nextdate ),
2116 split( /-/, $expirationdate )
2122 } elsif ($subscription->{numberlength
}>0) {
2123 return (countissuesfrom
($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength
}-1);
2129 =head2 GetFictiveIssueNumber
2131 $issueno = GetFictiveIssueNumber($subscription, $publishedate);
2133 Get the position of the issue published at $publisheddate, considering the
2134 first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
2135 This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
2136 issue is declared as 'irregular' (will be skipped at receipt), the next issue number
2137 will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
2138 depending on how many rows are in serial table.
2139 The issue number calculation is based on subscription frequency, first acquisition
2140 date, and $publisheddate.
2142 Returns undef when called for irregular frequencies.
2144 The routine is used to skip irregularities when calculating the next issue
2145 date (in GetNextDate) or the next issue number (in GetNextSeq).
2149 sub GetFictiveIssueNumber
{
2150 my ($subscription, $publisheddate) = @_;
2152 my $frequency = GetSubscriptionFrequency
($subscription->{'periodicity'});
2153 my $unit = $frequency->{unit
} ?
lc $frequency->{'unit'} : undef;
2157 my ( $year, $month, $day ) = split /-/, $publisheddate;
2158 my ( $fa_year, $fa_month, $fa_day ) = split /-/, $subscription->{'firstacquidate'};
2159 my $delta = _delta_units
( [$fa_year, $fa_month, $fa_day], [$year, $month, $day], $unit );
2161 if( $frequency->{'unitsperissue'} == 1 ) {
2162 $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
2163 } else { # issuesperunit == 1
2164 $issueno = 1 + int( $delta / $frequency->{'unitsperissue'} );
2170 my ( $date1, $date2, $unit ) = @_;
2171 # date1 and date2 are array refs in the form [ yy, mm, dd ]
2173 if( $unit eq 'day' ) {
2174 return Delta_Days
( @
$date1, @
$date2 );
2175 } elsif( $unit eq 'week' ) {
2176 return int( Delta_Days
( @
$date1, @
$date2 ) / 7 );
2179 # In case of months or years, this is a wrapper around N_Delta_YMD.
2180 # Note that N_Delta_YMD returns 29 days between e.g. 22-2-72 and 22-3-72
2181 # while we expect 1 month.
2182 my @delta = N_Delta_YMD
( @
$date1, @
$date2 );
2183 if( $delta[2] > 27 ) {
2184 # Check if we could add a month
2185 my @jump = Add_Delta_YM
( @
$date1, $delta[0], 1 + $delta[1] );
2186 if( Delta_Days
( @jump, @
$date2 ) >= 0 ) {
2190 if( $delta[1] >= 12 ) {
2194 # if unit is year, we only return full years
2195 return $unit eq 'month' ?
$delta[0] * 12 + $delta[1] : $delta[0];
2198 sub _get_next_date_day
{
2199 my ($subscription, $freqdata, $year, $month, $day) = @_;
2201 my @newissue; # ( yy, mm, dd )
2202 # We do not need $delta_days here, since it would be zero where used
2204 if( $freqdata->{issuesperunit
} == 1 ) {
2206 @newissue = Add_Delta_Days
(
2207 $year, $month, $day, $freqdata->{"unitsperissue"} );
2208 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2210 @newissue = ( $year, $month, $day );
2211 $subscription->{countissuesperunit
}++;
2213 # We finished a cycle of issues within a unit.
2214 # No subtraction of zero needed, just add one day
2215 @newissue = Add_Delta_Days
( $year, $month, $day, 1 );
2216 $subscription->{countissuesperunit
} = 1;
2221 sub _get_next_date_week
{
2222 my ($subscription, $freqdata, $year, $month, $day) = @_;
2224 my @newissue; # ( yy, mm, dd )
2225 my $delta_days = int( 7 / $freqdata->{issuesperunit
} );
2227 if( $freqdata->{issuesperunit
} == 1 ) {
2228 # Add full weeks (of 7 days)
2229 @newissue = Add_Delta_Days
(
2230 $year, $month, $day, 7 * $freqdata->{"unitsperissue"} );
2231 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2232 # Add rounded number of days based on frequency.
2233 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2234 $subscription->{countissuesperunit
}++;
2236 # We finished a cycle of issues within a unit.
2237 # Subtract delta * (issues - 1), add 1 week
2238 @newissue = Add_Delta_Days
( $year, $month, $day,
2239 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2240 @newissue = Add_Delta_Days
( @newissue, 7 );
2241 $subscription->{countissuesperunit
} = 1;
2246 sub _get_next_date_month
{
2247 my ($subscription, $freqdata, $year, $month, $day) = @_;
2249 my @newissue; # ( yy, mm, dd )
2250 my $delta_days = int( 30 / $freqdata->{issuesperunit
} );
2252 if( $freqdata->{issuesperunit
} == 1 ) {
2254 @newissue = Add_Delta_YM
(
2255 $year, $month, $day, 0, $freqdata->{"unitsperissue"} );
2256 } elsif ( $subscription->{countissuesperunit
} < $freqdata->{issuesperunit
} ) {
2257 # Add rounded number of days based on frequency.
2258 @newissue = Add_Delta_Days
( $year, $month, $day, $delta_days );
2259 $subscription->{countissuesperunit
}++;
2261 # We finished a cycle of issues within a unit.
2262 # Subtract delta * (issues - 1), add 1 month
2263 @newissue = Add_Delta_Days
( $year, $month, $day,
2264 -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2265 @newissue = Add_Delta_YM
( @newissue, 0, 1 );
2266 $subscription->{countissuesperunit
} = 1;
2271 sub _get_next_date_year
{
2272 my ($subscription, $freqdata, $year, $month, $day) = @_;
2274 my @newissue; # ( yy, mm, dd )
2275 my $delta_days = int( 365 / $freqdata->{issuesperunit
} );
2277 if( $freqdata->{issuesperunit
} == 1 ) {
2279 @newissue = Add_Delta_YM
( $year, $month, $day, $freqdata->{"unitsperissue"}, 0 );
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 year
2287 @newissue = Add_Delta_Days
( $year, $month, $day, -$delta_days * ($freqdata->{issuesperunit
} - 1) );
2288 @newissue = Add_Delta_YM
( @newissue, 1, 0 );
2289 $subscription->{countissuesperunit
} = 1;
2296 $resultdate = GetNextDate($publisheddate,$subscription)
2298 this function it takes the publisheddate and will return the next issue's date
2299 and will skip dates if there exists an irregularity.
2300 $publisheddate has to be an ISO date
2301 $subscription is a hashref containing at least 'periodicity', 'firstacquidate', 'irregularity', and 'countissuesperunit'
2302 $updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
2303 - eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
2304 skipped then the returned date will be 2007-05-10
2307 $resultdate - then next date in the sequence (ISO date)
2309 Return undef if subscription is irregular
2314 my ( $subscription, $publisheddate, $updatecount ) = @_;
2316 return unless $subscription and $publisheddate;
2318 my $freqdata = GetSubscriptionFrequency
($subscription->{'periodicity'});
2320 if ($freqdata->{'unit'}) {
2321 my ( $year, $month, $day ) = split /-/, $publisheddate;
2323 # Process an irregularity Hash
2324 # Suppose that irregularities are stored in a string with this structure
2325 # irreg1;irreg2;irreg3
2326 # where irregX is the number of issue which will not be received
2327 # (the first issue takes the number 1, the 2nd the number 2 and so on)
2329 if ( $subscription->{irregularity
} ) {
2330 my @irreg = split /;/, $subscription->{'irregularity'} ;
2331 foreach my $irregularity (@irreg) {
2332 $irregularities{$irregularity} = 1;
2336 # Get the 'fictive' next issue number
2337 # It is used to check if next issue is an irregular issue.
2338 my $issueno = GetFictiveIssueNumber
($subscription, $publisheddate) + 1;
2340 # Then get the next date
2341 my $unit = lc $freqdata->{'unit'};
2342 if ($unit eq 'day') {
2343 while ($irregularities{$issueno}) {
2344 ($year, $month, $day) = _get_next_date_day
($subscription,
2345 $freqdata, $year, $month, $day);
2348 ($year, $month, $day) = _get_next_date_day
($subscription, $freqdata,
2349 $year, $month, $day);
2351 elsif ($unit eq 'week') {
2352 while ($irregularities{$issueno}) {
2353 ($year, $month, $day) = _get_next_date_week
($subscription,
2354 $freqdata, $year, $month, $day);
2357 ($year, $month, $day) = _get_next_date_week
($subscription,
2358 $freqdata, $year, $month, $day);
2360 elsif ($unit eq 'month') {
2361 while ($irregularities{$issueno}) {
2362 ($year, $month, $day) = _get_next_date_month
($subscription,
2363 $freqdata, $year, $month, $day);
2366 ($year, $month, $day) = _get_next_date_month
($subscription,
2367 $freqdata, $year, $month, $day);
2369 elsif ($unit eq 'year') {
2370 while ($irregularities{$issueno}) {
2371 ($year, $month, $day) = _get_next_date_year
($subscription,
2372 $freqdata, $year, $month, $day);
2375 ($year, $month, $day) = _get_next_date_year
($subscription,
2376 $freqdata, $year, $month, $day);
2380 my $dbh = C4
::Context
->dbh;
2383 SET countissuesperunit
= ?
2384 WHERE subscriptionid
= ?
2386 my $sth = $dbh->prepare($query);
2387 $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
2390 return sprintf("%04d-%02d-%02d", $year, $month, $day);
2396 $string = &_numeration($value,$num_type,$locale);
2398 _numeration returns the string corresponding to $value in the num_type
2410 my ($value, $num_type, $locale) = @_;
2415 if ( $num_type =~ /^dayname$/ or $num_type =~ /^dayabrv$/ ) {
2416 # 1970-11-01 was a Sunday
2417 $value = $value % 7;
2418 my $dt = DateTime
->new(
2424 $string = $num_type =~ /^dayname$/
2425 ?
$dt->strftime("%A")
2426 : $dt->strftime("%a");
2427 } elsif ( $num_type =~ /^monthname$/ or $num_type =~ /^monthabrv$/ ) {
2428 $value = $value % 12;
2429 my $dt = DateTime
->new(
2431 month
=> $value + 1,
2434 $string = $num_type =~ /^monthname$/
2435 ?
$dt->strftime("%B")
2436 : $dt->strftime("%b");
2437 } elsif ( $num_type =~ /^season$/ ) {
2438 my @seasons= qw( Spring Summer Fall Winter );
2439 $value = $value % 4;
2440 $string = $seasons[$value];
2441 } elsif ( $num_type =~ /^seasonabrv$/ ) {
2442 my @seasonsabrv= qw( Spr Sum Fal Win );
2443 $value = $value % 4;
2444 $string = $seasonsabrv[$value];
2452 =head2 CloseSubscription
2454 Close a subscription given a subscriptionid
2458 sub CloseSubscription
{
2459 my ( $subscriptionid ) = @_;
2460 return unless $subscriptionid;
2461 my $dbh = C4
::Context
->dbh;
2462 my $sth = $dbh->prepare( q{
2465 WHERE subscriptionid = ?
2467 $sth->execute( $subscriptionid );
2469 # Set status = missing when status = stopped
2470 $sth = $dbh->prepare( q{
2473 WHERE subscriptionid = ?
2476 $sth->execute( STOPPED
, $subscriptionid, EXPECTED
);
2479 =head2 ReopenSubscription
2481 Reopen a subscription given a subscriptionid
2485 sub ReopenSubscription
{
2486 my ( $subscriptionid ) = @_;
2487 return unless $subscriptionid;
2488 my $dbh = C4
::Context
->dbh;
2489 my $sth = $dbh->prepare( q{
2492 WHERE subscriptionid = ?
2494 $sth->execute( $subscriptionid );
2496 # Set status = expected when status = stopped
2497 $sth = $dbh->prepare( q{
2500 WHERE subscriptionid = ?
2503 $sth->execute( EXPECTED
, $subscriptionid, STOPPED
);
2506 =head2 subscriptionCurrentlyOnOrder
2508 $bool = subscriptionCurrentlyOnOrder( $subscriptionid );
2510 Return 1 if subscription is currently on order else 0.
2514 sub subscriptionCurrentlyOnOrder
{
2515 my ( $subscriptionid ) = @_;
2516 my $dbh = C4
::Context
->dbh;
2518 SELECT COUNT
(*) FROM aqorders
2519 WHERE subscriptionid
= ?
2520 AND datereceived IS NULL
2521 AND datecancellationprinted IS NULL
2523 my $sth = $dbh->prepare( $query );
2524 $sth->execute($subscriptionid);
2525 return $sth->fetchrow_array;
2528 =head2 can_claim_subscription
2530 $can = can_claim_subscription( $subscriptionid[, $userid] );
2532 Return 1 if the subscription can be claimed by the current logged user (or a given $userid), else 0.
2536 sub can_claim_subscription
{
2537 my ( $subscription, $userid ) = @_;
2538 return _can_do_on_subscription
( $subscription, $userid, 'claim_serials' );
2541 =head2 can_edit_subscription
2543 $can = can_edit_subscription( $subscriptionid[, $userid] );
2545 Return 1 if the subscription can be edited by the current logged user (or a given $userid), else 0.
2549 sub can_edit_subscription
{
2550 my ( $subscription, $userid ) = @_;
2551 return _can_do_on_subscription
( $subscription, $userid, 'edit_subscription' );
2554 =head2 can_show_subscription
2556 $can = can_show_subscription( $subscriptionid[, $userid] );
2558 Return 1 if the subscription can be shown by the current logged user (or a given $userid), else 0.
2562 sub can_show_subscription
{
2563 my ( $subscription, $userid ) = @_;
2564 return _can_do_on_subscription
( $subscription, $userid, '*' );
2567 sub _can_do_on_subscription
{
2568 my ( $subscription, $userid, $permission ) = @_;
2569 return 0 unless C4
::Context
->userenv;
2570 my $flags = C4
::Context
->userenv->{flags
};
2571 $userid ||= C4
::Context
->userenv->{'id'};
2573 if ( C4
::Context
->preference('IndependentBranches') ) {
2575 if C4
::Context
->IsSuperLibrarian()
2577 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2579 C4
::Auth
::haspermission
( $userid,
2580 { serials
=> $permission } )
2581 and ( not defined $subscription->{branchcode
}
2582 or $subscription->{branchcode
} eq ''
2583 or $subscription->{branchcode
} eq
2584 C4
::Context
->userenv->{'branch'} )
2589 if C4
::Context
->IsSuperLibrarian()
2591 C4
::Auth
::haspermission
( $userid, { serials
=> 'superserials' } )
2592 or C4
::Auth
::haspermission
(
2593 $userid, { serials
=> $permission }
2600 =head2 findSerialsByStatus
2602 @serials = findSerialsByStatus($status, $subscriptionid);
2604 Returns an array of serials matching a given status and subscription id.
2608 sub findSerialsByStatus
{
2609 my ( $status, $subscriptionid ) = @_;
2610 my $dbh = C4
::Context
->dbh;
2611 my $query = q
| SELECT
* from serial
2613 AND subscriptionid
= ?
2615 my $serials = $dbh->selectall_arrayref( $query, { Slice
=> {} }, $status, $subscriptionid );
2624 Koha Development Team <http://koha-community.org/>