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

Return to bug 18501