Bug 25444: Simplify the code using a loop
[koha-ffzg.git] / C4 / Letters.pm
index 6bc0382..b676689 100644 (file)
@@ -28,7 +28,6 @@ use Template;
 use Module::Load::Conditional qw(can_load);
 
 use C4::Members;
-use C4::Members::Attributes qw(GetBorrowerAttributes);
 use C4::Log;
 use C4::SMS;
 use C4::Debug;
@@ -37,8 +36,10 @@ use Koha::SMS::Providers;
 
 use Koha::Email;
 use Koha::Notice::Messages;
+use Koha::Notice::Templates;
 use Koha::DateUtils qw( format_sqldatetime dt_from_string );
 use Koha::Patrons;
+use Koha::Subscriptions;
 
 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
@@ -46,7 +47,7 @@ BEGIN {
     require Exporter;
     @ISA = qw(Exporter);
     @EXPORT = qw(
-        &GetLetters &GetLettersAvailableForALibrary &GetLetterTemplates &DelLetter &GetPreparedLetter &GetWrappedLetter &addalert &getalert &delalert &SendAlerts &GetPrintMessages &GetMessageTransportTypes
+        &GetLetters &GetLettersAvailableForALibrary &GetLetterTemplates &DelLetter &GetPreparedLetter &GetWrappedLetter &SendAlerts &GetPrintMessages &GetMessageTransportTypes
     );
 }
 
@@ -121,19 +122,18 @@ sub GetLetterTemplates {
     my $code      = $params->{code};
     my $branchcode = $params->{branchcode} // '';
     my $dbh       = C4::Context->dbh;
-    my $letters   = $dbh->selectall_arrayref(
-        q|
-            SELECT module, code, branchcode, name, is_html, title, content, message_transport_type, lang
-            FROM letter
-            WHERE module = ?
-            AND code = ?
-            and branchcode = ?
-        |
-        , { Slice => {} }
-        , $module, $code, $branchcode
-    );
-
-    return $letters;
+    return Koha::Notice::Templates->search(
+        {
+            module     => $module,
+            code       => $code,
+            branchcode => $branchcode,
+            (
+                C4::Context->preference('TranslateNotices')
+                ? ()
+                : ( lang => 'default' )
+            )
+        }
+    )->unblessed;
 }
 
 =head2 GetLettersAvailableForALibrary
@@ -266,71 +266,6 @@ sub DelLetter {
     , undef, $branchcode, $module, $code, ( $mtt ? $mtt : () ), ( $lang ? $lang : () ) );
 }
 
-=head2 addalert ($borrowernumber, $subscriptionid)
-
-    parameters : 
-    - $borrowernumber : the number of the borrower subscribing to the alert
-    - $subscriptionid
-
-    create an alert and return the alertid (primary key)
-
-=cut
-
-sub addalert {
-    my ( $borrowernumber, $subscriptionid) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth =
-      $dbh->prepare(
-        "insert into alert (borrowernumber, externalid) values (?,?)");
-    $sth->execute( $borrowernumber, $subscriptionid );
-
-    # get the alert number newly created and return it
-    my $alertid = $dbh->{'mysql_insertid'};
-    return $alertid;
-}
-
-=head2 delalert ($alertid)
-
-    parameters :
-    - alertid : the alert id
-    deletes the alert
-
-=cut
-
-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=?");
-    $sth->execute($alertid);
-}
-
-=head2 getalert ([$borrowernumber], [$subscriptionid])
-
-    parameters :
-    - $borrowernumber : the number of the borrower subscribing to the alert
-    - $subscriptionid
-    all parameters NON mandatory. If a parameter is omitted, the query is done without the corresponding parameter. For example, without $subscriptionid, returns all alerts for a borrower on a topic.
-
-=cut
-
-sub getalert {
-    my ( $borrowernumber, $subscriptionid ) = @_;
-    my $dbh   = C4::Context->dbh;
-    my $query = "SELECT a.*, b.branchcode FROM alert a JOIN borrowers b USING(borrowernumber) WHERE 1";
-    my @bind;
-    if ($borrowernumber and $borrowernumber =~ /^\d+$/) {
-        $query .= " AND borrowernumber=?";
-        push @bind, $borrowernumber;
-    }
-    if ($subscriptionid) {
-        $query .= " AND externalid=?";
-        push @bind, $subscriptionid;
-    }
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    return $sth->fetchall_arrayref({});
-}
-
 =head2 SendAlerts
 
     my $err = &SendAlerts($type, $externalid, $letter_code);
