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 1072-1077 sub old_holds { Link Here
1072
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1072
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1073
}
1073
}
1074
1074
1075
=head3 return_claims
1076
1077
my $return_claims = $patron->return_claims
1078
1079
=cut
1080
1081
sub return_claims {
1082
    my ($self) = @_;
1083
    my $return_claims = $self->_result->return_claims_borrowernumbers;
1084
    return Koha::Checkouts::ReturnClaims->_new_from_dbic( $return_claims );
1085
}
1086
1075
=head3 notice_email_address
1087
=head3 notice_email_address
1076
1088
1077
  my $email = $patron->notice_email_address;
1089
  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 43-47 Link Here
43
  },
43
  },
44
  "fund": {
44
  "fund": {
45
    "$ref": "definitions/fund.json"
45
    "$ref": "definitions/fund.json"
46
  },
47
  "return_claim": {
48
    "$ref": "definitions/return_claim.json"
46
  }
49
  }
47
}
50
}
(-)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 85-89 Link Here
85
  },
85
  },
86
  "/public/patrons/{patron_id}/guarantors/can_see_checkouts": {
86
  "/public/patrons/{patron_id}/guarantors/can_see_checkouts": {
87
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
87
    "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
88
  },
89
  "/return_claims/claim/{item_id}/": {
90
    "$ref": "paths/return_claims.json#/~1return_claims~1claim~1{item_id}"
91
  },
92
  "/return_claims/{claim_id}/notes": {
93
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}~1notes"
94
  },
95
  "/return_claims/{claim_id}/resolve": {
96
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}~1resolve"
97
  },
98
  "/return_claims/{claim_id}": {
99
    "$ref": "paths/return_claims.json#/~1return_claims~1{claim_id}"
88
  }
100
  }
89
}
101
}
(-)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 1078-1080 Circulation: Link Here
1078
                pages: Pages
1078
                pages: Pages
1079
                chapters: Chapters
1079
                chapters: Chapters
1080
            -
1080
            -
1081
    Return Claims:
1082
        -
1083
            - When marking a checkout as "claims returned",
1084
            - pref: ClaimReturnedChargeFee
1085
              default: ask
1086
              choices:
1087
                  ask: ask if a lost fee should be charged
1088
                  charge: charge a lost fee
1089
                  no_charge: don't charge a lost fee
1090
            - .
1091
        -
1092
            - Use the LOST authorised value
1093
            - pref: ClaimReturnedLostValue
1094
            - to represent returns claims
1095
        -
1096
            - Warn librarians that a patron has excessive return cliams if the patron has claimed the return of more than
1097
            - pref: ClaimReturnedWarningThreshold
1098
              class: integer
1099
            - items.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt (-13 / +23 lines)
Lines 100-120 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="hidden" name="op" value="set_lost" />
125
                                <input type="submit" name="submit" class="submit" value="Set status" /></form>
113
                            [% END %]
126
                            [% END %]
114
                        [% END %]
127
                        </form>
115
                        </select>
116
                        <input type="hidden" name="op" value="set_lost" />
117
                        <input type="submit" name="submit" class="submit" value="Set status" /></form>
118
                    [% ELSE %]
128
                    [% ELSE %]
119
                        [% FOREACH itemlostloo IN itemlostloop %]
129
                        [% FOREACH itemlostloo IN itemlostloop %]
120
                            [% IF ( itemlostloo.selected ) %]
130
                            [% IF ( itemlostloo.selected ) %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+35 lines)
Lines 732-737 Link Here
732
                                        <li><span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE.</span> <a href="#checkouts">See highlighted items below</a></li>
732
                                        <li><span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE.</span> <a href="#checkouts">See highlighted items below</a></li>
733
                                    [% END %]
733
                                    [% END %]
734
734
735
                                    [% SET ClaimReturnedWarningThreshold = Koha.Preference('ClaimReturnedWarningThreshold') %]
