Bug 32030: ERM - REST API - GET POST PUT DELETE specs
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Wed, 16 Mar 2022 15:49:40 +0000 (16:49 +0100)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 8 Nov 2022 12:43:37 +0000 (09:43 -0300)
Signed-off-by: Jonathan Field <jonathan.field@ptfs-europe.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Koha/REST/V1/ERM/Agreements.pm
api/v1/swagger/definitions/erm_agreement.yaml
api/v1/swagger/definitions/erm_agreement_period.yaml [new file with mode: 0644]
api/v1/swagger/definitions/erm_agreement_user_role.yaml [new file with mode: 0644]
api/v1/swagger/paths/erm_agreements.yaml
api/v1/swagger/swagger.yaml
t/db_dependent/api/v1/erm_agreements.t [changed mode: 0644->0755]
t/lib/TestBuilder.pm

index f521ca6..999881f 100644 (file)
@@ -21,6 +21,7 @@ use Mojo::Base 'Mojolicious::Controller';
 
 use Koha::ERM::Agreements;
 
+use Scalar::Util qw( blessed );
 use Try::Tiny qw( catch try );
 
 =head1 API
@@ -45,4 +46,198 @@ sub list {
 
 }
 
+=head3 get
+
+Controller function that handles retrieving a single Koha::ERM::Agreement object
+
+=cut
+
+sub get {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+        my $agreement_id = $c->validation->param('agreement_id');
+        my $agreement    = $c->objects->find( Koha::ERM::Agreements->search, $agreement_id );
+
+        unless ($agreement) {
+            return $c->render(
+                status  => 404,
+                openapi => { error => "Agreement not found" }
+            );
+        }
+
+        return $c->render(
+            status  => 200,
+            openapi => $agreement
+        );
+    }
+    catch {
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 add
+
+Controller function that handles adding a new Koha::ERM::Agreement object
+
+=cut
+
+sub add {
+    my $c = shift->openapi->valid_input or return;
+
+    return try {
+        Koha::Database->new->schema->txn_do(
+            sub {
+
+                my $body = $c->validation->param('body');
+
+                my $periods    = delete $body->{periods} // [];
+                my $user_roles = delete $body->{user_roles} // [];
+
+                my $agreement = Koha::ERM::Agreement->new_from_api($body)->store;
+                $agreement->periods($periods);
+                $agreement->user_roles($user_roles);
+
+                $c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id);
+                return $c->render(
+                    status  => 201,
+                    openapi => $agreement->to_api
+                );
+            }
+        );
+    }
+    catch {
+
+        my $to_api_mapping = Koha::ERM::Agreement->new->to_api_mapping;
+
+        if ( blessed $_ ) {
+            if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
+                return $c->render(
+                    status  => 409,
+                    openapi => { error => $_->error, conflict => $_->duplicate_id }
+                );
+            }
+            elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                            error => "Given "
+                            . $to_api_mapping->{ $_->broken_fk }
+                            . " does not exist"
+                    }
+                );
+            }
+            elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                            error => "Given "
+                            . $to_api_mapping->{ $_->parameter }
+                            . " does not exist"
+                    }
+                );
+            }
+        }
+
+        $c->unhandled_exception($_);
+    };
+}
+
+=head3 update
+
+Controller function that handles updating a Koha::ERM::Agreement object
+
+=cut
+
+sub update {
+    my $c = shift->openapi->valid_input or return;
+
+    my $agreement_id = $c->validation->param('agreement_id');
+    my $agreement = Koha::ERM::Agreements->find( $agreement_id );
+
+    unless ($agreement) {
+        return $c->render(
+            status  => 404,
+            openapi => { error => "Agreement not found" }
+        );
+    }
+
+    return try {
+        Koha::Database->new->schema->txn_do(
+            sub {
+
+                my $body = $c->validation->param('body');
+
+                my $periods    = delete $body->{periods} // [];
+                my $user_roles = delete $body->{user_roles} // [];
+
+                $agreement->set_from_api($body)->store;
+                $agreement->periods($periods);
+                $agreement->user_roles($user_roles);
+
+                $c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id);
+                return $c->render(
+                    status  => 200,
+                    openapi => $agreement->to_api
+                );
+            }
+        );
+    }
+    catch {
+        my $to_api_mapping = Koha::ERM::Agreement->new->to_api_mapping;
+
+        if ( blessed $_ ) {
+            if ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                            error => "Given "
+                            . $to_api_mapping->{ $_->broken_fk }
+                            . " does not exist"
+                    }
+                );
+            }
+            elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
+                return $c->render(
+                    status  => 400,
+                    openapi => {
+                            error => "Given "
+                            . $to_api_mapping->{ $_->parameter }
+                            . " does not exist"
+                    }
+                );
+            }
+        }
+
+        $c->unhandled_exception($_);
+    };
+};
+
+=head3 delete
+
+=cut
+
+sub delete {
+    my $c = shift->openapi->valid_input or return;
+
+    my $agreement = Koha::ERM::Agreements->find( $c->validation->param('agreement_id') );
+    unless ($agreement) {
+        return $c->render(
+            status  => 404,
+            openapi => { error => "Agreement not found" }
+        );
+    }
+
+    return try {
+        $agreement->delete;
+        return $c->render(
+            status  => 204,
+            openapi => q{}
+        );
+    }
+    catch {
+        $c->unhandled_exception($_);
+    };
+}
+
 1;
