View | Details | Raw Unified | Return to bug 28656
Collapse All | Expand All

(-)a/Koha/Account/Line.pm (-37 / +83 lines)
Lines 172-178 sub debit_offsets { Link Here
172
172
173
Return the credits linked to this account line if some exist.
173
Return the credits linked to this account line if some exist.
174
Search conditions and attributes may be passed if you wish to filter
174
Search conditions and attributes may be passed if you wish to filter
175
the resultant resultant resultset.
175
the resultant resultset.
176
176
177
=cut
177
=cut
178
178
Lines 200-206 sub credits { Link Here
200
200
201
Return the debits linked to this account line if some exist.
201
Return the debits linked to this account line if some exist.
202
Search conditions and attributes may be passed if you wish to filter
202
Search conditions and attributes may be passed if you wish to filter
203
the resultant resultant resultset.
203
the resultant resultset.
204
204
205
=cut
205
=cut
206
206
Lines 362-374 sub void { Link Here
362
362
363
=head3 cancel
363
=head3 cancel
364
364
365
  $debit_accountline->cancel({ cancellation_type => $type });
365
  $debit_accountline->cancel();
366
366
367
Cancel a charge. It will mark the debit as 'cancelled' by updating its
367
Cancel a charge. It will mark the debit as 'cancelled' by updating its
368
status to 'CANCELLED'.
368
status to 'CANCELLED'.
369
369
370
Charges that have been fully or partially paid will be refunded upto
370
Charges that have been fully or partially offset will be refunded upto
371
the amount paid excluding discounts, writeoffs and refunds.
371
the amount paid excluding discounts, writeoffs and prior refunds.
372
372
373
Returns the cancellation accountline.
373
Returns the cancellation accountline.
374
374
Lines 393-414 sub cancel { Link Here
393
            error => 'Account line ' . $self->id . 'is already cancelled' );
393
            error => 'Account line ' . $self->id . 'is already cancelled' );
394
    }
394
    }
395
395
396
    my $cancellation_type = $params->{cancellation_type} // 'CANCELLATION';
396
    my $cancellation_amount = $self->amount;
397
397
    my @applied_offsets;
398
    my $cancellation_amount = $self->amountoutstanding;
399
    if ( $self->amount != $self->amountoutstanding ) {
398
    if ( $self->amount != $self->amountoutstanding ) {
400
        my $credit_offsets = Koha::Account::Offsets->search(
399
        # Reductions are 'Writeoff', 'Refund' or 'Discount' lines applied against the debt already.
401
            {
400
        # We can ignore 'VOID' status as it will be accounted for in the offsets total
402
                debit_id  => $self->id,
401
        my $reduction_offsets = $self->debit_offsets->filter_by_non_reversable();
403
                credit_id => { '!=' => undef },    # not the debt itself
404
                type      => { '!=' => [ 'Writeoff', 'REFUND', 'DISCOUNT' ] }
405
                ,    # Don't refund writeoffs, refunds or discounts
406
                amount => { '<' => 0 }    # credits are negative on the DB
407
            }
408
        );
409
410
        $cancellation_amount +=
402
        $cancellation_amount +=
411
          $credit_offsets->count > 0 ? $credit_offsets->total * -1 : 0;
403
          $reduction_offsets->count > 0 ? $reduction_offsets->total : 0;
404
405
        # Payments are any credits applied (and not subsequently voided) that are 
406
        # not 'Writeoff', 'Refund' or 'Discount'
407
        @applied_offsets = $self->debit_offsets->filter_by_reversable();
412
    }
408
    }
413
409
414
    my $cancellation;
410
    my $cancellation;
Lines 416-430 sub cancel { Link Here
416
        sub {
412
        sub {
417
413
418
            # A 'cancellation' is a 'credit'
414
            # A 'cancellation' is a 'credit'
419
            $cancellation = $self->reduce(
415
            $cancellation = Koha::Account::Line->new(
420
                {
416
                {
421
                    reduction_type => $cancellation_type,
417
                    date              => \'NOW()',
422
                    amount         => $cancellation_amount,
418
                    amount            => 0 - $cancellation_amount,
423
                    staff_id       => $params->{staff_id},
419
                    credit_type_code  => 'CANCELLATION',
424
                    interface      => $params->{interface},
420
                    status            => 'ADDED',
425
                    branch         => $params->{branch}
421
                    amountoutstanding => 0 - $cancellation_amount,
422
                    manager_id        => $params->{staff_id},
423
                    borrowernumber    => $self->borrowernumber,
424
                    interface         => 'intranet',
425
                    branchcode        => $params->{branch},
426
                }
427
            )->store();
428
429
            Koha::Account::Offset->new(
430
                {
431
                    credit_id => $cancellation->accountlines_id,
432
                    type      => 'CREATE',
433
                    amount    => $cancellation_amount
426
                }
434
                }
427
            );
435
            )->store();
436
437
            # Link cancellation to charge
438
            $self->set(
439
                {
440
                    amountoutstanding => $cancellation_amount,
441
                    status            => 'CANCELLED'
442
                }
443
            )->store();
444
            $cancellation->apply( { debits => [$self] } );
445
446
            # Reverse any applied payments
447
            for my $applied_offset ( @applied_offsets ) {
448
                my $credit = $applied_offset->credit;
449
                $credit->amountoutstanding(
450
                    $credit->amountoutstanding - $applied_offset->amount )
451
                  ->store();
452
                
453
                Koha::Account::Offset->new(
454
                    {
455
                        credit_id => $applied_offset->credit_id,
456
                        debit_id  => $self->id,
457
                        amount    => $applied_offset->amount * -1,
458
                        type      => 'VOID',
459
                    }
460
                )->store();
461
            }
428
        }
462
        }
429
    );
