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

(-)a/Koha/Patron.pm (+110 lines)
Lines 3020-3025 sub to_api { Link Here
3020
        ? Mojo::JSON->true
3020
        ? Mojo::JSON->true
3021
        : Mojo::JSON->false;
3021
        : Mojo::JSON->false;
3022
3022
3023
    $json_patron->{self_renewal_available} = $self->is_eligible_for_self_renewal();
3024
3023
    return $json_patron;
3025
    return $json_patron;
3024
}
3026
}
3025
3027
Lines 3593-3598 sub is_anonymous { Link Here
3593
    return ( $anonymous_patron && $self->borrowernumber eq $anonymous_patron ) ? 1 : 0;
3595
    return ( $anonymous_patron && $self->borrowernumber eq $anonymous_patron ) ? 1 : 0;
3594
}
3596
}
3595
3597
3598
=head3 is_eligible_for_self_renewal
3599
3600
my $eligible_for_self_renewal = $patron->is_eligible_for_self_renewal();
3601
3602
Returns a boolean value for whether self-renewal is available or not
3603
3604
=cut
3605
3606
sub is_eligible_for_self_renewal {
3607
    my ($self) = @_;
3608
3609
    my $category = $self->category;
3610
    return 0 if !$category->self_renewal_enabled;
3611
3612
    return 0 if $self->debarred;
3613
3614
    my $expiry_window =
3615
        defined $category->self_renewal_availability_start
3616
        ? $category->self_renewal_availability_start
3617
        : C4::Context->preference('NotifyBorrowerDeparture');
3618
    my $post_expiry_window = $category->self_renewal_if_expired || 0;
3619
3620
    my $expiry_date  = dt_from_string( $self->dateexpiry, undef, 'floating' );
3621
    my $window_start = dt_from_string( $self->dateexpiry, undef, 'floating' )->subtract( days => $expiry_window );
3622
    my $window_end   = dt_from_string( $self->dateexpiry, undef, 'floating' )->add( days => $post_expiry_window );
3623
    my $today        = dt_from_string( undef,             undef, 'floating' );
3624
3625
    my $within_expiry_window =
3626
        $window_start < $today->truncate( to => 'day' ) && $today < $window_end->truncate( to => 'day' );
3627
    return 0 if !$within_expiry_window;
3628
3629
    my $charges_status            = $self->is_patron_inside_charge_limits();
3630
    my $self_renewal_charge_limit = $category->self_renewal_fines_block;
3631
    foreach my $key ( keys %$charges_status ) {
3632
        my $within_renewal_limit =
3633
            ( $self_renewal_charge_limit && $self_renewal_charge_limit > $charges_status->{$key}->{charge} ) ? 1 : 0;
3634
        return 0 if $charges_status->{$key}->{overlimit} && !$within_renewal_limit;
3635
    }
3636
3637
    return 1;
3638
}
3639
3640
=head3 request_modification
3641
3642
$patron->request_modification
3643
3644
Used in the OPAC and in the patron self-renewal workflow to request a modification to a patron's account
3645
Automatically approves the request based on the AutoApprovePatronProfileSettings syspref
3646
3647
=cut
3648
3649
sub request_modification {
3650
    my ( $self, $modification ) = @_;
3651
3652
    Koha::Patron::Modifications->search( { borrowernumber => $self->borrowernumber } )->delete;
3653
3654
    $modification->{verification_token} = q{}                   if !$modification->{verification_token};
3655
    $modification->{borrowernumber}     = $self->borrowernumber if !$modification->{borrowernumber};
3656
3657
    my $patron_modification = Koha::Patron::Modification->new($modification)->store()->discard_changes;
3658
3659
    #Automatically approve patron profile changes if AutoApprovePatronProfileSettings is enabled
3660
    $patron_modification->approve() if C4::Context->preference('AutoApprovePatronProfileSettings');
3661
}
3662
3663
=head3 create_expiry_notice_parameters
3664
3665
my $letter_params = $expiring_patron->create_expiry_notice_parameters(
3666
    { letter_code => $which_notice, forceprint => $forceprint, is_notice_mandatory => $is_notice_mandatory } );