index 180d0e9..7451901 100644 (file)
@@ -39,6 +39,16 @@ properties:
     type:
       - string
       - "null"
+  periods:
+    type: array
+    description: periods defined for this agreement
+    items:
+      $ref: erm_agreement_period.yaml
+  user_roles:
+    type: array
+    description: role for users
+    items:
+      $ref: erm_agreement_user_role.yaml
 additionalProperties: false
 required:
   - agreement_id
diff --git a/api/v1/swagger/definitions/erm_agreement_period.yaml b/api/v1/swagger/definitions/erm_agreement_period.yaml
new file mode 100644 (file)
index 0000000..7695e9d
--- /dev/null
@@ -0,0 +1,31 @@
+---
+type: object
+properties:
+  agreement_period_id:
+    $ref: ../x-primitives.yaml#/agreement_period_id
+  agreement_id:
+    type: integer
+    description: Internal agreement identifier
+  started_on:
+    type: string
+    format: date
+    description: Start of the agreement period
+  ended_on:
+    type:
+      - string
+      - "null"
+    format: date
+    description: End of the agreemnent period
+  cancellation_deadline:
+    type:
+      - string
+      - "null"
+    format: date
+    description: Deadline for the cancellation
+  notes:
+    type:
+      - string
+      - "null"
+additionalProperties: false
+required:
+  - started_on
diff --git a/api/v1/swagger/definitions/erm_agreement_user_role.yaml b/api/v1/swagger/definitions/erm_agreement_user_role.yaml
new file mode 100644 (file)
index 0000000..68c3cb3
--- /dev/null
@@ -0,0 +1,21 @@
+---
+type: object
+properties:
+  agreement_id:
+    type: integer
+    description: Internal agreement identifier
+  user_id:
+    type: integer
+    description: Internal patron identifier
+  role:
+    description: role of the user
+    type:
+      - string
+  patron:
+    type:
+      - object
+      - "null"
+additionalProperties: false
+required:
+  - user_id
+  - role
index 54ff7ee..4a04eee 100644 (file)
@@ -5,7 +5,7 @@
     operationId: listErmAgreements
     tags:
       - agreement
-    summary: List erm_agreements
+    summary: List agreements
     produces:
       - application/json
     parameters:
     x-koha-authorization:
       permissions:
         erm: 1