736
                                    [% SET return_claims = patron.return_claims %]
737
                                    [% IF return_claims.count %]
738
                                        <li><span class="circ-hlt return-claims">Return claims: Patron has [% return_claims.count | html %] RETURN CLAIMS.</span>
739
                                    [% END %]
740
735
                                    [% IF ( charges ) %]
741
                                    [% IF ( charges ) %]
736
                                        [% INCLUDE 'blocked-fines.inc' fines = chargesamount %]
742
                                        [% INCLUDE 'blocked-fines.inc' fines = chargesamount %]
737
                                    [% END %]
743
                                    [% END %]
Lines 845-850 Link Here
845
                                </li>
851
                                </li>
846
                            [% END %]
852
                            [% END %]
847
853
854
                            <li>
855
                                [% IF ( patron.return_claims.count ) %]
856
                                    <a href="#return-claims" id="return-claims-tab">
857
                                        <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span>
858
                                        /
859
                                        <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span>
860
                                        Claim(s)
861
                                    </a>
862
                                [% ELSE %]
863
                                    <a href="#return-claims" id="return-claims-tab">
864
                                        <span id="return-claims-count-resolved">0</span>
865
                                        /
866
                                        <span id="return-claims-count-unresolved">0</span>
867
                                        Claim(s)
868
                                    </a>
869
                                [% END %]
870
                            </li>
871
872
                            [% IF Koha.Preference('ArticleRequests') %]
873
                                <li>
874
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
875
                                </li>
876
                            [% END %]
877
848
                            <li><a id="debarments-tab-link" href="#reldebarments">[% debarments.count | html %] Restrictions</a></li>
878
                            <li><a id="debarments-tab-link" href="#reldebarments">[% debarments.count | html %] Restrictions</a></li>
849
879
850
                            [% SET enrollments = patron.get_club_enrollments(1) %]
880
                            [% SET enrollments = patron.get_club_enrollments(1) %]
Lines 928-933 Link Here
928
                            [% END # /IF holds_count %]
958
                            [% END # /IF holds_count %]
929
                        </div> <!-- /#reserves -->
959
                        </div> <!-- /#reserves -->
930
960
961
                        [% INCLUDE 'patron-return-claims.inc' %]
962
931
                        [% IF Koha.Preference('ArticleRequests') %]
963
                        [% IF Koha.Preference('ArticleRequests') %]
932
                            [% INCLUDE 'patron-article-requests.inc' %]
964
                            [% INCLUDE 'patron-article-requests.inc' %]
933
                        [% END %]
965
                        [% END %]
Lines 995-1000 Link Here
995
    [% Asset.js("js/circ-patron-search-results.js") | $raw %]
1027
    [% Asset.js("js/circ-patron-search-results.js") | $raw %]
996
    <script type="text/javascript">
1028
    <script type="text/javascript">
997
        /* Set some variable needed in circulation.js */
1029
        /* Set some variable needed in circulation.js */
1030
        var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]";
1031
        var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]";
1032
        var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]";
998
        var MSG_DT_LOADING_RECORDS = _("Loading... you may continue scanning.");
1033
        var MSG_DT_LOADING_RECORDS = _("Loading... you may continue scanning.");
999
        var interface = "[% interface | html %]";
1034
        var interface = "[% interface | html %]";
1000
        var theme = "[% theme | html %]";
1035
        var theme = "[% theme | html %]";
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+24 lines)
Lines 715-720 Link Here
715
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
715
                                    <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a>
716
                                </li>
716
                                </li>
717
                            [% END %]
717
                            [% END %]
718
719
                            <li>
720
                                [% IF ( patron.return_claims.count ) %]
721
                                    <a href="#return-claims" id="return-claims-tab">
722
                                        <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span>
723
                                        /
724
                                        <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span>
725
                                        Claim(s)
726
                                    </a>
727
                                [% ELSE %]
