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

(-)a/Koha/REST/V1/Holds.pm (+77 lines)
Lines 558-561 sub update_pickup_location { Link Here
558
    };
558
    };
559
}
559
}
560
560
561
=head3 update_hold_date
562
563
Method that handles modifying the hold date of a Koha::Hold object
564
565
=cut
566
567
sub update_hold_date {
568
    my $c = shift->openapi->valid_input or return;
569
570
    my $hold_id   = $c->param('hold_id');
571
    my $body      = $c->req->json;
572
    my $hold_date = $body->{hold_date};
573
574
    my $hold = Koha::Holds->find($hold_id);
575
576
    unless ( C4::Context->preference('AllowHoldDateInFuture') ) {
577
        return $c->render(
578
            status  => 403,
579
            openapi => { error => "Update not allowed" }
580
        );
581
    }
582
583
    unless ($hold) {
584
        return $c->render(
585
            status  => 404,
586
            openapi => { error => "Hold not found" }
587
        );
588
    }
589
590
    return try {
591
592
        $hold->set( { reservedate => $hold_date } )->store;
593
594
        return $c->render(
595
            status  => 200,
596
            openapi => { hold_date => $hold_date }
597
        );
598
    } catch {
599
        $c->unhandled_exception($_);
600
    };
601
}
602
603
=head3 update_expiration_date
604
605
Method that handles modifying the expiration date of a Koha::Hold object
606
607
=cut
608
609
sub update_expiration_date {
610
    my $c = shift->openapi->valid_input or return;
611
612
    my $hold_id         = $c->param('hold_id');
613
    my $body            = $c->req->json;
614
    my $expiration_date = $body->{expiration_date};
615
616
    my $hold = Koha::Holds->find($hold_id);
617
618
    unless ($hold) {
619
        return $c->render(
620
            status  => 404,
621
            openapi => { error => "Hold not found" }
622
        );
623
    }
624
625
    return try {
626
627
        $hold->set( { expirationdate => $expiration_date } )->store;
628
629
        return $c->render(
630
            status  => 200,
631
            openapi => { expiration_date => $expiration_date }
632
        );
633
    } catch {
634
        $c->unhandled_exception($_);
635
    };
636
}
637
561
1;
638
1;
(-)a/api/v1/swagger/paths/holds.yaml (+142 lines)
Lines 755-757 Link Here
755
    x-koha-authorization:
755
    x-koha-authorization:
756
      permissions:
756
      permissions:
757
        reserveforothers: place_holds
757
        reserveforothers: place_holds
758
"/holds/{hold_id}/hold_date":
759
  put:
760
    x-mojo-to: Holds#update_hold_date
761
    operationId: updateHoldDate
762
    tags:
763
      - holds
764
    summary: Update hold date
765
    parameters:
766
      - $ref: "../swagger.yaml#/parameters/hold_id_pp"
767
      - name: body
768
        in: body
769
        description: A JSON object containing the new hold date
770
        required: true
771
        schema:
772
          type: object
773
          properties:
774
            hold_date:
775
              description: The date the hold was placed
776
              type: string
777
              format: date
778
          additionalProperties: false
779
    produces:
780
      - application/json
781
    responses:
782
      "200":
783
        description: The new hold date value for the hold
784
        schema:
785
          type: object
786
          properties:
787
            hold_date:
788
              description: The date the hold was placed
789
              type: string
790
              format: date
791
          additionalProperties: false
792
      "400":
793
        description: Bad request
794
        schema:
795
          $ref: "../swagger.yaml#/definitions/error"
796
      "401":
797
        description: Authentication required
798
        schema:
799
          $ref: "../swagger.yaml#/definitions/error"
800
      "403":
801
        description: Access forbidden
802
        schema:
803
          $ref: "../swagger.yaml#/definitions/error"
804
      "404":
805
        description: Hold not found
806
        schema:
807
          $ref: "../swagger.yaml#/definitions/error"
808
      "409":
809
        description: |
810
          Unable to perform action on hold. Possible `error_code` attribute values:
811
812
          * `hold_waiting`
813
          * `hold_in_transit`
814
          * `hold_in_processing`
815
        schema:
816
          $ref: "../swagger.yaml#/definitions/error"
817
      "500":