+  post:
+    x-mojo-to: ERM::Agreements#add
+    operationId: addErmAgreements
+    tags:
+      - agreement
+    summary: Add agreement
+    consumes:
+      - application/json
+    produces:
+      - application/json
+    parameters:
+      - description: A JSON object containing information about the new agreement
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: ../definitions.yaml#/erm_agreement
+    responses:
+      201:
+        description: A successfully created agreement
+        schema:
+          items:
+            $ref: ../definitions.yaml#/erm_agreement
+      400:
+        description: Bad parameter
+        schema:
+          $ref: ../definitions.yaml#/error
+      401:
+        description: Authentication required
+        schema:
+          $ref: ../definitions.yaml#/error
+      403:
+        description: Access forbidden
+        schema:
+          $ref: ../definitions.yaml#/error
+      404:
+        description: Ressource not found
+        schema:
+          $ref: ../definitions.yaml#/error
+      409:
+        description: Conflict in creating resource
+        schema:
+          $ref: ../definitions.yaml#/error
+      500:
+        description: |-
+          Internal server error. Possible `error_code` attribute values:
+          * `internal_server_error`
+        schema:
+          $ref: ../definitions.yaml#/error
+      503:
+        description: Under maintenance
+        schema:
+          $ref: ../definitions.yaml#/error
+    x-koha-authorization:
+      permissions:
+        erm: 1
+"/erm/agreements/{agreement_id}":
+  get:
+    x-mojo-to: ERM::Agreements#get
+    operationId: getErmAgreements
+    tags:
+      - agreement
+    summary: Get agreement
+    produces:
+      - application/json
+    parameters:
+      - $ref: ../parameters.yaml#/agreement_id_pp
+    responses:
+      200:
+        description: An agreement
+        schema:
+          items:
+            $ref: ../definitions.yaml#/erm_agreement
+      401:
+        description: Authentication required
+        schema:
+          $ref: ../definitions.yaml#/error
+      403:
+        description: Access forbidden
+        schema:
+          $ref: ../definitions.yaml#/error
+      404:
+        description: Ressource not found
+        schema:
+          $ref: ../definitions.yaml#/error
+      500:
+        description: |-
+          Internal server error. Possible `error_code` attribute values:
+          * `internal_server_error`
+        schema:
+          $ref: ../definitions.yaml#/error
+      503:
+        description: Under maintenance
+        schema:
+          $ref: ../definitions.yaml#/error
+    x-koha-authorization:
+      permissions:
+        erm: 1
+    x-koha-embed:
+      - periods
+      - user_roles
+      - user_roles.patron
+  put:
+    x-mojo-to: ERM::Agreements#update
+    operationId: updateErmAgreements
+    tags:
+      - agreement
+    summary: Update agreement
+    consumes:
+      - application/json
+    produces:
+      - application/json
+    parameters:
+      - $ref: ../parameters.yaml#/agreement_id_pp
+      - name: body
+        in: body
+        description: A JSON object containing new information about existing agreement
+        required: true
+        schema:
+          $ref: ../definitions.yaml#/erm_agreement
+
+    responses:
+      200:
+        description: A successfully updated agreement
+        schema:
+          items:
+            $ref: ../definitions.yaml#/erm_agreement
+      400:
+        description: Bad parameter
+        schema:
+          $ref: ../definitions.yaml#/error
+      403:
+        description: Access forbidden
+        schema:
+          $ref: ../definitions.yaml#/error
+      404:
+        description: Ressource not found
+        schema:
+          $ref: ../definitions.yaml#/error
+      409:
+        description: Conflict in updating resource
+        schema:
+          $ref: ../definitions.yaml#/error
+      500:
+        description: |-
+          Internal server error. Possible `error_code` attribute values:
+          * `internal_server_error`
+        schema:
+          $ref: ../definitions.yaml#/error
+      503:
+        description: Under maintenance
+        schema:
+          $ref: ../definitions.yaml#/error
+    x-koha-authorization:
+      permissions:
+        erm: 1
+    x-koha-embed:
+      - periods
+      - user_roles
+  delete:
+    x-mojo-to: ERM::Agreements#delete
+    operationId: deleteErmAgreements
+    tags:
+      - agreement
+    summary: Delete agreement
+    produces:
+      - application/json
+    parameters:
+      - $ref: ../parameters.yaml#/agreement_id_pp
+    responses:
+      204:
+        description: Agreement deleted
+      400:
+        description: Agreement deletion failed
+        schema:
+          $ref: ../definitions.yaml#/error
+      401:
+        description: Authentication required
+        schema:
+          $ref: ../definitions.yaml#/error
+      403:
+        description: Access forbidden
+        schema:
+          $ref: ../definitions.yaml#/error
+      404:
+        description: Ressource not found
+        schema:
+          $ref: ../definitions.yaml#/error
+      409:
+        description: Conflict in deleting resource
+        schema:
+          $ref: ../definitions.yaml#/error
+      500:
+        description: |-
+          Internal server error. Possible `error_code` attribute values:
+          * `internal_server_error`
+        schema:
+          $ref: ../definitions.yaml#/error
+      503:
+        description: Under maintenance
+        schema:
+          $ref: ../definitions.yaml#/error
+    x-koha-authorization:
+      permissions:
+        erm: 1
index 62daad3..f384dfa 100644 (file)
@@ -159,6 +159,8 @@ paths:
     $ref: "./paths/config_smtp_servers.yaml#/~1config~1smtp_servers~1{smtp_server_id}"
   /erm/agreements:
     $ref: ./paths/erm_agreements.yaml#/~1erm~1agreements