728
                                    <a href="#return-claims" id="return-claims-tab">
729
                                        <span id="return-claims-count-resolved">0</span>
730
                                        /
731
                                        <span id="return-claims-count-unresolved">0</span>
732
                                        Claim(s)
733
                                    </a>
734
                                [% END %]
735
                            </li>
736
718
                            <li>
737
                            <li>
719
                                <a id="debarments-tab-link" href="#reldebarments">[% debarments.size | html %] Restrictions</a>
738
                                <a id="debarments-tab-link" href="#reldebarments">[% debarments.size | html %] Restrictions</a>
720
                            </li>
739
                            </li>
Lines 807-812 Link Here
807
                            </div> [% # /div#reserves %]
826
                            </div> [% # /div#reserves %]
808
                        [% END %]
827
                        [% END %]
809
828
829
                        [% INCLUDE 'patron-return-claims.inc' %]
830
810
                        [% IF Koha.Preference('ArticleRequests') %]
831
                        [% IF Koha.Preference('ArticleRequests') %]
811
                            [% INCLUDE 'patron-article-requests.inc' %]
832
                            [% INCLUDE 'patron-article-requests.inc' %]
812
                        [% END %]
833
                        [% END %]
Lines 839-844 Link Here
839
    [% Asset.js("js/messaging-preference-form.js") | $raw %]
860
    [% Asset.js("js/messaging-preference-form.js") | $raw %]
840
    <script>
861
    <script>
841
        /* Set some variable needed in circulation.js */
862
        /* Set some variable needed in circulation.js */
863
        var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]";
864
        var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]";
865
        var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]";
842
        var interface = "[% interface | html %]";
866
        var interface = "[% interface | html %]";
843
        var theme = "[% theme | html %]";
867
        var theme = "[% theme | html %]";
844
        var borrowernumber = "[% patron.borrowernumber | html %]";
868
        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 538-543 $(document).ready(function() { Link Here
538
                        }
540
                        }
539
                    }
541
                    }
540
                },
542
                },