3667
3668
Returns the parameters to send an expiry notice to a patron
3669
Used by both the membership_expiry.pl cron and the self-renewal workflow
3670
3671
=cut
3672
3673
sub create_expiry_notice_parameters {
3674
    my ( $self, $args ) = @_;
3675
3676
    my $letter_code         = $args->{letter_code};
3677
    my $forceprint          = $args->{forceprint} || 0;
3678
    my $is_notice_mandatory = $args->{is_notice_mandatory};
3679
3680
    my $letter_params = {
3681
        module         => 'members',
3682
        letter_code    => $letter_code,
3683
        branchcode     => $self->branchcode,
3684
        lang           => $self->lang,
3685
        borrowernumber => $self->borrowernumber,
3686
        tables         => {
3687
            borrowers => $self->borrowernumber,
3688
            branches  => $self->branchcode,
3689
        },
3690
    };
3691
3692
    my $sending_params = {
3693
        letter_params => $letter_params,
3694
        message_name  => 'Patron_Expiry',
3695
        forceprint    => $forceprint
3696
    };
3697
3698
    if ($is_notice_mandatory) {
3699
        $sending_params->{expiry_notice_mandatory} = 1;
3700
        $sending_params->{primary_contact_method}  = $forceprint ? 'print' : $self->primary_contact_method;
3701
    }
3702
3703
    return $sending_params;
3704
}
3705
3596
=head2 Internal methods
3706
=head2 Internal methods
3597
3707
3598
=head3 _type
3708
=head3 _type
(-)a/Koha/REST/V1/Patrons/SelfRenewal.pm (+137 lines)
Line 0 Link Here
1
package Koha::REST::V1::Patrons::SelfRenewal;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <https://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Patrons;
23
use Koha::Patron::Attribute::Types;
24
25
use Try::Tiny qw( catch try );
26
use JSON      qw( to_json );
27
28
=head1 NAME
29
30
Koha::REST::V1::Patrons::SelfRenewal
31
32
=head1 API
33
34
=head2 Methods
35
36
=head3 start
37
38
Controller function that retrieves the metadata required to begin a patron self renewal
39
40
=cut
41
42
sub start {
43
    my $c = shift->openapi->valid_input or return;
44
45
    my $patron = Koha::Patrons->find( $c->param('patron_id') );
46
47
    return $c->render( status => 403, openapi => { error => "You are not eligible for self-renewal" } )
48
        if !$patron->is_eligible_for_self_renewal() || !$patron;
49
50
    return try {
51
        my $category              = $patron->category;
52
        my $self_renewal_settings = {
53
            self_renewal_failure_message     => $category->self_renewal_failure_message,
54
            self_renewal_information_message => $category->self_renewal_information_message,
55
            opac_patron_details              => C4::Context->preference('OPACPatronDetails')
56
        };
57
58
        return $c->render(
59
            status  => 200,
60
            openapi => { self_renewal_settings => $self_renewal_settings }
61
        );
62
    } catch {
63
        $c->unhandled_exception($_);
64
    };
65
}
66
67
=head3 submit
68
69
Controller function that receives the renewal request and process the renewal
70
71
=cut
72
73
sub submit {
74
    my $c = shift->openapi->valid_input or return;
75
76
    my $patron = Koha::Patrons->find( $c->param('patron_id') );
77
78
    return try {
79
        Koha::Database->new->schema->txn_do(
80
            sub {
81
                my $body = $c->req->json;
82
83
                return $c->render( status => 403, openapi => { error => "You are not eligible for self-renewal" } )
84
                    if !$patron->is_eligible_for_self_renewal() || !$patron;
85
86
                my $OPACPatronDetails = C4::Context->preference("OPACPatronDetails");
87
                if ($OPACPatronDetails) {
88
                    my $patron_details      = $body->{patron};
89
                    my $extended_attributes = delete $patron_details->{extended_attributes};
90
                    my $changed_fields      = {};
91
                    my $changes_detected;
92
                    foreach my $key ( keys %$patron_details ) {
93
                        my $submitted_value = $patron_details->{$key};
94
                        my $original_value  = $patron->$key;
95
96
                        if ( $submitted_value ne $original_value ) {
97
                            $changed_fields->{$key} = $submitted_value;
98
                            $changes_detected++;
99
                        }
100
                    }
101
                    if ($changes_detected) {
102
                        $changed_fields->{changed_fields}      = join ',', keys %$changed_fields;
103
                        $changed_fields->{extended_attributes} = to_json($extended_attributes) if $extended_attributes;
104
                        $patron->request_modification($changed_fields);
105
                    }
106
                }
107
108
                my $new_expiry_date = $patron->renew_account;
109
                my $response        = { expiry_date => $new_expiry_date };
110
111
                if ($new_expiry_date) {
112
                    my $is_notice_mandatory = $patron->category->enforce_expiry_notice;
113
                    my $letter_params       = $patron->create_expiry_notice_parameters(
114
                        {
115
                            letter_code => "MEMBERSHIP_RENEWED", is_notice_mandatory => $is_notice_mandatory,
116
                            forceprint  => 1
117
                        }
118
                    );
119
120
                    my $result = $patron->queue_notice($letter_params);
121
                    $response->{confirmation_sent} = 1 if $result->{sent};
122
                }
123
124
                return $c->render(
125
                    status  => 201,
126
                    openapi => $response
127
                );
128
            }
129
        );
130
131
    } catch {
132
        $c->unhandled_exception($_);
133
    };
134
135
}
136
137
1;
(-)a/koha-tmpl/intranet-tmpl/prog/js/fetch/patron-api-client.js (+17 lines)
Lines 25-30 export class PatronAPIClient { Link Here
25
                }),
