From 9a448eb78b6fe58187ef8a80d79c5fb4c01e2384 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 14 Aug 2020 17:16:04 +0100 Subject: [PATCH] Bug 18501: (QA follow-up) Migrate and update unit tests This patch moves the _FixAccountForLostAndFound tests from Circulation.t to Koha/Items.t and updates then to call an item store as aposed to the now removed _FixAccountForLostAndFound method. Signed-off-by: Martin Renvoize Signed-off-by: Jonathan Druart --- t/db_dependent/Circulation.t | 435 +---------------------- t/db_dependent/Koha/Items.t | 650 ++++++++++++++++++++++++++++++++++- 2 files changed, 641 insertions(+), 444 deletions(-) diff --git a/t/db_dependent/Circulation.t b/t/db_dependent/Circulation.t index 4bdae841c7..1dbf754d91 100755 --- a/t/db_dependent/Circulation.t +++ b/t/db_dependent/Circulation.t @@ -18,7 +18,7 @@ use Modern::Perl; use utf8; -use Test::More tests => 50; +use Test::More tests => 48; use Test::Exception; use Test::MockModule; use Test::Deep qw( cmp_deeply ); @@ -2669,397 +2669,6 @@ subtest 'AddReturn | is_overdue' => sub { }; }; -subtest '_FixAccountForLostAndFound' => sub { - - plan tests => 5; - - t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 ); - t::lib::Mocks::mock_preference( 'WhenLostForgiveFine', 0 ); - - my $processfee_amount = 20; - my $replacement_amount = 99.00; - my $item_type = $builder->build_object( - { class => 'Koha::ItemTypes', - value => { - notforloan => undef, - rentalcharge => 0, - defaultreplacecost => undef, - processfee => $processfee_amount, - rentalcharge_daily => 0, - } - } - ); - my $library = $builder->build_object( { class => 'Koha::Libraries' } ); - - my $biblio = $builder->build_sample_biblio({ author => 'Hall, Daria' }); - - subtest 'Full write-off tests' => sub { - - plan tests => 12; - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - my $manager = $builder->build_object({ class => "Koha::Patrons" }); - t::lib::Mocks::mock_userenv({ patron => $manager,branchcode => $manager->branchcode }); - - my $item = $builder->build_sample_item( - { - biblionumber => $biblio->biblionumber, - library => $library->branchcode, - replacementprice => $replacement_amount, - itype => $item_type->itemtype, - } - ); - - AddIssue( $patron->unblessed, $item->barcode ); - - # Simulate item marked as lost - $item->itemlost(3)->store; - LostItem( $item->itemnumber, 1 ); - - my $processing_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } ); - is( $processing_fee_lines->count, 1, 'Only one processing fee produced' ); - my $processing_fee_line = $processing_fee_lines->next; - is( $processing_fee_line->amount + 0, - $processfee_amount, 'The right PROCESSING amount is generated' ); - is( $processing_fee_line->amountoutstanding + 0, - $processfee_amount, 'The right PROCESSING amountoutstanding is generated' ); - - my $lost_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } ); - is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); - my $lost_fee_line = $lost_fee_lines->next; - is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' ); - is( $lost_fee_line->amountoutstanding + 0, - $replacement_amount, 'The right LOST amountoutstanding is generated' ); - is( $lost_fee_line->status, - undef, 'The LOST status was not set' ); - - my $account = $patron->account; - my $debts = $account->outstanding_debits; - - # Write off the debt - my $credit = $account->add_credit( - { amount => $account->balance, - type => 'WRITEOFF', - interface => 'test', - } - ); - $credit->apply( { debits => [ $debts->as_list ], offset_type => 'Writeoff' } ); - - my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - is( $credit_return_id, undef, 'No LOST_FOUND account line added' ); - - $lost_fee_line->discard_changes; # reload from DB - is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' ); - is( $lost_fee_line->debit_type_code, - 'LOST', 'Lost fee now still has account type of LOST' ); - is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND"); - - is( $patron->account->balance, -0, 'The patron balance is 0, everything was written off' ); - }; - - subtest 'Full payment tests' => sub { - - plan tests => 13; - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - - my $item = $builder->build_sample_item( - { - biblionumber => $biblio->biblionumber, - library => $library->branchcode, - replacementprice => $replacement_amount, - itype => $item_type->itemtype - } - ); - - AddIssue( $patron->unblessed, $item->barcode ); - - # Simulate item marked as lost - $item->itemlost(1)->store; - LostItem( $item->itemnumber, 1 ); - - my $processing_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } ); - is( $processing_fee_lines->count, 1, 'Only one processing fee produced' ); - my $processing_fee_line = $processing_fee_lines->next; - is( $processing_fee_line->amount + 0, - $processfee_amount, 'The right PROCESSING amount is generated' ); - is( $processing_fee_line->amountoutstanding + 0, - $processfee_amount, 'The right PROCESSING amountoutstanding is generated' ); - - my $lost_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } ); - is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); - my $lost_fee_line = $lost_fee_lines->next; - is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' ); - is( $lost_fee_line->amountoutstanding + 0, - $replacement_amount, 'The right LOST amountountstanding is generated' ); - - my $account = $patron->account; - my $debts = $account->outstanding_debits; - - # Write off the debt - my $credit = $account->add_credit( - { amount => $account->balance, - type => 'PAYMENT', - interface => 'test', - } - ); - $credit->apply( { debits => [ $debts->as_list ], offset_type => 'Payment' } ); - - my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - my $credit_return = Koha::Account::Lines->find($credit_return_id); - - is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' ); - is( $credit_return->amount + 0, - -99.00, 'The account line of type LOST_FOUND has an amount of -99' ); - is( $credit_return->amountoutstanding + 0, - -99.00, 'The account line of type LOST_FOUND has an amountoutstanding of -99' ); - - $lost_fee_line->discard_changes; - is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' ); - is( $lost_fee_line->debit_type_code, - 'LOST', 'Lost fee now still has account type of LOST' ); - is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND"); - - is( $patron->account->balance, - -99, 'The patron balance is -99, a credit that equals the lost fee payment' ); - }; - - subtest 'Test without payment or write off' => sub { - - plan tests => 13; - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - - my $item = $builder->build_sample_item( - { - biblionumber => $biblio->biblionumber, - library => $library->branchcode, - replacementprice => 23.00, - replacementprice => $replacement_amount, - itype => $item_type->itemtype - } - ); - - AddIssue( $patron->unblessed, $item->barcode ); - - # Simulate item marked as lost - $item->itemlost(3)->store; - LostItem( $item->itemnumber, 1 ); - - my $processing_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } ); - is( $processing_fee_lines->count, 1, 'Only one processing fee produced' ); - my $processing_fee_line = $processing_fee_lines->next; - is( $processing_fee_line->amount + 0, - $processfee_amount, 'The right PROCESSING amount is generated' ); - is( $processing_fee_line->amountoutstanding + 0, - $processfee_amount, 'The right PROCESSING amountoutstanding is generated' ); - - my $lost_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } ); - is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); - my $lost_fee_line = $lost_fee_lines->next; - is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' ); - is( $lost_fee_line->amountoutstanding + 0, - $replacement_amount, 'The right LOST amountountstanding is generated' ); - - my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - my $credit_return = Koha::Account::Lines->find($credit_return_id); - - is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' ); - is( $credit_return->amount + 0, -99.00, 'The account line of type LOST_FOUND has an amount of -99' ); - is( $credit_return->amountoutstanding + 0, 0, 'The account line of type LOST_FOUND has an amountoutstanding of 0' ); - - $lost_fee_line->discard_changes; - is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' ); - is( $lost_fee_line->debit_type_code, - 'LOST', 'Lost fee now still has account type of LOST' ); - is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND"); - - is( $patron->account->balance, 20, 'The patron balance is 20, still owes the processing fee' ); - }; - - subtest 'Test with partial payement and write off, and remaining debt' => sub { - - plan tests => 16; - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - my $item = $builder->build_sample_item( - { - biblionumber => $biblio->biblionumber, - library => $library->branchcode, - replacementprice => $replacement_amount, - itype => $item_type->itemtype - } - ); - - AddIssue( $patron->unblessed, $item->barcode ); - - # Simulate item marked as lost - $item->itemlost(1)->store; - LostItem( $item->itemnumber, 1 ); - - my $processing_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } ); - is( $processing_fee_lines->count, 1, 'Only one processing fee produced' ); - my $processing_fee_line = $processing_fee_lines->next; - is( $processing_fee_line->amount + 0, - $processfee_amount, 'The right PROCESSING amount is generated' ); - is( $processing_fee_line->amountoutstanding + 0, - $processfee_amount, 'The right PROCESSING amountoutstanding is generated' ); - - my $lost_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } ); - is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); - my $lost_fee_line = $lost_fee_lines->next; - is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' ); - is( $lost_fee_line->amountoutstanding + 0, - $replacement_amount, 'The right LOST amountountstanding is generated' ); - - my $account = $patron->account; - is( $account->balance, $processfee_amount + $replacement_amount, 'Balance is PROCESSING + L' ); - - # Partially pay fee - my $payment_amount = 27; - my $payment = $account->add_credit( - { amount => $payment_amount, - type => 'PAYMENT', - interface => 'test', - } - ); - - $payment->apply( { debits => [ $lost_fee_line ], offset_type => 'Payment' } ); - - # Partially write off fee - my $write_off_amount = 25; - my $write_off = $account->add_credit( - { amount => $write_off_amount, - type => 'WRITEOFF', - interface => 'test', - } - ); - $write_off->apply( { debits => [ $lost_fee_line ], offset_type => 'Writeoff' } ); - - is( $account->balance, - $processfee_amount + $replacement_amount - $payment_amount - $write_off_amount, - 'Payment and write off applied' - ); - - # Store the amountoutstanding value - $lost_fee_line->discard_changes; - my $outstanding = $lost_fee_line->amountoutstanding; - - my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - my $credit_return = Koha::Account::Lines->find($credit_return_id); - - is( $account->balance, $processfee_amount - $payment_amount, 'Balance is PROCESSING - PAYMENT (LOST_FOUND)' ); - - $lost_fee_line->discard_changes; - is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' ); - is( $lost_fee_line->debit_type_code, - 'LOST', 'Lost fee now still has account type of LOST' ); - is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND"); - - is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' ); - is( $credit_return->amount + 0, - ($payment_amount + $outstanding ) * -1, - 'The account line of type LOST_FOUND has an amount equal to the payment + outstanding' - ); - is( $credit_return->amountoutstanding + 0, - $payment_amount * -1, - 'The account line of type LOST_FOUND has an amountoutstanding equal to the payment' - ); - - is( $account->balance, - $processfee_amount - $payment_amount, - 'The patron balance is the difference between the PROCESSING and the credit' - ); - }; - - subtest 'Partial payement, existing debits and AccountAutoReconcile' => sub { - - plan tests => 8; - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - my $barcode = 'KD123456793'; - my $replacement_amount = 100; - my $processfee_amount = 20; - - my $item_type = $builder->build_object( - { class => 'Koha::ItemTypes', - value => { - notforloan => undef, - rentalcharge => 0, - defaultreplacecost => undef, - processfee => 0, - rentalcharge_daily => 0, - } - } - ); - my $item = Koha::Item->new( - { - biblionumber => $biblio->biblionumber, - homebranch => $library->branchcode, - holdingbranch => $library->branchcode, - barcode => $barcode, - replacementprice => $replacement_amount, - itype => $item_type->itemtype - }, - )->store; - - AddIssue( $patron->unblessed, $barcode ); - - # Simulate item marked as lost - $item->itemlost(1)->store; - LostItem( $item->itemnumber, 1 ); - - my $lost_fee_lines = Koha::Account::Lines->search( - { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } ); - is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); - my $lost_fee_line = $lost_fee_lines->next; - is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' ); - is( $lost_fee_line->amountoutstanding + 0, - $replacement_amount, 'The right LOST amountountstanding is generated' ); - - my $account = $patron->account; - is( $account->balance, $replacement_amount, 'Balance is L' ); - - # Partially pay fee - my $payment_amount = 27; - my $payment = $account->add_credit( - { amount => $payment_amount, - type => 'PAYMENT', - interface => 'test', - } - ); - $payment->apply({ debits => [ $lost_fee_line ], offset_type => 'Payment' }); - - is( $account->balance, - $replacement_amount - $payment_amount, - 'Payment applied' - ); - - my $manual_debit_amount = 80; - $account->add_debit( { amount => $manual_debit_amount, type => 'OVERDUE', interface =>'test' } ); - - is( $account->balance, $manual_debit_amount + $replacement_amount - $payment_amount, 'Manual debit applied' ); - - t::lib::Mocks::mock_preference( 'AccountAutoReconcile', 1 ); - - my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - my $credit_return = Koha::Account::Lines->find($credit_return_id); - - is( $account->balance, $manual_debit_amount - $payment_amount, 'Balance is PROCESSING - payment (LOST_FOUND)' ); - - my $manual_debit = Koha::Account::Lines->search({ borrowernumber => $patron->id, debit_type_code => 'OVERDUE', status => 'UNRETURNED' })->next; - is( $manual_debit->amountoutstanding + 0, $manual_debit_amount - $payment_amount, 'reconcile_balance was called' ); - }; -}; - subtest '_FixOverduesOnReturn' => sub { plan tests => 14; @@ -3145,48 +2754,6 @@ subtest '_FixOverduesOnReturn' => sub { is( $accountline->status, 'RETURNED', 'Passed status has been used to set as RETURNED )'); }; -subtest '_FixAccountForLostAndFound returns undef if patron is deleted' => sub { - plan tests => 1; - - my $manager = $builder->build_object({ class => "Koha::Patrons" }); - t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $manager->branchcode }); - - my $biblio = $builder->build_sample_biblio({ author => 'Hall, Kylie' }); - - my $branchcode = $library2->{branchcode}; - - my $item = $builder->build_sample_item( - { - biblionumber => $biblio->biblionumber, - library => $branchcode, - replacementprice => 99.00, - itype => $itemtype, - } - ); - - my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); - - ## Start with basic call, should just close out the open fine - my $accountline = Koha::Account::Line->new( - { - borrowernumber => $patron->id, - debit_type_code => 'LOST', - status => undef, - itemnumber => $item->itemnumber, - amount => 99.00, - amountoutstanding => 99.00, - interface => 'test', - } - )->store(); - - $patron->delete(); - - my $return_value = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber ); - - is( $return_value, undef, "_FixAccountForLostAndFound returns undef if patron is deleted" ); - -}; - subtest 'Set waiting flag' => sub { plan tests => 11; diff --git a/t/db_dependent/Koha/Items.t b/t/db_dependent/Koha/Items.t index 975060b50a..68232df0ef 100644 --- a/t/db_dependent/Koha/Items.t +++ b/t/db_dependent/Koha/Items.t @@ -65,24 +65,30 @@ my $retrieved_item_1 = Koha::Items->find( $new_item_1->itemnumber ); is( $retrieved_item_1->barcode, $new_item_1->barcode, 'Find a item by id should return the correct item' ); subtest 'store' => sub { - plan tests => 5; + plan tests => 6; my $biblio = $builder->build_sample_biblio; - my $today = dt_from_string->set( hour => 0, minute => 0, second => 0 ); - my $item = Koha::Item->new( + my $today = dt_from_string->set( hour => 0, minute => 0, second => 0 ); + my $item = Koha::Item->new( { homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, biblionumber => $biblio->biblionumber, location => 'my_loc', } - )->store - ->get_from_storage; - - is( t::lib::Dates::compare($item->replacementpricedate, $today), 0, 'replacementpricedate must have been set to today if not given'); - is( t::lib::Dates::compare($item->datelastseen, $today), 0, 'datelastseen must have been set to today if not given'); - is( $item->itype, $biblio->biblioitem->itemtype, 'items.itype must have been set to biblioitem.itemtype is not given'); - is( $item->permanent_location, $item->location, 'permanent_location must have been set to location if not given' ); + )->store->get_from_storage; + + is( t::lib::Dates::compare( $item->replacementpricedate, $today ), + 0, 'replacementpricedate must have been set to today if not given' ); + is( t::lib::Dates::compare( $item->datelastseen, $today ), + 0, 'datelastseen must have been set to today if not given' ); + is( + $item->itype, + $biblio->biblioitem->itemtype, + 'items.itype must have been set to biblioitem.itemtype is not given' + ); + is( $item->permanent_location, $item->location, + 'permanent_location must have been set to location if not given' ); $item->delete; subtest '*_on updates' => sub { @@ -129,6 +135,630 @@ subtest 'store' => sub { } }; + subtest '_lost_found_trigger' => sub { + plan tests => 6; + + t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 ); + t::lib::Mocks::mock_preference( 'WhenLostForgiveFine', 0 ); + + my $processfee_amount = 20; + my $replacement_amount = 99.00; + my $item_type = $builder->build_object( + { + class => 'Koha::ItemTypes', + value => { + notforloan => undef, + rentalcharge => 0, + defaultreplacecost => undef, + processfee => $processfee_amount, + rentalcharge_daily => 0, + } + } + ); + my $library = $builder->build_object( { class => 'Koha::Libraries' } ); + + $biblio = $builder->build_sample_biblio( { author => 'Hall, Daria' } ); + + subtest 'Full write-off tests' => sub { + + plan tests => 12; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $manager = + $builder->build_object( { class => "Koha::Patrons" } ); + t::lib::Mocks::mock_userenv( + { patron => $manager, branchcode => $manager->branchcode } ); + + my $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + library => $library->branchcode, + replacementprice => $replacement_amount, + itype => $item_type->itemtype, + } + ); + + C4::Circulation::AddIssue( $patron->unblessed, $item->barcode ); + + # Simulate item marked as lost + $item->itemlost(3)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + my $processing_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'PROCESSING' + } + ); + is( $processing_fee_lines->count, + 1, 'Only one processing fee produced' ); + my $processing_fee_line = $processing_fee_lines->next; + is( $processing_fee_line->amount + 0, + $processfee_amount, + 'The right PROCESSING amount is generated' ); + is( $processing_fee_line->amountoutstanding + 0, + $processfee_amount, + 'The right PROCESSING amountoutstanding is generated' ); + + my $lost_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'LOST' + } + ); + is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); + my $lost_fee_line = $lost_fee_lines->next; + is( $lost_fee_line->amount + 0, + $replacement_amount, 'The right LOST amount is generated' ); + is( $lost_fee_line->amountoutstanding + 0, + $replacement_amount, + 'The right LOST amountoutstanding is generated' ); + is( $lost_fee_line->status, undef, 'The LOST status was not set' ); + + my $account = $patron->account; + my $debts = $account->outstanding_debits; + + # Write off the debt + my $credit = $account->add_credit( + { + amount => $account->balance, + type => 'WRITEOFF', + interface => 'test', + } + ); + $credit->apply( + { debits => [ $debts->as_list ], offset_type => 'Writeoff' } ); + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, undef, 'No LOST_FOUND account line added' ); + + $lost_fee_line->discard_changes; # reload from DB + is( $lost_fee_line->amountoutstanding + 0, + 0, 'Lost fee has no outstanding amount' ); + is( $lost_fee_line->debit_type_code, + 'LOST', 'Lost fee now still has account type of LOST' ); + is( $lost_fee_line->status, 'FOUND', + "Lost fee now has account status of FOUND - No Refund" ); + + is( $patron->account->balance, + -0, 'The patron balance is 0, everything was written off' ); + }; + + subtest 'Full payment tests' => sub { + + plan tests => 14; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + + my $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + library => $library->branchcode, + replacementprice => $replacement_amount, + itype => $item_type->itemtype + } + ); + + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $item->barcode ); + + # Simulate item marked as lost + $item->itemlost(1)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + my $processing_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'PROCESSING' + } + ); + is( $processing_fee_lines->count, + 1, 'Only one processing fee produced' ); + my $processing_fee_line = $processing_fee_lines->next; + is( $processing_fee_line->amount + 0, + $processfee_amount, + 'The right PROCESSING amount is generated' ); + is( $processing_fee_line->amountoutstanding + 0, + $processfee_amount, + 'The right PROCESSING amountoutstanding is generated' ); + + my $lost_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'LOST' + } + ); + is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); + my $lost_fee_line = $lost_fee_lines->next; + is( $lost_fee_line->amount + 0, + $replacement_amount, 'The right LOST amount is generated' ); + is( $lost_fee_line->amountoutstanding + 0, + $replacement_amount, + 'The right LOST amountountstanding is generated' ); + + my $account = $patron->account; + my $debts = $account->outstanding_debits; + + # Pay off the debt + my $credit = $account->add_credit( + { + amount => $account->balance, + type => 'PAYMENT', + interface => 'test', + } + ); + $credit->apply( + { debits => [ $debts->as_list ], offset_type => 'Payment' } ); + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, 1, 'Refund triggered' ); + + my $credit_return = Koha::Account::Lines->search( + { + itemnumber => $item->itemnumber, + credit_type_code => 'LOST_FOUND' + }, + { rows => 1 } + )->single; + + ok( $credit_return, 'An account line of type LOST_FOUND is added' ); + is( $credit_return->amount + 0, + -99.00, + 'The account line of type LOST_FOUND has an amount of -99' ); + is( + $credit_return->amountoutstanding + 0, + -99.00, +'The account line of type LOST_FOUND has an amountoutstanding of -99' + ); + + $lost_fee_line->discard_changes; + is( $lost_fee_line->amountoutstanding + 0, + 0, 'Lost fee has no outstanding amount' ); + is( $lost_fee_line->debit_type_code, + 'LOST', 'Lost fee now still has account type of LOST' ); + is( $lost_fee_line->status, 'FOUND', + "Lost fee now has account status of FOUND" ); + + is( $patron->account->balance, -99, +'The patron balance is -99, a credit that equals the lost fee payment' + ); + }; + + subtest 'Test without payment or write off' => sub { + + plan tests => 14; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + + my $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + library => $library->branchcode, + replacementprice => 23.00, + replacementprice => $replacement_amount, + itype => $item_type->itemtype + } + ); + + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $item->barcode ); + + # Simulate item marked as lost + $item->itemlost(3)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + my $processing_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'PROCESSING' + } + ); + is( $processing_fee_lines->count, + 1, 'Only one processing fee produced' ); + my $processing_fee_line = $processing_fee_lines->next; + is( $processing_fee_line->amount + 0, + $processfee_amount, + 'The right PROCESSING amount is generated' ); + is( $processing_fee_line->amountoutstanding + 0, + $processfee_amount, + 'The right PROCESSING amountoutstanding is generated' ); + + my $lost_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'LOST' + } + ); + is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); + my $lost_fee_line = $lost_fee_lines->next; + is( $lost_fee_line->amount + 0, + $replacement_amount, 'The right LOST amount is generated' ); + is( $lost_fee_line->amountoutstanding + 0, + $replacement_amount, + 'The right LOST amountountstanding is generated' ); + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, 1, 'Refund triggered' ); + + my $credit_return = Koha::Account::Lines->search( + { + itemnumber => $item->itemnumber, + credit_type_code => 'LOST_FOUND' + }, + { rows => 1 } + )->single; + + ok( $credit_return, 'An account line of type LOST_FOUND is added' ); + is( $credit_return->amount + 0, + -99.00, + 'The account line of type LOST_FOUND has an amount of -99' ); + is( + $credit_return->amountoutstanding + 0, + 0, +'The account line of type LOST_FOUND has an amountoutstanding of 0' + ); + + $lost_fee_line->discard_changes; + is( $lost_fee_line->amountoutstanding + 0, + 0, 'Lost fee has no outstanding amount' ); + is( $lost_fee_line->debit_type_code, + 'LOST', 'Lost fee now still has account type of LOST' ); + is( $lost_fee_line->status, 'FOUND', + "Lost fee now has account status of FOUND" ); + + is( $patron->account->balance, + 20, 'The patron balance is 20, still owes the processing fee' ); + }; + + subtest + 'Test with partial payement and write off, and remaining debt' => + sub { + + plan tests => 17; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + library => $library->branchcode, + replacementprice => $replacement_amount, + itype => $item_type->itemtype + } + ); + + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $item->barcode ); + + # Simulate item marked as lost + $item->itemlost(1)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + my $processing_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'PROCESSING' + } + ); + is( $processing_fee_lines->count, + 1, 'Only one processing fee produced' ); + my $processing_fee_line = $processing_fee_lines->next; + is( $processing_fee_line->amount + 0, + $processfee_amount, + 'The right PROCESSING amount is generated' ); + is( $processing_fee_line->amountoutstanding + 0, + $processfee_amount, + 'The right PROCESSING amountoutstanding is generated' ); + + my $lost_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'LOST' + } + ); + is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); + my $lost_fee_line = $lost_fee_lines->next; + is( $lost_fee_line->amount + 0, + $replacement_amount, 'The right LOST amount is generated' ); + is( $lost_fee_line->amountoutstanding + 0, + $replacement_amount, + 'The right LOST amountountstanding is generated' ); + + my $account = $patron->account; + is( + $account->balance, + $processfee_amount + $replacement_amount, + 'Balance is PROCESSING + L' + ); + + # Partially pay fee + my $payment_amount = 27; + my $payment = $account->add_credit( + { + amount => $payment_amount, + type => 'PAYMENT', + interface => 'test', + } + ); + + $payment->apply( + { debits => [$lost_fee_line], offset_type => 'Payment' } ); + + # Partially write off fee + my $write_off_amount = 25; + my $write_off = $account->add_credit( + { + amount => $write_off_amount, + type => 'WRITEOFF', + interface => 'test', + } + ); + $write_off->apply( + { debits => [$lost_fee_line], offset_type => 'Writeoff' } ); + + is( + $account->balance, + $processfee_amount + + $replacement_amount - + $payment_amount - + $write_off_amount, + 'Payment and write off applied' + ); + + # Store the amountoutstanding value + $lost_fee_line->discard_changes; + my $outstanding = $lost_fee_line->amountoutstanding; + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, 1, 'Refund triggered' ); + + my $credit_return = Koha::Account::Lines->search( + { + itemnumber => $item->itemnumber, + credit_type_code => 'LOST_FOUND' + }, + { rows => 1 } + )->single; + + ok( $credit_return, 'An account line of type LOST_FOUND is added' ); + + is( + $account->balance, + $processfee_amount - $payment_amount, + 'Balance is PROCESSING - PAYMENT (LOST_FOUND)' + ); + + $lost_fee_line->discard_changes; + is( $lost_fee_line->amountoutstanding + 0, + 0, 'Lost fee has no outstanding amount' ); + is( $lost_fee_line->debit_type_code, + 'LOST', 'Lost fee now still has account type of LOST' ); + is( $lost_fee_line->status, 'FOUND', + "Lost fee now has account status of FOUND" ); + + is( + $credit_return->amount + 0, + ( $payment_amount + $outstanding ) * -1, +'The account line of type LOST_FOUND has an amount equal to the payment + outstanding' + ); + is( + $credit_return->amountoutstanding + 0, + $payment_amount * -1, +'The account line of type LOST_FOUND has an amountoutstanding equal to the payment' + ); + + is( + $account->balance, + $processfee_amount - $payment_amount, +'The patron balance is the difference between the PROCESSING and the credit' + ); + }; + + subtest 'Partial payment, existing debits and AccountAutoReconcile' => + sub { + + plan tests => 10; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $barcode = 'KD123456793'; + my $replacement_amount = 100; + my $processfee_amount = 20; + + my $item_type = $builder->build_object( + { + class => 'Koha::ItemTypes', + value => { + notforloan => undef, + rentalcharge => 0, + defaultreplacecost => undef, + processfee => 0, + rentalcharge_daily => 0, + } + } + ); + my $item = Koha::Item->new( + { + biblionumber => $biblio->biblionumber, + homebranch => $library->branchcode, + holdingbranch => $library->branchcode, + barcode => $barcode, + replacementprice => $replacement_amount, + itype => $item_type->itemtype + }, + )->store; + + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $barcode ); + + # Simulate item marked as lost + $item->itemlost(1)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + my $lost_fee_lines = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + itemnumber => $item->itemnumber, + debit_type_code => 'LOST' + } + ); + is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' ); + my $lost_fee_line = $lost_fee_lines->next; + is( $lost_fee_line->amount + 0, + $replacement_amount, 'The right LOST amount is generated' ); + is( $lost_fee_line->amountoutstanding + 0, + $replacement_amount, + 'The right LOST amountountstanding is generated' ); + + my $account = $patron->account; + is( $account->balance, $replacement_amount, 'Balance is L' ); + + # Partially pay fee + my $payment_amount = 27; + my $payment = $account->add_credit( + { + amount => $payment_amount, + type => 'PAYMENT', + interface => 'test', + } + ); + $payment->apply( + { debits => [$lost_fee_line], offset_type => 'Payment' } ); + + is( + $account->balance, + $replacement_amount - $payment_amount, + 'Payment applied' + ); + + my $manual_debit_amount = 80; + $account->add_debit( + { + amount => $manual_debit_amount, + type => 'OVERDUE', + interface => 'test' + } + ); + + is( + $account->balance, + $manual_debit_amount + $replacement_amount - $payment_amount, + 'Manual debit applied' + ); + + t::lib::Mocks::mock_preference( 'AccountAutoReconcile', 1 ); + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, 1, 'Refund triggered' ); + + my $credit_return = Koha::Account::Lines->search( + { + itemnumber => $item->itemnumber, + credit_type_code => 'LOST_FOUND' + }, + { rows => 1 } + )->single; + + ok( $credit_return, 'An account line of type LOST_FOUND is added' ); + + is( + $account->balance, + $manual_debit_amount - $payment_amount, + 'Balance is PROCESSING - payment (LOST_FOUND)' + ); + + my $manual_debit = Koha::Account::Lines->search( + { + borrowernumber => $patron->id, + debit_type_code => 'OVERDUE', + status => 'UNRETURNED' + } + )->next; + is( + $manual_debit->amountoutstanding + 0, + $manual_debit_amount - $payment_amount, + 'reconcile_balance was called' + ); + }; + + subtest 'Patron deleted' => sub { + plan tests => 1; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $barcode = 'KD123456794'; + my $replacement_amount = 100; + my $processfee_amount = 20; + + my $item_type = $builder->build_object( + { + class => 'Koha::ItemTypes', + value => { + notforloan => undef, + rentalcharge => 0, + defaultreplacecost => undef, + processfee => 0, + rentalcharge_daily => 0, + } + } + ); + my $item = Koha::Item->new( + { + biblionumber => $biblio->biblionumber, + homebranch => $library->branchcode, + holdingbranch => $library->branchcode, + barcode => $barcode, + replacementprice => $replacement_amount, + itype => $item_type->itemtype + }, + )->store; + + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $barcode ); + + # Simulate item marked as lost + $item->itemlost(1)->store; + C4::Circulation::LostItem( $item->itemnumber, 1 ); + + $issue->delete(); + $patron->delete(); + + # Simulate item marked as found + $item->itemlost(0)->store; + is( $item->{_refunded}, undef, 'No refund triggered' ); + + }; + }; }; subtest 'get_transfer' => sub { -- 2.20.1