Bug 22638: Self checkin CSS update
[koha.git] / Koha / Account / Line.pm
blob6443b4d3464bc25eef7daa1327e94cae6061e083
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 item
46 Return the item linked to this account line if exists
48 =cut
50 sub item {
51 my ( $self ) = @_;
52 my $rs = $self->_result->itemnumber;
53 return unless $rs;
54 return Koha::Item->_new_from_dbic( $rs );
57 =head3 checkout
59 Return the checkout linked to this account line if exists
61 =cut
63 sub checkout {
64 my ( $self ) = @_;
65 return unless $self->issue_id ;
67 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
68 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
69 return $self->{_checkout};
72 =head3 void
74 $payment_accountline->void();
76 =cut
78 sub void {
79 my ($self) = @_;
81 # Make sure it is a payment we are voiding
82 return unless $self->amount < 0;
84 my @account_offsets =
85 Koha::Account::Offsets->search(
86 { credit_id => $self->id, amount => { '<' => 0 } } );
88 $self->_result->result_source->schema->txn_do(
89 sub {
90 foreach my $account_offset (@account_offsets) {
91 my $fee_paid =
92 Koha::Account::Lines->find( $account_offset->debit_id );
94 next unless $fee_paid;
96 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
97 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
98 $fee_paid->amountoutstanding($new_amount);
99 $fee_paid->store();
101 Koha::Account::Offset->new(
103 credit_id => $self->id,
104 debit_id => $fee_paid->id,
105 amount => $amount_paid,
106 type => 'Void Payment',
108 )->store();
111 if ( C4::Context->preference("FinesLog") ) {
112 logaction(
113 "FINES", 'VOID',
114 $self->borrowernumber,
115 Dumper(
117 action => 'void_payment',
118 borrowernumber => $self->borrowernumber,
119 amount => $self->amount,
120 amountoutstanding => $self->amountoutstanding,
121 description => $self->description,
122 accounttype => $self->accounttype,
123 payment_type => $self->payment_type,
124 note => $self->note,
125 itemnumber => $self->itemnumber,
126 manager_id => $self->manager_id,
127 offsets =>
128 [ map { $_->unblessed } @account_offsets ],
134 $self->set(
136 accounttype => 'VOID',
137 amountoutstanding => 0,
138 amount => 0,
141 $self->store();
147 =head3 apply
149 my $debits = $account->outstanding_debits;
150 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
152 Applies the credit to a given debits set.
154 =head4 arguments hashref
156 =over 4
158 =item debits - Koha::Account::Lines object set of debits
160 =item offset_type (optional) - a string indicating the offset type (valid values are those from
161 the 'account_offset_types' table)
163 =back
165 =cut
167 sub apply {
168 my ( $self, $params ) = @_;
170 my $debits = $params->{debits};
171 my $offset_type = $params->{offset_type} // 'Credit Applied';
173 unless ( $self->is_credit ) {
174 Koha::Exceptions::Account::IsNotCredit->throw(
175 error => 'Account line ' . $self->id . ' is not a credit'
179 my $available_credit = $self->amountoutstanding * -1;
181 unless ( $available_credit > 0 ) {
182 Koha::Exceptions::Account::NoAvailableCredit->throw(
183 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
187 my $schema = Koha::Database->new->schema;
189 $schema->txn_do( sub {
190 while ( my $debit = $debits->next ) {
192 unless ( $debit->is_debit ) {
193 Koha::Exceptions::Account::IsNotDebit->throw(
194 error => 'Account line ' . $debit->id . 'is not a debit'
197 my $amount_to_cancel;
198 my $owed = $debit->amountoutstanding;
200 if ( $available_credit >= $owed ) {
201 $amount_to_cancel = $owed;
203 else { # $available_credit < $debit->amountoutstanding
204 $amount_to_cancel = $available_credit;
207 # record the account offset
208 Koha::Account::Offset->new(
209 { credit_id => $self->id,
210 debit_id => $debit->id,
211 amount => $amount_to_cancel * -1,
212 type => $offset_type,
214 )->store();
216 $available_credit -= $amount_to_cancel;
218 $self->amountoutstanding( $available_credit * -1 )->store;
219 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
223 return $available_credit;
226 =head3 adjust
228 This method allows updating a debit or credit on a patron's account
230 $account_line->adjust(
232 amount => $amount,
233 type => $update_type,
234 interface => $interface
238 $update_type can be any of:
239 - fine_update
241 Authors Note: The intention here is that this method is only used
242 to adjust accountlines where the final amount is not yet known/fixed.
243 Incrementing fines are the only existing case at the time of writing,
244 all other forms of 'adjustment' should be recorded as distinct credits
245 or debits and applied, via an offset, to the corresponding debit or credit.
247 =cut
249 sub adjust {
250 my ( $self, $params ) = @_;
252 my $amount = $params->{amount};
253 my $update_type = $params->{type};
254 my $interface = $params->{interface};
256 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
257 Koha::Exceptions::Account::UnrecognisedType->throw(
258 error => 'Update type not recognised'
262 my $account_type = $self->accounttype;
263 unless ( $Koha::Account::Line::allowed_update->{$update_type} eq $account_type ) {
264 Koha::Exceptions::Account::UnrecognisedType->throw(
265 error => 'Update type not allowed on this accounttype'
269 my $schema = Koha::Database->new->schema;
271 $schema->txn_do(
272 sub {
274 my $amount_before = $self->amount;
275 my $amount_outstanding_before = $self->amountoutstanding;
276 my $difference = $amount - $amount_before;
277 my $new_outstanding = $amount_outstanding_before + $difference;
279 my $offset_type = substr( $update_type, 0, index( $update_type, '_' ) );
280 $offset_type .= ( $difference > 0 ) ? "_increase" : "_decrease";
282 # Catch cases that require patron refunds
283 if ( $new_outstanding < 0 ) {
284 my $account =
285 Koha::Patrons->find( $self->borrowernumber )->account;
286 my $credit = $account->add_credit(
288 amount => $new_outstanding * -1,
289 description => 'Overpayment refund',
290 type => 'credit',
291 interface => $interface,
292 ( $update_type eq 'fine_update' ? ( item_id => $self->itemnumber ) : ()),
295 $new_outstanding = 0;
298 # Update the account line
299 $self->set(
301 date => \'NOW()',
302 amount => $amount,
303 amountoutstanding => $new_outstanding
305 )->store();
307 # Record the account offset
308 my $account_offset = Koha::Account::Offset->new(
310 debit_id => $self->id,
311 type => $offset_type,
312 amount => $difference
314 )->store();
316 if ( C4::Context->preference("FinesLog") ) {
317 logaction(
318 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
319 $self->borrowernumber,
320 Dumper(
321 { action => $update_type,
322 borrowernumber => $self->borrowernumber,
323 amount => $amount,
324 description => undef,
325 amountoutstanding => $new_outstanding,
326 accounttype => $self->accounttype,
327 note => undef,
328 itemnumber => $self->itemnumber,
329 manager_id => undef,
332 ) if ( $update_type eq 'fine_update' );
337 return $self;
340 =head3 is_credit
342 my $bool = $line->is_credit;
344 =cut
346 sub is_credit {
347 my ($self) = @_;
349 return ( $self->amount < 0 );
352 =head3 is_debit
354 my $bool = $line->is_debit;
356 =cut
358 sub is_debit {
359 my ($self) = @_;
361 return !$self->is_credit;
364 =head2 Internal methods
366 =cut
368 =head3 _type
370 =cut
372 sub _type {
373 return 'Accountline';
378 =head2 Name mappings
380 =head3 $allowed_update
382 =cut
384 our $allowed_update = { 'fine_update' => 'FU', };
386 =head1 AUTHORS
388 Kyle M Hall <kyle@bywatersolutions.com >
389 Tomás Cohen Arazi <tomascohen@theke.io>
390 Martin Renvoize <martin.renvoize@ptfs-europe.com>
392 =cut