Lines 2351-2357
subtest 'CanBookBeIssued + AutoReturnCheckedOutItems' => sub {
Link Here
|
2351 |
|
2351 |
|
2352 |
|
2352 |
|
2353 |
subtest 'AddReturn | is_overdue' => sub { |
2353 |
subtest 'AddReturn | is_overdue' => sub { |
2354 |
plan tests => 8; |
2354 |
plan tests => 9; |
2355 |
|
2355 |
|
2356 |
t::lib::Mocks::mock_preference('MarkLostItemsAsReturned', 'batchmod|moredetail|cronjob|additem|pendingreserves|onpayment'); |
2356 |
t::lib::Mocks::mock_preference('MarkLostItemsAsReturned', 'batchmod|moredetail|cronjob|additem|pendingreserves|onpayment'); |
2357 |
t::lib::Mocks::mock_preference('CalculateFinesOnReturn', 1); |
2357 |
t::lib::Mocks::mock_preference('CalculateFinesOnReturn', 1); |
Lines 2664-2669
subtest 'AddReturn | is_overdue' => sub {
Link Here
|
2664 |
Koha::Account::Lines->search( |
2664 |
Koha::Account::Lines->search( |
2665 |
{ borrowernumber => $patron->borrowernumber } )->delete; |
2665 |
{ borrowernumber => $patron->borrowernumber } )->delete; |
2666 |
}; |
2666 |
}; |
|
|
2667 |
|
2668 |
subtest 'enh 23091 | Lost item return policies' => sub { |
2669 |
plan tests => 4; |
2670 |
|
2671 |
my $manager = $builder->build_object({ class => "Koha::Patrons" }); |
2672 |
|
2673 |
my $branchcode_false = |
2674 |
$builder->build( { source => 'Branch' } )->{branchcode}; |
2675 |
my $specific_rule_false = $builder->build( |
2676 |
{ |
2677 |
source => 'CirculationRule', |
2678 |
value => { |
2679 |
branchcode => $branchcode_false, |
2680 |
categorycode => undef, |
2681 |
itemtype => undef, |
2682 |
rule_name => 'lostreturn', |
2683 |
rule_value => 0 |
2684 |
} |
2685 |
} |
2686 |
); |
2687 |
my $branchcode_refund = |
2688 |
$builder->build( { source => 'Branch' } )->{branchcode}; |
2689 |
my $specific_rule_refund = $builder->build( |
2690 |
{ |
2691 |
source => 'CirculationRule', |
2692 |
value => { |
2693 |
branchcode => $branchcode_refund, |
2694 |
categorycode => undef, |
2695 |
itemtype => undef, |
2696 |
rule_name => 'lostreturn', |
2697 |
rule_value => 'refund' |
2698 |
} |
2699 |
} |
2700 |
); |
2701 |
my $branchcode_restore = |
2702 |
$builder->build( { source => 'Branch' } )->{branchcode}; |
2703 |
my $specific_rule_restore = $builder->build( |
2704 |
{ |
2705 |
source => 'CirculationRule', |
2706 |
value => { |
2707 |
branchcode => $branchcode_restore, |
2708 |
categorycode => undef, |
2709 |
itemtype => undef, |
2710 |
rule_name => 'lostreturn', |
2711 |
rule_value => 'restore' |
2712 |
} |
2713 |
} |
2714 |
); |
2715 |
my $branchcode_charge = |
2716 |
$builder->build( { source => 'Branch' } )->{branchcode}; |
2717 |
my $specific_rule_charge = $builder->build( |
2718 |
{ |
2719 |
source => 'CirculationRule', |
2720 |
value => { |
2721 |
branchcode => $branchcode_charge, |
2722 |
categorycode => undef, |
2723 |
itemtype => undef, |
2724 |
rule_name => 'lostreturn', |
2725 |
rule_value => 'charge' |
2726 |
} |
2727 |
} |
2728 |
); |
2729 |
|
2730 |
my $replacement_amount = 99.00; |
2731 |
t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' ); |
2732 |
t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 ); |
2733 |
t::lib::Mocks::mock_preference( 'WhenLostForgiveFine', 0 ); |
2734 |
t::lib::Mocks::mock_preference( 'BlockReturnOfLostItems', 0 ); |
2735 |
t::lib::Mocks::mock_preference( 'RefundLostOnReturnControl', |
2736 |
'CheckinLibrary' ); |
2737 |
t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge', |
2738 |
undef ); |
2739 |
|
2740 |
subtest 'lostreturn | false' => sub { |
2741 |
plan tests => 12; |
2742 |
|
2743 |
t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_false }); |
2744 |
|
2745 |
my $item = $builder->build_sample_item( |
2746 |
{ |
2747 |
replacementprice => $replacement_amount |
2748 |
} |
2749 |
); |
2750 |
|
2751 |
# Issue the item |
2752 |
my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode, $ten_days_ago ); |
2753 |
|
2754 |
# Fake fines cronjob on this checkout |
2755 |
my ($fine) = |
2756 |
CalcFine( $item, $patron->categorycode, $library->{branchcode}, |
2757 |
$ten_days_ago, $now ); |
2758 |
UpdateFine( |
2759 |
{ |
2760 |
issue_id => $issue->issue_id, |
2761 |
itemnumber => $item->itemnumber, |
2762 |
borrowernumber => $patron->borrowernumber, |
2763 |
amount => $fine, |
2764 |
due => output_pref($ten_days_ago) |
2765 |
} |
2766 |
); |
2767 |
my $overdue_fees = Koha::Account::Lines->search( |
2768 |
{ |
2769 |
borrowernumber => $patron->id, |
2770 |
itemnumber => $item->itemnumber, |
2771 |
debit_type_code => 'OVERDUE' |
2772 |
} |
2773 |
); |
2774 |
is( $overdue_fees->count, 1, 'Overdue item fee produced' ); |
2775 |
my $overdue_fee = $overdue_fees->next; |
2776 |
is( $overdue_fee->amount + 0, |
2777 |
10, 'The right OVERDUE amount is generated' ); |
2778 |
is( $overdue_fee->amountoutstanding + 0, |
2779 |
10, |
2780 |
'The right OVERDUE amountoutstanding is generated' ); |
2781 |
|
2782 |
# Simulate item marked as lost |
2783 |
$item->itemlost(3)->store; |
2784 |
C4::Circulation::LostItem( $item->itemnumber, 1 ); |
2785 |
|
2786 |
my $lost_fee_lines = Koha::Account::Lines->search( |
2787 |
{ |
2788 |
borrowernumber => $patron->id, |
2789 |
itemnumber => $item->itemnumber, |
2790 |
debit_type_code => 'LOST' |
2791 |
} |
2792 |
); |
2793 |
is( $lost_fee_lines->count, 1, 'Lost item fee produced' ); |
2794 |
my $lost_fee_line = $lost_fee_lines->next; |
2795 |
is( $lost_fee_line->amount + 0, |
2796 |
$replacement_amount, 'The right LOST amount is generated' ); |
2797 |
is( $lost_fee_line->amountoutstanding + 0, |
2798 |
$replacement_amount, |
2799 |
'The right LOST amountoutstanding is generated' ); |
2800 |
is( $lost_fee_line->status, undef, 'The LOST status was not set' ); |
2801 |
|
2802 |
# Return lost item |
2803 |
my ( $returned, $message ) = |
2804 |
AddReturn( $item->barcode, $branchcode_false, undef, $five_days_ago ); |
2805 |
|
2806 |
$overdue_fee->discard_changes; |
2807 |
is( $overdue_fee->amount + 0, |
2808 |
10, 'The OVERDUE amount is left intact' ); |
2809 |
is( $overdue_fee->amountoutstanding + 0, |
2810 |
10, |
2811 |
'The OVERDUE amountoutstanding is left intact' ); |
2812 |
|
2813 |
$lost_fee_line->discard_changes; |
2814 |
is( $lost_fee_line->amount + 0, |
2815 |
$replacement_amount, 'The LOST amount is left intact' ); |
2816 |
is( $lost_fee_line->amountoutstanding + 0, |
2817 |
$replacement_amount, |
2818 |
'The LOST amountoutstanding is left intact' ); |
2819 |
# FIXME: Should we set the LOST fee status to 'FOUND' regardless of whether we're refunding or not? |
2820 |
is( $lost_fee_line->status, undef, 'The LOST status was not set' ); |
2821 |
}; |
2822 |
|
2823 |
subtest 'lostreturn | refund' => sub { |
2824 |
plan tests => 12; |
2825 |
|
2826 |
t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_refund }); |
2827 |
|
2828 |
my $item = $builder->build_sample_item( |
2829 |
{ |
2830 |
replacementprice => $replacement_amount |
2831 |
} |
2832 |
); |
2833 |
|
2834 |
# Issue the item |
2835 |
my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode, $ten_days_ago ); |
2836 |
|
2837 |
# Fake fines cronjob on this checkout |
2838 |
my ($fine) = |
2839 |
CalcFine( $item, $patron->categorycode, $library->{branchcode}, |
2840 |
$ten_days_ago, $now ); |
2841 |
UpdateFine( |
2842 |
{ |
2843 |
issue_id => $issue->issue_id, |
2844 |
itemnumber => $item->itemnumber, |
2845 |
borrowernumber => $patron->borrowernumber, |
2846 |
amount => $fine, |
2847 |
due => output_pref($ten_days_ago) |
2848 |
} |
2849 |
); |
2850 |
my $overdue_fees = Koha::Account::Lines->search( |
2851 |
{ |
2852 |
borrowernumber => $patron->id, |
2853 |
itemnumber => $item->itemnumber, |
2854 |
debit_type_code => 'OVERDUE' |
2855 |
} |
2856 |
); |
2857 |
is( $overdue_fees->count, 1, 'Overdue item fee produced' ); |
2858 |
my $overdue_fee = $overdue_fees->next; |
2859 |
is( $overdue_fee->amount + 0, |
2860 |
10, 'The right OVERDUE amount is generated' ); |
2861 |
is( $overdue_fee->amountoutstanding + 0, |
2862 |
10, |
2863 |
'The right OVERDUE amountoutstanding is generated' ); |
2864 |
|
2865 |
# Simulate item marked as lost |
2866 |
$item->itemlost(3)->store; |
2867 |
C4::Circulation::LostItem( $item->itemnumber, 1 ); |
2868 |
|
2869 |
my $lost_fee_lines = Koha::Account::Lines->search( |
2870 |
{ |
2871 |
borrowernumber => $patron->id, |
2872 |
itemnumber => $item->itemnumber, |
2873 |
debit_type_code => 'LOST' |
2874 |
} |
2875 |
); |
2876 |
is( $lost_fee_lines->count, 1, 'Lost item fee produced' ); |
2877 |
my $lost_fee_line = $lost_fee_lines->next; |
2878 |
is( $lost_fee_line->amount + 0, |
2879 |
$replacement_amount, 'The right LOST amount is generated' ); |
2880 |
is( $lost_fee_line->amountoutstanding + 0, |
2881 |
$replacement_amount, |
2882 |
'The right LOST amountoutstanding is generated' ); |
2883 |
is( $lost_fee_line->status, undef, 'The LOST status was not set' ); |
2884 |
|
2885 |
# Return the lost item |
2886 |
my ( undef, $message ) = |
2887 |
AddReturn( $item->barcode, $branchcode_refund, undef, $five_days_ago ); |
2888 |
|
2889 |
$overdue_fee->discard_changes; |
2890 |
is( $overdue_fee->amount + 0, |
2891 |
10, 'The OVERDUE amount is left intact' ); |
2892 |
is( $overdue_fee->amountoutstanding + 0, |
2893 |
10, |
2894 |
'The OVERDUE amountoutstanding is left intact' ); |
2895 |
|
2896 |
$lost_fee_line->discard_changes; |
2897 |
is( $lost_fee_line->amount + 0, |
2898 |
$replacement_amount, 'The LOST amount is left intact' ); |
2899 |
is( $lost_fee_line->amountoutstanding + 0, |
2900 |
0, |
2901 |
'The LOST amountoutstanding is refunded' ); |
2902 |
is( $lost_fee_line->status, 'FOUND', 'The LOST status was set to FOUND' ); |
2903 |
}; |
2904 |
|
2905 |
subtest 'lostreturn | restore' => sub { |
2906 |
plan tests => 13; |
2907 |
|
2908 |
t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_restore }); |
2909 |
|
2910 |
my $item = $builder->build_sample_item( |
2911 |
{ |
2912 |
replacementprice => $replacement_amount |
2913 |
} |
2914 |
); |
2915 |
|
2916 |
# Issue the item |
2917 |
my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode , $ten_days_ago); |
2918 |
|
2919 |
# Fake fines cronjob on this checkout |
2920 |
my ($fine) = |
2921 |
CalcFine( $item, $patron->categorycode, $library->{branchcode}, |
2922 |
$ten_days_ago, $now ); |
2923 |
UpdateFine( |
2924 |
{ |
2925 |
issue_id => $issue->issue_id, |
2926 |
itemnumber => $item->itemnumber, |
2927 |
borrowernumber => $patron->borrowernumber, |
2928 |
amount => $fine, |
2929 |
due => output_pref($ten_days_ago) |
2930 |
} |
2931 |
); |
2932 |
my $overdue_fees = Koha::Account::Lines->search( |
2933 |
{ |
2934 |
borrowernumber => $patron->id, |
2935 |
itemnumber => $item->itemnumber, |
2936 |
debit_type_code => 'OVERDUE' |
2937 |
} |
2938 |
); |
2939 |
is( $overdue_fees->count, 1, 'Overdue item fee produced' ); |
2940 |
my $overdue_fee = $overdue_fees->next; |
2941 |
is( $overdue_fee->amount + 0, |
2942 |
10, 'The right OVERDUE amount is generated' ); |
2943 |
is( $overdue_fee->amountoutstanding + 0, |
2944 |
10, |
2945 |
'The right OVERDUE amountoutstanding is generated' ); |
2946 |
|
2947 |
# Simulate item marked as lost |
2948 |
$item->itemlost(3)->store; |
2949 |
C4::Circulation::LostItem( $item->itemnumber, 1 ); |
2950 |
|
2951 |
my $lost_fee_lines = Koha::Account::Lines->search( |
2952 |
{ |
2953 |
borrowernumber => $patron->id, |
2954 |
itemnumber => $item->itemnumber, |
2955 |
debit_type_code => 'LOST' |
2956 |
} |
2957 |
); |
2958 |
is( $lost_fee_lines->count, 1, 'Lost item fee produced' ); |
2959 |
my $lost_fee_line = $lost_fee_lines->next; |
2960 |
is( $lost_fee_line->amount + 0, |
2961 |
$replacement_amount, 'The right LOST amount is generated' ); |
2962 |
is( $lost_fee_line->amountoutstanding + 0, |
2963 |
$replacement_amount, |
2964 |
'The right LOST amountoutstanding is generated' ); |
2965 |
is( $lost_fee_line->status, undef, 'The LOST status was not set' ); |
2966 |
|
2967 |
# Simulate refunding overdue fees upon marking item as lost |
2968 |
my $overdue_forgive = $patron->account->add_credit( |
2969 |
{ |
2970 |
amount => 10.00, |
2971 |
user_id => $manager->borrowernumber, |
2972 |
library_id => $branchcode_restore, |
2973 |
interface => 'test', |
2974 |
type => 'FORGIVEN', |
2975 |
item_id => $item->itemnumber |
2976 |
} |
2977 |
); |
2978 |
$overdue_forgive->apply( |
2979 |
{ debits => [$overdue_fee], offset_type => 'Forgiven' } ); |
2980 |
$overdue_fee->discard_changes; |
2981 |
is($overdue_fee->amountoutstanding + 0, 0, 'Overdue fee forgiven'); |
2982 |
|
2983 |
# Do nothing |
2984 |
my ( undef, $message ) = |
2985 |
AddReturn( $item->barcode, $branchcode_restore, undef, $five_days_ago ); |
2986 |
|
2987 |
$overdue_fee->discard_changes; |
2988 |
is( $overdue_fee->amount + 0, |
2989 |
10, 'The OVERDUE amount is left intact' ); |
2990 |
is( $overdue_fee->amountoutstanding + 0, |
2991 |
10, |
2992 |
'The OVERDUE amountoutstanding is restored' ); |
2993 |
|
2994 |
$lost_fee_line->discard_changes; |
2995 |
is( $lost_fee_line->amount + 0, |
2996 |
$replacement_amount, 'The LOST amount is left intact' ); |
2997 |
is( $lost_fee_line->amountoutstanding + 0, |
2998 |
0, |
2999 |
'The LOST amountoutstanding is refunded' ); |
3000 |
is( $lost_fee_line->status, 'FOUND', 'The LOST status was set to FOUND' ); |
3001 |
}; |
3002 |
|
3003 |
subtest 'lostreturn | charge' => sub { |
3004 |
plan tests => 16; |
3005 |
|
3006 |
t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_charge }); |
3007 |
|
3008 |
my $item = $builder->build_sample_item( |
3009 |
{ |
3010 |
replacementprice => $replacement_amount |
3011 |
} |
3012 |
); |
3013 |
|
3014 |
# Issue the item |
3015 |
my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode, $ten_days_ago ); |
3016 |
|
3017 |
# Fake fines cronjob on this checkout |
3018 |
my ($fine) = |
3019 |
CalcFine( $item, $patron->categorycode, $library->{branchcode}, |
3020 |
$ten_days_ago, $now ); |
3021 |
UpdateFine( |
3022 |
{ |
3023 |
issue_id => $issue->issue_id, |
3024 |
itemnumber => $item->itemnumber, |
3025 |
borrowernumber => $patron->borrowernumber, |
3026 |
amount => $fine, |
3027 |
due => output_pref($ten_days_ago) |
3028 |
} |
3029 |
); |
3030 |
my $overdue_fees = Koha::Account::Lines->search( |
3031 |
{ |
3032 |
borrowernumber => $patron->id, |
3033 |
itemnumber => $item->itemnumber, |
3034 |
debit_type_code => 'OVERDUE' |
3035 |
} |
3036 |
); |
3037 |
is( $overdue_fees->count, 1, 'Overdue item fee produced' ); |
3038 |
my $overdue_fee = $overdue_fees->next; |
3039 |
is( $overdue_fee->amount + 0, |
3040 |
10, 'The right OVERDUE amount is generated' ); |
3041 |
is( $overdue_fee->amountoutstanding + 0, |
3042 |
10, |
3043 |
'The right OVERDUE amountoutstanding is generated' ); |
3044 |
|
3045 |
# Simulate item marked as lost |
3046 |
$item->itemlost(3)->store; |
3047 |
C4::Circulation::LostItem( $item->itemnumber, 1 ); |
3048 |
|
3049 |
my $lost_fee_lines = Koha::Account::Lines->search( |
3050 |
{ |
3051 |
borrowernumber => $patron->id, |
3052 |
itemnumber => $item->itemnumber, |
3053 |
debit_type_code => 'LOST' |
3054 |
} |
3055 |
); |
3056 |
is( $lost_fee_lines->count, 1, 'Lost item fee produced' ); |
3057 |
my $lost_fee_line = $lost_fee_lines->next; |
3058 |
is( $lost_fee_line->amount + 0, |
3059 |
$replacement_amount, 'The right LOST amount is generated' ); |
3060 |
is( $lost_fee_line->amountoutstanding + 0, |
3061 |
$replacement_amount, |
3062 |
'The right LOST amountoutstanding is generated' ); |
3063 |
is( $lost_fee_line->status, undef, 'The LOST status was not set' ); |
3064 |
|
3065 |
# Simulate refunding overdue fees upon marking item as lost |
3066 |
my $overdue_forgive = $patron->account->add_credit( |
3067 |
{ |
3068 |
amount => 10.00, |
3069 |
user_id => $manager->borrowernumber, |
3070 |
library_id => $branchcode_charge, |
3071 |
interface => 'test', |
3072 |
type => 'FORGIVEN', |
3073 |
item_id => $item->itemnumber |
3074 |
} |
3075 |
); |
3076 |
$overdue_forgive->apply( |
3077 |
{ debits => [$overdue_fee], offset_type => 'Forgiven' } ); |
3078 |
$overdue_fee->discard_changes; |
3079 |
is($overdue_fee->amountoutstanding + 0, 0, 'Overdue fee forgiven'); |
3080 |
|
3081 |
# Do nothing |
3082 |
my ( undef, $message ) = |
3083 |
AddReturn( $item->barcode, $branchcode_charge, undef, $five_days_ago ); |
3084 |
|
3085 |
$lost_fee_line->discard_changes; |
3086 |
is( $lost_fee_line->amount + 0, |
3087 |
$replacement_amount, 'The LOST amount is left intact' ); |
3088 |
is( $lost_fee_line->amountoutstanding + 0, |
3089 |
0, |
3090 |
'The LOST amountoutstanding is refunded' ); |
3091 |
is( $lost_fee_line->status, 'FOUND', 'The LOST status was set to FOUND' ); |
3092 |
|
3093 |
$overdue_fees = Koha::Account::Lines->search( |
3094 |
{ |
3095 |
borrowernumber => $patron->id, |
3096 |
itemnumber => $item->itemnumber, |
3097 |
debit_type_code => 'OVERDUE' |
3098 |
}, |
3099 |
{ |
3100 |
order_by => { '-asc' => 'accountlines_id'} |
3101 |
} |
3102 |
); |
3103 |
is( $overdue_fees->count, 2, 'A second OVERDUE fee has been added' ); |
3104 |
$overdue_fee = $overdue_fees->next; |
3105 |
is( $overdue_fee->amount + 0, |
3106 |
10, 'The original OVERDUE amount is left intact' ); |
3107 |
is( $overdue_fee->amountoutstanding + 0, |
3108 |
0, |
3109 |
'The original OVERDUE amountoutstanding is left as forgiven' ); |
3110 |
$overdue_fee = $overdue_fees->next; |
3111 |
is( $overdue_fee->amount + 0, |
3112 |
5, 'The new OVERDUE amount is correct for the backdated return' ); |
3113 |
is( $overdue_fee->amountoutstanding + 0, |
3114 |
5, |
3115 |
'The new OVERDUE amountoutstanding is correct for the backdated return' ); |
3116 |
}; |
3117 |
}; |
2667 |
}; |
3118 |
}; |
2668 |
|
3119 |
|
2669 |
subtest '_FixOverduesOnReturn' => sub { |
3120 |
subtest '_FixOverduesOnReturn' => sub { |
2670 |
- |
|
|