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

(-)a/t/db_dependent/Circulation.t (-434 / +1 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
use utf8;
19
use utf8;
20
20
21
use Test::More tests => 50;
21
use Test::More tests => 48;
22
use Test::Exception;
22
use Test::Exception;
23
use Test::MockModule;
23
use Test::MockModule;
24
use Test::Deep qw( cmp_deeply );
24
use Test::Deep qw( cmp_deeply );
Lines 2669-3065 subtest 'AddReturn | is_overdue' => sub { Link Here
2669
    };
2669
    };
2670
};
2670
};
2671
2671
2672
subtest '_FixAccountForLostAndFound' => sub {
2673
2674
    plan tests => 5;
2675
2676
    t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
2677
    t::lib::Mocks::mock_preference( 'WhenLostForgiveFine',          0 );
2678
2679
    my $processfee_amount  = 20;
2680
    my $replacement_amount = 99.00;
2681
    my $item_type          = $builder->build_object(
2682
        {   class => 'Koha::ItemTypes',
2683
            value => {
2684
                notforloan         => undef,
2685
                rentalcharge       => 0,
2686
                defaultreplacecost => undef,
2687
                processfee         => $processfee_amount,
2688
                rentalcharge_daily => 0,
2689
            }
2690
        }
2691
    );
2692
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
2693
2694
    my $biblio = $builder->build_sample_biblio({ author => 'Hall, Daria' });
2695
2696
    subtest 'Full write-off tests' => sub {
2697
2698
        plan tests => 12;
2699
2700
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2701
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
2702
        t::lib::Mocks::mock_userenv({ patron => $manager,branchcode => $manager->branchcode });
2703
2704
        my $item = $builder->build_sample_item(
2705
            {
2706
                biblionumber     => $biblio->biblionumber,
2707
                library          => $library->branchcode,
2708
                replacementprice => $replacement_amount,
2709
                itype            => $item_type->itemtype,
2710
            }
2711
        );
2712
2713
        AddIssue( $patron->unblessed, $item->barcode );
2714
2715
        # Simulate item marked as lost
2716
        $item->itemlost(3)->store;
2717
        LostItem( $item->itemnumber, 1 );
2718
2719
        my $processing_fee_lines = Koha::Account::Lines->search(
2720
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } );
2721
        is( $processing_fee_lines->count, 1, 'Only one processing fee produced' );
2722
        my $processing_fee_line = $processing_fee_lines->next;
2723
        is( $processing_fee_line->amount + 0,
2724
            $processfee_amount, 'The right PROCESSING amount is generated' );
2725
        is( $processing_fee_line->amountoutstanding + 0,
2726
            $processfee_amount, 'The right PROCESSING amountoutstanding is generated' );
2727
2728
        my $lost_fee_lines = Koha::Account::Lines->search(
2729
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } );
2730
        is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
2731
        my $lost_fee_line = $lost_fee_lines->next;
2732
        is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' );
2733
        is( $lost_fee_line->amountoutstanding + 0,
2734
            $replacement_amount, 'The right LOST amountoutstanding is generated' );
2735
        is( $lost_fee_line->status,
2736
            undef, 'The LOST status was not set' );
2737
2738
        my $account = $patron->account;
2739
        my $debts   = $account->outstanding_debits;
2740
2741
        # Write off the debt
2742
        my $credit = $account->add_credit(
2743
            {   amount => $account->balance,
2744
                type   => 'WRITEOFF',
2745
                interface => 'test',
2746
            }
2747
        );
2748
        $credit->apply( { debits => [ $debts->as_list ], offset_type => 'Writeoff' } );
2749
2750
        my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
2751
        is( $credit_return_id, undef, 'No LOST_FOUND account line added' );
2752
2753
        $lost_fee_line->discard_changes; # reload from DB
2754
        is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' );
2755
        is( $lost_fee_line->debit_type_code,
2756
            'LOST', 'Lost fee now still has account type of LOST' );
2757
        is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND");
2758
2759
        is( $patron->account->balance, -0, 'The patron balance is 0, everything was written off' );
2760
    };
2761
2762
    subtest 'Full payment tests' => sub {
2763
2764
        plan tests => 13;
2765
2766
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2767
2768
        my $item = $builder->build_sample_item(
2769
            {
2770
                biblionumber     => $biblio->biblionumber,
2771
                library          => $library->branchcode,
2772
                replacementprice => $replacement_amount,
2773
                itype            => $item_type->itemtype
2774
            }
2775
        );
2776
2777
        AddIssue( $patron->unblessed, $item->barcode );
2778
2779
        # Simulate item marked as lost
2780
        $item->itemlost(1)->store;
2781
        LostItem( $item->itemnumber, 1 );
2782
2783
        my $processing_fee_lines = Koha::Account::Lines->search(
2784
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } );
2785
        is( $processing_fee_lines->count, 1, 'Only one processing fee produced' );
2786
        my $processing_fee_line = $processing_fee_lines->next;
2787
        is( $processing_fee_line->amount + 0,
2788
            $processfee_amount, 'The right PROCESSING amount is generated' );
2789
        is( $processing_fee_line->amountoutstanding + 0,
2790
            $processfee_amount, 'The right PROCESSING amountoutstanding is generated' );
2791
2792
        my $lost_fee_lines = Koha::Account::Lines->search(
2793
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } );
2794
        is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
2795
        my $lost_fee_line = $lost_fee_lines->next;
2796
        is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' );
