Bug 32030: Link external packages with agreements

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>
This commit is contained in:
Jonathan Druart 2022-06-30 17:14:40 +02:00 committed by Tomas Cohen Arazi
parent 62c8469e80
commit 111622efcc
No known key found for this signature in database
GPG Key ID: 0A272EA1B2F3C15F
14 changed files with 476 additions and 393 deletions

View File

@ -84,6 +84,26 @@ sub vendor {
return Koha::Acquisition::Bookseller->_new_from_dbic($rs);
}
=head3 to_api_mapping
=cut
sub to_api_mapping {
my ( $self ) = @_;
return {
external_id => undef,
( # Do we really need this?
$self->external_id
? (
package_id => $self->external_id,
koha_internal_id => $self->package_id
)
: ()
)
};
}
=head2 Internal methods
=head3 _type

View File

@ -9,6 +9,8 @@ use List::Util qw( first );
use Koha::Exceptions;
use Koha::ERM::EHoldings::Packages;
sub new {
my $class = shift;
my $self = {};
@ -80,8 +82,13 @@ sub build_vendor {
sub build_package {
my ( $self, $result ) = @_;
my $local_package = $self->get_local_package(
$result->{vendorId} . '-' . $result->{packageId} );
my $package = {
package_id => $result->{vendorId} . '-' . $result->{packageId},
( $local_package
? ( koha_internal_id => $local_package->package_id )
: () ),
name => $result->{packageName},
content_type => $result->{contentType}, # This does not exist in /vendors/1/packages/2/titles/3
created_on => undef,
@ -121,11 +128,18 @@ sub build_additional_params {
return $additional_params;
}
sub get_local_package {
my ( $self, $package_id ) = @_;
return Koha::ERM::EHoldings::Packages->find(
{ provider => 'ebsco', external_id => $package_id } );
}
sub embed {
my ( $self, $object, $info, $embed_header ) = @_;
$embed_header ||= q{};
my @embed_resources;
foreach my $embed_req ( split /\s*,\s*/, $embed_header ) {
if ( $embed_req eq 'vendor.name' ) {
$object->{vendor} = { name => $info->{vendorName}, };
@ -145,6 +159,23 @@ sub embed {
elsif ( $embed_req eq 'package.name' ) {
$object->{package} = { name => $info->{packageName}, };
}
elsif ( $embed_req eq 'package_agreements.agreement' ) {
# How to deal with 'package_agreements.agreement'?
$object->{package_agreements} = [];
my $package_id = $info->{vendorId} . '-' . $info->{packageId};
my $local_package = $self->get_local_package($package_id);
if ( $local_package ) {
for my $package_agreement (
@{ $local_package->package_agreements->as_list } )
{
push @{ $object->{package_agreements} },
{
%{ $package_agreement->unblessed },
agreement => $package_agreement->agreement->unblessed,
};
}
}
}
if ( $embed_req eq 'resources' || $embed_req eq 'resources.package' ) {
push @embed_resources, $embed_req;
}

View File

@ -35,7 +35,8 @@ use Try::Tiny qw( catch try );
sub list {
my $c = shift->openapi->valid_input or return;
return try {
my $packages_set = Koha::ERM::EHoldings::Packages->new;
my $packages_set =
Koha::ERM::EHoldings::Packages->search( { 'me.external_id' => undef } );
my $packages = $c->objects->search($packages_set);
return $c->render( status => 200, openapi => $packages );
}
@ -89,6 +90,7 @@ sub add {
my $body = $c->validation->param('body');
my $package_agreements = delete $body->{package_agreements} // [];
delete $body->{external_id} unless $body->{external_id};
my $package = Koha::ERM::EHoldings::Package->new_from_api($body)->store;
$package->package_agreements($package_agreements);
@ -164,9 +166,12 @@ sub update {
my $body = $c->validation->param('body');
my $package_agreements = delete $body->{package_agreements} // [];
use Data::Printer colored => 1; warn p $package_agreements;
delete $body->{external_id} unless $body->{external_id};
$package->set_from_api($body)->store;
# FIXME If there is no package_agreements and external_id is set, we could delete the row
# ie. It's coming from EBSCO and we don't have local data linked to it
$package->package_agreements($package_agreements);
$c->res->headers->location($c->req->url->to_string . '/' . $package->package_id);

View File

@ -13,11 +13,21 @@ properties:
name:
description: name of the package
type: string
provider:
description: external id of the package
type:
- string
- "null"
external_id:
description: external id of the package
type:
- string
- "null"
koha_internal_id:
description: internal id of the package
type:
- integer
- "null"
package_type:
description: type of the package
type:

View File

@ -191,6 +191,7 @@ return {
`vendor_id` INT(11) DEFAULT NULL COMMENT 'foreign key to aqbooksellers',
`name` VARCHAR(255) NOT NULL COMMENT 'name of the package',
`external_id` VARCHAR(255) DEFAULT NULL COMMENT 'External key',
`provider` ENUM('ebsco') DEFAULT NULL COMMENT 'External provider',
`package_type` VARCHAR(80) DEFAULT NULL COMMENT 'type of the package',
`content_type` VARCHAR(80) DEFAULT NULL COMMENT 'type of the package',
`created_on` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'date of creation of the package',

View File

@ -2902,6 +2902,7 @@ CREATE TABLE `erm_eholdings_packages` (
`vendor_id` INT(11) DEFAULT NULL COMMENT 'foreign key to aqbooksellers',
`name` VARCHAR(255) NOT NULL COMMENT 'name of the package',
`external_id` VARCHAR(255) DEFAULT NULL COMMENT 'External key',
`provider` ENUM('ebsco') DEFAULT NULL COMMENT 'External provider',
`package_type` VARCHAR(80) DEFAULT NULL COMMENT 'type of the package',
`content_type` VARCHAR(80) DEFAULT NULL COMMENT 'type of the package',
`created_on` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'date of creation of the package',

View File

@ -1,7 +1,7 @@
<template>
<div v-if="!this.initialized">{{ $t("Loading") }}</div>
<div v-else-if="this.agreements" id="agreements_list">
<Toolbar />
<Toolbar v-if="before_route_entered" />
<table v-if="this.agreements.length" id="agreement_list"></table>
<div v-else-if="this.initialized" class="dialog message">
{{ $t("There are no agreements defined") }}
@ -36,11 +36,17 @@ export default {
return {
agreements: [],
initialized: false,
before_route_entered: false,
building_table: false,
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.getAgreements()
vm.before_route_entered = true // FIXME This is ugly, but we need to distinguish when it's used as main component or child component (from EHoldingsEBSCOPAckagesShow for instance)
if (!vm.building_table) {
vm.building_table = true
vm.getAgreements().then(() => vm.build_datatable())
}
})
},
methods: {
@ -58,193 +64,232 @@ export default {
delete_agreement: function (agreement_id) {
this.$router.push("/cgi-bin/koha/erm/agreements/delete/" + agreement_id)
},
select_agreement: function (agreement_id) {
this.$emit('select-agreement', agreement_id)
this.$emit('close')
},
build_datatable: function () {
let show_agreement = this.show_agreement
let edit_agreement = this.edit_agreement
let delete_agreement = this.delete_agreement
let select_agreement = this.select_agreement
let default_search = this.$route.query.q
let actions = this.before_route_entered ? 'edit_delete' : 'select'
window['vendors'] = this.vendors.map(e => {
e['_id'] = e['id']
e['_str'] = e['name']
return e
})
let vendors_map = this.vendors.reduce((map, e) => {
map[e.id] = e
return map
}, {})
window['av_agreement_statuses'] = this.av_agreement_statuses.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_statuses_map = this.av_agreement_statuses.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_closure_reasons'] = this.av_agreement_closure_reasons.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_closure_reasons_map = this.av_agreement_closure_reasons.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_renewal_priorities'] = this.av_agreement_renewal_priorities.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_renewal_priorities_map = this.av_agreement_renewal_priorities.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_is_perpetual'] = [{ _id: 0, _str: _('No') }, { _id: 1, _str: _("Yes") }]
const table = $('#agreement_list').kohaTable({
"ajax": {
"url": "/api/v1/erm/agreements",
},
"order": [[0, "asc"]],
autoWidth: false,
"search": { search: default_search },
"columnDefs": [{
"targets": [0, 2],
"render": function (data, type, row, meta) {
if (type == 'display') {
return escape_str(data)
}
return data
}
}],
"columns": [
{
"title": __("Name"),
"data": "me.agreement_id:me.name",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
// Rendering done in drawCallback
return ""
}
},
{
"title": __("Vendor"),
"data": "vendor_id",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.vendor_id != undefined ? escape_str(vendors_map[row.vendor_id].name) : ""
}
},
{
"title": __("Description"),
"data": "description",
"searchable": true,
"orderable": true
},
{
"title": __("Status"),
"data": "status",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return escape_str(av_agreement_statuses_map[row.status].lib)
}
},
{
"title": __("Closure reason"),
"data": "closure_reason",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(av_agreement_closure_reasons_map[row.closure_reason].lib) : ""
}
},
{
"title": __("Is perpetual"),
"data": "is_perpetual",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return escape_str(row.is_perpetual ? _("Yes") : _("No"))
}
},
{
"title": __("Renewal priority"),
"data": "renewal_priority",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(av_agreement_renewal_priorities_map[row.renewal_priority].lib) : ""
}
},
{
"title": __("Actions"),
"data": function (row, type, val, meta) {
return '<div class="actions"></div>'
},
"className": "actions noExport",
"searchable": false,
"orderable": false
}
],
drawCallback: function (settings) {
var api = new $.fn.dataTable.Api(settings)
if (actions == 'edit_delete') {
$.each($(this).find("td .actions"), function (index, e) {
let agreement_id = api.row(index).data().agreement_id
let editButton = createVNode("a", {
class: "btn btn-default btn-xs", role: "button", onClick: () => {
edit_agreement(agreement_id)
}
},
[createVNode("i", { class: "fa fa-pencil", 'aria-hidden': "true" }), __("Edit")])
let deleteButton = createVNode("a", {
class: "btn btn-default btn-xs", role: "button", onClick: () => {
delete_agreement(agreement_id)
}
},
[createVNode("i", { class: "fa fa-trash", 'aria-hidden': "true" }), __("Delete")])
let n = createVNode('span', {}, [editButton, " ", deleteButton])
render(n, e)
})
} else {
$.each($(this).find("td .actions"), function (index, e) {
let agreement_id = api.row(index).data().agreement_id
let selectButton = createVNode("a", {
class: "btn btn-default btn-xs", role: "button", onClick: () => {
select_agreement(agreement_id)
}
},
[createVNode("i", { class: "fa fa-check", 'aria-hidden': "true" }), __("Select")])
let n = createVNode('span', {}, [selectButton])
render(n, e)
})
}
$.each($(this).find("tbody tr td:first-child"), function (index, e) {
let row = api.row(index).data()
if (!row) return // Happen if the table is empty
let n = createVNode("a", {
role: "button",
onClick: () => {
show_agreement(row.agreement_id)
}
},
`${row.name} (#${row.agreement_id})`
)
render(n, e)
})
},
preDrawCallback: function (settings) {
var table_id = settings.nTable.id
$("#" + table_id).find("thead th").eq(1).attr('data-filter', 'vendors')
$("#" + table_id).find("thead th").eq(3).attr('data-filter', 'av_agreement_statuses')
$("#" + table_id).find("thead th").eq(4).attr('data-filter', 'av_agreement_closure_reasons')
$("#" + table_id).find("thead th").eq(5).attr('data-filter', 'av_agreement_is_perpetual')
$("#" + table_id).find("thead th").eq(6).attr('data-filter', 'av_agreement_renewal_priorities')
}
}, agreement_table_settings, 1)
},
destroy_table: function () {
$('#agreement_list')
.DataTable()
.destroy(true)
},
},
updated() {
let show_agreement = this.show_agreement
let edit_agreement = this.edit_agreement
let delete_agreement = this.delete_agreement
let default_search = this.$route.query.q
window['vendors'] = this.vendors.map(e => {
e['_id'] = e['id']
e['_str'] = e['name']
return e
})
let vendors_map = this.vendors.reduce((map, e) => {
map[e.id] = e
return map
}, {})
window['av_agreement_statuses'] = this.av_agreement_statuses.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_statuses_map = this.av_agreement_statuses.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_closure_reasons'] = this.av_agreement_closure_reasons.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_closure_reasons_map = this.av_agreement_closure_reasons.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_renewal_priorities'] = this.av_agreement_renewal_priorities.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
let av_agreement_renewal_priorities_map = this.av_agreement_renewal_priorities.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
window['av_agreement_is_perpetual'] = [{ _id: 0, _str: _('No') }, { _id: 1, _str: _("Yes") }]
const table = $('#agreement_list').kohaTable({
"ajax": {
"url": "/api/v1/erm/agreements",
},
"order": [[0, "asc"]],
"search": { search: default_search },
"columnDefs": [{
"targets": [0, 2],
"render": function (data, type, row, meta) {
if (type == 'display') {
return escape_str(data)
}
return data
}
}],
"columns": [
{
"title": __("Name"),
"data": "me.agreement_id:me.name",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
// Rendering done in drawCallback
return ""
}
},
{
"title": __("Vendor"),
"data": "vendor_id",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.vendor_id != undefined ? escape_str(vendors_map[row.vendor_id].name) : ""
}
},
{
"title": __("Description"),
"data": "description",
"searchable": true,
"orderable": true
},
{
"title": __("Status"),
"data": "status",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return escape_str(av_agreement_statuses_map[row.status].lib)
}
},
{
"title": __("Closure reason"),
"data": "closure_reason",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(av_agreement_closure_reasons_map[row.closure_reason].lib) : ""
}
},
{
"title": __("Is perpetual"),
"data": "is_perpetual",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return escape_str(row.is_perpetual ? _("Yes") : _("No"))
}
},
{
"title": __("Renewal priority"),
"data": "renewal_priority",
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(av_agreement_renewal_priorities_map[row.renewal_priority].lib) : ""
}
},
{
"title": __("Actions"),
"data": function (row, type, val, meta) {
return '<div class="actions"></div>'
},
"className": "actions noExport",
"searchable": false,
"orderable": false
}
],
drawCallback: function (settings) {
var api = new $.fn.dataTable.Api(settings)
$.each($(this).find("td .actions"), function (index, e) {
let agreement_id = api.row(index).data().agreement_id
let editButton = createVNode("a", {
class: "btn btn-default btn-xs", role: "button", onClick: () => {
edit_agreement(agreement_id)
}
},
[createVNode("i", { class: "fa fa-pencil", 'aria-hidden': "true" }), __("Edit")])
let deleteButton = createVNode("a", {
class: "btn btn-default btn-xs", role: "button", onClick: () => {
delete_agreement(agreement_id)
}
},
[createVNode("i", { class: "fa fa-trash", 'aria-hidden': "true" }), __("Delete")])
let n = createVNode('span', {}, [editButton, " ", deleteButton])
render(n, e)
})
$.each($(this).find("tbody tr td:first-child"), function (index, e) {
let row = api.row(index).data()
if (!row) return // Happen if the table is empty
let n = createVNode("a", {
role: "button",
onClick: () => {
show_agreement(row.agreement_id)
}
},
`${row.name} (#${row.agreement_id})`
)
render(n, e)
})
},
preDrawCallback: function (settings) {
var table_id = settings.nTable.id
$("#" + table_id).find("thead th").eq(1).attr('data-filter', 'vendors')
$("#" + table_id).find("thead th").eq(3).attr('data-filter', 'av_agreement_statuses')
$("#" + table_id).find("thead th").eq(4).attr('data-filter', 'av_agreement_closure_reasons')
$("#" + table_id).find("thead th").eq(5).attr('data-filter', 'av_agreement_is_perpetual')
$("#" + table_id).find("thead th").eq(6).attr('data-filter', 'av_agreement_renewal_priorities')
}
}, agreement_table_settings, 1)
mounted() {
if (!this.building_table) {
this.building_table = true
this.getAgreements().then(() => this.build_datatable())
}
},
beforeUnmount() {
$('#agreement_list')
.DataTable()
.destroy(true)
// This delays the closing of the modal, do we really need it?
//this.destroy_table()
},
components: { Toolbar },
name: "AgreementsList",
emits: ["select-agreement", "close"],
}
</script>
<style scoped>
#agreement_list {
display: table;
}
</style>

