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

(-)a/Koha/Checkout.pm (-1 / +44 lines)
Lines 21-29 package Koha::Checkout; Link Here
21
use Modern::Perl;
21
use Modern::Perl;
22
22
23
use Carp;
23
use Carp;
24
use DateTime;
24
25
26
use Koha::Checkouts::ReturnClaims;
25
use Koha::Database;
27
use Koha::Database;
26
use DateTime;
27
use Koha::DateUtils;
28
use Koha::DateUtils;
28
use Koha::Items;
29
use Koha::Items;
29
30
Lines 88-93 sub patron { Link Here
88
    return Koha::Patron->_new_from_dbic( $patron_rs );
89
    return Koha::Patron->_new_from_dbic( $patron_rs );
89
}
90
}
90
91
92
=head3 claim_returned
93
94
my $return_claim = $checkout->claim_returned();
95
96
=cut
97
98
sub claim_returned {
99
    my ( $self, $params ) = @_;
100
101
    my $notes           = $params->{notes};
102
    my $charge_lost_fee = $params->{charge_lost_fee};
103
    my $created_by      = $params->{created_by};
104
105
    $created_by ||= C4::Context->userenv->{number} if C4::Context->userenv;
106
107
    my $claim = Koha::Checkouts::ReturnClaims->find( { issue_id => $self->id } );
108
    $claim ||= Koha::Checkouts::ReturnClaims->find( { old_issue_id => $self->id } );
109
110
    $claim ||= Koha::Checkouts::ReturnClaim->new(
111
        {
112
            issue_id       => $self->id,
113
            itemnumber     => $self->itemnumber,
114
            borrowernumber => $self->borrowernumber,
115
            notes          => $notes,
116
            created_on     => dt_from_string,
117
            created_by     => $created_by,
118
        }
119
    )->store();
120
121
    my $ClaimReturnedLostValue = C4::Context->preference('ClaimReturnedLostValue');
122
    C4::Items::ModItem( { itemlost => $ClaimReturnedLostValue }, undef, $self->itemnumber );
123
124
    my $ClaimReturnedChargeFee = C4::Context->preference('ClaimReturnedChargeFee');
125
    $charge_lost_fee =
126
        $ClaimReturnedChargeFee eq 'charge'    ? 1
127
      : $ClaimReturnedChargeFee eq 'no_charge' ? 0
128
      :   $charge_lost_fee;    # $ClaimReturnedChargeFee eq 'ask'
129
    C4::Circulation::LostItem( $self->itemnumber, 'claim_returned' ) if $charge_lost_fee;
130
131
    return $claim;
132
}
133
91
=head3 type
134
=head3 type
92
135
93
=cut
136
=cut
(-)a/Koha/Checkouts/ReturnClaim.pm (+65 lines)
Line 0 Link Here
1
package Koha::Checkouts::ReturnClaim;
2
3
# Copyright ByWater Solutions 2019
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use base qw(Koha::Object);
23
24
use Koha::Checkouts;
25
use Koha::Old::Checkouts;
26
27
=head1 NAME
28
29
Koha::Checkouts::ReturnClaim - Koha ReturnClaim object class
30
31
=head1 API
32
33
=head2 Class Methods
34
35
=cut
36
37
=head3 checkout
38
39
=cut
40
41
sub checkout {
42
    my ( $self ) = @_;
43
44
    my $issue = $self->_result->issue;
45
    return Koha::Checkout->_new_from_dbic( $issue ) if $issue;
46
47
    my $old_issue = $self->_result->old_issue;
48
    return Koha::Old::Checkout->_new_from_dbic( $old_issue ) if $old_issue;
49
}
50
51
=head3 _type
52
53
=cut
54
55
sub _type {
56
    return 'ReturnClaim';
57
}
58
59
=head1 AUTHOR
60
61
Kyle M Hall <kyle@bywatersolutions.com>
62
63
=cut
64
65
1;
(-)a/Koha/Checkouts/ReturnClaims.pm (+86 lines)
Line 0 Link Here
1
package Koha::Checkouts::ReturnClaims;
2
3
# Copyright ByWater Solutions 2019
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use Koha::Database;
25
26
use Koha::Checkouts::ReturnClaim;
27
28
use base qw(Koha::Objects);
29
30
=head1 NAME
31
32
Koha::Checkouts::ReturnClaims - Koha ReturnClaim object set class
33
34
=head1 API
35
36
=head2 Class Methods
37
38
=cut
39
40
=head3 unresolved
41
42
=cut
43
44
sub unresolved {
45
    my ($self) = @_;
46
47
    my $results = $self->_resultset()->search_rs( { resolved_on => undef } );
48
49
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $results );
50
}
51
52
=head3 resolved
53
54
=cut
55
56
sub resolved {
57
    my ($self) = @_;
58
59
    my $results = $self->_resultset()->search_rs( { resolved_on => { '!=' => undef } } );
60
61
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $results );
62
}
63
64
=head3 type
65
66
=cut
67
68
sub _type {
69
    return 'ReturnClaim';
70
}
71
72
=head3 object_class
73
74
=cut
75
76
sub object_class {
77
    return 'Koha::Checkouts::ReturnClaim';
78
}
79
80
=head1 AUTHOR
81
82
Kyle M Hall <kyle@bywatersolutions.com>
83
84
=cut
85
86
1;
(-)a/Koha/Patron.pm (+12 lines)
Lines 1041-1046 sub old_holds { Link Here
1041
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1041
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1042
}
1042
}
1043
1043
1044
=head3 return_claims
1045
1046
my $return_claims = $patron->return_claims
1047
1048
=cut
1049
1050
sub return_claims {
1051
    my ($self) = @_;
1052
    my $return_claims = $self->_result->return_claims_borrowernumbers;
1053
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1054
}
1055
1044
=head3 notice_email_address
1056
=head3 notice_email_address
1045
1057
1046
  my $email = $patron->notice_email_address;
1058
  my $email = $patron->notice_email_address;
