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

(-)a/C4/Auth.pm (-1 / +1 lines)
Lines 1391-1397 sub checkauth { Link Here
1391
        $template->param(
1391
        $template->param(
1392
            TwoFA_prompt => 1,
1392
            TwoFA_prompt => 1,
1393
            invalid_otp_token => $invalid_otp_token,
1393
            invalid_otp_token => $invalid_otp_token,
1394
            notice_email_address => $patron->notice_email_address, # We could also pass logged_in_user if necessary
1394
            notice_email_addresses => $patron->notice_email_addresses, # We could also pass logged_in_user if necessary
1395
        );
1395
        );
1396
    }
1396
    }
1397
1397
(-)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 } );
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 } );
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 3742-3755 sub SendCirculationAlert { Link Here
3742
3742
3743
        C4::Context->dbh->do(q|LOCK TABLE message_queue READ|) unless $do_not_lock;
3743
        C4::Context->dbh->do(q|LOCK TABLE message_queue READ|) unless $do_not_lock;
3744
        C4::Context->dbh->do(q|LOCK TABLE message_queue WRITE|) unless $do_not_lock;
3744
        C4::Context->dbh->do(q|LOCK TABLE message_queue WRITE|) unless $do_not_lock;
3745
        my $message = C4::Message->find_last_message($borrower, $type, $mtt);
3745
        my @messages = C4::Message->find_last_messages($borrower, $type, $mtt);
3746
        unless ( $message ) {
3746
        unless ( @messages ) {
3747
            C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3747
            C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3748
            my $patron = Koha::Patrons->find($borrower->{borrowernumber});
3748
            my $patron = Koha::Patrons->find($borrower->{borrowernumber});
3749
            C4::Message->enqueue($letter, $patron, $mtt);
3749
            C4::Message->enqueue($letter, $patron, $mtt);
3750
        } else {
3750
        } else {
3751
            $message->append($letter);
3751
            foreach my $message (@messages) {
3752
            $message->update;
3752
                $message->append($letter);
3753
                $message->update;
3754
            }
3753
        }
3755
        }
3754
        C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3756
        C4::Context->dbh->do(q|UNLOCK TABLES|) unless $do_not_lock;
3755
    }
3757
    }
(-)a/C4/Letters.pm (-57 / +83 lines)
Lines 30-36 use C4::Log qw( logaction ); Link Here
30
use C4::SMS;
30
use C4::SMS;
31
use C4::Templates;
31
use C4::Templates;
32
use Koha::SMS::Providers;
32
use Koha::SMS::Providers;
33
33
use Koha::Database;
34
use Koha::Email;
34
use Koha::Email;
35
use Koha::Notice::Messages;
35
use Koha::Notice::Messages;
36
use Koha::Notice::Templates;
36
use Koha::Notice::Templates;
Lines 883-902 sub _parseletter { Link Here
883
883
884
=head2 EnqueueLetter
884
=head2 EnqueueLetter
885
885
886
  my $success = EnqueueLetter( { letter => $letter, 
886
    my @message_ids = EnqueueLetter({
887
        borrowernumber => '12', message_transport_type => 'email' } )
887
        letter => $letter,
888
        borrowernumber => '12',
889
        message_transport_type => 'email'
890
    });
888
891
889
Places a letter in the message_queue database table, which will
892
Places a letter in the message_queue database table, which will
890
eventually get processed (sent) by the process_message_queue.pl
893
eventually get processed (sent) by the process_message_queue.pl
891
cronjob when it calls SendQueuedMessages.
894
cronjob when it calls SendQueuedMessages.
892
895
893
Return message_id on success
896
return the list of message ids
894
897
895
Parameters
898
Parameters
896
* letter - required; A letter hashref as returned from GetPreparedLetter
899
* letter - required; A letter hashref as returned from GetPreparedLetter
897
* message_transport_type - required; One of the available mtts
900
* message_transport_type - required; One of the available mtts
898
* borrowernumber - optional if 'to_address' is passed; The borrowernumber of the patron we enqueuing the notice for
901
* borrowernumber - optional if 'to_address' is passed; The borrowernumber of the patron we enqueuing the notice for
899
* to_address - optional if 'borrowernumber' is passed; The destination email address for the notice (defaults to patron->notice_email_address)
902
* to_address - optional if 'borrowernumber' is passed; The destination email address for the notice (defaults to patron->notice_email_addresses)
900
* from_address - optional; The from address for the notice, defaults to patron->library->from_email_address
903
* from_address - optional; The from address for the notice, defaults to patron->library->from_email_address
901
* reply_address - optional; The reply address for the notice, defaults to patron->library->reply_to
904
* reply_address - optional; The reply address for the notice, defaults to patron->library->reply_to
902
905
Lines 906-912 sub EnqueueLetter { Link Here
906
    my $params = shift or return;
909
    my $params = shift or return;
907
910
908
    return unless exists $params->{'letter'};
911
    return unless exists $params->{'letter'};
909
#   return unless exists $params->{'borrowernumber'};
910
    return unless exists $params->{'message_transport_type'};
912
    return unless exists $params->{'message_transport_type'};
911
913
912
    my $content = $params->{letter}->{content};
914
    my $content = $params->{letter}->{content};
Lines 925-954 sub EnqueueLetter { Link Here
925
        );
927
        );
926
    }
928
    }
927
929
928
    my $dbh       = C4::Context->dbh();
930
    my @to_addresses;
929
    my $statement = << 'ENDSQL';
931
    if ( $params->{to_address} ) {
930
INSERT INTO message_queue
932
        @to_addresses = ( $params->{to_address} );
931
( letter_id, borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, reply_address, content_type, failure_code )
933
    } elsif ( $params->{borrowernumber} and $params->{message_transport_type} eq 'email' ) {
932
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, CAST(NOW() AS DATETIME), ?, ?, ?, ?, ? )
934
        my $patron = Koha::Patrons->find( $params->{borrowernumber} );
