From ab5d7b5a6313e8ddb7f16f49b2318e7743808491 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 3 May 2022 18:30:38 +0200 Subject: [PATCH] Bug 32030: ERM - Licenses Signed-off-by: Jonathan Field Signed-off-by: Martin Renvoize Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- Koha/ERM/Agreement/License.pm | 71 ++++ Koha/ERM/Agreement/Licenses.pm | 53 +++ Koha/ERM/License.pm | 44 +++ Koha/ERM/Licenses.pm | 53 +++ Koha/REST/V1/ERM/Licenses.pm | 233 ++++++++++++ api/v1/swagger/definitions/erm_license.yaml | 40 ++ .../definitions/erm_license_agreement.yaml | 34 ++ api/v1/swagger/paths/erm_licenses.yaml | 274 ++++++++++++++ api/v1/swagger/swagger.yaml | 12 + cypress/integration/Licenses_spec.ts | 245 ++++++++++++ .../data/mysql/mandatory/auth_val_cat.sql | 9 + .../intranet-tmpl/prog/en/modules/erm/erm.tt | 18 +- .../js/vue/components/ERM/AgreementsList.vue | 36 +- ...mentsButtonDelete.vue => ButtonDelete.vue} | 2 +- ...greementsButtonEdit.vue => ButtonEdit.vue} | 2 +- .../prog/js/vue/components/ERM/ERMMain.vue | 9 + .../prog/js/vue/components/ERM/Licenses.vue | 102 +++++ .../js/vue/components/ERM/LicensesFormAdd.vue | 205 ++++++++++ .../ERM/LicensesFormConfirmDelete.vue | 85 +++++ .../js/vue/components/ERM/LicensesList.vue | 201 ++++++++++ .../js/vue/components/ERM/LicensesShow.vue | 114 ++++++ .../js/vue/components/ERM/LicensesToolbar.vue | 12 + .../intranet-tmpl/prog/js/vue/main-erm.ts | 15 + t/db_dependent/api/v1/erm_licenses.t | 353 ++++++++++++++++++ 24 files changed, 2201 insertions(+), 21 deletions(-) create mode 100644 Koha/ERM/Agreement/License.pm create mode 100644 Koha/ERM/Agreement/Licenses.pm create mode 100644 Koha/ERM/License.pm create mode 100644 Koha/ERM/Licenses.pm create mode 100644 Koha/REST/V1/ERM/Licenses.pm create mode 100644 api/v1/swagger/definitions/erm_license.yaml create mode 100644 api/v1/swagger/definitions/erm_license_agreement.yaml create mode 100644 api/v1/swagger/paths/erm_licenses.yaml create mode 100644 cypress/integration/Licenses_spec.ts rename koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/{AgreementsButtonDelete.vue => ButtonDelete.vue} (84%) rename koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/{AgreementsButtonEdit.vue => ButtonEdit.vue} (84%) create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Licenses.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesToolbar.vue create mode 100755 t/db_dependent/api/v1/erm_licenses.t diff --git a/Koha/ERM/Agreement/License.pm b/Koha/ERM/Agreement/License.pm new file mode 100644 index 0000000000..9f34ae4b94 --- /dev/null +++ b/Koha/ERM/Agreement/License.pm @@ -0,0 +1,71 @@ +package Koha::ERM::Agreement::License; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Database; + +use Koha::Agreements; +use Koha::Licenses; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::ERM::Agreement::License - Koha Agreement License Object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 license + +Return the license + +=cut + +sub license { + my ( $self ) = @_; + my $license_rs = $self->_result->license; + return Koha::ERM::License->_new_from_dbic($license_rs); +} + +=head3 agreement + +Return the agreement + +=cut + +sub agreement { + my ( $self ) = @_; + my $agreement_rs = $self->_result->agreement; + return Koha::ERM::Agreement->_new_from_dbic($agreement_rs); +} + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'ErmAgreementLicense'; +} + +1; diff --git a/Koha/ERM/Agreement/Licenses.pm b/Koha/ERM/Agreement/Licenses.pm new file mode 100644 index 0000000000..61d9e4c14d --- /dev/null +++ b/Koha/ERM/Agreement/Licenses.pm @@ -0,0 +1,53 @@ +package Koha::ERM::Agreement::Licenses; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + + +use Koha::Database; + +use Koha::ERM::Agreement::License; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::ERM::Agreement::Licenses- Koha Agreement License Object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'ErmAgreementLicense'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::ERM::Agreement::License'; +} + +1; diff --git a/Koha/ERM/License.pm b/Koha/ERM/License.pm new file mode 100644 index 0000000000..cd798ff794 --- /dev/null +++ b/Koha/ERM/License.pm @@ -0,0 +1,44 @@ +package Koha::ERM::License; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::ERM::License - Koha ERM License Object class + +=head1 API + +=head2 Class Methods + +=cut + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'ErmLicense'; +} + +1; diff --git a/Koha/ERM/Licenses.pm b/Koha/ERM/Licenses.pm new file mode 100644 index 0000000000..c45af4d785 --- /dev/null +++ b/Koha/ERM/Licenses.pm @@ -0,0 +1,53 @@ +package Koha::ERM::Licenses; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + + +use Koha::Database; + +use Koha::ERM::License; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::ERM::Licenses - Koha ERM License Object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'ErmLicense'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::ERM::License'; +} + +1; diff --git a/Koha/REST/V1/ERM/Licenses.pm b/Koha/REST/V1/ERM/Licenses.pm new file mode 100644 index 0000000000..11573ecbcb --- /dev/null +++ b/Koha/REST/V1/ERM/Licenses.pm @@ -0,0 +1,233 @@ +package Koha::REST::V1::ERM::Licenses; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::ERM::Licenses; + +use Scalar::Util qw( blessed ); +use Try::Tiny qw( catch try ); + +=head1 API + +=head2 Methods + +=head3 list + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $licenses_set = Koha::ERM::Licenses->new; + my $licenses = $c->objects->search( $licenses_set ); + return $c->render( status => 200, openapi => $licenses ); + } + catch { + $c->unhandled_exception($_); + }; + +} + +=head3 get + +Controller function that handles retrieving a single Koha::ERM::License object + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + return try { + my $license_id = $c->validation->param('license_id'); + my $license = $c->objects->find( Koha::ERM::Licenses->search, $license_id ); + + unless ($license) { + return $c->render( + status => 404, + openapi => { error => "License not found" } + ); + } + + return $c->render( + status => 200, + openapi => $license + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 add + +Controller function that handles adding a new Koha::ERM::License 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 $license = Koha::ERM::License->new_from_api($body)->store; + + $c->res->headers->location($c->req->url->to_string . '/' . $license->license_id); + return $c->render( + status => 201, + openapi => $license->to_api + ); + } + ); + } + catch { + + my $to_api_mapping = Koha::ERM::License->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::License object + +=cut + +sub update { + my $c = shift->openapi->valid_input or return; + + my $license_id = $c->validation->param('license_id'); + my $license = Koha::ERM::Licenses->find( $license_id ); + + unless ($license) { + return $c->render( + status => 404, + openapi => { error => "License not found" } + ); + } + + return try { + Koha::Database->new->schema->txn_do( + sub { + + my $body = $c->validation->param('body'); + + $license->set_from_api($body)->store; + + $c->res->headers->location($c->req->url->to_string . '/' . $license->license_id); + return $c->render( + status => 200, + openapi => $license->to_api + ); + } + ); + } + catch { + my $to_api_mapping = Koha::ERM::License->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 $license = Koha::ERM::Licenses->find( $c->validation->param('license_id') ); + unless ($license) { + return $c->render( + status => 404, + openapi => { error => "License not found" } + ); + } + + return try { + $license->delete; + return $c->render( + status => 204, + openapi => q{} + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/api/v1/swagger/definitions/erm_license.yaml b/api/v1/swagger/definitions/erm_license.yaml new file mode 100644 index 0000000000..3431f52082 --- /dev/null +++ b/api/v1/swagger/definitions/erm_license.yaml @@ -0,0 +1,40 @@ +--- +type: object +properties: + license_id: + type: integer + description: internally assigned license identifier + readOnly: true + name: + description: name of the license + type: string + description: + description: description of the license + type: + - string + - "null" + type: + description: description of the license + type: + - string + - "null" + status: + description: status of the license + type: string + started_on: + type: + - string + - "null" + format: date + description: Start of the license + ended_on: + type: + - string + - "null" + format: date + description: End of the license +additionalProperties: false +required: + - license_id + - name + - status diff --git a/api/v1/swagger/definitions/erm_license_agreement.yaml b/api/v1/swagger/definitions/erm_license_agreement.yaml new file mode 100644 index 0000000000..873bc9bd78 --- /dev/null +++ b/api/v1/swagger/definitions/erm_license_agreement.yaml @@ -0,0 +1,34 @@ +--- +type: object +properties: + license_id: + type: integer + description: internally assigned license identifier + readOnly: true + agreement_id: + description: foreign key to agreements + type: integer + status: + description: status of the license + type: + - string + - "null" + physical_location: + description: physical location of the license + type: + - string + - "null" + notes: + description: notes about the license + type: + - string + - "null" + uri: + description: URI of the license + type: + - string + - "null" +additionalProperties: false +required: + - license_id + - agreement_id diff --git a/api/v1/swagger/paths/erm_licenses.yaml b/api/v1/swagger/paths/erm_licenses.yaml new file mode 100644 index 0000000000..d04df9aaad --- /dev/null +++ b/api/v1/swagger/paths/erm_licenses.yaml @@ -0,0 +1,274 @@ +--- +/erm/licenses: + get: + x-mojo-to: ERM::Licenses#list + operationId: listErmLicenses + tags: + - license + summary: List licenses for agreements + produces: + - application/json + parameters: + - description: Case insensitive search on license license_id + in: query + name: license_id + required: false + type: integer + - description: Case insensitive search on license name + in: query + name: name + required: false + type: string + - description: Case insensitive search on license type + in: query + name: type + required: false + type: string + - description: Case insensitive search on license status + in: query + name: status + required: false + type: string + - description: Case insensitive search on license start date + in: query + name: started_on + required: false + type: string + - description: Case insensitive search on license end date + in: query + name: ended_on + required: false + type: string + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + responses: + 200: + description: A list of agreements' licenses + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_license" + type: array + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + post: + x-mojo-to: ERM::Licenses#add + operationId: addERMLicenses + tags: + - license + summary: Add license + consumes: + - application/json + produces: + - application/json + parameters: + - description: A JSON object containing information about the new agreement's license + in: body + name: body + required: true + schema: + $ref: "../swagger.yaml#/definitions/erm_license" + responses: + 201: + description: A successfully created license + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_license" + 400: + description: Bad parameter + schema: + $ref: "../swagger.yaml#/definitions/error" + 401: + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: Ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: Conflict in creating resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + Internal server error. Possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 +"/erm/licenses/{license_id}": + get: + x-mojo-to: ERM::Licenses#get + operationId: getERMlicense + tags: + - license + summary: get license + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/license_id_pp" + responses: + 200: + description: license + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_license" + 401: + description: authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + internal server error. possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + x-koha-embed: + - agreements + put: + x-mojo-to: ERM::Licenses#update + operationId: updateERMlicenses + tags: + - license + summary: update license + consumes: + - application/json + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/license_id_pp" + - name: body + in: body + description: a json object containing new information about existing license + required: true + schema: + $ref: "../swagger.yaml#/definitions/erm_license" + + responses: + 200: + description: a successfully updated license + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_license" + 400: + description: bad parameter + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: conflict in updating resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + internal server error. possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 + x-koha-embed: + - agreements + delete: + x-mojo-to: ERM::Licenses#delete + operationId: deleteERMlicenses + tags: + - license + summary: Delete license + produces: + - application/json + parameters: + - $ref: "../swagger.yaml#/parameters/license_id_pp" + responses: + 204: + description: license deleted + 400: + description: license deletion failed + schema: + $ref: "../swagger.yaml#/definitions/error" + 401: + description: authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + 404: + description: ressource not found + schema: + $ref: "../swagger.yaml#/definitions/error" + 409: + description: conflict in deleting resource + schema: + $ref: "../swagger.yaml#/definitions/error" + 500: + description: |- + internal server error. possible `error_code` attribute values: + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + 503: + description: under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + erm: 1 diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 94b0e0afa0..57e69db401 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -24,6 +24,8 @@ definitions: $ref: ./definitions/city.yaml erm_agreement: $ref: ./definitions/erm_agreement.yaml + erm_license: + $ref: ./definitions/erm_license.yaml error: $ref: ./definitions/error.yaml fund: @@ -163,6 +165,10 @@ paths: $ref: ./paths/erm_agreements.yaml#/~1erm~1agreements "/erm/agreements/{agreement_id}": $ref: "./paths/erm_agreements.yaml#/~1erm~1agreements~1{agreement_id}" + /erm/licenses: + $ref: ./paths/erm_licenses.yaml#/~1erm~1licenses + "/erm/licenses/{license_id}": + $ref: "./paths/erm_licenses.yaml#/~1erm~1licenses~1{license_id}" /erm/users: $ref: ./paths/erm_users.yaml#/~1erm~1users /holds: @@ -374,6 +380,12 @@ parameters: name: library_id required: true type: string + license_id_pp: + description: License internal identifier + in: path + name: license_id + required: true + type: integer match: description: Matching criteria enum: diff --git a/cypress/integration/Licenses_spec.ts b/cypress/integration/Licenses_spec.ts new file mode 100644 index 0000000000..068fafe8a7 --- /dev/null +++ b/cypress/integration/Licenses_spec.ts @@ -0,0 +1,245 @@ +import { mount } from "@cypress/vue"; +const dayjs = require("dayjs"); /* Cannot use our calendar JS code, it's in an include file (!) + Also note that moment.js is deprecated */ + +const dates = { + today_iso: dayjs().format("YYYY-MM-DD"), + today_us: dayjs().format("MM/DD/YYYY"), + tomorrow_iso: dayjs().add(1, "day").format("YYYY-MM-DD"), + tomorrow_us: dayjs().add(1, "day").format("MM/DD/YYYY"), +}; +function get_license() { + return { + license_id: 1, + name: "license 1", + description: "my first license", + type: "local", + status: "active", + started_on: dates["today_iso"], + ended_on: dates["tomorrow_iso"], + }; +} + +describe("License CRUD operations", () => { + beforeEach(() => { + cy.login("koha", "koha"); + cy.title().should("eq", "Koha staff interface"); + }); + + it("List license", () => { + // GET license returns 500 + cy.intercept("GET", "/api/v1/erm/licenses", { + statusCode: 500, + error: "Something went wrong", + }); + cy.visit("/cgi-bin/koha/erm/erm.pl"); + cy.get("#navmenulist").contains("Licenses").click(); + cy.get("main div[class='dialog alert']").contains( + /Something went wrong/ + ); + + // GET licenses returns empty list + cy.intercept("GET", "/api/v1/erm/licenses*", []); + cy.visit("/cgi-bin/koha/erm/licenses"); + cy.get("#licenses_list").contains("There are no licenses defined."); + + // GET licenses returns something + let license = get_license(); + let licenses = [license]; + + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: licenses, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/licenses/*", license); + cy.visit("/cgi-bin/koha/erm/licenses"); + cy.get("#licenses_list").contains("Showing 1 to 1 of 1 entries"); + }); + + it("Add license", () => { + // Click the button in the toolbar + cy.visit("/cgi-bin/koha/erm/licenses"); + cy.contains("New license").click(); + cy.get("#licenses_add h2").contains("New license"); + + // Fill in the form for normal attributes + let license = get_license(); + + cy.get("#licenses_add").contains("Submit").click(); + cy.get("input:invalid,textarea:invalid,select:invalid").should( + "have.length", + 4 + ); + cy.get("#license_name").type(license.name); + cy.get("#license_description").type(license.description); + cy.get("#licenses_add").contains("Submit").click(); + cy.get("#license_type").select(license.type); + cy.get("#license_status").select(license.status); + + cy.get("#started_on").click(); + cy.get(".flatpickr-calendar") + .eq(0) + .find("span.today") + .click({ force: true }); + + cy.get("#ended_on").click(); + cy.get(".flatpickr-calendar") + .eq(1) + .find("span.today") + .next("span") + .click(); + + // Submit the form, get 500 + cy.intercept("POST", "/api/v1/erm/licenses", { + statusCode: 500, + error: "Something went wrong", + }); + cy.get("#licenses_add").contains("Submit").click(); + cy.get("main div[class='dialog alert']").contains( + "Something went wrong: Internal Server Error" + ); + + // Submit the form, success! + cy.intercept("POST", "/api/v1/erm/licenses", { + statusCode: 201, + body: license, + }); + cy.get("#licenses_add").contains("Submit").click(); + cy.get("main div[class='dialog message']").contains( + "License created" + ); + }); + + it("Edit license", () => { + let license = get_license(); + let licenses = [license]; + // Click the 'Edit' button from the list + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: licenses, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/licenses/*", license).as( + "get-license" + ); + cy.visit("/cgi-bin/koha/erm/licenses"); + cy.get("#licenses_list table tbody tr:first") + .contains("Edit") + .click(); + cy.wait("@get-license"); + cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet! + cy.get("#licenses_add h2").contains("Edit license"); + + // Form has been correctly filled in + cy.get("#license_name").should("have.value", license.name); + cy.get("#license_description").should( + "have.value", + license.description + ); + cy.get("#license_type").should("have.value", license.type); + cy.get("#license_status").should("have.value", license.status); + cy.get("#started_on").invoke("val").should("eq", dates["today_us"]); + cy.get("#ended_on").invoke("val").should("eq", dates["tomorrow_us"]); + + // Submit the form, get 500 + cy.intercept("PUT", "/api/v1/erm/licenses/*", { + statusCode: 500, + error: "Something went wrong", + }); + cy.get("#licenses_add").contains("Submit").click(); + cy.get("main div[class='dialog alert']").contains( + "Something went wrong: Internal Server Error" + ); + + // Submit the form, success! + cy.intercept("PUT", "/api/v1/erm/licenses/*", { + statusCode: 200, + body: license, + }); + cy.get("#licenses_add").contains("Submit").click(); + cy.get("main div[class='dialog message']").contains( + "License updated" + ); + }); + + it("Show license", () => { + let license = get_license(); + let licenses = [license]; + // Click the "name" link from the list + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: licenses, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/licenses/*", license).as( + "get-license" + ); + cy.visit("/cgi-bin/koha/erm/licenses"); + let name_link = cy.get( + "#licenses_list table tbody tr:first td:first a" + ); + name_link.should( + "have.text", + license.name + " (#" + license.license_id + ")" + ); + name_link.click(); + cy.wait("@get-license"); + cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet! + cy.get("#licenses_show h2").contains( + "License #" + license.license_id + ); + }); + + it("Delete license", () => { + let license = get_license(); + let licenses = [license]; + + // Click the 'Delete' button from the list + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: licenses, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/licenses/*", license); + cy.visit("/cgi-bin/koha/erm/licenses"); + + cy.get("#licenses_list table tbody tr:first") + .contains("Delete") + .click(); + cy.get("#licenses_confirm_delete h2").contains("Delete license"); + cy.contains("License name: " + license.name); + + // Submit the form, get 500 + cy.intercept("DELETE", "/api/v1/erm/licenses/*", { + statusCode: 500, + error: "Something went wrong", + }); + cy.contains("Yes, delete").click(); + cy.get("main div[class='dialog alert']").contains( + "Something went wrong: Internal Server Error" + ); + + // Submit the form, success! + cy.intercept("DELETE", "/api/v1/erm/licenses/*", { + statusCode: 204, + body: null, + }); + cy.contains("Yes, delete").click(); + cy.get("main div[class='dialog message']").contains( + "License deleted" + ); + }); +}); diff --git a/installer/data/mysql/mandatory/auth_val_cat.sql b/installer/data/mysql/mandatory/auth_val_cat.sql index ed9cdd56fc..c6ff7eb97f 100644 --- a/installer/data/mysql/mandatory/auth_val_cat.sql +++ b/installer/data/mysql/mandatory/auth_val_cat.sql @@ -97,6 +97,15 @@ VALUES ('ERM_AGREEMENT_RENEWAL_PRIORITY', 'cancel', 'Cancel'), ('ERM_AGREEMENT_USER_ROLES', 'librarian', 'ERM librarian'), ('ERM_AGREEMENT_USER_ROLES', 'subject_specialist', 'Subject specialist'), + ('ERM_LICENSE_TYPE', 'local', 'Local'), + ('ERM_LICENSE_TYPE', 'consortial', 'Consortial'), + ('ERM_LICENSE_TYPE', 'national', 'National'), + ('ERM_LICENSE_TYPE', 'alliance', 'Alliance'), + ('ERM_LICENSE_STATUS', 'in_negotiation', 'In negociation'), + ('ERM_LICENSE_STATUS', 'not_yet_active', 'Not yet active'), + ('ERM_LICENSE_STATUS', 'active', 'Active'), + ('ERM_LICENSE_STATUS', 'rejected', 'Rejected'), + ('ERM_LICENSE_STATUS', 'expired', 'Expired'), ('ERM_AGREEMENT_LICENSE_STATUS', 'controlling', 'Controlling'), ('ERM_AGREEMENT_LICENSE_STATUS', 'future', 'Future'), ('ERM_AGREEMENT_LICENSE_STATUS', 'history', 'Historic'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/erm/erm.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/erm/erm.tt index bd71761c88..2960f8d670 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/erm/erm.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/erm/erm.tt @@ -34,8 +34,8 @@ const agreement_user_roles = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_USER_ROLES')) | $raw %]; var table_settings = [% TablesSettings.GetTableSettings( 'erm', 'agreements', 'agreements', 'json' ) | $raw %]; - var agreements_table_url = '/api/v1/erm/agreements?'; + var agreements_table_url = '/api/v1/erm/agreements?'; [% IF agreement_name_filter %] var agreement_name_filter = { 'name': { @@ -44,6 +44,22 @@ }; agreements_table_url += 'q='+ encodeURIComponent(JSON.stringify(agreement_name_filter)); [% END %] + + const license_types = [% To.json(AuthorisedValues.Get('ERM_LICENSE_TYPE')) | $raw %]; + const license_statuses = [% To.json(AuthorisedValues.Get('ERM_LICENSE_STATUS')) | $raw %]; + + var table_settings = [% TablesSettings.GetTableSettings( 'erm', 'agreements', 'agreements', 'json' ) | $raw %]; + + var licenses_table_url = '/api/v1/erm/licenses?'; + [% IF license_name_filter %] + var license_name_filter = { + 'name': { + "like": '%[%- license_name_filter | html -%]%' + } + }; + licenses_table_url += 'q='+ encodeURIComponent(JSON.stringify(license_name_filter)); + [% END %] + [% Asset.js("js/vue/dist/main.js") | $raw %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsList.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsList.vue index f4f5c882e9..1ceb85b9b4 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsList.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsList.vue @@ -1,6 +1,6 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsButtonEdit.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ButtonEdit.vue similarity index 84% rename from koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsButtonEdit.vue rename to koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ButtonEdit.vue index 160677004f..d49479f16f 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsButtonEdit.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ButtonEdit.vue @@ -6,6 +6,6 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue index f65874b6e2..e1245bc819 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue @@ -22,6 +22,15 @@ Agreements +
  • + + + Licenses +
  • + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Licenses.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Licenses.vue new file mode 100644 index 0000000000..72a37a40cb --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Licenses.vue @@ -0,0 +1,102 @@ + + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue new file mode 100644 index 0000000000..736c96b4c1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue @@ -0,0 +1,205 @@ +