543
                {
544
                    "bVisible": ClaimReturnedLostValue ? true : false,
545
                    "bSortable": false,
546
                    "mDataProp": function ( oObj ) {
547
                        let content = "";
548
549
                        if ( oObj.return_claim_id ) {
550
                          content = `<span class="badge">${oObj.return_claim_created_on_formatted}</span>`;
551
                        } else {
552
                          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>`;
553
                        }
554
                        return content;
555
                    }
556
                },
541
                {
557
                {
542
                    "bVisible": exports_enabled == 1 ? true : false,
558
                    "bVisible": exports_enabled == 1 ? true : false,
543
                    "bSortable": false,
559
                    "bSortable": false,
Lines 808-811 $(document).ready(function() { Link Here
808
            }
824
            }
809
        } ).prop('checked', false);
825
        } ).prop('checked', false);
810
    }
826
    }
827
828
    // Handle return claims
829
    $(document).on("click", '.claim-returned-btn', function(e){
830
        e.preventDefault();
831
        itemnumber = $(this).data('itemnumber');
832
833
        $('#claims-returned-itemnumber').val(itemnumber);
834
        $('#claims-returned-notes').val("");
835
        $('#claims-returned-charge-lost-fee').attr('checked', false)
836
        $('#claims-returned-modal').modal()
837
    });
838
    $(document).on("click", '#claims-returned-modal-btn-submit', function(e){
839
        let itemnumber = $('#claims-returned-itemnumber').val();
840
        let notes = $('#claims-returned-notes').val();
841
        let fee = $('#claims-returned-charge-lost-fee').attr('checked') ? true : false;
842
843
        $('#claims-returned-modal').modal('hide')
844
845
        $(`.claim-returned-btn[data-itemnumber='${itemnumber}']`).replaceWith(`<img id='return_claim_spinner_${itemnumber}' src='${interface}/${theme}/img/spinner-small.gif' />`);
846
847
        params = {
848
            notes: notes,
849
            charge_lost_fee: fee,
850
            created_by: $.cookie("lastborrowernumber")
851
        };
852
853
        $.post( `/api/v1/return_claims/claim/${itemnumber}`, JSON.stringify(params), function( data ) {
854
855
            id = "#return_claim_spinner_" + data.itemnumber;
856
857
            let content = "";
858
            if ( data.id ) {
859
            console.log(data);
860
                content = `<span class="badge">${data.created_on_formatted}</span>`;
861
                $(id).parent().parent().addClass('ok');
862
            } else {
863
                content = RETURN_CLAIMED_FAILURE;
864
                $(id).parent().parent().addClass('warn');
865
            }
866
867
            $(id).replaceWith( content );
868
869
            refreshReturnClaimsTable();
870
        }, "json")
871
872
    });
873
874
875
    // Don't load return claims table unless it is clicked on
876
    var returnClaimsTable;
877
    $("#return-claims-tab").click( function() {
878
        refreshReturnClaimsTable();
879
    });
880
881
    function refreshReturnClaimsTable(){
882
        loadReturnClaimsTable();
883
        $("#return-claims-table").DataTable().ajax.reload();
884
    }
885
    function loadReturnClaimsTable() {
886
        if ( ! returnClaimsTable ) {
887
            returnClaimsTable = $("#return-claims-table").dataTable({
888
                "bAutoWidth": false,
889
                "sDom": "rt",
890
                "aaSorting": [],
891
                "aoColumns": [
892
                    {
893
                        "mDataProp": "id",
894
                        "bVisible": false,
895
                    },
896
                    {
897
                        "mDataProp": function ( oObj ) {
898
                              let title = `<a class="return-claim-title strong" href="/cgi-bin/koha/circ/request-rcticle.pl?biblionumber=[% rc.checkout.item.biblionumber | html %]">
899
                                  ${oObj.title}
900
                                  ${oObj.enumchron || ""}
901
                              </a>`;
902
                              if ( oObj.author ) {
903
                                title += `by ${oObj.author}`;
904
                              }
905
                              title += `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${oObj.biblionumber}&itemnumber=${oObj.itemnumber}">${oObj.barcode}</a>`;
906
907
                              return title;
908
                        }
909
                    },
910
                    {
911
                        "sClass": "return-claim-notes-td",
912
                        "mDataProp": function ( oObj ) {
913
                            return `
914
                                <span id="return-claim-notes-static-${oObj.id}" class="return-claim-notes" data-return-claim-id="${oObj.id}">${oObj.notes}</span>
915
                                <i style="float:right" class="fa fa-pencil-square-o" title="Double click to edit"></i>
916
                            `;
917
                        }
918
                    },
919
                    {
920
                        "mDataProp": "created_on",
921
                    },
922
                    {
923
                        "mDataProp": "updated_on",
924
                    },
925
                    {
926
                        "mDataProp": function ( oObj ) {
927
                            if ( ! oObj.resolution ) return "";
928
929
                            let desc = `<strong>${oObj.resolution_data.lib}</strong> on <i>${oObj.resolved_on_formatted}</i>`;
930
                            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>`;
931
                            return desc;
932
                        }
933
                    },
934
                    {
935
                        "mDataProp": function ( oObj ) {
936
                            let delete_html = oObj.resolved_on
937
                                ? `<li><a href="#" class="return-claim-tools-delete" data-return-claim-id="${oObj.id}"><i class="fa fa-trash"></i> Delete</a></li>`
938
                                : "";
939
                            let resolve_html = ! oObj.resolution
940
                                ? `<li><a href="#" class="return-claim-tools-resolve" data-return-claim-id="${oObj.id}"><i class="fa fa-check-square"></i> Resolve</a></li>`
941
                                : "";
942
943
                            return `
944
                                <div class="btn-group">
945
                                  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
946
                                    Actions <span class="caret"></span>
947
                                  </button>
948
                                  <ul class="dropdown-menu">
949
                                    <li><a href="#" class="return-claim-tools-editnotes" data-return-claim-id="${oObj.id}"><i class="fa fa-edit"></i> Edit notes</a></li>
950
                                    ${resolve_html}
951
                                    ${delete_html}
952
                                  </ul>
953
                                </div>
954
                            `;
955
                        }
956
                    },
957
                ],
958
                "bPaginate": false,
959
                "bProcessing": true,
960
                "bServerSide": false,
961
                "sAjaxSource": '/cgi-bin/koha/svc/return_claims',
962
                "fnServerData": function ( sSource, aoData, fnCallback ) {
963
                    aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
964
965
                    $.getJSON( sSource, aoData, function (json) {
966
                        let resolved = json.resolved;
967
                        let unresolved = json.unresolved;
968
969
                        $('#return-claims-count-resolved').text(resolved);
970
                        $('#return-claims-count-unresolved').text(unresolved);
971
972
                        fnCallback(json)
973
                    } );
974
                },
975
            });
976
        }
977
    }
978
979
    $('body').on('click', '.return-claim-tools-editnotes', function() {
980
        let id = $(this).data('return-claim-id');
981
        $(`#return-claim-notes-static-${id}`).parent().dblclick();
982
    });
983
    $('body').on('dblclick', '.return-claim-notes-td', function() {
984
        let elt = $(this).children('.return-claim-notes');
985
        let id = elt.data('return-claim-id');
986
        if ( $(`#return-claim-notes-editor-textarea-${id}`).length == 0 ) {
987
            let note = elt.text();
988
            let editor = `
989
                <span id="return-claim-notes-editor-${id}">
990
                    <textarea id="return-claim-notes-editor-textarea-${id}">${note}</textarea>
991
                    <br/>
992
                    <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>
993
                    <a class="claim-returned-notes-editor-cancel" data-return-claim-id="${id}" href="#">Cancel</a>
994
                </span>
995
            `;
996
            elt.hide();
997
            $(editor).insertAfter( elt );
998
        }
999
    });
1000
1001
    $('body').on('click', '.claim-returned-notes-editor-submit', function(){
1002
        let id = $(this).data('return-claim-id');
1003
        let notes = $(`#return-claim-notes-editor-textarea-${id}`).val();
1004
1005
        let params = {
1006
            notes: notes,
1007
            updated_by: $.cookie("lastborrowernumber")
1008
        };
1009
1010
        $(this).parent().remove();
1011
1012
        $.ajax({
1013
            url: `/api/v1/return_claims/${id}/notes`,
1014
            type: 'PUT',
1015
            data: JSON.stringify(params),
1016
            success: function( data ) {
1017
                let notes = $(`#return-claim-notes-static-${id}`);
1018
                notes.text(data.notes);
1019
                notes.show();
1020
            },
1021
            contentType: "json"
1022
        });
1023
    });
1024
1025
    $('body').on('click', '.claim-returned-notes-editor-cancel', function(){
1026
        let id = $(this).data('return-claim-id');
1027
        $(this).parent().remove();
1028
        $(`#return-claim-notes-static-${id}`).show();
1029
    });
1030
1031
    // Hanld return claim deletion
1032
    $('body').on('click', '.return-claim-tools-delete', function() {
1033
        let confirmed = confirm(CONFIRM_DELETE_RETURN_CLAIM);
1034
        if ( confirmed ) {
1035
            let id = $(this).data('return-claim-id');
1036
1037
            $.ajax({
1038
                url: `/api/v1/return_claims/${id}`,
1039
                type: 'DELETE',
1040
                success: function( data ) {
1041
                    refreshReturnClaimsTable();
1042
                }
1043
            });
1044
        }
1045
    });
1046
1047
    // Handle return claim resolution
1048
    $('body').on('click', '.return-claim-tools-resolve', function() {
1049
        let id = $(this).data('return-claim-id');
1050
1051
        $('#claims-returned-resolved-modal-id').val(id);
1052
        $('#claims-returned-resolved-modal').modal()
1053
    });
1054
1055
    $(document).on('click', '#claims-returned-resolved-modal-btn-submit', function(e) {
1056
        let resolution = $('#claims-returned-resolved-modal-resolved-code').val();
1057
        let id = $('#claims-returned-resolved-modal-id').val();
1058
1059
        $('#claims-returned-resolved-modal-btn-submit-spinner').show();
1060
        $('#claims-returned-resolved-modal-btn-submit-icon').hide();
1061
1062
        params = {
1063
          resolution: resolution,
1064
          updated_by: $.cookie("lastborrowernumber"),
1065
        };
1066
1067
        $.ajax({
1068
            url: `/api/v1/return_claims/${id}/resolve`,
1069
            type: 'PUT',
1070
            data: JSON.stringify(params),
1071
            success: function( data ) {
1072
                $('#claims-returned-resolved-modal-btn-submit-spinner').hide();
1073
                $('#claims-returned-resolved-modal-btn-submit-icon').show();
1074
                $('#claims-returned-resolved-modal').modal('hide')
1075
1076
                refreshReturnClaimsTable();
1077
            },
1078
            contentType: "json"
1079
        });
1080
1081
    });
1082
811
 });