933
ENDSQL
935
        if ($patron) {
934
936
            @to_addresses = @{ $patron->notice_email_addresses };
935
    my $sth    = $dbh->prepare($statement);
937
        }
936
    my $result = $sth->execute(
938
    }
937
        $params->{letter}->{id} || undef,         # letter.id
939
938
        $params->{'borrowernumber'},              # borrowernumber
940
    my $from_address;
939
        $params->{'letter'}->{'title'},           # subject
941
    if ( $params->{from_address} ) {
940
        $params->{'letter'}->{'content'},         # content
942
        $from_address = $params->{from_address};
941
        $params->{'letter'}->{'metadata'} || '',  # metadata
943
    } elsif ( $params->{message_transport_type} eq 'email' ) {
942
        $params->{'letter'}->{'code'}     || '',  # letter_code
944
        if ( $params->{borrowernumber} ) {
943
        $params->{'message_transport_type'},      # message_transport_type
945
            my $rs = Koha::Database->schema->resultset('Borrower')->search( { borrowernumber => $params->{borrowernumber} }, { join => 'branchcode' } );
944
        'pending',                                # status
946
            $from_address = $rs->next->branchcode->branchemail;
945
        $params->{'to_address'},                  # to_address
947
        }
946
        $params->{'from_address'},                # from_address
948
947
        $params->{'reply_address'},               # reply_address
949
        $from_address ||= C4::Context->preference('KohaAdminEmailAddress');
948
        $params->{'letter'}->{'content-type'},    # content_type
950
    }
949
        $params->{'failure_code'}        || '',   # failure_code
951
950
    );
952
    my @message_ids;
951
    return $dbh->last_insert_id(undef,undef,'message_queue', undef);
953
954
    my $rs = Koha::Database->schema->resultset('MessageQueue');
955
    if ( $params->{message_transport_type} eq 'email' ) {
956
        for my $to_address (@to_addresses) {
957
            my $message = $rs->create(
958
                {   letter_id              => $params->{letter}->{id} || undef,
959
                    borrowernumber         => $params->{borrowernumber},
960
                    subject                => $params->{letter}->{title},
961
                    content                => $params->{letter}->{content},
962
                    metadata               => ( $params->{letter}->{metadata} || '' ),
963
                    letter_code            => ( $params->{letter}->{code}     || '' ),
964
                    message_transport_type => $params->{message_transport_type},
965
                    status                 => 'pending',
966
                    time_queued            => \'NOW()',
967
                    to_address             => $to_address,
968
                    from_address           => $from_address,
969
                    reply_address          => $params->{reply_address},
970
                    content_type           => $params->{letter}->{'content-type'},
971
                    failure_code           => $params->{failure_code} || '',
972
                }
973
            );
974
            push @message_ids, $message->id();
975
        }
976
    } else {
977
        my $message = $rs->create(
978
            {   letter_id              => $params->{letter}->{id} || undef,
979
                borrowernumber         => $params->{borrowernumber},
980
                subject                => $params->{letter}{title},
981
                content                => $params->{letter}{content},
982
                metadata               => ( $params->{letter}{metadata} || '' ),
983
                letter_code            => ( $params->{letter}{code}     || '' ),
984
                message_transport_type => $params->{message_transport_type},
985
                status                 => 'pending',
986
                time_queued            => \'NOW()',
987
                from_address           => $from_address,
988
                reply_address          => $params->{reply_address},
989
                content_type           => $params->{letter}{'content-type'},
990
                failure_code           => $params->{failure_code} || '',
991
            }
992
        );
993
        push @message_ids, $message->id();
994
    }
995
996
    return @message_ids;
952
}
997
}
953
998
954
=head2 SendQueuedMessages ([$hashref]) 
999
=head2 SendQueuedMessages ([$hashref]) 
Lines 1101-1131 Return is an arrayref of hashes, each has represents a message in the message qu Link Here
1101
sub GetQueuedMessages {
1146
sub GetQueuedMessages {
1102
    my $params = shift;
1147
    my $params = shift;
1103
1148
1104
    my $dbh = C4::Context->dbh();
1149
    my ( %cond, %attrs );
1105
    my $statement = << 'ENDSQL';
1106
SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, updated_on, failure_code
1107
FROM message_queue
1108
ENDSQL
1109
1110
    my @query_params;
1111
    my @whereclauses;
1112
    if ( exists $params->{'borrowernumber'} ) {
1113
        push @whereclauses, ' borrowernumber = ? ';
1114
        push @query_params, $params->{'borrowernumber'};
1115
    }
1116
1150
1117
    if ( @whereclauses ) {
1151
    $cond{borrowernumber} = $params->{borrowernumber} if $params->{borrowernumber};
1118
        $statement .= ' WHERE ' . join( 'AND', @whereclauses );
1119
    }
1120
1152
1121
    if ( defined $params->{'limit'} ) {
1153
    $attrs{rows} = $params->{limit} if $params->{limit};
1122
        $statement .= ' LIMIT ? ';
1123
        push @query_params, $params->{'limit'};
1124
    }
1125
1154
1126
    my $sth = $dbh->prepare( $statement );
1155
    my $rs = Koha::Database->schema->resultset('MessageQueue')->search( \%cond, \%attrs );
1127
    my $result = $sth->execute( @query_params );
1156
    $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
1128
    return $sth->fetchall_arrayref({});
1157
    return [ $rs->all ];
1129
}
1158
}
1130
1159
1131
=head2 GetMessageTransportTypes
1160
=head2 GetMessageTransportTypes
Lines 1189-1197 sub ResendMessage { Link Here
1189
            status => 'pending',
1218
            status => 'pending',
1190
        });
1219
        });
1191
        $rv = $rv > 0? 1: 0;
1220
        $rv = $rv > 0? 1: 0;
1192
        # Clear destination email address to force address update
1193
        _update_message_to_address( $message_id, undef ) if $rv &&
1194
            $message->{message_transport_type} eq 'email';
1195
    }
1221
    }
1196
    return $rv;
1222
    return $rv;