+  "/erm/agreements/{agreement_id}":
+    $ref: "./paths/erm_agreements.yaml#/~1erm~1agreements~1{agreement_id}"
   /erm/users:
     $ref: ./paths/erm_users.yaml#/~1erm~1users
   /holds:
@@ -274,6 +276,18 @@ parameters:
     name: advancededitormacro_id
     required: true
     type: integer
+  agreement_id_pp:
+    description: Agreement internal identifier
+    in: path
+    name: agreement_id
+    required: true
+    type: integer
+  agreement_period_id_pp:
+    description: Agreement period internal identifier
+    in: path
+    name: agreement_period_id
+    required: true
+    type: integer
   biblio_id_pp:
     description: Record internal identifier
     in: path
old mode 100644 (file)
new mode 100755 (executable)
index 8d1cfb5..99f4c34
@@ -17,7 +17,7 @@
 
 use Modern::Perl;
 
-use Test::More tests => 1;
+use Test::More tests => 5;
 use Test::Mojo;
 
 use t::lib::TestBuilder;
@@ -30,7 +30,6 @@ my $schema  = Koha::Database->new->schema;
 my $builder = t::lib::TestBuilder->new;
 
 my $t = Test::Mojo->new('Koha::REST::V1');
-t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
 
 subtest 'list() tests' => sub {
 
@@ -43,7 +42,7 @@ subtest 'list() tests' => sub {
     my $librarian = $builder->build_object(
         {
             class => 'Koha::Patrons',
-            value => { flags => 27 ** 2 }
+            value => { flags => 2**28}
         }
     );
     my $password = 'thePassword123';
@@ -62,40 +61,45 @@ subtest 'list() tests' => sub {
 
     ## Authorized user tests
     # No agreements, so empty array should be returned
-    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")
-      ->status_is(200)
+    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")->status_is(200)
       ->json_is( [] );
 
-    my $agreement = $builder->build_object({ class => 'Koha::ERM::Agreements' });
+    my $agreement =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } );
 
     # One agreement created, should get returned
-    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")
-      ->status_is(200)
-      ->json_is( [$agreement->to_api] );
+    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")->status_is(200)
+      ->json_is( [ $agreement->to_api ] );
 
     my $another_agreement = $builder->build_object(
-        { class => 'Koha::ERM::Agreements', value => { vendor_id => $agreement->vendor_id } } );
-    my $agreement_with_another_vendor_id = $builder->build_object({ class => 'Koha::ERM::Agreements' });
+        {
+            class => 'Koha::ERM::Agreements',
+            value => { vendor_id => $agreement->vendor_id }
+        }
+    );
+    my $agreement_with_another_vendor_id =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } );
 
     # Two agreements created, they should both be returned
