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

(-)a/Koha/REST/V1/Patron.pm (-6 / +137 lines)
Lines 18-32 package Koha::REST::V1::Patron; Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
21
use Koha::AuthUtils qw(hash_password);
22
use Koha::Patrons;
22
use Koha::Patrons;
23
use Koha::Patron::Categories;
24
use Koha::Libraries;
23
25
24
sub list {
26
sub list {
25
    my ($c, $args, $cb) = @_;
27
    my ($c, $args, $cb) = @_;
26
28
27
    my $user = $c->stash('koha.user');
29
    my $params = $c->req->query_params->to_hash;
28
30
    my $patrons;
29
    my $patrons = Koha::Patrons->search;
31
    if (keys %$params) {
32
        my @valid_params = Koha::Patrons->columns;
33
        foreach my $key (keys %$params) {
34
            delete $params->{$key} unless grep { $key eq $_ } @valid_params;
35
        }
36
        $patrons = Koha::Patrons->search($params);
37
    } else {
38
        $patrons = Koha::Patrons->search;
39
    }
30
40
31
    $c->$cb($patrons->unblessed, 200);
41
    $c->$cb($patrons->unblessed, 200);
32
}
42
}
Lines 34-41 sub list { Link Here
34
sub get {
44
sub get {
35
    my ($c, $args, $cb) = @_;
45
    my ($c, $args, $cb) = @_;
36
46
37
    my $user = $c->stash('koha.user');
38
39
    my $patron = Koha::Patrons->find($args->{borrowernumber});
47
    my $patron = Koha::Patrons->find($args->{borrowernumber});
40
    unless ($patron) {
48
    unless ($patron) {
41
        return $c->$cb({error => "Patron not found"}, 404);
49
        return $c->$cb({error => "Patron not found"}, 404);
Lines 44-47 sub get { Link Here
44
    return $c->$cb($patron->unblessed, 200);
52
    return $c->$cb($patron->unblessed, 200);
45
}
53
}
46
54
55
sub add {
56
    my ($c, $args, $cb) = @_;
57
58
    my $body = $c->req->json;
59
60
    # patron cardnumber and/or userid unique?
61
    if ($body->{cardnumber} || $body->{userid}) {
62
        my $patron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
63
        if ($patron) {
64
            return $c->$cb({
65
                error => "Patron cardnumber and userid must be unique",
66
                conflict => { cardnumber => $patron->cardnumber, userid => $patron->userid }
67
            }, 409);
68
        }
69
    }
70
71
    my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
72
    unless ($branch) {
73
        return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
74
    }
75
    my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
76
    unless ($category) {
77
        return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
78
    }
79
    # All OK - save new patron
80
81
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
82
83
    my $patron = eval {
84
        Koha::Patron->new($body)->store;
85
    };
86
87
    unless ($patron) {
88
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
89
    }
90
91
    return $c->$cb($patron->unblessed, 201);
92
}
93
94
sub edit {
95
    my ($c, $args, $cb) = @_;
96
97
    my $patron = Koha::Patrons->find($args->{borrowernumber});
98
    unless ($patron) {
99
        return $c->$cb({error => "Patron not found"}, 404);
100
    }
101
102
    my $body = $c->req->json;
103
104
    # Can we change userid and/or cardnumber? in that case check that they are altered first
105
    if ($body->{cardnumber} || $body->{userid}) {
106
        if ( ($body->{cardnumber} && $body->{cardnumber} ne $patron->cardnumber) || ($body->{userid} && $body->{userid} ne $patron->userid) ) {
107
            my $conflictingPatron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
108
            if ($conflictingPatron) {
109
                return $c->$cb({
110
                    error => "Patron cardnumber and userid must be unique",
111
                    conflict => { cardnumber => $conflictingPatron->cardnumber, userid => $conflictingPatron->userid }
112
                }, 409);
113
            }
114
        }
115
    }
116
117
    if ($body->{branchcode}) {
118
        my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
119
        unless ($branch) {
120
            return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
121
        }
122
    }
123
124
    if ($body->{categorycode}) {
125
        my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
126
        unless ($category) {
127
            return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
128
        }
129
    }
130
    # ALL OK - Update patron
131
    # Perhaps limit/validate what should be updated here? flags, et.al.
132
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
133
134
    my $updatedpatron = eval {
135
        $patron->set($body);
136
    };
137
138
    if ($updatedpatron) {
139
        if ($updatedpatron->is_changed) {
140
141
            my $res = eval {
142
                $updatedpatron->store;
143
            };
144
145
            unless ($res) {
146
                return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
147
            }
148
            return $c->$cb($res->unblessed, 200);
149
150
        } else {
151
            return $c->$cb({}, 204); # No Content = No changes made
152
        }
153
    } else {
154
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
155
    }
156
}
157
158
sub delete {
159
    my ($c, $args, $cb) = @_;
160
161
    my $patron = Koha::Patrons->find($args->{borrowernumber});
162
    unless ($patron) {
163
        return $c->$cb({error => "Patron not found"}, 404);
164
    }
165
166
    # check if loans, reservations, debarrment, etc. before deletion!
167
    my $res = $patron->delete;
168
169
    if ($res eq '1') {
170
        return $c->$cb({}, 200);
171
    } elsif ($res eq '-1') {
172
        return $c->$cb({}, 404);
173
    } else {
174
        return $c->$cb({}, 400);
175
    }
176
}
177
47
1;
178
1;
(-)a/api/v1/swagger/paths/patrons.json (-4 / +165 lines)
Lines 28-33 Link Here
28
          "borrowers": "1"
28
          "borrowers": "1"
29
        }
29
        }
30
      }
30
      }