@@ -379,22 +314,21 @@ sub SendAlerts {
              return;
 
         my %letter;
-        # find the list of borrowers to alert
-        my $alerts = getalert( '', $subscriptionid );
-        foreach (@$alerts) {
-            my $patron = Koha::Patrons->find( $_->{borrowernumber} );
-            next unless $patron; # Just in case
+        # find the list of subscribers to notify
+        my $subscription = Koha::Subscriptions->find( $subscriptionid );
+        my $subscribers = $subscription->subscribers;
+        while ( my $patron = $subscribers->next ) {
             my $email = $patron->email or next;
 
 #                    warn "sending issues...";
             my $userenv = C4::Context->userenv;
-            my $library = Koha::Libraries->find( $_->{branchcode} );
+            my $library = $patron->library;
             my $letter = GetPreparedLetter (
                 module => 'serial',
                 letter_code => $letter_code,
                 branchcode => $userenv->{branch},
                 tables => {
-                    'branches'    => $_->{branchcode},
+                    'branches'    => $library->branchcode,
                     'biblio'      => $biblionumber,
                     'biblioitems' => $biblionumber,
                     'borrowers'   => $patron->unblessed,
@@ -458,22 +392,23 @@ sub SendAlerts {
 
         if ($type eq 'claimissues') {
             $strsth = qq{
-            SELECT serial.*,subscription.*, biblio.*, aqbooksellers.*,
+            SELECT serial.*,subscription.*, biblio.*, biblioitems.*, aqbooksellers.*,
             aqbooksellers.id AS booksellerid
             FROM serial
             LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid
             LEFT JOIN biblio ON serial.biblionumber=biblio.biblionumber
+            LEFT JOIN biblioitems ON serial.biblionumber = biblioitems.biblionumber
             LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
             WHERE serial.serialid IN (
             };
 
             if (!@$externalid){
-                carp "No Order selected";
-                return { error => "no_order_selected" };
+                carp "No issues selected";
+                return { error => "no_issues_selected" };
             }
 
             $strsth .= join( ",", ('?') x @$externalid ) . ")";
-            $action = "CLAIM ISSUE";
+            $action = "SERIAL CLAIM";
             $sthorders = $dbh->prepare($strsth);
             $sthorders->execute( @$externalid );
             $dataorders = $sthorders->fetchall_arrayref( {} );
@@ -514,7 +449,6 @@ sub SendAlerts {
 
         my @email;
         my @cc;
-        push @email, $databookseller->{bookselleremail} if $databookseller->{bookselleremail};
         push @email, $datacontact->{email}           if ( $datacontact && $datacontact->{email} );
         unless (@email) {
             warn "Bookseller $dataorders->[0]->{booksellerid} without emails";
@@ -544,29 +478,33 @@ sub SendAlerts {
 
         # ... then send mail
         my $library = Koha::Libraries->find( $userenv->{branch} );
-        my %mail = (
-            To => join( ',', @email),
-            Cc             => join( ',', @cc),
-            From           => $library->branchemail || C4::Context->preference('KohaAdminEmailAddress'),
-            Subject        => Encode::encode( "UTF-8", "" . $letter->{title} ),
-            Message => $letter->{'is_html'}
-                            ? _wrap_html( Encode::encode( "UTF-8", $letter->{'content'} ),
-                                          Encode::encode( "UTF-8", "" . $letter->{'title'} ))
-                            : Encode::encode( "UTF-8", "" . $letter->{'content'} ),
-            'Content-Type' => $letter->{'is_html'}
-                                ? 'text/html; charset="utf-8"'
-                                : 'text/plain; charset="utf-8"',
+        my $email = Koha::Email->new();
+        my %mail = $email->create_message_headers(
+            {
+                to => join( ',', @email ),
+                cc => join( ',', @cc ),
+                (
+                    (
+                        C4::Context->preference("ClaimsBccCopy")
+                          && ( $type eq 'claimacquisition'
+                            || $type eq 'claimissues' )
+                    ) ? ( bcc => $userenv->{emailaddress} )
+                    : ()
+                ),
+                from => $library->branchemail
+                  || C4::Context->preference('KohaAdminEmailAddress'),
+                subject => Encode::encode( "UTF-8", "" . $letter->{title} ),
+                message => $letter->{'is_html'} ? _wrap_html(
+                    Encode::encode( "UTF-8", $letter->{'content'} ),
+                    Encode::encode( "UTF-8", "" . $letter->{'title'} )
+                  )
+                : Encode::encode( "UTF-8", "" . $letter->{'content'} ),
+                contenttype => $letter->{'is_html'}
+                ? 'text/html; charset="utf-8"'
+                : 'text/plain; charset="utf-8"',
+            }
         );
 
-        if ($type eq 'claimacquisition' || $type eq 'claimissues' ) {
-            $mail{'Reply-to'} = C4::Context->preference('ReplytoDefault')
-              if C4::Context->preference('ReplytoDefault');
-            $mail{'Sender'} = C4::Context->preference('ReturnpathDefault')
-              if C4::Context->preference('ReturnpathDefault');
-            $mail{'Bcc'} = $userenv->{emailaddress}
-              if C4::Context->preference("ClaimsBccCopy");
-        }
-
         unless ( Mail::Sendmail::sendmail(%mail) ) {
             carp $Mail::Sendmail::error;
             return { error => $Mail::Sendmail::error };
@@ -591,6 +529,7 @@ sub SendAlerts {
             module => 'members',
             letter_code => $letter_code,
             branchcode => $externalid->{'branchcode'},
+            lang       => $externalid->{lang} || 'default',
             tables => {
                 'branches'    => $library,
                 'borrowers' => $externalid->{'borrowernumber'},
@@ -817,6 +756,7 @@ sub _parseletter_sth {
     ($table eq 'borrower_modifications') ? "SELECT * FROM $table WHERE verification_token = ?" :
     ($table eq 'subscription') ? "SELECT * FROM $table WHERE subscriptionid = ?" :
     ($table eq 'serial') ? "SELECT * FROM $table WHERE serialid = ?" :
+    ($table eq 'problem_reports') ? "SELECT * FROM $table WHERE reportid = ?" :
     undef ;
     unless ($query) {
         warn "ERROR: No _parseletter_sth query for table '$table'";
@@ -848,7 +788,7 @@ sub _parseletter {
     my $values = $values_in ? { %$values_in } : {};
 
     if ( $table eq 'borrowers' && $values->{'dateexpiry'} ){
-        $values->{'dateexpiry'} = output_pref({ str => $values->{dateexpiry}, dateonly => 1 });
+        $values->{'dateexpiry'} = output_pref({ dt => dt_from_string( $values->{'dateexpiry'} ), dateonly => 1 });
     }
 
     if ( $table eq 'reserves' && $values->{'waitingdate'} ) {
@@ -856,7 +796,7 @@ sub _parseletter {
     }
 
     if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
-        my $todaysdate = output_pref( DateTime->now() );
+        my $todaysdate = output_pref( dt_from_string() );
         $letter->{content} =~ s/<<today>>/$todaysdate/go;
     }
 
@@ -911,11 +851,13 @@ sub _parseletter {
     }
 
     if ($table eq 'borrowers' && $letter->{content}) {
-        if ( my $attributes = GetBorrowerAttributes($values->{borrowernumber}) ) {
+        my $patron = Koha::Patrons->find( $values->{borrowernumber} );
+        if ( $patron ) {
+            my $attributes = $patron->extended_attributes;
             my %attr;
-            foreach (@$attributes) {
-                my $code = $_->{code};
-                my $val  = $_->{value_description} || $_->{value};
+            while ( my $attribute = $attributes->next ) {
+                my $code = $attribute->code;
+                my $val  = $attribute->description; # FIXME - we always display intranet description here!
                 $val =~ s/\p{P}(?=$)//g if $val;
                 next unless $val gt '';
                 $attr{$code} ||= [];
@@ -971,9 +913,9 @@ sub EnqueueLetter {
     my $dbh       = C4::Context->dbh();
     my $statement = << 'ENDSQL';
 INSERT INTO message_queue
-( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, content_type )
+( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, reply_address, content_type )
 VALUES
-( ?,              ?,       ?,       ?,        ?,           ?,                      ?,      NOW(),       ?,          ?,            ? )
+( ?,              ?,       ?,       ?,        ?,           ?,                      ?,      NOW(),       ?,          ?,            ?,           ? )
 ENDSQL
 
     my $sth    = $dbh->prepare($statement);
@@ -987,6 +929,7 @@ ENDSQL
         'pending',                                # status
         $params->{'to_address'},                  # to_address
         $params->{'from_address'},                # from_address
+        $params->{'reply_address'},               # reply_address
         $params->{'letter'}->{'content-type'},    # content_type
     );
     return $dbh->last_insert_id(undef,undef,'message_queue', undef);
@@ -1058,7 +1001,15 @@ sub SendQueuedMessages {
                 }
                 $message->{to_address}  = $patron->smsalertnumber; #Sometime this is set to email - sms should always use smsalertnumber
                 $message->{to_address} .= '@' . $sms_provider->domain();
-                _update_message_to_address($message->{'message_id'},$message->{to_address});
+
+                # Check for possible from_address override
+                my $from_address = C4::Context->preference('EmailSMSSendDriverFromAddress');
+                if ($from_address && $message->{from_address} ne $from_address) {
+                    $message->{from_address} = $from_address;
+                    _update_message_from_address($message->{'message_id'}, $message->{from_address});
+                }
+
+                _update_message_to_address($message->{'message_id'}, $message->{to_address});
                 _send_message_by_email( $message, $params->{'username'}, $params->{'password'}, $params->{'method'} );
             } else {
                 _send_message_by_sms( $message );
@@ -1109,10 +1060,10 @@ sub GetPrintMessages {
 
   my $messages = GetQueuedMessage( { borrowernumber => '123', limit => 20 } );
 
-fetches messages out of the message queue.
+Fetches a list of messages from the message queue optionally filtered by borrowernumber
+and limited to specified limit.
 
-returns:
-list of hashes, each has represents a message in the message queue.
+Return is an arrayref of hashes, each has represents a message in the message queue.
 
 =cut
 
@@ -1121,7 +1072,7 @@ sub GetQueuedMessages {
 
     my $dbh = C4::Context->dbh();
     my $statement = << 'ENDSQL';
-SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued
+SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, updated_on
 FROM message_queue
 ENDSQL
 
@@ -1175,7 +1126,7 @@ sub GetMessage {
     return unless $message_id;
     my $dbh = C4::Context->dbh;
     return $dbh->selectrow_hashref(q|
-        SELECT message_id, borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, content_type
+        SELECT message_id, borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, updated_on, to_address, from_address, reply_address, content_type
         FROM message_queue
         WHERE message_id = ?
     |, {}, $message_id );
@@ -1279,7 +1230,7 @@ sub _get_unsent_messages {
 
     my $dbh = C4::Context->dbh();
     my $statement = qq{
-        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, mq.letter_code
+        SELECT mq.message_id, mq.borrowernumber, mq.subject, mq.content, mq.message_transport_type, mq.status, mq.time_queued, mq.from_address, mq.reply_address, mq.to_address, mq.content_type, b.branchcode, mq.letter_code
         FROM message_queue mq
         LEFT JOIN borrowers b ON b.borrowernumber = mq.borrowernumber
         WHERE status = ?
@@ -1339,9 +1290,10 @@ sub _send_message_by_email {
         }
     }
 
-    my $utf8   = decode('MIME-Header', $message->{'subject'} );
-    $message->{subject}= encode('MIME-Header', $utf8);
-    my $subject = encode('UTF-8', $message->{'subject'});
+    # Encode subject line separately
+    $message->{subject} = encode('MIME-Header', $message->{'subject'} );
+    my $subject = $message->{'subject'};
+
     my $content = encode('UTF-8', $message->{'content'});
     my $content_type = $message->{'content_type'} || 'text/plain; charset="UTF-8"';
     my $is_html = $content_type =~ m/html/io;
@@ -1357,9 +1309,14 @@ sub _send_message_by_email {
     my $email = Koha::Email->new();
     my %sendmail_params = $email->create_message_headers(
         {
-            to      => $to_address,
+            to => $to_address,
+            (
+                C4::Context->preference('NoticeBcc')
+                ? ( bcc => C4::Context->preference('NoticeBcc') )
+                : ()
+            ),
             from    => $message->{'from_address'} || $branch_email,
-            replyto => $branch_replyto,
+            replyto => $message->{'reply_address'} || $branch_replyto,
             sender  => $branch_returnpath,
             subject => $subject,
             message => $is_html ? _wrap_html( $content, $subject ) : $content,
@@ -1368,11 +1325,8 @@ sub _send_message_by_email {
     );
 
     $sendmail_params{'Auth'} = {user => $username, pass => $password, method => $method} if $username;
-    if ( my $bcc = C4::Context->preference('NoticeBcc') ) {
-       $sendmail_params{ Bcc } = $bcc;
-    }
 
-    _update_message_to_address($message->{'message_id'},$to_address) unless $message->{to_address}; #if initial message address was empty, coming here means that a to address was found and queue should be updated
+    _update_message_to_address($message->{'message_id'},$sendmail_params{To}) if !$message->{to_address} || $message->{to_address} ne $sendmail_params{To}; #if initial message address was empty, coming here means that a to address was found and queue should be updated; same if to address was overriden by create_message_headers
 
     if ( Mail::Sendmail::sendmail( %sendmail_params ) ) {
         _set_message_status( { message_id => $message->{'message_id'},
@@ -1416,7 +1370,7 @@ sub _is_duplicate {
         WHERE message_transport_type = ?
         AND borrowernumber = ?
         AND letter_code = ?
-        AND CAST(time_queued AS date) = CAST(NOW() AS date)
+        AND CAST(updated_on AS date) = CAST(NOW() AS date)
         AND status="sent"
         AND content = ?
     |, {}, $message->{message_transport_type}, $message->{borrowernumber}, $message->{letter_code}, $message->{content} );
@@ -1453,6 +1407,12 @@ sub _update_message_to_address {
     $dbh->do('UPDATE message_queue SET to_address=? WHERE message_id=?',undef,($to,$id));
 }
 
+sub _update_message_from_address {
+    my ($message_id, $from_address) = @_;
+    my $dbh = C4::Context->dbh();
+    $dbh->do('UPDATE message_queue SET from_address = ? WHERE message_id = ?', undef, ($from_address, $message_id));
+}
+
 sub _set_message_status {
     my $params = shift or return;
 
@@ -1559,7 +1519,7 @@ sub _get_tt_params {
             module   => 'Koha::Holds',
             singular => 'hold',
             plural   => 'holds',
-            fk       => [ 'borrowernumber', 'biblionumber' ],
+            pk       => 'reserve_id',
         },
         serial => {
             module   => 'Koha::Serials',