@@ -, +, @@ automatic claims (new checkbox on the first page of subscription-add.pl) with more than 5 days in the past, some with less) something in the 'Email' template verify that it sends an email notification only for serials that were expected more than 5 days ago --- C4/Letters.pm | 9 +- C4/Serials.pm | 30 +++--- installer/data/mysql/atomicupdate/bug_18783.perl | 12 +++ installer/data/mysql/kohastructure.sql | 1 + .../prog/en/modules/serials/subscription-add.tt | 8 ++ .../prog/en/modules/serials/subscription-detail.tt | 1 + misc/cronjobs/serialsClaim.pl | 117 +++++++++++++++++++++ serials/subscription-add.pl | 6 +- t/db_dependent/Serials.t | 16 ++- 9 files changed, 181 insertions(+), 19 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_18783.perl create mode 100755 misc/cronjobs/serialsClaim.pl --- a/C4/Letters.pm +++ a/C4/Letters.pm @@ -576,11 +576,18 @@ sub SendAlerts { $letter->{content} =~ s/(.*?)<\/order>/$1/gxms; # ... then send mail + my $from; my $library = Koha::Libraries->find( $userenv->{branch} ); + if ($library and $library->branchemail) { + $from = $library->branchemail; + } else { + $from = C4::Context->preference('KohaAdminEmailAddress'); + } + my %mail = ( To => join( ',', @email), Cc => join( ',', @cc), - From => $library->branchemail || C4::Context->preference('KohaAdminEmailAddress'), + From => $from, Subject => Encode::encode( "UTF-8", "" . $letter->{title} ), Message => $letter->{'is_html'} ? _wrap_html( Encode::encode( "UTF-8", $letter->{'content'} ), --- a/C4/Serials.pm +++ a/C4/Serials.pm @@ -343,7 +343,8 @@ sub GetFullSubscription { my $sth = $dbh->prepare($query); $sth->execute($subscriptionid); my $subscriptions = $sth->fetchall_arrayref( {} ); - my $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions; + my $cannotedit; + $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions; for my $subscription ( @$subscriptions ) { $subscription->{cannotedit} = $cannotedit; } @@ -366,9 +367,6 @@ sub PrepareSerialsData { my $year; my @res; my $startdate; - my $aqbooksellername; - my $bibliotitle; - my @loopissues; my $first; my $previousnote = ""; @@ -503,7 +501,8 @@ sub GetFullSubscriptionsFromBiblionumber { my $sth = $dbh->prepare($query); $sth->execute($biblionumber); my $subscriptions = $sth->fetchall_arrayref( {} ); - my $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions; + my $cannotedit; + $cannotedit = not can_edit_subscription( $subscriptions->[0] ) if scalar @$subscriptions; for my $subscription ( @$subscriptions ) { $subscription->{cannotedit} = $cannotedit; } @@ -1348,9 +1347,11 @@ sub ModSubscription { $biblionumber, $callnumber, $notes, $letter, $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq, - $itemtype, $previousitemtype + $itemtype, $previousitemtype, $auto_claim_enabled ) = @_; + $auto_claim_enabled //= 0; + my $dbh = C4::Context->dbh; my $query = "UPDATE subscription SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?, @@ -1361,7 +1362,8 @@ sub ModSubscription { callnumber=?, notes=?, letter=?, manualhistory=?, internalnotes=?, serialsadditems=?, staffdisplaycount=?, opacdisplaycount=?, graceperiod=?, location = ?, enddate=?, - skip_serialseq=?, itemtype=?, previousitemtype=? + skip_serialseq=?, itemtype=?, previousitemtype=?, + auto_claim_enabled=? WHERE subscriptionid = ?"; my $sth = $dbh->prepare($query); @@ -1375,7 +1377,7 @@ sub ModSubscription { $letter, ($manualhistory ? $manualhistory : 0), $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq, - $itemtype, $previousitemtype, + $itemtype, $previousitemtype, $auto_claim_enabled, $subscriptionid ); my $rows = $sth->rows; @@ -1409,8 +1411,12 @@ sub NewSubscription { $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, - $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype + $location, $enddate, $skip_serialseq, $itemtype, $previousitemtype, + $auto_claim_enabled ) = @_; + + $auto_claim_enabled //= 0; + my $dbh = C4::Context->dbh; #save subscription (insert into database) @@ -1423,8 +1429,8 @@ sub NewSubscription { irregularity, numberpattern, locale, callnumber, manualhistory, internalnotes, serialsadditems, staffdisplaycount, opacdisplaycount, graceperiod, location, enddate, skip_serialseq, - itemtype, previousitemtype) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) + itemtype, previousitemtype, auto_claim_enabled) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) |; my $sth = $dbh->prepare($query); $sth->execute( @@ -1435,7 +1441,7 @@ sub NewSubscription { $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq, - $itemtype, $previousitemtype + $itemtype, $previousitemtype, $auto_claim_enabled ); my $subscriptionid = $dbh->{'mysql_insertid'}; --- a/installer/data/mysql/atomicupdate/bug_18783.perl +++ a/installer/data/mysql/atomicupdate/bug_18783.perl @@ -0,0 +1,12 @@ +$DBversion = 'XXX'; +if ( CheckVersion($DBversion) ) { + if ( !column_exists('subscription', 'auto_claim_enabled') ) { + $dbh->do(q{ + ALTER TABLE subscription + ADD COLUMN auto_claim_enabled tinyint NOT NULL DEFAULT 0 AFTER previousitemtype + }); + } + + SetVersion($DBversion); + print "Upgrade to $DBversion done (Bug 18783 - Automatic claims for serials)\n"; +} --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -2123,6 +2123,7 @@ CREATE TABLE `subscription` ( -- information related to the subscription `reneweddate` date default NULL, -- date of last renewal for the subscription `itemtype` VARCHAR( 10 ) NULL, `previousitemtype` VARCHAR( 10 ) NULL, + `auto_claim_enabled` tinyint NOT NULL DEFAULT 0, -- enable automatic claiming PRIMARY KEY (`subscriptionid`), CONSTRAINT subscription_ibfk_1 FOREIGN KEY (periodicity) REFERENCES subscription_frequencies (id) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT subscription_ibfk_2 FOREIGN KEY (numberpattern) REFERENCES subscription_numberpatterns (id) ON DELETE SET NULL ON UPDATE CASCADE --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tt @@ -684,6 +684,14 @@ $(document).ready(function() { day(s)
  • + + [% IF auto_claim_enabled %] + + [% ELSE %] + + [% END %] +
  • +
  • --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt @@ -110,6 +110,7 @@ $(document).ready(function() { [% END %]
  • Grace period: [% graceperiod %]
  • +
  • Automatic claims: [% IF auto_claim_enabled %]Enabled[% ELSE %]Disabled[% END %]
  • --- a/misc/cronjobs/serialsClaim.pl +++ a/misc/cronjobs/serialsClaim.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl + +# Copyright 2017 Biblibre +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +=head1 NAME + +serialsClaims.pl - Send claim notice to suppliers that have late or missing issues + +=head1 SYNOPSIS + +serialsClaims.pl --letter-code LETTER_CODE [--max-claims MAX_CLAIMS] + +Options: + --letter-code LETTER_CODE Mandatory. Use letter LETTER_CODE. + --max-claims MAX_CLAIMS Send up to MAX_CLAIMS notices + +=cut + +use Modern::Perl; + +use DateTime; +use Getopt::Long; + +use Koha::Acquisition::Booksellers; +use Koha::DateUtils; +use Koha::Subscriptions; + +use C4::Context; +use C4::Letters; +use C4::Serials; + +sub usage { + return < \$letter_code, + 'max-claims=i' => \$max_claims, +) or die usage(); + +die usage() unless $letter_code; + +my $suppliers = GetSuppliersWithLateIssues(); +foreach my $supplier (@$suppliers) { + my $bookseller = Koha::Acquisition::Booksellers->find($supplier->{id}); + my $supplierinfo = $bookseller->name . ' (' . $bookseller->id . ')'; + + my $deliverytime = $bookseller->deliverytime; + unless ($deliverytime) { + say STDERR "Warning: There is no delivery time set for supplier $supplierinfo. Automatic claiming is disabled for this supplier."; + next; + } + + my @serials = GetLateOrMissingIssues($bookseller->id); + my @serialids; + foreach my $serial (@serials) { + if ($max_claims && $serial->{claims_count} >= $max_claims) { + say "Maximum claims count reached for serial " . $serial->{serialid}; + next; + } + + my $subscription = Koha::Subscriptions->find($serial->{subscriptionid}); + next unless $subscription->auto_claim_enabled; + + my $claims_count = $serial->{claims_count}; + my $date = $serial->{claimdate} ? $serial->{claimdate} : $serial->{planneddate}; + my $newclaimdate = dt_from_string($date)->add(days => $deliverytime); + my $now = DateTime->now(time_zone => C4::Context->tz); + + if ($newclaimdate <= $now) { + push @serialids, $serial->{serialid}; + } + } + + if (@serialids) { + my $err; + eval { + $err = SendAlerts('claimissues', \@serialids, $letter_code); + if ( not ref $err or not exists $err->{error} ) { + C4::Serials::updateClaim( \@serialids ); + } + }; + if ( $@ ) { + say STDERR "Error: $@ while claiming serials " . join(',', @serialids); + } elsif ( ref $err and exists $err->{error} ) { + if ( $err->{error} eq "no_email" ) { + say STDERR "Error: Supplier $supplierinfo has no email"; + } elsif ( $err->{error} =~ m|Bad or missing From address| ) { + say STDERR "Error: Supplier $supplierinfo has no email"; + } else { + say STDERR "Error: " . $err->{error}; + } + } else { + say "Claim sent to $supplierinfo for serials " . join(',', @serialids); + } + } +} --- a/serials/subscription-add.pl +++ a/serials/subscription-add.pl @@ -321,6 +321,7 @@ sub redirect_add_subscription { my $itemtype = $query->param('itemtype'); my $previousitemtype = $query->param('previousitemtype'); my $skip_serialseq = $query->param('skip_serialseq'); + my $auto_claim_enabled = $query->param('auto_claim_enabled'); my $startdate = output_pref( { str => scalar $query->param('startdate'), dateonly => 1, dateformat => 'iso' } ); my $enddate = output_pref( { str => scalar $query->param('enddate'), dateonly => 1, dateformat => 'iso' } ); @@ -342,7 +343,7 @@ sub redirect_add_subscription { join(";",@irregularity), $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, - $skip_serialseq + $skip_serialseq, undef, undef, $auto_claim_enabled ); my $additional_fields = Koha::AdditionalField->all( { tablename => 'subscription' } ); @@ -400,6 +401,7 @@ sub redirect_mod_subscription { my $itemtype = $query->param('itemtype'); my $previousitemtype = $query->param('previousitemtype'); my $skip_serialseq = $query->param('skip_serialseq'); + my $auto_claim_enabled = $query->param('auto_claim_enabled'); # Guess end date if(!defined $enddate || $enddate eq '') { @@ -426,7 +428,7 @@ sub redirect_mod_subscription { $status, $biblionumber, $callnumber, $notes, $letter, $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $subscriptionid, - $skip_serialseq, $itemtype, $previousitemtype + $skip_serialseq, $itemtype, $previousitemtype, $auto_claim_enabled ); my $additional_fields = Koha::AdditionalField->all( { tablename => 'subscription' } ); --- a/t/db_dependent/Serials.t +++ a/t/db_dependent/Serials.t @@ -355,10 +355,18 @@ $dbh->rollback; sub get_biblio { my $bib = MARC::Record->new(); - $bib->append_fields( - MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'), - MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'), - ); + + if (C4::Context->preference('marcflavour') eq 'UNIMARC') { + $bib->append_fields( + MARC::Field->new('200', ' ', ' ', f => 'Moffat, Steven'), + MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'), + ); + } else { + $bib->append_fields( + MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'), + MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'), + ); + } my ($bibnum, $bibitemnum) = AddBiblio($bib, ''); return ($bibnum, $bibitemnum); } --