Bug 20434: Update UNIMARC framework - auth (SAUTTIT)
[koha.git] / Koha / Account / Line.pm
blob124aa29153a0ac2d4bdf001751a8fd191c64bc7f
1 package Koha::Account::Line;
3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
8 # version.
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 use Modern::Perl;
20 use Carp;
21 use Data::Dumper;
23 use C4::Log qw(logaction);
25 use Koha::Account::Offsets;
26 use Koha::Database;
27 use Koha::Exceptions::Account;
28 use Koha::Items;
30 use base qw(Koha::Object);
32 =encoding utf8
34 =head1 NAME
36 Koha::Account::Line - Koha accountline Object class
38 =head1 API
40 =head2 Class methods
42 =cut
44 =head3 patron
46 Return the patron linked to this account line
48 =cut
50 sub patron {
51 my ( $self ) = @_;
52 my $rs = $self->_result->borrowernumber;
53 return unless $rs;
54 return Koha::Patron->_new_from_dbic( $rs );
57 =head3 item
59 Return the item linked to this account line if exists
61 =cut
63 sub item {
64 my ( $self ) = @_;
65 my $rs = $self->_result->itemnumber;
66 return unless $rs;
67 return Koha::Item->_new_from_dbic( $rs );
70 =head3 checkout
72 Return the checkout linked to this account line if exists
74 =cut
76 sub checkout {
77 my ( $self ) = @_;
78 return unless $self->issue_id ;
80 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
81 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
82 return $self->{_checkout};
85 =head3 void
87 $payment_accountline->void();
89 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
90 created by the application of this credit upon any debits and mark the credit
91 as 'void' by updating it's status to "VOID".
93 =cut
95 sub void {
96 my ($self) = @_;
98 # Make sure it is a payment we are voiding
99 return unless $self->amount < 0;
101 my @account_offsets =
102 Koha::Account::Offsets->search(
103 { credit_id => $self->id, amount => { '<' => 0 } } );
105 $self->_result->result_source->schema->txn_do(
106 sub {
107 foreach my $account_offset (@account_offsets) {
108 my $fee_paid =
109 Koha::Account::Lines->find( $account_offset->debit_id );
111 next unless $fee_paid;
113 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
114 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
115 $fee_paid->amountoutstanding($new_amount);
116 $fee_paid->store();
118 Koha::Account::Offset->new(
120 credit_id => $self->id,
121 debit_id => $fee_paid->id,
122 amount => $amount_paid,
123 type => 'Void Payment',
125 )->store();
128 if ( C4::Context->preference("FinesLog") ) {
129 logaction(
130 "FINES", 'VOID',
131 $self->borrowernumber,
132 Dumper(
134 action => 'void_payment',
135 borrowernumber => $self->borrowernumber,
136 amount => $self->amount,
137 amountoutstanding => $self->amountoutstanding,
138 description => $self->description,
139 accounttype => $self->accounttype,
140 payment_type => $self->payment_type,
141 note => $self->note,
142 itemnumber => $self->itemnumber,
143 manager_id => $self->manager_id,
144 offsets =>
145 [ map { $_->unblessed } @account_offsets ],
151 $self->set(
153 status => 'VOID',
154 amountoutstanding => 0,
155 amount => 0,
158 $self->store();
164 =head3 apply
166 my $debits = $account->outstanding_debits;
167 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
169 Applies the credit to a given debits array reference.
171 =head4 arguments hashref
173 =over 4
175 =item debits - Koha::Account::Lines object set of debits
177 =item offset_type (optional) - a string indicating the offset type (valid values are those from
178 the 'account_offset_types' table)
180 =back
182 =cut
184 sub apply {
185 my ( $self, $params ) = @_;
187 my $debits = $params->{debits};
188 my $offset_type = $params->{offset_type} // 'Credit Applied';
190 unless ( $self->is_credit ) {
191 Koha::Exceptions::Account::IsNotCredit->throw(
192 error => 'Account line ' . $self->id . ' is not a credit'
196 my $available_credit = $self->amountoutstanding * -1;
198 unless ( $available_credit > 0 ) {
199 Koha::Exceptions::Account::NoAvailableCredit->throw(
200 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
204 my $schema = Koha::Database->new->schema;
206 $schema->txn_do( sub {
207 for my $debit ( @{$debits} ) {
209 unless ( $debit->is_debit ) {
210 Koha::Exceptions::Account::IsNotDebit->throw(
211 error => 'Account line ' . $debit->id . 'is not a debit'
214 my $amount_to_cancel;
215 my $owed = $debit->amountoutstanding;
217 if ( $available_credit >= $owed ) {
218 $amount_to_cancel = $owed;
220 else { # $available_credit < $debit->amountoutstanding
221 $amount_to_cancel = $available_credit;
224 # record the account offset
225 Koha::Account::Offset->new(
226 { credit_id => $self->id,
227 debit_id => $debit->id,
228 amount => $amount_to_cancel * -1,
229 type => $offset_type,
231 )->store();
233 $available_credit -= $amount_to_cancel;
235 $self->amountoutstanding( $available_credit * -1 )->store;
236 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
238 # Same logic exists in Koha::Account::pay
239 if ( $debit->amountoutstanding == 0
240 && $debit->itemnumber
241 && $debit->accounttype
242 && $debit->accounttype eq 'LOST' )
244 C4::Circulation::ReturnLostItem( $self->borrowernumber, $debit->itemnumber );
250 return $available_credit;
253 =head3 adjust
255 This method allows updating a debit or credit on a patron's account
257 $account_line->adjust(
259 amount => $amount,
260 type => $update_type,
261 interface => $interface
265 $update_type can be any of:
266 - overdue_update
268 Authors Note: The intention here is that this method is only used
269 to adjust accountlines where the final amount is not yet known/fixed.
270 Incrementing fines are the only existing case at the time of writing,
271 all other forms of 'adjustment' should be recorded as distinct credits
272 or debits and applied, via an offset, to the corresponding debit or credit.
274 =cut
276 sub adjust {
277 my ( $self, $params ) = @_;
279 my $amount = $params->{amount};
280 my $update_type = $params->{type};
281 my $interface = $params->{interface};
283 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
284 Koha::Exceptions::Account::UnrecognisedType->throw(
285 error => 'Update type not recognised'
289 my $account_type = $self->accounttype;
290 my $account_status = $self->status;
291 unless (
293 exists(
294 $Koha::Account::Line::allowed_update->{$update_type}
295 ->{$account_type}
297 && ( $Koha::Account::Line::allowed_update->{$update_type}
298 ->{$account_type} eq $account_status )
302 Koha::Exceptions::Account::UnrecognisedType->throw(
303 error => 'Update type not allowed on this accounttype' );
306 my $schema = Koha::Database->new->schema;
308 $schema->txn_do(
309 sub {
311 my $amount_before = $self->amount;
312 my $amount_outstanding_before = $self->amountoutstanding;
313 my $difference = $amount - $amount_before;
314 my $new_outstanding = $amount_outstanding_before + $difference;
316 my $offset_type = $account_type;
317 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
319 # Catch cases that require patron refunds
320 if ( $new_outstanding < 0 ) {
321 my $account =
322 Koha::Patrons->find( $self->borrowernumber )->account;
323 my $credit = $account->add_credit(
325 amount => $new_outstanding * -1,
326 description => 'Overpayment refund',
327 type => 'credit',
328 interface => $interface,
329 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
332 $new_outstanding = 0;
335 # Update the account line
336 $self->set(
338 date => \'NOW()',
339 amount => $amount,
340 amountoutstanding => $new_outstanding,
342 )->store();
344 # Record the account offset
345 my $account_offset = Koha::Account::Offset->new(
347 debit_id => $self->id,
348 type => $offset_type,
349 amount => $difference
351 )->store();
353 if ( C4::Context->preference("FinesLog") ) {
354 logaction(
355 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
356 $self->borrowernumber,
357 Dumper(
358 { action => $update_type,
359 borrowernumber => $self->borrowernumber,
360 amount => $amount,
361 description => undef,
362 amountoutstanding => $new_outstanding,
363 accounttype => $self->accounttype,
364 note => undef,
365 itemnumber => $self->itemnumber,
366 manager_id => undef,
369 ) if ( $update_type eq 'overdue_update' );
374 return $self;
377 =head3 is_credit
379 my $bool = $line->is_credit;
381 =cut
383 sub is_credit {
384 my ($self) = @_;
386 return ( $self->amount < 0 );
389 =head3 is_debit
391 my $bool = $line->is_debit;
393 =cut
395 sub is_debit {
396 my ($self) = @_;
398 return !$self->is_credit;
401 =head2 Internal methods
403 =cut
405 =head3 _type
407 =cut
409 sub _type {
410 return 'Accountline';
415 =head2 Name mappings
417 =head3 $allowed_update
419 =cut
421 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
423 =head1 AUTHORS
425 Kyle M Hall <kyle@bywatersolutions.com >
426 Tomás Cohen Arazi <tomascohen@theke.io>
427 Martin Renvoize <martin.renvoize@ptfs-europe.com>
429 =cut