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

(-)a/Koha/REST/V1/Checkouts.pm (+94 lines)
Lines 281-286 sub add { Link Here
281
    };
281
    };
282
}
282
}
283
283
284
=head3 checkin
285
286
Check in a checked out item via item_id or barcode
287
288
=cut
289
290
sub checkin {
291
292
    my $c          = shift->openapi->valid_input or return;
293
    my $body       = $c->req->json;
294
    my $item_id    = $body->{item_id};
295
    my $barcode    = $body->{external_id};
296
    my $library_id = $body->{library_id};
297
298
    my $exemptfine = $body->{exemptfine};
299
300
    return try {
301
302
        unless ( $item_id or $barcode ) {
303
            return $c->render(
304
                status  => 400,
305
                openapi => {
306
                    error      => 'Missing or wrong parameters',
307
                    error_code => 'MISSING_OR_WRONG_PARAMETERS',
308
                }
309
            );
310
        }
311
312
        my $item;
313
        if ($item_id) {
314
            $item = Koha::Items->find($item_id);
315
        }
316
        else {
317
            $item = Koha::Items->find( { barcode => $barcode } );
318
        }
319
320
        unless ($item) {
321
            return $c->render(
322
                status  => 404,
323
                openapi => {
324
                    error      => 'Item not found',
325
                    error_code => 'ITEM_NOT_FOUND',
326
                }
327
            );
328
        }
329
330
        # check that item matches when barcode and item_id were given
331
        if (    $item_id
332
            and $barcode
333
            and ( $item->barcode ne $barcode or $item->id != $item_id ) )
334
        {
335
            return $c->render(
336
                status  => 409,
337
                openapi => {
338
                    error =>
339
                      'Item id and external id belong to different items',
340
                    error_code => 'ITEM_ID_NOT_MATCHING_EXTERNAL_ID',
341
                }
342
            );
343
        }
344
345
        my ( $returned, $return_messages ) =
346
          C4::Circulation::AddReturn( $item->barcode, $library_id,
347
            $exemptfine );
348
349
        my $response = { returned => $returned, messages => $return_messages };
350
351
        if ($return_messages->{BadBarcode}){
352
          $response->{error} = 'Item not found.';
353
          return $c->render(
354
                  status  => 409,
355
                  openapi => $response
356
              );
357
        }
358
359
        unless ($returned) {
360
            return $c->render(
361
                status  => 403,
362
                openapi => $response
363
            );
364
        }
365
366
        $c->res->headers->location( $c->req->url->to_string );
367
        return $c->render(
368
            status  => 201,
369
            openapi => $response
370
        );
371
372
    }
373
    catch {
374
        $c->unhandled_exception($_);
375
    };
376
}
377
284
=head3 get_renewals
378
=head3 get_renewals
285
379
286
List Koha::Checkout::Renewals
380
List Koha::Checkout::Renewals
(-)a/api/v1/swagger/definitions/checkin.yaml (+20 lines)
Line 0 Link Here
1
---
2
type: object
3
properties:
4
  returned:
5
    type: integer
6
    description: True if return checkin succeeded
7
    readOnly: true
8
  messages:
9
    description: Messages to the returned item
10
    type: object
11
  item_id:
12
    type: integer
13
    description: Internal item identifier
14
  external_id:
15
    type: string
16
    description: Barcode of the item
17
  exemptfine:
18
    type: boolean
19
    description: If true overdue charges for the item will be removed
20
additionalProperties: true
(-)a/api/v1/swagger/paths/checkin.yaml (+63 lines)
Line 0 Link Here
1
---
2
/checkin:
3
  post:
4
    x-mojo-to: Checkouts#checkin
5
    operationId: addCheckin
6
    tags:
7
      - checkin
8
      - patrons
9
    summary: Add a checkin
10
    parameters:
11
      - name: body
12
        in: body
13
        description: A JSON object containing information about the checkin
14
        required: true
15
        schema:
16
          $ref: "../swagger.yaml#/definitions/checkin"
17
    consumes:
18
      - application/json
19
    produces:
20
      - application/json
21
    responses:
22
      "201":
23
        description: Created checkin
24
        schema:
25
          $ref: "../swagger.yaml#/definitions/checkin"
26
      "400":