818
        description: |
819
          Internal server error. Possible `error_code` attribute values:
820
821
          * `internal_server_error`
822
      "503":
823
        description: Under maintenance
824
        schema:
825
          $ref: "../swagger.yaml#/definitions/error"
826
    x-koha-authorization:
827
      permissions:
828
        reserveforothers: place_holds
829
"/holds/{hold_id}/expiration_date":
830
  put:
831
    x-mojo-to: Holds#update_expiration_date
832
    operationId: updateHoldExpirationDate
833
    tags:
834
      - holds
835
    summary: Update hold expiration date
836
    parameters:
837
      - $ref: "../swagger.yaml#/parameters/hold_id_pp"
838
      - name: body
839
        in: body
840
        description: A JSON object containing the new expiration date
841
        required: true
842
        schema:
843
          type: object
844
          properties:
845
            expiration_date:
846
              description: The date the hold expires
847
              type: string
848
              format: date
849
          additionalProperties: false
850
    produces:
851
      - application/json
852
    responses:
853
      "200":
854
        description: The new expiration date value for the hold
855
        schema:
856
          type: object
857
          properties:
858
            expiration_date:
859
              description: The date the hold expires
860
              type: string
861
              format: date
862
          additionalProperties: false
863
      "400":
864
        description: Bad request
865
        schema:
866
          $ref: "../swagger.yaml#/definitions/error"
867
      "401":
868
        description: Authentication required
869
        schema:
870
          $ref: "../swagger.yaml#/definitions/error"
871
      "403":
872
        description: Access forbidden
873
        schema:
874
          $ref: "../swagger.yaml#/definitions/error"
875
      "404":
876
        description: Hold not found
877
        schema:
878
          $ref: "../swagger.yaml#/definitions/error"
879
      "409":
880
        description: |
881
          Unable to perform action on hold. Possible `error_code` attribute values:
882
883
          * `hold_waiting`
884
          * `hold_in_transit`
885
          * `hold_in_processing`
886
        schema:
887
          $ref: "../swagger.yaml#/definitions/error"
888
      "500":
889
        description: |
890
          Internal server error. Possible `error_code` attribute values:
891
892
          * `internal_server_error`
893
      "503":
894
        description: Under maintenance
895
        schema:
896
          $ref: "../swagger.yaml#/definitions/error"
897
    x-koha-authorization:
898
      permissions:
899
        reserveforothers: place_holds
(-)a/api/v1/swagger/swagger.yaml (+4 lines)
Lines 391-396 paths: Link Here
391
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1priority"
391
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1priority"
392
  "/holds/{hold_id}/suspension":
392
  "/holds/{hold_id}/suspension":
393
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1suspension"
393
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1suspension"
394
  "/holds/{hold_id}/hold_date":
395
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1hold_date"
396
  "/holds/{hold_id}/expiration_date":
397
    $ref: "./paths/holds.yaml#/~1holds~1{hold_id}~1expiration_date"
394
  /ill/backends:
398
  /ill/backends:
395
    $ref: ./paths/ill_backends.yaml#/~1ill~1backends
399
    $ref: ./paths/ill_backends.yaml#/~1ill~1backends
396
  "/ill/backends/{ill_backend_id}":
400
  "/ill/backends/{ill_backend_id}":
(-)a/t/db_dependent/api/v1/holds.t (-2 / +124 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 14;
20
use Test::More tests => 16;
21
use Test::MockModule;
21
use Test::MockModule;
22
use Test::Mojo;
22
use Test::Mojo;
23
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
Lines 1579-1581 subtest 'delete() tests' => sub { Link Here
1579
1579
1580
    $schema->storage->txn_rollback;
1580
    $schema->storage->txn_rollback;
1581
};
1581
};
1582
- 
1582
1583
subtest 'PUT /holds/{hold_id}/hold_date tests' => sub {
1584
1585
    plan tests => 10;
1586
1587
    $schema->storage->txn_begin;
1588
1589
    my $password = 'AbcdEFG123';
1590
1591
    my $library_1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1 } } );
1592
1593
    my $patron = $builder->build_object( { class => 'Koha::Patrons', value => { flags => 0 } } );
1594
    $patron->set_password( { password => $password, skip_validation => 1 } );