463
    );
430
464
Lines 454-460 Reduction type may be one of: Link Here
454
488
455
* REFUND
489
* REFUND
456
* DISCOUNT
490
* DISCOUNT
457
* CANCELLATION
458
491
459
Returns the reduction accountline (which will be a credit)
492
Returns the reduction accountline (which will be a credit)
460
493
Lines 482-487 sub reduce { Link Here
482
        }
515
        }
483
    }
516
    }
484
517
518
    # Amount should always be passed as positive
519
    Koha::Exceptions::Account::AmountNotPositive->throw(
520
        error => 'Reduce amount passed is not positive' )
521
      unless ( $params->{amount} > 0 );
522
485
    # More mandatory parameters
523
    # More mandatory parameters
486
    if ( $params->{interface} eq 'intranet' ) {
524
    if ( $params->{interface} eq 'intranet' ) {
487
        my @optional = ( 'staff_id', 'branch' );
525
        my @optional = ( 'staff_id', 'branch' );
Lines 496-520 sub reduce { Link Here
496
534
497
    # Make sure the reduction isn't more than the original
535
    # Make sure the reduction isn't more than the original
498
    my $original = $self->amount;
536
    my $original = $self->amount;
499
    Koha::Exceptions::Account::AmountNotPositive->throw(
500
        error => 'Reduce amount passed is not positive' )
501
      unless ( $params->{amount} > 0 );
502
    Koha::Exceptions::ParameterTooHigh->throw( error =>
537
    Koha::Exceptions::ParameterTooHigh->throw( error =>
503
"Amount to reduce ($params->{amount}) is higher than original amount ($original)"
538
"Amount to reduce ($params->{amount}) is higher than original amount ($original)"
504
    ) unless ( $original >= $params->{amount} );
539
    ) unless ( $original >= $params->{amount} );
505
    my $reduced =
540
506
      $self->credits( { credit_type_code => [ 'WRITEOFF', 'DISCOUNT', 'REFUND' ] } )->total;
541
    # Make sure combined reduction isn't more than the original
542
    my $reduced = 0;
543
    if ( $self->amount != $self->amountoutstanding ) {
544
        my $reduction_offsets = Koha::Account::Offsets->search(
545
            {
546
                debit_id  => $self->id,
547
                credit_id => { '!=' => undef },    # not the debt itself
548
                type      => { '!=' => [ 'Writeoff', 'REFUND', 'DISCOUNT' ] }
549
                ,    # Don't refund writeoffs, refunds or discounts
550
                amount => { '<' => 0 }    # credits are negative on the DB
551
            }
552
        );
553
554
        $reduced = $reduction_offsets->count > 0 ? $reduction_offsets->total * -1 : 0;
555
    }
556
507
    Koha::Exceptions::ParameterTooHigh->throw( error =>
557
    Koha::Exceptions::ParameterTooHigh->throw( error =>
508
"Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
558
"Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
509
          . abs($original)
559
          . abs($original)
510
          . ")" )
560
          . ")" )
511
      unless ( $original >= ( $params->{amount} + abs($reduced) ) );
561
      unless ( $original >= ( $params->{amount} + abs($reduced) ) );
512
562
513
    my $status = {
563
    my $status = { 'REFUND' => 'REFUNDED', 'DISCOUNT' => 'DISCOUNTED' };
514
        'REFUND'       => 'REFUNDED',
515
        'DISCOUNT'     => 'DISCOUNTED',
516
        'CANCELLATION' => 'CANCELLED'
517
    };
518
564
519
    my $reduction;
565
    my $reduction;
520
    $self->_result->result_source->schema->txn_do(
566
    $self->_result->result_source->schema->txn_do(
(-)a/Koha/Account/Offsets.pm (-1 / +43 lines)
Lines 61-66 sub total { Link Here
61
      : 0;
61
      : 0;
62
}
62
}
63
63
64
65
=head3
66
67
=cut
68
69
sub filter_by_non_reversable {
70
    my ($self) = @_;
71
72
    my $me = $self->_resultset()->current_source_alias . ".";
73
    my $where = {
74
        debit_id                  => { '!=' => undef },
75
        credit_id                 => { '!=' => undef },
76
        'credit.credit_type_code' => [ 'WRITEOFF', 'REFUND', 'DISCOUNT' ],
77
        'credit.status'           => [ { '!=' => 'VOID' }, undef ],
78
        $me.amount                    => { '<' => 0 }
79
    };
80
    my $attr = { join => 'credit' };
81
82
    return $self->search( $where, $attr );
83
}
84
85
=head3
86
87
=cut
88
89
sub filter_by_reversable {
90
    my ($self) = @_;
91
92
    my $me    = $self->_resultset()->current_source_alias . ".";
93
    my $where = {
94
        debit_id                  => { '!=' => undef },
95
        credit_id                 => { '!=' => undef },
96
        'credit.credit_type_code' => {
97
            '-not_in' => [ 'WRITEOFF', 'REFUND', 'DISCOUNT' ]
98
        },
99
        'credit.status' => [ { '!=' => 'VOID' }, undef ],
100
        $me . amount    => { '<' => 0 }
101
    };
102
    my $attr = { join => 'credit' };
103
104
    return $self->search( $where, $attr );
105
}
106
64
=head2 Internal methods
107
=head2 Internal methods
65
108
66
=head3 _type
109
=head3 _type
67
- 

Return to bug 28656