X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FLetters.pm;h=712514896e1024650c0bd800716e6a2a3c228953;hb=e52b493611766b61a0018350adc590ab07e9c94b;hp=89213fe6ddefa8a56b5a8a6f366c9f76acf959f0;hpb=b20c2d6857629eed3f3eaf44cdca68dda36f4216;p=koha_fer diff --git a/C4/Letters.pm b/C4/Letters.pm index 89213fe6dd..712514896e 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -29,6 +29,7 @@ use C4::Branch; use C4::Log; use C4::SMS; use C4::Debug; +use Koha::DateUtils; use Date::Calc qw( Add_Delta_Days ); use Encode; use Carp; @@ -38,7 +39,7 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); BEGIN { require Exporter; # set the version for version checking - $VERSION = 3.01; + $VERSION = 3.07.00.049; @ISA = qw(Exporter); @EXPORT = qw( &GetLetters &GetPreparedLetter &GetWrappedLetter &addalert &getalert &delalert &findrelatedto &SendAlerts &GetPrintMessages @@ -93,7 +94,7 @@ $template->param(LETTERLOOP => \@letterloop); =cut -sub GetLetters (;$) { +sub GetLetters { # returns a reference to a hash of references to ALL letters... my $cat = shift; @@ -116,11 +117,21 @@ sub GetLetters (;$) { return \%letters; } -my %letter; -sub getletter ($$$) { +# FIXME: using our here means that a Plack server will need to be +# restarted fairly regularly when working with this routine. +# A better option would be to use Koha::Cache and use a cache +# that actually works in a persistent environment, but as a +# short-term fix, our will work. +our %letter; +sub getletter { my ( $module, $code, $branchcode ) = @_; - if (C4::Context->preference('IndependantBranches') && $branchcode){ + $branchcode ||= ''; + + if ( C4::Context->preference('IndependentBranches') + and $branchcode + and C4::Context->userenv ) { + $branchcode = C4::Context->userenv->{'branch'}; } @@ -149,7 +160,7 @@ sub getletter ($$$) { =cut -sub addalert ($$$) { +sub addalert { my ( $borrowernumber, $type, $externalid ) = @_; my $dbh = C4::Context->dbh; my $sth = @@ -170,7 +181,7 @@ sub addalert ($$$) { =cut -sub delalert ($) { +sub delalert { my $alertid = shift or die "delalert() called without valid argument (alertid)"; # it's gonna die anyway. $debug and warn "delalert: deleting alertid $alertid"; my $sth = C4::Context->dbh->prepare("delete from alert where alertid=?"); @@ -187,7 +198,7 @@ sub delalert ($) { =cut -sub getalert (;$$$) { +sub getalert { my ( $borrowernumber, $type, $externalid ) = @_; my $dbh = C4::Context->dbh; my $query = "SELECT a.*, b.branchcode FROM alert a JOIN borrowers b USING(borrowernumber) WHERE"; @@ -224,16 +235,16 @@ sub getalert (;$$$) { # outmoded POD: # When type=virtual, the id is related to a virtual shelf and this sub returns the name of the sub -sub findrelatedto ($$) { - my $type = shift or return undef; - my $externalid = shift or return undef; +sub findrelatedto { + my $type = shift or return; + my $externalid = shift or return; my $q = ($type eq 'issue' ) ? "select title as result from subscription left join biblio on subscription.biblionumber=biblio.biblionumber where subscriptionid=?" : ($type eq 'borrower') ? "select concat(firstname,' ',surname) from borrowers where borrowernumber=?" : undef; unless ($q) { warn "findrelatedto(): Illegal type '$type'"; - return undef; + return; } my $sth = C4::Context->dbh->prepare($q); $sth->execute($externalid); @@ -277,6 +288,7 @@ sub SendAlerts { # warn "sending issues..."; my $userenv = C4::Context->userenv; + my $branchdetails = GetBranchDetail($_->{'branchcode'}); my $letter = GetPreparedLetter ( module => 'serial', letter_code => $letter_code, @@ -293,7 +305,7 @@ sub SendAlerts { # ... then send mail my %mail = ( To => $email, - From => $email, + From => $branchdetails->{'branchemail'} || C4::Context->preference("KohaAdminEmailAddress"), Subject => Encode::encode( "utf8", "" . $letter->{title} ), Message => Encode::encode( "utf8", "" . $letter->{content} ), 'Content-Type' => 'text/plain; charset="utf8"', @@ -312,7 +324,7 @@ sub SendAlerts { FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber - LEFT JOIN biblioitems ON aqorders.biblioitemnumber=biblioitems.biblioitemnumber + LEFT JOIN biblioitems ON aqorders.biblionumber=biblioitems.biblionumber LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id WHERE aqorders.ordernumber IN ( } @@ -454,6 +466,9 @@ sub GetPreparedLetter { } } + my $OPACBaseURL = C4::Context->preference('OPACBaseURL'); + $letter->{content} =~ s/<>/$OPACBaseURL/go; + if ($want_librarian) { # parsing librarian name my $userenv = C4::Context->userenv; @@ -536,43 +551,48 @@ sub _substitute_tables { $sth->execute( $ref ? @$param : $param ); $values = $sth->fetchrow_hashref; + $sth->finish(); } _parseletter ( $letter, $table, $values ); } } -my %handles = (); sub _parseletter_sth { my $table = shift; + my $sth; unless ($table) { carp "ERROR: _parseletter_sth() called without argument (table)"; return; } - # check cache first - (defined $handles{$table}) and return $handles{$table}; + # NOTE: we used to check whether we had a statement handle cached in + # a %handles module-level variable. This was a dumb move and + # broke things for the rest of us. prepare_cached is a better + # way to cache statement handles anyway. my $query = - ($table eq 'biblio' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : - ($table eq 'biblioitems' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : - ($table eq 'items' ) ? "SELECT * FROM $table WHERE itemnumber = ?" : - ($table eq 'issues' ) ? "SELECT * FROM $table WHERE itemnumber = ?" : - ($table eq 'reserves' ) ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?" : - ($table eq 'borrowers' ) ? "SELECT * FROM $table WHERE borrowernumber = ?" : - ($table eq 'branches' ) ? "SELECT * FROM $table WHERE branchcode = ?" : - ($table eq 'suggestions' ) ? "SELECT * FROM $table WHERE suggestionid = ?" : - ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE id = ?" : - ($table eq 'aqorders' ) ? "SELECT * FROM $table WHERE ordernumber = ?" : - ($table eq 'opac_news' ) ? "SELECT * FROM $table WHERE idnew = ?" : + ($table eq 'biblio' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : + ($table eq 'biblioitems' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : + ($table eq 'items' ) ? "SELECT * FROM $table WHERE itemnumber = ?" : + ($table eq 'issues' ) ? "SELECT * FROM $table WHERE itemnumber = ?" : + ($table eq 'old_issues' ) ? "SELECT * FROM $table WHERE itemnumber = ? ORDER BY timestamp DESC LIMIT 1" : + ($table eq 'reserves' ) ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?" : + ($table eq 'borrowers' ) ? "SELECT * FROM $table WHERE borrowernumber = ?" : + ($table eq 'branches' ) ? "SELECT * FROM $table WHERE branchcode = ?" : + ($table eq 'suggestions' ) ? "SELECT * FROM $table WHERE suggestionid = ?" : + ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE id = ?" : + ($table eq 'aqorders' ) ? "SELECT * FROM $table WHERE ordernumber = ?" : + ($table eq 'opac_news' ) ? "SELECT * FROM $table WHERE idnew = ?" : + ($table eq 'borrower_modifications') ? "SELECT * FROM $table WHERE borrowernumber = ? OR verification_token =?": undef ; unless ($query) { warn "ERROR: No _parseletter_sth query for table '$table'"; return; # nothing to get } - unless ($handles{$table} = C4::Context->dbh->prepare($query)) { + unless ($sth = C4::Context->dbh->prepare_cached($query)) { warn "ERROR: Failed to prepare query: '$query'"; return; } - return $handles{$table}; # now cache is populated for that $table + return $sth; # now cache is populated for that $table } =head2 _parseletter($letter, $table, $values) @@ -586,40 +606,33 @@ sub _parseletter_sth { =cut -my %columns = (); sub _parseletter { my ( $letter, $table, $values ) = @_; - # TEMPORARY hack until the expirationdate column is added to reserves if ( $table eq 'reserves' && $values->{'waitingdate'} ) { my @waitingdate = split /-/, $values->{'waitingdate'}; - $values->{'expirationdate'} = C4::Dates->new( - sprintf( - '%04d-%02d-%02d', - Add_Delta_Days( @waitingdate, C4::Context->preference( 'ReservesMaxPickUpDelay' ) ) - ), - 'iso' - )->output(); + my $dt = dt_from_string(); + $dt->add( days => C4::Context->preference('ReservesMaxPickUpDelay') || 0); + $values->{'expirationdate'} = output_pref({ dt => $dt, dateonly => 1 }); + + $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 }); + } if ($letter->{content} && $letter->{content} =~ /<>/) { - my @da = localtime(); - my $todaysdate = "$da[2]:$da[1] " . C4::Dates->today(); + my $todaysdate = output_pref( DateTime->now() ); $letter->{content} =~ s/<>/$todaysdate/go; } - # and get all fields from the table -# my $columns = $columns{$table}; -# unless ($columns) { -# $columns = $columns{$table} = C4::Context->dbh->selectcol_arrayref("SHOW COLUMNS FROM $table"); -# } -# foreach my $field (@$columns) { - while ( my ($field, $val) = each %$values ) { my $replacetablefield = "<<$table.$field>>"; my $replacefield = "<<$field>>"; - $val =~ s/\p{P}(?=$)//g if $val; + $val =~ s/\p{P}$// if $val && $table=~/biblio/; + #BZ 9886: Assuming that we want to eliminate ISBD punctuation here + #Therefore adding the test on biblio. This includes biblioitems, + #but excludes items. Removed unneeded global and lookahead. + my $replacedby = defined ($val) ? $val : ''; ($letter->{title} ) and do { $letter->{title} =~ s/$replacetablefield/$replacedby/g; @@ -661,17 +674,24 @@ places a letter in the message_queue database table, which will eventually get processed (sent) by the process_message_queue.pl cronjob when it calls SendQueuedMessages. -return true on success +return message_id on success =cut -sub EnqueueLetter ($) { - my $params = shift or return undef; +sub EnqueueLetter { + my $params = shift or return; return unless exists $params->{'letter'}; - return unless exists $params->{'borrowernumber'}; +# return unless exists $params->{'borrowernumber'}; return unless exists $params->{'message_transport_type'}; + my $content = $params->{letter}->{content}; + $content =~ s/\s+//g if(defined $content); + if ( not defined $content or $content eq '' ) { + warn "Trying to add an empty message to the message queue" if $debug; + return; + } + # If we have any attachments we should encode then into the body. if ( $params->{'attachments'} ) { $params->{'letter'} = _add_attachments( @@ -703,7 +723,7 @@ ENDSQL $params->{'from_address'}, # from_address $params->{'letter'}->{'content-type'}, # content_type ); - return $result; + return $dbh->last_insert_id(undef,undef,'message_queue', undef); } =head2 SendQueuedMessages ([$hashref]) @@ -716,7 +736,7 @@ returns number of messages sent. =cut -sub SendQueuedMessages (;$) { +sub SendQueuedMessages { my $params = shift; my $unsent_messages = _get_unsent_messages(); @@ -771,7 +791,8 @@ sub GetPrintMessages { my $params = shift || {}; return _get_unsent_messages( { message_transport_type => 'print', - borrowernumber => $params->{'borrowernumber'}, } ); + borrowernumber => $params->{'borrowernumber'}, + } ); } =head2 GetQueuedMessages ([$hashref]) @@ -861,13 +882,14 @@ sub _add_attachments { } -sub _get_unsent_messages (;$) { +sub _get_unsent_messages { my $params = shift; my $dbh = C4::Context->dbh(); my $statement = << 'ENDSQL'; -SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, from_address, to_address, content_type - FROM message_queue +SELECT mq.message_id, mq.borrowernumber, mq.subject, mq.content, mq.message_transport_type, mq.status, mq.time_queued, mq.from_address, mq.to_address, mq.content_type, b.branchcode + FROM message_queue mq + LEFT JOIN borrowers b ON b.borrowernumber = mq.borrowernumber WHERE status = ? ENDSQL @@ -886,6 +908,7 @@ ENDSQL push @query_params, $params->{'limit'}; } } + $debug and warn "_get_unsent_messages SQL: $statement"; $debug and warn "_get_unsent_messages params: " . join(',',@query_params); my $sth = $dbh->prepare( $statement ); @@ -893,26 +916,20 @@ ENDSQL return $sth->fetchall_arrayref({}); } -sub _send_message_by_email ($;$$$) { +sub _send_message_by_email { my $message = shift or return; my ($username, $password, $method) = @_; - my $to_address = $message->{to_address}; + my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); + my $to_address = $message->{'to_address'}; unless ($to_address) { - my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); unless ($member) { warn "FAIL: No 'to_address' and INVALID borrowernumber ($message->{borrowernumber})"; _set_message_status( { message_id => $message->{'message_id'}, status => 'failed' } ); return; } - my $which_address = C4::Context->preference('AutoEmailPrimaryAddress'); - # If the system preference is set to 'first valid' (value == OFF), look up email address - if ($which_address eq 'OFF') { - $to_address = GetFirstValidEmailAddress( $message->{'borrowernumber'} ); - } else { - $to_address = $member->{$which_address}; - } + $to_address = C4::Members::GetNoticeEmailAddress( $message->{'borrowernumber'} ); unless ($to_address) { # warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})"; # warning too verbose for this more common case? @@ -928,9 +945,12 @@ sub _send_message_by_email ($;$$$) { my $content = encode('utf8', $message->{'content'}); my $content_type = $message->{'content_type'} || 'text/plain; charset="UTF-8"'; my $is_html = $content_type =~ m/html/io; + + my $branch_email = ( $member ) ? GetBranchDetail( $member->{'branchcode'} )->{'branchemail'} : undef; + my %sendmail_params = ( To => $to_address, - From => $message->{'from_address'} || C4::Context->preference('KohaAdminEmailAddress'), + From => $message->{'from_address'} || $branch_email || C4::Context->preference('KohaAdminEmailAddress'), Subject => $subject, charset => 'utf8', Message => $is_html ? _wrap_html($content, $subject) : $content, @@ -975,8 +995,8 @@ $content EOS } -sub _send_message_by_sms ($) { - my $message = shift or return undef; +sub _send_message_by_sms { + my $message = shift or return; my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); return unless $member->{'smsalertnumber'}; @@ -994,11 +1014,11 @@ sub _update_message_to_address { $dbh->do('UPDATE message_queue SET to_address=? WHERE message_id=?',undef,($to,$id)); } -sub _set_message_status ($) { - my $params = shift or return undef; +sub _set_message_status { + my $params = shift or return; foreach my $required_parameter ( qw( message_id status ) ) { - return undef unless exists $params->{ $required_parameter }; + return unless exists $params->{ $required_parameter }; } my $dbh = C4::Context->dbh();