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

(-)a/Koha/Account/Line.pm (-27 / +28 lines)
Lines 128-141 sub void { Link Here
128
128
129
=head3 apply
129
=head3 apply
130
130
131
    my $outstanding_amount = $credit->apply({ debit =>  $debit, [ offset_type => $offset_type ] });
131
    my $outstanding_amount = $credit->apply({ debits =>  $debits, [ offset_type => $offset_type ] });
132
132
133
=cut
133
=cut
134
134
135
sub apply {
135
sub apply {
136
    my ( $self, $params ) = @_;
136
    my ( $self, $params ) = @_;
137
137
138
    my $debit       = $params->{debit};
138
    my $debits      = $params->{debits};
139
    my $offset_type = $params->{offset_type} // 'credit_applied';
139
    my $offset_type = $params->{offset_type} // 'credit_applied';
140
140
141
    unless ( $self->is_credit ) {
141
    unless ( $self->is_credit ) {
Lines 144-155 sub apply { Link Here
144
        );
144
        );
145
    }
145
    }
146
146
147
    unless ( $debit->is_debit ) {
148
        Koha::Exceptions::Account::IsNotDebit->throw(
149
            error => 'Account line ' . $debit->id . 'is not a debit'
150
        );
151
    }
152
153
    my $available_credit = $self->amountoutstanding * -1;
147
    my $available_credit = $self->amountoutstanding * -1;
154
148
155
    unless ( $available_credit > 0 ) {
149
    unless ( $available_credit > 0 ) {
Lines 161-190 sub apply { Link Here
161
    my $schema = Koha::Database->new->schema;
155
    my $schema = Koha::Database->new->schema;
162
156
163
    $schema->txn_do( sub {
157
    $schema->txn_do( sub {
158
        foreach my $debit ( @{ $debits } ) {
164
159
165
        my $amount_to_cancel;
160
            unless ( $debit->is_debit ) {
166
        my $owed = $debit->amountoutstanding;
161
                Koha::Exceptions::Account::IsNotDebit->throw(
167
162
                    error => 'Account line ' . $debit->id . 'is not a debit'
168
        if ( $available_credit >= $owed ) {
163
                );
169
            $amount_to_cancel = $owed;
164
            }
170
        }
165
            my $amount_to_cancel;
171
        else {    # $available_credit < $debit->amountoutstanding
166
            my $owed = $debit->amountoutstanding;
172
            $amount_to_cancel = $available_credit;
173
        }
174
167
175
        # record the account offset
168
            if ( $available_credit >= $owed ) {
176
        Koha::Account::Offset->new(
169
                $amount_to_cancel = $owed;
177
            {   credit_id => $self->id,
170
            }
178
                debit_id  => $debit->id,
171
            else {    # $available_credit < $debit->amountoutstanding
179
                amount    => $amount_to_cancel,
172
                $amount_to_cancel = $available_credit;
180
                type      => $offset_type,
181
            }
173
            }
182
        )->store();
183
174
184
        $available_credit -= $amount_to_cancel;
175
            # record the account offset
176
            Koha::Account::Offset->new(
177
                {   credit_id => $self->id,
178
                    debit_id  => $debit->id,
179
                    amount    => $amount_to_cancel,
180
                    type      => $offset_type,
181
                }
182
            )->store();
183
184
            $available_credit -= $amount_to_cancel;
185
185
186
        $self->amountoutstanding( $available_credit * -1 )->store;
186
            $self->amountoutstanding( $available_credit * -1 )->store;
187
        $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
187
            $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
188
        }
188
    });
189
    });
189
190
190
    return $available_credit;
191
    return $available_credit;
(-)a/t/db_dependent/Koha/Account/Lines.t (-7 / +39 lines)
Lines 94-100 subtest 'is_credit() and is_debit() tests' => sub { Link Here
94
94
95
subtest 'apply() tests' => sub {
95
subtest 'apply() tests' => sub {
96
96
97
    plan tests => 12;
97
    plan tests => 24;
98
98
99
    $schema->storage->txn_begin;
99
    $schema->storage->txn_begin;
100
100
Lines 122-128 subtest 'apply() tests' => sub { Link Here
122
    $credit->discard_changes;
122
    $credit->discard_changes;
123
    $debit_1->discard_changes;
123
    $debit_1->discard_changes;
124
124
125
    my $remaining_credit = $credit->apply( { debit => $debit_1, offset_type => 'Manual Credit' } );
125
    my $remaining_credit = $credit->apply( { debits => [ $debit_1 ], offset_type => 'Manual Credit' } );
126
    is( $remaining_credit, 90, 'Remaining credit is correctly calculated' );
126
    is( $remaining_credit, 90, 'Remaining credit is correctly calculated' );
127
    $credit->discard_changes;
127
    $credit->discard_changes;
128
    is( $credit->amountoutstanding * -1, $remaining_credit, 'Remaining credit correctly stored' );
128
    is( $credit->amountoutstanding * -1, $remaining_credit, 'Remaining credit correctly stored' );
Lines 137-164 subtest 'apply() tests' => sub { Link Here
137
    is( $THE_offest->amount * 1, 10, 'Amount was calculated correctly (less than the available credit)' );
137
    is( $THE_offest->amount * 1, 10, 'Amount was calculated correctly (less than the available credit)' );
138
    is( $THE_offest->type, 'Manual Credit', 'Passed type stored correctly' );
138
    is( $THE_offest->type, 'Manual Credit', 'Passed type stored correctly' );
139
139
140
    $remaining_credit = $credit->apply( { debit => $debit_2, offset_type => 'Manual Credit' } );
140
    $remaining_credit = $credit->apply( { debits => [ $debit_2 ] } );
141
    is( $remaining_credit, 0, 'No remaining credit left' );
141
    is( $remaining_credit, 0, 'No remaining credit left' );
142
    $credit->discard_changes;
142
    $credit->discard_changes;
143
    is( $credit->amountoutstanding * 1, 0, 'No outstanding credit' );
143
    is( $credit->amountoutstanding * 1, 0, 'No outstanding credit' );
144
    $debit_2->discard_changes;
144
    $debit_2->discard_changes;
145
    is( $debit_2->amountoutstanding * 1, 10, 'Outstanding amount decremented correctly' );
145
    is( $debit_2->amountoutstanding * 1, 10, 'Outstanding amount decremented correctly' );
146
146
147
    $offsets = Koha::Account::Offsets->search( { credit_id => $credit->id, debit_id => $debit_2->id } );
148
    is( $offsets->count, 1, 'Only one offset is generated' );
149
    $THE_offest = $offsets->next;
150
    is( $THE_offest->amount * 1, 10, 'Amount was calculated correctly (less than the available credit)' );
151
    is( $THE_offest->type, 'credit_applied', 'Defaults to credit_applied offset type' );
152
147
    throws_ok
153
    throws_ok
148
        { $debit_1->apply({ debit => $credit }); }
154
        { $debit_1->apply({ debits => [ $credit ] }); }
149
        'Koha::Exceptions::Account::IsNotCredit',
155
        'Koha::Exceptions::Account::IsNotCredit',
150
        '->apply() can only be used with credits';
156
        '->apply() can only be used with credits';
151
157
152
    throws_ok
158
    throws_ok
153
        { $credit->apply({ debit => $credit }); }
159
        { $credit->apply({ debits => [ $credit ] }); }
154
        'Koha::Exceptions::Account::IsNotDebit',
160
        'Koha::Exceptions::Account::IsNotDebit',
155
        '->apply() can only be applied to credits';
161
        '->apply() can only be applied to credits';
156
162
157
    throws_ok
163
    throws_ok
158
        { $credit->apply({ debit => $debit_1 }); }
164
        { $credit->apply({ debits => [ $debit_1 ] }); }
159
        'Koha::Exceptions::Account::NoAvailableCredit',
165
        'Koha::Exceptions::Account::NoAvailableCredit',
160
        '->apply() can only be used with outstanding credits';
166
        '->apply() can only be used with outstanding credits';
161
167
168
    my $credit_2 = $account->add_credit({ amount => 20 });
169
    my $debit_3  = Koha::Account::Line->new(
170
        {   borrowernumber    => $patron->id,
171
            accounttype       => "F",
172
            amount            => 100,
173
            amountoutstanding => 100
174
        }
175
    )->store;
176
177
    my $debits = Koha::Account::Lines->search({ id => { -in => [ $debit_1->id, $debit_2->id, $debit_3->id, $credit->id ] } });
178
    throws_ok {
179
        $credit_2->apply( { debits => $debits, offset_type => 'Manual Credit' } ); }
180
        'Koha::Exceptions::Account::IsNotDebit',
181
        '->apply() rolls back if any of the passed lines is not a debit';
182
183
    is( $debit_1->discard_changes->amountoutstanding,  0, 'No changes to already cancelled debit' );
184
    is( $debit_2->discard_changes->amountoutstanding,  10, 'Debit cancelled' );
185
    is( $debit_3->discard_changes->amountoutstanding,  100, 'Outstanding amount correctly calculated' );
186
    is( $credit_2->discard_changes->amountoutstanding, 20, 'No changes made' );
187
188
    $debits = Koha::Account::Lines->search({ id => { -in => [ $debit_1->id, $debit_2->id, $debit_3->id ] } });
189
    $remaining_credit = $credit_2->apply( { debits => $debits, offset_type => 'Manual Credit' } );
190
191
    is( $debit_1->discard_changes->amountoutstanding,  0, 'No changes to already cancelled debit' );
192
    is( $debit_2->discard_changes->amountoutstanding,  0, 'Debit cancelled' );
193
    is( $debit_3->discard_changes->amountoutstanding,  90, 'Outstanding amount correctly calculated' );
194
    is( $credit_2->discard_changes->amountoutstanding, 0, 'No remaining credit' );
162
195
163
    $schema->storage->txn_rollback;
196
    $schema->storage->txn_rollback;
164
};
197
};
165
- 

Return to bug 20997