(-)a/Koha/REST/V1/ReturnClaims.pm (+212 lines)
Line 0 Link Here
1
package Koha::REST::V1::ReturnClaims;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Checkouts::ReturnClaims;
23
use Koha::Checkouts;
24
use Koha::DateUtils qw( dt_from_string output_pref );
25
26
=head1 NAME
27
28
Koha::REST::V1::ReturnClaims
29
30
=head2 Operations
31
32
=head3 claim_returned
33
34
Claim that a checked out item was returned.
35
36
=cut
37
38
sub claim_returned {
39
    my $c     = shift->openapi->valid_input or return;
40
    my $input = $c->validation->output;
41
    my $body  = $c->validation->param('body');
42
43
    my $itemnumber      = $input->{item_id};
44
    my $charge_lost_fee = $body->{charge_lost_fee} ? 1 : 0;
45
    my $created_by      = $body->{created_by};
46
    my $notes           = $body->{notes};
47
48
    my $checkout = Koha::Checkouts->find( { itemnumber => $itemnumber } );
49
50
    return $c->render(
51
        openapi => { error => "Not found - Checkout not found" },
52
        status  => 404
53
    ) unless $checkout;
54
55
    my $claim = Koha::Checkouts::ReturnClaims->find(
56
        {
57
            issue_id => $checkout->id
58
        }
59
    );
60
    return $c->render(
61
        openapi => { error => "Bad request - claim exists" },
62
        status  => 400
63
    ) if $claim;
64
65
    $claim = $checkout->claim_returned(
66
        {
67
            charge_lost_fee => $charge_lost_fee,
68
            created_by      => $created_by,
69
            notes           => $notes,
70
        }
71
    );
72
73
    my $data = $claim->unblessed;
74
75
    my $c_dt = dt_from_string( $data->{created_on} );
76
    my $u_dt = dt_from_string( $data->{updated_on} );
77
78
    $data->{created_on_formatted} = output_pref( { dt => $c_dt } );
79
    $data->{updated_on_formatted} = output_pref( { dt => $u_dt } );
80
81
    $data->{created_on} = $c_dt->iso8601;
82
    $data->{updated_on} = $u_dt->iso8601;
83
84
    return $c->render( openapi => $data, status => 200 );
85
}
86
87
=head3 update_notes
88
89
Update the notes of an existing claim
90
91
=cut
92
93
sub update_notes {
94
    my $c     = shift->openapi->valid_input or return;
95
    my $input = $c->validation->output;
96
    my $body  = $c->validation->param('body');
97
98
    my $id         = $input->{claim_id};
99
    my $updated_by = $body->{updated_by};
100
    my $notes      = $body->{notes};
101
102
    $updated_by ||=
103
      C4::Context->userenv ? C4::Context->userenv->{number} : undef;
104
105
    my $claim = Koha::Checkouts::ReturnClaims->find($id);
106
107
    return $c->render(
108
        openapi => { error => "Not found - Claim not found" },
109
        status  => 404
110
    ) unless $claim;
111
112
    $claim->set(
113
        {
114
            notes      => $notes,
115
            updated_by => $updated_by,
116
            updated_on => dt_from_string(),
117
        }
118
    );
119
    $claim->store();
120
121
    my $data = $claim->unblessed;
122
123
    my $c_dt = dt_from_string( $data->{created_on} );
124
    my $u_dt = dt_from_string( $data->{updated_on} );
125
126
    $data->{created_on_formatted} = output_pref( { dt => $c_dt } );
127
    $data->{updated_on_formatted} = output_pref( { dt => $u_dt } );
128
129
    $data->{created_on} = $c_dt->iso8601;
130
    $data->{updated_on} = $u_dt->iso8601;
131
132
    return $c->render( openapi => $data, status => 200 );
133
}
134
135
=head3 resolve_claim
136
137
Marks a claim as resolved
138
139
=cut
140
141
sub resolve_claim {
142
    my $c     = shift->openapi->valid_input or return;
143
    my $input = $c->validation->output;
144
    my $body  = $c->validation->param('body');
145
146
    my $id          = $input->{claim_id};
147
    my $resolved_by = $body->{updated_by};
148
    my $resolution  = $body->{resolution};
149
150
    $resolved_by ||=
151
      C4::Context->userenv ? C4::Context->userenv->{number} : undef;
152
153
    my $claim = Koha::Checkouts::ReturnClaims->find($id);
154
155
    return $c->render(
156
        openapi => { error => "Not found - Claim not found" },
157
        status  => 404
158
    ) unless $claim;
159
160
    $claim->set(
161
        {
162
            resolution  => $resolution,
163
            resolved_by => $resolved_by,
164
            resolved_on => dt_from_string(),
165
        }
166
    );
167
    $claim->store();
168
169
    my $data = $claim->unblessed;
170
171
    my $c_dt = dt_from_string( $data->{created_on} );
172
    my $u_dt = dt_from_string( $data->{updated_on} );
173
    my $r_dt = dt_from_string( $data->{resolved_on} );
174
175
    $data->{created_on_formatted}  = output_pref( { dt => $c_dt } );
176
    $data->{updated_on_formatted}  = output_pref( { dt => $u_dt } );
177
    $data->{resolved_on_formatted} = output_pref( { dt => $r_dt } );
178
179
    $data->{created_on}  = $c_dt->iso8601;
180
    $data->{updated_on}  = $u_dt->iso8601;
181
    $data->{resolved_on} = $r_dt->iso8601;
182
183
    return $c->render( openapi => $data, status => 200 );
184
}
185
186
=head3 delete_claim
187
188
Deletes the claim from the database
189
190
=cut
191
192
sub delete_claim {
193
    my $c     = shift->openapi->valid_input or return;
194
    my $input = $c->validation->output;
195
196
    my $id         = $input->{claim_id};
197
198
    my $claim = Koha::Checkouts::ReturnClaims->find($id);
199
200
    return $c->render(
201
        openapi => { error => "Not found - Claim not found" },
202
        status  => 404
203
    ) unless $claim;
204
205
    $claim->delete();
206
207
    my $data = $claim->unblessed;
208
209
    return $c->render( openapi => $data, status => 200 );
210
}
211
212
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 40-44 Link Here
40
  },
40
  },
41
  "fund": {
41
  "fund": {
42
    "$ref": "definitions/fund.json"
42
    "$ref": "definitions/fund.json"
43
  },
44
  "return_claim": {
45
    "$ref": "definitions/return_claim.json"
43
  }
46
  }
44
}
47
}
(-)a/api/v1/swagger/definitions/return_claim.json (+90 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "id": {
5
      "type": [
6
        "integer"
7
      ],
8
      "description": "internally assigned return claim identifier"
9
    },
10
    "item_id": {
11
      "type": [
12
        "integer"
13
      ],
14
      "description": "internal identifier of the claimed item"
15
    },
16
    "issue_id": {
17
      "type": [
18
        "integer",
19
        "null"
20
      ],
21
      "description": "internal identifier of the claimed checkout if still checked out"
22
    },
23
    "old_issue_id": {
24
      "type": [
25
        "integer",
26
        "null"
27
      ],
28
      "description": "internal identifier of the claimed checkout if not longer checked out"
29
    },
30
    "patron_id": {
31
      "$ref": "../x-primitives.json#/patron_id"
32
    },
33
    "notes": {
34
      "type": [
35
        "string",
36
        "null"
37
      ],
38
      "description": "notes about this claim"
39
    },
40
    "created_on": {
41
      "type": [
42
        "string",
43
        "null"
44
      ],
45
      "description": "date of claim creation"
46
    },
47
    "created_by": {
48
      "type": [
49
        "integer",
50
        "null"
51
      ],
52
      "description": "patron id of librarian who made the claim"
53
    },
54
    "updated_on": {
55
      "type": [
56
        "string",
57
        "null"
58
      ],
59
      "description": "date the claim was last updated"
60
    },
61
    "updated_by": {
62
      "type": [
63
        "integer",
64
        "null"
65
      ],
66
      "description": "patron id of librarian who last updated the claim"
67
    },
68
    "resolution": {
69
      "type": [
70
        "string",
71
        "null"
72
      ],
73
      "description": "code of resolution type for this claim"
74
    },
75
    "resolved_on": {
76
      "type": [
77
        "string",
78
        "null"
79
      ],
80
      "description": "date the claim was resolved"
81
    },
82
    "resolved_by": {
83
      "type": [
84
        "integer",
85
        "null"
86
      ],
87
      "description": "patron id of librarian who resolved this claim"
88
    }
89
  }
90
}
(-)a/api/v1/swagger/paths.json (+12 lines)
Lines 70-74 Link Here
70
  },
70
  },
71
  "/public/patrons/{patron_id}/password": {
71
  "/public/patrons/{patron_id}/password": {
72
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1password"
72
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1password"
73
  },
74
  "/return_claims/claim/{item_id}/": {
75
    "$ref": "paths/return_claims.json#/~1return_claims~1claim~1{item_id}"
76
  },
77
  "/return_claims/{claim_id}/notes": {
78
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}~1notes"
79
  },
80
  "/return_claims/{claim_id}/resolve": {
81
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}~1resolve"
82
  },
83
  "/return_claims/{claim_id}": {
84
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}"
73
  }
85
  }