25
                }),
26
        };
26
        };
27
    }
27
    }
28
29
    get self_renewal() {
30
        return {
31
            start: (id, query, params, headers) =>
32
                this.httpClient.getAll({
33
                    endpoint: `public/patrons/${id}/self_renewal`,
34
                    query,
35
                    params,
36
                    headers,
37
                }),
38
            submit: (id, renewal) =>
39
                this.httpClient.post({
40
                    endpoint: `public/patrons/${id}/self_renewal`,
41
                    body: renewal,
42
                }),
43
        };
44
    }
28
}
45
}
29
46
30
export default PatronAPIClient;
47
export default PatronAPIClient;
(-)a/misc/cronjobs/membership_expiry.pl (-25 / +3 lines)
Lines 285-316 while ( my $expiring_patron = $upcoming_mem_expires->next ) { Link Here
285
        $which_notice = $letter_expiry;
285
        $which_notice = $letter_expiry;
286
    }
286
    }
287
287
288
    my $from_address  = $expiring_patron->library->from_email_address;
289
    my $letter_params = {
290
        module         => 'members',
291
        letter_code    => $which_notice,
292
        branchcode     => $expiring_patron->branchcode,
293
        lang           => $expiring_patron->lang,
294
        borrowernumber => $expiring_patron->borrowernumber,
295
        tables         => {
296
            borrowers => $expiring_patron->borrowernumber,
297
            branches  => $expiring_patron->branchcode,
298
        },
299
    };
300
301
    my $sending_params = {
302
        letter_params => $letter_params,
303
        message_name  => 'Patron_Expiry',
304
        forceprint    => $forceprint
305
    };
306
307
    my $is_notice_mandatory = grep( $expiring_patron->categorycode, @mandatory_expiry_notice_categories );
288
    my $is_notice_mandatory = grep( $expiring_patron->categorycode, @mandatory_expiry_notice_categories );
308
    if ($is_notice_mandatory) {
289
    my $letter_params       = $expiring_patron->create_expiry_notice_parameters(
309
        $sending_params->{expiry_notice_mandatory} = 1;
290
        { letter_code => $which_notice, forceprint => $forceprint, is_notice_mandatory => $is_notice_mandatory } );
310
        $sending_params->{primary_contact_method}  = $forceprint ? 'print' : $expiring_patron->primary_contact_method;
311
    }
312
291
313
    my $result = $expiring_patron->queue_notice($sending_params);
292
    my $result = $expiring_patron->queue_notice($letter_params);
314
    $count_enqueued++ if $result->{sent};
293
    $count_enqueued++ if $result->{sent};
315
}
294
}
316
295
317
- 

Return to bug 26355