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