74
}
86
}
(-)a/api/v1/swagger/paths/return_claims.json (+358 lines)
Line 0 Link Here
1
{
2
  "/return_claims/claim/{item_id}": {
3
    "post": {
4
      "x-mojo-to": "ReturnClaims#claim_returned",
5
      "operationId": "claimReturned",
6
      "tags": [
7
        "claims",
8
        "returned",
9
        "return",
10
        "claim"
11
      ],
12
      "parameters": [
13
        {
14
          "name": "item_id",
15
          "in": "path",
16
          "required": true,
17
          "description": "Itemnumber of item to claim as returned",
18
          "type": "integer"
19
        },
20
        {
21
          "name": "body",
22
          "in": "body",
23
          "description": "A JSON object containing fields to modify",
24
          "required": true,
25
          "schema": {
26
            "type": "object",
27
            "properties": {
28
              "notes": {
29
                "description": "Notes about this return claim",
30
                "type": "string"
31
              },
32
              "created_by": {
33
                "description": "User id for the librarian submitting this claim",
34
                "type": "string"
35
              },
36
              "charge_lost_fee": {
37
                "description": "Charge a lost fee if true and Koha is set to allow a choice. Ignored otherwise.",
38
                "type": "boolean"
39
              }
40
            }
41
          }
42
        }
43
      ],
44
      "produces": [
45
        "application/json"
46
      ],
47
      "responses": {
48
        "200": {
49
          "description": "Created claim",
50
          "schema": {
51
            "$ref": "../definitions.json#/return_claim"
52
          }
53
        },
54
        "400": {
55
          "description": "Bad request",
56
          "schema": {
57
            "$ref": "../definitions.json#/error"
58
          }
59
        },
60
        "401": {
61
          "description": "Authentication required",
62
          "schema": {
63
            "$ref": "../definitions.json#/error"
64
          }
65
        },
66
        "403": {
67
          "description": "Access forbidden",
68
          "schema": {
69
            "$ref": "../definitions.json#/error"
70
          }
71
        },
72
        "404": {
73
          "description": "Checkout not found",
74
          "schema": {
75
            "$ref": "../definitions.json#/error"
76
          }
77
        },
78
        "500": {
79
          "description": "Internal server error",
80
          "schema": {
81
            "$ref": "../definitions.json#/error"
82
          }
83
        },
84
        "503": {
85
          "description": "Under maintenance",
86
          "schema": {
87
            "$ref": "../definitions.json#/error"
88
          }
89
        }
90
      },
91
      "x-koha-authorization": {
92
        "permissions": {
93
          "circulate": "circulate_remaining_permissions"
94
        }
95
      }
96
    }
97
  },
98
  "/return_claims/{claim_id}/notes": {
99
    "put": {
100
      "x-mojo-to": "ReturnClaims#update_notes",
101
      "operationId": "updateClaimNotes",
102
      "tags": [
103
        "claims",
104
        "returned",
105
        "return",
106
        "claim",
107
        "notes"
108
      ],
109
      "parameters": [
110
        {
111
          "name": "claim_id",
112
          "in": "path",
113
          "required": true,
114
          "description": "Unique identifier for the claim whose notes are to be updated",
115
          "type": "integer"
116
        },
117
        {
118
          "name": "body",
119
          "in": "body",
120
          "description": "A JSON object containing fields to modify",
121
          "required": true,
122
          "schema": {
123
            "type": "object",
124
            "properties": {
125
              "notes": {
126
                "description": "Notes about this return claim",
127
                "type": "string"
128
              },
129
              "updated_by": {
130
                "description": "User id for the librarian updating the claim notes",
131
                "type": "string"
132
              }
133
            }
134
          }
135
        }
136
      ],
137
      "produces": [
138
        "application/json"
139
      ],
140
      "responses": {
141
        "200": {
142
          "description": "Claim notes updated",
143
          "schema": {
144
            "$ref": "../definitions.json#/return_claim"
145
          }
146
        },
147
        "400": {
148
          "description": "Bad request",
149
          "schema": {
150
            "$ref": "../definitions.json#/error"
151
          }
152
        },
153
        "401": {
154
          "description": "Authentication required",
155
          "schema": {
156
            "$ref": "../definitions.json#/error"
157
          }
158
        },
159
        "403": {
160
          "description": "Access forbidden",
161
          "schema": {
162
            "$ref": "../definitions.json#/error"
163
          }
164
        },
165
        "404": {
166
          "description": "Claim not found",
167
          "schema": {
168
            "$ref": "../definitions.json#/error"
169
          }
170
        },
171
        "500": {
172
          "description": "Internal server error",
173
          "schema": {
174
            "$ref": "../definitions.json#/error"
175
          }
176
        },
177
        "503": {
178
          "description": "Under maintenance",
179
          "schema": {
180
            "$ref": "../definitions.json#/error"
181
          }
182
        }
183
      },
184
      "x-koha-authorization": {
185
        "permissions": {
186
          "circulate": "circulate_remaining_permissions"
187
        }
188
      }
189
    }
190
  },
191
  "/return_claims/{claim_id}": {
192
    "delete": {
193
      "x-mojo-to": "ReturnClaims#delete_claim",
194
      "operationId": "deletedClaim",
195
      "tags": [
196
        "claims",
197
        "returned",
198
        "return",
199
        "claim",
200
        "delete"
201
      ],
202
      "parameters": [
203
        {
204
          "name": "claim_id",
205
          "in": "path",
206
          "required": true,
207
          "description": "Unique identifier for the claim to be deleted",
208
          "type": "integer"
209
        }
210
      ],
211
      "produces": [
212
        "application/json"
213
      ],
214
      "responses": {
215
        "200": {
216
          "description": "Claim deleted",
217
          "schema": {
218
            "$ref": "../definitions.json#/return_claim"
219
          }
220
        },
221
        "400": {
222
          "description": "Bad request",
223
          "schema": {
224
            "$ref": "../definitions.json#/error"
225
          }
226
        },
227
        "401": {
228
          "description": "Authentication required",
229
          "schema": {
230
            "$ref": "../definitions.json#/error"
231
          }
232
        },
233
        "403": {
234
          "description": "Access forbidden",
235
          "schema": {
236
            "$ref": "../definitions.json#/error"
237
          }
238
        },
239
        "404": {
240
          "description": "Claim not found",
241
          "schema": {
242
            "$ref": "../definitions.json#/error"
243
          }
244
        },
245
        "500": {
246
          "description": "Internal server error",
247
          "schema": {
248
            "$ref": "../definitions.json#/error"
249
          }
250
        },
251
        "503": {
252
          "description": "Under maintenance",
253
          "schema": {
254
            "$ref": "../definitions.json#/error"
255
          }
256
        }
257
      },
258
      "x-koha-authorization": {
259
        "permissions": {
260
          "circulate": "circulate_remaining_permissions"
261
        }
262
      }
263
    }
264
  },
265
  "/return_claims/{claim_id}/resolve": {
266
    "put": {
267
      "x-mojo-to": "ReturnClaims#resolve_claim",
268
      "operationId": "updateClaimResolve",
269
      "tags": [
270
        "claims",
271
        "returned",
272
        "return",
273
        "claim",
274
        "notes"
275
      ],
276
      "parameters": [
277
        {
278
          "name": "claim_id",
279
          "in": "path",
280
          "required": true,
281
          "description": "Unique identifier for the claim to be resolved",
282
          "type": "integer"
283
        },
284
        {
285
          "name": "body",
286
          "in": "body",
287
          "description": "A JSON object containing fields to modify",
288
          "required": true,
289
          "schema": {
290
            "type": "object",
291
            "properties": {
292
              "resolution": {
293
                "description": "The RETURN_CLAIM_RESOLUTION code to be used to resolve the calim",
294
                "type": "string"
295
              },
296
              "resolved_by": {
297
                "description": "User id for the librarian resolving the claim",
298
                "type": "string"
299
              }
300
            }
301
          }
302
        }
303
      ],
304
      "produces": [
305
        "application/json"
306
      ],
307
      "responses": {
308
        "200": {
309
          "description": "Claim resolved",
310
          "schema": {
311
            "$ref": "../definitions.json#/return_claim"
312
          }
313
        },
314
        "400": {
315
          "description": "Bad request",
316
          "schema": {
317
            "$ref": "../definitions.json#/error"
318
          }
319
        },
320
        "401": {
321
          "description": "Authentication required",
322
          "schema": {
323
            "$ref": "../definitions.json#/error"
324
          }
325
        },
326
        "403": {
327
          "description": "Access forbidden",
328
          "schema": {
329
            "$ref": "../definitions.json#/error"
330
          }
331
        },
332
        "404": {
333
          "description": "Claim not found",
334
          "schema": {
335
            "$ref": "../definitions.json#/error"
336
          }
337
        },
338
        "500": {
339
          "description": "Internal server error",
340
          "schema": {
341
            "$ref": "../definitions.json#/error"
342
          }
343
        },
344
        "503": {
345
          "description": "Under maintenance",
346
          "schema": {
347
            "$ref": "../definitions.json#/error"
348
          }
349
        }
350
      },
351
      "x-koha-authorization": {
352
        "permissions": {
353
          "circulate": "circulate_remaining_permissions"
354
        }
355
      }
356
    }
357
  }
358
}
(-)a/installer/data/mysql/atomicupdate/bug_14697.perl (-1 / +1 lines)
Lines 30-36 if( CheckVersion( $DBversion ) ) { Link Here
30
    }
30
    }