27
        description: Missing or wrong parameters
28
        schema:
29
          $ref: "../swagger.yaml#/definitions/error"
30
      "401":
31
        description: Authentication required
32
        schema:
33
          $ref: "../swagger.yaml#/definitions/error"
34
      "403":
35
        description: Cannot create checkin
36
        schema:
37
          $ref: "../swagger.yaml#/definitions/checkin"
38
      "404":
39
        description: Item not found
40
        schema:
41
          $ref: "../swagger.yaml#/definitions/error"
42
      "409":
43
        description: Conflict in creating checkin
44
        schema:
45
          $ref: "../swagger.yaml#/definitions/error"
46
      "412":
47
        description: Precondition failed
48
        schema:
49
          $ref: "../swagger.yaml#/definitions/error"
50
      "500":
51
        description: |
52
          Internal server error. Possible `error_code` attribute values:
53
54
          * `internal_server_error`
55
        schema:
56
          $ref: "../swagger.yaml#/definitions/error"
57
      "503":
58
        description: Under maintenance
59
        schema:
60
          $ref: "../swagger.yaml#/definitions/error"
61
    x-koha-authorization:
62
      permissions:
63
        circulate: circulate_remaining_permissions
(-)a/api/v1/swagger/swagger.yaml (+4 lines)
Lines 26-31 definitions: Link Here
26
    $ref: ./definitions/cash_register.yaml
26
    $ref: ./definitions/cash_register.yaml
27
  cashup:
27
  cashup:
28
    $ref: ./definitions/cashup.yaml
28
    $ref: ./definitions/cashup.yaml
29
  checkin:
30
    $ref: ./definitions/checkin.yaml
29
  checkout:
31
  checkout:
30
    $ref: ./definitions/checkout.yaml
32
    $ref: ./definitions/checkout.yaml
31
  checkouts:
33
  checkouts:
Lines 271-276 paths: Link Here
271
    $ref: "./paths/cash_registers.yaml#/~1cash_registers~1{cash_register_id}~1cashups"
273
    $ref: "./paths/cash_registers.yaml#/~1cash_registers~1{cash_register_id}~1cashups"
272
  "/cashups/{cashup_id}":
274
  "/cashups/{cashup_id}":
273
    $ref: "./paths/cash_registers.yaml#/~1cashups~1{cashup_id}"
275
    $ref: "./paths/cash_registers.yaml#/~1cashups~1{cashup_id}"
276
  /checkin:
277
    $ref: ./paths/checkin.yaml#/~1checkin
274
  /checkouts:
278
  /checkouts:
275
    $ref: ./paths/checkouts.yaml#/~1checkouts
279
    $ref: ./paths/checkouts.yaml#/~1checkouts
276
  "/checkouts/{checkout_id}":
280
  "/checkouts/{checkout_id}":
