View | Details | Raw Unified | Return to bug 12802
Collapse All | Expand All

(-)a/C4/Auth.pm (-1 / +1 lines)
Lines 1407-1413 sub checkauth { Link Here
1407
        $template->param(
1407
        $template->param(
1408
            TwoFA_prompt => 1,
1408
            TwoFA_prompt => 1,
1409
            invalid_otp_token => $invalid_otp_token,
1409
            invalid_otp_token => $invalid_otp_token,
1410
            notice_email_address => $patron->notice_email_address, # We could also pass logged_in_user if necessary
1410
            notice_email_addresses => $patron->notice_email_addresses, # We could also pass logged_in_user if necessary
1411
        );
1411
        );
1412
    }
1412
    }
1413
1413
(-)a/C4/Auth_with_ldap.pm (-5 / +6 lines)
Lines 236-245 sub checkpw_ldap { Link Here
236
236
237
        # Send welcome email if enabled
237
        # Send welcome email if enabled
238
        if ( $config{welcome} ) {
238
        if ( $config{welcome} ) {
239
            my $emailaddr = $patron->notice_email_address;
239
            my $emailaddrs = $patron->notice_email_addresses;
240
240
241
            # if we manage to find a valid email address, send notice
241
            # if we manage to find a valid email address, send notice
242
            if ($emailaddr) {
242
            if (@$emailaddrs) {
243
                my $letter = C4::Letters::GetPreparedLetter(
243
                my $letter = C4::Letters::GetPreparedLetter(
244
                    module      => 'members',
244
                    module      => 'members',
245
                    letter_code => 'WELCOME',
245
                    letter_code => 'WELCOME',
Lines 252-267 sub checkpw_ldap { Link Here
252
                    want_librarian => 1,
252
                    want_librarian => 1,
253
                ) or return;
253
                ) or return;
254
254
255
                my $message_id = C4::Letters::EnqueueLetter(
255
                my @message_ids = C4::Letters::EnqueueLetter(
256
                    {
256
                    {
257
                        letter                 => $letter,
257
                        letter                 => $letter,
258
                        borrowernumber         => $patron->id,
258
                        borrowernumber         => $patron->id,
259
                        to_address             => $emailaddr,
260
                        message_transport_type => 'email'
259
                        message_transport_type => 'email'
261
                    }
260
                    }
262
                );
261
                );
263
262
264
                C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
263
                foreach my $message_id (@message_ids) {
264
                    C4::Letters::SendQueuedMessages( { message_id => $message_id } );
265
                }
265
            }
266
            }
266
        }
267
        }
267
   } else {
268
   } else {
(-)a/C4/Auth_with_shibboleth.pm (-5 / +6 lines)
Lines 144-153 sub _autocreate { Link Here
144
144
145
    # Send welcome email if enabled
145
    # Send welcome email if enabled
146
    if ( $config->{welcome} ) {
146
    if ( $config->{welcome} ) {
147
        my $emailaddr = $patron->notice_email_address;
147
        my $emailaddrs = $patron->notice_email_addresses;
148
148
149
        # if we manage to find a valid email address, send notice
149
        # if we manage to find a valid email address, send notice
150
        if ($emailaddr) {
150
        if (@$emailaddrs) {
151
            my $letter = C4::Letters::GetPreparedLetter(
151
            my $letter = C4::Letters::GetPreparedLetter(
152
                module      => 'members',
152
                module      => 'members',
153
                letter_code => 'WELCOME',
153
                letter_code => 'WELCOME',
Lines 161-175 sub _autocreate { Link Here
161
                want_librarian => 1,
161
                want_librarian => 1,
162
            ) or return;
162
            ) or return;
163
163
164
            my $message_id = C4::Letters::EnqueueLetter(
164
            my @message_ids = C4::Letters::EnqueueLetter(
165
                {
165
                {
166
                    letter                 => $letter,
166
                    letter                 => $letter,
167
                    borrowernumber         => $patron->id,
167
                    borrowernumber         => $patron->id,
168
                    to_address             => $emailaddr,
169
                    message_transport_type => 'email'
168
                    message_transport_type => 'email'
170
                }
169
                }
171
            );
170
            );
172
            C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
171
            foreach my $message_id (@message_ids) {
172
                C4::Letters::SendQueuedMessages( { message_id => $message_id } );
173
            }
173
        }
174
        }
174
    }
175
    }
175
    return ( 1, $patron->cardnumber, $patron->userid );
176
    return ( 1, $patron->cardnumber, $patron->userid );
(-)a/C4/Circulation.pm (-4 / +6 lines)
Lines 3780-3793 sub SendCirculationAlert { Link Here
3780
3780
3781
        C4::Context->dbh->do(q|LOCK TABLE message_queue READ|) unless $do_not_lock;
3781
        C4::Context->dbh->do(q|LOCK TABLE message_queue READ|) unless $do_not_lock;
3782
        C4::Context->dbh->do(q|LOCK TABLE message_queue WRITE|) unless $do_not_lock;
3782
        C4::Context->dbh->do(q|LOCK TABLE message_queue WRITE|) unless $do_not_lock;
3783
        my $message = C4::Message->find_last_message($borrower, $type, $mtt);
3783
        my @messages = C4::Message->find_last_messages($borrower, $type, $mtt);
3784
        unless ( $message ) {
3784
        unless ( @messages ) {
3785
            C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3785
            C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3786
            my $patron = Koha::Patrons->find($borrower->{borrowernumber});
3786
            my $patron = Koha::Patrons->find($borrower->{borrowernumber});
3787
            C4::Message->enqueue($letter, $patron, $mtt);
3787
            C4::Message->enqueue($letter, $patron, $mtt);
3788
        } else {
3788
        } else {
3789
            $message->append($letter);
3789
            foreach my $message (@messages) {
3790
            $message->update;
3790
                $message->append($letter);
3791
                $message->update;
3792
            }
3791
        }
3793
        }
3792
        C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3794
        C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3793
    }
3795
    }
(-)a/C4/Letters.pm (-49 / +86 lines)
Lines 31-36 use C4::SMS; Link Here
31
use C4::Templates;
31
use C4::Templates;
32
use Koha::Auth::TwoFactorAuth;
32
use Koha::Auth::TwoFactorAuth;
33
use Koha::DateUtils qw( dt_from_string output_pref );
33
use Koha::DateUtils qw( dt_from_string output_pref );
34
use Koha::Database;
34
use Koha::Email;
35
use Koha::Email;
35
use Koha::Exceptions;
36
use Koha::Exceptions;
36
use Koha::Notice::Messages;
37
use Koha::Notice::Messages;
Lines 898-917 sub _parseletter { Link Here
898
899
899
=head2 EnqueueLetter
900
=head2 EnqueueLetter
900
901
901
  my $success = EnqueueLetter( { letter => $letter, 
902
    my @message_ids = EnqueueLetter({
902
        borrowernumber => '12', message_transport_type => 'email' } )
903
        letter => $letter,
904
        borrowernumber => '12',
905
        message_transport_type => 'email'
906
    });
903
907
904
Places a letter in the message_queue database table, which will
908
Places a letter in the message_queue database table, which will
905
eventually get processed (sent) by the process_message_queue.pl
909
eventually get processed (sent) by the process_message_queue.pl
906
cronjob when it calls SendQueuedMessages.
910
cronjob when it calls SendQueuedMessages.
907
911
908
Return message_id on success
912
return the list of message ids
909
913
910
Parameters
914
Parameters
911
* letter - required; A letter hashref as returned from GetPreparedLetter
915
* letter - required; A letter hashref as returned from GetPreparedLetter
912
* message_transport_type - required; One of the available mtts
916
* message_transport_type - required; One of the available mtts
913
* borrowernumber - optional if 'to_address' is passed; The borrowernumber of the patron we enqueuing the notice for
917
* borrowernumber - optional if 'to_address' is passed; The borrowernumber of the patron we enqueuing the notice for
914
* to_address - optional if 'borrowernumber' is passed; The destination email address for the notice (defaults to patron->notice_email_address)
918
* to_address - optional if 'borrowernumber' is passed; The destination email address for the notice (defaults to patron->notice_email_addresses)
915
* from_address - optional; The from address for the notice, defaults to patron->library->from_email_address
919
* from_address - optional; The from address for the notice, defaults to patron->library->from_email_address
916
* reply_address - optional; The reply address for the notice, defaults to patron->library->reply_to
920
* reply_address - optional; The reply address for the notice, defaults to patron->library->reply_to
917
921
Lines 921-927 sub EnqueueLetter { Link Here
921
    my $params = shift or return;
925
    my $params = shift or return;
922
926
923
    return unless exists $params->{'letter'};
927
    return unless exists $params->{'letter'};
924
#   return unless exists $params->{'borrowernumber'};
925
    return unless exists $params->{'message_transport_type'};
928
    return unless exists $params->{'message_transport_type'};
926
929
927
    my $content = $params->{letter}->{content};
930
    my $content = $params->{letter}->{content};
Lines 940-964 sub EnqueueLetter { Link Here
940
        );
943
        );
941
    }
944
    }
942
945
943
    my $message = Koha::Notice::Message->new(
946
    my @to_addresses;
944
        {
947
    if ( $params->{to_address} ) {
945
            letter_id              => $params->{letter}->{id} || undef,
948
        @to_addresses = ( $params->{to_address} );
946
            borrowernumber         => $params->{borrowernumber},
949
    } elsif ( $params->{borrowernumber} and $params->{message_transport_type} eq 'email' ) {
947
            subject                => $params->{letter}->{title},
950
        my $patron = Koha::Patrons->find( $params->{borrowernumber} );
948
            content                => $params->{letter}->{content},
951
        if ($patron) {
949
            metadata               => $params->{letter}->{metadata} || q{},
952
            @to_addresses = @{ $patron->notice_email_addresses };
950
            letter_code            => $params->{letter}->{code} || q{},
953
        }
951
            message_transport_type => $params->{message_transport_type},
954
    }
952
            status                 => 'pending',
955
953
            time_queued            => dt_from_string(),
956
    my $from_address;
954
            to_address             => $params->{to_address},
957
    if ( $params->{from_address} ) {
955
            from_address           => $params->{from_address},
958
        $from_address = $params->{from_address};
956
            reply_address          => $params->{reply_address},
959
    } elsif ( $params->{message_transport_type} eq 'email' ) {
957
            content_type           => $params->{letter}->{'content-type'},
960
        if ( $params->{borrowernumber} ) {
958
            failure_code           => $params->{failure_code} || q{},
961
            my $patron = Koha::Patrons->find( $params->borrowernumber );
962
            if ( $patron ) {
963
                $from_address = $patron->library->from_email_address;
964
            }
959
        }
965
        }
960
    )->store();
966
961
    return $message->id;
967
        $from_address ||= C4::Context->preference('KohaAdminEmailAddress');
968
    }
969
970
    my @message_ids;
971
972
    if ( $params->{message_transport_type} eq 'email' ) {
973
        foreach my $to_address ( @to_addresses ) {
974
            my $message = Koha::Notice::Message->new(
975
                {
976
                    letter_id              => $params->{letter}->{id} || undef,
977
                    borrowernumber         => $params->{borrowernumber},
978
                    subject                => $params->{letter}->{title},
979
                    content                => $params->{letter}->{content},
980
                    metadata               => $params->{letter}->{metadata} || q{},
981
                    letter_code            => $params->{letter}->{code} || q{},
982
                    message_transport_type => $params->{message_transport_type},
983
                    status                 => 'pending',
984
                    time_queued            => dt_from_string(),
985
                    to_address             => $params->{to_address},
986
                    from_address           => $params->{from_address},
987
                    reply_address          => $params->{reply_address},
988
                    content_type           => $params->{letter}->{'content-type'},
989
                    failure_code           => $params->{failure_code} || q{},
990
                }
991
            )->store();
992
            push @message_ids, $message->id();
993
        }
994
    } else {
995
        my $message = Koha::Notice::Message->new(
996
            {
997
                letter_id              => $params->{letter}->{id} || undef,
998
                borrowernumber         => $params->{borrowernumber},
999
                subject                => $params->{letter}->{title},
1000
                content                => $params->{letter}->{content},
1001
                metadata               => $params->{letter}->{metadata} || q{},
1002
                letter_code            => $params->{letter}->{code} || q{},
1003
                message_transport_type => $params->{message_transport_type},
1004
                status                 => 'pending',
1005
                time_queued            => dt_from_string(),
1006
                from_address           => $params->{from_address},
1007
                reply_address          => $params->{reply_address},
1008
                content_type           => $params->{letter}->{'content-type'},
1009
                failure_code           => $params->{failure_code} || q{},
1010
            }
1011
        )->store();
1012
        push @message_ids, $message->id();
1013
    }
1014
1015
    return @message_ids;
962
}
1016
}
963
1017
964
=head2 SendQueuedMessages ([$hashref]) 
1018
=head2 SendQueuedMessages ([$hashref]) 
Lines 1114-1144 Return is an arrayref of hashes, each has represents a message in the message qu Link Here
1114
sub GetQueuedMessages {
1168
sub GetQueuedMessages {
1115
    my $params = shift;
1169
    my $params = shift;
1116
1170
1117
    my $dbh = C4::Context->dbh();
1171
    my ( %cond, %attrs );
1118
    my $statement = << 'ENDSQL';
1119
SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, updated_on, failure_code
1120
FROM message_queue
1121
ENDSQL
1122
1123
    my @query_params;
1124
    my @whereclauses;
1125
    if ( exists $params->{'borrowernumber'} ) {
1126
        push @whereclauses, ' borrowernumber = ? ';
1127
        push @query_params, $params->{'borrowernumber'};
1128
    }
1129
1172
1130
    if ( @whereclauses ) {
1173
    $cond{borrowernumber} = $params->{borrowernumber} if $params->{borrowernumber};
1131
        $statement .= ' WHERE ' . join( 'AND', @whereclauses );
1132
    }
1133
1174
1134
    if ( defined $params->{'limit'} ) {
1175
    $attrs{rows} = $params->{limit} if $params->{limit};
1135
        $statement .= ' LIMIT ? ';
1136
        push @query_params, $params->{'limit'};
1137
    }
1138
1176
1139
    my $sth = $dbh->prepare( $statement );
1177
    my $rs = Koha::Database->schema->resultset('MessageQueue')->search( \%cond, \%attrs );
1140
    my $result = $sth->execute( @query_params );
1178
    $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
1141
    return $sth->fetchall_arrayref({});
1179
    return [ $rs->all ];
1142
}
1180
}
1143
1181
1144
=head2 GetMessageTransportTypes
1182
=head2 GetMessageTransportTypes
Lines 1202-1210 sub ResendMessage { Link Here
1202
            status => 'pending',
1240
            status => 'pending',
1203
        });
