Bug 12532: Send email to guarantee and guarantor

This patch allows guarantors to receive emails sended to their
guarentees. This patch is a rebase of the previous patches.
I took all the content of previous commit and put it in one commit.

TO TEST:

Before applying:
1) Search, or create, a patron with guarantor.
2) For both guarantors and guarantees:
   - Add an email address
   - Update the 'Patron messaging preferences' section so that an email is sent for item checkouts
3) Checkout an item. An email should be sent only to the guarantee.
4) Apply the patch.
5) Run updatedatabase.pl
6) Run prove t/db_dependent/Members.t and prove t/db_dependent/Letters.t
7) Enable 'RedirectGuaranteeEmail'
8) Run misc/cronjobs/process_message_queue.pl
9) Notice that the email should be sended to both the guarantee AND the
guarantor.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Hammat Wele 2023-04-26 15:02:02 +00:00 committed by Tomas Cohen Arazi
parent 101eabfd9d
commit dc629ea7b5
Signed by: tomascohen
GPG key ID: 0A272EA1B2F3C15F
8 changed files with 110 additions and 22 deletions

View file

@ -1319,9 +1319,10 @@ sub _send_message_by_email {
my $patron; my $patron;
my $to_address = $message->{'to_address'}; my $to_address = $message->{'to_address'};
unless ($to_address) { my $use_garantor = C4::Context->preference('RedirectGuaranteeEmail');
if($use_garantor eq 'yes' || !$to_address) {
$patron = Koha::Patrons->find( $message->{borrowernumber} ); $patron = Koha::Patrons->find( $message->{borrowernumber} );
unless ($patron) { unless ($patron or $to_address) {
warn "FAIL: No 'to_address' and INVALID borrowernumber ($message->{borrowernumber})"; warn "FAIL: No 'to_address' and INVALID borrowernumber ($message->{borrowernumber})";
_set_message_status( _set_message_status(
{ {
@ -1332,7 +1333,9 @@ sub _send_message_by_email {
); );
return; return;
} }
$to_address = $patron->notice_email_address; if ($patron) {
$to_address = $patron->notice_email_address;
}
unless ($to_address) { unless ($to_address) {
# warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})"; # warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})";
# warning too verbose for this more common case? # warning too verbose for this more common case?
@ -1470,6 +1473,10 @@ sub _send_message_by_email {
$smtp_transports->{ $smtp_server->id // 'default' } ||= $smtp_server->transport; $smtp_transports->{ $smtp_server->id // 'default' } ||= $smtp_server->transport;
my $smtp_transport = $smtp_transports->{ $smtp_server->id // 'default' }; my $smtp_transport = $smtp_transports->{ $smtp_server->id // 'default' };
_update_message_from_address($message->{'message_id'},$email->email->header('From') )
if !$message->{from_address}
|| $message->{from_address} ne $email->email->header('From');
try { try {
$email->send_or_die({ transport => $smtp_transport }); $email->send_or_die({ transport => $smtp_transport });

View file

@ -118,10 +118,14 @@ sub create {
$args->{to} = $params->{to}; $args->{to} = $params->{to};
} }
Koha::Exceptions::BadParameter->throw( my @emails = split(',', $args->{to});
error => "Invalid 'to' parameter: " . $args->{to}, foreach my $email (@emails) {
parameter => 'to' $email =~ s/ //g;
) unless Koha::Email->is_valid( $args->{to} ); # to is mandatory Koha::Exceptions::BadParameter->throw(
error => "Invalid 'to' parameter: ".$email,
parameter => 'to'
) unless Koha::Email->is_valid($email);
}
my $addresses = {}; my $addresses = {};
$addresses->{reply_to} = $params->{reply_to}; $addresses->{reply_to} = $params->{reply_to};

View file

@ -1581,14 +1581,35 @@ Returns the empty string if no email address.
sub notice_email_address{ sub notice_email_address{
my ( $self ) = @_; my ( $self ) = @_;
my $address;
my $guarantor_address;
my $which_address = C4::Context->preference("EmailFieldPrimary"); my $which_address = C4::Context->preference("EmailFieldPrimary");
# if syspref is set to 'first valid' (value == OFF), look up email address # if syspref is set to 'first valid' (value == OFF), look up email address
if ( $which_address eq 'OFF' ) { if ( $which_address eq 'OFF' ) {
return $self->first_valid_email_address; $address = $self->first_valid_email_address;
} else {
$address = $self->$which_address || '';
} }
return $self->$which_address || ''; my $use_guarantor = C4::Context->preference('RedirectGuaranteeEmail');
if ($use_guarantor) {
my @guarantors = map { $_->guarantors->as_list } $self->guarantor_relationships();
if (@guarantors) {
foreach my $guarantor (@guarantors) {
if ( $which_address eq 'OFF' ) {
$guarantor_address = $guarantor->first_valid_email_address;
} else {
$guarantor_address = $guarantor->$which_address || '';
}
if ($address){
$address .= ', ';
}
$address .= $guarantor_address if $guarantor_address;
}
}
}
return $address;
} }
=head3 first_valid_email_address =head3 first_valid_email_address

View file

@ -0,0 +1,14 @@
use Modern::Perl;
return {
bug_number => "12532",
description => "Add new system preference RedirectGuaranteeEmail",
up => sub {
my ($args) = @_;
my ($dbh, $out) = @$args{qw(dbh out)};
$dbh->do(q{INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('RedirectGuaranteeEmail', '0', 'Enable the ability to redirect guarantee email messages to guarantor.', NULL, 'YesNo') });
say $out "Added system preference 'RedirectGuaranteeEmail'";
},
};

View file

@ -603,6 +603,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
('RecallsMaxPickUpDelay','7',NULL,'Define the maximum time a recall can be awaiting pickup','Integer'), ('RecallsMaxPickUpDelay','7',NULL,'Define the maximum time a recall can be awaiting pickup','Integer'),
('RecordLocalUseOnReturn','0',NULL,'If ON, statistically record returns of unissued items as local use, instead of return','YesNo'), ('RecordLocalUseOnReturn','0',NULL,'If ON, statistically record returns of unissued items as local use, instead of return','YesNo'),
('Reference_NFL_Statuses','1|2',NULL,'Contains not for loan statuses considered as available for reference','Free'), ('Reference_NFL_Statuses','1|2',NULL,'Contains not for loan statuses considered as available for reference','Free'),
('RedirectGuaranteeEmail', '0', NULL, 'Enable the ability to redirect guarantee email messages to guarantor.', 'YesNo'),
('RefundLostOnReturnControl','CheckinLibrary','CheckinLibrary|ItemHomeBranch|ItemHoldingBranch','If a lost item is returned, choose which branch to pick rules for refunding.','Choice'), ('RefundLostOnReturnControl','CheckinLibrary','CheckinLibrary|ItemHomeBranch|ItemHoldingBranch','If a lost item is returned, choose which branch to pick rules for refunding.','Choice'),
('RenewAccruingItemWhenPaid','0','','If enabled, when the fines on an item accruing is paid off, attempt to renew that item. If the syspref "RenewalPeriodBase" is set to "due date", renewed items may still be overdue','YesNo'), ('RenewAccruingItemWhenPaid','0','','If enabled, when the fines on an item accruing is paid off, attempt to renew that item. If the syspref "RenewalPeriodBase" is set to "due date", renewed items may still be overdue','YesNo'),
('RenewAccruingItemInOpac','0','','If enabled, when the fines on an item accruing is paid off in the OPAC via a payment plugin, attempt to renew that item. If the syspref "RenewalPeriodBase" is set to "due date", renewed items may still be overdue','YesNo'), ('RenewAccruingItemInOpac','0','','If enabled, when the fines on an item accruing is paid off in the OPAC via a payment plugin, attempt to renew that item. If the syspref "RenewalPeriodBase" is set to "due date", renewed items may still be overdue','YesNo'),

View file

@ -359,6 +359,12 @@ Patrons:
1: Allow 1: Allow
0: "Don't allow" 0: "Don't allow"
- staff to set the ability for a patron's checkouts to be viewed by linked patrons in the OPAC. - staff to set the ability for a patron's checkouts to be viewed by linked patrons in the OPAC.
-
- pref: RedirectGuaranteeEmail
choices:
yes: Enable
no: Disable
- sending emails to both guarantees and their guarantor. This does not affect patrons without guarantors.
- -
- pref: AllowStaffToSetFinesVisibilityForGuarantor - pref: AllowStaffToSetFinesVisibilityForGuarantor
choices: choices:

View file

@ -894,6 +894,7 @@ subtest 'Test SMS handling in SendQueuedMessages' => sub {
t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' ); t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', ''); t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', '');
t::lib::Mocks::mock_preference('RedirectGuaranteeEmail', '0');
my $patron = Koha::Patrons->find($borrowernumber); my $patron = Koha::Patrons->find($borrowernumber);
$dbh->do(q| $dbh->do(q|
INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code) INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)

View file

@ -17,7 +17,7 @@
use Modern::Perl; use Modern::Perl;
use Test::More tests => 50; use Test::More tests => 57;
use Test::MockModule; use Test::MockModule;
use Test::Exception; use Test::Exception;
@ -101,21 +101,55 @@ ok ( $changedmember->{firstname} eq $CHANGED_FIRSTNAME &&
, "Member Changed") , "Member Changed")
or diag("Mismatching member details: ".Dumper($member, $changedmember)); or diag("Mismatching member details: ".Dumper($member, $changedmember));
# Add a new borrower # Test notice_email_address
# Add Guarantor for testing
my $GUARANTOR_EMAIL = "Robert\@email.com";
%data = ( %data = (
cardnumber => "123456789", cardnumber => "2997924548",
firstname => "Tomasito", firstname => "Robert",
surname => "None", surname => "Tables",
categorycode => $patron_category->{categorycode}, categorycode => $patron_category->{categorycode},
branchcode => $library2->{branchcode}, branchcode => $BRANCHCODE,
dateofbirth => '', dateofbirth => '',
debarred => '', dateexpiry => '9999-12-31',
dateexpiry => '', userid => 'bobbytables',
dateenrolled => '', email => $GUARANTOR_EMAIL
); );
my $borrowernumber = Koha::Patron->new( \%data )->store->borrowernumber;
$patron = Koha::Patrons->find( $borrowernumber ); $addmem=Koha::Patron->new(\%data)->store->borrowernumber;
my $borrower = $patron->unblessed; ok($addmem, "Koha::Patron->store()");
my $patron_guarantor = Koha::Patrons->find( { cardnumber => (\%data)->{'cardnumber'} } )
or BAIL_OUT("Cannot read member with card (\%data)->{'cardnumber'}");
my $member_guarantor = $patron_guarantor->unblessed;
my %data2 = (
guarantor_id => $member_guarantor->{borrowernumber},
guarantee_id => $member->{borrowernumber},
relationship => "father"
);
Koha::Patron::Relationship->new(\%data2)->store;
$member = Koha::Patrons->find( { cardnumber => $CARDNUMBER } );
t::lib::Mocks::mock_preference( 'RedirectGuaranteeEmail', '0' );
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
C4::Context->clear_syspref_cache();
my $notice_email = $member->notice_email_address;
is ($notice_email, $EMAIL, "notice_email_address returns correct value when EmailFieldPrimary is off");
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
C4::Context->clear_syspref_cache();
$notice_email = $member->notice_email_address;
is ($notice_email, $EMAILPRO, "notice_email_address returns correct value when EmailFieldPrimary is emailpro");
t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
t::lib::Mocks::mock_preference( 'RedirectGuaranteeEmail', '1' );
C4::Context->clear_syspref_cache();
$notice_email = $member->notice_email_address;
is ($notice_email, $EMAIL . ", " . $GUARANTOR_EMAIL, "notice_email_address returns correct value when RedirectGuaranteeEmail is enabled");
is( $borrower->{dateofbirth}, undef, 'Koha::Patron->store should undef dateofbirth if empty string is given'); is( $borrower->{dateofbirth}, undef, 'Koha::Patron->store should undef dateofbirth if empty string is given');
is( $borrower->{debarred}, undef, 'Koha::Patron->store should undef debarred if empty string is given'); is( $borrower->{debarred}, undef, 'Koha::Patron->store should undef debarred if empty string is given');
isnt( $borrower->{dateexpiry}, '0000-00-00', 'Koha::Patron->store should not set dateexpiry to 0000-00-00 if empty string is given'); isnt( $borrower->{dateexpiry}, '0000-00-00', 'Koha::Patron->store should not set dateexpiry to 0000-00-00 if empty string is given');