31
31
32
    $dbh->do(q{
32
    $dbh->do(q{
33
        INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
33
        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
34
        ('ClaimReturnedChargeFee', 'ask', 'ask|charge|no_charge', 'Controls whether or not a lost item fee is charged for return claims', 'Choice'),
34
        ('ClaimReturnedChargeFee', 'ask', 'ask|charge|no_charge', 'Controls whether or not a lost item fee is charged for return claims', 'Choice'),
35
        ('ClaimReturnedLostValue', '', '', 'Sets the LOST AV value that represents "Claims returned" as a lost value', 'Free'),
35
        ('ClaimReturnedLostValue', '', '', 'Sets the LOST AV value that represents "Claims returned" as a lost value', 'Free'),
36
        ('ClaimReturnedWarningThreshold', '', '', 'Sets the number of return claims past which the librarian will be warned the patron has many return claims', 'Integer');
36
        ('ClaimReturnedWarningThreshold', '', '', 'Sets the number of return claims past which the librarian will be warned the patron has many return claims', 'Integer');
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc (+71 lines)
Lines 28-33 Link Here
28
                        <th scope="col">Price</th>
28
                        <th scope="col">Price</th>
29
                        <th scope="col">Renew <p class="column-tool"><a href="#" id="CheckAllRenewals">select all</a> | <a href="#" id="UncheckAllRenewals">none</a></p></th>
29
                        <th scope="col">Renew <p class="column-tool"><a href="#" id="CheckAllRenewals">select all</a> | <a href="#" id="UncheckAllRenewals">none</a></p></th>
30
                        <th scope="col">Check in <p class="column-tool"><a href="#" id="CheckAllCheckins">select all</a> | <a href="#" id="UncheckAllCheckins">none</a></p></th>
30
                        <th scope="col">Check in <p class="column-tool"><a href="#" id="CheckAllCheckins">select all</a> | <a href="#" id="UncheckAllCheckins">none</a></p></th>
31
                        <th scope="col">Return claims</th>
31
                        <th scope="col">Export <p class="column-tool"><a href="#" id="CheckAllExports">select all</a> | <a href="#" id="UncheckAllExports">none</a></p></th>
32
                        <th scope="col">Export <p class="column-tool"><a href="#" id="CheckAllExports">select all</a> | <a href="#" id="UncheckAllExports">none</a></p></th>
32
                    </tr>
33
                    </tr>
33
                </thead>
34
                </thead>
Lines 83-85 Link Here
83
        <p>Patron has nothing checked out.</p>
84
        <p>Patron has nothing checked out.</p>
84
    [% END %]
85
    [% END %]
85
</div>
86
</div>
87
88
<!-- Claims Returned Modal -->
89
<div class="modal fade" id="claims-returned-modal" tabindex="-1" role="dialog" aria-labelledby="claims-returned-modal-label">
90
  <div class="modal-dialog" role="document">
91
    <div class="modal-content">
92
      <div class="modal-header">
93
        <h4 class="modal-title" id="claims-returned-modal-label">Claim returned</h4>
94
      </div>
95
      <div class="modal-body">
96
97
          <div class="form-group">
98
            <label for="claims-returned-notes" class="control-label">Notes</label>
99
            <div>
100
              <textarea id="claims-returned-notes" class="form-control" rows="3"></textarea>
101
            </div>
102
          </div>
103
104
          [% IF Koha.Preference('ClaimReturnedChargeFee') == 'ask' %]
105
            <div class="form-group">
106
              <div class="checkbox">
107
                <label for="claims-returned-charge-lost-fee">
108
                  <input id="claims-returned-charge-lost-fee" type="checkbox" value="1">
109
                  Charge lost fee
110
                </label>
111
              </div>
112
            </div>
113
          [% END %]
114
115
          <input type="hidden" id="claims-returned-itemnumber" />
116
      </div>
117
      <div class="modal-footer">
118
        <button id="claims-returned-modal-btn-submit" type="button" class="btn btn-primary"><i class="fa fa-exclamation-circle"></i> Make claim</button>
119
        <button class="btn btn-default deny cancel" href="#" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times"></i> Cancel</button>
120
      </div>
121
    </div>
122
  </div>
123
</div>
124
125
<!-- Resolve Return Claim Modal -->
126
<div class="modal fade" id="claims-returned-resolved-modal" tabindex="-1" role="dialog" aria-labelledby="claims-returned-resolved-modal-label">
127
  <div class="modal-dialog" role="document">
128
    <div class="modal-content">
129
      <div class="modal-header">
130
        <h4 class="modal-title" id="claims-returned-resolved-modal-label">Resolve return claim</h4>
131
      </div>
132
      <div class="modal-body">
133
134
          <div class="form-group">
135
            <label for="claims-returned-resolved-code">Resolution</label>
136
            [% SET resolutions = AuthorisedValues.GetAuthValueDropbox('RETURN_CLAIM_RESOLUTION') %]
137
            <select class="form-control" id="claims-returned-resolved-modal-resolved-code">
138
              [% FOREACH r IN resolutions %]
139
                  <option value="[% r.authorised_value | html %]">[% r.lib | html %]</option>
140
              [% END %]
141
            </select>
142
          </div>
143
144
          <input type="hidden" id="claims-returned-resolved-modal-id"/>
145
      </div>
146
      <div class="modal-footer">
147
        <button id="claims-returned-resolved-modal-btn-submit" type="button" class="btn btn-primary">
148
          <i id="claims-returned-resolved-modal-btn-submit-icon" class="fa fa-exclamation-circle"></i>
149
          <i id="claims-returned-resolved-modal-btn-submit-spinner" class="fa fa-spinner fa-pulse fa-fw" style="display:none"></i>
150
          Resolve claim
151
         </button>
152
        <button class="btn btn-default deny cancel" href="#" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times"></i> Cancel</button>
153
      </div>
154
    </div>
155
  </div>
156
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-return-claims.inc (+15 lines)
Line 0 Link Here
1
<div id="return-claims">
2
  <table id="return-claims-table" class="table table-bordered table-striped">
3
      <thead>
4
          <tr>
5
              <th class="return-claim-id">Claim ID</th>
6
              <th class="return-claim-record-title anti-the">Title</th>
7
              <th class="return-claim-notes">Notes</th>
8
              <th class="return-claim-created-on">Created on</th>
9
              <th class="return-claim-updated-on">Updated on</th>
10
              <th class="return-claim-resolution">Resolution</th>
11
              <th class="return-claim-actions">&nbsp;</th>
12
          </tr>
13
      </thead>
14
  </table>
15
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc (+5 lines)
Lines 5-10 Link Here
5
    var NOT_RENEWABLE_RESTRICTION = _("Not allowed: patron restricted");
5
    var NOT_RENEWABLE_RESTRICTION = _("Not allowed: patron restricted");
6
    var CIRCULATION_RENEWED_DUE = _("Renewed, due:");
6
    var CIRCULATION_RENEWED_DUE = _("Renewed, due:");
7
    var CIRCULATION_RENEW_FAILED = _("Renew failed:");
7
    var CIRCULATION_RENEW_FAILED = _("Renew failed:");
8
    var RETURN_CLAIMED = _("Return claimed");
9
    var RETURN_CLAIMED_FAILURE = _("Unable to claim as returned");
10
    var RETURN_CLAIMED_MAKE = _("Claim returned");
11
    var RETURN_CLAIMED_NOTES = _("Notes about return claim");
8
    var NOT_CHECKED_OUT = _("not checked out");
12
    var NOT_CHECKED_OUT = _("not checked out");
9
    var TOO_MANY_RENEWALS = _("too many renewals");
13
    var TOO_MANY_RENEWALS = _("too many renewals");
10
    var ON_RESERVE = _("on hold");
14
    var ON_RESERVE = _("on hold");
Lines 46-49 Link Here
46
    var CURRENT = _(" (current) ");
50
    var CURRENT = _(" (current) ");
47
    var MSG_NO_ITEMTYPE = _("No itemtype");
51
    var MSG_NO_ITEMTYPE = _("No itemtype");
48
    var MSG_CHECKOUTS_BY_ITEMTYPE = _("Number of checkouts by item type");
52
    var MSG_CHECKOUTS_BY_ITEMTYPE = _("Number of checkouts by item type");
53
    var CONFIRM_DELETE_RETURN_CLAIM = _("Are you sure you want to delete this return claim?");
49
</script>
54
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+19 lines)
Lines 1074-1076 Circulation: Link Here
1074
                pages: Pages
1074
                pages: Pages
1075
                chapters: Chapters
1075
                chapters: Chapters
1076
            -
1076
            -
1077
    Return Claims:
1078
        -
1079
            - When marking a checkout as "claims returned",
1080
            - pref: ClaimReturnedChargeFee
1081
              default: ask
1082
              choices:
1083
                  ask: ask if a lost fee should be charged
1084
                  charge: charge a lost fee
1085
                  no_charge: don't charge a lost fee
1086
            - .
1087
        -
1088
            - Use the LOST authorised value
1089
            - pref: ClaimReturnedLostValue
1090
            - to represent returns claims
1091
        -
1092
            - Warn librarians that a patron has excessive return cliams if the patron has claimed the return of more than
1093
            - pref: ClaimReturnedWarningThreshold
1094
              class: integer
1095
            - items.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt (-14 / +22 lines)
Lines 100-121 Link Here
100
                <li><span class="label">Lost status:</span>
100
                <li><span class="label">Lost status:</span>
101
                    [% IF ( CAN_user_circulate ) %]
101
                    [% IF ( CAN_user_circulate ) %]
102
                        <form action="updateitem.pl" method="post">
102
                        <form action="updateitem.pl" method="post">
103
                        <input type="hidden" name="biblionumber" value="[% ITEM_DAT.biblionumber | html %]" />
103
                            <input type="hidden" name="biblionumber" value="[% ITEM_DAT.biblionumber | html %]" />
104
                        <input type="hidden" name="biblioitemnumber" value="[% ITEM_DAT.biblioitemnumber | html %]" />
104
                            <input type="hidden" name="biblioitemnumber" value="[% ITEM_DAT.biblioitemnumber | html %]" />
105
                        <input type="hidden" name="itemnumber" value="[% ITEM_DAT.itemnumber | html %]" />
105
                            <input type="hidden" name="itemnumber" value="[% ITEM_DAT.itemnumber | html %]" />
106
                        <select name="itemlost" >
106
                            <select name="itemlost" >
107
                                    <option value="">Choose</option>
107
                                <option value="">Choose</option>
108
                        [% FOREACH itemlostloo IN itemlostloop %]
108
                                [% FOREACH itemlostloo IN itemlostloop %]
109
                            [% IF itemlostloo.authorised_value == ITEM_DAT.itemlost %]
109
                                    [% IF itemlostloo.authorised_value == ITEM_DAT.itemlost %]
110
                                    <option value="[% itemlostloo.authorised_value | html %]" selected="selected">[% itemlostloo.lib | html %]</option>
110
                                        <option value="[% itemlostloo.authorised_value | html %]" selected="selected">[% itemlostloo.lib | html %]</option>
111
                                    [% ELSE %]
112
                                        <option value="[% itemlostloo.authorised_value | html %]">[% itemlostloo.lib | html %]</option>
113
                                    [% END %]
114
                                [% END %]
115
                            </select>
116
                            <input type="hidden" name="withdrawn" value="[% ITEM_DAT.withdrawn | html %]" />
117
                            <input type="hidden" name="damaged" value="[% ITEM_DAT.damaged | html %]" />
118
119
                            [% SET ClaimReturnedLostValue = Koha.Preference('ClaimReturnedLostValue') %]
120
                            [% IF ClaimReturnedLostValue && ITEM_DAT.itemlost == ClaimReturnedLostValue %]
121
                                <input type="submit" name="submit" class="submit" value="Set status" disabled="disabled"/>
122
                                <p class="help-block">Item has been claimed as returned.</p>
111
                            [% ELSE %]
123
                            [% ELSE %]
112
                                    <option value="[% itemlostloo.authorised_value | html %]">[% itemlostloo.lib | html %]</option>
124
                                <input type="submit" name="submit" class="submit" value="Set status" />
113
                            [% END %]
125
                            [% END %]
114
                        [% END %]
126
                        </form>
115
                        </select>
116
                        <input type="hidden" name="withdrawn" value="[% ITEM_DAT.withdrawn | html %]" />
117
                        <input type="hidden" name="damaged" value="[% ITEM_DAT.damaged | html %]" />
118
                        <input type="submit" name="submit" class="submit" value="Set status" /></form>
119
                    [% ELSE %]
127
                    [% ELSE %]
120
                        [% FOREACH itemlostloo IN itemlostloop %]
128
                        [% FOREACH itemlostloo IN itemlostloop %]
121
                            [% IF ( itemlostloo.selected ) %]
129
                            [% IF ( itemlostloo.selected ) %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+35 lines)
Lines 728-733 Link Here
728
                                        <li><span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE.</span> <a href="#checkouts">See highlighted items below</a></li>
728
                                        <li><span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE.</span> <a href="#checkouts">See highlighted items below</a></li>
729
                                    [% END %]
729
                                    [% END %]
730
730
731
                                    [% SET ClaimReturnedWarningThreshold = Koha.Preference('ClaimReturnedWarningThreshold') %]
732
                                    [% SET return_claims = patron.return_claims %]
733
                                    [% IF return_claims.count %]
734
                                        <li><span class="circ-hlt return-claims">Return claims: Patron has [% return_claims.count | html %] RETURN CLAIMS.</span>
735
                                    [% END %]
736
731
                                    [% IF ( charges ) %]
737
                                    [% IF ( charges ) %]
732
                                        [% INCLUDE 'blocked-fines.inc' fines = chargesamount %]
738
                                        [% INCLUDE 'blocked-fines.inc' fines = chargesamount %]
733
                                    [% END %]
739
                                    [% END %]
Lines 841-846 Link Here
841
                                </li>
847
                                </li>
842
                            [% END %]
848
                            [% END %]
843
849
850
                            <li>
851
                                [% IF ( patron.return_claims.count ) %]
852
                                    <a href="#return-claims" id="return-claims-tab">
853
                                        <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span>
854
                                        /
855
                                        <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span>
856
                                        Claim(s)
857
                                    </a>
858
                                [% ELSE %]
859
                                    <a href="#return-claims" id="return-claims-tab">
860
                                        <span id="return-claims-count-resolved">0</span>
861
                                        /
862
                                        <span id="return-claims-count-unresolved">0</span>
863
                                        Claim(s)
864
                                    </a>
865
                                [% END %]
866
                            </li>
867
868
                            [% IF Koha.Preference('ArticleRequests') %]
869
                                <li>
870
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
871
                                </li>
872
                            [% END %]
873
844
                            <li><a id="debarments-tab-link" href="#reldebarments">[% debarments.count | html %] Restrictions</a></li>
874
                            <li><a id="debarments-tab-link" href="#reldebarments">[% debarments.count | html %] Restrictions</a></li>
845
875
846
                            [% SET enrollments = patron.get_club_enrollments(1) %]
876
                            [% SET enrollments = patron.get_club_enrollments(1) %]
Lines 946-951 Link Here
946
                            [% END # /IF holds_count %]
976
                            [% END # /IF holds_count %]
947
                        </div> <!-- /#reserves -->
977
                        </div> <!-- /#reserves -->
948
978
979
                        [% INCLUDE 'patron-return-claims.inc' %]
980
949
                        [% IF Koha.Preference('ArticleRequests') %]
981
                        [% IF Koha.Preference('ArticleRequests') %]
950
                            [% INCLUDE 'patron-article-requests.inc' %]
982
                            [% INCLUDE 'patron-article-requests.inc' %]
951
                        [% END %]
983
                        [% END %]
Lines 1013-1018 Link Here
1013
    [% Asset.js("js/circ-patron-search-results.js") | $raw %]
1045
    [% Asset.js("js/circ-patron-search-results.js") | $raw %]
1014
    <script type="text/javascript">
1046
    <script type="text/javascript">
1015
        /* Set some variable needed in circulation.js */
1047
        /* Set some variable needed in circulation.js */
1048
        var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]";
1049
        var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]";
1050
        var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]";
1016
        var MSG_DT_LOADING_RECORDS = _("Loading... you may continue scanning.");
1051
        var MSG_DT_LOADING_RECORDS = _("Loading... you may continue scanning.");
1017
        var interface = "[% interface | html %]";
1052
        var interface = "[% interface | html %]";
1018
        var theme = "[% theme | html %]";
1053
        var theme = "[% theme | html %]";
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+24 lines)
Lines 707-712 Link Here
707
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
707
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
708
                                </li>
708
                                </li>
709
                            [% END %]
709
                            [% END %]
710
711
                            <li>
712
                                [% IF ( patron.return_claims.count ) %]
713
                                    <a href="#return-claims" id="return-claims-tab">
714
                                        <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span>
715
                                        /
716
                                        <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span>
717
                                        Claim(s)
718
                                    </a>
719
                                [% ELSE %]
720
                                    <a href="#return-claims" id="return-claims-tab">
721
                                        <span id="return-claims-count-resolved">0</span>
722
                                        /
723
                                        <span id="return-claims-count-unresolved">0</span>
724
                                        Claim(s)
725
                                    </a>
726
                                [% END %]
727
                            </li>
728
710
                            <li>
729
                            <li>
711
                                <a id="debarments-tab-link" href="#reldebarments">[% debarments.size | html %] Restrictions</a>
730
                                <a id="debarments-tab-link" href="#reldebarments">[% debarments.size | html %] Restrictions</a>
712
                            </li>
731
                            </li>
Lines 820-825 Link Here
820
                            </div> [% # /div#reserves %]
839
                            </div> [% # /div#reserves %]
821
                        [% END %]
840
                        [% END %]
822
841
842
                        [% INCLUDE 'patron-return-claims.inc' %]
843
823
                        [% IF Koha.Preference('ArticleRequests') %]
844
                        [% IF Koha.Preference('ArticleRequests') %]
824
                            [% INCLUDE 'patron-article-requests.inc' %]
845
                            [% INCLUDE 'patron-article-requests.inc' %]
825
                        [% END %]
846
                        [% END %]
Lines 852-857 Link Here
852
    [% Asset.js("js/messaging-preference-form.js") | $raw %]
873
    [% Asset.js("js/messaging-preference-form.js") | $raw %]
853
    <script>
874
    <script>
854
        /* Set some variable needed in circulation.js */
875
        /* Set some variable needed in circulation.js */
876
        var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]";
877
        var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]";
878
        var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]";