31
    },
32
    "post": {
33
      "operationId": "addPatron",
34
      "tags": ["patrons"],
35
      "parameters": [{
36
        "name": "body",
37
        "in": "body",
38
        "description": "A JSON object containing information about the new patron",
39
        "required": true,
40
        "schema": {
41
          "$ref": "../definitions.json#/patron"
42
        }
43
      }],
44
      "consumes": ["application/json"],
45
      "produces": ["application/json"],
46
      "responses": {
47
        "201": {
48
          "description": "A successfully created patron",
49
          "schema": {
50
            "items": {
51
              "$ref": "../definitions.json#/patron"
52
            }
53
          }
54
        },
55
        "403": {
56
          "description": "Access forbidden",
57
          "schema": {
58
            "$ref": "../definitions.json#/error"
59
          }
60
        },
61
        "404": {
62
          "description": "Resource not found",
63
          "schema": {
64
            "$ref": "../definitions.json#/error"
65
          }
66
        },
67
        "409": {
68
          "description": "Conflict in creating resource",
69
          "schema": {
70
            "$ref": "../definitions.json#/error"
71
          }
72
        },
73
        "500": {
74
          "description": "Internal error",
75
          "schema": {
76
            "$ref": "../definitions.json#/error"
77
          }
78
        }
79
      },
80
      "x-koha-authorization": {
81
        "permissions": {
82
          "borrowers": "1"
83
        }
84
      }
31
    }
85
    }
32
  },
86
  },