1083
 });
(-)a/svc/checkouts (-21 / +40 lines)
Lines 64-91 print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); Link Here
64
my @parameters;
64
my @parameters;
65
my $sql = '
65
my $sql = '
66
    SELECT
66
    SELECT
67
        issuedate,
67
        issues.issuedate,
68
        date_due,
68
        issues.date_due,
69
        date_due < now() as date_due_overdue,
69
        issues.date_due < now() as date_due_overdue,
70
        issues.timestamp,
70
        issues.timestamp,
71
71
72
        onsite_checkout,
72
        issues.onsite_checkout,
73
73
74
        biblionumber,
74
        biblio.biblionumber,
75
        biblio.title,
75
        biblio.title,
76
        biblio.subtitle,
76
        biblio.subtitle,
77
        biblio.medium,
77
        biblio.medium,
78
        biblio.part_number,
78
        biblio.part_number,
79
        biblio.part_name,
79
        biblio.part_name,
80
        author,
80
        biblio.author,
81
81
82
        itemnumber,
82
        items.itemnumber,
83
        barcode,
83
        items.barcode,
84
        branches2.branchname AS homebranch,
84
        branches2.branchname AS homebranch,
85
        itemnotes,
85
        items.itemnotes,
86
        itemnotes_nonpublic,