855
        var interface = "[% interface | html %]";
879
        var interface = "[% interface | html %]";
856
        var theme = "[% theme | html %]";
880
        var theme = "[% theme | html %]";
857
        var borrowernumber = "[% patron.borrowernumber | html %]";
881
        var borrowernumber = "[% patron.borrowernumber | html %]";
(-)a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js (-1 / +273 lines)
Lines 268-274 $(document).ready(function() { Link Here
268
268
269
                        due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
269
                        due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
270
270
271
                        if ( oObj.lost ) {
271
                        if ( oObj.lost && oObj.claims_returned ) {
272
                            due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>";
273
                        } else if ( oObj.lost ) {
272
                            due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
274
                            due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
273
                        }
275
                        }
274
276
Lines 536-541 $(document).ready(function() { Link Here
536
                        }
538
                        }
537
                    }
539
                    }
538
                },
540
                },
541
                {
542
                    "bVisible": ClaimReturnedLostValue ? true : false,
543
                    "bSortable": false,
544
                    "mDataProp": function ( oObj ) {
545
                        let content = "";
546
547
                        if ( oObj.return_claim_id ) {
548
                          content = `<span class="badge">${oObj.return_claim_created_on_formatted}</span>`;
549
                        } else {
550
                          content = `<a class="btn btn-default btn-xs claim-returned-btn" data-itemnumber="${oObj.itemnumber}"><i class="fa fa-exclamation-circle"></i> ${RETURN_CLAIMED_MAKE}</a>`;
551
                        }
552
                        return content;
553
                    }
554
                },