33
  "/patrons/{borrowernumber}": {
87
  "/patrons/{borrowernumber}": {
Lines 35-45 Link Here
35
      "operationId": "getPatron",
89
      "operationId": "getPatron",
36
      "tags": ["patrons"],
90
      "tags": ["patrons"],
37
      "parameters": [{
91
      "parameters": [{
38
          "$ref": "../parameters.json#/borrowernumberPathParam"
92
        "$ref": "../parameters.json#/borrowernumberPathParam"
39
        }
93
      }],
40
      ],
41
      "produces": [
94
      "produces": [
42
          "application/json"
95
        "application/json"
43
      ],
96
      ],
44
      "responses": {
97
      "responses": {
45
        "200": {
98
        "200": {
Lines 68-73 Link Here
68
          "borrowers": "1"
121
          "borrowers": "1"
69
        }
122
        }
70
      }
123
      }
124
    },
125
    "put": {
126
      "operationId": "editPatron",
127
      "tags": ["patrons"],
128
      "parameters": [
129
        {
130
          "$ref": "../parameters.json#/borrowernumberPathParam"
131
        },
132
        {
133
          "name": "body",
134
          "in": "body",
135
          "description": "A JSON object containing new information about existing patron",
136
          "required": true,
137
          "schema": {
138
            "$ref": "../definitions.json#/patron"
139
          }
140
        }
141
      ],
142
      "consumes": ["application/json"],
143
      "produces": ["application/json"],
144
      "responses": {
145
        "200": {
146
          "description": "A successfully updated patron",
147
          "schema": {
148
            "items": {
149
              "$ref": "../definitions.json#/patron"
150
            }
151
          }
152
        },
153
        "204": {
154
          "description": "No Content",
155
          "schema": {
156
            "type": "object"
157
          }
158
        },
159
        "403": {
160
          "description": "Access forbidden",
161
          "schema": {
162
            "$ref": "../definitions.json#/error"
163
          }
164
        },
165
        "404": {
166
          "description": "Resource not found",
167
          "schema": {
168
            "$ref": "../definitions.json#/error"
169
          }
170
        },
171
        "409": {
172
          "description": "Conflict in updating resource",
173
          "schema": {
174
            "$ref": "../definitions.json#/error"
175
          }
176
        },
177
        "500": {
178
          "description": "Internal error",
179
          "schema": {
180
            "$ref": "../definitions.json#/error"
181
          }
182
        }
183
      },
184
      "x-koha-authorization": {
185
        "allow-owner": true,
186
        "allow-guarantor": true,
187
        "permissions": {
188
          "borrowers": "1"
189
        }
190
      }
191
    },
192
    "delete": {
193
      "operationId": "deletePatron",
194
      "tags": ["patrons"],
195
      "parameters": [{
196
        "$ref": "../parameters.json#/borrowernumberPathParam"
197
      }],
198
      "produces": ["application/json"],
199
      "responses": {
200
        "200": {
201
          "description": "Patron deleted successfully",
202
          "schema": {
203
            "type": "object"
204
          }
205
        },
206
        "400": {
207
          "description": "Patron deletion failed",
208
          "schema": {
209
            "$ref": "../definitions.json#/error"
210
          }
211
        },
212
        "403": {
213
          "description": "Access forbidden",
214
          "schema": {
215
            "$ref": "../definitions.json#/error"
216
          }
217
        },
218
        "404": {
219
          "description": "Patron not found",
220
          "schema": {
221
            "$ref": "../definitions.json#/error"
222
          }
223
        }
224
      },
225
      "x-koha-authorization": {
226
        "allow-owner": true,
227
        "allow-guarantor": true,
228
        "permissions": {
229
          "borrowers": "1"
230
        }
231
      }
71
    }
232
    }
72
  }
233
  }