(-)a/t/db_dependent/api/v1/checkin.t (-1 / +192 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
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 22;
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 qw( AddIssue AddReturn CanBookBeIssued );
30
31
use Koha::Database;
32
use Koha::DateUtils qw( dt_from_string output_pref );
33
use Koha::Token;
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 $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
46
my $librarian  = $builder->build_object(
47
    {
48
        class => 'Koha::Patrons',
49
        value => { flags => 2, branchcode => $branchcode }
50
    }
51
);
52
my $password = 'thePassword123';
53
$librarian->set_password( { password => $password, skip_validation => 1 } );
54
my $userid = $librarian->userid;
55
56
my $other_branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
57
my $patron           = $builder->build_object(
58
    {
59
        class => 'Koha::Patrons',
60
        value => { flags => 0, branchcode => $other_branchcode },
61
    }
62
);
63
my $unauth_password = 'thePassword000';
64
$patron->set_password(
65
    { password => $unauth_password, skip_validattion => 1 } );
66
my $unauth_userid = $patron->userid;
67
my $patron_id     = $patron->borrowernumber;
68
69
my $item1    = $builder->build_sample_item;
70
my $item1_id = $item1->id;
71
72
my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
73
my $biblio_2 = $builder->build_sample_biblio;
74
my $item_2   = $builder->build_sample_item(
75
    { biblionumber => $biblio_2->biblionumber, itype => $itemtype } );
76
my $item_2_barcode = $item_2->barcode;
77
my $item_2_id      = $item_2->id;
78
79
my $not_issued_item         = $builder->build_sample_item;
80
my $not_issued_item_id      = $not_issued_item->id;
81
my $not_issued_item_barcode = $not_issued_item->barcode;
82
83
my $barcode        = '321321321321';
84
my $matching_items = Koha::Items->search( { barcode => $barcode } );
85
while ( my $item = $matching_items->next ) {
86
    $item->delete;
87
}
88
89
my $non_existent_item         = $builder->build_sample_item;
90
my $non_existent_item_id      = $non_existent_item->id;
91
my $non_existent_item_barcode = $non_existent_item->barcode;
92
$non_existent_item->delete;
93
94
my $checkout = $builder->build_object(
95
    {
96
        class => 'Koha::Checkouts',
97
        value => {
98
            itemnumber     => $item1_id,
99
            branchcode     => $branchcode,
100
            borrowernumber => $patron_id,
101
            note           => undef,
102
            notedate       => undef,
103
            noteseen       => undef
104
        }
105
    }
106
);
107
my $checkout_id = $checkout->id;
108
109
my $reserved_checkout = $builder->build_object(
110
    {
111
        class => 'Koha::Checkouts',
112
        value => {
113
            itemnumber     => $item_2_id,
114
            branchcode     => $branchcode,
115
            borrowernumber => $patron_id,
116
            note           => undef,
117
            notedate       => undef,
118
            noteseen       => undef
119
        }
120
    }
121
);
122
my $reserved_checkout_id = $reserved_checkout->id;
123
124
$dbh->do('DELETE FROM reserves');
125
Koha::CirculationRules->search()->delete();
126
Koha::CirculationRules->set_rules(
127
    {
128
        categorycode => undef,
129
        branchcode   => undef,
130
        itemtype     => undef,
131
        rules        => {
132
            reservesallowed  => 1,
133
            holds_per_record => 99
134
        }
135
    }
136
);
137
138
my $reserve_id = C4::Reserves::AddReserve(
139
    {
140
        branchcode     => $branchcode,
141
        borrowernumber => $patron->borrowernumber,
142
        biblionumber   => $biblio_2->biblionumber,
143
        priority       => 1,
144
        itemnumber     => $item_2->itemnumber,
145
    }
146
);
147
148
# empty checkin
149
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json => {} )
150
  ->status_is(400);
151
152
# checkin on unknow item id
153
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json =>
154
      { item_id => $non_existent_item_id } )->status_is(404)
155
  ->json_is( { error => 'Item not found', error_code => 'ITEM_NOT_FOUND' } );
156
157
# checkin with unknow barcode
158
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json =>
159
      { external_id => $non_existent_item_barcode } )->status_is(404)
160
  ->json_is( { error => 'Item not found', error_code => 'ITEM_NOT_FOUND' } );
161
162
# not isued
163
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json =>
164
      { item_id => $not_issued_item_id, library_id => $branchcode } )
165
  ->status_is(403)->json_is( '/returned' => 0 )
166
  ->json_has( '/messages' => { NotIssued => $not_issued_item_barcode } );
167
168
# checkin okay
169
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json =>
170
      { item_id => $item1_id, library_id => $branchcode } )->status_is(201)
171
  ->json_is( '/returned' => 1 )
172
  ->json_has(
173
    '/messages' => { TransferTrigger => 'ReturnToHome', WasReturned => '1' } );
174
175
#mismatch of item_id and barcode when both given
176
$t->post_ok(
177
    "//$userid:$password@/api/v1/checkin" => json => {
178
        item_id     => $not_issued_item_id,
179
        external_id => $item_2_barcode,
180
        library_id  => $branchcode
181
    }
182
)->status_is(409);
183
184
# reserved item
185
$t->post_ok( "//$userid:$password@/api/v1/checkin" => json =>
186
      { item_id => $item_2_id, library_id => $branchcode } )->status_is(201)
187
  ->json_is( '/returned' => 1 )->json_has(
188
    '/messages' => { WasReturned => '1' },
189
    '/ResFound' => { "ResFound"  => "Reserved" }
190
  );
191
192
$schema->storage->txn_rollback;

Return to bug 24401