1197
}
1223
}
Lines 1334-1341 sub _send_message_by_email { Link Here
1334
            );
1360
            );
1335
            return;
1361
            return;
1336
        }
1362
        }
1337
        $to_address = $patron->notice_email_address;
1363
        my $to_addresses = $patron->notice_email_addresses;
1338
        unless ($to_address) {  
1364
        unless (@$to_addresses) {
1339
            # warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})";
1365
            # warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})";
1340
            # warning too verbose for this more common case?
1366
            # warning too verbose for this more common case?
1341
            _set_message_status(
1367
            _set_message_status(
(-)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 808-819 SELECT COUNT(*) FROM reserves WHERE biblionumber=? AND borrowernumber<>? Link Here
808
Takes an itemnumber and returns the status of the reserve placed on it.
808
Takes an itemnumber and returns the status of the reserve placed on it.
809
If several reserves exist, the reserve with the lower priority is given.
809
If several reserves exist, the reserve with the lower priority is given.
810
810
811
=cut
812
813
## FIXME: I don't think this does what it thinks it does.
811
## FIXME: I don't think this does what it thinks it does.
814
## It only ever checks the first reserve result, even though
812
## It only ever checks the first reserve result, even though
815
## multiple reserves for that bib can have the itemnumber set
813
## multiple reserves for that bib can have the itemnumber set
816
## the sub is only used once in the codebase.
814
## the sub is only used once in the codebase.
815
816
=cut
817
817
sub GetReserveStatus {
818
sub GetReserveStatus {
818
    my ($itemnumber) = @_;
819
    my ($itemnumber) = @_;
819
820
Lines 1863-1871 sub _koha_notify_reserve { Link Here
1863
1864
1864
    my $patron = Koha::Patrons->find( $borrowernumber );
1865
    my $patron = Koha::Patrons->find( $borrowernumber );
1865
1866
1866
    # Try to get the borrower's email address
1867
    my $to_address = $patron->notice_email_address;
1868
1869
    my $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( {
1867
    my $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( {
1870
            borrowernumber => $borrowernumber,
1868
            borrowernumber => $borrowernumber,
1871
            message_name => 'Hold_Filled'
1869
            message_name => 'Hold_Filled'
Lines 1908-1916 sub _koha_notify_reserve { Link Here
1908
        } );
1906
        } );
1909
    };
1907
    };
1910
1908
1909
    # Try to get the borrower's email addresses
1910
    my $to_addresses = $patron->notice_email_addresses;
1911
1911
    while ( my ( $mtt, $letter_code ) = each %{ $messagingprefs->{transports} } ) {
1912
    while ( my ( $mtt, $letter_code ) = each %{ $messagingprefs->{transports} } ) {
1912
        next if (
1913
        next if (
1913
               ( $mtt eq 'email' and not $to_address ) # No email address
1914
               ( $mtt eq 'email' and not @$to_addresses ) # No email address
1914
            or ( $mtt eq 'sms'   and not $patron->smsalertnumber ) # No SMS number
1915
            or ( $mtt eq 'sms'   and not $patron->smsalertnumber ) # No SMS number
1915
            or ( $mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') ) # Notice is handled by TalkingTech_itiva_outbound.pl
1916
            or ( $mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') ) # Notice is handled by TalkingTech_itiva_outbound.pl
1916
            or ( $mtt eq 'phone' and not $patron->phone ) # No phone number to call
1917
            or ( $mtt eq 'phone' and not $patron->phone ) # No phone number to call
(-)a/Koha/Patron.pm (-17 / +26 lines)
Lines 907-916 sub set_password { Link Here
907
    if ( C4::Context->preference('NotifyPasswordChange') ) {
907
    if ( C4::Context->preference('NotifyPasswordChange') ) {
908
        my $self_from_storage = $self->get_from_storage;
908
        my $self_from_storage = $self->get_from_storage;
909
        if ( !C4::Auth::checkpw_hash( $password, $self_from_storage->password ) ) {
909
        if ( !C4::Auth::checkpw_hash( $password, $self_from_storage->password ) ) {
910
            my $emailaddr = $self_from_storage->notice_email_address;
910
            my $emailaddrs = $self_from_storage->notice_email_addresses;
911
911
912
            # if we manage to find a valid email address, send notice
912
            # if we manage to find a valid email address, send notice
913
            if ($emailaddr) {
913
            if (@$emailaddrs) {
914
                my $letter = C4::Letters::GetPreparedLetter(
914
                my $letter = C4::Letters::GetPreparedLetter(
915
                    module      => 'members',
915
                    module      => 'members',
916
                    letter_code => 'PASSWORD_CHANGE',
916
                    letter_code => 'PASSWORD_CHANGE',
Lines 924-938 sub set_password { Link Here
924
                    want_librarian => 1,
924
                    want_librarian => 1,
925
                ) or return;
925
                ) or return;
926
926
927
                my $message_id = C4::Letters::EnqueueLetter(
927
                my @message_ids = C4::Letters::EnqueueLetter(
928
                    {
928
                    {
929
                        letter                 => $letter,
929
                        letter                 => $letter,
930
                        borrowernumber         => $self_from_storage->id,
930
                        borrowernumber         => $self_from_storage->id,
931
                        to_address             => $emailaddr,
932
                        message_transport_type => 'email'
931
                        message_transport_type => 'email'
933
                    }
932
                    }
934
                );
933
                );
935
                C4::Letters::SendQueuedMessages( { message_id => $message_id } );
934
                foreach my $message_id (@message_ids) {
935
                    C4::Letters::SendQueuedMessages( { message_id => $message_id } );
936
                }
936
            }
937
            }
937
        }
938
        }
938
    }
939
    }
Lines 1402-1426 sub return_claims { Link Here
1402
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1403
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1403
}
1404
}
1404
1405
1405
=head3 notice_email_address
1406
=head3 notice_email_addresses
1406
1407
1407
  my $email = $patron->notice_email_address;
1408
  my $emails = $patron->notice_email_addresses;
1408
1409
1409
Return the email address of patron used for notices.
1410
Return an arrayref containing the email addresses of patron used for notices.
1410
Returns the empty string if no email address.
1411
1411
1412
=cut
1412
=cut
1413
1413
1414
sub notice_email_address{
1414
sub notice_email_addresses {
1415
    my ( $self ) = @_;
1415
    my ( $self ) = @_;
1416
1416
1417
    my $which_address = C4::Context->preference("EmailFieldPrimary");
1417
    my $which_addresses = C4::Context->preference("EmailFieldPrimary");
1418
    # if syspref is set to 'first valid' (value == OFF), look up email address
1418
    # if syspref is set to 'first valid' (value == OFF), look up email address
1419
    if ( $which_address eq 'OFF' ) {
1419
    my @email_addresses;
1420
        return $self->first_valid_email_address;
1420
    for my $email_address_field (split /,/, $which_addresses) {
1421
        # if syspref is set to 'first valid' (value == OFF), look up email address
1422
        if ( $email_address_field eq 'OFF' ) {
1423
            return [ $self->first_valid_email_address ];
1424
        }
1425
1426
        my $email_address = $self->$email_address_field;
1427
        push @email_addresses, $email_address if $email_address;
1421
    }
1428
    }
1422
1429
1423
    return $self->$which_address || '';
1430
    return \@email_addresses;
1424
}
1431
}
1425
1432
1426
=head3 first_valid_email_address
1433
=head3 first_valid_email_address
Lines 2214-2220 sub queue_notice { Link Here
2214
    foreach my $mtt (@message_transports){
2221
    foreach my $mtt (@message_transports){
2215
        next if ($mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') );
2222
        next if ($mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') );
2216
        # Notice is handled by TalkingTech_itiva_outbound.pl
2223
        # Notice is handled by TalkingTech_itiva_outbound.pl
2217
        if (   ( $mtt eq 'email' and not $self->notice_email_address )
2224
        my $email_addresses = $self->notice_email_addresses;
2225
        if (   ( $mtt eq 'email' and not @$email_addresses )
2218
            or ( $mtt eq 'sms'   and not $self->smsalertnumber )
2226
            or ( $mtt eq 'sms'   and not $self->smsalertnumber )
2219
            or ( $mtt eq 'phone' and not $self->phone ) )
2227
            or ( $mtt eq 'phone' and not $self->phone ) )
2220
        {
2228
        {
Lines 2353-2369 sub notify_library_of_registration { Link Here
2353
                || C4::Context->preference('KohaAdminEmailAddress');
2361
                || C4::Context->preference('KohaAdminEmailAddress');
2354
        }
2362
        }
2355
2363
2356
        my $message_id = C4::Letters::EnqueueLetter(
2364
        my ($message_id) = C4::Letters::EnqueueLetter(
2357
            {
2365
            {
2358
                letter                 => $letter,
2366
                letter                 => $letter,
2359
                borrowernumber         => $self->borrowernumber,
2367
                borrowernumber         => $self->borrowernumber,
2360
                to_address             => $to_address,
2368
                to_address             => $to_address,
2361
                message_transport_type => 'email'
2369
                message_transport_type => 'email'
2362
            }
2370
            }
2363
        ) or warn "can't enqueue letter $letter";
2371
        );
2364
        if ( $message_id ) {
2372
        if ( $message_id ) {
2365
            return 1;
2373
            return 1;
2366
        }
2374
        }
2375
        warn "can't enqueue letter $letter";
2367
    }
2376
    }
2368
}
2377
}
2369
2378
(-)a/Koha/Patron/Password/Recovery.pm (-3 / +6 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 158-165 sub SendPasswordRecoveryEmail { Link Here
158
        }
158
        }
159
    );
159
    );
160
160
161
    my $num_letters_attempted =
161
    my $num_letters_attempted = 0;
162
      C4::Letters::SendQueuedMessages( { message_id => $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 448-457 sub import_patrons { Link Here
448
448
449
        # Send WELCOME welcome email is the user is new and we're set to send mail
449
        # Send WELCOME welcome email is the user is new and we're set to send mail
450
        if ($send_welcome && $is_new) {
450
        if ($send_welcome && $is_new) {
451
            my $emailaddr = $patron->notice_email_address;
451
            my $emailaddrs = $patron->notice_email_addresses;
452
452
453
            # if we manage to find a valid email address, send notice
453
            # if we manage to find a valid email address, send notice
454
            if ($emailaddr) {
454
            if (@$emailaddrs) {
455
                eval {
455
                eval {
456
                    my $letter = GetPreparedLetter(
456
                    my $letter = GetPreparedLetter(
457
                        module      => 'members',
457
                        module      => 'members',
Lines 465-475 sub import_patrons { Link Here
465
                        want_librarian => 1,
465
                        want_librarian => 1,
466
                    ) or return;
466
                    ) or return;
467
467
468
                    my $message_id = EnqueueLetter(
468
                    EnqueueLetter(
469
                        {
469
                        {
470
                            letter                 => $letter,
470
                            letter                 => $letter,
471
                            borrowernumber         => $patron->id,
471
                            borrowernumber         => $patron->id,
472
                            to_address             => $emailaddr,
473
                            message_transport_type => 'email'
472
                            message_transport_type => 'email'
474
                        }
473
                        }
475
                    );
474
                    );
Lines 482-488 sub import_patrons { Link Here
482
                        {
481
                        {
483
                            feedback     => 1,
482
                            feedback     => 1,
484
                            name         => 'welcome_sent',
483
                            name         => 'welcome_sent',
485
                            value        => $borrower{'surname'} . ' / ' . $borrowernumber . ' / ' . $emailaddr
484
                            value        => $borrower{'surname'} . ' / ' . $borrowernumber . ' / ' . join(', ', @$emailaddrs)
486
                        }
485
                        }
487
                    );
486
                    );
488
                }
487
                }
(-)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});
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 (-7 / +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(
134
            foreach my $acknowledgement_message_id (@acknowledgement_message_ids) {
135
                { message_id => $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-163 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(
162
                foreach my $message_id (@message_ids) {
160
                    { message_id => $message_id } );
163
                    C4::Letters::SendQueuedMessages(
164
                        { message_id => $message_id } );
165
                }
161
            }
166
            }
162
        }
167
        }
163
    }
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 213-219 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
213
('EmailAddressForPatronRegistrations', '', '', ' If you choose EmailAddressForPatronRegistrations you have to enter a valid email address: ', 'free'),
213
('EmailAddressForPatronRegistrations', '', '', ' If you choose EmailAddressForPatronRegistrations you have to enter a valid email address: ', 'free'),
214
('EmailAddressForSuggestions','','',' If you choose EmailAddressForSuggestions you have to enter a valid email address: ','free'),
214
('EmailAddressForSuggestions','','',' If you choose EmailAddressForSuggestions you have to enter a valid email address: ','free'),
215
('EmailFieldPrecedence','email|emailpro|B_email','','Ordered list of patron email fields to use when AutoEmailPrimaryAddress is set to first valid','multiple'),
215
('EmailFieldPrecedence','email|emailpro|B_email','','Ordered list of patron email fields to use when AutoEmailPrimaryAddress is set to first valid','multiple'),
216
('EmailFieldPrimary','OFF','email|emailpro|B_email|cardnumber|OFF','Defines the default email address field where patron email notices are sent.','Choice'),
216
('EmailFieldPrimary','OFF','email|emailpro|B_email|cardnumber|OFF','Defines the default email address field where patron email notices are sent.','multiple'),
217
('emailLibrarianWhenHoldIsPlaced','0',NULL,'If ON, emails the librarian whenever a hold is placed','YesNo'),
217
('emailLibrarianWhenHoldIsPlaced','0',NULL,'If ON, emails the librarian whenever a hold is placed','YesNo'),
218
('EmailOverduesNoEmail','1',NULL,'Send send overdues of patrons without email address to staff','YesNo'),
218
('EmailOverduesNoEmail','1',NULL,'Send send overdues of patrons without email address to staff','YesNo'),
219
('EmailPatronRegistrations', '0', '0|EmailAddressForPatronRegistrations|BranchEmailAddress|KohaAdminEmailAddress', 'Choose email address that new patron registrations will be sent to: ', 'Choice'),
219
('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 182-188 Patrons: Link Here
182
         - "Use the patron's"
182
         - "Use the patron's"
183
         - pref: EmailFieldPrimary
183
         - pref: EmailFieldPrimary
184
           default: "OFF"
184
           default: "OFF"
185
           choices:
185
           multiple:
186
               email: primary email
186
               email: primary email
187
               emailpro: secondary email
187
               emailpro: secondary email
188
               B_email: alternate email
188
               B_email: alternate email
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt (-1 / +1 lines)
Lines 226-232 Link Here
226
226
227
            $("#send_otp").on("click", function(e){
227
            $("#send_otp").on("click", function(e){
228
                e.preventDefault();
228
                e.preventDefault();
229
                [% UNLESS notice_email_address %]
229
                [% UNLESS notice_email_addresses.size > 0 %]
230
                    alert("Cannot send the notice, you don't have an email address defined.")
230
                    alert("Cannot send the notice, you don't have an email address defined.")
231
                [% ELSE %]
231
                [% ELSE %]
232
                $("#email_success").hide();
232
                $("#email_success").hide();
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt (-3 / +3 lines)
Lines 72-82 Link Here
72
                            [% reser.patron.surname | html %][%IF ( reser.patron.firstname ) %], [% reser.patron.firstname | html %][% END %]
72
                            [% reser.patron.surname | html %][%IF ( reser.patron.firstname ) %], [% reser.patron.firstname | html %][% END %]
73
                        </a>
73
                        </a>
74
                        [% IF ( reser.patron.phone ) %]<br />[% reser.patron.phone | html %][% END %]
74
                        [% IF ( reser.patron.phone ) %]<br />[% reser.patron.phone | html %][% END %]
75
                            [% IF ( reser.patron.notice_email_address ) %]
75
                            [% FOREACH notice_email_address IN reser.patron.notice_email_addresses %]
76
                                <br />
76
                                <br />
77
                                [% BLOCK subject %]Hold:[% END %]
77
                                [% BLOCK subject %]Hold:[% END %]
78
                                <a href="mailto:[% reser.patron.notice_email_address | uri %]?subject=[% INCLUDE subject %] [% reser.title | uri %]">
78
                                <a href="mailto:[% notice_email_address | uri %]?subject=[% INCLUDE subject %] [% reser.title | uri %]">
79
                                    [% reser.patron.notice_email_address | html %]
79
                                    [% notice_email_address | html %]
80
                                </a>
80
                                </a>
81
                            [% END %]
81
                            [% END %]
82
                        [% ELSIF ( reser.recall ) %]
82
                        [% 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-xs btn-default" onclick="loadEnrollmentForm([% c.id | html%])">
62
                            <button class="btn btn-xs btn-default" onclick="loadEnrollmentForm([% 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 426-434 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
426
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
426
        # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
427
        if ( $patron && C4::Context->preference("AutoEmailNewUser") ) {
427
        if ( $patron && C4::Context->preference("AutoEmailNewUser") ) {
428
            #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
428
            #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
429
            my $emailaddr = $patron->notice_email_address;
429
            my $emailaddrs = $patron->notice_email_addresses;
430
            # if we manage to find a valid email address, send notice 
430
            # if we manage to find a valid email address, send notice 
431
            if ($emailaddr) {
431
            if (@$emailaddrs) {
432
                eval {
432
                eval {
433
                    my $letter = GetPreparedLetter(
433
                    my $letter = GetPreparedLetter(
434
                        module      => 'members',
434
                        module      => 'members',
Lines 442-456 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
442
                        want_librarian => 1,
442
                        want_librarian => 1,
443
                    ) or return;
443
                    ) or return;
444
444
445
                    my $message_id = EnqueueLetter(
445
                    my @message_ids = EnqueueLetter(
446
                        {
446
                        {
447
                            letter                 => $letter,
447
                            letter                 => $letter,
448
                            borrowernumber         => $patron->id,
448
                            borrowernumber         => $patron->id,
449
                            to_address             => $emailaddr,
450
                            message_transport_type => 'email'
449
                            message_transport_type => 'email'
451
                        }
450
                        }
452
                    );
451
                    );
453
                    SendQueuedMessages({ message_id => $message_id });
452
                    foreach my $message_id (@message_ids) {
453
                        SendQueuedMessages({ message_id => $message_id });
454
                    }
454
                };
455
                };
455
                if ($@) {
456
                if ($@) {
456
                    $template->param( error_alert => $@ );
457
                    $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 604-610 END_SQL Link Here
604
604
605
                my $patron = Koha::Patrons->find( $borrowernumber );
605
                my $patron = Koha::Patrons->find( $borrowernumber );
606
                @emails_to_use = ();
606
                @emails_to_use = ();
607
                my $notice_email = $patron->notice_email_address;
608
                unless ($nomail) {
607
                unless ($nomail) {
609
                    if (@emails) {
608
                    if (@emails) {
610
                        foreach (@emails) {
609
                        foreach (@emails) {
Lines 612-618 END_SQL Link Here
612
                        }
611
                        }
613
                    }
612
                    }
614
                    else {
613
                    else {
615
                        push @emails_to_use, $notice_email if ($notice_email);
614
                        my $notice_emails = $patron->notice_email_addresses;
615
                        push @emails_to_use, @$notice_emails;
616
                    }
616
                    }
617
                }
617
                }
618
618
Lines 770-776 END_SQL Link Here
770
                              letternumber   => $i,
770
                              letternumber   => $i,
771
                              postcode       => $data->{'zipcode'},
771
                              postcode       => $data->{'zipcode'},
772
                              country        => $data->{'country'},
772
                              country        => $data->{'country'},
773
                              email          => $notice_email,
773
                              email          => ( scalar( @emails_to_use ) ? $emails_to_use[0] : undef ),
774
                              itemcount      => $itemcount,
774
                              itemcount      => $itemcount,
775
                              titles         => $titles,
775
                              titles         => $titles,
776
                              outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
776
                              outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
Lines 789-795 END_SQL Link Here
789
                                  city           => $data->{'city'},
789
                                  city           => $data->{'city'},
790
                                  postcode       => $data->{'zipcode'},
790
                                  postcode       => $data->{'zipcode'},
791
                                  country        => $data->{'country'},
791
                                  country        => $data->{'country'},
792
                                  email          => $notice_email,
792
                                  email          => ( scalar( @emails_to_use ) ? $emails_to_use[0] : undef ),
793
                                  itemcount      => $itemcount,
793
                                  itemcount      => $itemcount,
794
                                  titles         => $titles,
794
                                  titles         => $titles,
795
                                  outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
795
                                  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 202-217 if ( $action eq 'create' ) { Link Here
202
                },
202
                },
203
            );
203
            );
204
204
205
            my $message_id = C4::Letters::EnqueueLetter(
205
            my @message_ids = C4::Letters::EnqueueLetter(
206
                {
206
                {
207
                    borrowernumber         => $borrower{borrowernumber},
207
                    letter                 => $letter,
208
                    letter                 => $letter,
208
                    message_transport_type => 'email',
209
                    message_transport_type => 'email',
209
                    to_address             => $borrower{'email'},
210
                    from_address =>
211
                      C4::Context->preference('KohaAdminEmailAddress'),
212
                }
210
                }
213
            );
211
            );
214
            C4::Letters::SendQueuedMessages({ message_id => $message_id });
212
            for my $message_id (@message_ids) {
213
                C4::Letters::SendQueuedMessages({ message_id => $message_id });
214
            }
215
        }
215
        }
216
        else {
216
        else {
217
            $borrower{password}         ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode}));
217
            $borrower{password}         ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode}));
Lines 255-263 if ( $action eq 'create' ) { Link Here
255
                # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
255
                # If 'AutoEmailNewUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode.
256
                if ( C4::Context->preference("AutoEmailNewUser") ) {
256
                if ( C4::Context->preference("AutoEmailNewUser") ) {
257
                    #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
257
                    #look for defined primary email address, if blank - attempt to use borr.email and borr.emailpro instead
258
                    my $emailaddr = $patron->notice_email_address;
258
                    my $emailaddrs = $patron->notice_email_addresses;
259
                    # if we manage to find a valid email address, send notice
259
                    # if we manage to find a valid email address, send notice
260
                    if ($emailaddr) {
260
                    if (@$emailaddrs) {
261
                        eval {
261
                        eval {
262
                            my $letter = GetPreparedLetter(
262
                            my $letter = GetPreparedLetter(
263
                                module      => 'members',
263
                                module      => 'members',
Lines 271-285 if ( $action eq 'create' ) { Link Here
271
                                want_librarian => 1,
271
                                want_librarian => 1,
272
                            ) or return;
272
                            ) or return;
273
273
274
                            my $message_id = EnqueueLetter(
274
                            my @message_ids = EnqueueLetter(
275
                                {
275
                                {
276
                                    letter                 => $letter,
276
                                    letter                 => $letter,
277
                                    borrowernumber         => $patron->id,
277
                                    borrowernumber         => $patron->id,
278
                                    to_address             => $emailaddr,
279
                                    message_transport_type => 'email'
278
                                    message_transport_type => 'email'
280
                                }
279
                                }
281
                            );
280
                            );
282
                            SendQueuedMessages({ message_id => $message_id });
281
                            foreach my $message_id (@message_ids) {
282
                                SendQueuedMessages({ message_id => $message_id });
283
                            }
283
                        };
284
                        };
284
                    }
285
                    }
285
                }
286
                }
(-)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 });
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 } );
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 197-205 if ( $op =~ /save/i ) { Link Here
197
197
198
            if ( $notify ) {
198
            if ( $notify ) {
199
                my $patron = Koha::Patrons->find( $suggestion_only->{managedby} );
199
                my $patron = Koha::Patrons->find( $suggestion_only->{managedby} );
200
                my $email_address = $patron->notice_email_address;
200
                my $email_addresses = $patron->notice_email_addresses;
201
                if ($patron->notice_email_address) {
201
                if (@$email_addresses) {
202
203
                    my $letter = C4::Letters::GetPreparedLetter(
202
                    my $letter = C4::Letters::GetPreparedLetter(
204
                        module      => 'suggestions',
203
                        module      => 'suggestions',
205
                        letter_code => 'NOTIFY_MANAGER',
204
                        letter_code => 'NOTIFY_MANAGER',
(-)a/t/db_dependent/Koha/Patron.t (-3 / +3 lines)
Lines 1393-1409 subtest 'notify_library_of_registration()' => sub { Link Here
1393
    $schema->storage->txn_rollback;
1393
    $schema->storage->txn_rollback;
1394
};
1394
};
1395
1395
1396
subtest 'notice_email_address' => sub {
1396
subtest 'notice_email_addresses' => sub {
1397
    plan tests => 2;
1397
    plan tests => 2;
1398
1398
1399
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1399
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1400
1400
1401
    t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'email|emailpro' );
1401
    t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'email|emailpro' );
1402
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1402
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1403
    is ($patron->notice_email_address, $patron->email, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is off");
1403
    is_deeply ($patron->notice_email_addresses, [$patron->email], "Koha::Patron->notice_email_addresses returns correct value when EmailFieldPrimary is off");
1404
1404
1405
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1405
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1406
    is ($patron->notice_email_address, $patron->emailpro, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is emailpro");
1406
    is_deeply ($patron->notice_email_addresses, [$patron->emailpro], "Koha::Patron->notice_email_addresses returns correct value when EmailFieldPrimary is emailpro");
1407
1407
1408
    $patron->delete;
1408
    $patron->delete;
1409
};
1409
};
(-)a/t/db_dependent/Koha/Patrons.t (-1 / +1 lines)
Lines 1971-1977 subtest '->set_password' => sub { Link Here
1971
    t::lib::Mocks::mock_preference( 'NotifyPasswordChange', 1 );
1971
    t::lib::Mocks::mock_preference( 'NotifyPasswordChange', 1 );
1972
    $patron->set_password({ password => 'abcd   c' });
1972
    $patron->set_password({ password => 'abcd   c' });
1973
    my $queued_notices = Koha::Notice::Messages->search({ borrowernumber => $patron->borrowernumber });
1973
    my $queued_notices = Koha::Notice::Messages->search({ borrowernumber => $patron->borrowernumber });
1974
    is( $queued_notices->count, 1, "One notice queued when NotifyPasswordChange enabled" );
1974
    is( $queued_notices->count, scalar @{ $patron->notice_email_addresses }, "One notice queued for each notice email address when NotifyPasswordChange enabled" );
1975
    my $THE_notice = $queued_notices->next;
1975
    my $THE_notice = $queued_notices->next;
1976
    is( $THE_notice->status, 'failed', "The notice was handled immediately and failed on wrong email address."); #FIXME Mock sending mail
1976
    is( $THE_notice->status, 'failed', "The notice was handled immediately and failed on wrong email address."); #FIXME Mock sending mail
1977
    $schema->storage->txn_rollback;
1977
    $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 863-870 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
863
    is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
860
    is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
864
861
865
    my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
862
    my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
866
    $patron->set( { smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() } )->store;
863
    $patron->set( { smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id(), email => '', emailpro => '' } )->store;
867
    $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
864
    C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
868
865
869
    warning_like { C4::Letters::SendQueuedMessages(); }
866
    warning_like { C4::Letters::SendQueuedMessages(); }
870
        qr|Fake send_or_die|,
867
        qr|Fake send_or_die|,
Lines 887-893 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
887
884
888
    t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', 'override@example.com');
885
    t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', 'override@example.com');
889
886
890
    $message_id = C4::Letters::EnqueueLetter($my_message);
887
    C4::Letters::EnqueueLetter($my_message);
891
    warning_like { C4::Letters::SendQueuedMessages(); }
888
    warning_like { C4::Letters::SendQueuedMessages(); }
892
        qr|Fake send_or_die|,
889
        qr|Fake send_or_die|,
893
        "SendAlerts is using the mocked send_or_die routine (claimissues)";
890
        "SendAlerts is using the mocked send_or_die routine (claimissues)";
Lines 905-911 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
905
902
906
    $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
903
    $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
907
    $my_message->{to_address} = 'fixme@kidclamp.iswrong';
904
    $my_message->{to_address} = 'fixme@kidclamp.iswrong';
908
    $message_id = C4::Letters::EnqueueLetter($my_message);
905
    C4::Letters::EnqueueLetter($my_message);
909
906
910
    my $number_attempted = C4::Letters::SendQueuedMessages({
907
    my $number_attempted = C4::Letters::SendQueuedMessages({
911
        borrowernumber => -1, # -1 still triggers the borrowernumber condition
908
        borrowernumber => -1, # -1 still triggers the borrowernumber condition
Lines 919-924 subtest 'Test SMS handling in SendQueuedMessages' => sub { Link Here
919
916
920
    my $sms_message_address = $schema->resultset('MessageQueue')->search({
917
    my $sms_message_address = $schema->resultset('MessageQueue')->search({
921
        borrowernumber => $borrowernumber,
918
        borrowernumber => $borrowernumber,
919
        message_transport_type => 'sms',
922
        status => 'sent'
920
        status => 'sent'
923
    })->next()->to_address();
921
    })->next()->to_address();
924
    is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
922
    is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
Lines 1157-1163 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1157
        'message_transport_type' => 'email',
1155
        'message_transport_type' => 'email',
1158
        'from_address'           => '@example.com' # invalid from_address
1156
        'from_address'           => '@example.com' # invalid from_address
1159
    };
1157
    };
1160
    my $message_id = C4::Letters::EnqueueLetter($my_message);
1158
    my ($message_id) = C4::Letters::EnqueueLetter($my_message);
1161
    $send_or_die_count = 0; # reset
1159
    $send_or_die_count = 0; # reset
1162
    my $processed = C4::Letters::SendQueuedMessages( { message_id => $message_id } );
1160
    my $processed = C4::Letters::SendQueuedMessages( { message_id => $message_id } );
1163
    is( $send_or_die_count, 0, 'Nothing sent when one message_id passed' );
1161
    is( $send_or_die_count, 0, 'Nothing sent when one message_id passed' );
Lines 1166-1172 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1166
    is( $message_1->{failure_code}, 'INVALID_EMAIL:from', 'Failure code set correctly for invalid email parameter');
1164
    is( $message_1->{failure_code}, 'INVALID_EMAIL:from', 'Failure code set correctly for invalid email parameter');
1167
1165
1168
    $my_message->{from_address} = 'root@example.org'; # valid from_address
1166
    $my_message->{from_address} = 'root@example.org'; # valid from_address
1169
    $message_id = C4::Letters::EnqueueLetter($my_message);
1167
    ($message_id) = C4::Letters::EnqueueLetter($my_message);
1170
    warning_like { C4::Letters::SendQueuedMessages( { message_id => $message_id } ); }
1168
    warning_like { C4::Letters::SendQueuedMessages( { message_id => $message_id } ); }
1171
        qr|Fake send_or_die|,
1169
        qr|Fake send_or_die|,
1172
        "SendQueuedMessages is using the mocked send_or_die routine";
1170
        "SendQueuedMessages is using the mocked send_or_die routine";
Lines 1176-1178 subtest 'Test message_id parameter for SendQueuedMessages' => sub { Link Here
1176
    is( $message_1->{status}, 'failed', 'Message 1 status is unchanged' );
1174
    is( $message_1->{status}, 'failed', 'Message 1 status is unchanged' );
1177
    is( $message_2->{status}, 'sent', 'Valid from_address => status sent' );
1175
    is( $message_2->{status}, 'sent', 'Valid from_address => status sent' );
1178
};
1176
};
1177
1178
subtest 'EnqueueLetter and EmailFieldPrimary' => sub {
1179
    plan tests => 19;
1180
1181
    my ( $email, $emailpro ) = ( 'email@example.org', 'emailpro@example.org' );
1182
    my $borrowernumber = Koha::Patron->new(
1183
        {   firstname      => 'Jane',
1184
            surname        => 'Smith',
1185
            categorycode   => $patron_category,
1186
            branchcode     => $library->{branchcode},
1187
            dateofbirth    => $date,
1188
            smsalertnumber => undef,
1189
            email          => $email,
1190
            emailpro       => $emailpro,
1191
        }
1192
    )->store->borrowernumber;
1193
1194
    my $my_message = {
1195
        borrowernumber         => $borrowernumber,
1196
        message_transport_type => 'email',
1197
        to_address             => 'to@example.com',
1198
        from_address           => 'from@example.com',
1199
        letter                 => {
1200
            content      => 'a message',
1201
            title        => 'message title',
1202
            metadata     => 'metadata',
1203
            code         => 'TEST_MESSAGE',
1204
            content_type => 'text/plain',
1205
        },
1206
    };
1207
1208
    $dbh->do(q|DELETE FROM message_queue|);
1209
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email' );
1210
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1211
    is( scalar @message_ids, 1, 'message successfully queued' );
1212
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1213
    is( scalar(@$messages),         1,                'The message has been queued for the expected patron' );
1214
    is( $messages->[0]{to_address}, 'to@example.com', 'EmailFieldPrimary=email, EnqueueLetter used the to_address given in parameter' );
1215
1216
    $dbh->do(q|DELETE FROM message_queue|);
1217
    delete $my_message->{to_address};
1218
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1219
    is( scalar @message_ids, 1, 'message successfully queued' );
1220
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1221
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1222
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=email, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1223
1224
    $dbh->do(q|DELETE FROM message_queue|);
1225
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1226
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1227
    is( scalar @message_ids, 1, 'message successfully queued' );
1228
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1229
    is( scalar(@$messages),         1,         'The message has been queued for the expected patron' );
1230
    is( $messages->[0]{to_address}, $emailpro, 'EmailFieldPrimary=emailpro, EnqueueLetter used the patron emailpro address if no to_address is given in parameter' );
1231
1232
    $dbh->do(q|DELETE FROM message_queue|);
1233
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1234
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1235
    is( scalar @message_ids, 1, 'message successfully queued' );
1236
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1237
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1238
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=OFF, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1239
1240
    $dbh->do(q|DELETE FROM message_queue|);
1241
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email,OFF,emailpro' );    # This is no consistent. OFF should be alone.
1242
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1243
    is( scalar @message_ids, 1, 'message successfully queued' );
1244
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1245
    is( scalar(@$messages),         1,      'The message has been queued for the expected patron' );
1246
    is( $messages->[0]{to_address}, $email, 'EmailFieldPrimary=email,OFF,emailpro, EnqueueLetter used the patron email address if no to_address is given in parameter' );
1247
1248
    $dbh->do(q|DELETE FROM message_queue|);
1249
    t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'email,emailpro' );
1250
    @message_ids = C4::Letters::EnqueueLetter($my_message);
1251
    is( scalar @message_ids, 2, 'messages successfully queued' );
1252
    $messages = C4::Letters::GetQueuedMessages( { borrowernumber => $borrowernumber } );
1253
    is( scalar(@$messages),         2,         'The messages have been queued for the expected patron' );
1254
    is( $messages->[0]{to_address}, $email,    'EmailFieldPrimary=email,emailpro, EnqueueLetter used the patron email address for the first letter' );
1255
    is( $messages->[1]{to_address}, $emailpro, 'EmailFieldPrimary=email,emailpro, EnqueueLetter used the patron emailpro address for the second letter' );
1256
};
(-)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