539
                {
555
                {
540
                    "bVisible": exports_enabled == 1 ? true : false,
556
                    "bVisible": exports_enabled == 1 ? true : false,
541
                    "bSortable": false,
557
                    "bSortable": false,
Lines 804-807 $(document).ready(function() { Link Here
804
            }
820
            }
805
        } ).prop('checked', false);
821
        } ).prop('checked', false);
806
    }
822
    }
823
824
    // Handle return claims
825
    $(document).on("click", '.claim-returned-btn', function(e){
826
        e.preventDefault();
827
        itemnumber = $(this).data('itemnumber');
828
829
        $('#claims-returned-itemnumber').val(itemnumber);
830
        $('#claims-returned-notes').val("");
831
        $('#claims-returned-charge-lost-fee').attr('checked', false)
832
        $('#claims-returned-modal').modal()
833
    });
834
    $(document).on("click", '#claims-returned-modal-btn-submit', function(e){
835
        let itemnumber = $('#claims-returned-itemnumber').val();
836
        let notes = $('#claims-returned-notes').val();
837
        let fee = $('#claims-returned-charge-lost-fee').attr('checked') ? true : false;
838
839
        $('#claims-returned-modal').modal('hide')
840
841
        $(`.claim-returned-btn[data-itemnumber='${itemnumber}']`).replaceWith(`<img id='return_claim_spinner_${itemnumber}' src='${interface}/${theme}/img/spinner-small.gif' />`);
842
843
        params = {
844
            notes: notes,
845
            charge_lost_fee: fee,
846
            created_by: $.cookie("lastborrowernumber")
847
        };
848
849
        $.post( `/api/v1/return_claims/claim/${itemnumber}`, JSON.stringify(params), function( data ) {
850
851
            id = "#return_claim_spinner_" + data.itemnumber;
852
853
            let content = "";
854
            if ( data.id ) {
855
            console.log(data);
856
                content = `<span class="badge">${data.created_on_formatted}</span>`;
857
                $(id).parent().parent().addClass('ok');
858
            } else {
859
                content = RETURN_CLAIMED_FAILURE;
860
                $(id).parent().parent().addClass('warn');
861
            }
862
863
            $(id).replaceWith( content );
864
865
            refreshReturnClaimsTable();
866
        }, "json")
867
868
    });
869
870
871
    // Don't load return claims table unless it is clicked on
872
    var returnClaimsTable;
873
    $("#return-claims-tab").click( function() {
874
        refreshReturnClaimsTable();
875
    });
876
877
    function refreshReturnClaimsTable(){
878
        loadReturnClaimsTable();
879
        $("#return-claims-table").DataTable().ajax.reload();
880
    }
881
    function loadReturnClaimsTable() {
882
        if ( ! returnClaimsTable ) {
883
            returnClaimsTable = $("#return-claims-table").dataTable({
884
                "bAutoWidth": false,
885
                "sDom": "rt",
886
                "aaSorting": [],
887
                "aoColumns": [
888
                    {
889
                        "mDataProp": "id",
890
                        "bVisible": false,
891
                    },
892
                    {
893
                        "mDataProp": function ( oObj ) {
894
                              let title = `<a class="return-claim-title strong" href="/cgi-bin/koha/circ/request-rcticle.pl?biblionumber=[% rc.checkout.item.biblionumber | html %]">
895
                                  ${oObj.title}
896
                                  ${oObj.enumchron || ""}
897
                              </a>`;
898
                              if ( oObj.author ) {
899
                                title += `by ${oObj.author}`;
900
                              }
901
                              title += `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${oObj.biblionumber}&itemnumber=${oObj.itemnumber}">${oObj.barcode}</a>`;
902
903
                              return title;
904
                        }
905
                    },
906
                    {
907
                        "sClass": "return-claim-notes-td",
908
                        "mDataProp": function ( oObj ) {
909
                            return `
910
                                <span id="return-claim-notes-static-${oObj.id}" class="return-claim-notes" data-return-claim-id="${oObj.id}">${oObj.notes}</span>
911
                                <i style="float:right" class="fa fa-pencil-square-o" title="Double click to edit"></i>
912
                            `;
913
                        }
914
                    },
915
                    {
916
                        "mDataProp": "created_on",
917
                    },
918
                    {
919
                        "mDataProp": "updated_on",
920
                    },
921
                    {
922
                        "mDataProp": function ( oObj ) {
923
                            if ( ! oObj.resolution ) return "";
924
925
                            let desc = `<strong>${oObj.resolution_data.lib}</strong> on <i>${oObj.resolved_on_formatted}</i>`;
926
                            if (oObj.resolved_by_data) desc += ` by <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=${oObj.resolved_by_data.borrowernumber}">${oObj.resolved_by_data.firstname || ""} ${oObj.resolved_by_data.surname || ""}</a>`;
927
                            return desc;
928
                        }
929
                    },
930
                    {
931
                        "mDataProp": function ( oObj ) {
932
                            let delete_html = oObj.resolved_on
933
                                ? `<li><a href="#" class="return-claim-tools-delete" data-return-claim-id="${oObj.id}"><i class="fa fa-trash"></i> Delete</a></li>`
934
                                : "";
935
                            let resolve_html = ! oObj.resolution
936
                                ? `<li><a href="#" class="return-claim-tools-resolve" data-return-claim-id="${oObj.id}"><i class="fa fa-check-square"></i> Resolve</a></li>`
937
                                : "";
938
939
                            return `
940
                                <div class="btn-group">
941
                                  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
942
                                    Actions <span class="caret"></span>
943
                                  </button>
944
                                  <ul class="dropdown-menu">
945
                                    <li><a href="#" class="return-claim-tools-editnotes" data-return-claim-id="${oObj.id}"><i class="fa fa-edit"></i> Edit notes</a></li>
946
                                    ${resolve_html}
947
                                    ${delete_html}
948
                                  </ul>
949
                                </div>
950
                            `;
951
                        }
952
                    },
953
                ],
954
                "bPaginate": false,
955
                "bProcessing": true,
956
                "bServerSide": false,
957
                "sAjaxSource": '/cgi-bin/koha/svc/return_claims',
958
                "fnServerData": function ( sSource, aoData, fnCallback ) {
959
                    aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
960
961
                    $.getJSON( sSource, aoData, function (json) {
962
                        let resolved = json.resolved;
963
                        let unresolved = json.unresolved;
964
965
                        $('#return-claims-count-resolved').text(resolved);
966
                        $('#return-claims-count-unresolved').text(unresolved);
967
968
                        fnCallback(json)
969
                    } );
970
                },
971
            });
972
        }
973
    }
974
975
    $('body').on('click', '.return-claim-tools-editnotes', function() {
976
        let id = $(this).data('return-claim-id');
977
        $(`#return-claim-notes-static-${id}`).parent().dblclick();
978
    });
979
    $('body').on('dblclick', '.return-claim-notes-td', function() {
980
        let elt = $(this).children('.return-claim-notes');
981
        let id = elt.data('return-claim-id');
982
        if ( $(`#return-claim-notes-editor-textarea-${id}`).length == 0 ) {
983
            let note = elt.text();
984
            let editor = `
985
                <span id="return-claim-notes-editor-${id}">
986
                    <textarea id="return-claim-notes-editor-textarea-${id}">${note}</textarea>
987
                    <br/>
988
                    <a class="btn btn-default btn-xs claim-returned-notes-editor-submit" data-return-claim-id="${id}"><i class="fa fa-save"></i> Update</a>
989
                    <a class="claim-returned-notes-editor-cancel" data-return-claim-id="${id}" href="#">Cancel</a>
990
                </span>
991
            `;
992
            elt.hide();
993
            $(editor).insertAfter( elt );
994
        }
995
    });
996
997
    $('body').on('click', '.claim-returned-notes-editor-submit', function(){
998
        let id = $(this).data('return-claim-id');
999
        let notes = $(`#return-claim-notes-editor-textarea-${id}`).val();
1000
1001
        let params = {
1002
            notes: notes,
1003
            updated_by: $.cookie("lastborrowernumber")
1004
        };
1005
1006
        $(this).parent().remove();
1007
1008
        $.ajax({
1009
            url: `/api/v1/return_claims/${id}/notes`,
1010
            type: 'PUT',
1011
            data: JSON.stringify(params),
1012
            success: function( data ) {
1013
                let notes = $(`#return-claim-notes-static-${id}`);
1014
                notes.text(data.notes);
1015
                notes.show();
1016
            },
1017
            contentType: "json"
1018
        });
1019
    });