-    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")
-      ->status_is(200)
-      ->json_is([$agreement->to_api,
-                 $another_agreement->to_api,
-                 $agreement_with_another_vendor_id->to_api
-                 ] );
+    $t->get_ok("//$userid:$password@/api/v1/erm/agreements")->status_is(200)
+      ->json_is(
+        [
+            $agreement->to_api,
+            $another_agreement->to_api,
+            $agreement_with_another_vendor_id->to_api
+        ]
+      );
 
     # Filtering works, two agreements sharing vendor_id
-    $t->get_ok("//$userid:$password@/api/v1/erm/agreements?vendor_id=" . $agreement->vendor_id )
-      ->status_is(200)
-      ->json_is([ $agreement->to_api,
-                  $another_agreement->to_api
-                  ]);
+    $t->get_ok( "//$userid:$password@/api/v1/erm/agreements?vendor_id="
+          . $agreement->vendor_id )->status_is(200)
+      ->json_is( [ $agreement->to_api, $another_agreement->to_api ] );
 
     # Warn on unsupported query parameter
-    $t->get_ok("//$userid:$password@/api/v1/erm/agreements?blah=blah" )
+    $t->get_ok("//$userid:$password@/api/v1/erm/agreements?blah=blah")
       ->status_is(400)
-      ->json_is( [{ path => '/query/blah', message => 'Malformed query string'}] );
+      ->json_is(
+        [ { path => '/query/blah', message => 'Malformed query string' } ] );
 
     # Unauthorized access
     $t->get_ok("//$unauth_userid:$password@/api/v1/erm/agreements")
@@ -104,3 +108,302 @@ subtest 'list() tests' => sub {
     $schema->storage->txn_rollback;
 };
 
