use Koha::ERM::Agreement::Periods;
use Koha::ERM::Agreement::UserRoles;
+use Koha::ERM::Agreement::Licenses;
=head1 NAME
return Koha::ERM::Agreement::UserRoles->_new_from_dbic($user_roles_rs);
}
+=head3 agreement_licenses
+
+Returns the agreement_licenses for this agreement
+
+=cut
+
+sub agreement_licenses {
+ my ( $self, $agreement_licenses ) = @_;
+
+ if ( $agreement_licenses ) {
+ my $schema = $self->_result->result_source->schema;
+ $schema->txn_do(
+ sub {
+ $self->agreement_licenses->delete;
+
+ for my $agreement_license (@$agreement_licenses) {
+ $self->_result->add_to_erm_agreement_licenses($agreement_license);
+ }
+ }
+ );
+ }
+ my $agreement_licenses_rs = $self->_result->erm_agreement_licenses;
+ return Koha::ERM::Agreement::Licenses->_new_from_dbic($agreement_licenses_rs);
+}
+
=head2 Internal methods
=head3 _type
use Koha::Database;
-use Koha::Agreements;
-use Koha::Licenses;
+use Koha::ERM::Agreements;
+use Koha::ERM::Licenses;
use base qw(Koha::Object);
my $periods = delete $body->{periods} // [];
my $user_roles = delete $body->{user_roles} // [];
+ my $agreement_licenses = delete $body->{agreement_licenses} // [];
my $agreement = Koha::ERM::Agreement->new_from_api($body)->store;
$agreement->periods($periods);
$agreement->user_roles($user_roles);
+ $agreement->agreement_licenses($agreement_licenses);
$c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id);
return $c->render(
my $periods = delete $body->{periods} // [];
my $user_roles = delete $body->{user_roles} // [];
+ my $agreement_licenses = delete $body->{agreement_licenses} // [];
$agreement->set_from_api($body)->store;
$agreement->periods($periods);
$agreement->user_roles($user_roles);
+ $agreement->agreement_licenses($agreement_licenses);
$c->res->headers->location($c->req->url->to_string . '/' . $agreement->agreement_id);
return $c->render(
description: role for users
items:
$ref: erm_agreement_user_role.yaml
+ agreement_licenses:
+ type: array
+ description: agreement licenses
+ items:
+ $ref: erm_agreement_license.yaml
+
additionalProperties: false
required:
- agreement_id
--- /dev/null
+---
+type: object
+properties:
+ agreement_license_id:
+ type: integer
+ description: Internal agreement license identifier
+ agreement_id:
+ type: integer
+ description: Internal agreement identifier
+ license_id:
+ type: integer
+ description: Internal license identifier
+ status:
+ type: string
+ physical_location:
+ type:
+ - string
+ - "null"
+ notes:
+ type:
+ - string
+ - "null"
+ uri:
+ type:
+ - string
+ - "null"
+additionalProperties: false
+required:
+ - license_id
+ - status
additionalProperties: false
required:
- license_id
- - agreement_id
- periods
- user_roles
- user_roles.patron
+ - agreement_licenses
+ - agreement_licenses.license
put:
x-mojo-to: ERM::Agreements#update
operationId: updateErmAgreements
x-koha-embed:
- periods
- user_roles
+ - agreement_licenses
delete:
x-mojo-to: ERM::Agreements#delete
operationId: deleteErmAgreements
licenses_table_url += 'q='+ encodeURIComponent(JSON.stringify(license_name_filter));
[% END %]
+ const agreement_license_statuses = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_LICENSE_STATUS')) | $raw %];
+ const agreement_license_location = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_LICENSE_LOCATION')) | $raw %];
+
</script>
[% Asset.js("js/vue/dist/main.js") | $raw %]
--- /dev/null
+<template>
+ <fieldset class="rows" id="agreement_licenses">
+ <legend>Licenses</legend>
+ <fieldset
+ class="rows"
+ v-for="(agreement_license, counter) in agreement_licenses"
+ v-bind:key="counter"
+ >
+ <legend>
+ Agreement license {{ counter + 1 }}
+ <a href="#" @click.prevent="deleteLicense(counter)"
+ ><i class="fa fa-trash"></i> Remove this license</a
+ >
+ </legend>
+ <ol>
+ <li>
+ <label :for="`license_id_${counter}`">License: </label>
+ <select
+ :id="`license_id_${counter}`"
+ v-model="agreement_license.license_id"
+ required
+ >
+ <option value=""></option>
+ <option
+ v-for="license in licenses"
+ :key="license.license_id"
+ :value="license.license_id"
+ :selected="
+ license.license_id ==
+ agreement_license.license_id
+ ? true
+ : false
+ "
+ >
+ {{ license.name }}
+ </option>
+ </select>
+ <span class="required">Required</span>
+ </li>
+ <li>
+ <label :for="`license_status_${counter}`">Status: </label>
+ <select v-model="agreement_license.status" required>
+ <option value=""></option>
+ <option
+ v-for="r in av_agreement_license_statuses"
+ :key="r.authorised_values"
+ :value="r.authorised_value"
+ :selected="
+ r.authorised_value == agreement_license.status
+ ? true
+ : false
+ "
+ >
+ {{ r.lib }}
+ </option>
+ </select>
+ <span class="required">Required</span>
+ </li>
+ <li>
+ <label :for="`license_location_${counter}`"
+ >Physical location:
+ </label>
+ <select v-model="agreement_license.physical_location">
+ <option value=""></option>
+ <option
+ v-for="r in av_agreement_license_location"
+ :key="r.authorised_values"
+ :value="r.authorised_value"
+ :selected="
+ r.authorised_value ==
+ agreement_license.physical_location
+ ? true
+ : false
+ "
+ >
+ {{ r.lib }}
+ </option>
+ </select>
+ </li>
+ <li>
+ <label :for="`license_notes_${counter}`">Notes:</label>
+ <input
+ :id="`license_notes_${counter}`"
+ v-model="agreement_license.notes"
+ placeholder="Notes"
+ />
+ </li>
+ <li>
+ <label :for="`license_uri_${counter}`">URI:</label>
+ <input
+ :id="`license_uri_${counter}`"
+ v-model="agreement_license.uri"
+ placeholder="URI"
+ />
+ </li>
+ </ol>
+ </fieldset>
+ <a class="btn btn-default" @click="addLicense"
+ ><font-awesome-icon icon="plus" /> Add new license</a
+ >
+ </fieldset>
+</template>
+
+<script>
+export default {
+ name: 'AgreementLicenses',
+ data() {
+ return {
+ licenses: [],
+ }
+ },
+ props: {
+ av_agreement_license_statuses: Array,
+ av_agreement_license_location: Array,
+ agreement_licenses: Array,
+ },
+ beforeCreate() {
+ // FIXME it's not called on setup, but setup() does not have 'this'.
+ const apiUrl = "/api/v1/erm/licenses"
+
+ fetch(apiUrl)
+ .then((res) => res.json())
+ .then(
+ (result) => {
+ this.licenses = result
+ },
+ (error) => {
+ this.$emit("set-error", error)
+ }
+ )
+ },
+ methods: {
+ addLicense() {
+ this.agreement_licenses.push({
+ license_id: null,
+ status: null,
+ physical_location: null,
+ notes: '',
+ uri: '',
+ })
+ },
+ deleteLicense(counter) {
+ this.agreement_licenses.splice(counter, 1)
+ },
+ },
+}
+</script>
<select v-model="user_role.role" required>
<option value=""></option>
<option
- v-for="r in av_user_roles"
+ v-for="r in av_agreement_user_roles"
:key="r.authorised_values"
:value="r.authorised_value"
:selected="
export default {
name: 'AgreementUserRoles',
props: {
- av_user_roles: Array,
+ av_agreement_user_roles: Array,
user_roles: Array,
},
beforeUpdate() {
<List
v-if="op == 'list'"
:vendors="vendors"
- :av_statuses="statuses"
- :av_closure_reasons="closure_reasons"
- :av_renewal_priorities="renewal_priorities"
+ :av_agreement_statuses="agreement_statuses"
+ :av_agreement_closure_reasons="agreement_closure_reasons"
+ :av_agreement_renewal_priorities="agreement_renewal_priorities"
@set-current-agreement-id="setCurrentAgreementID"
@switch-view="switchView"
@set-error="setError"
v-if="op == 'show'"
:agreement_id="agreement_id"
:vendors="vendors"
- :av_statuses="statuses"
- :av_closure_reasons="closure_reasons"
- :av_renewal_priorities="renewal_priorities"
- :av_user_roles="user_roles"
+ :av_agreement_statuses="agreement_statuses"
+ :av_agreement_closure_reasons="agreement_closure_reasons"
+ :av_agreement_renewal_priorities="agreement_renewal_priorities"
+ :av_agreement_user_roles="agreement_user_roles"
+ :av_agreement_license_statuses="agreement_license_statuses"
+ :av_agreement_license_location="agreement_license_location"
@switch-view="switchView"
@set-error="setError"
/>
v-if="op == 'add-form'"
:agreement_id="agreement_id"
:vendors="vendors"
- :av_statuses="statuses"
- :av_closure_reasons="closure_reasons"
- :av_renewal_priorities="renewal_priorities"
- :av_user_roles="user_roles"
+ :av_agreement_statuses="agreement_statuses"
+ :av_agreement_closure_reasons="agreement_closure_reasons"
+ :av_agreement_renewal_priorities="agreement_renewal_priorities"
+ :av_agreement_user_roles="agreement_user_roles"
+ :av_agreement_license_statuses="agreement_license_statuses"
+ :av_agreement_license_location="agreement_license_location"
@agreement-created="agreementCreated"
@agreement-updated="agreementUpdated"
@switch-view="switchView"
message: null,
error: null,
vendors: [],
- statuses: agreement_statuses,
- closure_reasons: agreement_closure_reasons,
- renewal_priorities: agreement_renewal_priorities,
- user_roles: agreement_user_roles,
+ agreement_statuses,
+ agreement_closure_reasons,
+ agreement_renewal_priorities,
+ agreement_user_roles,
+ agreement_license_statuses,
+ agreement_license_location,
}
},
beforeCreate() {
>
<option value=""></option>
<option
- v-for="status in av_statuses"
+ v-for="status in av_agreement_statuses"
:key="status.authorised_values"
:value="status.authorised_value"
:selected="
>
<option value=""></option>
<option
- v-for="r in av_closure_reasons"
+ v-for="r in av_agreement_closure_reasons"
:key="r.authorised_values"
:value="r.authorised_value"
:selected="
<select v-model="agreement.renewal_priority">
<option value=""></option>
<option
- v-for="p in av_renewal_priorities"
+ v-for="p in av_agreement_renewal_priorities"
:key="p.authorised_values"
:value="p.authorised_value"
:selected="
<AgreementPeriods :periods="agreement.periods" />
<AgreementUserRoles
:user_roles="agreement.user_roles"
- :av_user_roles="av_user_roles"
+ :av_agreement_user_roles="av_agreement_user_roles"
+ />
+ <AgreementLicenses
+ :agreement_licenses="agreement.agreement_licenses"
+ :av_agreement_license_statuses="av_agreement_license_statuses"
+ :av_agreement_license_location="
+ av_agreement_license_location
+ "
/>
</ol>
</fieldset>
<fieldset class="action">
<input type="submit" value="Submit" />
- <a role="button" class="cancel" @click="$emit('switch-view', 'list')"
+ <a
+ role="button"
+ class="cancel"
+ @click="$emit('switch-view', 'list')"
>Cancel</a
>
</fieldset>
<script>
import AgreementPeriods from './AgreementPeriods.vue'
import AgreementUserRoles from './AgreementUserRoles.vue'
+import AgreementLicenses from './AgreementLicenses.vue'
export default {
data() {
license_info: '',
periods: [],
user_roles: [],
+ agreement_licenses: [],
}
}
},
fetch(apiUrl, {
headers: {
- 'x-koha-embed': 'periods,user_roles,user_roles.patron'
+ 'x-koha-embed': 'periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license'
}
})
.then(res => res.json())
agreement.user_roles = agreement.user_roles.map(({ patron, patron_str, ...keepAttrs }) => keepAttrs)
+ agreement.agreement_licenses = agreement.agreement_licenses.map(({ license, agreement_id, agreement_license_id, ...keepAttrs }) => keepAttrs)
+
const options = {
method: method,
body: JSON.stringify(agreement),
props: {
agreement_id: Number,
vendors: Array,
- av_statuses: Array,
- av_closure_reasons: Array,
- av_renewal_priorities: Array,
- av_user_roles: Array,
+ av_agreement_statuses: Array,
+ av_agreement_closure_reasons: Array,
+ av_agreement_renewal_priorities: Array,
+ av_agreement_user_roles: Array,
+ av_agreement_license_statuses: Array,
+ av_agreement_license_location: Array,
},
components: {
AgreementPeriods,
- AgreementUserRoles
+ AgreementUserRoles,
+ AgreementLicenses,
},
name: "AgreementsFormAdd",
}
let show_agreement = this.show_agreement
let edit_agreement = this.edit_agreement
let delete_agreement = this.delete_agreement
- window['agreements_av_vendors'] = this.vendors.map(e => {
+ window['vendors'] = this.vendors.map(e => {
e['_id'] = e['id']
e['_str'] = e['name']
return e
map[e.id] = e
return map
}, {})
- window['agreements_av_statuses'] = this.av_statuses.map(e => {
+ window['av_agreement_statuses'] = this.av_agreement_statuses.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
- let statuses_map = this.av_statuses.reduce((map, e) => {
+ let av_agreement_statuses_map = this.av_agreement_statuses.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
- window['agreements_av_closure_reasons'] = this.av_closure_reasons.map(e => {
+ window['av_agreement_closure_reasons'] = this.av_agreement_closure_reasons.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
- let closure_reasons_map = this.av_closure_reasons.reduce((map, e) => {
+ let av_agreement_closure_reasons_map = this.av_agreement_closure_reasons.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
- window['agreements_av_renewal_priorities'] = this.av_renewal_priorities.map(e => {
+ window['av_agreement_renewal_priorities'] = this.av_agreement_renewal_priorities.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
- let renewal_priorities_map = this.av_renewal_priorities.reduce((map, e) => {
+ let av_agreement_renewal_priorities_map = this.av_agreement_renewal_priorities.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
- window['agreements_av_is_perpetual'] = [{ _id: 0, _str: _('No') }, { _id: 1, _str: _("Yes") }]
+ window['av_agreement_is_perpetual'] = [{ _id: 0, _str: _('No') }, { _id: 1, _str: _("Yes") }]
$('#agreement_list').kohaTable({
"ajax": {
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
- return escape_str(statuses_map[row.status].lib)
+ return escape_str(av_agreement_statuses_map[row.status].lib)
}
},
{
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
- return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(closure_reasons_map[row.closure_reason].lib) : ""
+ return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(av_agreement_closure_reasons_map[row.closure_reason].lib) : ""
}
},
{
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
- return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(renewal_priorities_map[row.renewal_priority].lib) : ""
+ return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(av_agreement_renewal_priorities_map[row.renewal_priority].lib) : ""
}
},
{
render(n, e)
})
- $.each($(this).find("tr td:eq(0)"), function (index, 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: () => {
},
preDrawCallback: function (settings) {
var table_id = settings.nTable.id
- $("#" + table_id).find("thead th").eq(1).attr('data-filter', 'agreements_av_vendors')
- $("#" + table_id).find("thead th").eq(3).attr('data-filter', 'agreements_av_statuses')
- $("#" + table_id).find("thead th").eq(4).attr('data-filter', 'agreements_av_closure_reasons')
- $("#" + table_id).find("thead th").eq(5).attr('data-filter', 'agreements_av_is_perpetual')
- $("#" + table_id).find("thead th").eq(6).attr('data-filter', 'agreements_av_renewal_priorities')
+ $("#" + 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')
}
}, table_settings, 1)
},
props: {
vendors: Array,
- av_statuses: Array,
- av_closure_reasons: Array,
- av_renewal_priorities: Array,
+ av_agreement_statuses: Array,
+ av_agreement_closure_reasons: Array,
+ av_agreement_renewal_priorities: Array,
},
name: "AgreementsList",
}
<td>{{ patron_to_html(role.patron) }}</td>
<td>
{{
- av_user_roles.find(
+ av_agreement_user_roles.find(
(r) =>
r.authorised_value == role.role
).lib
props: {
agreement_id: Number,
vendors: Array,
- av_statuses: Array,
- av_closure_reasons: Array,
- av_renewal_priorities: Array,
- av_user_roles: Array,
+ av_agreement_statuses: Array,
+ av_agreement_closure_reasons: Array,
+ av_agreement_renewal_priorities: Array,
+ av_agreement_user_roles: Array,
},
components: {
AgreementPeriods,
<div class="dialog alert" v-if="error">{{ error }}</div>
<List
v-if="op == 'list'"
- :av_types="types"
- :av_statuses="statuses"
+ :av_license_types="license_types"
+ :av_license_statuses="license_statuses"
@set-current-license-id="setCurrentLicenseID"
@switch-view="switchView"
@set-error="setError"
<Show
v-if="op == 'show'"
:license_id="license_id"
- :av_types="types"
- :av_statuses="statuses"
+ :av_license_types="license_types"
+ :av_license_statuses="license_statuses"
@switch-view="switchView"
@set-error="setError"
/>
<AddForm
v-if="op == 'add-form'"
:license_id="license_id"
- :av_types="types"
- :av_statuses="statuses"
+ :av_license_types="license_types"
+ :av_license_statuses="license_statuses"
@license-created="licenseCreated"
@license-updated="licenseUpdated"
@switch-view="switchView"
op: "list",
message: null,
error: null,
- types: license_types,
- statuses: license_statuses,
+ license_types,
+ license_statuses,
}
},
methods: {
>
<option value=""></option>
<option
- v-for="type in av_types"
+ v-for="type in av_license_types"
:key="type.authorised_values"
:value="type.authorised_value"
:selected="
>
<option value=""></option>
<option
- v-for="status in av_statuses"
+ v-for="status in av_license_statuses"
:key="status.authorised_values"
:value="status.authorised_value"
:selected="
emits: ['license-created', 'license-updated', 'set-error', 'switch-view'],
props: {
license_id: Number,
- av_types: Array,
- av_statuses: Array,
+ av_license_types: Array,
+ av_license_statuses: Array,
},
components: {
flatPickr
let show_license = this.show_license
let edit_license = this.edit_license
let delete_license = this.delete_license
- window['licenses_av_types'] = this.av_types.map(e => {
+ window['av_license_types'] = this.av_license_types.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
- let types_map = this.av_types.reduce((map, e) => {
+ let av_license_types_map = this.av_license_types.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
- window['licenses_av_statuses'] = this.av_statuses.map(e => {
+ window['av_license_statuses'] = this.av_license_statuses.map(e => {
e['_id'] = e['authorised_value']
e['_str'] = e['lib']
return e
})
- let statuses_map = this.av_statuses.reduce((map, e) => {
+ let av_license_statuses_map = this.av_license_statuses.reduce((map, e) => {
map[e.authorised_value] = e
return map
}, {})
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
- return escape_str(types_map[row.type].lib)
+ return escape_str(av_license_types_map[row.type].lib)
}
},
{
"searchable": true,
"orderable": true,
"render": function (data, type, row, meta) {
- return escape_str(statuses_map[row.status].lib)
+ return escape_str(av_license_statuses_map[row.status].lib)
}
},
{
},
preDrawCallback: function (settings) {
var table_id = settings.nTable.id
- $("#" + table_id).find("thead th").eq(2).attr('data-filter', 'licenses_av_types')
- $("#" + table_id).find("thead th").eq(3).attr('data-filter', 'licenses_av_statuses')
+ $("#" + table_id).find("thead th").eq(2).attr('data-filter', 'av_license_types')
+ $("#" + table_id).find("thead th").eq(3).attr('data-filter', 'av_license_statuses')
}
}, table_settings, 1)
},
},
props: {
- av_types: Array,
- av_statuses: Array,
+ av_license_types: Array,
+ av_license_statuses: Array,
},
name: "LicensesList",
}
<li>
<label>Type: </label>
<span>{{
- get_lib_from_av(av_types, license.type)
+ get_lib_from_av(av_license_types, license.type)
}}</span>
</li>
<li>
<label>Status: </label>
<span>{{
- get_lib_from_av(av_statuses, license.status)
+ get_lib_from_av(av_license_statuses, license.status)
}}</span>
</li>
emits: ['set-error', 'switch-view'],
props: {
license_id: Number,
- av_types: Array,
- av_statuses: Array,
+ av_license_types: Array,
+ av_license_statuses: Array,
},
components: {
},