86
        items.itemnotes_nonpublic,
87
        itemcallnumber,
87
        items.itemcallnumber,
88
        replacementprice,
88
        items.replacementprice,
89
89
90
        issues.branchcode,
90
        issues.branchcode,
91
        branches.branchname,
91
        branches.branchname,
Lines 95-111 my $sql = ' Link Here
95
95
96
        items.ccode AS collection,
96
        items.ccode AS collection,
97
97
98
        borrowernumber,
98
        borrowers.borrowernumber,
99
        surname,
99
        borrowers.surname,
100
        firstname,
100
        borrowers.firstname,
101
        cardnumber,
101
        borrowers.cardnumber,
102
102
103
        itemlost,
103
        items.itemlost,
104
        damaged,
104
        items.damaged,
105
        location,
105
        items.location,
106
        items.enumchron,
106
        items.enumchron,
107
107
108
        DATEDIFF( issuedate, CURRENT_DATE() ) AS not_issued_today
108
        DATEDIFF( issues.issuedate, CURRENT_DATE() ) AS not_issued_today,
109
110
        return_claims.id AS return_claim_id,
111
        return_claims.notes AS return_claim_notes,
112
        return_claims.created_on AS return_claim_created_on,
113
        return_claims.updated_on AS return_claim_updated_on