1020
1021
    $('body').on('click', '.claim-returned-notes-editor-cancel', function(){
1022
        let id = $(this).data('return-claim-id');
1023
        $(this).parent().remove();
1024
        $(`#return-claim-notes-static-${id}`).show();
1025
    });
1026
1027
    // Hanld return claim deletion
1028
    $('body').on('click', '.return-claim-tools-delete', function() {
1029
        let confirmed = confirm(CONFIRM_DELETE_RETURN_CLAIM);
1030
        if ( confirmed ) {
1031
            let id = $(this).data('return-claim-id');
1032
1033
            $.ajax({
1034
                url: `/api/v1/return_claims/${id}`,
1035
                type: 'DELETE',
1036
                success: function( data ) {
1037
                    refreshReturnClaimsTable();
1038
                }
1039
            });
1040
        }
1041
    });
1042
1043
    // Handle return claim resolution
1044
    $('body').on('click', '.return-claim-tools-resolve', function() {
1045
        let id = $(this).data('return-claim-id');
1046
1047
        $('#claims-returned-resolved-modal-id').val(id);
1048
        $('#claims-returned-resolved-modal').modal()
1049
    });
1050
1051
    $(document).on('click', '#claims-returned-resolved-modal-btn-submit', function(e) {
1052
        let resolution = $('#claims-returned-resolved-modal-resolved-code').val();
1053
        let id = $('#claims-returned-resolved-modal-id').val();
1054
1055
        $('#claims-returned-resolved-modal-btn-submit-spinner').show();
1056
        $('#claims-returned-resolved-modal-btn-submit-icon').hide();
1057
1058
        params = {
1059
          resolution: resolution,
1060
          updated_by: $.cookie("lastborrowernumber"),
1061
        };
1062
1063
        $.ajax({
1064
            url: `/api/v1/return_claims/${id}/resolve`,
1065
            type: 'PUT',
1066
            data: JSON.stringify(params),
1067
            success: function( data ) {
1068
                $('#claims-returned-resolved-modal-btn-submit-spinner').hide();
1069
                $('#claims-returned-resolved-modal-btn-submit-icon').show();
1070
                $('#claims-returned-resolved-modal').modal('hide')
1071
1072
                refreshReturnClaimsTable();
1073
            },
1074
            contentType: "json"
1075
        });
1076
1077
    });
1078
807
 });
1079
 });
(-)a/svc/checkouts (-21 / +40 lines)
Lines 65-88 print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); Link Here
65
my @parameters;
65
my @parameters;
66
my $sql = '
66
my $sql = '
67
    SELECT
67
    SELECT
68
        issuedate,
68
        issues.issuedate,
69
        date_due,
69
        issues.date_due,
70
        date_due < now() as date_due_overdue,
70
        issues.date_due < now() as date_due_overdue,
71
        issues.timestamp,
71
        issues.timestamp,
72
72
73
        onsite_checkout,
73
        issues.onsite_checkout,
74
74
75
        biblionumber,
75
        biblio.biblionumber,
76
        biblio.title,
76
        biblio.title,
77
        author,
77
        biblio.author,
78
78
79
        itemnumber,
79
        items.itemnumber,
80
        barcode,
80
        items.barcode,
81
        branches2.branchname AS homebranch,
81
        branches2.branchname AS homebranch,
82
        itemnotes,
82
        items.itemnotes,
83
        itemnotes_nonpublic,
83
        items.itemnotes_nonpublic,
84
        itemcallnumber,
84
        items.itemcallnumber,
85
        replacementprice,
85
        items.replacementprice,
86
86
87
        issues.branchcode,
87
        issues.branchcode,
88
        branches.branchname,
88
        branches.branchname,
Lines 92-108 my $sql = ' Link Here
92
92
93
        items.ccode AS collection,
93
        items.ccode AS collection,
94
94
95
        borrowernumber,
95
        borrowers.borrowernumber,
96
        surname,
96
        borrowers.surname,
97
        firstname,
97
        borrowers.firstname,
98
        cardnumber,
98
        borrowers.cardnumber,
99
99
100
        itemlost,
100
        items.itemlost,
101
        damaged,
101
        items.damaged,
102
        location,
102
        items.location,
103
        items.enumchron,
103
        items.enumchron,
104
104
105
        DATEDIFF( issuedate, CURRENT_DATE() ) AS not_issued_today
105
        DATEDIFF( issues.issuedate, CURRENT_DATE() ) AS not_issued_today,
106
107
        return_claims.id AS return_claim_id,
108
        return_claims.notes AS return_claim_notes,
109
        return_claims.created_on AS return_claim_created_on,
110
        return_claims.updated_on AS return_claim_updated_on
111
106
    FROM issues
112
    FROM issues
107
        LEFT JOIN items USING ( itemnumber )
113
        LEFT JOIN items USING ( itemnumber )
108
        LEFT JOIN biblio USING ( biblionumber )
114
        LEFT JOIN biblio USING ( biblionumber )
Lines 110-116 my $sql = ' Link Here
110
        LEFT JOIN borrowers USING ( borrowernumber )
116
        LEFT JOIN borrowers USING ( borrowernumber )
111
        LEFT JOIN branches ON ( issues.branchcode = branches.branchcode )
117
        LEFT JOIN branches ON ( issues.branchcode = branches.branchcode )
112
        LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode )
118
        LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode )
113
    WHERE borrowernumber
119
        LEFT JOIN return_claims USING ( issue_id )
120
    WHERE issues.borrowernumber
114
';
121
';
115
122
116
if ( @borrowernumber == 1 ) {
123
if ( @borrowernumber == 1 ) {
Lines 128-133 my $sth = $dbh->prepare($sql); Link Here
128
$sth->execute(@parameters);
135
$sth->execute(@parameters);
129
136
130
my $item_level_itypes = C4::Context->preference('item-level_itypes');
137
my $item_level_itypes = C4::Context->preference('item-level_itypes');
138
my $claims_returned_lost_value = C4::Context->preference('ClaimReturnedLostValue');
131
139
132
my @checkouts_today;
140
my @checkouts_today;
133
my @checkouts_previous;
141
my @checkouts_previous;
Lines 162-170 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
162
        $collection = $av->count ? $av->next->lib : '';
170
        $collection = $av->count ? $av->next->lib : '';
163
    }
171
    }
164
    my $lost;
172
    my $lost;
173
    my $claims_returned;
165
    if ( $c->{itemlost} ) {
174
    if ( $c->{itemlost} ) {
166
        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $c->{itemlost} });
175
        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $c->{itemlost} });
167
        $lost = $av->count ? $av->next->lib : '';
176
        $lost = $av->count ? $av->next->lib : '';
177
        $claims_returned = $c->{itemlost} eq $claims_returned_lost_value;
168
    }
178
    }
169
    my $damaged;
179
    my $damaged;
170
    if ( $c->{damaged} ) {
180
    if ( $c->{damaged} ) {
Lines 204-209 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
204
        renewals_count      => $renewals_count,
214
        renewals_count      => $renewals_count,
205
        renewals_allowed    => $renewals_allowed,
215
        renewals_allowed    => $renewals_allowed,
206
        renewals_remaining  => $renewals_remaining,
216
        renewals_remaining  => $renewals_remaining,
217
218
        return_claim_id         => $c->{return_claim_id},
219
        return_claim_notes      => $c->{return_claim_notes},
220
        return_claim_created_on => $c->{return_claim_created_on},
221
        return_claim_updated_on => $c->{return_claim_updated_on},
222
        return_claim_created_on_formatted => $c->{return_claim_created_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_created_on} ) }) : undef,
223
        return_claim_updated_on_formatted => $c->{return_claim_updated_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_updated_on} ) }) : undef,
