Bug 7016 Followup: Add new GetItemnumberForBiblio subroutine
[koha_gimpoz] / C4 / Letters.pm
index f3ba145..6846a00 100644 (file)
@@ -13,19 +13,24 @@ package C4::Letters;
 # 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, write to the Free Software Foundation, Inc., 59 Temple Place,
-# Suite 330, Boston, MA  02111-1307 USA
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 use strict;
 use warnings;
 
 use MIME::Lite;
 use Mail::Sendmail;
+use Encode;
+use Carp;
+
 use C4::Members;
+use C4::Branch;
 use C4::Log;
 use C4::SMS;
 use C4::Debug;
+use Date::Calc qw( Add_Delta_Days );
 use Encode;
 use Carp;
 
@@ -37,7 +42,7 @@ BEGIN {
        $VERSION = 3.01;
        @ISA = qw(Exporter);
        @EXPORT = qw(
-       &GetLetters &getletter &addalert &getalert &delalert &findrelatedto &SendAlerts
+       &GetLetters &getletter &addalert &getalert &delalert &findrelatedto &SendAlerts GetPrintMessages
        );
 }
 
@@ -150,7 +155,7 @@ sub addalert ($$$) {
     parameters :
     - alertid : the alert id
     deletes the alert
-    
+
 =cut
 
 sub delalert ($) {
@@ -271,7 +276,7 @@ sub SendAlerts {
 
             # and parse borrower ...
             my $innerletter = $letter;
-            my $borinfo = GetMember( $_->{'borrowernumber'}, 'borrowernumber' );
+            my $borinfo = C4::Members::GetMember('borrowernumber' => $_->{'borrowernumber'});
             parseletter( $innerletter, 'borrowers', $_->{'borrowernumber'} );
 
             # ... then send mail
@@ -283,7 +288,7 @@ sub SendAlerts {
                     Message => "" . $innerletter->{content},
                     'Content-Type' => 'text/plain; charset="utf8"',
                     );
-                sendmail(%mail);
+                sendmail(%mail) or carp $Mail::Sendmail::error;
 
 # warn "sending to $mail{To} From $mail{From} subj $mail{Subject} Mess $mail{Message}";
             }
@@ -318,12 +323,14 @@ sub SendAlerts {
         $letter->{content} =~ s/<<LibrarianSurname>>/$userenv->{surname}/g;
         $letter->{content} =~
           s/<<LibrarianEmailaddress>>/$userenv->{emailaddress}/g;
-        foreach my $data (@$dataorders) {
-            my $line = $1 if ( $letter->{content} =~ m/(<<.*>>)/ );
-            foreach my $field ( keys %$data ) {
-                $line =~ s/(<<[^\.]+.$field>>)/$data->{$field}/;
+        foreach my $data ( @{$dataorders} ) {
+            if ( $letter->{content} =~ m/(<<.*>>)/ ) {
+                my $line = $1;
+                foreach my $field ( keys %{$data} ) {
+                    $line =~ s/(<<[^\.]+.$field>>)/$data->{$field}/;
+                }
+                $letter->{content} =~ s/(<<.*>>)/$line\n$1/;
             }
-            $letter->{content} =~ s/(<<.*>>)/$line\n$1/;
         }
         $letter->{content} =~ s/<<[^>]*>>//g;
         my $innerletter = $letter;
@@ -344,9 +351,7 @@ sub SendAlerts {
                 Message        => "" . $innerletter->{content},
                 'Content-Type' => 'text/plain; charset="utf8"',
             );
-            sendmail(%mail);
-            warn
-"sending to $mail{To} From $mail{From} subj $mail{Subject} Mess $mail{Message}";
+            sendmail(%mail) or carp $Mail::Sendmail::error;
         }
         if ( C4::Context->preference("LetterLog") ) {
             logaction(
@@ -388,33 +393,43 @@ sub SendAlerts {
         $letter->{content} =~ s/<<LibrarianSurname>>/$userenv->{surname}/g;
         $letter->{content} =~
           s/<<LibrarianEmailaddress>>/$userenv->{emailaddress}/g;
-        foreach my $data (@$dataorders) {
-            my $line = $1 if ( $letter->{content} =~ m/(<<.*>>)/ );
-            foreach my $field ( keys %$data ) {
-                $line =~ s/(<<[^\.]+.$field>>)/$data->{$field}/;
+        foreach my $data ( @{$dataorders} ) {
+            if ( $letter->{content} =~ m/(<<.*>>)/ ) {
+                my $line = $1;
+                foreach my $field ( keys %{$data} ) {
+                    $line =~ s/(<<[^\.]+.$field>>)/$data->{$field}/;
+                }
+                $letter->{content} =~ s/(<<.*>>)/$line\n$1/;
             }
-            $letter->{content} =~ s/(<<.*>>)/$line\n$1/;
         }
         $letter->{content} =~ s/<<[^>]*>>//g;
         my $innerletter = $letter;
 
         # ... then send mail
         if (   $databookseller->{bookselleremail}
-            || $databookseller->{contemail} )
-        {
+            || $databookseller->{contemail} ) {
+            my $mail_to = $databookseller->{bookselleremail};
+            if ($databookseller->{contemail}) {
+                if (!$mail_to) {
+                    $mail_to = $databookseller->{contemail};
+                } else {
+                    $mail_to .= q|,|;
+                    $mail_to .= $databookseller->{contemail};
+                }
+            }
+            my $mail_subj = $innerletter->{title};
+            my $mail_msg  = $innerletter->{content};
+            $mail_msg  ||= q{};
+            $mail_subj ||= q{};
+
             my %mail = (
-                To => $databookseller->{bookselleremail}
-                  . (
-                    $databookseller->{contemail}
-                    ? "," . $databookseller->{contemail}
-                    : ""
-                  ),
+                To => $mail_to,
                 From    => $userenv->{emailaddress},
-                Subject => "" . $innerletter->{title},
-                Message => "" . $innerletter->{content},
+                Subject => $mail_subj,
+                Message => $mail_msg,
                 'Content-Type' => 'text/plain; charset="utf8"',
             );
-            sendmail(%mail);
+            sendmail(%mail) or carp $Mail::Sendmail::error;
             logaction(
                 "ACQUISITION",
                 "CLAIM ISSUE",
@@ -427,25 +442,24 @@ sub SendAlerts {
                   . $innerletter->{content}
             ) if C4::Context->preference("LetterLog");
         }
-        warn
-"sending to From $userenv->{emailaddress} subj $innerletter->{title} Mess $innerletter->{content}";
     }    
    # send an "account details" notice to a newly created user 
     elsif ( $type eq 'members' ) {
-        $letter->{content} =~ s/<<borrowers.title>>/$externalid->{'title'}/g;
-        $letter->{content} =~ s/<<borrowers.firstname>>/$externalid->{'firstname'}/g;
-        $letter->{content} =~ s/<<borrowers.surname>>/$externalid->{'surname'}/g;
-        $letter->{content} =~ s/<<borrowers.userid>>/$externalid->{'userid'}/g;
+        # must parse the password special, before it's hashed.
         $letter->{content} =~ s/<<borrowers.password>>/$externalid->{'password'}/g;
 
+        parseletter( $letter, 'borrowers', $externalid->{'borrowernumber'});
+        parseletter( $letter, 'branches', $externalid->{'branchcode'} );
+
+        my $branchdetails = GetBranchDetail($externalid->{'branchcode'});
         my %mail = (
                 To      =>     $externalid->{'emailaddr'},
-                From    =>  C4::Context->preference("KohaAdminEmailAddress"),
+                From    =>  $branchdetails->{'branchemail'} || C4::Context->preference("KohaAdminEmailAddress"),
                 Subject => $letter->{'title'}, 
                 Message => $letter->{'content'},
                 'Content-Type' => 'text/plain; charset="utf8"',
         );
-        sendmail(%mail);
+        sendmail(%mail) or carp $Mail::Sendmail::error;
     }
 }
 
@@ -475,9 +489,12 @@ sub parseletter_sth {
     ($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 'suggestions'  ) ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?" :
     ($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 = ?"                      : undef ;
     unless ($query) {
         warn "ERROR: No parseletter_sth query for table '$table'";
@@ -496,7 +513,6 @@ sub parseletter {
         carp "ERROR: parseletter() 1st argument 'letter' empty";
         return;
     }
-    #  warn "Parseletter : ($letter, $table, $pk ...)";
     my $sth = parseletter_sth($table);
     unless ($sth) {
         warn "parseletter_sth('$table') failed to return a valid sth.  No substitution will be done for that table.";
@@ -509,23 +525,38 @@ sub parseletter {
     }
 
     my $values = $sth->fetchrow_hashref;
+    
+    # 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();
+    }
+
 
     # and get all fields from the table
     my $columns = C4::Context->dbh->prepare("SHOW COLUMNS FROM $table");
     $columns->execute;
     while ( ( my $field ) = $columns->fetchrow_array ) {
         my $replacefield = "<<$table.$field>>";
+        $values->{$field} =~ s/\p{P}(?=$)//g if $values->{$field};
         my $replacedby   = $values->{$field} || '';
         ($letter->{title}  ) and $letter->{title}   =~ s/$replacefield/$replacedby/g;
         ($letter->{content}) and $letter->{content} =~ s/$replacefield/$replacedby/g;
     }
+    return $letter;
 }
 
 =head2 EnqueueLetter
 
-=over 4
-
-my $success = EnqueueLetter( { letter => $letter, borrowernumber => '12', message_transport_type => 'email' } )
+  my $success = EnqueueLetter( { letter => $letter, 
+        borrowernumber => '12', message_transport_type => 'email' } )
 
 places a letter in the message_queue database table, which will
 eventually get processed (sent) by the process_message_queue.pl
@@ -533,8 +564,6 @@ cronjob when it calls SendQueuedMessages.
 
 return true on success
 
-=back
-
 =cut
 
 sub EnqueueLetter ($) {
@@ -580,16 +609,12 @@ ENDSQL
 
 =head2 SendQueuedMessages ([$hashref]) 
 
-=over 4
+  my $sent = SendQueuedMessages( { verbose => 1 } );
 
 sends all of the 'pending' items in the message queue.
 
-my $sent = SendQueuedMessages( { verbose => 1 } );
-
 returns number of messages sent.
 
-=back
-
 =cut
 
 sub SendQueuedMessages (;$) {
@@ -605,7 +630,7 @@ sub SendQueuedMessages (;$) {
         # This is just begging for subclassing
         next MESSAGE if ( lc($message->{'message_transport_type'}) eq 'rss' );
         if ( lc( $message->{'message_transport_type'} ) eq 'email' ) {
-            _send_message_by_email( $message );
+            _send_message_by_email( $message, $params->{'username'}, $params->{'password'}, $params->{'method'} );
         }
         elsif ( lc( $message->{'message_transport_type'} ) eq 'sms' ) {
             _send_message_by_sms( $message );
@@ -616,14 +641,10 @@ sub SendQueuedMessages (;$) {
 
 =head2 GetRSSMessages
 
-=over 4
-
-my $message_list = GetRSSMessages( { limit => 10, borrowernumber => '14' } )
+  my $message_list = GetRSSMessages( { limit => 10, borrowernumber => '14' } )
 
 returns a listref of all queued RSS messages for a particular person.
 
-=back
-
 =cut
 
 sub GetRSSMessages {
@@ -638,19 +659,31 @@ sub GetRSSMessages {
                                    borrowernumber         => $params->{'borrowernumber'}, } );
 }
 
-=head2 GetQueuedMessages ([$hashref])
+=head2 GetPrintMessages
 
-=over 4
+  my $message_list = GetPrintMessages( { borrowernumber => $borrowernumber } )
 
-my $messages = GetQueuedMessage( { borrowernumber => '123', limit => 20 } );
+Returns a arrayref of all queued print messages (optionally, for a particular
+person).
+
+=cut
+
+sub GetPrintMessages {
+    my $params = shift || {};
+    
+    return _get_unsent_messages( { message_transport_type => 'print',
+                                   borrowernumber         => $params->{'borrowernumber'}, } );
+}
+
+=head2 GetQueuedMessages ([$hashref])
+
+  my $messages = GetQueuedMessage( { borrowernumber => '123', limit => 20 } );
 
 fetches messages out of the message queue.
 
 returns:
 list of hashes, each has represents a message in the message queue.
 
-=back
-
 =cut
 
 sub GetQueuedMessages {
@@ -760,19 +793,27 @@ 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};
     unless ($to_address) {
-        my $member = C4::Members::GetMember( $message->{'borrowernumber'} );
+        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;
         }
-        unless ($to_address = $member->{email}) {   # assigment, not comparison
+        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};
+        }
+        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?
             _set_message_status( { message_id => $message->{'message_id'},
@@ -781,35 +822,38 @@ sub _send_message_by_email ($) {
         }
     }
 
-       my $content = encode('utf8', $message->{'content'});
+    my $utf8   = decode('MIME-Header', $message->{'subject'} );
+    $message->{subject}= encode('MIME-Header', $utf8);
+    my $content = encode('utf8', $message->{'content'});
     my %sendmail_params = (
         To   => $to_address,
         From => $message->{'from_address'} || C4::Context->preference('KohaAdminEmailAddress'),
-        Subject => $message->{'subject'},
+        Subject => encode('utf8', $message->{'subject'}),
         charset => 'utf8',
         Message => $content,
         'content-type' => $message->{'content_type'} || 'text/plain; charset="UTF-8"',
     );
+    $sendmail_params{'Auth'} = {user => $username, pass => $password, method => $method} if $username;
+    if ( my $bcc = C4::Context->preference('OverdueNoticeBcc') ) {
+       $sendmail_params{ Bcc } = $bcc;
+    }
     
-    my $success = sendmail( %sendmail_params );
 
-    if ( $success ) {
-        # warn "Sendmail OK. Log says: " .  $Mail::Sendmail::log;
+    if ( sendmail( %sendmail_params ) ) {
         _set_message_status( { message_id => $message->{'message_id'},
-                               status     => 'sent' } );
-        return $success;
+                status     => 'sent' } );
+        return 1;
     } else {
-        # warn "Mail::Sendmail::error - " . $Mail::Sendmail::error;
-        # warn "Mail::Sendmail::log   - " . $Mail::Sendmail::log;
         _set_message_status( { message_id => $message->{'message_id'},
-                               status     => 'failed' } );
+                status     => 'failed' } );
+        carp $Mail::Sendmail::error;
         return;
     }
 }
 
 sub _send_message_by_sms ($) {
     my $message = shift or return undef;
-    my $member = C4::Members::GetMember( $message->{'borrowernumber'} );
+    my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} );
     return unless $member->{'smsalertnumber'};
 
     my $success = C4::SMS->send_sms( { destination => $member->{'smsalertnumber'},