2797
        is( $lost_fee_line->amountoutstanding + 0,
2798
            $replacement_amount, 'The right LOST amountountstanding is generated' );
2799
2800
        my $account = $patron->account;
2801
        my $debts   = $account->outstanding_debits;
2802
2803
        # Write off the debt
2804
        my $credit = $account->add_credit(
2805
            {   amount => $account->balance,
2806
                type   => 'PAYMENT',
2807
                interface => 'test',
2808
            }
2809
        );
2810
        $credit->apply( { debits => [ $debts->as_list ], offset_type => 'Payment' } );
2811
2812
        my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
2813
        my $credit_return = Koha::Account::Lines->find($credit_return_id);
2814
2815
        is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' );
2816
        is( $credit_return->amount + 0,
2817
            -99.00, 'The account line of type LOST_FOUND has an amount of -99' );
2818
        is( $credit_return->amountoutstanding + 0,
2819
            -99.00, 'The account line of type LOST_FOUND has an amountoutstanding of -99' );
2820
2821
        $lost_fee_line->discard_changes;
2822
        is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' );
2823
        is( $lost_fee_line->debit_type_code,
2824
            'LOST', 'Lost fee now still has account type of LOST' );
2825
        is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND");
2826
2827
        is( $patron->account->balance,
2828
            -99, 'The patron balance is -99, a credit that equals the lost fee payment' );
2829
    };
2830
2831
    subtest 'Test without payment or write off' => sub {
2832
2833
        plan tests => 13;
2834
2835
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2836
2837
        my $item = $builder->build_sample_item(
2838
            {
2839
                biblionumber     => $biblio->biblionumber,
2840
                library          => $library->branchcode,
2841
                replacementprice => 23.00,
2842
                replacementprice => $replacement_amount,
2843
                itype            => $item_type->itemtype
2844
            }
2845
        );
2846
2847
        AddIssue( $patron->unblessed, $item->barcode );
2848
2849
        # Simulate item marked as lost
2850
        $item->itemlost(3)->store;
2851
        LostItem( $item->itemnumber, 1 );
2852
2853
        my $processing_fee_lines = Koha::Account::Lines->search(
2854
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } );
2855
        is( $processing_fee_lines->count, 1, 'Only one processing fee produced' );
2856
        my $processing_fee_line = $processing_fee_lines->next;
2857
        is( $processing_fee_line->amount + 0,
2858
            $processfee_amount, 'The right PROCESSING amount is generated' );
2859
        is( $processing_fee_line->amountoutstanding + 0,
2860
            $processfee_amount, 'The right PROCESSING amountoutstanding is generated' );
2861
2862
        my $lost_fee_lines = Koha::Account::Lines->search(
2863
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } );
2864
        is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
2865
        my $lost_fee_line = $lost_fee_lines->next;
2866
        is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' );
2867
        is( $lost_fee_line->amountoutstanding + 0,
2868
            $replacement_amount, 'The right LOST amountountstanding is generated' );
2869
2870
        my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
2871
        my $credit_return = Koha::Account::Lines->find($credit_return_id);
2872
2873
        is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' );
2874
        is( $credit_return->amount + 0, -99.00, 'The account line of type LOST_FOUND has an amount of -99' );
2875
        is( $credit_return->amountoutstanding + 0, 0, 'The account line of type LOST_FOUND has an amountoutstanding of 0' );
2876
2877
        $lost_fee_line->discard_changes;
2878
        is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' );
2879
        is( $lost_fee_line->debit_type_code,
2880
            'LOST', 'Lost fee now still has account type of LOST' );
2881
        is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND");
2882
2883
        is( $patron->account->balance, 20, 'The patron balance is 20, still owes the processing fee' );
2884
    };
2885
2886
    subtest 'Test with partial payement and write off, and remaining debt' => sub {
2887
2888
        plan tests => 16;
2889
2890
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2891
        my $item = $builder->build_sample_item(
2892
            {
2893
                biblionumber     => $biblio->biblionumber,
2894
                library          => $library->branchcode,
2895
                replacementprice => $replacement_amount,
2896
                itype            => $item_type->itemtype
2897
            }
2898
        );
2899
2900
        AddIssue( $patron->unblessed, $item->barcode );
2901
2902
        # Simulate item marked as lost
2903
        $item->itemlost(1)->store;
2904
        LostItem( $item->itemnumber, 1 );
2905
2906
        my $processing_fee_lines = Koha::Account::Lines->search(
2907
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'PROCESSING' } );
2908
        is( $processing_fee_lines->count, 1, 'Only one processing fee produced' );
2909
        my $processing_fee_line = $processing_fee_lines->next;
2910
        is( $processing_fee_line->amount + 0,
2911
            $processfee_amount, 'The right PROCESSING amount is generated' );
2912
        is( $processing_fee_line->amountoutstanding + 0,
2913
            $processfee_amount, 'The right PROCESSING amountoutstanding is generated' );
2914
2915
        my $lost_fee_lines = Koha::Account::Lines->search(
2916
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } );
2917
        is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
2918
        my $lost_fee_line = $lost_fee_lines->next;
2919
        is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' );
2920
        is( $lost_fee_line->amountoutstanding + 0,
2921
            $replacement_amount, 'The right LOST amountountstanding is generated' );
2922
2923
        my $account = $patron->account;
2924
        is( $account->balance, $processfee_amount + $replacement_amount, 'Balance is PROCESSING + L' );
2925
2926
        # Partially pay fee