224
207
        issuedate_formatted => output_pref(
225
        issuedate_formatted => output_pref(
208
            {
226
            {
209
                dt          => dt_from_string( $c->{issuedate} ),
227
                dt          => dt_from_string( $c->{issuedate} ),
Lines 221-226 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
221
            GetMarcBiblio({ biblionumber => $c->{biblionumber} }),
239
            GetMarcBiblio({ biblionumber => $c->{biblionumber} }),
222
            GetFrameworkCode( $c->{biblionumber} ) ),
240
            GetFrameworkCode( $c->{biblionumber} ) ),
223
        lost    => $lost,
241
        lost    => $lost,
242
        claims_returned => $claims_returned,
224
        damaged => $damaged,
243
        damaged => $damaged,
225
        borrower => {
244
        borrower => {
226
            surname    => $c->{surname},
245
            surname    => $c->{surname},
(-)a/svc/return_claims (+127 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2019 ByWater Solutions
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use CGI;
23
use JSON qw(to_json);
24
25
use C4::Auth qw(check_cookie_auth haspermission get_session);
26
use C4::Context;
27
28
use Koha::AuthorisedValues;
29
use Koha::DateUtils;
30
use Koha::Patrons;
31
32
my $input = new CGI;
33
34
my ( $auth_status, $sessionID ) =
35
  check_cookie_auth( $input->cookie('CGISESSID') );
36
37
my $session = get_session($sessionID);
38
my $userid  = $session->param('id');
39
40
unless (
41
    haspermission(
42
        $userid, { circulate => 'circulate_remaining_permissions' }
43
    )
44
    || haspermission( $userid, { borrowers => 'edit_borrowers' } )
45
  )
46
{
47
    exit 0;
48
}
49
50
my @sort_columns = qw/title notes created_on updated_on/;
51
52
my $borrowernumber   = $input->param('borrowernumber');
53
my $offset           = $input->param('iDisplayStart');
54
my $results_per_page = $input->param('iDisplayLength') || -1;
55
56
my $sorting_column = $input->param('iSortCol_0') || q{};
57
$sorting_column =
58
  ( $sorting_column && $sort_columns[$sorting_column] )
59
  ? $sort_columns[$sorting_column]
60
  : 'created_on';
61
62
my $sorting_direction = $input->param('sSortDir_0') || q{};
63
$sorting_direction = $sorting_direction eq 'asc' ? 'asc' : 'desc';
64
65
$results_per_page = undef if ( $results_per_page == -1 );
66
67
binmode STDOUT, ":encoding(UTF-8)";
68
print $input->header( -type => 'text/plain', -charset => 'UTF-8' );
69
70
my $sql = qq{
71
    SELECT
72
        return_claims.*,
73
74
        biblio.biblionumber,
75
        biblio.title,
76
        biblio.author,
77
78
        items.enumchron,
79
        items.barcode
80
    FROM return_claims
81
        LEFT JOIN items USING ( itemnumber )
82
        LEFT JOIN biblio USING ( biblionumber )
83
        LEFT JOIN biblioitems USING ( biblionumber )
84
    WHERE return_claims.borrowernumber = ?
85
    ORDER BY $sorting_column $sorting_direction
86
};
87
88
my $dbh = C4::Context->dbh();
89
my $sth = $dbh->prepare($sql);
90
$sth->execute($borrowernumber);
91
92
my $resolved = 0;
93
my $unresolved = 0;
94
my @return_claims;
95
while ( my $claim = $sth->fetchrow_hashref() ) {
96
    $claim->{created_on_formatted}  = output_pref( { dt => dt_from_string( $claim->{created_on} ) } ) if $claim->{created_on};
97
    $claim->{updated_on_formatted}  = output_pref( { dt => dt_from_string( $claim->{updated_on} ) } ) if $claim->{updated_on};
98
    $claim->{resolved_on_formatted} = output_pref( { dt => dt_from_string( $claim->{resolved_on} ) } ) if $claim->{resolved_on};
99
100
    my $patron = $claim->{resolved_by} ? Koha::Patrons->find( $claim->{resolved_by} ) : undef;
101
    $claim->{resolved_by_data} = $patron->unblessed if $patron;
102
103
    my $resolution = $claim->{resolution}
104
      ? Koha::AuthorisedValues->find(
105
        {
106
            category         => 'RETURN_CLAIM_RESOLUTION',
107
            authorised_value => $claim->{resolution},
108
        }
109
      )
110
      : undef;
111
    $claim->{resolution_data} = $resolution->unblessed if $resolution;
112
113
    $claim->{resolved_on} ? $resolved++ : $unresolved++;
114
115
    push( @return_claims, $claim );
116
}
117
118
my $data = {
119
    iTotalRecords        => scalar @return_claims,
120
    iTotalDisplayRecords => scalar @return_claims,
121
    sEcho                => $input->param('sEcho') || undef,
122
    aaData               => \@return_claims,
123
    resolved             => $resolved,
124
    unresolved           => $unresolved
125
};
126
127
print to_json($data);
(-)a/t/db_dependent/api/v1/return_claims.t (-1 / +160 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 3 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
use Modern::Perl;
19
20
use Test::More tests => 25;
21
use Test::MockModule;
22
use Test::Mojo;
23
use t::lib::Mocks;
24
use t::lib::TestBuilder;
25
26
use DateTime;
27
28
use C4::Context;
29
use C4::Circulation;
30
31
use Koha::Checkouts::ReturnClaims;
32
use Koha::Database;
33
use Koha::DateUtils;
34
35
my $schema  = Koha::Database->schema;
36
my $builder = t::lib::TestBuilder->new;
37
38
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
39
my $t = Test::Mojo->new('Koha::REST::V1');
40
41
$schema->storage->txn_begin;
42
43
my $dbh = C4::Context->dbh;
44
45
my $librarian = $builder->build_object(
46
    {
47
        class => 'Koha::Patrons',
48
        value => { flags => 1 }
49
    }
50
);
51
my $password = 'thePassword123';
52
$librarian->set_password( { password => $password, skip_validation => 1 } );
53
my $userid = $librarian->userid;
54
55
my $patron = $builder->build_object(
56
    {
57
        class => 'Koha::Patrons',
58
        value => { flags => 0 }
59
    }
60
);
61
my $unauth_password = 'thePassword000';
62
$patron->set_password(
63
    { password => $unauth_password, skip_validattion => 1 } );
64
my $unauth_userid = $patron->userid;
65
my $patron_id     = $patron->borrowernumber;
66
67
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
68
my $module     = new Test::MockModule('C4::Context');
69
$module->mock( 'userenv', sub { { branch => $branchcode } } );
70
71
my $item1       = $builder->build_sample_item;
72
my $itemnumber1 = $item1->itemnumber;
73
74
my $date_due = DateTime->now->add( weeks => 2 );
75
my $issue1 =
76
  C4::Circulation::AddIssue( $patron->unblessed, $item1->barcode, $date_due );
77
78
t::lib::Mocks::mock_preference( 'ClaimReturnedChargeFee', 'ask' );
79
t::lib::Mocks::mock_preference( 'ClaimReturnedLostValue', '99' );
80
81
# Test creating a return claim
82
## Invalid id
83
$t->post_ok(
84
    "//$userid:$password@/api/v1/return_claims/claim/1" => json => {
85
        charge_lost_fee => Mojo::JSON->false,
86
        created_by      => $librarian->id,
87
        notes           => "This is a test note."
88
    }
89
)->status_is(404);
90
91
## Valid id
92
$t->post_ok(
93
    "//$userid:$password@/api/v1/return_claims/claim/$itemnumber1" => json => {
94
        charge_lost_fee => Mojo::JSON->false,
95
        created_by      => $librarian->id,
96
        notes           => "This is a test note."
97
    }
98
)->status_is(200);
99
my $claim_id = $t->tx->res->json->{id};
100
101
## Duplicate id
102
$t->post_ok(
103
    "//$userid:$password@/api/v1/return_claims/claim/$itemnumber1" => json => {
104
        charge_lost_fee => Mojo::JSON->false,
105
        created_by      => $librarian->id,
106
        notes           => "This is a test note."
107
    }
108
)->status_is(400);
109
110
# Test editing a claim note
111
## Valid claim id
112
$t->put_ok(
113
    "//$userid:$password@/api/v1/return_claims/$claim_id/notes" => json => {
114
        notes      => "This is a different test note.",
115
        updated_by => $librarian->id,
116
    }
117
)->status_is(200);
118
my $claim = Koha::Checkouts::ReturnClaims->find($claim_id);
119
is( $claim->notes,      "This is a different test note." );
120
is( $claim->updated_by, $librarian->id );
121
ok( $claim->updated_on );
122
123
## Bad claim id
124
$t->put_ok(
125
    "//$userid:$password@/api/v1/return_claims/99999999999/notes" => json => {
126
        notes      => "This is a different test note.",
127
        updated_by => $librarian->id,
128
    }
129
)->status_is(404);
130
131
# Resolve a claim
132
## Valid claim id
133
$t->put_ok(
134
    "//$userid:$password@/api/v1/return_claims/$claim_id/resolve" => json => {
135
        resolved_by => $librarian->id,
136
        resolution  => "FOUNDINLIB",
137
    }
138
)->status_is(200);
139
$claim = Koha::Checkouts::ReturnClaims->find($claim_id);
140
is( $claim->resolution, "FOUNDINLIB" );
141
is( $claim->updated_by, $librarian->id );
142
ok( $claim->resolved_on );
143
144
## Invalid claim id
145
$t->put_ok(
146
    "//$userid:$password@/api/v1/return_claims/999999999999/resolve" => json => {
147
        resolved_by => $librarian->id,
148
        resolution  => "FOUNDINLIB",
149
    }
150
)->status_is(404);
151
152
# Test deleting a return claim
153
$t = $t->delete_ok("//$userid:$password@/api/v1/return_claims/$claim_id")
154
  ->status_is(200);
155
$claim = Koha::Checkouts::ReturnClaims->find($claim_id);
156
isnt( $claim, "Return claim was deleted" );
157
158
$t->delete_ok("//$userid:$password@/api/v1/return_claims/$claim_id")
159
  ->status_is(404);
160

Return to bug 14697