View File

@ -1,84 +1,121 @@
<template>
<fieldset class="rows" id="package_agreements">
<legend>{{ $t("Agreements") }}</legend>
<fieldset
class="rows"
v-for="(package_agreement, counter) in package_agreements"
<transition name="modal">
<div v-if="showModal" class="modal">
<AgreementsList @select-agreement="addAgreement" />
<input
type="button"
@click="showModal = false"
:value="$t('Close')"
/>
</div>
</transition>
<div id="package_agreements">
<div
v-for="(
package_agreement, counter
) in erm_package.package_agreements"
v-bind:key="counter"
>
<legend>
{{ $t("Agreement .counter", { counter: counter + 1 }) }}
<a href="#" @click.prevent="deleteAgreement(counter)"
><i class="fa fa-trash"></i>
{{ $t("Remove this agreement") }}</a
>
</legend>
<ol>
<li>
<label :for="`agreement_id_${counter}`"
>{{ $t("Agreement") }}:
</label>
<select
v-model="package_agreement.agreement_id"
:id="`agreement_id_${counter}`"
required
>
<option value=""></option>
<option
v-for="agreement in agreements"
:key="agreement.agreement_id"
:value="agreement.agreement_id"
:selected="
agreement.agreement_id ==
package_agreement.agreement_id
? true
: false
"
>
{{ agreement.name }}
</option>
</select>
<span class="required">{{ $t("Required") }}</span>
</li>
</ol>
</fieldset>
<a
v-if="agreements.length"
class="btn btn-default"
@click="addAgreement"
<router-link
:to="`/cgi-bin/koha/erm/agreements/${package_agreement.agreement.agreement_id}`"
>{{ package_agreement.agreement.name }}</router-link
>
&nbsp;
<a
href="#"
@click.prevent="deleteAgreement(counter)"
:title="$t('Remove this agreement')"
><i class="fa fa-trash"></i
></a>
</div>
<a class="btn btn-default btn-xs" @click="showModal = true"
><font-awesome-icon icon="plus" /> {{ $t("Add new agreement") }}</a
>
<span v-else>{{ $t("There are no agreements created yet") }}</span>
</fieldset>
</div>
</template>
<script>
import { fetchAgreements } from "../../fetch"
import AgreementsList from "./AgreementsList.vue"
import { createPackage, editPackage } from "../../fetch"
export default {
data() {
return {
agreements: [],
}
return { showModal: false, }
},
beforeCreate() {
fetchAgreements().then((agreements) => {
this.agreements = agreements
})
},
methods: {
addAgreement() {
this.package_agreements.push({
agreement_id: null,
})
serializeAgreement() {
let erm_package = JSON.parse(JSON.stringify(this.erm_package)) // copy
delete erm_package.vendor_id // This is the EBSCO's vendor_id
// Remove remote data, we don't need to store them (don't we?)
// Keep the name, it's mandatory by the REST API specs
delete erm_package.package_type
delete erm_package.content_type
erm_package.external_id = erm_package.package_id
delete erm_package.package_id
erm_package.provider = 'ebsco'
erm_package.package_id = erm_package.koha_internal_id
delete erm_package.koha_internal_id
return erm_package
},
addAgreement(agreement_id) {
this.showModal = false
let erm_package = this.serializeAgreement()
// Only add if it does not exist
// TODO Add a warning?
if (!erm_package.package_agreements.find((a) => a.agreement_id == agreement_id)) {
erm_package.package_agreements.push({ agreement_id })
if (this.erm_package.koha_internal_id) {
editPackage(erm_package).then(() => {
this.$emit('refresh-agreements')
})
} else {
createPackage(erm_package).then(() => {
this.$emit('refresh-agreements')
})
}
}
},
deleteAgreement(counter) {
this.package_agreements.splice(counter, 1)
let erm_package = this.serializeAgreement()
erm_package.package_agreements.splice(counter, 1)
editPackage(erm_package).then(() => {
this.$emit('refresh-agreements')
})
},
},
props: {
package_agreements: Array,
erm_package: Object,
},
components: {
AgreementsList,
},
emits: ['refresh-agreements'],
name: 'EHoldingsEBSCOPackageAgreements',
}
</script>
<style scoped>
#package_agreements {
padding-left: 26rem;
}
.modal {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 80%;
height: 80%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity 0.3s ease;
margin: auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
</style>

View File

@ -51,6 +51,14 @@
<span>{{ format_date(erm_package.created_on) }}</span>
</li>
<li>
<label>Agreements</label>
<EHoldingsPackageAgreements
:erm_package="erm_package"
@refresh-agreements="refreshAgreements"
/>
</li>
<li>
<label
>Titles ({{ erm_package.resources_count }})</label
@ -78,6 +86,7 @@
</template>
<script>
import EHoldingsPackageAgreements from "./EHoldingsEBSCOPackageAgreements.vue"
import EHoldingsPackageTitlesList from "./EHoldingsEBSCOPackageTitlesList.vue"
import { useAVStore } from "../../stores/authorised_values"
import { fetchEBSCOPackage } from "../../fetch"
@ -101,10 +110,12 @@ export default {
vendor_id: null,
name: '',
external_id: '',
provider: '',
package_type: '',
content_type: '',
created_on: null,
resources: null,
package_agreements: [],
},
initialized: false,
}
@ -123,8 +134,14 @@ export default {
this.erm_package = erm_package
this.initialized = true
},
refreshAgreements() {
// FIXME We could GET /erm/eholdings/packages/$package_id/agreements instead
this.initialized = false
this.getPackage(this.erm_package.package_id)
},
},
components: {
EHoldingsPackageAgreements,
EHoldingsPackageTitlesList,
},
name: "EHoldingsEBSCOPackagesShow",
@ -134,4 +151,4 @@ export default {
fieldset.rows label {
width: 25rem;
}
</style>
</style>

View File

@ -115,7 +115,7 @@ import EHoldingsPackageAgreements from "./EHoldingsLocalPackageAgreements.vue"
import { useVendorStore } from "../../stores/vendors"
import { useAVStore } from "../../stores/authorised_values"
import { setMessage, setError } from "../../messages"
import { fetchLocalPackage } from '../../fetch'
import { fetchLocalPackage, createPackage, editPackage } from '../../fetch'
import { storeToRefs } from "pinia"
export default {
@ -138,10 +138,13 @@ export default {
return {
erm_package: {
package_id: null,
vendor_id: null,
name: '',
external_id: '',
package_type: '',
content_type: '',
created_on: null,
resources: null,
package_agreements: [],
},
initialized: false,
@ -166,42 +169,26 @@ export default {
e.preventDefault()
let erm_package = JSON.parse(JSON.stringify(this.erm_package)) // copy
let apiUrl = '/api/v1/erm/eholdings/local/packages'
let method = 'POST'
if (erm_package.package_id) {
method = 'PUT'
apiUrl += '/' + erm_package.package_id
}
delete erm_package.package_id
delete erm_package.resources
delete erm_package.vendor
delete erm_package.resources_count
erm_package.package_agreements = erm_package.package_agreements.map(({ package_id, agreement, ...keepAttrs }) => keepAttrs)
const options = {
method: method,
body: JSON.stringify(erm_package),
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
}
fetch(apiUrl, options)
.then(response => {
editPackage(erm_package).then(response => {
if (response.status == 200) {
this.$router.push("/cgi-bin/koha/erm/eholdings/local/packages")
setMessage(this.$t("Package updated"))
} else if (response.status == 201) {
} else {
setError(response.message || response.statusText)
}
})
} else {
createPackage(erm_package).then(response => {
if (response.status == 201) {
this.$router.push("/cgi-bin/koha/erm/eholdings/local/packages")
setMessage(this.$t("Package created"))
} else {
setError(response.message || response.statusText)
}
}, (error) => {
setError(error)
}).catch(e => { console.log(e) })
})
}
},
},
components: {

View File

@ -35,17 +35,6 @@
>
</span>
</li>
<li v-if="erm_package.external_id">
<label>{{ $t("External ID") }}:</label>
<span>
<!-- FIXME Create a syspref to store the URL -->
<a
:href="`https://ptfs-europe-demo.folio.ebsco.com/eholdings/packages/${erm_package.vendor.external_id}-${erm_package.external_id}`"
>
{{ erm_package.external_id }}
</a>
</span>
</li>
<li>
<label>{{ $t("Package type") }}:</label>
<span>{{

View File

@ -1,107 +0,0 @@
<template>
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
<AgreementsList />
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" @click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</template>
<script>
import AgreementsList from "./AgreementsList.vue"
export default {
setup() {
},
components:{
AgreementsList
}
}
</script>
export default
<style scoped>
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity 0.3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter-from, .modal-leave-to {
opacity: 0;
}
.modal-enter-active .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>

View File

@ -104,6 +104,53 @@ export const fetchVendors = async function () {
return vendors;
};
const _createEditPackage = async function (method, erm_package) {
let apiUrl = "/api/v1/erm/eholdings/local/packages";
if (method == "PUT") {
apiUrl += "/" + erm_package.package_id;
}
delete erm_package.package_id;
delete erm_package.resources;
delete erm_package.vendor;
delete erm_package.resources_count;
delete erm_package.is_selected;
erm_package.package_agreements = erm_package.package_agreements.map(
({ package_id, agreement, ...keepAttrs }) => keepAttrs
);
const options = {
method: method,
body: JSON.stringify(erm_package),
headers: {
"Content-Type": "application/json;charset=utf-8",
},
};
let r;
await fetch(apiUrl, options)
.then(
(response) => {
r = response;
},
(error) => {
setError(error);
}
)
.catch((e) => {
console.log(e);
});
return r;
};
export const createPackage = function (erm_package) {
return _createEditPackage("POST", erm_package);
};
export const editPackage = function (erm_package) {
return _createEditPackage("PUT", erm_package);
};
const _fetchPackage = async function (apiUrl, package_id) {
if (!package_id) return;
let erm_package;

View File

@ -175,7 +175,7 @@ export const routes = [
breadcrumb: () =>
build_breadcrumb(
breadcrumb_paths.agreements,
"Edit agreement" // $t("Edit agreemetn")
"Edit agreement" // $t("Edit agreement")
),
},
},