+subtest 'get() tests' => sub {
+
+    plan tests => 8;
+
+    $schema->storage->txn_begin;
+
+    my $agreement =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } );
+    my $librarian = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 2**28 }
+        }
+    );
+    my $password = 'thePassword123';
+    $librarian->set_password( { password => $password, skip_validation => 1 } );
+    my $userid = $librarian->userid;
+
+    my $patron = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 0 }
+        }
+    );
+
+    $patron->set_password( { password => $password, skip_validation => 1 } );
+    my $unauth_userid = $patron->userid;
+
+    $t->get_ok( "//$userid:$password@/api/v1/erm/agreements/"
+          . $agreement->agreement_id )->status_is(200)
+      ->json_is( $agreement->to_api );
+
+    $t->get_ok( "//$unauth_userid:$password@/api/v1/erm/agreements/"
+          . $agreement->agreement_id )->status_is(403);
+
+    my $agreement_to_delete =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } );
+    my $non_existent_id = $agreement_to_delete->id;
+    $agreement_to_delete->delete;
+
+    $t->get_ok("//$userid:$password@/api/v1/erm/agreements/$non_existent_id")
+      ->status_is(404)->json_is( '/error' => 'Agreement not found' );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'add() tests' => sub {
+
+    plan tests => 22;
+
+    $schema->storage->txn_begin;
+
+    my $librarian = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 2**28 }
+        }
+    );
+    my $password = 'thePassword123';
+    $librarian->set_password( { password => $password, skip_validation => 1 } );
+    my $userid = $librarian->userid;
+
+    my $patron = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 0 }
+        }
+    );
+
+    $patron->set_password( { password => $password, skip_validation => 1 } );
+    my $unauth_userid = $patron->userid;
+
+    my $agreement = {
+        vendor_id => undef,
+        name             => "Agreement name",
+        description      => "Agreement description",
+        status           => "active",
+        closure_reason   => "",
+        is_perpetual     => 1,
+        renewal_priority => "",
+        license_info     => "Agreement license_info",
+    };
+
+    # Unauthorized attempt to write
+    $t->post_ok( "//$unauth_userid:$password@/api/v1/erm/agreements" => json =>
+          $agreement )->status_is(403);
+
+    # Authorized attempt to write invalid data
+    my $agreement_with_invalid_field = {
+        blah             => "Agreement Blah",
+        name             => "Agreement name",
+        description      => "Agreement description",
+        status           => "active",
+        closure_reason   => "",
+        is_perpetual     => 1,
+        renewal_priority => "",
+        license_info     => "Agreement license_info",
+    };
+
+    $t->post_ok( "//$userid:$password@/api/v1/erm/agreements" => json =>
+          $agreement_with_invalid_field )->status_is(400)->json_is(
+        "/errors" => [
+            {
+                message => "Properties not allowed: blah.",
+                path    => "/body"
+            }
+        ]
+          );
+
+    # Authorized attempt to write
+    my $agreement_id =
+      $t->post_ok(
+        "//$userid:$password@/api/v1/erm/agreements" => json => $agreement )
+      ->status_is( 201, 'SWAGGER3.2.1' )->header_like(
+        Location => qr|^/api/v1/erm/agreements/\d*|,
+        'SWAGGER3.4.1'
+    )->json_is( '/vendor_id' => $agreement->{vendor_id} )
+      ->json_is( '/name'             => $agreement->{name} )
+      ->json_is( '/description'      => $agreement->{description} )
+      ->json_is( '/status'           => $agreement->{status} )
+      ->json_is( '/closure_reason'   => $agreement->{closure_reason} )
+      ->json_is( '/is_perpetual'     => $agreement->{is_perpetual} )
+      ->json_is( '/renewal_priority' => $agreement->{renewal_priority} )
+      ->json_is( '/license_info'     => $agreement->{license_info} )
+      ->tx->res->json->{agreement_id};
+
+    # Authorized attempt to create with null id
+    $agreement->{agreement_id} = undef;
+    $t->post_ok(
+        "//$userid:$password@/api/v1/erm/agreements" => json => $agreement )
+      ->status_is(400)->json_has('/errors');
+
+    # Authorized attempt to create with existing id
+    $agreement->{agreement_id} = $agreement_id;
+    $t->post_ok(
+        "//$userid:$password@/api/v1/erm/agreements" => json => $agreement )
+      ->status_is(400)->json_is(
+        "/errors" => [
+            {
+                message => "Read-only.",
+                path    => "/body/agreement_id"
+            }
+        ]
+      );
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'update() tests' => sub {
+
+    plan tests => 15;
+
+    $schema->storage->txn_begin;
+
+    my $librarian = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 2**28 }
+        }
+    );
+    my $password = 'thePassword123';
+    $librarian->set_password( { password => $password, skip_validation => 1 } );
+    my $userid = $librarian->userid;
+
+    my $patron = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 0 }
+        }
+    );
+
+    $patron->set_password( { password => $password, skip_validation => 1 } );
+    my $unauth_userid = $patron->userid;
+
+    my $agreement_id =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } )->agreement_id;
+
+    # Unauthorized attempt to update
+    $t->put_ok(
+        "//$unauth_userid:$password@/api/v1/erm/agreements/$agreement_id" =>
+          json => { name => 'New unauthorized name change' } )->status_is(403);
+
+    # Attempt partial update on a PUT
+    my $agreement_with_missing_field = {
+        description      => 'New description',
+        status           => 'active',
+        closure_reason   => undef,
+        is_perpetual     => 1,
+        renewal_priority => undef,
+        license_info     => 'New license_info',
+    };
+
+    $t->put_ok(
+        "//$userid:$password@/api/v1/erm/agreements/$agreement_id" => json =>
+          $agreement_with_missing_field )->status_is(400)
+      ->json_is( "/errors" =>
+          [ { message => "Missing property.", path => "/body/name" } ] );
+
+    # Full object update on PUT
+    my $agreement_with_updated_field = {
+        vendor_id        => undef,
+        name             => 'New name',
+        description      => 'New description',
+        status           => 'closed',
+        closure_reason   => undef,
+        is_perpetual     => 1,
+        renewal_priority => undef,
+        license_info     => 'New license_info',
+    };
+
+    $t->put_ok(
+        "//$userid:$password@/api/v1/erm/agreements/$agreement_id" => json =>
+          $agreement_with_updated_field )->status_is(200)
+      ->json_is( '/name' => 'New name' );
+
+    # Authorized attempt to write invalid data
+    my $agreement_with_invalid_field = {
+        blah             => "Agreement Blah",
+        name             => "Agreement name",
+        description      => "Agreement description",
+        status           => "closed",
+        closure_reason   => undef,
+        is_perpetual     => 1,
+        renewal_priority => undef,
+        license_info     => "Agreement license_info",
+    };
+
+    $t->put_ok(
+        "//$userid:$password@/api/v1/erm/agreements/$agreement_id" => json =>
+          $agreement_with_invalid_field )->status_is(400)->json_is(
+        "/errors" => [
+            {
+                message => "Properties not allowed: blah.",
+                path    => "/body"
+            }
+        ]
+          );
+
+    my $agreement_to_delete =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } );
+    my $non_existent_id = $agreement_to_delete->id;
+    $agreement_to_delete->delete;
+
+    $t->put_ok( "//$userid:$password@/api/v1/erm/agreements/$non_existent_id" =>
+          json => $agreement_with_updated_field )->status_is(404);
+
+    # Wrong method (POST)
+    $agreement_with_updated_field->{agreement_id} = 2;
+
+    $t->post_ok(
+        "//$userid:$password@/api/v1/erm/agreements/$agreement_id" => json =>
+          $agreement_with_updated_field )->status_is(404);
+
+    $schema->storage->txn_rollback;
+};
+
+subtest 'delete() tests' => sub {
+
+    plan tests => 7;
+
+    $schema->storage->txn_begin;
+
+    my $librarian = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 2**28 }
+        }
+    );
+    my $password = 'thePassword123';
+    $librarian->set_password( { password => $password, skip_validation => 1 } );
+    my $userid = $librarian->userid;
+
+    my $patron = $builder->build_object(
+        {
+            class => 'Koha::Patrons',
+            value => { flags => 0 }
+        }
+    );
+
+    $patron->set_password( { password => $password, skip_validation => 1 } );
+    my $unauth_userid = $patron->userid;
+
+    my $agreement_id =
+      $builder->build_object( { class => 'Koha::ERM::Agreements' } )->id;
+
+    # Unauthorized attempt to delete
+    $t->delete_ok(
+        "//$unauth_userid:$password@/api/v1/erm/agreements/$agreement_id")
+      ->status_is(403);
+
+    $t->delete_ok("//$userid:$password@/api/v1/erm/agreements/$agreement_id")
+      ->status_is( 204, 'SWAGGER3.2.4' )->content_is( '', 'SWAGGER3.3.4' );
+
+    $t->delete_ok("//$userid:$password@/api/v1/erm/agreements/$agreement_id")
+      ->status_is(404);
+
+    $schema->storage->txn_rollback;
+};
+
index e066c2f..d065835 100644 (file)
@@ -637,6 +637,12 @@ sub _gen_default_values {
             opac => 1,
             staff_client => 1
         },
+        ErmAgreement => {
+            status           => 'active',
+            closure_reason   => undef,
+            renewal_priority => undef,
+            vendor_id        => undef,
+          },
     };
 }