114
109
    FROM issues
115
    FROM issues
110
        LEFT JOIN items USING ( itemnumber )
116
        LEFT JOIN items USING ( itemnumber )
111
        LEFT JOIN biblio USING ( biblionumber )
117
        LEFT JOIN biblio USING ( biblionumber )
Lines 113-119 my $sql = ' Link Here
113
        LEFT JOIN borrowers USING ( borrowernumber )
119
        LEFT JOIN borrowers USING ( borrowernumber )
114
        LEFT JOIN branches ON ( issues.branchcode = branches.branchcode )
120
        LEFT JOIN branches ON ( issues.branchcode = branches.branchcode )
115
        LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode )
121
        LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode )
116
    WHERE borrowernumber
122
        LEFT JOIN return_claims USING ( issue_id )
123
    WHERE issues.borrowernumber
117
';
124
';
118
125
119
if ( @borrowernumber == 1 ) {
126
if ( @borrowernumber == 1 ) {
Lines 131-136 my $sth = $dbh->prepare($sql); Link Here
131
$sth->execute(@parameters);
138
$sth->execute(@parameters);
132
139
133
my $item_level_itypes = C4::Context->preference('item-level_itypes');
140
my $item_level_itypes = C4::Context->preference('item-level_itypes');
141
my $claims_returned_lost_value = C4::Context->preference('ClaimReturnedLostValue');
134
142
135
my @checkouts_today;
143
my @checkouts_today;
136
my @checkouts_previous;
144
my @checkouts_previous;
Lines 165-173 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
165
        $collection = $av->count ? $av->next->lib : '';
173
        $collection = $av->count ? $av->next->lib : '';
166
    }
174
    }
167
    my $lost;
175
    my $lost;
176
    my $claims_returned;
168
    if ( $c->{itemlost} ) {
177
    if ( $c->{itemlost} ) {
169
        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $c->{itemlost} });
178
        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $c->{itemlost} });
170
        $lost = $av->count ? $av->next->lib : '';
179
        $lost = $av->count ? $av->next->lib : '';
180
        $claims_returned = $c->{itemlost} eq $claims_returned_lost_value;
171
    }
181
    }
172
    my $damaged;
182
    my $damaged;
173
    if ( $c->{damaged} ) {
183
    if ( $c->{damaged} ) {
Lines 212-217 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
212
        renewals_count      => $renewals_count,
222
        renewals_count      => $renewals_count,
213
        renewals_allowed    => $renewals_allowed,
223
        renewals_allowed    => $renewals_allowed,
214
        renewals_remaining  => $renewals_remaining,
224
        renewals_remaining  => $renewals_remaining,
225
226
        return_claim_id         => $c->{return_claim_id},
227
        return_claim_notes      => $c->{return_claim_notes},
228
        return_claim_created_on => $c->{return_claim_created_on},
229
        return_claim_updated_on => $c->{return_claim_updated_on},
230
        return_claim_created_on_formatted => $c->{return_claim_created_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_created_on} ) }) : undef,
231
        return_claim_updated_on_formatted => $c->{return_claim_updated_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_updated_on} ) }) : undef,
232
215
        issuedate_formatted => output_pref(
233
        issuedate_formatted => output_pref(
216
            {
234
            {
217
                dt          => dt_from_string( $c->{issuedate} ),
235
                dt          => dt_from_string( $c->{issuedate} ),
Lines 225-230 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
225
            }
243
            }
226
        ),
244
        ),
227
        lost    => $lost,
245
        lost    => $lost,
246
        claims_returned => $claims_returned,
228
        damaged => $damaged,
247
        damaged => $damaged,
229
        borrower => {
248
        borrower => {
230
            surname    => $c->{surname},
249
            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 / +159 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);

Return to bug 14697