@@ -, +, @@ on it. It should now be marked as cancelled that it still works --- Koha/Account/Line.pm | 99 +++++++++---- installer/data/mysql/account_credit_types.sql | 3 +- installer/data/mysql/account_offset_types.sql | 3 +- .../data/mysql/atomicupdate/bug_24603.perl | 20 +++ .../prog/en/modules/members/boraccount.tt | 4 +- members/cancel-charge.pl | 9 +- t/db_dependent/Koha/Account/Line.t | 131 +++++++++++++----- 7 files changed, 202 insertions(+), 67 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_24603.perl --- a/Koha/Account/Line.pm +++ a/Koha/Account/Line.pm @@ -291,46 +291,90 @@ sub void { Cancel a charge. It will mark the debit as 'cancelled' by updating its status to 'CANCELLED'. + Charges that have been fully or partially paid cannot be cancelled. -Return self in case of success, undef otherwise +Returns the cancellation accountline. =cut sub cancel { - my ($self) = @_; + my ( $self, $params ) = @_; - # Make sure it is a charge we are cancelling - return unless $self->is_debit; + # Make sure it is a charge we are reducing + unless ( $self->is_debit ) { + Koha::Exceptions::Account::IsNotDebit->throw( + error => 'Account line ' . $self->id . 'is not a debit' ); + } + if ( $self->debit_type_code eq 'PAYOUT' ) { + Koha::Exceptions::Account::IsNotDebit->throw( + error => 'Account line ' . $self->id . 'is a payout' ); + } # Make sure it is not already cancelled - return if $self->status && $self->status eq 'CANCELLED'; + if ( $self->status && $self->status eq 'CANCELLED' ) { + Koha::Exceptions::Account->throw( + error => 'Account line ' . $self->id . 'is already cancelled' ); + } # Make sure it has not be paid yet - return if $self->amount != $self->amountoutstanding; - - if ( C4::Context->preference("FinesLog") ) { - logaction('FINES', 'CANCEL', $self->borrowernumber, Dumper({ - action => 'cancel_charge', - borrowernumber => $self->borrowernumber, - amount => $self->amount, - amountoutstanding => $self->amountoutstanding, - description => $self->description, - debit_type_code => $self->debit_type_code, - note => $self->note, - itemnumber => $self->itemnumber, - manager_id => $self->manager_id, - })); + if ( $self->amount != $self->amountoutstanding ) { + Koha::Exceptions::Account->throw( + error => 'Account line ' . $self->id . 'is already offset' ); } - $self->set({ - status => 'CANCELLED', - amountoutstanding => 0, - amount => 0, - }); - $self->store(); + # Check for mandatory parameters + my @mandatory = ( 'staff_id', 'branch' ); + for my $param (@mandatory) { + unless ( defined( $params->{$param} ) ) { + Koha::Exceptions::MissingParameter->throw( + error => "The $param parameter is mandatory" ); + } + } - return $self; + my $cancellation; + $self->_result->result_source->schema->txn_do( + sub { + + # A 'cancellation' is a 'credit' + $cancellation = Koha::Account::Line->new( + { + date => \'NOW()', + amount => 0 - $self->amount, + credit_type_code => 'CANCELLATION', + status => 'ADDED', + amountoutstanding => 0 - $self->amount, + manager_id => $params->{staff_id}, + borrowernumber => $self->borrowernumber, + interface => 'intranet', + branchcode => $params->{branch}, + } + )->store(); + + my $cancellation_offset = Koha::Account::Offset->new( + { + credit_id => $cancellation->accountlines_id, + type => 'CANCELLATION', + amount => $self->amount + } + )->store(); + + # Link cancellation to charge + $cancellation->apply( + { + debits => [$self], + offset_type => 'CANCELLATION' + } + ); + $cancellation->status('APPLIED')->store(); + + # Update status of original debit + $self->status('CANCELLED')->store; + } + ); + + $cancellation->discard_changes; + return $cancellation; } =head3 reduce @@ -453,7 +497,8 @@ sub reduce { } else { - # Zero amount offset used to link original 'debit' to reduction 'credit' + # Zero amount offset used to link original 'debit' to + # reduction 'credit' my $link_reduction_offset = Koha::Account::Offset->new( { credit_id => $reduction->accountlines_id, --- a/installer/data/mysql/account_credit_types.sql +++ a/installer/data/mysql/account_credit_types.sql @@ -6,6 +6,7 @@ INSERT INTO account_credit_types ( code, description, can_be_added_manually, is_ ('DISCOUNT', 'A discount applied to a patrons fine', 0, 1), ('REFUND', 'A refund applied to a patrons fine', 0, 1), ('LOST_FOUND', 'Lost item fee refund', 0, 1), -('PURCHASE', 'Purchase', 0, 1); +('PURCHASE', 'Purchase', 0, 1), +('CANCELLATION', 'Cancellation', 0, 1); INSERT INTO authorised_values (category,authorised_value,lib) VALUES ('PAYMENT_TYPE','CASH','Cash'); --- a/installer/data/mysql/account_offset_types.sql +++ a/installer/data/mysql/account_offset_types.sql @@ -21,4 +21,5 @@ INSERT INTO account_offset_types ( type ) VALUES ('Credit Applied'), ('PAYOUT'), ('DISCOUNT'), -('REFUND'); +('REFUND'), +('CANCELLATION'); --- a/installer/data/mysql/atomicupdate/bug_24603.perl +++ a/installer/data/mysql/atomicupdate/bug_24603.perl @@ -0,0 +1,20 @@ +$DBversion = 'XXX'; # will be replaced by the RM +if ( CheckVersion($DBversion) ) { + + $dbh->do( + qq{ + INSERT IGNORE INTO account_credit_types (code, description, can_be_added_manually, is_system) + VALUES + ('CANCELLATION', 'A cancellation applied to a patron charge', 0, 1) + } + ); + + $dbh->do( + qq{ + INSERT IGNORE INTO account_offset_types ( type ) VALUES ('CANCELLATION'); + } + ); + + # Always end with this (adjust the bug info) + NewVersion( $DBversion, 24603, "Add CANCELLATION credit_type_code" ); +} --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt @@ -87,12 +87,12 @@ [% END %] Details [% IF account.is_debit && account.amountoutstanding > 0 %] - Pay + Pay [% END %] [% IF account.is_credit && account.status != 'VOID' %] Void payment [% END %] - [% IF account.is_debit && account.amount == account.amountoutstanding && account.status != 'CANCELLED' %] + [% IF account.is_debit && account.amount == account.amountoutstanding && account.status != 'CANCELLED' && !(account.debit_type_code == 'PAYOUT') %]