73
}
234
}
(-)a/t/db_dependent/api/v1/patrons.t (-17 / +152 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 20;
20
use Test::More tests => 74;
21
use Test::Mojo;
21
use Test::Mojo;
22
use t::lib::TestBuilder;
22
use t::lib::TestBuilder;
23
23
Lines 25-41 use C4::Auth; Link Here
25
use C4::Context;
25
use C4::Context;
26
26
27
use Koha::Database;
27
use Koha::Database;
28
use Koha::Patron;
29
28
30
my $builder = t::lib::TestBuilder->new();
29
BEGIN {
30
    use_ok('Koha::Object');
31
    use_ok('Koha::Patron');
32
}
31
33
34
my $builder = t::lib::TestBuilder->new();
32
my $dbh = C4::Context->dbh;
35
my $dbh = C4::Context->dbh;
33
$dbh->{AutoCommit} = 0;
36
my $schema  = Koha::Database->schema;
34
$dbh->{RaiseError} = 1;
35
37
36
$ENV{REMOTE_ADDR} = '127.0.0.1';
38
$ENV{REMOTE_ADDR} = '127.0.0.1';
37
my $t = Test::Mojo->new('Koha::REST::V1');
39
my $t = Test::Mojo->new('Koha::REST::V1');
38
40
41
$schema->storage->txn_begin;
42
39
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
43
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
40
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
44
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
41
my $guarantor = $builder->build({
45
my $guarantor = $builder->build({
Lines 46-52 my $guarantor = $builder->build({ Link Here
46
        flags        => 0,
50
        flags        => 0,
47
    }
51
    }
48
});
52
});
49
my $borrower = $builder->build({
53
my $patron = $builder->build({
50
    source => 'Borrower',
54
    source => 'Borrower',
51
    value => {
55
    value => {
52
        branchcode   => $branchcode,
56
        branchcode   => $branchcode,
Lines 59-70 my $borrower = $builder->build({ Link Here
59
$t->get_ok('/api/v1/patrons')
63
$t->get_ok('/api/v1/patrons')
60
  ->status_is(401);
64
  ->status_is(401);
61
65
62
$t->get_ok("/api/v1/patrons/" . $borrower->{ borrowernumber })
66
$t->get_ok("/api/v1/patrons/" . $patron->{ borrowernumber })
63
  ->status_is(401);
67
  ->status_is(401);
64
68
65
my $session = C4::Auth::get_session('');
69
my $session = C4::Auth::get_session('');
66
$session->param('number', $borrower->{ borrowernumber });
70
$session->param('number', $patron->{ borrowernumber });
67
$session->param('id', $borrower->{ userid });
71
$session->param('id', $patron->{ userid });
68
$session->param('ip', '127.0.0.1');
72
$session->param('ip', '127.0.0.1');
69
$session->param('lasttime', time());
73
$session->param('lasttime', time());
70
$session->flush;
74
$session->flush;
Lines 81-100 $tx->req->cookies({name => 'CGISESSID', value => $session->id}); Link Here
81
$t->request_ok($tx)
85
$t->request_ok($tx)
82
  ->status_is(403);
86
  ->status_is(403);
83
87
84
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . ($borrower->{ borrowernumber }-1));
88
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . ($patron->{ borrowernumber }-1));
85
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
89
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
86
$t->request_ok($tx)
90
$t->request_ok($tx)
87
  ->status_is(403)
91
  ->status_is(403)
88
  ->json_is('/required_permissions', {"borrowers" => "1"});
92
  ->json_is('/required_permissions', {"borrowers" => "1"});
89
93
90
# User without permissions, but is the owner of the object
94
# User without permissions, but is the owner of the object
91
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $borrower->{borrowernumber});
95
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $patron->{borrowernumber});
92
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
96
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
93
$t->request_ok($tx)
97
$t->request_ok($tx)
94
  ->status_is(200);
98
  ->status_is(200);
95
99
96
# User without permissions, but is the guarantor of the owner of the object
100
# User without permissions, but is the guarantor of the owner of the object
97
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $borrower->{borrowernumber});
101
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $patron->{borrowernumber});
98
$tx->req->cookies({name => 'CGISESSID', value => $session2->id});
102
$tx->req->cookies({name => 'CGISESSID', value => $session2->id});
99
$t->request_ok($tx)
103
$t->request_ok($tx)
100
  ->status_is(200)
104
  ->status_is(200)
Lines 121-132 $tx->req->cookies({name => 'CGISESSID', value => $session->id}); Link Here
121
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
125
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
122
$t->request_ok($tx)
126
$t->request_ok($tx)
123
  ->status_is(200);
127
  ->status_is(200);
128
ok(@{$tx->res->json} >= 1, 'Json response lists all when no params given');
124
129
125
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $borrower->{ borrowernumber });
130
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $patron->{ borrowernumber });
126
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
131
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
127
$t->request_ok($tx)
132
$t->request_ok($tx)
128
  ->status_is(200)
133
  ->status_is(200)
129
  ->json_is('/borrowernumber' => $borrower->{ borrowernumber })
134
  ->json_is('/borrowernumber' => $patron->{ borrowernumber })
130
  ->json_is('/surname' => $borrower->{ surname });
135
  ->json_is('/surname' => $patron->{ surname });
136
137
$tx = $t->ua->build_tx(GET => '/api/v1/patrons' => form => {surname => 'nonexistent'});
138
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
139
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
140
$t->request_ok($tx)
141
  ->status_is(200);
142
ok(@{$tx->res->json} == 0, "Json response yields no results when params doesn't match");
143
144
$tx = $t->ua->build_tx(GET => '/api/v1/patrons' => form => {surname => $patron->{ surname }});
145
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
146
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
147
$t->request_ok($tx)
148
  ->status_is(200)
149
  ->json_has($patron);
150
ok(@{$tx->res->json} == 1, 'Json response yields expected results when params match');
151
152
### POST /api/v1/patrons
153
154
my $newpatron = {
155
  branchcode   => $branchcode,
156
  categorycode => $categorycode,
157
  surname      => "TestUser",
158
  cardnumber => "123456",
159
  userid => "testuser"
160
};
161
162
$newpatron->{ branchcode } = "nonexistent"; # Test invalid branchcode
163
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
164
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
165
$t->request_ok($tx)
166
  ->status_is(404)
167
  ->json_is('/error' => "Library with branchcode \"nonexistent\" does not exist");
168
169
$newpatron->{ branchcode } = $branchcode;
170
$newpatron->{ categorycode } = "nonexistent"; # Test invalid patron category
171
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
172
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
173
$t->request_ok($tx)
174
  ->status_is(404)
175
  ->json_is('/error' => "Patron category \"nonexistent\" does not exist");
176
$newpatron->{ categorycode } = $categorycode;
177
178
$newpatron->{ falseproperty } = "Non existent property";
179
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
180
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
181
$t->request_ok($tx)
182
  ->status_is(500)
183
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
184
185
delete $newpatron->{ falseproperty };
186
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
187
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
188
$t->request_ok($tx)
189
  ->status_is(201, 'Patron created successfully')
190
  ->json_has('/borrowernumber', 'got a borrowernumber')
191
  ->json_is('/cardnumber', $newpatron->{ cardnumber })
192
  ->json_is('/surname' => $newpatron->{ surname })
193
  ->json_is('/firstname' => $newpatron->{ firstname });
194
$newpatron->{borrowernumber} = $tx->res->json->{borrowernumber};
195
196
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
197
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
198
$t->request_ok($tx)
199
  ->status_is(409)
200
  ->json_has('/error', 'Fails when trying to POST duplicate cardnumber or userid')
201
  ->json_has('/conflict', { userid => $newpatron->{ userid }, cardnumber => $newpatron->{ cardnumber } });
202
203
### PUT /api/v1/patrons
204
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/0" => json => {});
205
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
206
$t->request_ok($tx)
207
  ->status_is(404)
208
  ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
209
210
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {categorycode => "nonexistent"});
211
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
212
$t->request_ok($tx)
213
  ->status_is(404)
