From b7f5434deede5e2fa064ff31712e72c5b46e3a89 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Mon, 28 Aug 2017 10:29:57 -0400 Subject: [PATCH] Bug 19191 - Add ability to email receipts for account payments and write-offs Some libraries are paperless and require all payment receipts to be emailed. Koha should give libraries the option to send email receipts if a patron has an email address. If a notice for the type of "credit" exists ( payment or writeoff ), then an email receipt will be sent. These notices only support Template Toolkit syntax. Test Plan: 1) Apply this patch and dependencies 2) Run updatedatabase.pl 3) Note two new notices exist in the notices editor, ACCOUNT_PAYMENT and ACCOUNT_WRITEOFF 4) Find or create a patron with an email address that owes some amount of money 5) Make a payment for one or more fees 6) Note a new email is queued for the patron 7) Make a writeoff for one or more fees 8) Note a new new email is queued for the patron Signed-off-by: Josef Moravec --- C4/Letters.pm | 21 +++++++----- Koha/Account.pm | 28 ++++++++++++++++ Koha/Account/Offset.pm | 28 ++++++++++++++++ installer/data/mysql/atomicupdate/bug_19191.sql | 3 ++ .../data/mysql/en/mandatory/sample_notices.sql | 5 +++ t/db_dependent/Accounts.t | 38 +++++++++++++++++++++- t/db_dependent/Letters/TemplateToolkit.t | 14 +++++++- 7 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_19191.sql diff --git a/C4/Letters.pm b/C4/Letters.pm index 3f23090..562423b 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -699,12 +699,13 @@ sub GetPreparedLetter { return; } + my $objects = $params{objects} || {}; my $tables = $params{tables} || {}; my $substitute = $params{substitute} || {}; my $loops = $params{loops} || {}; # loops is not supported for historical notices syntax my $repeat = $params{repeat}; - %$tables || %$substitute || $repeat || %$loops - or carp( "ERROR: nothing to substitute - both 'tables', 'loops' and 'substitute' are empty" ), + %$tables || %$substitute || $repeat || %$loops || %$objects + or carp( "ERROR: nothing to substitute - all of 'objects', 'tables', 'loops' and 'substitute' are empty" ), return; my $want_librarian = $params{want_librarian}; @@ -779,10 +780,11 @@ sub GetPreparedLetter { $letter->{content} = _process_tt( { - content => $letter->{content}, - tables => $tables, - loops => $loops, + content => $letter->{content}, + tables => $tables, + loops => $loops, substitute => $substitute, + objects => $objects, } ); @@ -1453,9 +1455,10 @@ sub _set_message_status { sub _process_tt { my ( $params ) = @_; - my $content = $params->{content}; - my $tables = $params->{tables}; - my $loops = $params->{loops}; + my $content = $params->{content}; + my $tables = $params->{tables}; + my $loops = $params->{loops}; + my $objects = $params->{objects}; my $substitute = $params->{substitute} || {}; my $use_template_cache = C4::Context->config('template_cache_dir') && defined $ENV{GATEWAY_INTERFACE}; @@ -1471,7 +1474,7 @@ sub _process_tt { } ) or die Template->error(); - my $tt_params = { %{ _get_tt_params( $tables ) }, %{ _get_tt_params( $loops, 'is_a_loop' ) }, %$substitute }; + my $tt_params = { %{ _get_tt_params( $tables ) }, %{ _get_tt_params( $loops, 'is_a_loop' ) }, %$substitute, %$objects }; $content = qq|[% USE KohaDates %]$content|; diff --git a/Koha/Account.pm b/Koha/Account.pm index ed1fd3c..4fb2eb4 100644 --- a/Koha/Account.pm +++ b/Koha/Account.pm @@ -25,6 +25,7 @@ use Data::Dumper; use C4::Log qw( logaction ); use C4::Stats qw( UpdateStats ); +use Koha::Patrons; use Koha::Account::Lines; use Koha::Account::Offsets; use Koha::DateUtils qw( dt_from_string ); @@ -77,6 +78,8 @@ sub pay { my $userenv = C4::Context->userenv; + my $patron = Koha::Patrons->find( $self->{patron_id} ); + # We should remove accountno, it is no longer needed my $last = Koha::Account::Lines->search( { @@ -257,6 +260,31 @@ sub pay { ); } + require C4::Letters; + if ( + my $letter = C4::Letters::GetPreparedLetter( + module => 'circulation', + letter_code => uc("ACCOUNT_$type"), + message_transport_type => 'email', + lang => Koha::Patrons->find( $self->{patron_id} )->lang, + objects => { + patron => scalar Koha::Patrons->find( $self->{patron_id} ), + library => scalar Koha::Libraries->find( $self->{library_id} ), + offsets => \@account_offsets, + credit => $payment, + }, + ) + ) + { + C4::Letters::EnqueueLetter( + { + letter => $letter, + borrowernumber => $self->{patron_id}, + message_transport_type => 'email', + } + ) or warn "can't enqueue letter $letter"; + } + return $payment->id; } diff --git a/Koha/Account/Offset.pm b/Koha/Account/Offset.pm index b411653..aaf67a9 100644 --- a/Koha/Account/Offset.pm +++ b/Koha/Account/Offset.pm @@ -35,6 +35,34 @@ Account offsets are used to track the changes in account lines =cut +=head3 debit + +Returns the fine or fee associated with this offset. + +=cut + +sub debit { + my ( $self ) = @_; + + $self->{_debit} ||= Koha::Account::Lines->find( $self->debit_id ); + + return $self->{_debit}; +} + +=head3 credit + +Returns the payment or writeoff associated with this offset. + +=cut + +sub credit { + my ( $self ) = @_; + + $self->{_credit} ||= Koha::Account::Lines->find( $self->credit_id ); + + return $self->{_credit}; +} + =head3 _type =cut diff --git a/installer/data/mysql/atomicupdate/bug_19191.sql b/installer/data/mysql/atomicupdate/bug_19191.sql new file mode 100644 index 0000000..be54bd1 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_19191.sql @@ -0,0 +1,3 @@ +INSERT INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`, `lang`) VALUES +('circulation', 'ACCOUNT_PAYMENT', '', 'Account Payment', 0, 'Account Payment', '[%- USE Price -%]\r\nA payment of [% credit.amount * -1 | $Price %] has been applied to your account.\r\n\r\nThis payment affected the following fees:\r\n[%- FOREACH o IN offsets %]\r\nDescription: [% o.debit.description %]\r\nAmount paid: [% o.amount * -1 | $Price %]\r\nAmount remaining: [% o.debit.amountoutstanding | $Price %]\r\n[% END %]', 'email', 'default'), +('circulation', 'ACCOUNT_WRITEOFF', '', 'Account Writeoff', 0, 'Account Writeoff', '[%- USE Price -%]\r\nAn account writeoff of [% credit.amount * -1 | $Price %] has been applied to your account.\r\n\r\nThis writeoff affected the following fees:\r\n[%- FOREACH o IN offsets %]\r\nDescription: [% o.debit.description %]\r\nAmount paid: [% o.amount * -1 | $Price %]\r\nAmount remaining: [% o.debit.amountoutstanding | $Price %]\r\n[% END %]', 'email', 'default'); diff --git a/installer/data/mysql/en/mandatory/sample_notices.sql b/installer/data/mysql/en/mandatory/sample_notices.sql index 7a5c4da..4665580 100644 --- a/installer/data/mysql/en/mandatory/sample_notices.sql +++ b/installer/data/mysql/en/mandatory/sample_notices.sql @@ -174,3 +174,8 @@ INSERT INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title` ('circulation', 'AR_PENDING', '', 'Article request - open', 0, 'Article request received', 'Dear <> <> (<>)\r\n\r\nWe have received your request for an article from <> (<>).\r\n\r\nArticle requested:\r\nTitle: <>\r\nAuthor: <>\r\nVolume: <>\r\nIssue: <>\r\nDate: <>\r\nPages: <>\r\nChapters: <>\r\nNotes: <>\r\n\r\n\r\nThank you!', 'email'), ('circulation', 'AR_SLIP', '', 'Article request - print slip', 0, 'Article request', 'Article request:\r\n\r\n<> <> (<>),\r\n\r\nTitle: <>\r\nBarcode: <>\r\n\r\nArticle requested:\r\nTitle: <>\r\nAuthor: <>\r\nVolume: <>\r\nIssue: <>\r\nDate: <>\r\nPages: <>\r\nChapters: <>\r\nNotes: <>\r\n', 'print'), ('circulation', 'AR_PROCESSING', '', 'Article request - processing', 0, 'Article request processing', 'Dear <> <> (<>),\r\n\r\nWe are now processing your request for an article from <> (<>).\r\n\r\nArticle requested:\r\nTitle: <>\r\nAuthor: <>\r\nVolume: <>\r\nIssue: <>\r\nDate: <>\r\nPages: <>\r\nChapters: <>\r\nNotes: <>\r\n\r\nThank you!', 'email'); + +INSERT INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`, `lang`) + VALUES + ('circulation', 'ACCOUNT_PAYMENT', '', 'Account Payment', 0, 'Account Payment', '[%- USE Price -%]\r\nA payment of [% credit.amount * -1 | $Price %] has been applied to your account.\r\n\r\nThis payment affected the following fees:\r\n[%- FOREACH o IN offsets %]\r\nDescription: [% o.debit.description %]\r\nAmount paid: [% o.amount * -1 | $Price %]\r\nAmount remaining: [% o.debit.amountoutstanding | $Price %]\r\n[% END %]', 'email', 'default'), + ('circulation', 'ACCOUNT_WRITEOFF', '', 'Account Writeoff', 0, 'Account Writeoff', '[%- USE Price -%]\r\nAn account writeoff of [% credit.amount * -1 | $Price %] has been applied to your account.\r\n\r\nThis writeoff affected the following fees:\r\n[%- FOREACH o IN offsets %]\r\nDescription: [% o.debit.description %]\r\nAmount paid: [% o.amount * -1 | $Price %]\r\nAmount remaining: [% o.debit.amountoutstanding | $Price %]\r\n[% END %]', 'email', 'default'); diff --git a/t/db_dependent/Accounts.t b/t/db_dependent/Accounts.t index 51c094a..107cc28 100644 --- a/t/db_dependent/Accounts.t +++ b/t/db_dependent/Accounts.t @@ -18,7 +18,7 @@ use Modern::Perl; -use Test::More tests => 23; +use Test::More tests => 24; use Test::MockModule; use Test::Warn; @@ -627,4 +627,40 @@ subtest "Koha::Account::chargelostitem tests" => sub { is( $procfee->amount, "2.040000", "Processing fee if processing fee"); }; +subtest "Koha::Account::Offset tests" => sub { + + plan tests => 2; + + Koha::Account::Lines->delete(); + Koha::Patrons->delete(); + + # Create a borrower + my $categorycode = $builder->build({ source => 'Category' })->{ categorycode }; + my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode }; + + my $borrower = Koha::Patron->new( { + cardnumber => 'chelseahall', + surname => 'Hall', + firstname => 'Chelsea', + } ); + $borrower->categorycode( $categorycode ); + $borrower->branchcode( $branchcode ); + $borrower->store; + + my $account = Koha::Account->new({ patron_id => $borrower->id }); + + my $line = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amountoutstanding => 27 })->store(); + + my $id = $account->pay( + { + amount => 13, + } + ); + + my $offset = Koha::Account::Offsets->find( { credit_id => $id } ); + + is( $offset->credit->id, $id, 'Got correct credit for account offset' ); + is( $offset->debit->id, $line->id, 'Got correct debit for account offset' ); +}; + 1; diff --git a/t/db_dependent/Letters/TemplateToolkit.t b/t/db_dependent/Letters/TemplateToolkit.t index 611b936..f237976 100644 --- a/t/db_dependent/Letters/TemplateToolkit.t +++ b/t/db_dependent/Letters/TemplateToolkit.t @@ -19,7 +19,7 @@ # along with Koha; if not, see . use Modern::Perl; -use Test::More tests => 17; +use Test::More tests => 18; use Test::Warn; use MARC::Record; @@ -42,6 +42,7 @@ use Koha::Serial; use Koha::Subscription; use Koha::Suggestion; use Koha::Checkout; +use Koha::Patrons; use Koha::Notice::Messages; use Koha::Notice::Templates; use Koha::Patron::Modification; @@ -134,6 +135,17 @@ $prepared_letter = GetPreparedLetter( ); is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with arrayref' ); +$prepared_letter = GetPreparedLetter( + ( + module => 'test', + letter_code => 'TEST_PATRON', + objects => { + borrower => scalar Koha::Patrons->find( $patron->{borrowernumber} ), + }, + ) +); +is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly as object' ); + $sth->execute( "TEST_BIBLIO", "[% biblio.id %]" ); $prepared_letter = GetPreparedLetter( ( -- 2.1.4