Bug 30708: Duplicate/copy items to an opened train
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / vue / components / Preservation / TrainsShow.vue
1 <template>
2     <transition name="modal">
3         <div v-if="show_modal" class="modal">
4             <h2>{{ $__("Copy item to the following train") }}</h2>
5             <form @submit="copyItem($event)">
6                 <div class="page-section">
7                     <fieldset class="rows">
8                         <ol>
9                             <li>
10                                 <label class="required" for="train_list"
11                                     >{{ $__("Select a train") }}:</label
12                                 >
13                                 <v-select
14                                     v-model="train_id_selected_for_copy"
15                                     label="name"
16                                     :options="train_list"
17                                     :reduce="t => t.train_id"
18                                 >
19                                     <template #search="{ attributes, events }">
20                                         <input
21                                             :required="
22                                                 !train_id_selected_for_copy
23                                             "
24                                             class="vs__search"
25                                             v-bind="attributes"
26                                             v-on="events"
27                                         />
28                                     </template>
29                                 </v-select>
30                                 <span class="required">{{
31                                     $__("Required")
32                                 }}</span>
33                             </li>
34                         </ol>
35                     </fieldset>
36                     <fieldset class="action">
37                         <input type="submit" value="Copy" />
38                         <input
39                             type="button"
40                             @click="show_modal = false"
41                             :value="$__('Close')"
42                         />
43                     </fieldset>
44                 </div>
45             </form>
46         </div>
47     </transition>
48     <div v-if="!initialized">{{ $__("Loading") }}</div>
49     <div v-else id="trains_show">
50         <div id="toolbar" class="btn-toolbar">
51             <router-link
52                 :to="`/cgi-bin/koha/preservation/trains/${train.train_id}/items/add`"
53                 class="btn btn-default"
54                 ><font-awesome-icon icon="plus" />
55                 {{ $__("Add items") }}</router-link
56             >
57             <router-link
58                 :to="`/cgi-bin/koha/preservation/trains/edit/${train.train_id}`"
59                 class="btn btn-default"
60                 ><font-awesome-icon icon="pencil" />
61                 {{ $__("Edit") }}</router-link
62             >
63             <a @click="deleteTrain(train)" class="btn btn-default"
64                 ><font-awesome-icon icon="trash" /> {{ $__("Delete") }}</a
65             >
66             <a
67                 v-if="!train.closed_on"
68                 class="btn btn-default"
69                 @click="closeTrain"
70                 ><font-awesome-icon icon="remove" /> {{ $__("Close") }}</a
71             >
72             <a
73                 v-else-if="!train.sent_on"
74                 class="btn btn-default"
75                 @click="sendTrain"
76                 ><font-awesome-icon icon="paper-plane" /> {{ $__("Send") }}</a
77             >
78             <a
79                 v-else-if="!train.received_on"
80                 class="btn btn-default"
81                 @click="receiveTrain"
82                 ><font-awesome-icon icon="inbox" /> {{ $__("Receive") }}</a
83             >
84         </div>
85         <h2>
86             {{ $__("Train #%s").format(train.train_id) }}
87         </h2>
88         <div>
89             <fieldset class="rows">
90                 <ol>
91                     <li>
92                         <label>{{ $__("Name") }}:</label>
93                         <span>
94                             {{ train.name }}
95                         </span>
96                     </li>
97                     <li>
98                         <label>{{ $__("Description") }}:</label>
99                         <span>
100                             {{ train.description }}
101                         </span>
102                     </li>
103                     <li v-if="train.closed_on">
104                         <label>{{ $__("Closed on") }}:</label>
105                         <span>
106                             {{ format_date(train.closed_on) }}
107                         </span>
108                     </li>
109                     <li v-if="train.sent_on">
110                         <label>{{ $__("Sent on") }}:</label>
111                         <span>
112                             {{ format_date(train.sent_on) }}
113                         </span>
114                     </li>
115                     <li v-if="train.received_on">
116                         <label>{{ $__("Received on") }}:</label>
117                         <span>
118                             {{ format_date(train.received_on) }}
119                         </span>
120                     </li>
121                     <li>
122                         <label
123                             >{{
124                                 $__("Status for item added to this train")
125                             }}:</label
126                         >
127                         <span>{{
128                             get_lib_from_av("av_notforloan", train.not_for_loan)
129                         }}</span>
130                     </li>
131                     <li>
132                         <label>{{ $__("Default processing") }}:</label>
133                         <span>
134                             {{ train.default_processing.name }}
135                         </span>
136                     </li>
137                 </ol>
138             </fieldset>
139             <fieldset v-if="train.items.length" class="rows">
140                 <legend>{{ $__("Items") }}</legend>
141                 <table v-if="item_table.display" :id="table_id"></table>
142                 <ol v-else>
143                     <li
144                         :id="`item_${counter}`"
145                         class="rows"
146                         v-for="(item, counter) in train.items"
147                         v-bind:key="counter"
148                     >
149                         <label
150                             >{{ item.user_train_item_id }}
151                             <span class="action_links">
152                                 <router-link
153                                     :to="`/cgi-bin/koha/preservation/trains/${train.train_id}/items/edit/${item.train_item_id}`"
154                                     :title="$__('Edit')"
155                                     ><i class="fa fa-pencil"></i></router-link
156                             ></span>
157                         </label>
158                         <div class="attributes_values">
159                             <span
160                                 :id="`attribute_${counter_attribute}`"
161                                 class="attribute_value"
162                                 v-for="(
163                                     attribute, counter_attribute
164                                 ) in item.attributes"
165                                 v-bind:key="counter_attribute"
166                             >
167                                 <!-- FIXME We need to display the description of the AV here -->
168                                 {{ attribute.processing_attribute.name }}={{
169                                     attribute.value
170                                 }}
171                             </span>
172                         </div>
173                     </li>
174                 </ol>
175             </fieldset>
176             <fieldset class="action">
177                 <router-link
178                     to="/cgi-bin/koha/preservation/trains"
179                     role="button"
180                     class="cancel"
181                     >{{ $__("Close") }}</router-link
182                 >
183             </fieldset>
184         </div>
185     </div>
186 </template>
187
188 <script>
189 import { inject, createVNode, render } from "vue"
190 import { APIClient } from "../../fetch/api-client"
191 import { useDataTable } from "../../composables/datatables"
192
193 export default {
194     setup() {
195         const format_date = $date
196
197         const AVStore = inject("AVStore")
198         const { get_lib_from_av } = AVStore
199
200         const { setConfirmationDialog, setMessage } = inject("mainStore")
201
202         const table_id = "item_list"
203         useDataTable(table_id)
204
205         return {
206             format_date,
207             get_lib_from_av,
208             table_id,
209             setConfirmationDialog,
210             setMessage,
211         }
212     },
213     data() {
214         return {
215             train: {
216                 train_id: null,
217                 name: "",
218                 description: "",
219             },
220             initialized: false,
221             show_modal: false,
222             item_table: {
223                 display: false,
224                 data: [],
225                 columns: [],
226             },
227             train_list: [],
228             train_id_selected_for_copy: null,
229             train_item_id_to_copy: null,
230         }
231     },
232     beforeRouteEnter(to, from, next) {
233         next(vm => {
234             vm.getTrain(to.params.train_id).then(() => vm.build_datatable())
235             vm.getTrainList()
236         })
237     },
238     methods: {
239         async getTrain(train_id) {
240             const client = APIClient.preservation
241             await client.trains.get(train_id).then(
242                 train => {
243                     this.train = train
244                     let display = this.train.items.every(
245                         item =>
246                             item.processing_id ==
247                             this.train.default_processing_id
248                     )
249                     if (display) {
250                         this.item_table.data = []
251                         this.train.items.forEach(item => {
252                             let item_row = {}
253                             this.train.default_processing.attributes.forEach(
254                                 attribute => {
255                                     let v = ""
256                                     if (item.attributes.length >= 0) {
257                                         let a = item.attributes.find(
258                                             a =>
259                                                 a.processing_attribute_id ==
260                                                 attribute.processing_attribute_id
261                                         )
262                                         if (a) {
263                                             v = a.value
264                                         }
265                                     }
266
267                                     item_row[
268                                         attribute.processing_attribute_id
269                                     ] = v
270                                 }
271                             )
272                             item_row.item = item
273                             this.item_table.data.push(item_row)
274                         })
275                         this.item_table.columns = []
276                         this.item_table.columns.push({
277                             name: "",
278                             title: this.$__("ID"),
279                             data: "item.user_train_item_id",
280                         })
281                         train.default_processing.attributes.forEach(a =>
282                             this.item_table.columns.push({
283                                 name: a.name,
284                                 title: a.name,
285                                 data: a.processing_attribute_id,
286                             })
287                         )
288                         this.item_table.columns.push({
289                             name: "actions",
290                             className: "actions noExport",
291                             title: this.$__("Actions"),
292                             searchable: false,
293                             orderable: false,
294                             render: (data, type, row) => {
295                                 return ""
296                             },
297                         })
298                     }
299                     this.initialized = true
300                     this.item_table.display = display
301                 },
302                 error => {}
303             )
304         },
305         getTrainList: function () {
306             const client = APIClient.preservation
307             let q = { "me.closed_on": null }
308             client.trains.getAll(q).then(
309                 trains => (this.train_list = trains),
310                 error => {}
311             )
312         },
313         deleteTrain: function (train) {
314             this.setConfirmationDialog(
315                 {
316                     title: this.$__(
317                         "Are you sure you want to remove this train?"
318                     ),
319                     message: train.name,
320                     accept_label: this.$__("Yes, delete"),
321                     cancel_label: this.$__("No, do not delete"),
322                 },
323                 () => {
324                     const client = APIClient.preservation
325                     client.trains.delete(train.train_id).then(
326                         success => {
327                             this.setMessage(
328                                 this.$__("Train %s deleted").format(train.name),
329                                 true
330                             )
331                         },
332                         error => {}
333                     )
334                 }
335             )
336         },
337         async updateTrainDate(attribute) {
338             let train = JSON.parse(JSON.stringify(this.train))
339             let train_id = train.train_id
340             delete train.train_id
341             delete train.items
342             delete train.default_processing
343             train[attribute] = new Date()
344             const client = APIClient.preservation
345             if (train_id) {
346                 return client.trains
347                     .update(train, train_id)
348                     .then(() => this.getTrain(this.train.train_id))
349             } else {
350                 return client.trains
351                     .create(train)
352                     .then(() => this.getTrain(this.train.train_id))
353             }
354         },
355         closeTrain() {
356             this.updateTrainDate("closed_on")
357         },
358         sendTrain() {
359             this.updateTrainDate("sent_on")
360         },
361         receiveTrain() {
362             this.updateTrainDate("received_on").then(
363                 success => {
364                     // Rebuild the table to show the "copy" button
365                     $("#" + this.table_id)
366                         .DataTable()
367                         .destroy()
368                     this.build_datatable()
369                 },
370                 error => {}
371             )
372         },
373         editItem(train_item_id) {
374             this.$router.push(
375                 `/cgi-bin/koha/preservation/trains/${this.train.train_id}/items/edit/${train_item_id}`
376             )
377         },
378         removeItem(train_item_id) {
379             this.setConfirmationDialog(
380                 {
381                     title: this.$__(
382                         "Are you sure you want to remove this item?"
383                     ),
384                     accept_label: this.$__("Yes, remove"),
385                     cancel_label: this.$__("No, do not remove"),
386                 },
387                 () => {
388                     const client = APIClient.preservation
389                     client.train_items
390                         .delete(this.train.train_id, train_item_id)
391                         .then(
392                             success => {
393                                 this.setMessage(this.$__("Item removed"), true)
394                                 this.getTrain(this.train.train_id).then(() => {
395                                     $("#" + this.table_id)
396                                         .DataTable()
397                                         .destroy()
398                                     this.build_datatable()
399                                 })
400                             },
401                             error => {}
402                         )
403                 }
404             )
405         },
406         selectTrainForCopy(train_item_id) {
407             this.show_modal = true
408             this.train_item_id_to_copy = train_item_id
409         },
410         copyItem(event) {
411             event.preventDefault()
412             const client = APIClient.preservation
413             client.train_items
414                 .copy(
415                     this.train_id_selected_for_copy,
416                     this.train.train_id,
417                     this.train_item_id_to_copy
418                 )
419                 .then(
420                     success => {
421                         this.setMessage(this.$__("Item copied successfully."))
422                         this.show_modal = false
423                     },
424                     error => {}
425                 )
426         },
427         build_datatable: function () {
428             let table_id = this.table_id
429             let item_table = this.item_table
430             let removeItem = this.removeItem
431             let editItem = this.editItem
432             let selectTrainForCopy = this.selectTrainForCopy
433             let train = this.train
434
435             let table = KohaTable(table_id, {
436                 data: item_table.data,
437                 ordering: false,
438                 autoWidth: false,
439                 columns: item_table.columns,
440                 drawCallback: function (settings) {
441                     var api = new $.fn.dataTable.Api(settings)
442                     $.each($(this).find("td.actions"), function (index, e) {
443                         let tr = $(this).parent()
444                         let train_item_id = api.row(tr).data()
445                             .item.train_item_id
446
447                         let editButton = createVNode(
448                             "a",
449                             {
450                                 class: "btn btn-default btn-xs",
451                                 role: "button",
452                                 onClick: () => {
453                                     editItem(train_item_id)
454                                 },
455                             },
456                             [
457                                 createVNode("i", {
458                                     class: "fa fa-pencil",
459                                     "aria-hidden": "true",
460                                 }),
461                                 __("Edit"),
462                             ]
463                         )
464
465                         let removeButton = createVNode(
466                             "a",
467                             {
468                                 class: "btn btn-default btn-xs",
469                                 role: "button",
470                                 onClick: () => {
471                                     removeItem(train_item_id)
472                                 },
473                             },
474                             [
475                                 createVNode("i", {
476                                     class: "fa fa-trash",
477                                     "aria-hidden": "true",
478                                 }),
479                                 __("Remove"),
480                             ]
481                         )
482                         let buttons = [editButton, "", removeButton]
483
484                         if (train.received_on !== null) {
485                             buttons.push("")
486                             buttons.push(
487                                 createVNode(
488                                     "a",
489                                     {
490                                         class: "btn btn-default btn-xs",
491                                         role: "button",
492                                         onClick: () => {
493                                             selectTrainForCopy(train_item_id)
494                                         },
495                                     },
496                                     [
497                                         createVNode("i", {
498                                             class: "fa fa-copy",
499                                             "aria-hidden": "true",
500                                         }),
501                                         __("Copy"),
502                                     ]
503                                 )
504                             )
505                         }
506
507                         let n = createVNode("span", {}, buttons)
508                         render(n, e)
509                     })
510                 },
511             })
512         },
513     },
514     name: "TrainsShow",
515 }
516 </script>
517 <style scoped>
518 .action_links a {
519     padding-left: 0.2em;
520     font-size: 11px;
521 }
522 .attributes_values {
523     float: left;
524 }
525 .attribute_value {
526     display: block;
527 }
528 .modal {
529     position: fixed;
530     z-index: 9998;
531     top: 0;
532     left: 0;
533     width: 35%;
534     height: 30%;
535     background-color: rgba(0, 0, 0, 0.5);
536     display: table;
537     transition: opacity 0.3s ease;
538     margin: auto;
539     padding: 20px 30px;
540     background-color: #fff;
541     border-radius: 2px;
542     box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
543     transition: all 0.3s ease;
544 }
545 </style>