214
  ->json_is('/error' => "Patron category \"nonexistent\" does not exist");
215
216
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {branchcode => "nonexistent"});
217
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
218
$t->request_ok($tx)
219
  ->status_is(404)
220
  ->json_is('/error' => "Library with branchcode \"nonexistent\" does not exist");
221
222
$newpatron->{ falseproperty } = "Non existent property";
223
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
224
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
225
$t->request_ok($tx)
226
  ->status_is(500)
227
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
228
delete $newpatron->{ falseproperty };
229
230
$newpatron->{ cardnumber } = $patron-> { cardnumber };
231
$newpatron->{ userid } = $patron-> { userid };
232
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
233
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
234
$t->request_ok($tx)
235
  ->status_is(409)
236
  ->json_has('/error' => "Fails when trying to update to an existing cardnumber or userid")
237
  ->json_has('/conflict', { cardnumber => $patron->{ cardnumber }, userid => $patron->{ userid } });
238
239
$newpatron->{ cardnumber } = "123456";
240
$newpatron->{ userid } = "testuser";
241
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
242
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
243
$t->request_ok($tx)
244
  ->status_is(204, 'No changes - patron NOT updated');
245
246
$newpatron->{ cardnumber } = "234567";
247
$newpatron->{ userid } = "updatedtestuser";
248
$newpatron->{ surname } = "UpdatedTestUser";
249
250
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
251
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
252
$t->request_ok($tx)
253
  ->status_is(200, 'Patron updated successfully')
254
  ->json_has($newpatron);
255
256
### DELETE /api/v1/patrons
257
258
$tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/0");
259
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
260
$t->request_ok($tx)
261
  ->status_is(404, 'Patron not found');
262
263
$tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/" . $newpatron->{ borrowernumber });
264
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
265
$t->request_ok($tx)
266
  ->status_is(200, 'Patron deleted successfully');
131
267
132
$dbh->rollback;
268
$schema->storage->txn_rollback;
133
- 

Return to bug 16330