1595
    my $userid = $patron->userid;
1596
    $builder->build(
1597
        {
1598
            source => 'UserPermission',
1599
            value  => {
1600
                borrowernumber => $patron->borrowernumber,
1601
                module_bit     => 6,
1602
                code           => 'place_holds',
1603
            },
1604
        }
1605
    );
1606
1607
    # Disable logging
1608
    t::lib::Mocks::mock_preference( 'HoldsLog',      0 );
1609
    t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
1610
1611
    my $biblio = $builder->build_sample_biblio;
1612
1613
    # biblio-level hold
1614
    my $hold = Koha::Holds->find(
1615
        AddReserve(
1616
            {
1617
                branchcode     => $library_1->branchcode,
1618
                borrowernumber => $patron->borrowernumber,
1619
                biblionumber   => $biblio->biblionumber,
1620
                priority       => 1,
1621
                itemnumber     => undef,
1622
            }
1623
        )
1624
    );
1625
1626
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 0 );
1627
1628
    $t->put_ok(
1629
        "//$userid:$password@/api/v1/holds/" . $hold->id . "/hold_date" => json => { hold_date => '2022-01-01' } )
1630
        ->status_is(403)->json_is( { error => 'Update not allowed' } );
1631
1632
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 1 );
1633
1634
    # Attempt to use an invalid pickup locations ends in 400
1635
    $t->put_ok( "//$userid:$password@/api/v1/holds/0" . "/hold_date" => json => { hold_date => '2022-01-01' } )
1636
        ->status_is(404)->json_is( { error => 'Hold not found' } );
1637
1638
    $t->put_ok(
1639
        "//$userid:$password@/api/v1/holds/" . $hold->id . "/hold_date" => json => { hold_date => '2022-01-01' } )
1640
        ->status_is(200)->json_is( { hold_date => '2022-01-01' } );
1641
1642
    is( $hold->discard_changes->reservedate, '2022-01-01', 'hold date changed correctly' );
1643
1644
    $schema->storage->txn_rollback;
1645
};
1646
1647
subtest 'PUT /holds/{hold_id}/expiration_date tests' => sub {
1648
1649
    plan tests => 7;
1650
1651
    $schema->storage->txn_begin;
1652
1653
    my $password = 'AbcdEFG123';
1654
1655
    my $library_1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1 } } );
1656
1657
    my $patron = $builder->build_object( { class => 'Koha::Patrons', value => { flags => 0 } } );
1658
    $patron->set_password( { password => $password, skip_validation => 1 } );
1659
    my $userid = $patron->userid;
1660
    $builder->build(
1661
        {
1662
            source => 'UserPermission',
1663
            value  => {
1664
                borrowernumber => $patron->borrowernumber,
1665
                module_bit     => 6,
1666
                code           => 'place_holds',
1667
            },
1668
        }
1669
    );
1670
1671
    # Disable logging
1672
    t::lib::Mocks::mock_preference( 'HoldsLog',      0 );
1673
    t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
1674
1675
    my $biblio = $builder->build_sample_biblio;
1676
1677
    # biblio-level hold
1678
    my $hold = Koha::Holds->find(
1679
        AddReserve(
1680
            {
1681
                branchcode     => $library_1->branchcode,
1682
                borrowernumber => $patron->borrowernumber,
1683
                biblionumber   => $biblio->biblionumber,
1684
                priority       => 1,
1685
                itemnumber     => undef,
1686
            }
1687
        )
1688
    );
1689
1690
    # Attempt to use an invalid pickup locations ends in 400
1691
    $t->put_ok(
1692
        "//$userid:$password@/api/v1/holds/0" . "/expiration_date" => json => { expiration_date => '2022-01-01' } )
1693
        ->status_is(404)->json_is( { error => 'Hold not found' } );
1694
1695
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1696
            . $hold->id
1697
            . "/expiration_date" => json => { expiration_date => '2022-01-01' } )->status_is(200)
1698
        ->json_is( { expiration_date => '2022-01-01' } );
1699
1700
    is( $hold->discard_changes->expirationdate, '2022-01-01', 'expiration date changed correctly' );
1701
1702
    $schema->storage->txn_rollback;
1703
};
1704

Return to bug 30661