2927
        my $payment_amount = 27;
2928
        my $payment        = $account->add_credit(
2929
            {   amount => $payment_amount,
2930
                type   => 'PAYMENT',
2931
                interface => 'test',
2932
            }
2933
        );
2934
2935
        $payment->apply( { debits => [ $lost_fee_line ], offset_type => 'Payment' } );
2936
2937
        # Partially write off fee
2938
        my $write_off_amount = 25;
2939
        my $write_off        = $account->add_credit(
2940
            {   amount => $write_off_amount,
2941
                type   => 'WRITEOFF',
2942
                interface => 'test',
2943
            }
2944
        );
2945
        $write_off->apply( { debits => [ $lost_fee_line ], offset_type => 'Writeoff' } );
2946
2947
        is( $account->balance,
2948
            $processfee_amount + $replacement_amount - $payment_amount - $write_off_amount,
2949
            'Payment and write off applied'
2950
        );
2951
2952
        # Store the amountoutstanding value
2953
        $lost_fee_line->discard_changes;
2954
        my $outstanding = $lost_fee_line->amountoutstanding;
2955
2956
        my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
2957
        my $credit_return = Koha::Account::Lines->find($credit_return_id);
2958
2959
        is( $account->balance, $processfee_amount - $payment_amount, 'Balance is PROCESSING - PAYMENT (LOST_FOUND)' );
2960
2961
        $lost_fee_line->discard_changes;
2962
        is( $lost_fee_line->amountoutstanding + 0, 0, 'Lost fee has no outstanding amount' );
2963
        is( $lost_fee_line->debit_type_code,
2964
            'LOST', 'Lost fee now still has account type of LOST' );
2965
        is( $lost_fee_line->status, 'FOUND', "Lost fee now has account status of FOUND");
2966
2967
        is( $credit_return->credit_type_code, 'LOST_FOUND', 'An account line of type LOST_FOUND is added' );
2968
        is( $credit_return->amount + 0,
2969
            ($payment_amount + $outstanding ) * -1,
2970
            'The account line of type LOST_FOUND has an amount equal to the payment + outstanding'
2971
        );
2972
        is( $credit_return->amountoutstanding + 0,
2973
            $payment_amount * -1,
2974
            'The account line of type LOST_FOUND has an amountoutstanding equal to the payment'
2975
        );
2976
2977
        is( $account->balance,
2978
            $processfee_amount - $payment_amount,
2979
            'The patron balance is the difference between the PROCESSING and the credit'
2980
        );
2981
    };
2982
2983
    subtest 'Partial payement, existing debits and AccountAutoReconcile' => sub {
2984
2985
        plan tests => 8;
2986
2987
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2988
        my $barcode = 'KD123456793';
2989
        my $replacement_amount = 100;
2990
        my $processfee_amount  = 20;
2991
2992
        my $item_type          = $builder->build_object(
2993
            {   class => 'Koha::ItemTypes',
2994
                value => {
2995
                    notforloan         => undef,
2996
                    rentalcharge       => 0,
2997
                    defaultreplacecost => undef,
2998
                    processfee         => 0,
2999
                    rentalcharge_daily => 0,
3000
                }
3001
            }
3002
        );
3003
        my $item = Koha::Item->new(
3004
            {
3005
                biblionumber     => $biblio->biblionumber,
3006
                homebranch       => $library->branchcode,
3007
                holdingbranch    => $library->branchcode,
3008
                barcode          => $barcode,
3009
                replacementprice => $replacement_amount,
3010
                itype            => $item_type->itemtype
3011
            },
3012
        )->store;
3013
3014
        AddIssue( $patron->unblessed, $barcode );
3015
3016
        # Simulate item marked as lost
3017
        $item->itemlost(1)->store;
3018
        LostItem( $item->itemnumber, 1 );
3019
3020
        my $lost_fee_lines = Koha::Account::Lines->search(
3021
            { borrowernumber => $patron->id, itemnumber => $item->itemnumber, debit_type_code => 'LOST' } );
3022
        is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
3023
        my $lost_fee_line = $lost_fee_lines->next;
3024
        is( $lost_fee_line->amount + 0, $replacement_amount, 'The right LOST amount is generated' );
3025
        is( $lost_fee_line->amountoutstanding + 0,
3026
            $replacement_amount, 'The right LOST amountountstanding is generated' );
3027
3028
        my $account = $patron->account;
3029
        is( $account->balance, $replacement_amount, 'Balance is L' );
3030
3031
        # Partially pay fee
3032
        my $payment_amount = 27;
3033
        my $payment        = $account->add_credit(
3034
            {   amount => $payment_amount,
3035
                type   => 'PAYMENT',
3036
                interface => 'test',
3037
            }
3038
        );
3039
        $payment->apply({ debits => [ $lost_fee_line ], offset_type => 'Payment' });
3040
3041
        is( $account->balance,
3042
            $replacement_amount - $payment_amount,
3043
            'Payment applied'
3044
        );
3045
3046
        my $manual_debit_amount = 80;
3047
        $account->add_debit( { amount => $manual_debit_amount, type => 'OVERDUE', interface =>'test' } );
3048
3049
        is( $account->balance, $manual_debit_amount + $replacement_amount - $payment_amount, 'Manual debit applied' );
3050
3051
        t::lib::Mocks::mock_preference( 'AccountAutoReconcile', 1 );
3052
3053
        my $credit_return_id = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
3054
        my $credit_return = Koha::Account::Lines->find($credit_return_id);
3055
3056
        is( $account->balance, $manual_debit_amount - $payment_amount, 'Balance is PROCESSING - payment (LOST_FOUND)' );
3057
3058
        my $manual_debit = Koha::Account::Lines->search({ borrowernumber => $patron->id, debit_type_code => 'OVERDUE', status => 'UNRETURNED' })->next;
3059
        is( $manual_debit->amountoutstanding + 0, $manual_debit_amount - $payment_amount, 'reconcile_balance was called' );
3060
    };