1241
        });
1204
        $rv = $rv > 0? 1: 0;
1242
        $rv = $rv > 0? 1: 0;
1205
        # Clear destination email address to force address update
1206
        _update_message_to_address( $message_id, undef ) if $rv &&
1207
            $message->{message_transport_type} eq 'email';
1208
    }
1243
    }
1209
    return $rv;
1244
    return $rv;
1210
}
1245
}
Lines 1337-1342 sub _send_message_by_email { Link Here
1337
    my $cc_address;
1372
    my $cc_address;
1338
    my @guarantor_address;
1373
    my @guarantor_address;
1339
    my $count_guarantor_address;
1374
    my $count_guarantor_address;
1375
    my $to_addresses;
1340
    if (C4::Context->preference('RedirectGuaranteeEmail') && $patron) {
1376
    if (C4::Context->preference('RedirectGuaranteeEmail') && $patron) {
1341
        # Get guarantor addresses
1377
        # Get guarantor addresses
1342
        my $guarantor_relationships = $patron->guarantor_relationships;
1378
        my $guarantor_relationships = $patron->guarantor_relationships;
Lines 1361-1368 sub _send_message_by_email { Link Here
1361
        }
1397
        }
1362
        if ($patron) {
1398
        if ($patron) {
1363
            $to_address = $patron->notice_email_address;
1399
            $to_address = $patron->notice_email_address;
1400
            $to_addresses = $patron->notice_email_addresses;
1364
        }
1401
        }
1365
        if (!$to_address && !$count_guarantor_address) {
1402
        if (!$to_address && !$count_guarantor_address && !$to_addresses) {
1366
            warn "FAIL: No 'to_address', email address or guarantors email address for borrowernumber ($message->{borrowernumber})";
1403
            warn "FAIL: No 'to_address', email address or guarantors email address for borrowernumber ($message->{borrowernumber})";
1367
            _set_message_status(
1404
            _set_message_status(
1368
                {
1405
                {
(-)a/C4/Message.pm (-35 / +8 lines)
Lines 54-60 How to update a borrower's last checkout message: Link Here
54
54
55
  use C4::Message;
55
  use C4::Message;
56
  my $borrower = { borrowernumber => 1 };
56
  my $borrower = { borrowernumber => 1 };
57
  my $message  = C4::Message->find_last_message($borrower, 'CHECKOUT', 'email');
57
  my $message  = C4::Message->find_last_messages($borrower, 'CHECKOUT', 'email');
58
  $message->append("you also checked out some other book....");
58
  $message->append("you also checked out some other book....");
59
  $message->update;
59
  $message->update;
60
60
Lines 111-127 sub find { Link Here
111
    }
111
    }
112
}
112
}
113
113
114
=head3 C4::Message->find_last_message($borrower, $letter_code, $transport)
114
=head3 C4::Message->find_last_messages($borrower, $letter_code, $transport)
115
115
116
This method is used to get the borrower's most recent, pending, check-in or
116
This method is used to get the borrower's most recent, pending, check-in or
117
checkout message.  (This makes it possible to add more information to the
117
checkout messages.  (This makes it possible to add more information to the
118
message before it gets sent out.)
118
message before it gets sent out.)
119
119
120
=cut
120
=cut
121
121
122
# C4::Message->find_last_message($borrower, $letter_code, $transport)
122
# C4::Message->find_last_messages($borrower, $letter_code, $transport)
123
# -- get the borrower's most recent pending checkin or checkout notification
123
# -- get the borrower's most recent pending checkin or checkout notifications
124
sub find_last_message {
124
sub find_last_messages {
125
    my ($class, $borrower, $letter_code, $transport) = @_;
125
    my ($class, $borrower, $letter_code, $transport) = @_;
126
    # $type is the message_transport_type
126
    # $type is the message_transport_type
127
    $transport ||= 'email';
127
    $transport ||= 'email';
Lines 140-150 sub find_last_message { Link Here
140
        $letter_code,
140
        $letter_code,
141
        $transport,
141
        $transport,
142
    );
142
    );
143
    if (@$msgs) {
143
144
        return $class->new($msgs->[0]);
144
    return map { $class->new($_) } @$msgs;
145
    } else {
146
        return;
147
    }
148
}
145
}
149
146
150
147
Lines 159-165 the message. Link Here
159
sub enqueue {
156
sub enqueue {
160
    my ( $class, $letter, $patron, $transport ) = @_;
157
    my ( $class, $letter, $patron, $transport ) = @_;
161
    my $metadata   = _metadata($letter);
158
    my $metadata   = _metadata($letter);
162
    my $to_address = _to_address( $patron, $transport );
163
159
164
    # Same as render_metadata
160
    # Same as render_metadata
165
    my $format ||= sub { $_[0] || "" };
161
    my $format ||= sub { $_[0] || "" };
Lines 172-204 sub enqueue { Link Here
172
            letter                 => $letter,
168
            letter                 => $letter,
173
            borrowernumber         => $patron->id,
169
            borrowernumber         => $patron->id,
174
            message_transport_type => $transport,
170
            message_transport_type => $transport,
175
            to_address             => $to_address,
176
        }
171
        }
177
    );
172
    );
178
}
173
}
179
174
180
# based on message $transport, pick an appropriate address to send to
181
sub _to_address {
182
    my ( $patron, $transport ) = @_;
183
    my $address;
184
    if ( $transport eq 'email' ) {
185
        $address = $patron->notice_email_address;
186
    }
187
    elsif ( $transport eq 'sms' ) {
188
        $address = $patron->smsalertnumber;
189
    }
190
    else {
191
        warn "'$transport' is an unknown message transport.";
192
    }
193
    if ( not defined $address ) {
194
        warn "An appropriate $transport address "
195
          . "for borrower "
196
          . $patron->userid
197
          . "could not be found.";
198
    }
199
    return $address;
200
}
201
202
# _metadata($letter) -- return the letter split into head/body/footer
175
# _metadata($letter) -- return the letter split into head/body/footer
203
sub _metadata {
176
sub _metadata {
204
    my ($letter) = @_;
177
    my ($letter) = @_;
(-)a/C4/Reserves.pm (-6 / +7 lines)
Lines 842-853 SELECT COUNT(*) FROM reserves WHERE biblionumber=? AND borrowernumber<>? Link Here
842
Takes an itemnumber and returns the status of the reserve placed on it.
842
Takes an itemnumber and returns the status of the reserve placed on it.
843
If several reserves exist, the reserve with the lower priority is given.
843
If several reserves exist, the reserve with the lower priority is given.
844
844
845
=cut
846
847
## FIXME: I don't think this does what it thinks it does.
845
## FIXME: I don't think this does what it thinks it does.
848
## It only ever checks the first reserve result, even though
846
## It only ever checks the first reserve result, even though
849
## multiple reserves for that bib can have the itemnumber set
847
## multiple reserves for that bib can have the itemnumber set
850
## the sub is only used once in the codebase.
848
## the sub is only used once in the codebase.
849
850
=cut
851
851
sub GetReserveStatus {
852
sub GetReserveStatus {
852
    my ($itemnumber) = @_;
853
    my ($itemnumber) = @_;
853
854
Lines 1854-1862 sub _koha_notify_reserve { Link Here
1854
1855
1855
    my $patron = Koha::Patrons->find( $borrowernumber );
1856
    my $patron = Koha::Patrons->find( $borrowernumber );
1856
1857
1857
    # Try to get the borrower's email address
1858
    my $to_address = $patron->notice_email_address;
1859
1860
    my $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( {
1858
    my $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( {
1861
            borrowernumber => $borrowernumber,
1859
            borrowernumber => $borrowernumber,
1862
            message_name => 'Hold_Filled'
1860
            message_name => 'Hold_Filled'
Lines 1916-1924 sub _koha_notify_reserve { Link Here
1916
        }
1914
        }
1917
    };
1915
    };
1918
1916
1917
    # Try to get the borrower's email addresses
1918
    my $to_addresses = $patron->notice_email_addresses;
1919
1919
    while ( my ( $mtt, $letter_code ) = each %{ $messagingprefs->{transports} } ) {
1920
    while ( my ( $mtt, $letter_code ) = each %{ $messagingprefs->{transports} } ) {
1920
        next if (
1921
        next if (
1921
               ( $mtt eq 'email' and not $to_address ) # No email address
1922
               ( $mtt eq 'email' and not @$to_addresses ) # No email address
1922
            or ( $mtt eq 'sms'   and not $patron->smsalertnumber ) # No SMS number
1923
            or ( $mtt eq 'sms'   and not $patron->smsalertnumber ) # No SMS number
1923
            or ( $mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') ) # Notice is handled by TalkingTech_itiva_outbound.pl
1924
            or ( $mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') ) # Notice is handled by TalkingTech_itiva_outbound.pl
1924
            or ( $mtt eq 'phone' and not $patron->phone ) # No phone number to call
1925
            or ( $mtt eq 'phone' and not $patron->phone ) # No phone number to call
(-)a/Koha/Patron.pm (-17 / +26 lines)
Lines 1014-1023 sub set_password { Link Here
1014
    if ( C4::Context->preference('NotifyPasswordChange') ) {
1014
    if ( C4::Context->preference('NotifyPasswordChange') ) {
1015
        my $self_from_storage = $self->get_from_storage;
1015
        my $self_from_storage = $self->get_from_storage;
1016
        if ( !C4::Auth::checkpw_hash( $password, $self_from_storage->password ) ) {
1016
        if ( !C4::Auth::checkpw_hash( $password, $self_from_storage->password ) ) {
1017
            my $emailaddr = $self_from_storage->notice_email_address;
1017
            my $emailaddrs = $self_from_storage->notice_email_addresses;
1018
1018
1019
            # if we manage to find a valid email address, send notice
1019
            # if we manage to find a valid email address, send notice
1020
            if ($emailaddr) {
1020
            if (@$emailaddrs) {
1021
                my $letter = C4::Letters::GetPreparedLetter(
1021
                my $letter = C4::Letters::GetPreparedLetter(
1022
                    module      => 'members',
1022
                    module      => 'members',
1023
                    letter_code => 'PASSWORD_CHANGE',
1023
                    letter_code => 'PASSWORD_CHANGE',
Lines 1031-1045 sub set_password { Link Here
1031
                    want_librarian => 1,
1031
                    want_librarian => 1,
1032
                ) or return;
1032
                ) or return;
1033
1033
1034
                my $message_id = C4::Letters::EnqueueLetter(
1034
                my @message_ids = C4::Letters::EnqueueLetter(
1035
                    {
1035
                    {
1036
                        letter                 => $letter,
1036
                        letter                 => $letter,
1037
                        borrowernumber         => $self_from_storage->id,
1037
                        borrowernumber         => $self_from_storage->id,
1038
                        to_address             => $emailaddr,
1039
                        message_transport_type => 'email'
1038
                        message_transport_type => 'email'
1040
                    }
1039
                    }
1041
                );
1040
                );
1042
                C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
1041
                foreach my $message_id (@message_ids) {
1042
                    C4::Letters::SendQueuedMessages( { message_id => $message_id } );
1043
                }
1043
            }
1044
            }
1044
        }
1045
        }
1045
    }
1046
    }
Lines 1603-1627 sub return_claims { Link Here
1603
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1604
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1604
}
1605
}
1605
1606
1606
=head3 notice_email_address
1607
=head3 notice_email_addresses
1607
1608
1608
  my $email = $patron->notice_email_address;
1609
  my $emails = $patron->notice_email_addresses;
1609
1610
1610
Return the email address of patron used for notices.
1611
Return an arrayref containing the email addresses of patron used for notices.
1611
Returns the empty string if no email address.
1612
1612
1613
=cut
1613
=cut
1614
1614
1615
sub notice_email_address{
1615
sub notice_email_addresses {
1616
    my ( $self ) = @_;
1616
    my ( $self ) = @_;
1617
1617
1618
    my $which_address = C4::Context->preference("EmailFieldPrimary");
1618
    my $which_addresses = C4::Context->preference("EmailFieldPrimary");
1619
    # if syspref is set to 'first valid' (value == OFF), look up email address
1619
    # if syspref is set to 'first valid' (value == OFF), look up email address
1620
    if ( $which_address eq 'OFF' ) {
1620
    my @email_addresses;
1621
        return $self->first_valid_email_address;
1621
    for my $email_address_field (split /,/, $which_addresses) {
1622
        # if syspref is set to 'first valid' (value == OFF), look up email address
1623
        if ( $email_address_field eq 'OFF' ) {
1624
            return [ $self->first_valid_email_address ];
1625
        }
1626
1627
        my $email_address = $self->$email_address_field;
1628
        push @email_addresses, $email_address if $email_address;
1622
    }
1629
    }
1623
1630
1624
    return $self->$which_address || '';
1631
    return \@email_addresses;
1625
}
1632
}
1626
1633
1627
=head3 first_valid_email_address
1634
=head3 first_valid_email_address
Lines 2517-2523 sub queue_notice { Link Here
2517
    foreach my $mtt (@message_transports){
2524
    foreach my $mtt (@message_transports){
2518
        next if ($mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') );
2525
        next if ($mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') );
2519
        # Notice is handled by TalkingTech_itiva_outbound.pl
2526
        # Notice is handled by TalkingTech_itiva_outbound.pl
2520
        if (   ( $mtt eq 'email' and not $self->notice_email_address )
2527
        my $email_addresses = $self->notice_email_addresses;
2528
        if (   ( $mtt eq 'email' and not @$email_addresses )
2521
            or ( $mtt eq 'sms'   and not $self->smsalertnumber )
2529
            or ( $mtt eq 'sms'   and not $self->smsalertnumber )
2522
            or ( $mtt eq 'phone' and not $self->phone ) )
2530
            or ( $mtt eq 'phone' and not $self->phone ) )
2523
        {
2531
        {
Lines 2661-2677 sub notify_library_of_registration { Link Here
2661
                || C4::Context->preference('KohaAdminEmailAddress');
2669
                || C4::Context->preference('KohaAdminEmailAddress');
2662
        }
2670
        }
2663
2671
2664
        my $message_id = C4::Letters::EnqueueLetter(
2672
        my ($message_id) = C4::Letters::EnqueueLetter(
2665
            {
2673
            {
2666
                letter                 => $letter,
2674
                letter                 => $letter,
2667
                borrowernumber         => $self->borrowernumber,
2675
                borrowernumber         => $self->borrowernumber,
2668
                to_address             => $to_address,
2676
                to_address             => $to_address,
2669
                message_transport_type => 'email'
2677
                message_transport_type => 'email'
2670
            }
2678
            }
2671
        ) or warn "can't enqueue letter $letter";
2679
        );
2672
        if ( $message_id ) {
2680
        if ( $message_id ) {
2673
            return 1;
2681
            return 1;
2674
        }
2682
        }
2683
        warn "can't enqueue letter $letter";
2675
    }
2684
    }
2676
}
2685
}
2677
2686
(-)a/Koha/Patron/Password/Recovery.pm (-2 / +5 lines)
Lines 148-154 sub SendPasswordRecoveryEmail { Link Here
148
    my $library = $borrower->library;
148
    my $library = $borrower->library;
149
    my $kohaEmail = $library->from_email_address; # send from patron's branch or Koha Admin
149
    my $kohaEmail = $library->from_email_address; # send from patron's branch or Koha Admin
150
150
151
    my $message_id = C4::Letters::EnqueueLetter(
151
    my @message_ids = C4::Letters::EnqueueLetter(
152
        {
152
        {
153
            letter                 => $letter,
153
            letter                 => $letter,
154
            borrowernumber         => $borrower->borrowernumber,
154
            borrowernumber         => $borrower->borrowernumber,
Lines 159-165 sub SendPasswordRecoveryEmail { Link Here
159
    );
159
    );
160
160
161
    my $num_letters_attempted = 0;
161
    my $num_letters_attempted = 0;
162
    $num_letters_attempted = C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
162
    foreach my $message_id (@message_ids) {
163
        $num_letters_attempted +=
164
          C4::Letters::SendQueuedMessages( { message_id => $message_id } );
165
    }
163
166
164
    return ($num_letters_attempted > 0);
167
    return ($num_letters_attempted > 0);
165
}
168
}
(-)a/Koha/Patrons/Import.pm (-5 / +4 lines)
Lines 454-463 sub import_patrons { Link Here
454
454
455
        # Send WELCOME welcome email is the user is new and we're set to send mail
455
        # Send WELCOME welcome email is the user is new and we're set to send mail
456
        if ($send_welcome && $is_new) {
456
        if ($send_welcome && $is_new) {
457
            my $emailaddr = $patron->notice_email_address;
457
            my $emailaddrs = $patron->notice_email_addresses;
458
458
459
            # if we manage to find a valid email address, send notice
459
            # if we manage to find a valid email address, send notice
460
            if ($emailaddr) {
460
            if (@$emailaddrs) {
461
                eval {
461
                eval {
462
                    my $letter = GetPreparedLetter(
462
                    my $letter = GetPreparedLetter(
463
                        module      => 'members',
463
                        module      => 'members',
Lines 471-481 sub import_patrons { Link Here
471
                        want_librarian => 1,
471
                        want_librarian => 1,
472
                    ) or return;
472
                    ) or return;
473
473
474
                    my $message_id = EnqueueLetter(
474
                    EnqueueLetter(
475
                        {
475
                        {
476
                            letter                 => $letter,
476
                            letter                 => $letter,
477
                            borrowernumber         => $patron->id,
477
                            borrowernumber         => $patron->id,
478
                            to_address             => $emailaddr,
479
                            message_transport_type => 'email'
478
                            message_transport_type => 'email'
480
                        }
479
                        }
481
                    );
480
                    );
Lines 488-494 sub import_patrons { Link Here
488
                        {
487
                        {
489
                            feedback     => 1,
488
                            feedback     => 1,
490
                            name         => 'welcome_sent',
489
                            name         => 'welcome_sent',
491
                            value        => $borrower{'surname'} . ' / ' . $borrowernumber . ' / ' . $emailaddr
490
                            value        => $borrower{'surname'} . ' / ' . $borrowernumber . ' / ' . join(', ', @$emailaddrs)
492
                        }
491
                        }
493
                    );
492
                    );
494
                }
493
                }
(-)a/Koha/REST/V1/TwoFactorAuth.pm (-9 / +11 lines)
Lines 55-76 sub send_otp_token { Link Here
55
                borrowers => $patron->unblessed,
55
                borrowers => $patron->unblessed,
56
            }
56
            }
57
        );
57
        );
58
        my $message_id = C4::Letters::EnqueueLetter(
58
        my @message_ids = C4::Letters::EnqueueLetter(
59
            {
59
            {
60
                letter                 => $letter,
60
                letter                 => $letter,
61
                borrowernumber         => $patron->borrowernumber,
61
                borrowernumber         => $patron->borrowernumber,
62
                message_transport_type => 'email'
62
                message_transport_type => 'email'
63
            }
63
            }
64
        );
64
        );
65
        C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
65
        foreach my $message_id (@message_ids) {
66
            C4::Letters::SendQueuedMessages( { message_id => $message_id } );
66
67
67
        my $message = C4::Letters::GetMessage($message_id);
68
            my $message = C4::Letters::GetMessage($message_id);
68
69
            if ( $message->{status} ne 'sent' ) {
69
        if ( $message->{status} eq 'sent' ) {
70
                return $c->render( status => 400, openapi => { error => 'email_not_sent' } );
70
            return $c->render(status => 200, openapi => {});
71
            }
71
        } elsif ( $message->{status} eq 'failed' ) {
72
            return $c->render(status => 400, openapi => { error => 'email_not_sent'});
73
        }
72
        }
73
74
        return $c->render( status => 200, openapi => {} );
75
74
    }
76
    }
75
    catch {
77
    catch {
76
        $c->unhandled_exception($_);
78
        $c->unhandled_exception($_);
Lines 155-161 sub verification { Link Here
155
        # FIXME Generate a (new?) secret
157
        # FIXME Generate a (new?) secret
156
        $patron->encode_secret($secret32);
158
        $patron->encode_secret($secret32);
157
        $patron->auth_method('two-factor')->store;
159
        $patron->auth_method('two-factor')->store;
158
        if ( $patron->notice_email_address ) {
160
        if ( @{ $patron->notice_email_addresses } ) {
159
            $patron->queue_notice(
161
            $patron->queue_notice(
160
                {
162
                {
161
                    letter_params => {
163
                    letter_params => {
(-)a/Koha/Ticket.pm (-6 / +12 lines)
Lines 124-138 sub store { Link Here
124
        );
124
        );
125
125
126
        if ($acknowledgement_letter) {
126
        if ($acknowledgement_letter) {
127
            my $acknowledgement_message_id = C4::Letters::EnqueueLetter(
127
            my @acknowledgement_message_ids = C4::Letters::EnqueueLetter(
128
                {
128
                {
129
                    letter                 => $acknowledgement_letter,
129
                    letter                 => $acknowledgement_letter,
130
                    message_transport_type => 'email',
130
                    message_transport_type => 'email',
131
                    borrowernumber         => $self->reporter_id,
131
                    borrowernumber         => $self->reporter_id,
132
                }
132
                }
133
            );
133
            );
134
            C4::Letters::SendQueuedMessages( { message_id => $acknowledgement_message_id } )
134
            foreach my $acknowledgement_message_id (@acknowledgement_message_ids) {
135
                if $acknowledgement_message_id;
135
                C4::Letters::SendQueuedMessages(
136
                    { message_id => $acknowledgement_message_id } );
137
            }
136
        }
138
        }
137
139
138
        # Notify cataloger by email
140
        # Notify cataloger by email
Lines 147-162 sub store { Link Here
147
            );
149
            );
148
150
149
            if ($notify_letter) {
151
            if ($notify_letter) {
150
                my $message_id = C4::Letters::EnqueueLetter(
152
                my ($reporter_first_notice_email_address) = @{ $self->reporter->notice_email_addresses };
153
                my @message_ids = C4::Letters::EnqueueLetter(
151
                    {
154
                    {
152
                        letter                 => $notify_letter,
155
                        letter                 => $notify_letter,
153
                        message_transport_type => 'email',
156
                        message_transport_type => 'email',
154
                        to_address             =>
157
                        to_address             =>
155
                          C4::Context->preference('CatalogerEmails'),
158
                          C4::Context->preference('CatalogerEmails'),
156
                        reply_address => $self->reporter->notice_email_address,
159
                        reply_address => $reporter_first_notice_email_address,
157
                    }
160
                    }
158
                );
161
                );
159
                C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
162
                foreach my $message_id (@message_ids) {
163
                    C4::Letters::SendQueuedMessages(
164
                        { message_id => $message_id } );
165
                }
160
            }
166
            }
161
        }
167
        }
162
    }
168
    }
(-)a/basket/sendbasket.pl (-1 / +1 lines)
Lines 58-64 if ($email_add) { Link Here
58
      );
58
      );
59
59
60
    my $patron     = Koha::Patrons->find($borrowernumber);
60
    my $patron     = Koha::Patrons->find($borrowernumber);
61
    my $user_email = $patron->notice_email_address;
61
    my ($user_email) = @{ $patron->notice_email_addresses };
62
62
63
    my $comment = $query->param('comment');
63
    my $comment = $query->param('comment');
64
64
(-)a/circ/pendingreserves.pl (-1 / +1 lines)
Lines 93-99 if ( $op eq 'cancel_reserve' and $reserve_id ) { Link Here
93
                        from_address           => $from_address,
93
                        from_address           => $from_address,
94
                    }
94
                    }
95
                );
95
                );
96
                unless ( $patron->notice_email_address ) {
96
                unless ( @{ $patron->notice_email_addresses } ) {
97
                    push @messages, {type => 'alert', code => 'no_email_address', };
97
                    push @messages, {type => 'alert', code => 'no_email_address', };
98
                }
98
                }
99
                push @messages, { type => 'message', code => 'letter_enqueued' };
99
                push @messages, { type => 'message', code => 'letter_enqueued' };
(-)a/installer/data/mysql/atomicupdate/bug-12802.pl (+12 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number  => '12802',
5
    description => 'Change type of system preference AutoEmailPrimaryAddress to multiple',
6
    up          => sub {
7
        my ($args) = @_;
8
        my ( $dbh, $out ) = @$args{qw(dbh out)};
9
10
        $dbh->do("UPDATE systempreferences SET type='multiple' WHERE variable='AutoEmailPrimaryAddress'");
11
    },
12
};
(-)a/installer/data/mysql/mandatory/sysprefs.sql (-1 / +1 lines)
Lines 225-231 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
225
('EmailAddressForPatronRegistrations', '', '', ' If you choose EmailAddressForPatronRegistrations you have to enter a valid email address: ', 'free'),
225
('EmailAddressForPatronRegistrations', '', '', ' If you choose EmailAddressForPatronRegistrations you have to enter a valid email address: ', 'free'),
226
('EmailAddressForSuggestions','','',' If you choose EmailAddressForSuggestions you have to enter a valid email address: ','free'),
226
('EmailAddressForSuggestions','','',' If you choose EmailAddressForSuggestions you have to enter a valid email address: ','free'),
227
('EmailFieldPrecedence','email|emailpro|B_email','','Ordered list of patron email fields to use when AutoEmailPrimaryAddress is set to first valid','multiple'),
227
('EmailFieldPrecedence','email|emailpro|B_email','','Ordered list of patron email fields to use when AutoEmailPrimaryAddress is set to first valid','multiple'),
228
('EmailFieldPrimary','OFF','email|emailpro|B_email|cardnumber|OFF','Defines the default email address field where patron email notices are sent.','Choice'),
228
('EmailFieldPrimary','OFF','email|emailpro|B_email|cardnumber|OFF','Defines the default email address field where patron email notices are sent.','multiple'),
229
('emailLibrarianWhenHoldIsPlaced','0',NULL,'If ON, emails the librarian whenever a hold is placed','YesNo'),
229
('emailLibrarianWhenHoldIsPlaced','0',NULL,'If ON, emails the librarian whenever a hold is placed','YesNo'),
230
('EmailOverduesNoEmail','1',NULL,'Send send overdues of patrons without email address to staff','YesNo'),
230
('EmailOverduesNoEmail','1',NULL,'Send send overdues of patrons without email address to staff','YesNo'),
231
('EmailPatronRegistrations', '0', '0|EmailAddressForPatronRegistrations|BranchEmailAddress|KohaAdminEmailAddress', 'Choose email address that new patron registrations will be sent to: ', 'Choice'),
231
('EmailPatronRegistrations', '0', '0|EmailAddressForPatronRegistrations|BranchEmailAddress|KohaAdminEmailAddress', 'Choose email address that new patron registrations will be sent to: ', 'Choice'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc (-3 / +3 lines)
Lines 54-62 Link Here
54
                </td>
54
                </td>
55
                <td><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% reserveloo.borrower.borrowernumber | uri %]">[% INCLUDE 'patron-title.inc' patron=reserveloo.borrower invert_name=1 no_title=1 %]</a>
55
                <td><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% reserveloo.borrower.borrowernumber | uri %]">[% INCLUDE 'patron-title.inc' patron=reserveloo.borrower invert_name=1 no_title=1 %]</a>
56
                    [% IF ( reserveloo.borrower.phone ) %]<br /><span class="patron_phone">[% reserveloo.borrower.phone | html %]</span>[% END %]
56
                    [% IF ( reserveloo.borrower.phone ) %]<br /><span class="patron_phone">[% reserveloo.borrower.phone | html %]</span>[% END %]
57
                    [% IF ( reserveloo.borrower.notice_email_address ) %]
57
                    [% FOREACH notice_email_address IN reserveloo.borrower.notice_email_addresses %]
58
                        <span class="patron_email"><br /><a href="mailto:[% reserveloo.borrower.notice_email_address | uri %]?subject=[% "Hold waiting: " | uri %][% reserveloo.biblio.title | uri %]">
58
                        <span class="patron_email"><br /><a href="mailto:[% notice_email_address | uri %]?subject=[% "Hold waiting: " | uri %][% reserveloo.biblio.title | uri %]">
59
                        [% reserveloo.borrower.notice_email_address | html %]</a></span>
59
                        [% notice_email_address | html %]</a></span>
60
                    [% END %]
60
                    [% END %]
61
                </td>
61
                </td>
62
                <td>[% Branches.GetName( reserveloo.item.homebranch ) | html %]</td>
62
                <td>[% Branches.GetName( reserveloo.item.homebranch ) | html %]</td>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (-1 / +1 lines)
Lines 194-200 Patrons: Link Here
194
         - "Use the patron's"
194
         - "Use the patron's"
195
         - pref: EmailFieldPrimary
195
         - pref: EmailFieldPrimary
196
           default: "OFF"
196
           default: "OFF"
197
           choices:
197
           multiple:
198
               email: primary email
198
               email: primary email
199
               emailpro: secondary email
199
               emailpro: secondary email
200
               B_email: alternate email
200
               B_email: alternate email
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt (-1 / +1 lines)
Lines 254-260 Link Here
254
254
255
            $("#send_otp").on("click", function(e){
255
            $("#send_otp").on("click", function(e){
256
                e.preventDefault();
256
                e.preventDefault();
257
                [% UNLESS notice_email_address %]
257
                [% UNLESS notice_email_addresses.size > 0 %]
258
                    alert("Cannot send the notice, you don't have an email address defined.")
258
                    alert("Cannot send the notice, you don't have an email address defined.")
259
                [% ELSE %]
259
                [% ELSE %]
260
                $("#email_success").hide();
260
                $("#email_success").hide();
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt (-3 / +3 lines)
Lines 77-87 Link Here
77
                            [% reser.patron.surname | html %][%IF ( reser.patron.firstname ) %], [% reser.patron.firstname | html %][% END %]
77
                            [% reser.patron.surname | html %][%IF ( reser.patron.firstname ) %], [% reser.patron.firstname | html %][% END %]
78
                        </a>
78
                        </a>
79
                        [% IF ( reser.patron.phone ) %]<br />[% reser.patron.phone | html %][% END %]
79
                        [% IF ( reser.patron.phone ) %]<br />[% reser.patron.phone | html %][% END %]
80
                            [% IF ( reser.patron.notice_email_address ) %]
80
                            [% FOREACH notice_email_address IN reser.patron.notice_email_addresses %]
81
                                <br />
81
                                <br />
82
                                [% BLOCK subject %]Hold:[% END %]
82
                                [% BLOCK subject %]Hold:[% END %]
83
                                <a href="mailto:[% reser.patron.notice_email_address | uri %]?subject=[% INCLUDE subject %] [% reser.title | uri %]">
83
                                <a href="mailto:[% notice_email_address | uri %]?subject=[% INCLUDE subject %] [% reser.title | uri %]">
84
                                    [% reser.patron.notice_email_address | html %]
84
                                    [% notice_email_address | html %]
85
                                </a>
85
                                </a>
86
                            [% END %]
86
                            [% END %]
87
                        [% ELSIF ( reser.recall ) %]
87
                        [% ELSIF ( reser.recall ) %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt (-1 / +1 lines)
Lines 58-64 Link Here
58
                    <td>[% c.name | html %]</td>
58
                    <td>[% c.name | html %]</td>
59
                    <td>[% c.description | html %]</td>
59
                    <td>[% c.description | html %]</td>
60
                    <td>
60
                    <td>
61
                        [% IF !c.club_template.is_email_required || ( c.club_template.is_email_required && borrower.notice_email_address ) %]
61
                        [% IF !c.club_template.is_email_required || ( c.club_template.is_email_required && borrower.notice_email_addresses.size > 0 ) %]
62
                            <button class="btn btn-sm btn-primary load_enrollment" data-id="[% c.id | html%]">
62
                            <button class="btn btn-sm btn-primary load_enrollment" data-id="[% c.id | html%]">
63
                                <i class="fa fa-plus" aria-hidden="true"></i> Enroll
63
                                <i class="fa fa-plus" aria-hidden="true"></i> Enroll
64
                            </button>
64
                            </button>
(-)a/members/memberentry.pl (-5 / +6 lines)
Lines 454-462 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
454
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
454
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
455
        if ( $patron && C4::Context->preference("AutoEmailNewUser") ) {
455
        if ( $patron && C4::Context->preference("AutoEmailNewUser") ) {
456
            #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
456
            #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
457
            my $emailaddr = $patron->notice_email_address;
457
            my $emailaddrs = $patron->notice_email_addresses;
458
            # if we manage to find a valid email address, send notice 
458
            # if we manage to find a valid email address, send notice 
459
            if ($emailaddr) {
459
            if (@$emailaddrs) {
460
                eval {
460
                eval {
461
                    my $letter = GetPreparedLetter(
461
                    my $letter = GetPreparedLetter(
462
                        module      => 'members',
462
                        module      => 'members',
Lines 470-484 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
470
                        want_librarian => 1,
470
                        want_librarian => 1,
471
                    ) or return;
471
                    ) or return;
472
472
473
                    my $message_id = EnqueueLetter(
473
                    my @message_ids = EnqueueLetter(
474
                        {
474
                        {
475
                            letter                 => $letter,
475
                            letter                 => $letter,
476
                            borrowernumber         => $patron->id,
476
                            borrowernumber         => $patron->id,
477
                            to_address             => $emailaddr,
478
                            message_transport_type => 'email'
477
                            message_transport_type => 'email'
479
                        }
478
                        }
480
                    );
479
                    );
481
                    SendQueuedMessages( { message_id => $message_id } ) if $message_id;
480
                    foreach my $message_id (@message_ids) {
481
                        SendQueuedMessages({ message_id => $message_id });
482
                    }
482
                };
483
                };
483
                if ($@) {
484
                if ($@) {
484
                    $template->param( error_alert => $@ );
485
                    $template->param( error_alert => $@ );
(-)a/members/notices.pl (-7 / +6 lines)
Lines 62-71 if ( $op eq 'resend_notice' ) { Link Here
62
}
62
}
63
63
64
if ( $op eq 'send_welcome' ) {
64
if ( $op eq 'send_welcome' ) {
65
    my $emailaddr = $patron->notice_email_address;
65
    my $emailaddrs = $patron->notice_email_addresses;
66
66
67
    # if we manage to find a valid email address, send notice
67
    # if we manage to find a valid email address, send notice
68
    if ($emailaddr) {
68
    if (@$emailaddrs) {
69
        eval {
69
        eval {
70
            my $letter = GetPreparedLetter(
70
            my $letter = GetPreparedLetter(
71
                module      => 'members',
71
                module      => 'members',
Lines 79-89 if ( $op eq 'send_welcome' ) { Link Here
79
                want_librarian => 1,
79
                want_librarian => 1,
80
            ) or return;
80
            ) or return;
81
81
82
            my $message_id = EnqueueLetter(
82
            EnqueueLetter(
83
                {
83
                {
84
                    letter                 => $letter,
84
                    letter                 => $letter,
85
                    borrowernumber         => $patron->id,
85
                    borrowernumber         => $patron->id,
86
                    to_address             => $emailaddr,
87
                    message_transport_type => 'email'
86
                    message_transport_type => 'email'
88
                }
87
                }
89
            );
88
            );
Lines 96-107 if ( $op eq 'send_welcome' ) { Link Here
96
95
97
if ( $op eq 'send_password_reset' ) {
96
if ( $op eq 'send_password_reset' ) {
98
97
99
    my $emailaddr = $patron->notice_email_address;
98
    my $emailaddrs = $patron->notice_email_addresses;
100
99
101
    if ($emailaddr) {
100
    if (@$emailaddrs) {
102
101
103
        # send staff initiated password recovery
102
        # send staff initiated password recovery
104
        SendPasswordRecoveryEmail( $patron, $emailaddr, 1 );
103
        SendPasswordRecoveryEmail( $patron, undef, 1 );
105
    }
104
    }
106
105
107
    # redirect to self to avoid form submission on refresh
106
    # redirect to self to avoid form submission on refresh
(-)a/members/two_factor_auth.pl (-1 / +1 lines)
Lines 63-69 else { Link Here
63
          Koha::Auth::TwoFactorAuth->new( { patron => $logged_in_user } );
63
          Koha::Auth::TwoFactorAuth->new( { patron => $logged_in_user } );
64
        $logged_in_user->secret(undef);
64
        $logged_in_user->secret(undef);
65
        $logged_in_user->auth_method('password')->store;
65
        $logged_in_user->auth_method('password')->store;
66
        if ( $logged_in_user->notice_email_address ) {
66
        if ( @{ $logged_in_user->notice_email_addresses } ) {
67
            $logged_in_user->queue_notice(
67
            $logged_in_user->queue_notice(
68
                {
68
                {
69
                    letter_params => {
69
                    letter_params => {
(-)a/misc/cronjobs/notice_unprocessed_suggestions.pl (-2 / +2 lines)
Lines 47-55 for my $number_of_days (@days) { Link Here
47
47
48
        my $budget = C4::Budgets::GetBudget( $suggestion->{budgetid} );
48
        my $budget = C4::Budgets::GetBudget( $suggestion->{budgetid} );
49
        my $patron = Koha::Patrons->find( $budget->{budget_owner_id} );
49
        my $patron = Koha::Patrons->find( $budget->{budget_owner_id} );
50
        my $email_address = $patron->notice_email_address;
50
        my $email_addresses = $patron->notice_email_addresses;
51
51
52
        if ($email_address) {
52
        if (@$email_addresses) {
53
            say "Patron " . $patron->borrowernumber . " is going to be notified" if $verbose;
53
            say "Patron " . $patron->borrowernumber . " is going to be notified" if $verbose;
54
            my $letter = C4::Letters::GetPreparedLetter(
54
            my $letter = C4::Letters::GetPreparedLetter(
55
                module      => 'suggestions',
55
                module      => 'suggestions',
(-)a/misc/cronjobs/overdue_notices.pl (-4 / +4 lines)
Lines 617-623 END_SQL Link Here
617
                        || $library->inbound_email_address;
617
                        || $library->inbound_email_address;
618
                }
618
                }
619
                @emails_to_use = ();
619
                @emails_to_use = ();
620
                my $notice_email = $patron->notice_email_address;
621
                unless ($nomail) {
620
                unless ($nomail) {
622
                    if (@emails) {
621
                    if (@emails) {
623
                        foreach (@emails) {
622
                        foreach (@emails) {
Lines 625-631 END_SQL Link Here
625
                        }
624
                        }
626
                    }
625
                    }
627
                    else {
626
                    else {
628
                        push @emails_to_use, $notice_email if ($notice_email);
627
                        my $notice_emails = $patron->notice_email_addresses;
628
                        push @emails_to_use, @$notice_emails;
629
                    }
629
                    }
630
                }
630
                }
631
631
Lines 784-790 END_SQL Link Here
784
                              letternumber   => $i,
784
                              letternumber   => $i,
785
                              postcode       => $data->{'zipcode'},
785
                              postcode       => $data->{'zipcode'},
786
                              country        => $data->{'country'},
786
                              country        => $data->{'country'},
787
                              email          => $notice_email,
787
                              email          => ( scalar( @emails_to_use ) ? $emails_to_use[0] : undef ),
788
                              itemcount      => $itemcount,
788
                              itemcount      => $itemcount,
789
                              titles         => $titles,
789
                              titles         => $titles,
790
                              outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
790
                              outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
Lines 803-809 END_SQL Link Here
803
                                  city           => $data->{'city'},
803
                                  city           => $data->{'city'},
804
                                  postcode       => $data->{'zipcode'},
804
                                  postcode       => $data->{'zipcode'},
805
                                  country        => $data->{'country'},
805
                                  country        => $data->{'country'},
806
                                  email          => $notice_email,
806
                                  email          => ( scalar( @emails_to_use ) ? $emails_to_use[0] : undef ),
807
                                  itemcount      => $itemcount,
807
                                  itemcount      => $itemcount,
808
                                  titles         => $titles,
808
                                  titles         => $titles,
809
                                  outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
809
                                  outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
(-)a/misc/cronjobs/thirdparty/TalkingTech_itiva_outbound.pl (-2 / +5 lines)
Lines 122-128 foreach my $type (@types) { Link Here
122
    my $patrons;
122
    my $patrons;
123
    foreach my $issues (@loop) {
123
    foreach my $issues (@loop) {
124
        $patrons->{$issues->{borrowernumber}} ||= Koha::Patrons->find( $issues->{borrowernumber} ) if $skip_patrons_with_email;
124
        $patrons->{$issues->{borrowernumber}} ||= Koha::Patrons->find( $issues->{borrowernumber} ) if $skip_patrons_with_email;
125
        next if $skip_patrons_with_email && $patrons->{$issues->{borrowernumber}}->notice_email_address;
125
        if ($skip_patrons_with_email) {
126
            my $email_addresses = $patrons->{$issues->{borrowernumber}}->notice_email_addresses;
127
            next if @$email_addresses;
128
        }
126
129
127
        my $date_dt = dt_from_string ( $issues->{'date_due'} );
130
        my $date_dt = dt_from_string ( $issues->{'date_due'} );
128
        my $due_date = output_pref( { dt => $date_dt, dateonly => 1, dateformat =>'metric' } );
131
        my $due_date = output_pref( { dt => $date_dt, dateonly => 1, dateformat =>'metric' } );
Lines 143-149 foreach my $type (@types) { Link Here
143
146
144
        my $message_id = 0;
147
        my $message_id = 0;
145
        if ($outfile) {
148
        if ($outfile) {
146
            $message_id = C4::Letters::EnqueueLetter(
149
            ($message_id) = C4::Letters::EnqueueLetter(
147
                {   letter                 => $letter,
150
                {   letter                 => $letter,
148
                    borrowernumber         => $issues->{'borrowernumber'},
151
                    borrowernumber         => $issues->{'borrowernumber'},
149
                    message_transport_type => 'itiva',
152
                    message_transport_type => 'itiva',
(-)a/opac/opac-memberentry.pl (-10 / +11 lines)
Lines 213-228 if ( $action eq 'create' ) { Link Here
213
                },
213
                },
214
            );
214
            );
215
215
216
            my $message_id = C4::Letters::EnqueueLetter(
216
            my @message_ids = C4::Letters::EnqueueLetter(
217
                {
217
                {
218
                    borrowernumber         => $borrower{borrowernumber},
218
                    letter                 => $letter,
219
                    letter                 => $letter,
219
                    message_transport_type => 'email',
220
                    message_transport_type => 'email',
220
                    to_address             => $borrower{'email'},
221
                    from_address =>
222
                      C4::Context->preference('KohaAdminEmailAddress'),
223
                }
221
                }
224
            );
222
            );
225
            C4::Letters::SendQueuedMessages( { message_id => $message_id } ) if $message_id;
223
            for my $message_id (@message_ids) {
224
                C4::Letters::SendQueuedMessages({ message_id => $message_id });
225
            }
226
        }
226
        }
227
        else {
227
        else {
228
            $borrower{password}         ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode}));
228
            $borrower{password}         ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode}));
Lines 266-274 if ( $action eq 'create' ) { Link Here
266
                # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
266
                # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
267
                if ( C4::Context->preference("AutoEmailNewUser") ) {
267
                if ( C4::Context->preference("AutoEmailNewUser") ) {
268
                    #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
268
                    #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
269
                    my $emailaddr = $patron->notice_email_address;
269
                    my $emailaddrs = $patron->notice_email_addresses;
270
                    # if we manage to find a valid email address, send notice
270
                    # if we manage to find a valid email address, send notice
271
                    if ($emailaddr) {
271
                    if (@$emailaddrs) {
272
                        eval {
272
                        eval {
273
                            my $letter = GetPreparedLetter(
273
                            my $letter = GetPreparedLetter(
274
                                module      => 'members',
274
                                module      => 'members',
Lines 282-296 if ( $action eq 'create' ) { Link Here
282
                                want_librarian => 1,
282
                                want_librarian => 1,
283
                            ) or return;
283
                            ) or return;
284
284
285
                            my $message_id = EnqueueLetter(
285
                            my @message_ids = EnqueueLetter(
286
                                {
286
                                {
287
                                    letter                 => $letter,
287
                                    letter                 => $letter,
288
                                    borrowernumber         => $patron->id,
288
                                    borrowernumber         => $patron->id,
289
                                    to_address             => $emailaddr,
290
                                    message_transport_type => 'email'
289
                                    message_transport_type => 'email'
291
                                }
290
                                }
292
                            );
291
                            );
293
                            SendQueuedMessages( { message_id => $message_id } ) if $message_id;
292
                            foreach my $message_id (@message_ids) {
293
                                SendQueuedMessages({ message_id => $message_id });
294
                            }
294
                        };
295
                        };
295
                    }
296
                    }
296
                }
297
                }
(-)a/opac/opac-registration-verify.pl (-5 / +6 lines)
Lines 96-104 if ( Link Here
96
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
96
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
97
        if ( C4::Context->preference("AutoEmailNewUser") ) {
97
        if ( C4::Context->preference("AutoEmailNewUser") ) {
98
            # Look up correct email address taking EmailFieldPrimary into account
98
            # Look up correct email address taking EmailFieldPrimary into account
99
            my $emailaddr = $patron->notice_email_address;
99
            my $emailaddrs = $patron->notice_email_addresses;
100
            # if we manage to find a valid email address, send notice
100
            # if we manage to find a valid email address, send notice
101
            if ($emailaddr) {
101
            if (@$emailaddrs) {
102
                eval {
102
                eval {
103
                    my $letter = GetPreparedLetter(
103
                    my $letter = GetPreparedLetter(
104
                        module      => 'members',
104
                        module      => 'members',
Lines 112-126 if ( Link Here
112
                        want_librarian => 1,
112
                        want_librarian => 1,
113
                    ) or return;
113
                    ) or return;
114
114
115
                    my $message_id = EnqueueLetter(
115
                    my @message_ids = EnqueueLetter(
116
                        {
116
                        {
117
                            letter                 => $letter,
117
                            letter                 => $letter,
118
                            borrowernumber         => $patron->id,
118
                            borrowernumber         => $patron->id,
119
                            to_address             => $emailaddr,
120
                            message_transport_type => 'email'
119
                            message_transport_type => 'email'
121
                        }
120
                        }
122
                    );
121
                    );
123
                    SendQueuedMessages( { message_id => $message_id } ) if $message_id;
122
                    foreach my $message_id (@message_ids) {
123
                        SendQueuedMessages({ message_id => $message_id });
124
                    }
124
                };
125
                };
125
            }
126
            }
126
        }
127
        }
(-)a/opac/opac-sendbasket.pl (-1 / +1 lines)
Lines 58-64 if ( $email_add ) { Link Here
58
      );
58
      );
59
59
60
    my $patron     = Koha::Patrons->find($borrowernumber);
60
    my $patron     = Koha::Patrons->find($borrowernumber);
61
    my $user_email = $patron->notice_email_address;
61
    my $user_email = @{ $patron->notice_email_addresses };
62
62
63
    my $comment = $query->param('comment');
63
    my $comment = $query->param('comment');
64
64
(-)a/opac/opac-sendshelf.pl (-1 / +1 lines)
Lines 61-67 if ( $shelf and $shelf->can_be_viewed($borrowernumber) ) { Link Here
61
        my $comment = $query->param('comment');
61
        my $comment = $query->param('comment');
62
62
63
        my $patron     = Koha::Patrons->find($borrowernumber);
63
        my $patron     = Koha::Patrons->find($borrowernumber);
64
        my $user_email = $patron->notice_email_address;
64
        my ($user_email) = @{ $patron->notice_email_addresses };
65
        my $shelf      = Koha::Virtualshelves->find($shelfid);
65
        my $shelf      = Koha::Virtualshelves->find($shelfid);
66
        my $contents   = $shelf->get_contents;
66
        my $contents   = $shelf->get_contents;
67
        my $iso2709;
67
        my $iso2709;
(-)a/opac/opac-shareshelf.pl (-5 / +2 lines)
Lines 164-170 sub notify_owner { Link Here
164
    my $patron = Koha::Patrons->find( $param->{owner} );
164
    my $patron = Koha::Patrons->find( $param->{owner} );
165
    return unless $patron;
165
    return unless $patron;
166
166
167
    my $toaddr = $patron->notice_email_address or return;
167
    return unless @{ $patron->notice_email_addresses };
168
168
169
    #prepare letter
169
    #prepare letter
170
    my $letter = C4::Letters::GetPreparedLetter(
170
    my $letter = C4::Letters::GetPreparedLetter(
Lines 179-188 sub notify_owner { Link Here
179
    #send letter to queue
179
    #send letter to queue
180
    C4::Letters::EnqueueLetter(
180
    C4::Letters::EnqueueLetter(
181
        {
181
        {
182
            borrowernumber         => $param->{owner},
182
            letter                 => $letter,
183
            letter                 => $letter,
183
            message_transport_type => 'email',
184
            message_transport_type => 'email',
184
            from_address => C4::Context->preference('KohaAdminEmailAddress'),
185
            to_address   => $toaddr,
186
        }
185
        }
187
    );
186
    );
188
}
187
}
Lines 208-214 sub process_addrlist { Link Here
208
207
209
sub send_invitekey {
208
sub send_invitekey {
210
    my ($param) = @_;
209
    my ($param) = @_;
211
    my $fromaddr = C4::Context->preference('KohaAdminEmailAddress');
212
    my $url =
210
    my $url =
213
        C4::Context->preference('OPACBaseURL')
211
        C4::Context->preference('OPACBaseURL')
214
      . "/cgi-bin/koha/opac-shareshelf.pl?shelfnumber="
212
      . "/cgi-bin/koha/opac-shareshelf.pl?shelfnumber="
Lines 250-256 sub send_invitekey { Link Here
250
            {
248
            {
251
                letter                 => $letter,
249
                letter                 => $letter,
252
                message_transport_type => 'email',
250
                message_transport_type => 'email',
253
                from_address           => $fromaddr,
254
                to_address             => $a,
251
                to_address             => $a,
255
            }
252
            }
256
        );
253
        );
(-)a/opac/opac-shelves.pl (-2 / +2 lines)
Lines 273-280 if ( $op eq 'add_form' ) { Link Here
273
        my $patrons = [];
273
        my $patrons = [];
274
        my $shares = $shelf->get_shares->search({ borrowernumber => { '!=' => undef } });
274
        my $shares = $shelf->get_shares->search({ borrowernumber => { '!=' => undef } });
275
        while( my $share = $shares->next ) {
275
        while( my $share = $shares->next ) {
276
            my $email = $share->sharee->notice_email_address;
276
            my $emails = $share->sharee->notice_email_addresses;
277
            push @$patrons, { email => $email, borrowernumber => $share->get_column('borrowernumber') } if $email;
277
            push @$patrons, { email => $emails->[0], borrowernumber => $share->get_column('borrowernumber') } if @$emails;
278
        }
278
        }
279
        if( @$patrons ) {
279
        if( @$patrons ) {
280
            $template->param( shared_users => $patrons );
280
            $template->param( shared_users => $patrons );
(-)a/pos/pay.pl (-2 / +4 lines)
Lines 106-112 if ( $action eq 'send' ) { Link Here
106
    );
106
    );
107
107
108
    # Add letter to the queue
108
    # Add letter to the queue
109
    my $message_id = EnqueueLetter(
109
    my @message_ids = EnqueueLetter(
110
        {
110
        {
111
            letter                 => $letter,
111
            letter                 => $letter,
112
            message_transport_type => 'email',
112
            message_transport_type => 'email',
Lines 116-122 if ( $action eq 'send' ) { Link Here
116
    );
116
    );
117
117
118
    # Send immediately
118
    # Send immediately
119
    SendQueuedMessages( { message_id => $message_id } ) if $message_id;
119
    foreach my $message_id (@message_ids) {
120
        SendQueuedMessages( { message_id => $message_id } );
121
    }
120
122
121
    # Set variables for template to allow printing still
123
    # Set variables for template to allow printing still
122
    $template->param(
124
    $template->param(
(-)a/suggestion/suggestion.pl (-3 / +2 lines)
Lines 202-210 if ( $op =~ /save/i ) { Link Here
202
202
203
            if ( $notify ) {
203
            if ( $notify ) {
204
                my $patron = Koha::Patrons->find( $suggestion_only->{managedby} );
204
                my $patron = Koha::Patrons->find( $suggestion_only->{managedby} );
205
                my $email_address = $patron->notice_email_address;
205
                my $email_addresses = $patron->notice_email_addresses;
206
                if ($patron->notice_email_address) {
206
                if (@$email_addresses) {
207
208
                    my $letter = C4::Letters::GetPreparedLetter(
207
                    my $letter = C4::Letters::GetPreparedLetter(
209
                        module      => 'suggestions',
208
                        module      => 'suggestions',
210
                        letter_code => 'NOTIFY_MANAGER',
209
                        letter_code => 'NOTIFY_MANAGER',
(-)a/t/db_dependent/Koha/Patron.t (-3 / +3 lines)
Lines 1789-1795 subtest 'notify_library_of_registration()' => sub { Link Here
1789
    $schema->storage->txn_rollback;
1789
    $schema->storage->txn_rollback;
1790
};
1790
};
1791
1791
1792
subtest 'notice_email_address' => sub {
1792
subtest 'notice_email_addresses' => sub {
1793
    plan tests => 2;
1793
    plan tests => 2;
1794
    $schema->storage->txn_begin;
1794
    $schema->storage->txn_begin;
1795
1795
Lines 1797-1806 subtest 'notice_email_address' => sub { Link Here
1797
1797
1798
    t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'email|emailpro' );
1798
    t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'email|emailpro' );
1799
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1799
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1800
    is ($patron->notice_email_address, $patron->email, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is off");
1800
    is_deeply ($patron->notice_email_addresses, [$patron->email], "Koha::Patron->notice_email_addresses returns correct value when EmailFieldPrimary is off");
1801
1801
1802
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1802
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1803
    is ($patron->notice_email_address, $patron->emailpro, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is emailpro");
1803
    is_deeply ($patron->notice_email_addresses, [$patron->emailpro], "Koha::Patron->notice_email_addresses returns correct value when EmailFieldPrimary is emailpro");
1804
1804
1805
    $patron->delete;
1805
    $patron->delete;
1806
    $schema->storage->txn_rollback;
1806
    $schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Patrons.t (-1 / +1 lines)
Lines 2018-2024 subtest '->set_password' => sub { Link Here
2018
    t::lib::Mocks::mock_preference( 'NotifyPasswordChange', 1 );
2018
    t::lib::Mocks::mock_preference( 'NotifyPasswordChange', 1 );
2019
    $patron->set_password({ password => 'abcd   c' });
2019
    $patron->set_password({ password => 'abcd   c' });
2020
    my $queued_notices = Koha::Notice::Messages->search({ borrowernumber => $patron->borrowernumber });
2020
    my $queued_notices = Koha::Notice::Messages->search({ borrowernumber => $patron->borrowernumber });
2021
    is( $queued_notices->count, 1, "One notice queued when NotifyPasswordChange enabled" );
2021
    is( $queued_notices->count, scalar @{ $patron->notice_email_addresses }, "One notice queued for each notice email address when NotifyPasswordChange enabled" );
2022
    my $THE_notice = $queued_notices->next;
2022
    my $THE_notice = $queued_notices->next;
2023
    is( $THE_notice->status, 'failed', "The notice was handled immediately and failed on wrong email address."); #FIXME Mock sending mail
2023
    is( $THE_notice->status, 'failed', "The notice was handled immediately and failed on wrong email address."); #FIXME Mock sending mail
2024
    $schema->storage->txn_rollback;
2024
    $schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Recall.t (-1 / +1 lines)
Lines 129-135 is( t::lib::Dates::compare( $expirationdate, $expected_expirationdate ), 0, "Exp Link Here
129
$recall2->set_waiting({ expirationdate => $expirationdate });
129
$recall2->set_waiting({ expirationdate => $expirationdate });
130
is( $recall2->waiting, 1, "Recall is waiting" );
130
is( $recall2->waiting, 1, "Recall is waiting" );
131
131
132
my $notice = C4::Message->find_last_message( $patron1->unblessed, 'PICKUP_RECALLED_ITEM', 'email' );
132
my ($notice) = C4::Message->find_last_messages( $patron1->unblessed, 'PICKUP_RECALLED_ITEM', 'email' );
133
ok( defined $notice, "Patron was notified to pick up waiting recall" );
133
ok( defined $notice, "Patron was notified to pick up waiting recall" );
134
134
135
$recall2->set_expired({ interface => 'COMMANDLINE' });
135
$recall2->set_expired({ interface => 'COMMANDLINE' });
(-)a/t/db_dependent/Letters.t (-14 / +92 lines)
Lines 117-124 my $my_message = { Link Here
117
    to_address             => undef,
117
    to_address             => undef,
118
    from_address           => 'from@example.com',
118
    from_address           => 'from@example.com',
119
};
119
};
120
my $message_id = C4::Letters::EnqueueLetter($my_message);
120
is( C4::Letters::EnqueueLetter($my_message), undef, 'EnqueueLetter without the letter argument returns undef' );
121
is( $message_id, undef, 'EnqueueLetter without the letter argument returns undef' );
122
121
123
delete $my_message->{message_transport_type};
122
delete $my_message->{message_transport_type};
124
$my_message->{letter} = {
123
$my_message->{letter} = {
Lines 129-141 $my_message->{letter} = { Link Here
129
    content_type => 'text/plain',
128
    content_type => 'text/plain',
130
};
129
};
131
130
132
$message_id = C4::Letters::EnqueueLetter($my_message);
131
my @message_ids = C4::Letters::EnqueueLetter($my_message);
133
is( $message_id, undef, 'EnqueueLetter without the message type argument argument returns undef' );
132
is( scalar @message_ids, 0, 'EnqueueLetter without the message type argument argument returns an empty list' );
134
133
135
$my_message->{message_transport_type} = 'sms';
134
$my_message->{message_transport_type} = 'sms';
136
$message_id = C4::Letters::EnqueueLetter($my_message);
135
@message_ids = C4::Letters::EnqueueLetter($my_message);
137
ok(defined $message_id && $message_id > 0, 'new message successfully queued');
136
is(scalar @message_ids, 1, 'new message successfully queued');
138
139
137
140
# GetQueuedMessages
138
# GetQueuedMessages
141
my $messages = C4::Letters::GetQueuedMessages();
139
my $messages = C4::Letters::GetQueuedMessages();
Lines 143-149 is( @$messages, 1, 'GetQueuedMessages without argument returns all the entries' Link Here
143
141
144
$messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
142
$messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
145
is( @$messages, 1, 'one message stored for the borrower' );
143
is( @$messages, 1, 'one message stored for the borrower' );
146
is( $messages->[0]->{message_id}, $message_id, 'EnqueueLetter returns the message id correctly' );
147
is( $messages->[0]->{borrowernumber}, $borrowernumber, 'EnqueueLetter stores the borrower number correctly' );
144
is( $messages->[0]->{borrowernumber}, $borrowernumber, 'EnqueueLetter stores the borrower number correctly' );
148
is( $messages->[0]->{subject}, $my_message->{letter}->{title}, 'EnqueueLetter stores the subject correctly' );
145
is( $messages->[0]->{subject}, $my_message->{letter}->{title}, 'EnqueueLetter stores the subject correctly' );
149
is( $messages->[0]->{content}, $my_message->{letter}->{content}, 'EnqueueLetter stores the content correctly' );
146
is( $messages->[0]->{content}, $my_message->{letter}->{content}, 'EnqueueLetter stores the content correctly' );
Lines 951-958 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
951
    is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
948
    is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
952
949
953
    my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
950
    my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
954
    $patron->set( { smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() } )->store;
951
    $patron->set( { smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id(), email => '', emailpro => '' } )->store;
955
    $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
952
    C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
956
953
957
    warning_like { C4::Letters::SendQueuedMessages(); }
954
    warning_like { C4::Letters::SendQueuedMessages(); }
958
        qr|Fake send_or_die|,
955
        qr|Fake send_or_die|,
Lines 975-981 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
975
972
976
    t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', 'override@example.com');
973
    t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', 'override@example.com');
977
974
978
    $message_id = C4::Letters::EnqueueLetter($my_message);
975
    C4::Letters::EnqueueLetter($my_message);
979
    warning_like { C4::Letters::SendQueuedMessages(); }
976
    warning_like { C4::Letters::SendQueuedMessages(); }
980
        qr|Fake send_or_die|,
977
        qr|Fake send_or_die|,
981
        "SendAlerts is using the mocked send_or_die routine (claimissues)";
978
        "SendAlerts is using the mocked send_or_die routine (claimissues)";
Lines 993-999 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
993
990
994
    $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
991
    $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
995
    $my_message->{to_address} = 'fixme@kidclamp.iswrong';
992
    $my_message->{to_address} = 'fixme@kidclamp.iswrong';
996
    $message_id = C4::Letters::EnqueueLetter($my_message);
993
    C4::Letters::EnqueueLetter($my_message);
997
994
998
    my $number_attempted = C4::Letters::SendQueuedMessages({
995
    my $number_attempted = C4::Letters::SendQueuedMessages({
999
        borrowernumber => -1, # -1 still triggers the borrowernumber condition
996
        borrowernumber => -1, # -1 still triggers the borrowernumber condition
Lines 1007-1012 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
1007
1004
1008
    my $sms_message_address = $schema->resultset('MessageQueue')->search({
1005
    my $sms_message_address = $schema->resultset('MessageQueue')->search({
1009
        borrowernumber => $borrowernumber,
1006
        borrowernumber => $borrowernumber,
1007
        message_transport_type => 'sms',
1010
        status => 'sent'
1008
        status => 'sent'
1011
    })->next()->to_address();
1009
    })->next()->to_address();
1012
    is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
1010
    is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
Lines 1391-1397 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1391
        'message_transport_type' => 'email',
1389
        'message_transport_type' => 'email',
1392
        'from_address'           => '@example.com' # invalid from_address
1390
        'from_address'           => '@example.com' # invalid from_address
1393
    };
1391
    };
1394
    my $message_id = C4::Letters::EnqueueLetter($my_message);
1392
    my ($message_id) = C4::Letters::EnqueueLetter($my_message);
1395
    $send_or_die_count = 0; # reset
1393
    $send_or_die_count = 0; # reset
1396
    my $processed = C4::Letters::SendQueuedMessages( { message_id => $message_id } );
1394
    my $processed = C4::Letters::SendQueuedMessages( { message_id => $message_id } );
1397
    is( $send_or_die_count, 0, 'Nothing sent when one message_id passed' );
1395
    is( $send_or_die_count, 0, 'Nothing sent when one message_id passed' );
Lines 1400-1406 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1400
    is( $message_1->{failure_code}, 'INVALID_EMAIL:from', 'Failure code set correctly for invalid email parameter');
1398
    is( $message_1->{failure_code}, 'INVALID_EMAIL:from', 'Failure code set correctly for invalid email parameter');
1401
1399
1402
    $my_message->{from_address} = 'root@example.org'; # valid from_address
1400
    $my_message->{from_address} = 'root@example.org'; # valid from_address
1403
    $message_id = C4::Letters::EnqueueLetter($my_message);
1401
    ($message_id) = C4::Letters::EnqueueLetter($my_message);
1404
    warning_like { C4::Letters::SendQueuedMessages( { message_id => $message_id } ); }
1402
    warning_like { C4::Letters::SendQueuedMessages( { message_id => $message_id } ); }
1405
        qr|Fake send_or_die|,
1403
        qr|Fake send_or_die|,
1406
        "SendQueuedMessages is using the mocked send_or_die routine";
1404
        "SendQueuedMessages is using the mocked send_or_die routine";
Lines 1410-1412 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1410
    is( $message_1->{status}, 'failed', 'Message 1 status is unchanged' );
1408
    is( $message_1->{status}, 'failed', 'Message 1 status is unchanged' );
1411
    is( $message_2->{status}, 'sent', 'Valid from_address => status sent' );
1409
    is( $message_2->{status}, 'sent', 'Valid from_address => status sent' );
1412
};
1410
};
1411
1412
subtest 'EnqueueLetter and EmailFieldPrimary' => sub {
1413
    plan tests => 19;
1414
1415
    my ( $email, $emailpro ) = ( 'email@example.org', 'emailpro@example.org' );
1416
    my $borrowernumber = Koha::Patron->new(
1417
        {   firstname      => 'Jane',
1418
            surname        => 'Smith',
1419
            categorycode   => $patron_category,
1420
            branchcode     => $library->{branchcode},
1421
            dateofbirth    => $date,
1422
            smsalertnumber => undef,
1423
            email          => $email,
1424
            emailpro       => $emailpro,
1425
        }
1426
    )->store->borrowernumber;
1427
1428
    my $my_message = {
1429
        borrowernumber         => $borrowernumber,
1430
        message_transport_type => 'email',
1431
        to_address             => 'to@example.com',
1432
        from_address           => 'from@example.com',
1433
        letter                 => {
1434
            content      => 'a message',
1435
            title        => 'message title',
1436
            metadata     => 'metadata',
1437
            code         => 'TEST_MESSAGE',
1438
            content_type => 'text/plain',
1439
        },
1440
    };
1441
1442
    $dbh->do(q|DELETE FROM message_queue|);
1443
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email' );
1444
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1445
    is( scalar @message_ids, 1, 'message successfully queued' );
1446
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1447
    is( scalar(@$messages),         1,                'The message has been queued for the expected patron' );
1448
    is( $messages->[0]{to_address}, 'to@example.com', 'EmailFieldPrimary=email, EnqueueLetter used the to_address given in parameter' );
1449
1450
    $dbh->do(q|DELETE FROM message_queue|);
1451
    delete $my_message->{to_address};
1452
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1453
    is( scalar @message_ids, 1, 'message successfully queued' );
1454
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1455
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1456
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=email, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1457
1458
    $dbh->do(q|DELETE FROM message_queue|);
1459
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1460
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1461
    is( scalar @message_ids, 1, 'message successfully queued' );
1462
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1463
    is( scalar(@$messages),         1,         'The message has been queued for the expected patron' );
1464
    is( $messages->[0]{to_address}, $emailpro, 'EmailFieldPrimary=emailpro, EnqueueLetter used the patron emailpro address if no to_address is given in parameter' );
1465
1466
    $dbh->do(q|DELETE FROM message_queue|);
1467
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1468
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1469
    is( scalar @message_ids, 1, 'message successfully queued' );
1470
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1471
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1472
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=OFF, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1473
1474
    $dbh->do(q|DELETE FROM message_queue|);
1475
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email,OFF,emailpro' );    # This is no consistent. OFF should be alone.
1476
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1477
    is( scalar @message_ids, 1, 'message successfully queued' );
1478
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1479
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1480
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=email,OFF,emailpro, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1481
1482
    $dbh->do(q|DELETE FROM message_queue|);
1483
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email,emailpro' );
1484
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1485
    is( scalar @message_ids, 2, 'messages successfully queued' );
1486
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1487
    is( scalar(@$messages),         2,         'The messages have been queued for the expected patron' );
1488
    is( $messages->[0]{to_address}, $email,    'EmailFieldPrimary=email,emailpro, EnqueueLetter used the patron email address for the first letter' );
1489
    is( $messages->[1]{to_address}, $emailpro, 'EmailFieldPrimary=email,emailpro, EnqueueLetter used the patron emailpro address for the second letter' );
1490
};
(-)a/t/db_dependent/Message.t (-3 / +3 lines)
Lines 52-58 my $letter = C4::Letters::GetPreparedLetter( Link Here
52
52
53
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
53
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
54
C4::Message->enqueue($letter, $patron, 'email');
54
C4::Message->enqueue($letter, $patron, 'email');
55
my $message = C4::Message->find_last_message($patron->unblessed, 'TEST_MESSAGE', 'email');
55
my ($message) = C4::Message->find_last_messages($patron->unblessed, 'TEST_MESSAGE', 'email');
56
like( $message->{metadata}, qr{heÄllo} );
56
like( $message->{metadata}, qr{heÄllo} );
57
is ($message->{to_address}, $patron->email, "To address set correctly for EmailFieldPrimary 'off'");
57
is ($message->{to_address}, $patron->email, "To address set correctly for EmailFieldPrimary 'off'");
58
58
Lines 71-75 like( $message->{metadata}, qr{hell❤️} ); Link Here
71
71
72
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
72
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
73
C4::Message->enqueue($letter, $patron, 'email');
73
C4::Message->enqueue($letter, $patron, 'email');
74
$message = C4::Message->find_last_message($patron->unblessed, 'TEST_MESSAGE', 'email');
74
($message) = C4::Message->find_last_messages($patron->unblessed, 'TEST_MESSAGE', 'email');
75
is ($patron->notice_email_address, $patron->emailpro, "To address set correctly for EmailFieldPrimary 'emailpro'");
75
is ($patron->notice_email_addresses, [$patron->emailpro], "To address set correctly for EmailFieldPrimary 'emailpro'");
(-)a/virtualshelves/sendshelf.pl (-2 / +1 lines)
Lines 61-67 if ($to_address) { Link Here
61
    my $comment = $query->param('comment');
61
    my $comment = $query->param('comment');
62
62
63
    my $patron     = Koha::Patrons->find($borrowernumber);
63
    my $patron     = Koha::Patrons->find($borrowernumber);
64
    my $user_email = $patron->notice_email_address;
64
    my ($user_email) = @{ $patron->notice_email_addresses };
65
    my $contents   = $shelf->get_contents;
65
    my $contents   = $shelf->get_contents;
66
    my @biblionumbers;
66
    my @biblionumbers;
67
    my $iso2709;
67
    my $iso2709;
68
- 

Return to bug 12802