From aa735af8afee04ec9e877abbb12c1a5bc08bc2db Mon Sep 17 00:00:00 2001 From: Jake Deery Date: Wed, 4 Sep 2024 14:52:58 +0000 Subject: [PATCH] Bug 37576: Add additional fields for ERM agreements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This bug adds support for additional fields in the ERM module's agreements, similar to how Bug 35287 added support for additional fields in the ERM module's licences. To test (k.t.d): a) APPLY PATCH b) Run cypress --spec t/cypress/integration/AdditionalFields_spec.ts 1) Note how the tests pass c) Add new additional fields for 'erm_agreements' 1) Go to /cgi-bin/koha/admin/additional-fields.pl?tablename=erm_agreements 2) Create field one called 'text non-repeatable' 3) Create field two called 'text repeatable', check 'repeatable' 4) Create field three called 'av non-repeatable', pick LANG authorised value 5) Create field four called 'av repeatable', pick LOC authorised value, check repeatable d) Create new agreement 1) Go to /cgi-bin/koha/erm/agreements/add, notice the new additional fields section 2) Complete all mandatory fields for a new licence 3) Experiment with the four different additional field types – it may be useful to watch the Cypress-generated test video for guidance 4) Select some AV options from the AV fields, deselect them, notice the repeatable one allows for multiple selection, the non-repeatable one does not e) Save the agreement, then view it 1) To view the licence, click its name in the table list on /cgi-bin/koha/erm/agreements 2) notice the additional fields on display 3) also notice that the authorised values are in their human-readable form, and not their coded form f) Edit the agreement, then view it again 1) Go to /cgi-bin/koha/erm/agreements/edit/1 2) Play around again with the fields. Save. 3) Repeat step e, have the edits shown up? g) Test searchability 1) Go to /cgi-bin/koha/admin/additional-fields.pl?tablename=erm_agreements 2) Edit one of the fields and make sure searchable is checked (ensure you choose a field that has some data in it) 3) Go to /cgi-bin/koha/erm/agreements 4) Notice that the searchable field(s) are now columns in the table 5) Notice that searchable AV fields contain a drop-down 6) Notice that searchable text fields have an input field 7) Perform a search on the additional field 8) Notice that the searching is working as expected h) SIGN OFF Signed-off-by: Michaela Sieber Signed-off-by: Nick Clemens --- Koha/AdditionalField.pm | 1 + Koha/ERM/Agreement.pm | 2 +- Koha/ERM/Agreements.pm | 2 +- Koha/REST/V1/ERM/Agreements.pm | 8 + Koha/REST/V1/ExtendedAttributeTypes.pm | 13 +- Koha/Schema/Result/ErmAgreement.pm | 32 + api/v1/swagger/definitions/erm_agreement.yaml | 10 + api/v1/swagger/paths/erm_agreements.yaml | 6 + .../paths/extended_attribute_types.yaml | 1 + .../en/modules/admin/additional-fields.tt | 5 +- .../vue/components/ERM/AgreementsFormAdd.vue | 12 + .../js/vue/components/ERM/AgreementsList.vue | 51 +- .../js/vue/components/ERM/AgreementsShow.vue | 11 +- .../prog/js/vue/fetch/erm-api-client.js | 2 +- .../integration/AdditionalFields_spec.ts | 568 ++++++++++++++++++ 15 files changed, 710 insertions(+), 14 deletions(-) diff --git a/Koha/AdditionalField.pm b/Koha/AdditionalField.pm index 7e5c16a049e..fd9621d6816 100644 --- a/Koha/AdditionalField.pm +++ b/Koha/AdditionalField.pm @@ -60,6 +60,7 @@ sub to_api { 'aqbasket' => 'basket', 'aqinvoices' => 'invoice', 'erm_licenses' => 'license', + 'erm_agreements' => 'agreement', 'aqorders' => 'order', }; diff --git a/Koha/ERM/Agreement.pm b/Koha/ERM/Agreement.pm index dac3e56c9e1..785c5e30c7b 100644 --- a/Koha/ERM/Agreement.pm +++ b/Koha/ERM/Agreement.pm @@ -25,7 +25,7 @@ use Koha::DateUtils qw( dt_from_string ); use Koha::Exceptions; use Koha::Acquisition::Bookseller; -use base qw(Koha::Object); +use base qw(Koha::Object::Mixin::AdditionalFields Koha::Object); use Koha::ERM::Agreement::Periods; use Koha::ERM::Agreement::Licenses; diff --git a/Koha/ERM/Agreements.pm b/Koha/ERM/Agreements.pm index e8b23c82e5f..9c786ca1077 100644 --- a/Koha/ERM/Agreements.pm +++ b/Koha/ERM/Agreements.pm @@ -24,7 +24,7 @@ use Koha::DateUtils qw( dt_from_string ); use Koha::ERM::Agreement; use Koha::ERM::Agreement::Periods; -use base qw(Koha::Objects); +use base qw(Koha::Objects::Mixin::AdditionalFields Koha::Objects); =head1 NAME diff --git a/Koha/REST/V1/ERM/Agreements.pm b/Koha/REST/V1/ERM/Agreements.pm index dd67576d053..2ba2e0fedea 100644 --- a/Koha/REST/V1/ERM/Agreements.pm +++ b/Koha/REST/V1/ERM/Agreements.pm @@ -97,6 +97,7 @@ sub add { my $agreement_licenses = delete $body->{agreement_licenses} // []; my $agreement_relationships = delete $body->{agreement_relationships} // []; my $documents = delete $body->{documents} // []; + my $extended_attributes = delete $body->{extended_attributes} // []; my $agreement = Koha::ERM::Agreement->new_from_api($body)->store; $agreement->periods($periods); @@ -105,6 +106,9 @@ sub add { $agreement->agreement_relationships($agreement_relationships); $agreement->documents($documents); + my @extended_attributes = map { {'id' => $_->{field_id}, 'value' => $_->{value}} } @{$extended_attributes}; + $agreement->extended_attributes( \@extended_attributes ); + $c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id); return $c->render( status => 201, @@ -181,6 +185,7 @@ sub update { my $agreement_licenses = delete $body->{agreement_licenses} // []; my $agreement_relationships = delete $body->{agreement_relationships} // []; my $documents = delete $body->{documents} // []; + my $extended_attributes = delete $body->{extended_attributes} // []; $agreement->set_from_api($body)->store; $agreement->periods($periods); @@ -189,6 +194,9 @@ sub update { $agreement->agreement_relationships($agreement_relationships); $agreement->documents($documents); + my @extended_attributes = map { {'id' => $_->{field_id}, 'value' => $_->{value}} } @{$extended_attributes}; + $agreement->extended_attributes( \@extended_attributes ); + $c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id); return $c->render( status => 200, diff --git a/Koha/REST/V1/ExtendedAttributeTypes.pm b/Koha/REST/V1/ExtendedAttributeTypes.pm index 8dfa4ea6ed6..f891c41dd10 100644 --- a/Koha/REST/V1/ExtendedAttributeTypes.pm +++ b/Koha/REST/V1/ExtendedAttributeTypes.pm @@ -46,12 +46,13 @@ sub list { # FIXME: Maybe not the best place for this mapping my $resource_to_table = { - basket => 'aqbasket', - credit => 'accountlines:credit', - debit => 'accountlines:debit', - invoice => 'aqinvoices', - license => 'erm_licenses', - order => 'aqorders', + basket => 'aqbasket', + credit => 'accountlines:credit', + debit => 'accountlines:debit', + invoice => 'aqinvoices', + license => 'erm_licenses', + agreement => 'erm_agreements', + order => 'aqorders', }; return try { diff --git a/Koha/Schema/Result/ErmAgreement.pm b/Koha/Schema/Result/ErmAgreement.pm index b2b97e4f3ee..78679d364fc 100644 --- a/Koha/Schema/Result/ErmAgreement.pm +++ b/Koha/Schema/Result/ErmAgreement.pm @@ -281,6 +281,38 @@ __PACKAGE__->add_columns( '+is_perpetual' => { is_boolean => 1 } ); +__PACKAGE__->has_many( + "additional_field_values", + "Koha::Schema::Result::AdditionalFieldValue", + sub { + my ($args) = @_; + + return { + "$args->{foreign_alias}.record_id" => { -ident => "$args->{self_alias}.agreement_id" }, + + "$args->{foreign_alias}.field_id" => + { -in => \'(SELECT id FROM additional_fields WHERE tablename="erm_agreements")' }, + }; + }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +__PACKAGE__->has_many( + "extended_attributes", + "Koha::Schema::Result::AdditionalFieldValue", + sub { + my ($args) = @_; + + return { + "$args->{foreign_alias}.record_id" => { -ident => "$args->{self_alias}.agreement_id" }, + + "$args->{foreign_alias}.field_id" => + { -in => \'(SELECT id FROM additional_fields WHERE tablename="erm_agreements")' }, + }; + }, + { cascade_copy => 0, cascade_delete => 0 }, +); + sub koha_object_class { 'Koha::ERM::Agreement'; } diff --git a/api/v1/swagger/definitions/erm_agreement.yaml b/api/v1/swagger/definitions/erm_agreement.yaml index e8fc871d349..d355d69b3c1 100644 --- a/api/v1/swagger/definitions/erm_agreement.yaml +++ b/api/v1/swagger/definitions/erm_agreement.yaml @@ -69,6 +69,16 @@ properties: type: - object - "null" + extended_attributes: + description: Related additional field values + type: + - array + items: + $ref: extended_attribute_value.yaml + _strings: + type: + - object + - "null" additionalProperties: false required: diff --git a/api/v1/swagger/paths/erm_agreements.yaml b/api/v1/swagger/paths/erm_agreements.yaml index 43a48e11790..933192191a8 100644 --- a/api/v1/swagger/paths/erm_agreements.yaml +++ b/api/v1/swagger/paths/erm_agreements.yaml @@ -69,6 +69,8 @@ enum: - user_roles - vendor + - extended_attributes + - +strings collectionFormat: csv - $ref: "../swagger.yaml#/parameters/match" - $ref: "../swagger.yaml#/parameters/order_by" @@ -198,6 +200,8 @@ - agreement_packages.package - documents - vendor + - extended_attributes + - +strings collectionFormat: csv responses: 200: @@ -265,6 +269,8 @@ - agreement_licenses - agreement_relationships - documents + - extended_attributes + - +strings collectionFormat: csv responses: 200: diff --git a/api/v1/swagger/paths/extended_attribute_types.yaml b/api/v1/swagger/paths/extended_attribute_types.yaml index 7bad73967c4..08f8141873e 100644 --- a/api/v1/swagger/paths/extended_attribute_types.yaml +++ b/api/v1/swagger/paths/extended_attribute_types.yaml @@ -19,6 +19,7 @@ - debit - invoice - license + - agreement - order - subscription - $ref: "../swagger.yaml#/parameters/match" diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt index ed1c4af13e3..d9a12a82fdc 100755 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt @@ -23,7 +23,7 @@ [% marcfield_tables = ['subscription', 'aqorders'] %] -[% searchable_tables = ['subscription', 'aqbasket', 'aqinvoices', 'erm_licenses'] %] +[% searchable_tables = ['subscription', 'aqbasket', 'aqinvoices', 'erm_licenses', 'erm_agreements'] %] [% show_marcfield = marcfield_tables.grep('^' _ tablename _ '$').size ? 1 : 0 %] [% show_searchable = searchable_tables.grep('^' _ tablename _ '$').size ? 1 : 0 %] @@ -136,7 +136,8 @@ [% WRAPPER table_option value="accountlines:debit" %]Account lines (debit)[% END %] [% END %] [% IF CAN_user_erm %] - [% WRAPPER table_option value="erm_licenses" %]ERM licenses[% END %] + [% WRAPPER table_option value="erm_licenses" %]ERM Licenses[% END %] + [% WRAPPER table_option value="erm_agreements" %]ERM Agreements[% END %] [% END %] [% ELSE %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue index 645a13b5bef..f7e8d264127 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue @@ -132,6 +132,11 @@ + this.table_url(), table_settings: this.agreement_table_settings, add_filters: true, @@ -161,7 +165,15 @@ export default { }, beforeRouteEnter(to, from, next) { next(vm => { - vm.getAgreementCount().then(() => (vm.initialized = true)) + vm.getAgreementCount().then(() => + vm + .getSearchableAdditionalFields() + .then(() => + vm + .getSearchableAVOptions() + .then(() => (vm.initialized = true)) + ) + ) }) }, methods: { @@ -173,6 +185,41 @@ export default { }, error => {} ) + }, + async getSearchableAdditionalFields() { + const client = APIClient.additional_fields + await client.additional_fields.getAll("agreement").then( + searchable_additional_fields => { + this.searchable_additional_fields = + searchable_additional_fields.filter( + field => field.searchable + ) + }, + error => {} + ) + }, + async getSearchableAVOptions() { + const client_av = APIClient.authorised_values + let av_cat_array = this.searchable_additional_fields + .filter(field => field.authorised_value_category_name) + .map(field => field.authorised_value_category_name) + + await client_av.values + .getCategoriesWithValues([ + ...new Set(av_cat_array.map(av_cat => '"' + av_cat + '"')), + ]) // unique + .then(av_categories => { + av_cat_array.forEach(av_cat => { + let av_match = av_categories.find( + element => element.category_name == av_cat + ) + this.searchable_av_options[av_cat] = + av_match.authorised_values.map(av => ({ + value: av.value, + label: av.description, + })) + }) + }) }, doShow: function ({ agreement_id }, dt, event) { event.preventDefault() diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue index 27eee68c05d..7b49fe88d67 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue @@ -322,6 +322,12 @@ +
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/erm-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/erm-api-client.js index a90ec237975..7bd23188987 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/erm-api-client.js +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/erm-api-client.js @@ -23,7 +23,7 @@ export class ERMAPIClient extends HttpClient { endpoint: "agreements/" + id, headers: { "x-koha-embed": - "periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license,agreement_relationships,agreement_relationships.related_agreement,documents,agreement_packages,agreement_packages.package,vendor", + "periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license,agreement_relationships,agreement_relationships.related_agreement,documents,agreement_packages,agreement_packages.package,vendor,extended_attributes,+strings", }, }), getAll: (query, params) => diff --git a/t/cypress/integration/AdditionalFields_spec.ts b/t/cypress/integration/AdditionalFields_spec.ts index a334df4688e..8ab3f6a46cc 100644 --- a/t/cypress/integration/AdditionalFields_spec.ts +++ b/t/cypress/integration/AdditionalFields_spec.ts @@ -83,6 +83,176 @@ function get_licenses_additional_fields() { ]; } +function get_no_additional_fields_agreement() { + return { + agreement_id: 1, + name: "agreement 1", + description: "my first agreement", + agreement_licenses: [], + agreement_packages: [], + agreement_relationships: [], + closure_reason: "", + is_perpetual: false, + license_info: "", + periods: [], + renewal_priority: "", + status: "active", + user_roles: [], + vendor_id: 1, + vendor: [cy.get_vendors_to_relate()[0]], + documents: [ + { + agreement_id: 1, + file_description: "file description", + file_name: "file.json", + notes: "file notes", + physical_location: "file physical location", + uri: "file uri", + uploaded_on: "2022-10-27T11:57:02+00:00", + }, + ], + extended_attributes: [], + _strings: { + "additional_field_values": [] + }, + }; +} +function get_agreement() { + return { + agreement_id: 1, + name: "agreement 1", + description: "my first agreement", + agreement_licenses: [], + agreement_packages: [], + agreement_relationships: [], + closure_reason: "", + is_perpetual: false, + license_info: "", + periods: [], + renewal_priority: "", + status: "active", + user_roles: [], + vendor_id: 1, + vendor: [cy.get_vendors_to_relate()[0]], + documents: [ + { + agreement_id: 1, + file_description: "file description", + file_name: "file.json", + notes: "file notes", + physical_location: "file physical location", + uri: "file uri", + uploaded_on: "2022-10-27T11:57:02+00:00", + }, + ], + extended_attributes: [ + { + field_id: 1, + id: "1", + record_id: "1", + value: "REF", + }, + { + field_id: 1, + id: "2", + record_id: "1", + value: "NFIC", + }, + { + field_id: 2, + id: "3", + record_id: "1", + value: "some text", + }, + { + field_id: 3, + id: "4", + record_id: "1", + value: "some repeatable text", + }, + { + field_id: 4, + id: "5", + record_id: "1", + value: "AF", + }, + ], + _strings: { + additional_field_values: [ + { + field_id: 1, + field_label: "AV Repeatable", + type: "av", + value_str: "Reference, Non-fiction", + }, + { + field_id: 2, + field_label: "Text non-repeatable", + type: "text", + value_str: "some text", + }, + { + field_id: 3, + field_label: "Text repeatable", + type: "text", + value_str: "some repeatable text", + }, + { + field_id: 4, + field_label: "AV Searchable", + type: "av", + value_str: "Afghanistan", + }, + ], + }, + }; +} + +function get_agreements_additional_fields() { + return [ + { + authorised_value_category_name: "CCODE", + extended_attribute_type_id: 1, + marcfield: "", + marcfield_mode: "get", + name: "AV Repeatable", + repeatable: true, + searchable: true, + resource_type: "agreement", + }, + { + authorised_value_category_name: null, + extended_attribute_type_id: 2, + marcfield: "", + marcfield_mode: "get", + name: "Text non-repeatable", + repeatable: false, + searchable: false, + resource_type: "agreement", + }, + { + authorised_value_category_name: null, + extended_attribute_type_id: 3, + marcfield: "", + marcfield_mode: "get", + name: "Text repeatable", + repeatable: true, + searchable: false, + resource_type: "agreement", + }, + { + authorised_value_category_name: "COUNTRY", + extended_attribute_type_id: 4, + marcfield: "", + marcfield_mode: "get", + name: "AV Searchable", + repeatable: false, + searchable: true, + resource_type: "agreement", + }, + ]; +} + function get_av_cats() { return [ { @@ -167,6 +337,10 @@ describe("Additional Fields operations", () => { ); }); + // + // for licenses + // + it("Additional Fields display - Table (licenses)", () => { let license = cy.get_license(); let licenses = [license]; @@ -555,4 +729,398 @@ describe("Additional Fields operations", () => { "#licenses_add form #additional_fields label[for='additional_field_3']" ).should("have.length", 2); }); + + // + // for agreements + // + + it("Additional Fields display - Table (agreements)", () => { + let agreement = get_agreement(); + let agreements = [agreement]; + let agreement_additional_fields = get_agreements_additional_fields(); + let av_cats = get_av_cats(); + + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: agreement_additional_fields, + statusCode: 200, + }); + + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: agreements, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/agreements/*", agreement); + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.get("#agreements_list").contains("Showing 1 to 1 of 1 entries"); + + cy.get("#agreements_list table tbody tr:first").contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[4] + ) + ); + cy.get("#agreements_list table tbody tr:first").contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[0] + ) + + ", " + + get_description_from_av_value( + av_cats, + agreement.extended_attributes[1] + ) + ); + }); + + it("Additional Fields display - Show (agreements)", () => { + let empty_agreement = get_no_additional_fields_agreement(); + let agreement = get_agreement(); + let agreements = [agreement]; + let vendors = cy.get_vendors_to_relate(); + let agreement_additional_fields = get_agreements_additional_fields(); + let av_cats = get_av_cats(); + + // Click the 'Edit' button from the list + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: agreements, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/agreements/*", empty_agreement).as( + "get-empty-agreement" + ); + + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: [], + statusCode: 200, + }).as("empty-additional-fields"); + + //Empty additional fields, should not display + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.get("#agreements_list table tbody tr:first td:first a").click(); + cy.wait("@get-empty-agreement"); + cy.get("#agreements_show #additional_fields").should("not.exist"); + + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: agreement_additional_fields, + statusCode: 200, + }).as("existing-additional-fields"); + + cy.intercept( + { + pathname: "/api/v1/authorised_value_categories", + query: { + q: '{"me.category_name":["CCODE", "COUNTRY"]}', + }, + }, + { + body: av_cats, + statusCode: 200, + } + ).as("avcategories"); + + cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as( + "get-agreement" + ); + + // There are additional fields, fieldset should exist + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.get("#agreements_list table tbody tr:first td:first a").click(); + cy.wait("@get-agreement"); + cy.get("#agreements_show #additional_fields").should("exist"); + + // All fields are presented correctly + cy.get( + "#agreements_show #additional_fields label[for='additional_field_1']" + ).contains(agreement_additional_fields[0].name); + cy.get( + "#agreements_show #additional_fields label[for='additional_field_1']" + ) + .parent() + .children("span") + .contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[0] + ) + + ", " + + get_description_from_av_value( + av_cats, + agreement.extended_attributes[1] + ) + ); + + cy.get( + "#agreements_show #additional_fields label[for='additional_field_2']" + ).contains(agreement_additional_fields[1].name); + cy.get( + "#agreements_show #additional_fields label[for='additional_field_2']" + ) + .parent() + .children("span") + .contains(agreement.extended_attributes[2].value); + + cy.get( + "#agreements_show #additional_fields label[for='additional_field_3']" + ).contains(agreement_additional_fields[2].name); + cy.get( + "#agreements_show #additional_fields label[for='additional_field_3']" + ) + .parent() + .children("span") + .contains(agreement.extended_attributes[3].value); + + cy.get( + "#agreements_show #additional_fields label[for='additional_field_4']" + ).contains(agreement_additional_fields[3].name); + cy.get( + "#agreements_show #additional_fields label[for='additional_field_4']" + ) + .parent() + .children("span") + .contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[4] + ) + ); + }); + + it("Additional Fields entry - Add (agreements)", () => { + let vendors = cy.get_vendors_to_relate(); + let agreement_additional_fields = get_licenses_additional_fields(); + let av_cats = get_av_cats(); + + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: [], + statusCode: 200, + }).as("empty-additional-fields"); + + // No additional fields, fieldset should not exist + cy.visit("/cgi-bin/koha/erm/agreements/add"); + cy.get("#agreements_add form #additional_fields").should("not.exist"); + + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: agreement_additional_fields, + statusCode: 200, + }).as("existing-additional-fields"); + + cy.intercept( + { + pathname: "/api/v1/authorised_value_categories", + query: { + q: '{"me.category_name":["CCODE", "COUNTRY"]}', + }, + }, + { + body: av_cats, + statusCode: 200, + } + ).as("avcategories"); + // There are additional fields, fieldset should exist + cy.visit("/cgi-bin/koha/erm/agreements/add"); + cy.get("#agreements_add form #additional_fields").should("exist"); + + // All additional fields should be listed + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_1']" + ).contains(agreement_additional_fields[0].name); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_2']" + ).contains(agreement_additional_fields[1].name); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_3']" + ).contains(agreement_additional_fields[2].name); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_4']" + ).contains(agreement_additional_fields[3].name); + + cy.get("#additional_fields #additional_field_1 .vs__selected").should( + "not.exist" + ); //new agreement, no pre-selected value + + // Pick one value + cy.get("#additional_fields #additional_field_1 .vs__search").click(); + cy.get( + "#additional_fields #additional_field_1 #vs5__option-0" + ).contains(av_cats[0].authorised_values[0].description); + cy.get("#additional_fields #additional_field_1 #vs5__option-0").click(); + cy.get("#additional_fields #additional_field_1 .vs__selected").contains( + av_cats[0].authorised_values[0].description + ); + cy.get("#additional_fields #additional_field_1 .vs__selected").should( + "have.length", + 1 + ); + + // Pick a second value for the same repeatable AV field + cy.get("#additional_fields #additional_field_1 .vs__search").click(); + cy.get( + "#additional_fields #additional_field_1 #vs5__option-1" + ).contains(av_cats[0].authorised_values[1].description); + cy.get("#additional_fields #additional_field_1 #vs5__option-1").click(); + cy.get("#additional_fields #additional_field_1 .vs__selected").contains( + av_cats[0].authorised_values[1].description + ); + cy.get("#additional_fields #additional_field_1 .vs__selected").should( + "have.length", + 2 + ); + + // Attempt to pick the same value again - should not be possible + cy.get("#additional_fields #additional_field_1 .vs__search").click(); + cy.get( + "#additional_fields #additional_field_1 #vs5__option-1" + ).contains(av_cats[0].authorised_values[1].description); + cy.get("#additional_fields #additional_field_1 #vs5__option-1").click(); + cy.get("#additional_fields #additional_field_1 .vs__selected").should( + "have.length", + 2 + ); + + // Remove the second selected value + cy.get( + "#additional_fields #additional_field_1 .vs__selected button[title='Deselect " + + av_cats[0].authorised_values[1].description + + "'" + ).click(); + cy.get("#additional_fields #additional_field_1 .vs__selected").should( + "have.length", + 1 + ); + cy.get("#additional_fields #additional_field_1 .vs__selected").contains( + av_cats[0].authorised_values[0].description + ); + }); + + it("Additional Fields entry - Edit (agreements)", () => { + let agreement = get_agreement(); + let agreements = [agreement]; + let vendors = cy.get_vendors_to_relate(); + let agreement_additional_fields = get_agreements_additional_fields(); + let av_cats = get_av_cats(); + + // Click the 'Edit' button from the list + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: agreements, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }); + cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as( + "get-agreement" + ); + + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + + cy.intercept("GET", "/api/v1/extended_attribute_types*", { + body: agreement_additional_fields, + statusCode: 200, + }).as("existing-additional-fields"); + + cy.intercept( + { + pathname: "/api/v1/authorised_value_categories", + query: { + q: '{"me.category_name":["CCODE", "COUNTRY"]}', + }, + }, + { + body: av_cats, + statusCode: 200, + } + ).as("avcategories"); + + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.get("#agreements_list table tbody tr:first").contains("Edit").click(); + cy.wait("@get-agreement"); + cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet! + + // All additional fields should be pre-populated + cy.get("#additional_fields #additional_field_1 .vs__selected").contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[0] + ) + ); + cy.get("#additional_fields #additional_field_1 .vs__selected").contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[1] + ) + ); + + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_2']" + ) + .parent() + .children("input") + .should("have.value", agreement.extended_attributes[2].value); + + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_3']" + ) + .parent() + .children("input") + .should("have.value", agreement.extended_attributes[3].value); + + cy.get("#additional_fields #additional_field_4 .vs__selected").contains( + get_description_from_av_value( + av_cats, + agreement.extended_attributes[4] + ) + ); + + // Clear text field works + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_2']" + ) + .parent() + .children(".clear_attribute") + .click(); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_2']" + ) + .parent() + .children("input") + .should("have.value", ""); + + // "+New" text field works + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_3']" + ).should("have.length", 1); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_3']" + ) + .parent() + .children(".clone_attribute") + .click(); + cy.get( + "#agreements_add form #additional_fields label[for='additional_field_3']" + ).should("have.length", 2); + }); + }); -- 2.39.5