3061
};
3062
3063
subtest '_FixOverduesOnReturn' => sub {
2672
subtest '_FixOverduesOnReturn' => sub {
3064
    plan tests => 14;
2673
    plan tests => 14;
3065
2674
Lines 3145-3192 subtest '_FixOverduesOnReturn' => sub { Link Here
3145
    is( $accountline->status, 'RETURNED', 'Passed status has been used to set as RETURNED )');
2754
    is( $accountline->status, 'RETURNED', 'Passed status has been used to set as RETURNED )');
3146
};
2755
};
3147
2756
3148
subtest '_FixAccountForLostAndFound returns undef if patron is deleted' => sub {
3149
    plan tests => 1;
3150
3151
    my $manager = $builder->build_object({ class => "Koha::Patrons" });
3152
    t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $manager->branchcode });
3153
3154
    my $biblio = $builder->build_sample_biblio({ author => 'Hall, Kylie' });
3155
3156
    my $branchcode  = $library2->{branchcode};
3157
3158
    my $item = $builder->build_sample_item(
3159
        {
3160
            biblionumber     => $biblio->biblionumber,
3161
            library          => $branchcode,
3162
            replacementprice => 99.00,
3163
            itype            => $itemtype,
3164
        }
3165
    );
3166
3167
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
3168
3169
    ## Start with basic call, should just close out the open fine
3170
    my $accountline = Koha::Account::Line->new(
3171
        {
3172
            borrowernumber => $patron->id,
3173
            debit_type_code    => 'LOST',
3174
            status         => undef,
3175
            itemnumber     => $item->itemnumber,
3176
            amount => 99.00,
3177
            amountoutstanding => 99.00,
3178
            interface => 'test',
3179
        }
3180
    )->store();
3181
3182
    $patron->delete();
3183
3184
    my $return_value = C4::Circulation::_FixAccountForLostAndFound( $item->itemnumber );
3185
3186
    is( $return_value, undef, "_FixAccountForLostAndFound returns undef if patron is deleted" );
