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

(-)a/Koha/REST/V1/Items.pm (-20 / +49 lines)
Lines 27-45 use List::MoreUtils qw( any ); Link Here
27
use Try::Tiny qw( catch try );
27
use Try::Tiny qw( catch try );
28
28
29
=head1 NAME
29
=head1 NAME
30
31
Koha::REST::V1::Items - Koha REST API for handling items (V1)
30
Koha::REST::V1::Items - Koha REST API for handling items (V1)
32
33
=head1 API
31
=head1 API
34
35
=head2 Methods
32
=head2 Methods
36
37
=cut
33
=cut
38
34
39
=head3 list
35
=head3 list
40
41
Controller function that handles listing Koha::Item objects
36
Controller function that handles listing Koha::Item objects
42
43
=cut
37
=cut
44
38
45
sub list {
39
sub list {
Lines 59-67 sub list { Link Here
59
}
53
}
60
54
61
=head3 list_public
55
=head3 list_public
62
63
Controller function that handles listing Koha::Item objects available to the opac
56
Controller function that handles listing Koha::Item objects available to the opac
64
65
=cut
57
=cut
66
58
67
sub list_public {
59
sub list_public {
Lines 85-93 sub list_public { Link Here
85
}
77
}
86
78
87
=head3 get
79
=head3 get
88
89
Controller function that handles retrieving a single Koha::Item
80
Controller function that handles retrieving a single Koha::Item
90
91
=cut
81
=cut
92
82
93
sub get {
83
sub get {
Lines 110-118 sub get { Link Here
110
}
100
}
111
101
112
=head3 delete
102
=head3 delete
113
114
Controller function that handles deleting a single Koha::Item
103
Controller function that handles deleting a single Koha::Item
115
116
=cut
104
=cut
117
105
118
sub delete {
106
sub delete {
Lines 173-184 sub delete { Link Here
173
        $c->unhandled_exception($_);
161
        $c->unhandled_exception($_);
174
    };
162
    };
175
}
163
}
164
=head3 checkout
176
165
177
=head3 pickup_locations
166
Check out an item
167
168
=cut
169
170
sub checkout {
171
    my $c = shift->openapi->valid_input or return;
172
    my $item_id = $c->validation->param('item_id');
173
    my $item = Koha::Items->find( $item_id );
174
    unless ( $item ) {
175
        return $c->render(
176
            status  => 404,
177
            openapi => { error => "Item not found" }
178
        );
179
    }
180
    my $patron_id = $c->validation->param('patron_id');
181
    my $patron    = Koha::Patrons->find( $patron_id );
182
    unless ( $patron ) {
183
        return $c->render(
184
            status  => 400,
185
            openapi => { error => "Patron not found" }
186
        );
187
    }
188
    try {
189
        my $barcode = $item->barcode;
190
        my ( $issuing_impossible, $needs_confirmation ) = C4::Circulation::CanBookBeIssued( $patron, $barcode );
191
        if ( keys %$issuing_impossible or keys %$needs_confirmation ) {
192
            return $c->render(
193
                status => 403,
194
                openapi => { error => "Checkout not allowed" }
195
            );
196
        }
197
        my $borrower = $patron->unblessed;
198
        my $checkout = C4::Circulation::AddIssue(
199
           $borrower,
200
           $barcode
201
        );
202
203
        $c->res->headers->location( $c->req->url->to_string );
204
        return $c->render(
205
            status  => 201,
206
            openapi => $checkout->to_api
207
        );
208
    }
209
    catch {
210
        $c->unhandled_exception($_);
211
    };
212
}
178
213
214
=head3 pickup_locations
179
Method that returns the possible pickup_locations for a given item
215
Method that returns the possible pickup_locations for a given item
180
used for building the dropdown selector
216
used for building the dropdown selector
181
182
=cut
217
=cut
183
218
184
sub pickup_locations {
219
sub pickup_locations {
Lines 242-250 sub pickup_locations { Link Here
242
}
277
}
243
278
244
=head3 bundled_items
279
=head3 bundled_items
245
246
Controller function that handles bundled_items Koha::Item objects
280
Controller function that handles bundled_items Koha::Item objects
247
248
=cut
281
=cut
249
282
250
sub bundled_items {
283
sub bundled_items {
Lines 274-282 sub bundled_items { Link Here
274
}
307
}
275
308
276
=head3 add_to_bundle
309
=head3 add_to_bundle
277
278
Controller function that handles adding items to this bundle
310
Controller function that handles adding items to this bundle
279
280
=cut
311
=cut
281
312
282
sub add_to_bundle {
313
sub add_to_bundle {
Lines 371-379 sub add_to_bundle { Link Here
371
}
402
}
372
403
373
=head3 remove_from_bundle
404
=head3 remove_from_bundle
374
375
Controller function that handles removing items from this bundle
405
Controller function that handles removing items from this bundle
376
377
=cut
406
=cut
378
407
379
sub remove_from_bundle {
408
sub remove_from_bundle {
(-)a/api/v1/swagger/paths/items.yaml (+35 lines)
Lines 396-401 Link Here
396
    x-koha-authorization:
396
    x-koha-authorization:
397
      permissions:
397
      permissions:
398
        reserveforothers: place_holds
398
        reserveforothers: place_holds
399
"/items/{item_id}/checkout/{patron_id}":
400
  post:
401
    x-mojo-to: Items#checkout
402
    operationId: addCheckout
403
    tags:
404
      - items
405
      - checkouts
406
    summary: Add a checkout
407
    parameters:
408
      - $ref: "../swagger.yaml#/parameters/item_id_pp"
409
      - $ref: "../swagger.yaml#/parameters/patron_id_pp"
410
    consumes:
411
      - application/json
412
    produces:
413
      - application/json
414
    responses:
415
      "201":
416
        description: Added checkout
417
        schema:
418
          $ref: "../swagger.yaml#/definitions/checkout"
419
      "400":
420
        description: Patron not found
421
        schema:
422
          $ref: "../swagger.yaml#/definitions/error"
423
      "403":
424
        description: Cannot add checkout
425
        schema:
426
          $ref: "../swagger.yaml#/definitions/error"
427
      "404":
428
        description: Item not found
429
        schema:
430
          $ref: "../swagger.yaml#/definitions/error"
431
    x-koha-authorization:
432
      permissions:
433
        circulate: circulate_remaining_permissions
399
"/public/items":
434
"/public/items":
400
  get:
435
  get:
401
    x-mojo-to: Items#list_public
436
    x-mojo-to: Items#list_public
(-)a/api/v1/swagger/swagger.yaml (+2 lines)
Lines 273-278 paths: Link Here
273
    $ref: ./paths/items.yaml#/~1items~1{item_id}~1bundled_items~1{bundled_item_id}
273
    $ref: ./paths/items.yaml#/~1items~1{item_id}~1bundled_items~1{bundled_item_id}
274
  "/items/{item_id}/pickup_locations":
274
  "/items/{item_id}/pickup_locations":
275
    $ref: "./paths/items.yaml#/~1items~1{item_id}~1pickup_locations"
275
    $ref: "./paths/items.yaml#/~1items~1{item_id}~1pickup_locations"
276
  "/items/{item_id}/checkout/{patron_id}":
277
    $ref: "./paths/items.yaml#/~1items~1{item_id}~1checkout~1{patron_id}"
276
  /jobs:
278
  /jobs:
277
    $ref: ./paths/jobs.yaml#/~1jobs
279
    $ref: ./paths/jobs.yaml#/~1jobs
278
  "/jobs/{job_id}":
280
  "/jobs/{job_id}":
(-)a/t/db_dependent/api/v1/items.t (-2 / +96 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 5;
22
use Test::More tests => 6;
23
use Test::MockModule;
23
use Test::MockModule;
24
use Test::Mojo;
24
use Test::Mojo;
25
use Test::Warn;
25
use Test::Warn;
Lines 30-35 use t::lib::Mocks; Link Here
30
use Mojo::JSON qw(encode_json);
30
use Mojo::JSON qw(encode_json);
31
31
32
use C4::Auth;
32
use C4::Auth;
33
use C4::Circulation;
33
use Koha::Items;
34
use Koha::Items;
34
use Koha::Database;
35
use Koha::Database;
35
36
Lines 572-574 subtest 'pickup_locations() tests' => sub { Link Here
572
573
573
    $schema->storage->txn_rollback;
574
    $schema->storage->txn_rollback;
574
};
575
};
575
- 
576
577
subtest 'checkout() tests' => sub {
578
579
    plan tests => 27;
580
581
    $schema->storage->txn_begin;
582
583
    my $item   = $builder->build_sample_item;
584
    my $item2  = $builder->build_sample_item;
585
    my $patron = $builder->build_object(
586
        {
587
            class => 'Koha::Patrons',
588
            value => { flags => 4 }
589
        }
590
    );
591
592
    # Make sure we have at least 10 items
593
    for ( 1..10 ) {
594
        $builder->build_sample_item;
595
    }
596
597
    my $nonprivilegedpatron = $builder->build_object(
598
        {
599
            class => 'Koha::Patrons',
600
            value => { flags => 0 }
601
        }
602
    );
603
604
    my $password = 'thePassword123';
605
606
    $nonprivilegedpatron->set_password(
607
        { password => $password, skip_validation => 1 } );
608
609
    my $userid = $nonprivilegedpatron->userid;
610
    my $itemid = $item->id;
611
    my $itemid2 = $item2->id;
612
    my $patronid = $patron->borrowernumber;
613
    my $non_existent_code = $item->itemnumber;
614
615
    $t->post_ok( "//$userid:$password@/api/v1/items/$itemid/checkout/$patronid" )
616
      ->status_is(403)
617
      ->json_is(
618
        '/error' => 'Authorization failure. Missing required permission(s).' );
619
620
    $t->get_ok( "//$userid:$password@/api/v1/items/" . $non_existent_code )
621
      ->status_is(403)
622
      ->json_is(
623
        '/error' => 'Authorization failure. Missing required permission(s).' );
624
625
    $patron->set_password( { password => $password, skip_validation => 1 } );
626
    $userid = $patron->userid;
627
628
    $t->get_ok( "//$userid:$password@/api/v1/items?_per_page=10" )
629
      ->status_is( 200, 'SWAGGER3.2.2' );
630
631
    my $response_count = scalar @{ $t->tx->res->json };
632
633
    is( $response_count, 10, 'The API returns 10 items' );
634
635
    $t->get_ok( "//$userid:$password@/api/v1/items?external_id=" . $item->barcode )
636
      ->status_is(200)
637
      ->json_is( '' => [ $item->to_api ], 'SWAGGER3.3.2');
638
639
    $patron->flags(1)->store;
640
    my $deleted_patron_id = $nonprivilegedpatron->id;
641
    $nonprivilegedpatron->delete;
642
    $t->post_ok( "//$userid:$password@/api/v1/items/$itemid/checkout/$deleted_patron_id" )
643
       ->status_is(400)
644
       ->json_is( '/error' => 'Patron not found' );
645
646
    my $barcode = $item->barcode;
647
    $item->delete;
648
649
    $t->post_ok("//$userid:$password@/api/v1/items/$itemid/checkout/$patronid")
650
       ->status_is(404);
651
652
    $t->get_ok( "//$userid:$password@/api/v1/items?external_id=" . $item->barcode )
653
      ->status_is(200)
654
      ->json_is( '' => [] );
655
656
    $t->get_ok( "//$userid:$password@/api/v1/items/" . $non_existent_code )
657
      ->status_is(404)
658
      ->json_is(
659
        '/error' => 'Item not found' );
660
661
    is( $patron->checkouts->count, 0);
662
663
    $t->post_ok( "//$userid:$password@/api/v1/items/$itemid2/checkout/$patronid")
664
       ->status_is(201);
665
666
    is( $patron->checkouts->count, 1);
667
668
    $schema->storage->txn_rollback;
669
};

Return to bug 24400