Bug 37762: VueJS ILL Module
Signed-off-by: Jason Robb <jrobb@sekls.org> Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
b307692fb1
commit
6dab32ee02
|
|
@ -24,6 +24,8 @@ RewriteRule ^(.*)_[0-9]{2}\.[0-9]{7}\.(js|css)$ $1.$2 [L]
|
|||
|
||||
RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT]
|
||||
RewriteRule ^/cgi-bin/koha/sip2/.*$ /cgi-bin/koha/sip2/sip2.pl [PT]
|
||||
RewriteCond %{REQUEST_URI} !ill-requests\.pl$
|
||||
RewriteRule ^/cgi-bin/koha/ill/.*$ /cgi-bin/koha/ill/ill.pl [PT]
|
||||
RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$
|
||||
RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT]
|
||||
RewriteRule ^/cgi-bin/koha/admin/record_sources(.*)?$ /cgi-bin/koha/admin/record_sources.pl$1 [PT]
|
||||
|
|
|
|||
|
|
@ -236,6 +236,8 @@
|
|||
|
||||
RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT]
|
||||
RewriteRule ^/cgi-bin/koha/sip2/.*$ /cgi-bin/koha/sip2/sip2.pl [PT]
|
||||
RewriteCond %{REQUEST_URI} !ill-requests\.pl$
|
||||
RewriteRule ^/cgi-bin/koha/ill/.*$ /cgi-bin/koha/ill/ill.pl [PT]
|
||||
RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$
|
||||
RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT]
|
||||
RewriteRule ^/cgi-bin/koha/admin/record_sources(.*)?$ /cgi-bin/koha/admin/record_sources.pl$1 [PT]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# 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 <https://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use CGI qw ( -utf8 );
|
||||
use C4::Context;
|
||||
use C4::Auth qw( get_template_and_user );
|
||||
use C4::Output qw( output_html_with_http_headers );
|
||||
|
||||
my $input = CGI->new;
|
||||
|
||||
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
||||
{
|
||||
template_name => "ill/ill.tt",
|
||||
query => $input,
|
||||
type => "intranet",
|
||||
flagsrequired => { ill => '*' },
|
||||
}
|
||||
);
|
||||
|
||||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
[% END %]
|
||||
<li><a class="dropdown-item" href="/cgi-bin/koha/authorities/authorities-home.pl">Authorities</a></li>
|
||||
[% IF Koha.Preference('ILLModule') && CAN_user_ill %]
|
||||
<li><a class="dropdown-item" href="/cgi-bin/koha/ill/ill-requests.pl">ILL requests</a></li>
|
||||
<li><a class="dropdown-item" href="/cgi-bin/koha/ill/ill.pl">Interlibrary loans</a></li>
|
||||
[% END %]
|
||||
[% IF ( CAN_user_serials ) %]
|
||||
<li><a class="dropdown-item" href="/cgi-bin/koha/serials/serials-home.pl">Serials</a></li>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
|
||||
[% WRAPPER 'sub-header.inc' %]
|
||||
[% WRAPPER breadcrumbs %]
|
||||
[% WRAPPER breadcrumb_item %]
|
||||
<a href="/cgi-bin/koha/ill/ill.pl">Interlibrary loans</a>
|
||||
[% END %]
|
||||
[% WRAPPER breadcrumb_item bc_active = (op == 'illlist' || op == 'batch_list' ? 1 : 0) %]
|
||||
[% IF op == 'batch_list' %]
|
||||
<a href="/cgi-bin/koha/ill/ill-requests.pl">ILL batch requests</a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
[% USE raw %]
|
||||
[% USE To %]
|
||||
[% USE Asset %]
|
||||
[% USE KohaDates %]
|
||||
[% USE TablesSettings %]
|
||||
[% PROCESS 'i18n.inc' %]
|
||||
[% SET footerjs = 1 %]
|
||||
[% PROCESS 'patron-search.inc' %]
|
||||
[% INCLUDE 'doc-head-open.inc' %]
|
||||
<title
|
||||
>[% FILTER collapse %]
|
||||
[% t("Interlibrary loans") | html %]
|
||||
› [% t("Koha") | html %]
|
||||
[% END %]</title
|
||||
>
|
||||
[% INCLUDE 'doc-head-close.inc' %]
|
||||
</head>
|
||||
|
||||
<body id="ill_module" class="ill">
|
||||
[% WRAPPER 'header.inc' %]
|
||||
[% INCLUDE 'cat-search.inc' %]
|
||||
[% END %]
|
||||
|
||||
<div id="ill"></div>
|
||||
|
||||
[% MACRO jsinclude BLOCK %]
|
||||
[% INCLUDE 'calendar.inc' %]
|
||||
[% INCLUDE 'datatables.inc' %]
|
||||
[% INCLUDE 'js-date-format.inc' %]
|
||||
<script nonce="[% Koha.CSPNonce | $raw %]">
|
||||
const supplying_ill_table_settings = [% TablesSettings.GetTableSettings( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) | $raw %];
|
||||
</script>
|
||||
[% Asset.js("js/vue/dist/ill.js") | $raw %]
|
||||
[% END %]
|
||||
[% INCLUDE 'intranet-bottom.inc' %]
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
</li>
|
||||
[% IF Koha.Preference('ILLModule') && CAN_user_ill %]
|
||||
<li>
|
||||
<a class="icon_general icon_ill" href="/cgi-bin/koha/ill/ill-requests.pl"><i class="fa fa-fw fa-retweet"></i>ILL requests</a>
|
||||
<a class="icon_general icon_ill" href="/cgi-bin/koha/ill/ill.pl"><i class="fa fa-fw fa-retweet"></i>Interlibrary loans</a>
|
||||
</li>
|
||||
[% END %]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
export class ILLAPIClient {
|
||||
constructor(HttpClient) {
|
||||
this.httpClient = new HttpClient({
|
||||
baseURL: "/api/v1/ill/",
|
||||
});
|
||||
}
|
||||
|
||||
get config() {
|
||||
return {
|
||||
get: () => {
|
||||
ILLModule: 1;
|
||||
}, // TODO: Fetch from API
|
||||
};
|
||||
}
|
||||
|
||||
get supplying() {
|
||||
return {
|
||||
get: id =>
|
||||
this.httpClient.get({
|
||||
endpoint: "iso18626_requests/" + id,
|
||||
headers: {
|
||||
"x-koha-embed": "requesting_agency,messages,hold",
|
||||
},
|
||||
}),
|
||||
getAll: (query, params) =>
|
||||
this.httpClient.getAll({
|
||||
endpoint: "iso18626_requests",
|
||||
query,
|
||||
params,
|
||||
}),
|
||||
patch: (iso18626_request, id) =>
|
||||
this.httpClient.patch({
|
||||
endpoint: "iso18626_requests/" + id,
|
||||
body: iso18626_request,
|
||||
}),
|
||||
count: (query = {}) =>
|
||||
this.httpClient.count({
|
||||
endpoint:
|
||||
"iso18626_requests?" +
|
||||
new URLSearchParams({
|
||||
_page: 1,
|
||||
_per_page: 20,
|
||||
...(query && { q: JSON.stringify(query) }),
|
||||
}),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
get requesting_agencies() {
|
||||
return {
|
||||
get: id =>
|
||||
this.httpClient.get({
|
||||
endpoint: "iso18626_requesting_agencies/" + id,
|
||||
headers: {
|
||||
"x-koha-embed": "ill_partner",
|
||||
},
|
||||
}),
|
||||
getAll: (query, params) =>
|
||||
this.httpClient.getAll({
|
||||
endpoint: "iso18626_requesting_agencies",
|
||||
query,
|
||||
params,
|
||||
}),
|
||||
delete: id =>
|
||||
this.httpClient.delete({
|
||||
endpoint: "iso18626_requesting_agencies/" + id,
|
||||
}),
|
||||
create: iso18626_requesting_agency =>
|
||||
this.httpClient.post({
|
||||
endpoint: "iso18626_requesting_agencies",
|
||||
body: iso18626_requesting_agency,
|
||||
}),
|
||||
update: (iso18626_requesting_agency, id) =>
|
||||
this.httpClient.put({
|
||||
endpoint: "iso18626_requesting_agencies/" + id,
|
||||
body: iso18626_requesting_agency,
|
||||
}),
|
||||
count: (query = {}) =>
|
||||
this.httpClient.count({
|
||||
endpoint:
|
||||
"iso18626_requesting_agencies?" +
|
||||
new URLSearchParams({
|
||||
_page: 1,
|
||||
_per_page: 1,
|
||||
...(query && { q: JSON.stringify(query) }),
|
||||
}),
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default ILLAPIClient;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<ModuleDashboard name="ILL" :availableWidgets="availableWidgets" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModuleDashboard from "../ModuleDashboard/ModuleDashboard.vue";
|
||||
import ILLRequests from "../ModuleDashboard/Widgets/ILLRequests.vue";
|
||||
import { markRaw } from "vue";
|
||||
|
||||
export default {
|
||||
components: { ModuleDashboard },
|
||||
setup() {
|
||||
const availableWidgets = [markRaw(ILLRequests)];
|
||||
return {
|
||||
availableWidgets,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export function ISO18626() {
|
||||
const getCodesForElement = element => {
|
||||
const codes = [
|
||||
{
|
||||
element: "courierName",
|
||||
values: [
|
||||
{
|
||||
value: "DB Schenker",
|
||||
description: $__("DB Schenker"),
|
||||
},
|
||||
{
|
||||
value: "DHL",
|
||||
description: $__("DHL"),
|
||||
},
|
||||
{
|
||||
value: "Fedex",
|
||||
description: $__("Fedex"),
|
||||
},
|
||||
{
|
||||
value: "PostNord AB",
|
||||
description: $__("PostNord AB"),
|
||||
},
|
||||
{
|
||||
value: "UPS",
|
||||
description: $__("UPS"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "deliveryMethod",
|
||||
values: [
|
||||
{
|
||||
value: "ArticleExchange",
|
||||
description: $__("Article Exchange"),
|
||||
},
|
||||
{
|
||||
value: "Courier",
|
||||
description: $__("Courier"),
|
||||
},
|
||||
{
|
||||
value: "Email",
|
||||
description: $__("Email"),
|
||||
},
|
||||
{
|
||||
value: "FTP",
|
||||
description: $__("FTP – File Transfer Protocol"),
|
||||
},
|
||||
{
|
||||
value: "Mail",
|
||||
description: $__("Mail"),
|
||||
},
|
||||
{
|
||||
value: "Odyssey",
|
||||
description: $__("Odyssey"),
|
||||
},
|
||||
{
|
||||
value: "URL",
|
||||
description: $__("Website to download from"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "itemFormat",
|
||||
values: [
|
||||
{
|
||||
value: "CassetteTape",
|
||||
description: $__("Cassette tape"),
|
||||
},
|
||||
{
|
||||
value: "CD",
|
||||
description: $__("CD"),
|
||||
},
|
||||
{
|
||||
value: "CD-ROM",
|
||||
description: $__("CD-ROM"),
|
||||
},
|
||||
{
|
||||
value: "Daisy-ROM",
|
||||
description: $__("Daisy-ROM"),
|
||||
},
|
||||
{
|
||||
value: "DVD",
|
||||
description: $__("DVD"),
|
||||
},
|
||||
{
|
||||
value: "EPUB",
|
||||
description: $__("EPUB"),
|
||||
},
|
||||
{
|
||||
value: "EPUB2",
|
||||
description: $__("EPUB2"),
|
||||
},
|
||||
{
|
||||
value: "EPUB3",
|
||||
description: $__("EPUB3"),
|
||||
},
|
||||
{
|
||||
value: "JPEG",
|
||||
description: $__("JPEG"),
|
||||
},
|
||||
{
|
||||
value: "LargePrint",
|
||||
description: $__("Large print"),
|
||||
},
|
||||
{
|
||||
value: "LP",
|
||||
description: $__("LP"),
|
||||
},
|
||||
{
|
||||
value: "Microform",
|
||||
description: $__("Microform"),
|
||||
},
|
||||
{
|
||||
value: "MP3",
|
||||
description: $__("MP3"),
|
||||
},
|
||||
{
|
||||
value: "Multimedia",
|
||||
description: $__("Multimedia"),
|
||||
},
|
||||
{
|
||||
value: "PaperCopy",
|
||||
description: $__("Paper copy"),
|
||||
},
|
||||
{
|
||||
value: "PDF",
|
||||
description: $__("PDF"),
|
||||
},
|
||||
{
|
||||
value: "Printed",
|
||||
description: $__("Printed"),
|
||||
},
|
||||
{
|
||||
value: "Tape",
|
||||
description: $__("Tape"),
|
||||
},
|
||||
{
|
||||
value: "TIFF",
|
||||
description: $__("TIFF"),
|
||||
},
|
||||
{
|
||||
value: "UltraHD",
|
||||
description: $__("Ultra HD"),
|
||||
},
|
||||
{
|
||||
value: "VHS",
|
||||
description: $__("VHS"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "loanCondition",
|
||||
values: [
|
||||
{
|
||||
value: "LibraryUseOnly",
|
||||
description: $__("Use in library only"),
|
||||
},
|
||||
{
|
||||
value: "WatchLibraryUseOnly",
|
||||
description: $__("Supervised use in library only"),
|
||||
},
|
||||
{
|
||||
value: "NoReproduction",
|
||||
description: $__("No reproduction"),
|
||||
},
|
||||
{
|
||||
value: "SignatureRequired",
|
||||
description: $__("Signature required"),
|
||||
},
|
||||
{
|
||||
value: "SpecCollSupervReq",
|
||||
description: $__(
|
||||
"Special collections supervision required"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "paymentMethod",
|
||||
values: [
|
||||
{
|
||||
value: "BankTransfer",
|
||||
description: $__("Bank transfer"),
|
||||
},
|
||||
{
|
||||
value: "CreditCard",
|
||||
description: $__("Credit card"),
|
||||
},
|
||||
{
|
||||
value: "DebitCard",
|
||||
description: $__("Debit card"),
|
||||
},
|
||||
{
|
||||
value: "EFTS",
|
||||
description: $__("Electronic Fund Transfer System"),
|
||||
},
|
||||
{
|
||||
value: "IBS",
|
||||
description: $__(
|
||||
"Interloan Billing System (New Zealand)"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "IIBS",
|
||||
description: $__(
|
||||
"International Interloan Billing System (New Zealand)"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "IFLAVoucher",
|
||||
description: $__("IFLA Voucher"),
|
||||
},
|
||||
{
|
||||
value: "IFM",
|
||||
description: $__("OCLC fee management system"),
|
||||
},
|
||||
{
|
||||
value: "LAPS",
|
||||
description: $__("Libraries Australia Payment Service"),
|
||||
},
|
||||
{
|
||||
value: "Paypal",
|
||||
description: $__("Paypal"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "reasonRetry",
|
||||
values: [
|
||||
{
|
||||
value: "AtBindery",
|
||||
description: $__("At bindery"),
|
||||
},
|
||||
{
|
||||
value: "CostExceedsMaxCost",
|
||||
description: $__("Cost exceeds max cost"),
|
||||
},
|
||||
{
|
||||
value: "CourierNotSupp",
|
||||
description: $__("Courier not supported"),
|
||||
},
|
||||
{
|
||||
value: "MultiVolAvail",
|
||||
description: $__(
|
||||
"More than one volume can fulfil the request"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "MustMeetLoanCondition",
|
||||
description: $__("Loan condition shall be met"),
|
||||
},
|
||||
{
|
||||
value: "NotCurrentAvailableForILL",
|
||||
description: $__("Not currently available for ILL"),
|
||||
},
|
||||
{
|
||||
value: "NotFoundAsCited",
|
||||
description: $__("Not found as cited"),
|
||||
},
|
||||
{
|
||||
value: "OnLoan",
|
||||
description: $__("On loan"),
|
||||
},
|
||||
{
|
||||
value: "OnOrder",
|
||||
description: $__("On order"),
|
||||
},
|
||||
{
|
||||
value: "ReqDelDateNotPossible",
|
||||
description: $__(
|
||||
"Requested delivery date not possible"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "ReqDelMethodNotSupp",
|
||||
description: $__(
|
||||
"Requested delivery method not supported"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "ReqEditionNotPossible",
|
||||
description: $__(
|
||||
"Requested edition cannot be provided"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "ReqFormatNotPossible",
|
||||
description: $__("Requested format not possible"),
|
||||
},
|
||||
{
|
||||
value: "ReqPayMethodNotSupported",
|
||||
description: $__(
|
||||
"Requested payment method not supported"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "ReqServLevelNotSupp",
|
||||
description: $__(
|
||||
"Requested service level not supported"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "ReqServTypeNotPossible",
|
||||
description: $__("Requested service type not possible"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "reasonUnfilled",
|
||||
values: [
|
||||
{
|
||||
value: "NonCirculating",
|
||||
description: $__("Non-circulating (e.g. handbook)"),
|
||||
},
|
||||
{
|
||||
value: "NotAvailableForILL",
|
||||
description: $__("Not available for ILL"),
|
||||
},
|
||||
{
|
||||
value: "NotHeld",
|
||||
description: $__("Not held"),
|
||||
},
|
||||
{
|
||||
value: "NotOnShelf",
|
||||
description: $__("Not on shelf"),
|
||||
},
|
||||
{
|
||||
value: "PolicyProblem",
|
||||
description: $__("Policy problem"),
|
||||
},
|
||||
{
|
||||
value: "PoorCondition",
|
||||
description: $__("Poor condition"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: "serviceLevel",
|
||||
values: [
|
||||
{
|
||||
value: "Express",
|
||||
description: $__("Express (Australia)"),
|
||||
},
|
||||
{
|
||||
value: "Normal",
|
||||
description: $__("Normal (Prioritaire A)"),
|
||||
},
|
||||
{
|
||||
value: "Rush",
|
||||
description: $__("Rush (Australia)"),
|
||||
},
|
||||
{
|
||||
value: "SecondaryMail",
|
||||
description: $__("Secondary mail (Prioritaire B)"),
|
||||
},
|
||||
{
|
||||
value: "Standard",
|
||||
description: $__("Standard (Australia)"),
|
||||
},
|
||||
{
|
||||
value: "Urgent",
|
||||
description: $__("Urgent"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return codes.find(code => code.element === element).values;
|
||||
};
|
||||
|
||||
return {
|
||||
getCodesForElement,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
<template>
|
||||
<FormElement
|
||||
:resource="messageFilterOptions"
|
||||
:attr="{
|
||||
label: 'Show confirmations',
|
||||
name: 'showConfirmationRows',
|
||||
type: 'checkbox',
|
||||
}"
|
||||
/>
|
||||
<table id="iso18626_messages">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Information</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Content</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="message in filteredMessages"
|
||||
v-bind:key="message.iso18626_message_id"
|
||||
>
|
||||
<td>
|
||||
<i
|
||||
v-if="message.type.includes('request')"
|
||||
class="fas fa-download"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<i v-else class="fas fa-upload" aria-hidden="true"></i>
|
||||
|
||||
{{ message.type }}
|
||||
</td>
|
||||
<td>
|
||||
{{ getMessageData(message.content) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ new Date(message.timestamp).toLocaleString() }}
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
@click="openModal(message.content)"
|
||||
>
|
||||
<i class="fas fa-envelope" aria-hidden="true"></i>
|
||||
View message
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormElement from "../FormElement.vue";
|
||||
import { inject, ref, computed } from "vue";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
iso18626_request: Object,
|
||||
},
|
||||
setup(props) {
|
||||
const modalVisible = ref(false);
|
||||
const messageFilterOptions = ref({
|
||||
showConfirmationRows: false,
|
||||
});
|
||||
const prettifiedMessage = ref(null);
|
||||
const { setConfirmationDialog, setMessage, setError } =
|
||||
inject("mainStore");
|
||||
|
||||
const filteredMessages = computed(() => {
|
||||
return props.iso18626_request.messages.filter(message => {
|
||||
if (messageFilterOptions.value.showConfirmationRows) {
|
||||
return true;
|
||||
}
|
||||
return !message.type.toLowerCase().includes("confirmation");
|
||||
});
|
||||
});
|
||||
|
||||
const getMessageData = (message, type) => {
|
||||
const parsedMessage = Object.values(JSON.parse(message))[0];
|
||||
let message_data;
|
||||
message_data =
|
||||
parsedMessage?.action !== undefined &&
|
||||
parsedMessage?.action !== null
|
||||
? parsedMessage?.action
|
||||
: null;
|
||||
if (message_data === null) {
|
||||
message_data =
|
||||
parsedMessage?.messageInfo?.reasonForMessage !==
|
||||
undefined &&
|
||||
parsedMessage?.messageInfo?.reasonForMessage !== null
|
||||
? parsedMessage?.messageInfo?.reasonForMessage
|
||||
: null;
|
||||
if (message_data !== null) {
|
||||
message_data = "Reason: " + message_data;
|
||||
}
|
||||
} else {
|
||||
message_data = "Action: " + message_data;
|
||||
}
|
||||
return message_data;
|
||||
};
|
||||
|
||||
function openModal(message) {
|
||||
const messageObj = Object.values(JSON.parse(message))[0];
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("accordion");
|
||||
generateCollapsibleTabs(messageObj, container);
|
||||
const message_type = Object.keys(JSON.parse(message))[0];
|
||||
setConfirmationDialog({
|
||||
title: `ISO18626 message: ${message_type}`,
|
||||
message: container.outerHTML,
|
||||
size: "modal-lg",
|
||||
});
|
||||
}
|
||||
|
||||
function generateCollapsibleTabs(obj, parent) {
|
||||
const sortedKeys = Object.keys(obj).sort((a, b) => {
|
||||
const order = [
|
||||
"action",
|
||||
"header",
|
||||
"confirmationHeader",
|
||||
"bibliographicInfo",
|
||||
"messageInfo",
|
||||
"statusInfo",
|
||||
];
|
||||
const indexA =
|
||||
order.indexOf(a) !== -1 ? order.indexOf(a) : Infinity;
|
||||
const indexB =
|
||||
order.indexOf(b) !== -1 ? order.indexOf(b) : Infinity;
|
||||
return indexA - indexB;
|
||||
});
|
||||
|
||||
const top_level_key_number = Object.keys(obj).length;
|
||||
for (const key of sortedKeys) {
|
||||
if (typeof obj[key] === "object") {
|
||||
const details = document.createElement("fieldset");
|
||||
details.classList.add("rows");
|
||||
|
||||
const summary = document.createElement("legend");
|
||||
const keySpan = document.createElement("span");
|
||||
keySpan.textContent =
|
||||
key.charAt(0).toUpperCase() + key.slice(1);
|
||||
summary.appendChild(keySpan);
|
||||
summary.setAttribute("data-bs-toggle", "collapse");
|
||||
summary.setAttribute("data-bs-target", "#collapse_" + key);
|
||||
|
||||
if (key === "header") {
|
||||
summary.setAttribute("aria-expanded", "false");
|
||||
summary.classList.add("collapsed");
|
||||
}
|
||||
summary.classList.add("expanded");
|
||||
|
||||
summary.setAttribute("aria-controls", "collapseExample");
|
||||
summary.innerHTML =
|
||||
'<i class="fa fa-caret-down"></i> ' + summary.innerHTML;
|
||||
|
||||
const nestedContainer = document.createElement("ol");
|
||||
nestedContainer.setAttribute("id", "collapse_" + key);
|
||||
nestedContainer.classList.add("collapse");
|
||||
if (key !== "header") {
|
||||
nestedContainer.classList.add("show");
|
||||
}
|
||||
const nestedTable = document.createElement("table");
|
||||
|
||||
// Call generateTableRows for the nested object
|
||||
generateTableRows(obj[key], nestedTable);
|
||||
|
||||
nestedContainer.appendChild(nestedTable);
|
||||
details.appendChild(summary);
|
||||
details.appendChild(nestedContainer);
|
||||
|
||||
parent.appendChild(details);
|
||||
} else {
|
||||
// Handle regular top-level items
|
||||
const div = document.createElement("div");
|
||||
div.textContent =
|
||||
key.charAt(0).toUpperCase() +
|
||||
key.slice(1) +
|
||||
": " +
|
||||
obj[key];
|
||||
div.classList.add("fs-2", "fw-bold", "p-2");
|
||||
parent.appendChild(div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateTableRows(obj, parent) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === "object") {
|
||||
const tr = document.createElement("tr");
|
||||
const th = document.createElement("th");
|
||||
th.textContent = key;
|
||||
tr.appendChild(th);
|
||||
|
||||
const td = document.createElement("td");
|
||||
tr.appendChild(td);
|
||||
|
||||
const nestedTable = document.createElement("table");
|
||||
nestedTable.classList.add("nested-table");
|
||||
nestedTable.style.paddingLeft = "20px";
|
||||
nestedTable.style.borderLeft = "1px solid #ccc";
|
||||
|
||||
generateTableRows(obj[key], nestedTable);
|
||||
|
||||
td.appendChild(nestedTable);
|
||||
|
||||
parent.appendChild(tr);
|
||||
} else {
|
||||
const tr = document.createElement("tr");
|
||||
const th = document.createElement("th");
|
||||
th.textContent = key;
|
||||
tr.appendChild(th);
|
||||
|
||||
const td = document.createElement("td");
|
||||
td.textContent = obj[key];
|
||||
tr.appendChild(td);
|
||||
|
||||
parent.appendChild(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
modalVisible,
|
||||
prettifiedMessage,
|
||||
openModal,
|
||||
filteredMessages,
|
||||
messageFilterOptions,
|
||||
getMessageData,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
FormElement,
|
||||
},
|
||||
name: "ResourceFormSave",
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<div v-if="initialized && config.settings.ILLModule == 1">
|
||||
<div id="sub-header">
|
||||
<Breadcrumbs />
|
||||
<Help />
|
||||
</div>
|
||||
<div class="main container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-10 order-md-2 order-sm-1">
|
||||
<main>
|
||||
<Dialog />
|
||||
<router-view />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 order-sm-2 order-md-1">
|
||||
<LeftMenu :title="$__('Interlibrary loans')"></LeftMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main container-fluid" v-else>
|
||||
<Dialog />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { inject, onBeforeMount, ref } from "vue";
|
||||
import { APIClient } from "../../fetch/api-client.js";
|
||||
import Breadcrumbs from "../Breadcrumbs.vue";
|
||||
import Help from "../Help.vue";
|
||||
import LeftMenu from "../LeftMenu.vue";
|
||||
import Dialog from "../Dialog.vue";
|
||||
import "vue-select/dist/vue-select.css";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const mainStore = inject("mainStore");
|
||||
|
||||
const { loading, loaded, setError } = mainStore;
|
||||
|
||||
const ILLStore = inject("ILLStore");
|
||||
|
||||
const { config } = storeToRefs(ILLStore);
|
||||
|
||||
const initialized = ref(false);
|
||||
|
||||
onBeforeMount(() => {
|
||||
loading();
|
||||
const client = APIClient.sysprefs;
|
||||
client.sysprefs
|
||||
.getAll(["ILLPartnerCode", "ILLModule"])
|
||||
.then(pref_values => {
|
||||
config.value.settings.ILLPartnerCode =
|
||||
pref_values.value.ILLPartnerCode;
|
||||
config.value.settings.ILLModule =
|
||||
pref_values.value.ILLModule;
|
||||
if (config.value.settings.ILLModule != 1) {
|
||||
loaded();
|
||||
return setError(
|
||||
$__(
|
||||
"The ILL module is disabled, turn on <a href='/cgi-bin/koha/admin/preferences.pl?tab=&op=search&searchfield=ILLModule'>ILLModule</a> to use it"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
loaded();
|
||||
});
|
||||
initialized.value = true;
|
||||
});
|
||||
|
||||
return {
|
||||
ILLStore,
|
||||
config,
|
||||
setError,
|
||||
loading,
|
||||
loaded,
|
||||
initialized,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Breadcrumbs,
|
||||
Dialog,
|
||||
Help,
|
||||
LeftMenu,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#menu ul ul,
|
||||
.sidebar_menu ul ul {
|
||||
background-color: transparent;
|
||||
padding-left: 2em;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
form .v-select {
|
||||
display: inline-block;
|
||||
background-color: white;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.v-select,
|
||||
input:not([type="submit"]):not([type="search"]):not([type="button"]):not(
|
||||
[type="checkbox"]
|
||||
):not([type="radio"]),
|
||||
textarea {
|
||||
border-color: rgba(60, 60, 60, 0.26);
|
||||
border-width: 1px;
|
||||
border-radius: 4px;
|
||||
min-width: 30%;
|
||||
}
|
||||
.flatpickr-input {
|
||||
width: 30%;
|
||||
}
|
||||
.sidebar_menu ul li a.current.disabled {
|
||||
background-color: inherit;
|
||||
border-left: 5px solid transparent;
|
||||
color: #000;
|
||||
}
|
||||
.sidebar_menu ul li a.disabled {
|
||||
color: #666;
|
||||
pointer-events: none;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
<template>
|
||||
<h2>{{ $__("Progress request") }}</h2>
|
||||
<div v-if="!initialized">{{ $__("Loading") }}</div>
|
||||
<template v-if="initialized">
|
||||
<div class="page-section">
|
||||
<p>
|
||||
This request's status is
|
||||
<strong>{{ iso18626_request.status }}</strong
|
||||
>.
|
||||
</p>
|
||||
<p>Below are the possible actions in order to progress it.</p>
|
||||
</div>
|
||||
<fieldset class="rows">
|
||||
<table id="request-status" class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $__("Action") }}</th>
|
||||
<th>{{ $__("Description") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(status, key) in statuses" :key="key">
|
||||
<template
|
||||
v-if="
|
||||
status.show_if_status_in.includes(
|
||||
iso18626_request.status
|
||||
)
|
||||
"
|
||||
>
|
||||
<td>
|
||||
<button
|
||||
class="btn"
|
||||
:class="`${status.btn_class ? status.btn_class : 'btn-default'}`"
|
||||
@click="progressRequest(key)"
|
||||
>
|
||||
<span
|
||||
:class="`fa-solid ${status.icon}`"
|
||||
></span>
|
||||
{{ status.button_label }}
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
{{ status.description }}
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<div
|
||||
v-if="iso18626_request.status == 'CopyCompleted'"
|
||||
class="page-section"
|
||||
>
|
||||
<p>This request has been completed. Nothing to do here.</p>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { createVNode, onBeforeMount, onMounted, ref, render } from "vue";
|
||||
import { APIClient } from "../../fetch/api-client.js";
|
||||
import { useDataTable } from "../../composables/datatables";
|
||||
import { inject } from "vue";
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const initialized = ref(false);
|
||||
const status = ref("RequestReceived"); // <--- define it here
|
||||
const iso18626_request = ref(null);
|
||||
const router = useRouter();
|
||||
|
||||
const { setConfirmationDialog, setMessage, setError } =
|
||||
inject("mainStore");
|
||||
|
||||
const statuses = ref({
|
||||
ExpectToSupply: {
|
||||
confirm_message: $__("TODO: Write this"),
|
||||
description: $__(
|
||||
"Supplying library expects to fill the request, based on e.g. information in the local OPAC"
|
||||
),
|
||||
button_label: $__("Expect to supply"),
|
||||
icon: "fa-calendar-days",
|
||||
show_if_status_in: ["RequestReceived"],
|
||||
},
|
||||
CopyCompleted: {
|
||||
confirm_message: $__(
|
||||
"By changing this request's status to CopyCompleted, a message will be sent to the requesting library notifying them that the transaction has concluded."
|
||||
),
|
||||
description: $__(
|
||||
"The supplying library has sent the requested item (this status is used when there is no need to return the item supplied)"
|
||||
),
|
||||
button_label: $__("Copy completed"),
|
||||
icon: "fa-check",
|
||||
btn_class: "btn-primary",
|
||||
show_if_status_in: ["RequestReceived"],
|
||||
},
|
||||
Loaned: {
|
||||
confirm_message: $__(
|
||||
"By changing this request's status to Loaned, a message will be sent to the requesting library notifying them that the item has been supplied."
|
||||
),
|
||||
description: $__(
|
||||
"The item is currently on loan to the requesting library for this request"
|
||||
),
|
||||
button_label: $__("Mark as loaned"),
|
||||
icon: "fa-box",
|
||||
show_if_status_in: [
|
||||
"RequestReceived",
|
||||
"ExpectToSupply",
|
||||
"WillSupply",
|
||||
],
|
||||
},
|
||||
RetryPossible: {
|
||||
confirm_message: $__(
|
||||
"By changing this request's status to RetryPossible, a message will be sent to the requesting library and they can submit a Retry request."
|
||||
),
|
||||
description: $__(
|
||||
"The supplying library cannot fill the request based on information provided or may be able to supply at a later date. The requesting library may submit a Retry request which may include updated information"
|
||||
),
|
||||
button_label: $__("Ask for retry"),
|
||||
icon: "fa-repeat",
|
||||
show_if_status_in: [
|
||||
"RequestReceived",
|
||||
"WillSupply",
|
||||
"ExpectToSupply",
|
||||
],
|
||||
},
|
||||
WillSupply: {
|
||||
confirm_message: $__(
|
||||
"By changing this request's status to WillSupply, a message will be sent to the requesting library notifying them that the item will be supplied."
|
||||
),
|
||||
description: $__(
|
||||
"Supplying library has located the item but has not sent it yet"
|
||||
),
|
||||
button_label: $__("Will supply"),
|
||||
icon: "fa-calendar-days",
|
||||
show_if_status_in: ["RequestReceived", "ExpectToSupply"],
|
||||
},
|
||||
Unfilled: {
|
||||
confirm_message: $__(
|
||||
"By changing this request's status to Unfilled, a message will be sent to the requesting library notifying them that the item will not be supplied."
|
||||
),
|
||||
description: $__(
|
||||
"The supplying library cannot fill the request. The explanation may be provided in the ReasonUnfilled data element"
|
||||
),
|
||||
button_label: $__("Unfilled"),
|
||||
icon: "fa-calendar-days",
|
||||
btn_class: "btn-danger",
|
||||
show_if_status_in: ["RequestReceived"],
|
||||
},
|
||||
});
|
||||
|
||||
const progressRequest = action => {
|
||||
setConfirmationDialog(
|
||||
{
|
||||
title: $__(
|
||||
"Update this request's status to <strong>%s</strong>?"
|
||||
).format(action),
|
||||
message: statuses.value[action].confirm_message,
|
||||
accept_label: $__("Yes, update"),
|
||||
cancel_label: $__("No, do not update"),
|
||||
inputs: [
|
||||
{
|
||||
name: "status",
|
||||
type: "hidden",
|
||||
value: action,
|
||||
label: $__("Status"),
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
(callback_result, inputFields) => {
|
||||
const client = APIClient.ill.supplying;
|
||||
client
|
||||
.patch(
|
||||
{ status: inputFields.status },
|
||||
iso18626_request.value.iso18626_request_id
|
||||
)
|
||||
.then(
|
||||
success => {
|
||||
router.push({
|
||||
name: "SupplyingShow",
|
||||
params: {
|
||||
iso18626_request_id:
|
||||
iso18626_request.value
|
||||
.iso18626_request_id,
|
||||
},
|
||||
});
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
const route = useRoute();
|
||||
const client = APIClient.ill.supplying;
|
||||
client.get(route.params.iso18626_request_id).then(
|
||||
result => {
|
||||
iso18626_request.value = result;
|
||||
initialized.value = true;
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
});
|
||||
onMounted(() => {
|
||||
// buildDatatable();
|
||||
});
|
||||
return {
|
||||
status,
|
||||
initialized,
|
||||
progressRequest,
|
||||
statuses,
|
||||
iso18626_request,
|
||||
};
|
||||
},
|
||||
name: "ProgressRequest",
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
<BaseResource
|
||||
:routeAction="routeAction"
|
||||
:instancedResource="this"
|
||||
></BaseResource>
|
||||
</template>
|
||||
<script>
|
||||
import { inject } from "vue";
|
||||
import BaseResource from "../BaseResource.vue";
|
||||
import { useBaseResource } from "../../composables/base-resource.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { APIClient } from "../../fetch/api-client.js";
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
routeAction: String,
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const ILLStore = inject("ILLStore");
|
||||
const { config } = ILLStore;
|
||||
|
||||
const baseResource = useBaseResource({
|
||||
resourceName: "iso18626_requesting_agency",
|
||||
nameAttr: "name",
|
||||
idAttr: "iso18626_requesting_agency_id",
|
||||
components: {
|
||||
show: "RequestingAgenciesShow",
|
||||
list: "RequestingAgenciesList",
|
||||
add: "RequestingAgenciesFormAdd",
|
||||
edit: "RequestingAgenciesFormAddEdit",
|
||||
},
|
||||
apiClient: APIClient.ill.requesting_agencies,
|
||||
i18n: {
|
||||
deleteConfirmationMessage: $__(
|
||||
"Are you sure you want to remove this requesting agency?"
|
||||
),
|
||||
deleteSuccessMessage: $__("Requesting agency %s deleted"),
|
||||
displayName: $__("Requesting agency"),
|
||||
editLabel: $__("Edit requesting agency #%s"),
|
||||
emptyListMessage: $__(
|
||||
"There are no requesting agencies defined"
|
||||
),
|
||||
newLabel: $__("New requesting agency"),
|
||||
},
|
||||
table: {
|
||||
resourceTableUrl:
|
||||
APIClient.ill.httpClient._baseURL +
|
||||
"iso18626_requesting_agencies",
|
||||
},
|
||||
resourceAttrs: [
|
||||
{
|
||||
name: "iso18626_requesting_agency_id",
|
||||
label: $__("ID"),
|
||||
type: "text",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Details"),
|
||||
},
|
||||
{
|
||||
name: "patron_id",
|
||||
type: "patronAutoComplete",
|
||||
label: __("ILL partner"),
|
||||
placeholder: __("Search for an ILL partner"),
|
||||
patronAutoCompleteOptions: {
|
||||
"additional-filters": {
|
||||
"me.category_id": config.settings.ILLPartnerCode,
|
||||
},
|
||||
},
|
||||
patronEmbedName: "ill_partner",
|
||||
required: true,
|
||||
group: $__("Details"),
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
label: $__("Name"),
|
||||
required: true,
|
||||
type: "text",
|
||||
group: $__("Details"),
|
||||
},
|
||||
{
|
||||
name: "type",
|
||||
label: $__("Type"),
|
||||
required: true,
|
||||
type: "select",
|
||||
options: [
|
||||
{
|
||||
value: "DNUCNI",
|
||||
description: __("DNUCNI"),
|
||||
},
|
||||
{
|
||||
value: "ICOLC",
|
||||
description: __("ICOLC"),
|
||||
},
|
||||
{
|
||||
value: "ISIL",
|
||||
description: __("ISIL"),
|
||||
},
|
||||
],
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
group: $__("Details"),
|
||||
},
|
||||
{
|
||||
name: "account_id",
|
||||
label: $__("Account ID"),
|
||||
required: true,
|
||||
type: "text",
|
||||
group: $__("ISO18626 authentication"),
|
||||
},
|
||||
{
|
||||
name: "securityCode",
|
||||
label: $__("Security Code"),
|
||||
required: true,
|
||||
type: "text",
|
||||
hideIn: ["List"],
|
||||
group: $__("ISO18626 authentication"),
|
||||
},
|
||||
{
|
||||
name: "callback_endpoint",
|
||||
label: $__("Callback endpoint"),
|
||||
type: "text",
|
||||
hideIn: ["List"],
|
||||
group: $__("Details"),
|
||||
},
|
||||
],
|
||||
moduleStore: "ILLStore",
|
||||
props: props,
|
||||
});
|
||||
|
||||
const tableOptions = {
|
||||
url: () => tableUrl(),
|
||||
options: {
|
||||
embed: "ill_partner",
|
||||
},
|
||||
actions: {
|
||||
0: ["show"],
|
||||
1: ["show"],
|
||||
"-1": ["edit", "delete"],
|
||||
},
|
||||
};
|
||||
|
||||
const onFormSave = (e, requestingAgencyToSave) => {
|
||||
e.preventDefault();
|
||||
|
||||
let iso18626_requesting_agency = JSON.parse(
|
||||
JSON.stringify(requestingAgencyToSave)
|
||||
); // copy
|
||||
let iso18626_requesting_agency_id =
|
||||
iso18626_requesting_agency.iso18626_requesting_agency_id;
|
||||
|
||||
delete iso18626_requesting_agency.iso18626_requesting_agency_id;
|
||||
delete iso18626_requesting_agency.ill_partner;
|
||||
|
||||
if (iso18626_requesting_agency_id) {
|
||||
return baseResource.apiClient
|
||||
.update(
|
||||
iso18626_requesting_agency,
|
||||
iso18626_requesting_agency_id
|
||||
)
|
||||
.then(
|
||||
requesting_agency => {
|
||||
baseResource.setMessage(
|
||||
$__("Requesting agency updated")
|
||||
);
|
||||
return requesting_agency;
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
} else {
|
||||
return baseResource.apiClient
|
||||
.create(iso18626_requesting_agency)
|
||||
.then(
|
||||
requesting_agency => {
|
||||
baseResource.setMessage(
|
||||
$__("Requesting agency created")
|
||||
);
|
||||
return requesting_agency;
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
}
|
||||
};
|
||||
const tableUrl = filters => {
|
||||
return baseResource.getResourceTableUrl();
|
||||
};
|
||||
|
||||
return {
|
||||
...baseResource,
|
||||
tableOptions,
|
||||
onFormSave,
|
||||
tableUrl,
|
||||
};
|
||||
},
|
||||
emits: ["select-resource"],
|
||||
name: "RequestingAgencyResource",
|
||||
components: {
|
||||
BaseResource,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,877 @@
|
|||
<template>
|
||||
<BaseResource
|
||||
:routeAction="routeAction"
|
||||
:instancedResource="this"
|
||||
></BaseResource>
|
||||
</template>
|
||||
<script>
|
||||
import { useRouter } from "vue-router";
|
||||
import { ISO18626 } from "./ISO18626.js";
|
||||
import BaseResource from "../BaseResource.vue";
|
||||
import { useBaseResource } from "../../composables/base-resource.js";
|
||||
import { inject, ref } from "vue";
|
||||
import { APIClient } from "../../fetch/api-client.js";
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
routeAction: String,
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const router = useRouter();
|
||||
const { getCodesForElement } = ISO18626();
|
||||
|
||||
const {
|
||||
setConfirmationDialog,
|
||||
setMessage,
|
||||
updateConfirmationDialogInputs,
|
||||
} = inject("mainStore");
|
||||
|
||||
const conditionalInputs = ref([]);
|
||||
|
||||
const statuses = ref([
|
||||
{
|
||||
id: "RequestReceived",
|
||||
next_actions: [
|
||||
"ExpectToSupply",
|
||||
"CopyCompleted",
|
||||
"Loaned",
|
||||
"RetryPossible",
|
||||
"WillSupply",
|
||||
"Unfilled",
|
||||
"Cancelled",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "ExpectToSupply",
|
||||
confirm_message: $__(
|
||||
"Supplying library expects to fill the request, based on e.g. information in the local OPAC. The message may include the ExpectedDeliveryDate"
|
||||
),
|
||||
button_label: $__("Expect to supply"),
|
||||
icon: "fa-calendar-days",
|
||||
next_actions: [
|
||||
"Loaned",
|
||||
"WillSupply",
|
||||
"RetryPossible",
|
||||
"Unfilled",
|
||||
],
|
||||
action_inputs: [
|
||||
{
|
||||
name: "expectedDeliveryDate",
|
||||
type: "date",
|
||||
label: $__("Expected delivery date"),
|
||||
toolTip: $__(
|
||||
"Date and time the supplying library expects to deliver the item."
|
||||
),
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
},
|
||||
{
|
||||
id: "WillSupply",
|
||||
confirm_message: $__(
|
||||
"Supplying library has located the item but has not sent it yet."
|
||||
),
|
||||
button_label: $__("Will supply"),
|
||||
icon: "fa-calendar-days",
|
||||
next_actions: [
|
||||
"Loaned",
|
||||
"RetryPossible",
|
||||
"CopyCompleted",
|
||||
"Unfilled",
|
||||
],
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "Loaned",
|
||||
confirm_message: $__(
|
||||
"The item is currently on loan to the requesting library for this request"
|
||||
),
|
||||
button_label: $__("Mark as loaned"),
|
||||
icon: "fa-box",
|
||||
next_actions: [
|
||||
"Overdue",
|
||||
"LoanCompleted",
|
||||
"CompletedWithoutReturn",
|
||||
], //[ 'Recalled', 'HoldReturn' ]
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "Overdue",
|
||||
confirm_message: $__(
|
||||
"The item currently on loan to the requesting library for this request is now overdue"
|
||||
),
|
||||
button_label: $__("Mark as ovedue"),
|
||||
icon: "fa-box",
|
||||
next_actions: ["LoanCompleted", "CompletedWithoutReturn"], //[ 'Recalled', 'HoldReturn', 'LoanCompleted' ]
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "Recalled",
|
||||
confirm_message: $__(
|
||||
"The item currently on loan to the requesting library for this request has been recalled"
|
||||
),
|
||||
button_label: $__("Ask for recall"),
|
||||
icon: "fa-box",
|
||||
next_actions: ["LoanCompleted", "CompletedWithoutReturn"],
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "RetryPossible",
|
||||
confirm_message: $__(
|
||||
"The supplying library cannot fill the request based on information provided or may be able to supply at a later date. Additional information is provided in the RetryInfo section. The requesting library may submit a Retry request which may include updated information"
|
||||
),
|
||||
button_label: $__("Ask for retry"),
|
||||
icon: "fa-repeat",
|
||||
next_actions: ["Cancelled", "Unfilled"],
|
||||
action_inputs: [
|
||||
{
|
||||
name: "retryBefore",
|
||||
label: $__("Retry before"),
|
||||
type: "date",
|
||||
toolTip: $__(
|
||||
"Specify that a retry should be attempted before the specified date."
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "retryAfter",
|
||||
label: $__("Retry after"),
|
||||
type: "date",
|
||||
toolTip: $__(
|
||||
"Specify that a retry should be attempted only after the specified date."
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "reasonRetry",
|
||||
label: $__("Reason for retry"),
|
||||
required: true,
|
||||
toolTip: $__(
|
||||
"Specify the reason why a retry from the requesting agency is necessary"
|
||||
),
|
||||
type: "select",
|
||||
onSelected: resource => {
|
||||
conditionalInputs.value = [];
|
||||
if (resource.reasonRetry == "CostExceedsMaxCost") {
|
||||
conditionalInputs.value.push({
|
||||
name: "offeredCostsCurrencyCode",
|
||||
type: "select",
|
||||
label: $__("Currency code"),
|
||||
required: true,
|
||||
toolTip: $__(
|
||||
"Specify the currency code for the offered costs"
|
||||
),
|
||||
options: [
|
||||
{
|
||||
value: "USD",
|
||||
description: __("USD"),
|
||||
},
|
||||
{
|
||||
value: "EUR",
|
||||
description: __("EUR"),
|
||||
},
|
||||
{
|
||||
value: "GBP",
|
||||
description: __("GBP"),
|
||||
},
|
||||
{
|
||||
value: "AUD",
|
||||
description: __("AUD"),
|
||||
},
|
||||
{
|
||||
value: "SEK",
|
||||
description: __("SEK"),
|
||||
},
|
||||
],
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
conditionalInputs.value.push({
|
||||
name: "offeredCostsMonetaryValue",
|
||||
type: "number",
|
||||
label: $__("Monetary value"),
|
||||
required: true,
|
||||
toolTip: $__(
|
||||
"Specify the monetary value for the offered costs"
|
||||
),
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "MultiVolAvail"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "volume",
|
||||
type: "text",
|
||||
label: $__("Volume(s)"),
|
||||
required: true,
|
||||
placeholder: "14,15",
|
||||
toolTip: $__(
|
||||
"Specify which volume(s) are available, separated by comma ','"
|
||||
),
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "MustMeetLoanCondition"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "loanCondition",
|
||||
label: $__("Loan condition(s)"),
|
||||
required: true,
|
||||
type: "select",
|
||||
toolTip: $__(
|
||||
"Specify the condition(s) of use that need to be met once the requested item is delivered"
|
||||
),
|
||||
allowMultipleChoices: true,
|
||||
options:
|
||||
getCodesForElement("loanCondition"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "ReqDelMethodNotSupp"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "deliveryMethod",
|
||||
type: "select",
|
||||
vselectStyle: {
|
||||
dropdownMaxHeight: "150px",
|
||||
},
|
||||
toolTip: $__(
|
||||
"Specify which delivery method(s) can be supplied"
|
||||
),
|
||||
allowMultipleChoices: true,
|
||||
label: $__("Delivery method(s)"),
|
||||
required: true,
|
||||
options:
|
||||
getCodesForElement("deliveryMethod"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
onUpdated: inputValues => {
|
||||
const deliveryMethods =
|
||||
inputValues.deliveryMethod;
|
||||
if (
|
||||
deliveryMethods &&
|
||||
deliveryMethods.includes("Courier")
|
||||
) {
|
||||
const existingInput =
|
||||
conditionalInputs.value.find(
|
||||
input =>
|
||||
input.name ===
|
||||
"courierName"
|
||||
);
|
||||
if (!existingInput) {
|
||||
conditionalInputs.value.push({
|
||||
name: "courierName",
|
||||
type: "select",
|
||||
vselectStyle: {
|
||||
dropdownMaxHeight:
|
||||
"150px",
|
||||
},
|
||||
allowMultipleChoices: true,
|
||||
toolTip: $__(
|
||||
"Specify which courier(s) can be used"
|
||||
),
|
||||
label: $__(
|
||||
"Courier name(s)"
|
||||
),
|
||||
required: true,
|
||||
options:
|
||||
getCodesForElement(
|
||||
"courierName"
|
||||
),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
updateConfirmationDialogInputs(
|
||||
getDialogInputs(inputValues)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const existingInput =
|
||||
conditionalInputs.value.find(
|
||||
input =>
|
||||
input.name ===
|
||||
"courierName"
|
||||
);
|
||||
if (existingInput) {
|
||||
const index =
|
||||
conditionalInputs.value.indexOf(
|
||||
existingInput
|
||||
);
|
||||
if (index > -1) {
|
||||
conditionalInputs.value.splice(
|
||||
index,
|
||||
1
|
||||
);
|
||||
updateConfirmationDialogInputs(
|
||||
getDialogInputs(
|
||||
inputValues
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "ReqEditionNotPossible"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "edition",
|
||||
type: "text",
|
||||
toolTip: $__(
|
||||
"Specify which edition(s) are available, separated by comma ','"
|
||||
),
|
||||
label: $__("Edition(s)"),
|
||||
required: true,
|
||||
placeholder: "14,15",
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "ReqFormatNotPossible"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "itemFormat",
|
||||
type: "select",
|
||||
vselectStyle: {
|
||||
dropdownMaxHeight: "150px",
|
||||
},
|
||||
toolTip: $__(
|
||||
"Specify which format(s) can be supplied"
|
||||
),
|
||||
allowMultipleChoices: true,
|
||||
label: $__("Item format(s)"),
|
||||
required: true,
|
||||
options: getCodesForElement("itemFormat"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry ==
|
||||
"ReqPayMethodNotSupported"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "paymentMethod",
|
||||
type: "select",
|
||||
toolTip: $__(
|
||||
"Specify which payment method(s) can be used"
|
||||
),
|
||||
allowMultipleChoices: true,
|
||||
label: $__("Payment method(s)"),
|
||||
required: true,
|
||||
options:
|
||||
getCodesForElement("paymentMethod"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "ReqServLevelNotSupp"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "serviceLevel",
|
||||
type: "select",
|
||||
toolTip: $__(
|
||||
"Select which service level(s) are supported"
|
||||
),
|
||||
allowMultipleChoices: true,
|
||||
label: $__("Service level(s)"),
|
||||
required: true,
|
||||
options: getCodesForElement("serviceLevel"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
} else if (
|
||||
resource.reasonRetry == "ReqServTypeNotPossible"
|
||||
) {
|
||||
conditionalInputs.value.push({
|
||||
name: "serviceType",
|
||||
type: "select",
|
||||
toolTip: $__(
|
||||
"Select the service type which can be supplied"
|
||||
),
|
||||
label: $__("Service type"),
|
||||
required: true,
|
||||
options: [
|
||||
//TODO: Only show the 2 options that dont match current resource's service_type
|
||||
{
|
||||
value: "Copy",
|
||||
description: __("Copy"),
|
||||
},
|
||||
{
|
||||
value: "CopyOrLoan",
|
||||
description: __("CopyOrLoan"),
|
||||
},
|
||||
{
|
||||
value: "Loan",
|
||||
description: __("Loan"),
|
||||
},
|
||||
],
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
});
|
||||
}
|
||||
updateConfirmationDialogInputs(
|
||||
getDialogInputs(resource)
|
||||
);
|
||||
},
|
||||
vselectStyle: {
|
||||
dropdownMaxHeight: "150px",
|
||||
},
|
||||
options: getCodesForElement("reasonRetry"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "Unfilled",
|
||||
confirm_message: $__(
|
||||
"The supplying library cannot fill the request. The explanation may be provided in the ReasonUnfilled data element"
|
||||
),
|
||||
button_label: $__("Unfilled"),
|
||||
icon: "fa-ban",
|
||||
btn_class: "btn btn-danger",
|
||||
next_actions: [],
|
||||
action_inputs: [
|
||||
{
|
||||
name: "reasonUnfilled",
|
||||
label: $__("Reason unfilled"),
|
||||
required: true,
|
||||
type: "select",
|
||||
options: getCodesForElement("reasonUnfilled"),
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
},
|
||||
],
|
||||
},
|
||||
//HoldReturn
|
||||
//ReleaseHoldReturn
|
||||
{
|
||||
id: "CopyCompleted",
|
||||
confirm_message: $__(
|
||||
"The supplying library has sent the requested item (this status is used when there is no need to return the item supplied)"
|
||||
),
|
||||
button_label: $__("Copy completed"),
|
||||
icon: "fa-check",
|
||||
btn_class: "btn btn-primary",
|
||||
next_actions: [],
|
||||
dont_show: iso18626_request =>
|
||||
iso18626_request.service_type === "Loan",
|
||||
index: -20,
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "LoanCompleted",
|
||||
confirm_message: $__(
|
||||
"The supplying library has received the borrowed item from the requesting agency (this status is used for requests when the item supplied shall be returned by the requesting library, i.e. a loan)"
|
||||
),
|
||||
button_label: $__("Loan completed"),
|
||||
icon: "fa-check",
|
||||
btn_class: "btn btn-primary",
|
||||
next_actions: [],
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "CompletedWithoutReturn",
|
||||
confirm_message: $__(
|
||||
"The supplying library has closed the request without the return of supplied item, e.g. because of loss or damage"
|
||||
),
|
||||
button_label: $__("Complete without return"),
|
||||
icon: "fa-check",
|
||||
btn_class: "btn btn-primary",
|
||||
next_actions: [],
|
||||
action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "Cancelled",
|
||||
confirm_message: $__(
|
||||
"You are responding to this request's cancellation action (as indicated by the requesting library)"
|
||||
),
|
||||
button_label: $__("Cancel"),
|
||||
icon: "fa-xmark",
|
||||
btn_class: "btn btn-danger",
|
||||
next_actions: [],
|
||||
action_inputs: [
|
||||
{
|
||||
name: "answerYesNo",
|
||||
type: "boolean",
|
||||
label: $__("Can cancel?"),
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
dont_show: iso18626_request =>
|
||||
iso18626_request.pending_requesting_agency_action !==
|
||||
"Cancel",
|
||||
},
|
||||
]);
|
||||
|
||||
const statusToUpdate = ref({});
|
||||
const action = ref();
|
||||
|
||||
const progressRequest = (actionClicked, iso18626_request) => {
|
||||
conditionalInputs.value = [];
|
||||
statusToUpdate.value = statuses.value.find(
|
||||
status => status.id === actionClicked
|
||||
);
|
||||
action.value = actionClicked;
|
||||
setConfirmationDialog(
|
||||
{
|
||||
size: "modal-lg",
|
||||
title: $__(
|
||||
"Update this request's status to <strong>%s</strong>?"
|
||||
).format(actionClicked),
|
||||
message: statusToUpdate.value.confirm_message,
|
||||
accept_label: $__("Confirm"),
|
||||
cancel_label: $__("Cancel"),
|
||||
inputs: getDialogInputs(),
|
||||
},
|
||||
(callback_result, inputFields) => {
|
||||
const client = APIClient.ill.supplying;
|
||||
inputFields.answerYesNo =
|
||||
inputFields.answerYesNo === true
|
||||
? "Y"
|
||||
: inputFields.answerYesNo === false
|
||||
? "N"
|
||||
: undefined;
|
||||
|
||||
client
|
||||
.patch(
|
||||
inputFields,
|
||||
iso18626_request.iso18626_request_id
|
||||
)
|
||||
.then(
|
||||
success => {
|
||||
for (const key in success) {
|
||||
if (iso18626_request.hasOwnProperty(key)) {
|
||||
iso18626_request[key] = success[key];
|
||||
}
|
||||
}
|
||||
setMessage(
|
||||
$__("ISO18626 request #%s updated").format(
|
||||
iso18626_request.iso18626_request_id
|
||||
),
|
||||
true
|
||||
);
|
||||
baseResource.refreshTemplateState();
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const getDialogInputs = inputValues => {
|
||||
if (inputValues && statusToUpdate.value.action_inputs) {
|
||||
for (const actionInput of statusToUpdate.value.action_inputs) {
|
||||
if (
|
||||
inputValues &&
|
||||
inputValues.hasOwnProperty(actionInput.name)
|
||||
) {
|
||||
actionInput.value = inputValues[actionInput.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inputValues && conditionalInputs.value) {
|
||||
for (const conditionalInput of conditionalInputs.value) {
|
||||
if (
|
||||
inputValues &&
|
||||
inputValues.hasOwnProperty(conditionalInput.name)
|
||||
) {
|
||||
conditionalInput.value =
|
||||
inputValues[conditionalInput.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
...(statusToUpdate.value.action_inputs
|
||||
? statusToUpdate.value.action_inputs
|
||||
: []),
|
||||
...(conditionalInputs.value ? conditionalInputs.value : []),
|
||||
{
|
||||
name: "messageInfoNote",
|
||||
type: "textarea",
|
||||
textAreaRows: 7,
|
||||
label: $__("Message note"),
|
||||
placeholder: $__(
|
||||
"Note to be sent to the requesting agency"
|
||||
),
|
||||
value:
|
||||
inputValues &&
|
||||
inputValues.hasOwnProperty("messageInfoNote")
|
||||
? inputValues.messageInfoNote
|
||||
: "",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
type: "hidden",
|
||||
value: action.value,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const additionalToolbarButtons = resource => {
|
||||
const show_buttons = [];
|
||||
const currentStatus = statuses.value.find(
|
||||
status => status.id === resource.status
|
||||
);
|
||||
if (currentStatus) {
|
||||
currentStatus.next_actions.forEach(nextStatus => {
|
||||
const nextStatusDef = statuses.value.find(
|
||||
status => status.id === nextStatus
|
||||
);
|
||||
|
||||
if (
|
||||
nextStatusDef.dont_show &&
|
||||
nextStatusDef.dont_show(resource)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
show_buttons.push({
|
||||
cssClass: nextStatusDef.btn_class,
|
||||
title: nextStatusDef.button_label,
|
||||
icon: nextStatusDef.icon,
|
||||
index: nextStatusDef.index,
|
||||
onClick: () =>
|
||||
progressRequest(nextStatusDef.id, resource),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show_buttons,
|
||||
};
|
||||
};
|
||||
|
||||
const defaultToolbarButtons = () => {
|
||||
return {
|
||||
list: [],
|
||||
show: [],
|
||||
};
|
||||
};
|
||||
|
||||
const baseResource = useBaseResource({
|
||||
resourceName: "iso18626_request",
|
||||
nameAttr: "iso18626_request_id",
|
||||
idAttr: "iso18626_request_id",
|
||||
components: {
|
||||
show: "SupplyingShow",
|
||||
list: "SupplyingList",
|
||||
},
|
||||
apiClient: APIClient.ill.supplying,
|
||||
additionalToolbarButtons,
|
||||
defaultToolbarButtons,
|
||||
i18n: {
|
||||
deleteConfirmationMessage: $__(
|
||||
"Are you sure you want to remove this supplying ILL?"
|
||||
),
|
||||
deleteSuccessMessage: $__("Supplying ILL %s deleted"),
|
||||
displayName: $__("Supplying ILL"),
|
||||
editLabel: $__("Edit supplying ILL #%s"),
|
||||
emptyListMessage: $__("There are no supplying ILLs defined"),
|
||||
newLabel: $__("New supplying ILL"),
|
||||
},
|
||||
table: {
|
||||
resourceTableUrl:
|
||||
APIClient.ill.httpClient._baseURL + "iso18626_requests",
|
||||
},
|
||||
resourceAttrs: [
|
||||
{
|
||||
name: "iso18626_request_id",
|
||||
label: $__("ID"),
|
||||
type: "text",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "supplyingAgencyId",
|
||||
label: $__("Supplying Agency ID"),
|
||||
type: "text",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "iso18626_requesting_agency_id",
|
||||
label: $__("Requesting Agency"),
|
||||
type: "relationshipSelect",
|
||||
showElement: {
|
||||
type: "text",
|
||||
value: "requesting_agency.name",
|
||||
link: {
|
||||
href: "/cgi-bin/koha/ill/iso18626_requesting_agencies",
|
||||
slug: "iso18626_requesting_agency_id",
|
||||
},
|
||||
},
|
||||
relationshipAPIClient: APIClient.ill.requesting_agencies,
|
||||
relationshipOptionLabelAttr: "name",
|
||||
relationshipRequiredKey: "iso18626_requesting_agency_id",
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
label: $__("Status"),
|
||||
type: "text",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "service_type",
|
||||
label: $__("Service type"),
|
||||
type: "text",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "pending_requesting_agency_action",
|
||||
label: $__("Pending RA action"),
|
||||
type: "text",
|
||||
hideIn: ["List", "Show", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "timestamp",
|
||||
label: $__("Last modified"),
|
||||
type: "date",
|
||||
hideIn: ["Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "requestingAgencyRequestId",
|
||||
label: $__("Requesting Agency Request ID"),
|
||||
type: "text",
|
||||
hideIn: ["List", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
group: $__("ISO18626 Messages"),
|
||||
name: "messages",
|
||||
label: "",
|
||||
type: "relationshipWidget",
|
||||
hideIn: ["List"],
|
||||
type: "component",
|
||||
columnData: "messages",
|
||||
hidden: iso18626_request => 1,
|
||||
showElement: {
|
||||
componentPath:
|
||||
"@koha-vue/components/ILL/ISO18626MessageDisplay.vue",
|
||||
componentProps: {
|
||||
iso18626_request: {
|
||||
type: "resource",
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
moduleStore: "ILLStore",
|
||||
props: props,
|
||||
});
|
||||
|
||||
const tableOptions = {
|
||||
url: () => tableUrl(),
|
||||
options: { embed: "requesting_agency,messages" },
|
||||
//table_settings: supplying_ill_table_settings, #FIXME: This causes error from datatables.js -> out of this scope
|
||||
table_settings: {
|
||||
columns: [
|
||||
{
|
||||
columnname: "iso18626_request_id",
|
||||
cannot_be_modified: 0,
|
||||
is_hidden: 0,
|
||||
cannot_be_toggled: 0,
|
||||
},
|
||||
{
|
||||
columnname: "supplyingAgencyId",
|
||||
is_hidden: 0,
|
||||
cannot_be_modified: 0,
|
||||
cannot_be_toggled: 0,
|
||||
},
|
||||
{
|
||||
is_hidden: 0,
|
||||
cannot_be_toggled: 0,
|
||||
cannot_be_modified: 0,
|
||||
columnname: "requestingAgencyId",
|
||||
},
|
||||
{
|
||||
is_hidden: 0,
|
||||
cannot_be_toggled: 0,
|
||||
cannot_be_modified: 0,
|
||||
columnname: "status",
|
||||
},
|
||||
{
|
||||
is_hidden: 0,
|
||||
cannot_be_modified: 0,
|
||||
cannot_be_toggled: 0,
|
||||
columnname: "timestamp",
|
||||
},
|
||||
{
|
||||
is_hidden: 0,
|
||||
cannot_be_toggled: 0,
|
||||
cannot_be_modified: 0,
|
||||
columnname: "requestingAgencyRequestId",
|
||||
},
|
||||
],
|
||||
default_display_length: null,
|
||||
table: "iso18626_requests",
|
||||
module: "ill",
|
||||
default_save_state: 1,
|
||||
page: "ill",
|
||||
default_sort_order: null,
|
||||
default_save_state_search: 0,
|
||||
},
|
||||
actions: {
|
||||
0: ["show"],
|
||||
1: [],
|
||||
"-1": [
|
||||
{
|
||||
receive: {
|
||||
text: $__("Manage request"),
|
||||
icon: "fa fa-pencil",
|
||||
should_display: row => 1,
|
||||
callback: ({ iso18626_request_id }, dt, event) => {
|
||||
event.preventDefault();
|
||||
router.push({
|
||||
name: "SupplyingShow",
|
||||
params: {
|
||||
iso18626_request_id:
|
||||
iso18626_request_id,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const afterResourceFetch = (componentData, resource, caller) => {
|
||||
if (caller === "show") {
|
||||
//TODO: Use dateformat sys pref?
|
||||
resource.timestamp = new Date(
|
||||
resource.timestamp
|
||||
).toLocaleString();
|
||||
}
|
||||
};
|
||||
|
||||
const onFormSave = (e, supplyingILLToSave) => {
|
||||
e.preventDefault();
|
||||
// Nothing to do here
|
||||
};
|
||||
const tableUrl = filters => {
|
||||
return baseResource.getResourceTableUrl();
|
||||
};
|
||||
|
||||
return {
|
||||
...baseResource,
|
||||
tableOptions,
|
||||
onFormSave,
|
||||
tableUrl,
|
||||
afterResourceFetch,
|
||||
};
|
||||
},
|
||||
emits: ["select-resource"],
|
||||
name: "SupplyingResource",
|
||||
components: {
|
||||
BaseResource,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -15,7 +15,9 @@
|
|||
>
|
||||
<slot />
|
||||
</a>
|
||||
<slot v-else />
|
||||
<template v-else v-html>
|
||||
<slot />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
<template>
|
||||
<WidgetWrapper v-bind="widgetWrapperProps">
|
||||
<template #default>
|
||||
<KohaTable
|
||||
ref="table"
|
||||
v-bind="tableOptions"
|
||||
:key="JSON.stringify(tableOptions)"
|
||||
@view="viewILLRequest"
|
||||
/>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="visitOldILLModule"
|
||||
>
|
||||
{{ visitOldILLModuleText }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</WidgetWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed } from "vue";
|
||||
import WidgetWrapper from "../WidgetWrapper.vue";
|
||||
import KohaTable from "../../KohaTable.vue";
|
||||
import { useBaseWidget } from "../../../composables/base-widget.js";
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export default {
|
||||
name: "ILLRequests",
|
||||
components: { WidgetWrapper, KohaTable },
|
||||
props: {
|
||||
display: String,
|
||||
dashboardColumn: String,
|
||||
},
|
||||
emits: ["removed", "added", "moveWidget"],
|
||||
setup(props, { emit }) {
|
||||
const table = ref();
|
||||
const default_settings = {
|
||||
//TODO: Grab logged in user, filter by user branch by default
|
||||
status: [], //["NEW", "UNAUTH"],
|
||||
per_page: 5,
|
||||
};
|
||||
const visitOldILLModuleText = $__(
|
||||
"Visit ILL requests (previously ILL Module)"
|
||||
);
|
||||
const settings = ref(default_settings);
|
||||
const settings_definitions = ref([
|
||||
{
|
||||
name: "status",
|
||||
type: "select",
|
||||
label: __("Status"),
|
||||
showInTable: true,
|
||||
options: settings.value.status.map(status => ({
|
||||
value: status.value,
|
||||
description: "my ets",
|
||||
})),
|
||||
allowMultipleChoices: true,
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
},
|
||||
{
|
||||
name: "per_page",
|
||||
type: "select",
|
||||
label: __("Show"),
|
||||
showInTable: true,
|
||||
options: [
|
||||
{ value: 5, description: "5" },
|
||||
{ value: 10, description: "10" },
|
||||
{ value: 20, description: "20" },
|
||||
],
|
||||
requiredKey: "value",
|
||||
selectLabel: "description",
|
||||
},
|
||||
]);
|
||||
|
||||
function settingsToQueryParams(settings) {
|
||||
const params = {};
|
||||
|
||||
if (settings.status && settings.status.length > 0) {
|
||||
params["me.status"] = {
|
||||
"-in": settings.status,
|
||||
};
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
const tableOptions = computed(() => ({
|
||||
columns: [
|
||||
{
|
||||
title: __("ID"),
|
||||
data: "ill_request_id",
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row, meta) {
|
||||
return (
|
||||
'<a target="_blank" href="/cgi-bin/koha/ill/ill-requests.pl?' +
|
||||
"op=illview&illrequest_id=" +
|
||||
encodeURIComponent(data) +
|
||||
'">' +
|
||||
escape_str(row.id_prefix) +
|
||||
escape_str(data) +
|
||||
"</a>"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: __("Status"),
|
||||
data: "_strings.status.str",
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
},
|
||||
{
|
||||
title: __("Library"),
|
||||
data: "library.name",
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
},
|
||||
{
|
||||
title: __("Patron"),
|
||||
data: "patron.firstname:patron.surname:patron.cardnumber",
|
||||
render: function (data, type, row, meta) {
|
||||
return row.patron
|
||||
? $patron_to_html(row.patron, {
|
||||
display_cardnumber: true,
|
||||
url: true,
|
||||
})
|
||||
: "";
|
||||
},
|
||||
},
|
||||
{
|
||||
title: __("Backend"),
|
||||
data: "ill_backend_id",
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
dom: "t",
|
||||
embed: "patron,library,extended_attributes,+strings",
|
||||
pageLength: settings.value.per_page || 5,
|
||||
processing: false,
|
||||
},
|
||||
url: "/api/v1/ill/requests",
|
||||
default_filters: settingsToQueryParams(settings.value),
|
||||
actions: {
|
||||
"-1": [
|
||||
{
|
||||
view: {
|
||||
text: $__("View"),
|
||||
icon: "fa fa-eye",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
const baseWidget = useBaseWidget(
|
||||
{
|
||||
id: "ILLRequests",
|
||||
name: $__("ILL Requests"),
|
||||
icon: "fa fa-download",
|
||||
description: $__(
|
||||
"Show ILL requests that need action. It filters requests by status and library. Provides a button to visit the ILL requests (previously ILL Module). This widget is configurable."
|
||||
),
|
||||
loading: false,
|
||||
settings: settings,
|
||||
settings_definitions: settings_definitions,
|
||||
...props,
|
||||
},
|
||||
emit
|
||||
);
|
||||
|
||||
function viewILLRequest(req, dt, event) {
|
||||
event.preventDefault();
|
||||
window.open(
|
||||
"/cgi-bin/koha/ill/ill-requests.pl?op=illview&illrequest_id=" +
|
||||
encodeURIComponent(req.ill_request_id),
|
||||
"_blank"
|
||||
);
|
||||
}
|
||||
|
||||
function visitOldILLModule() {
|
||||
const url = "/cgi-bin/koha/ill/ill-requests.pl";
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
return {
|
||||
...baseWidget,
|
||||
table,
|
||||
tableOptions,
|
||||
viewILLRequest,
|
||||
visitOldILLModuleText,
|
||||
visitOldILLModule,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import HttpClient from "./http-client";
|
||||
|
||||
import ERMAPIClient from "@fetch/erm-api-client";
|
||||
import ILLAPIClient from "@fetch/ill-api-client";
|
||||
import PatronAPIClient from "@fetch/patron-api-client";
|
||||
import AcquisitionAPIClient from "@fetch/acquisition-api-client";
|
||||
import AdditionalFieldsAPIClient from "@fetch/additional-fields-api-client";
|
||||
|
|
@ -14,6 +15,7 @@ import PreservationAPIClient from "@fetch/preservation-api-client";
|
|||
|
||||
export const APIClient = {
|
||||
erm: new ERMAPIClient(HttpClient),
|
||||
ill: new ILLAPIClient(HttpClient),
|
||||
patron: new PatronAPIClient(HttpClient),
|
||||
acquisition: new AcquisitionAPIClient(HttpClient),
|
||||
additional_fields: new AdditionalFieldsAPIClient(HttpClient),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
import { createApp } from "vue";
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import { createPinia } from "pinia";
|
||||
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faList,
|
||||
faPlus,
|
||||
faMinus,
|
||||
faPencil,
|
||||
faTrash,
|
||||
faSpinner,
|
||||
faGlobe,
|
||||
faUpload,
|
||||
faDownload,
|
||||
faBuildingColumns,
|
||||
faCheck,
|
||||
faXmark,
|
||||
faRepeat,
|
||||
faBox,
|
||||
faCalendarDays,
|
||||
faBan,
|
||||
faCog,
|
||||
faEllipsisVertical,
|
||||
faArrowRight,
|
||||
faArrowLeft,
|
||||
faArrowUp,
|
||||
faArrowDown,
|
||||
faSearch,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import vSelect from "vue-select";
|
||||
|
||||
library.add(
|
||||
faList,
|
||||
faPlus,
|
||||
faMinus,
|
||||
faPencil,
|
||||
faTrash,
|
||||
faSpinner,
|
||||
faGlobe,
|
||||
faUpload,
|
||||
faDownload,
|
||||
faBuildingColumns,
|
||||
faCheck,
|
||||
faXmark,
|
||||
faRepeat,
|
||||
faBox,
|
||||
faCalendarDays,
|
||||
faBan,
|
||||
faCog,
|
||||
faEllipsisVertical,
|
||||
faArrowRight,
|
||||
faArrowLeft,
|
||||
faArrowUp,
|
||||
faArrowDown,
|
||||
faSearch
|
||||
);
|
||||
|
||||
import App from "../components/ILL/Main.vue";
|
||||
|
||||
import { routes as routesDef } from "../routes/ill";
|
||||
|
||||
import { useMainStore } from "../stores/main";
|
||||
import { useVendorStore } from "../stores/vendors";
|
||||
import { useILLStore } from "../stores/ill";
|
||||
import { useNavigationStore } from "../stores/navigation";
|
||||
import i18n from "@koha-vue/i18n";
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
const mainStore = useMainStore(pinia);
|
||||
const navigationStore = useNavigationStore(pinia);
|
||||
const routes = navigationStore.setRoutes(routesDef);
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
linkActiveClass: "current",
|
||||
routes,
|
||||
});
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
const rootComponent = app
|
||||
.use(i18n)
|
||||
.use(pinia)
|
||||
.use(router)
|
||||
.component("font-awesome-icon", FontAwesomeIcon)
|
||||
.component("v-select", vSelect);
|
||||
|
||||
app.config.unwrapInjectedRef = true;
|
||||
app.provide("vendorStore", useVendorStore(pinia));
|
||||
app.provide("mainStore", mainStore);
|
||||
app.provide("navigationStore", navigationStore);
|
||||
const ILLStore = useILLStore(pinia);
|
||||
app.provide("ILLStore", ILLStore);
|
||||
|
||||
const { removeMessages } = mainStore;
|
||||
router.beforeEach((to, from) => {
|
||||
navigationStore.$patch({
|
||||
current: to.matched,
|
||||
params: to.params || {},
|
||||
from,
|
||||
});
|
||||
removeMessages();
|
||||
});
|
||||
|
||||
router.isReady().then(() => {
|
||||
app.mount("#ill");
|
||||
});
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { markRaw } from "vue";
|
||||
|
||||
import Home from "../components/ILL/Home.vue";
|
||||
import ProgressRequest from "../components/ILL/ProgressRequest.vue";
|
||||
import ResourceWrapper from "../components/ResourceWrapper.vue";
|
||||
|
||||
import { $__ } from "@koha-vue/i18n";
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/ill.pl",
|
||||
redirect: "/cgi-bin/koha/ill/home",
|
||||
is_default: true,
|
||||
is_base: true,
|
||||
title: $__("Interlibrary loans"),
|
||||
children: [
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/home",
|
||||
name: "Home",
|
||||
component: markRaw(Home),
|
||||
title: $__("Home"),
|
||||
icon: "fa fa-home",
|
||||
},
|
||||
{
|
||||
path: "/cgi-bin/koha/ill",
|
||||
title: $__("Borrowing"),
|
||||
icon: "fa fa-arrow-circle-down",
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/ill-requests.pl",
|
||||
title: $__("Requests"),
|
||||
icon: "fa fa-download",
|
||||
is_external: true,
|
||||
is_navigation_item: true,
|
||||
},
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/ill-requests.pl?method=batch_list",
|
||||
title: $__("Batches"),
|
||||
icon: "fa fa-clone",
|
||||
is_external: true,
|
||||
is_navigation_item: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/cgi-bin/koha/ill",
|
||||
title: $__("Lending"),
|
||||
icon: "fa fa-arrow-circle-up",
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/iso18626_requests",
|
||||
title: $__("Supplying ILLs"),
|
||||
icon: "fa fa-upload",
|
||||
is_end_node: true,
|
||||
resource: "ILL/SupplyingResource.vue",
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "SupplyingList",
|
||||
component: markRaw(ResourceWrapper),
|
||||
},
|
||||
{
|
||||
path: ":iso18626_request_id",
|
||||
name: "SupplyingShow",
|
||||
component: markRaw(ResourceWrapper),
|
||||
title: "{iso18626_request_id}",
|
||||
},
|
||||
{
|
||||
path: "progress-request/:iso18626_request_id",
|
||||
name: "ProgressRequest",
|
||||
component: markRaw(ProgressRequest),
|
||||
title: $__(
|
||||
"Progress request {iso18626_request_id}"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/cgi-bin/koha/ill/iso18626_requesting_agencies",
|
||||
title: $__("Requesting Agencies"),
|
||||
icon: "fa fa-building-columns",
|
||||
is_end_node: true,
|
||||
resource: "ILL/RequestingAgencyResource.vue",
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "RequestingAgenciesList",
|
||||
component: markRaw(ResourceWrapper),
|
||||
},
|
||||
{
|
||||
path: ":iso18626_requesting_agency_id",
|
||||
name: "RequestingAgenciesShow",
|
||||
component: markRaw(ResourceWrapper),
|
||||
title: "{name}",
|
||||
},
|
||||
{
|
||||
path: "add",
|
||||
name: "RequestingAgenciesFormAdd",
|
||||
component: markRaw(ResourceWrapper),
|
||||
title: $__("Add requesting agency"),
|
||||
},
|
||||
{
|
||||
path: "edit/:iso18626_requesting_agency_id",
|
||||
name: "RequestingAgenciesFormAddEdit",
|
||||
component: markRaw(ResourceWrapper),
|
||||
title: "{name}",
|
||||
breadcrumbFormat: ({
|
||||
match,
|
||||
params,
|
||||
query,
|
||||
}) => {
|
||||
match.name = "RequestingAgenciesShow";
|
||||
return match;
|
||||
},
|
||||
additionalBreadcrumbs: [
|
||||
{
|
||||
title: $__("Modify requesting agency"),
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { reactive, toRefs } from "vue";
|
||||
|
||||
export const useILLStore = defineStore("ill", () => {
|
||||
const store = reactive({
|
||||
config: {
|
||||
settings: {
|
||||
ILLModule: 1,
|
||||
ILLPartnerCode: "IL",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...toRefs(store),
|
||||
};
|
||||
});
|
||||
|
|
@ -133,6 +133,10 @@ module.exports = [
|
|||
"./koha-tmpl/intranet-tmpl/prog/js/vue/csp-nonce.js",
|
||||
"./koha-tmpl/intranet-tmpl/prog/js/vue/modules/sip2.ts",
|
||||
],
|
||||
ill: [
|
||||
"./koha-tmpl/intranet-tmpl/prog/js/vue/csp-nonce.js",
|
||||
"./koha-tmpl/intranet-tmpl/prog/js/vue/modules/ill.ts",
|
||||
],
|
||||
},
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
|
|
|
|||
Loading…
Reference in New Issue