3187
3188
};
3189
3190
subtest 'Set waiting flag' => sub {
2757
subtest 'Set waiting flag' => sub {
3191
    plan tests => 11;
2758
    plan tests => 11;
3192
2759
(-)a/t/db_dependent/Koha/Items.t (-11 / +640 lines)
Lines 65-88 my $retrieved_item_1 = Koha::Items->find( $new_item_1->itemnumber ); Link Here
65
is( $retrieved_item_1->barcode, $new_item_1->barcode, 'Find a item by id should return the correct item' );
65
is( $retrieved_item_1->barcode, $new_item_1->barcode, 'Find a item by id should return the correct item' );
66
66
67
subtest 'store' => sub {
67
subtest 'store' => sub {
68
    plan tests => 5;
68
    plan tests => 6;
69
69
70
    my $biblio = $builder->build_sample_biblio;
70
    my $biblio = $builder->build_sample_biblio;
71
    my $today = dt_from_string->set( hour => 0, minute => 0, second => 0 );
71
    my $today  = dt_from_string->set( hour => 0, minute => 0, second => 0 );
72
    my $item = Koha::Item->new(
72
    my $item   = Koha::Item->new(
73
        {
73
        {
74
            homebranch    => $library->{branchcode},
74
            homebranch    => $library->{branchcode},
75
            holdingbranch => $library->{branchcode},
75
            holdingbranch => $library->{branchcode},
76
            biblionumber  => $biblio->biblionumber,
76
            biblionumber  => $biblio->biblionumber,
77
            location      => 'my_loc',
77
            location      => 'my_loc',
78
        }
78
        }
79
    )->store
79
    )->store->get_from_storage;
80
    ->get_from_storage;
80
81
81
    is( t::lib::Dates::compare( $item->replacementpricedate, $today ),
82
    is( t::lib::Dates::compare($item->replacementpricedate, $today), 0, 'replacementpricedate must have been set to today if not given');
82
        0, 'replacementpricedate must have been set to today if not given' );
83
    is( t::lib::Dates::compare($item->datelastseen,         $today), 0, 'datelastseen must have been set to today if not given');
83
    is( t::lib::Dates::compare( $item->datelastseen, $today ),
84
    is( $item->itype, $biblio->biblioitem->itemtype, 'items.itype must have been set to biblioitem.itemtype is not given');
84
        0, 'datelastseen must have been set to today if not given' );
85
    is( $item->permanent_location, $item->location, 'permanent_location must have been set to location if not given' );
85
    is(
86
        $item->itype,
87
        $biblio->biblioitem->itemtype,
88
        'items.itype must have been set to biblioitem.itemtype is not given'
89
    );
90
    is( $item->permanent_location, $item->location,
91
        'permanent_location must have been set to location if not given' );
86
    $item->delete;
92
    $item->delete;
87
93
88
    subtest '*_on updates' => sub {
94
    subtest '*_on updates' => sub {
Lines 129-134 subtest 'store' => sub { Link Here
129
        }
135
        }
130
    };
136
    };
131
137
138
    subtest '_lost_found_trigger' => sub {
139
        plan tests => 6;
140
141
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
142
        t::lib::Mocks::mock_preference( 'WhenLostForgiveFine',          0 );
143
144
        my $processfee_amount  = 20;
145
        my $replacement_amount = 99.00;
146
        my $item_type          = $builder->build_object(
147
            {
148
                class => 'Koha::ItemTypes',
149
                value => {
150
                    notforloan         => undef,
151
                    rentalcharge       => 0,
152
                    defaultreplacecost => undef,
153
                    processfee         => $processfee_amount,
154
                    rentalcharge_daily => 0,
155
                }
156
            }
157
        );
158
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
159
160
        $biblio = $builder->build_sample_biblio( { author => 'Hall, Daria' } );
161
162
        subtest 'Full write-off tests' => sub {
163
164
            plan tests => 12;
165
166
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
167
            my $manager =
168
              $builder->build_object( { class => "Koha::Patrons" } );
169
            t::lib::Mocks::mock_userenv(
170
                { patron => $manager, branchcode => $manager->branchcode } );
171
172
            my $item = $builder->build_sample_item(
173
                {
174
                    biblionumber     => $biblio->biblionumber,
175
                    library          => $library->branchcode,
176
                    replacementprice => $replacement_amount,
177
                    itype            => $item_type->itemtype,
178
                }
179
            );
180
181
            C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
182
183
            # Simulate item marked as lost
184
            $item->itemlost(3)->store;
185
            C4::Circulation::LostItem( $item->itemnumber, 1 );
186
187
            my $processing_fee_lines = Koha::Account::Lines->search(
188
                {
189
                    borrowernumber  => $patron->id,
190
                    itemnumber      => $item->itemnumber,
191
                    debit_type_code => 'PROCESSING'
192
                }
193
            );
194
            is( $processing_fee_lines->count,
195
                1, 'Only one processing fee produced' );
196
            my $processing_fee_line = $processing_fee_lines->next;
197
            is( $processing_fee_line->amount + 0,
198
                $processfee_amount,
199
                'The right PROCESSING amount is generated' );
200
            is( $processing_fee_line->amountoutstanding + 0,
201
                $processfee_amount,
202
                'The right PROCESSING amountoutstanding is generated' );
203
204
            my $lost_fee_lines = Koha::Account::Lines->search(
205
                {
206
                    borrowernumber  => $patron->id,
207
                    itemnumber      => $item->itemnumber,
208
                    debit_type_code => 'LOST'
209
                }
210
            );
211
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
212
            my $lost_fee_line = $lost_fee_lines->next;
213
            is( $lost_fee_line->amount + 0,
214
                $replacement_amount, 'The right LOST amount is generated' );
215
            is( $lost_fee_line->amountoutstanding + 0,
216
                $replacement_amount,
217
                'The right LOST amountoutstanding is generated' );
218
            is( $lost_fee_line->status, undef, 'The LOST status was not set' );
219
220
            my $account = $patron->account;
221
            my $debts   = $account->outstanding_debits;
222
223
            # Write off the debt
224
            my $credit = $account->add_credit(
225
                {
226
                    amount    => $account->balance,
227
                    type      => 'WRITEOFF',
228
                    interface => 'test',
229
                }
230
            );
231
            $credit->apply(
232
                { debits => [ $debts->as_list ], offset_type => 'Writeoff' } );
233
234
            # Simulate item marked as found
235
            $item->itemlost(0)->store;
236
            is( $item->{_refunded}, undef, 'No LOST_FOUND account line added' );
237
238
            $lost_fee_line->discard_changes;    # reload from DB
239
            is( $lost_fee_line->amountoutstanding + 0,
240
                0, 'Lost fee has no outstanding amount' );
241
            is( $lost_fee_line->debit_type_code,
242
                'LOST', 'Lost fee now still has account type of LOST' );
243
            is( $lost_fee_line->status, 'FOUND',
244
                "Lost fee now has account status of FOUND - No Refund" );
245
246
            is( $patron->account->balance,
247
                -0, 'The patron balance is 0, everything was written off' );
248
        };
249
250
        subtest 'Full payment tests' => sub {
251
252
            plan tests => 14;
253
254
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
255
256
            my $item = $builder->build_sample_item(
257
                {
258
                    biblionumber     => $biblio->biblionumber,
259
                    library          => $library->branchcode,
260
                    replacementprice => $replacement_amount,
261
                    itype            => $item_type->itemtype
262
                }
263
            );
264
265
            my $issue =
266
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
267
268
            # Simulate item marked as lost
269
            $item->itemlost(1)->store;
270
            C4::Circulation::LostItem( $item->itemnumber, 1 );
271
272
            my $processing_fee_lines = Koha::Account::Lines->search(
273
                {
274
                    borrowernumber  => $patron->id,
275
                    itemnumber      => $item->itemnumber,
276
                    debit_type_code => 'PROCESSING'
277
                }
278
            );
279
            is( $processing_fee_lines->count,
280
                1, 'Only one processing fee produced' );
281
            my $processing_fee_line = $processing_fee_lines->next;
282
            is( $processing_fee_line->amount + 0,
283
                $processfee_amount,
284
                'The right PROCESSING amount is generated' );
285
            is( $processing_fee_line->amountoutstanding + 0,
286
                $processfee_amount,
287
                'The right PROCESSING amountoutstanding is generated' );
288
289
            my $lost_fee_lines = Koha::Account::Lines->search(
290
                {
291
                    borrowernumber  => $patron->id,
292
                    itemnumber      => $item->itemnumber,
293
                    debit_type_code => 'LOST'
294
                }
295
            );
296
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
297
            my $lost_fee_line = $lost_fee_lines->next;
298
            is( $lost_fee_line->amount + 0,
299
                $replacement_amount, 'The right LOST amount is generated' );
300
            is( $lost_fee_line->amountoutstanding + 0,
301
                $replacement_amount,
302
                'The right LOST amountountstanding is generated' );
303
304
            my $account = $patron->account;
305
            my $debts   = $account->outstanding_debits;
306
307
            # Pay off the debt
308
            my $credit = $account->add_credit(
309
                {
310
                    amount    => $account->balance,
311
                    type      => 'PAYMENT',
312
                    interface => 'test',
313
                }
314
            );
315
            $credit->apply(
316
                { debits => [ $debts->as_list ], offset_type => 'Payment' } );
317
318
            # Simulate item marked as found
319
            $item->itemlost(0)->store;
320
            is( $item->{_refunded}, 1, 'Refund triggered' );
321
322
            my $credit_return = Koha::Account::Lines->search(
323
                {
324
                    itemnumber       => $item->itemnumber,
325
                    credit_type_code => 'LOST_FOUND'
326
                },
327
                { rows => 1 }
328
            )->single;
329
330
            ok( $credit_return, 'An account line of type LOST_FOUND is added' );
331
            is( $credit_return->amount + 0,
332
                -99.00,
333
                'The account line of type LOST_FOUND has an amount of -99' );
334
            is(
335
                $credit_return->amountoutstanding + 0,
336
                -99.00,
337
'The account line of type LOST_FOUND has an amountoutstanding of -99'
338
            );
339
340
            $lost_fee_line->discard_changes;
341
            is( $lost_fee_line->amountoutstanding + 0,
342
                0, 'Lost fee has no outstanding amount' );
343
            is( $lost_fee_line->debit_type_code,
344
                'LOST', 'Lost fee now still has account type of LOST' );
345
            is( $lost_fee_line->status, 'FOUND',
346
                "Lost fee now has account status of FOUND" );
347
348
            is( $patron->account->balance, -99,
349
'The patron balance is -99, a credit that equals the lost fee payment'
350
            );
351
        };
352
353
        subtest 'Test without payment or write off' => sub {
354
355
            plan tests => 14;
356
357
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
358
359
            my $item = $builder->build_sample_item(
360
                {
361
                    biblionumber     => $biblio->biblionumber,
362
                    library          => $library->branchcode,
363
                    replacementprice => 23.00,
364
                    replacementprice => $replacement_amount,
365
                    itype            => $item_type->itemtype
366
                }
367
            );
368
369
            my $issue =
370
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
371
372
            # Simulate item marked as lost
373
            $item->itemlost(3)->store;
374
            C4::Circulation::LostItem( $item->itemnumber, 1 );
375
376
            my $processing_fee_lines = Koha::Account::Lines->search(
377
                {
378
                    borrowernumber  => $patron->id,
379
                    itemnumber      => $item->itemnumber,
380
                    debit_type_code => 'PROCESSING'
381
                }
382
            );
383
            is( $processing_fee_lines->count,
384
                1, 'Only one processing fee produced' );
385
            my $processing_fee_line = $processing_fee_lines->next;
386
            is( $processing_fee_line->amount + 0,
387
                $processfee_amount,
388
                'The right PROCESSING amount is generated' );
389
            is( $processing_fee_line->amountoutstanding + 0,
390
                $processfee_amount,
391
                'The right PROCESSING amountoutstanding is generated' );
392
393
            my $lost_fee_lines = Koha::Account::Lines->search(
394
                {
395
                    borrowernumber  => $patron->id,
396
                    itemnumber      => $item->itemnumber,
397
                    debit_type_code => 'LOST'
398
                }
399
            );
400
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
401
            my $lost_fee_line = $lost_fee_lines->next;
402
            is( $lost_fee_line->amount + 0,
403
                $replacement_amount, 'The right LOST amount is generated' );
404
            is( $lost_fee_line->amountoutstanding + 0,
405
                $replacement_amount,
406
                'The right LOST amountountstanding is generated' );
407
408
            # Simulate item marked as found
409
            $item->itemlost(0)->store;
410
            is( $item->{_refunded}, 1, 'Refund triggered' );
411
412
            my $credit_return = Koha::Account::Lines->search(
413
                {
414
                    itemnumber       => $item->itemnumber,
415
                    credit_type_code => 'LOST_FOUND'
416
                },
417
                { rows => 1 }
418
            )->single;
419
420
            ok( $credit_return, 'An account line of type LOST_FOUND is added' );
421
            is( $credit_return->amount + 0,
422
                -99.00,
423
                'The account line of type LOST_FOUND has an amount of -99' );
424
            is(
425
                $credit_return->amountoutstanding + 0,
426
                0,
427
'The account line of type LOST_FOUND has an amountoutstanding of 0'
428
            );
429
430
            $lost_fee_line->discard_changes;
431
            is( $lost_fee_line->amountoutstanding + 0,
432
                0, 'Lost fee has no outstanding amount' );
433
            is( $lost_fee_line->debit_type_code,
434
                'LOST', 'Lost fee now still has account type of LOST' );
435
            is( $lost_fee_line->status, 'FOUND',
436
                "Lost fee now has account status of FOUND" );
437
438
            is( $patron->account->balance,
439
                20, 'The patron balance is 20, still owes the processing fee' );
440
        };
441
442
        subtest
443
          'Test with partial payement and write off, and remaining debt' =>
444
          sub {
445
446
            plan tests => 17;
447
448
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
449
            my $item = $builder->build_sample_item(
450
                {
451
                    biblionumber     => $biblio->biblionumber,
452
                    library          => $library->branchcode,
453
                    replacementprice => $replacement_amount,
454
                    itype            => $item_type->itemtype
455
                }
456
            );
457
458
            my $issue =
459
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
460
461
            # Simulate item marked as lost
462
            $item->itemlost(1)->store;
463
            C4::Circulation::LostItem( $item->itemnumber, 1 );
464
465
            my $processing_fee_lines = Koha::Account::Lines->search(
466
                {
467
                    borrowernumber  => $patron->id,
468
                    itemnumber      => $item->itemnumber,
469
                    debit_type_code => 'PROCESSING'
470
                }
471
            );
472
            is( $processing_fee_lines->count,
473
                1, 'Only one processing fee produced' );
474
            my $processing_fee_line = $processing_fee_lines->next;
475
            is( $processing_fee_line->amount + 0,
476
                $processfee_amount,
477
                'The right PROCESSING amount is generated' );
478
            is( $processing_fee_line->amountoutstanding + 0,
479
                $processfee_amount,
480
                'The right PROCESSING amountoutstanding is generated' );
481
482
            my $lost_fee_lines = Koha::Account::Lines->search(
483
                {
484
                    borrowernumber  => $patron->id,
485
                    itemnumber      => $item->itemnumber,
486
                    debit_type_code => 'LOST'
487
                }
488
            );
489
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
490
            my $lost_fee_line = $lost_fee_lines->next;
491
            is( $lost_fee_line->amount + 0,
492
                $replacement_amount, 'The right LOST amount is generated' );
493
            is( $lost_fee_line->amountoutstanding + 0,
494
                $replacement_amount,
495
                'The right LOST amountountstanding is generated' );
496
497
            my $account = $patron->account;
498
            is(
499
                $account->balance,
500
                $processfee_amount + $replacement_amount,
501
                'Balance is PROCESSING + L'
502
            );
503
504
            # Partially pay fee
505
            my $payment_amount = 27;
506
            my $payment        = $account->add_credit(
507
                {
508
                    amount    => $payment_amount,
509
                    type      => 'PAYMENT',
510
                    interface => 'test',
511
                }
512
            );
513
514
            $payment->apply(
515
                { debits => [$lost_fee_line], offset_type => 'Payment' } );
516
517
            # Partially write off fee
518
            my $write_off_amount = 25;
519
            my $write_off        = $account->add_credit(
520
                {
521
                    amount    => $write_off_amount,
522
                    type      => 'WRITEOFF',
523
                    interface => 'test',
524
                }
525
            );
526
            $write_off->apply(
527
                { debits => [$lost_fee_line], offset_type => 'Writeoff' } );
528
529
            is(
530
                $account->balance,
531
                $processfee_amount +
532
                  $replacement_amount -
533
                  $payment_amount -
534
                  $write_off_amount,
535
                'Payment and write off applied'
536
            );
537
538
            # Store the amountoutstanding value
539
            $lost_fee_line->discard_changes;
540
            my $outstanding = $lost_fee_line->amountoutstanding;
541
542
            # Simulate item marked as found
543
            $item->itemlost(0)->store;
544
            is( $item->{_refunded}, 1, 'Refund triggered' );
545
546
            my $credit_return = Koha::Account::Lines->search(
547
                {
548
                    itemnumber       => $item->itemnumber,
549
                    credit_type_code => 'LOST_FOUND'
550
                },
551
                { rows => 1 }
552
            )->single;
553
554
            ok( $credit_return, 'An account line of type LOST_FOUND is added' );
555
556
            is(
557
                $account->balance,
558
                $processfee_amount - $payment_amount,
559
                'Balance is PROCESSING - PAYMENT (LOST_FOUND)'
560
            );
561
562
            $lost_fee_line->discard_changes;
563
            is( $lost_fee_line->amountoutstanding + 0,
564
                0, 'Lost fee has no outstanding amount' );
565
            is( $lost_fee_line->debit_type_code,
566
                'LOST', 'Lost fee now still has account type of LOST' );
567
            is( $lost_fee_line->status, 'FOUND',
568
                "Lost fee now has account status of FOUND" );
569
570
            is(
571
                $credit_return->amount + 0,
572
                ( $payment_amount + $outstanding ) * -1,
573
'The account line of type LOST_FOUND has an amount equal to the payment + outstanding'
574
            );
575
            is(
576
                $credit_return->amountoutstanding + 0,
577
                $payment_amount * -1,
578
'The account line of type LOST_FOUND has an amountoutstanding equal to the payment'
579
            );
580
581
            is(
582
                $account->balance,
583
                $processfee_amount - $payment_amount,
584
'The patron balance is the difference between the PROCESSING and the credit'
585
            );
586
          };
587
588
        subtest 'Partial payment, existing debits and AccountAutoReconcile' =>
589
          sub {
590
591
            plan tests => 10;
592
593
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
594
            my $barcode            = 'KD123456793';
595
            my $replacement_amount = 100;
596
            my $processfee_amount  = 20;
597
598
            my $item_type = $builder->build_object(
599
                {
600
                    class => 'Koha::ItemTypes',
601
                    value => {
602
                        notforloan         => undef,
603
                        rentalcharge       => 0,
604
                        defaultreplacecost => undef,
605
                        processfee         => 0,
606
                        rentalcharge_daily => 0,
607
                    }
608
                }
609
            );
610
            my $item = Koha::Item->new(
611
                {
612
                    biblionumber     => $biblio->biblionumber,
613
                    homebranch       => $library->branchcode,
614
                    holdingbranch    => $library->branchcode,
615
                    barcode          => $barcode,
616
                    replacementprice => $replacement_amount,
617
                    itype            => $item_type->itemtype
618
                },
619
            )->store;
620
621
            my $issue =
622
              C4::Circulation::AddIssue( $patron->unblessed, $barcode );
623
624
            # Simulate item marked as lost
625
            $item->itemlost(1)->store;
626
            C4::Circulation::LostItem( $item->itemnumber, 1 );
627
628
            my $lost_fee_lines = Koha::Account::Lines->search(
629
                {
630
                    borrowernumber  => $patron->id,
631
                    itemnumber      => $item->itemnumber,
632
                    debit_type_code => 'LOST'
633
                }
634
            );
635
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
636
            my $lost_fee_line = $lost_fee_lines->next;
637
            is( $lost_fee_line->amount + 0,
638
                $replacement_amount, 'The right LOST amount is generated' );
639
            is( $lost_fee_line->amountoutstanding + 0,
640
                $replacement_amount,
641
                'The right LOST amountountstanding is generated' );
642
643
            my $account = $patron->account;
644
            is( $account->balance, $replacement_amount, 'Balance is L' );
645
646
            # Partially pay fee
647
            my $payment_amount = 27;
648
            my $payment        = $account->add_credit(
649
                {
650
                    amount    => $payment_amount,
651
                    type      => 'PAYMENT',
652
                    interface => 'test',
653
                }
654
            );
655
            $payment->apply(
656
                { debits => [$lost_fee_line], offset_type => 'Payment' } );
657
658
            is(
659
                $account->balance,
660
                $replacement_amount - $payment_amount,
661
                'Payment applied'
662
            );
663
664
            my $manual_debit_amount = 80;
665
            $account->add_debit(
666
                {
667
                    amount    => $manual_debit_amount,
668
                    type      => 'OVERDUE',
669
                    interface => 'test'
670
                }
671
            );
672
673
            is(
674
                $account->balance,
675
                $manual_debit_amount + $replacement_amount - $payment_amount,
676
                'Manual debit applied'
677
            );
678
679
            t::lib::Mocks::mock_preference( 'AccountAutoReconcile', 1 );
680
681
            # Simulate item marked as found
682
            $item->itemlost(0)->store;
683
            is( $item->{_refunded}, 1, 'Refund triggered' );
684
685
            my $credit_return = Koha::Account::Lines->search(
686
                {
687
                    itemnumber       => $item->itemnumber,
688
                    credit_type_code => 'LOST_FOUND'
689
                },
690
                { rows => 1 }
691
            )->single;
692
693
            ok( $credit_return, 'An account line of type LOST_FOUND is added' );
694
695
            is(
696
                $account->balance,
697
                $manual_debit_amount - $payment_amount,
698
                'Balance is PROCESSING - payment (LOST_FOUND)'
699
            );
700
701
            my $manual_debit = Koha::Account::Lines->search(
702
                {
703
                    borrowernumber  => $patron->id,
704
                    debit_type_code => 'OVERDUE',
705
                    status          => 'UNRETURNED'
706
                }
707
            )->next;
708
            is(
709
                $manual_debit->amountoutstanding + 0,
710
                $manual_debit_amount - $payment_amount,
711
                'reconcile_balance was called'
712
            );
713
          };
714
715
        subtest 'Patron deleted' => sub {
716
            plan tests => 1;
717
718
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
719
            my $barcode            = 'KD123456794';
720
            my $replacement_amount = 100;
721
            my $processfee_amount  = 20;
722
723
            my $item_type = $builder->build_object(
724
                {
725
                    class => 'Koha::ItemTypes',
726
                    value => {
727
                        notforloan         => undef,
728
                        rentalcharge       => 0,
729
                        defaultreplacecost => undef,
730
                        processfee         => 0,
731
                        rentalcharge_daily => 0,
732
                    }
733
                }
734
            );
735
            my $item = Koha::Item->new(
736
                {
737
                    biblionumber     => $biblio->biblionumber,
738
                    homebranch       => $library->branchcode,
739
                    holdingbranch    => $library->branchcode,
740
                    barcode          => $barcode,
741
                    replacementprice => $replacement_amount,
742
                    itype            => $item_type->itemtype
743
                },
744
            )->store;
745
746
            my $issue =
747
              C4::Circulation::AddIssue( $patron->unblessed, $barcode );
748
749
            # Simulate item marked as lost
750
            $item->itemlost(1)->store;
751
            C4::Circulation::LostItem( $item->itemnumber, 1 );
752
753
            $issue->delete();
754
            $patron->delete();
755
756
            # Simulate item marked as found
757
            $item->itemlost(0)->store;
758
            is( $item->{_refunded}, undef, 'No refund triggered' );
759
760
        };
761
    };
132
};
762
};
133
763
134
subtest 'get_transfer' => sub {
764
subtest 'get_transfer' => sub {
135
- 

Return to bug 18501