]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/booking/create-reservation-dialog.component.ts
LP2061136 - Stamping 1405 DB upgrade script
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / booking / create-reservation-dialog.component.ts
1 import {Component, Input, Output, OnInit, ViewChild, EventEmitter} from '@angular/core';
2 import {FormGroup, FormControl, Validators} from '@angular/forms';
3 import {Router} from '@angular/router';
4 import {Observable, of} from 'rxjs';
5 import {switchMap, single, startWith, tap} from 'rxjs/operators';
6 import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
7 import {AuthService} from '@eg/core/auth.service';
8 import {FormatService} from '@eg/core/format.service';
9 import {IdlObject} from '@eg/core/idl.service';
10 import {NetService} from '@eg/core/net.service';
11 import {OrgService} from '@eg/core/org.service';
12 import {PcrudService} from '@eg/core/pcrud.service';
13 import {DialogComponent} from '@eg/share/dialog/dialog.component';
14 import {notBeforeMomentValidator} from '@eg/share/validators/not_before_moment_validator.directive';
15 import {PatronBarcodeValidator} from '@eg/share/validators/patron_barcode_validator.directive';
16 import {PatronSearchDialogComponent} from '@eg/staff/share/patron/search-dialog.component';
17 import {ToastService} from '@eg/share/toast/toast.service';
18 import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
19 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
20 import * as moment from 'moment-timezone';
21 import { datesInOrderValidator } from '@eg/share/validators/dates_in_order_validator.directive';
22
23 @Component({
24     selector: 'eg-create-reservation-dialog',
25     templateUrl: './create-reservation-dialog.component.html'
26 })
27
28 export class CreateReservationDialogComponent
29     extends DialogComponent implements OnInit {
30
31     @Input() targetResource: number;
32     @Input() targetResourceBarcode: string;
33     @Input() targetResourceType: ComboboxEntry;
34     @Input() patronId: number;
35     @Input() attributes: number[] = [];
36     @Input() resources: IdlObject[] = [];
37     @Output() reservationRequestCompleted: EventEmitter<boolean>;
38
39     create: FormGroup;
40     patron$: Observable<{first_given_name: string, second_given_name: string, family_name: string}>;
41     pickupLibId: number;
42     timezone: string = this.format.wsOrgTimezone;
43     pickupLibraryUsesDifferentTz: boolean;
44
45     public disableOrgs: () => number[];
46     addBresv$: () => Observable<any>;
47     @ViewChild('fail', { static: true }) fail: AlertDialogComponent;
48     @ViewChild('patronSearch') patronSearch: PatronSearchDialogComponent;
49
50     handlePickupLibChange: ($event: IdlObject) => void;
51
52     constructor(
53         private auth: AuthService,
54         private format: FormatService,
55         private net: NetService,
56         private org: OrgService,
57         private pcrud: PcrudService,
58         private router: Router,
59         private modal: NgbModal,
60         private pbv: PatronBarcodeValidator,
61         private toast: ToastService
62     ) {
63         super(modal);
64         this.reservationRequestCompleted = new EventEmitter<boolean>();
65     }
66
67     ngOnInit() {
68
69         this.create = new FormGroup({
70             'patronBarcode': new FormControl('',
71                 [Validators.required],
72                 [this.pbv.validate]
73             ),
74             'emailNotify': new FormControl(true),
75             'startTime': new FormControl(null, notBeforeMomentValidator(moment().add('15', 'minutes'))),
76             'endTime': new FormControl(),
77             'resourceList': new FormControl(),
78             'note': new FormControl(),
79         }, [datesInOrderValidator(['startTime', 'endTime'])]
80         );
81         if (this.patronId) {
82             this.pcrud.search('au', {id: this.patronId}, {
83                 flesh: 1,
84                 flesh_fields: {'au': ['card']}
85             }).subscribe((usr) =>
86                 this.create.patchValue({patronBarcode: usr.card().barcode()})
87             );
88         }
89
90         this.addBresv$ = () => {
91             let selectedResourceId = this.targetResource ? [this.targetResource] : null;
92             if (!selectedResourceId &&
93                 this.resourceListSelection !== null &&
94                 'any' !== this.resourceListSelection.id) {
95                 selectedResourceId = [this.resourceListSelection.id];
96             }
97             return this.net.request(
98                 'open-ils.booking',
99                 'open-ils.booking.reservations.create',
100                 this.auth.token(),
101                 this.patronBarcode.value.trim(),
102                 this.selectedTimes,
103                 this.pickupLibId,
104                 this.targetResourceType.id,
105                 selectedResourceId,
106                 this.attributes.filter(Boolean),
107                 this.emailNotify,
108                 this.bresvNote
109             ).pipe(tap({
110                 next: (response) => {
111                     if ('ilsevent' in response) {
112                         console.warn(response);
113                         this.fail.open();
114                     } else {
115                         this.toast.success('Reservation successfully created');
116                         console.debug(response);
117                         this.close();
118                     }
119                 }, error: (response: unknown) => {
120                     console.warn(response);
121                     this.fail.open();
122                 }, complete: () => this.reservationRequestCompleted.emit(true)
123             }));
124         };
125
126         this.handlePickupLibChange = ($event) => {
127             this.pickupLibId = $event.id();
128             this.org.settings('lib.timezone', this.pickupLibId).then((tz) => {
129                 this.timezone = tz['lib.timezone'] || this.format.wsOrgTimezone;
130                 this.pickupLibraryUsesDifferentTz = (tz['lib.timezone'] && (this.format.wsOrgTimezone !== tz['lib.timezone']));
131             });
132         };
133
134         this.disableOrgs = () => this.org.filterList( { canHaveVolumes : false }, true);
135
136         this.patron$ = this.patronBarcode.statusChanges.pipe(
137             startWith({first_given_name: '', second_given_name: '', family_name: ''}),
138             switchMap(() => {
139                 if ('VALID' === this.patronBarcode.status) {
140                     return this.net.request(
141                         'open-ils.actor',
142                         'open-ils.actor.get_barcodes',
143                         this.auth.token(),
144                         this.auth.user().ws_ou(),
145                         'actor', this.patronBarcode.value.trim()).pipe(
146                         single(),
147                         switchMap((result) => {
148                             return this.pcrud.retrieve('au', result[0]['id']).pipe(
149                                 switchMap((au) => {
150                                     return of({
151                                         first_given_name: au.first_given_name(),
152                                         second_given_name: au.second_given_name(),
153                                         family_name: au.family_name()});
154                                 })
155                             );
156                         })
157                     );
158                 } else {
159                     return of({
160                         first_given_name: '',
161                         second_given_name: '',
162                         family_name: ''
163                     });
164                 }
165             })
166         );
167     }
168
169     setDefaultTimes(times: moment.Moment[], granularity: number) {
170         this.create.patchValue({startTime: moment.min(times),
171             endTime: moment.max(times).clone().add(granularity, 'minutes')
172         });
173     }
174
175     openPatronReservations = (): void => {
176         this.net.request(
177             'open-ils.actor',
178             'open-ils.actor.get_barcodes',
179             this.auth.token(),
180             this.auth.user().ws_ou(),
181             'actor', this.patronBarcode.value
182         ).subscribe((patron) => this.router.navigate(['/staff', 'booking', 'manage_reservations', 'by_patron', patron[0]['id']]));
183     };
184
185     addBresvAndOpenPatronReservations = (): void => {
186         this.addBresv$()
187             .subscribe(() => this.openPatronReservations());
188     };
189
190     searchPatrons() {
191         this.patronSearch.open({size: 'xl'}).toPromise().then(
192             patrons => {
193                 if (!patrons || patrons.length === 0) { return; }
194                 const user = patrons[0];
195                 this.create.patchValue({patronBarcode: user.card().barcode()});
196             }
197         );
198     }
199
200     get emailNotify() {
201         return this.create.get('emailNotify').value;
202     }
203
204     get bresvNote() {
205         return this.create.get('note').value;
206     }
207
208     get patronBarcode() {
209         return this.create.get('patronBarcode');
210     }
211
212     get resourceListSelection() {
213         return this.create.get('resourceList').value;
214     }
215
216     get selectedTimes() {
217         return [this.create.get('startTime').value.toISOString(),
218             this.create.get('endTime').value.toISOString()];
219     }
220 }
221