]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/share/circ/route-dialog.component.ts
LP1904036 Route dialog autoprint race condition repair
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / share / circ / route-dialog.component.ts
1 import {Component, OnInit, Output, Input, ViewChild, EventEmitter} from '@angular/core';
2 import {empty, of, from, Observable} from 'rxjs';
3 import {tap, concatMap} from 'rxjs/operators';
4 import {IdlService, IdlObject} from '@eg/core/idl.service';
5 import {PcrudService} from '@eg/core/pcrud.service';
6 import {OrgService} from '@eg/core/org.service';
7 import {CircService} from './circ.service';
8 import {StringComponent} from '@eg/share/string/string.component';
9 import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
10 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
11 import {DialogComponent} from '@eg/share/dialog/dialog.component';
12 import {CheckinResult} from './circ.service';
13 import {ServerStoreService} from '@eg/core/server-store.service';
14 import {PrintService} from '@eg/share/print/print.service';
15
16 /** Route Item Dialog */
17
18 @Component({
19   templateUrl: 'route-dialog.component.html',
20   selector: 'eg-circ-route-dialog'
21 })
22 export class RouteDialogComponent extends DialogComponent {
23
24     checkin: CheckinResult;
25     noAutoPrint: {[template: string]: boolean} = {};
26     slip: string;
27     today = new Date();
28
29     constructor(
30         private modal: NgbModal,
31         private pcrud: PcrudService,
32         private org: OrgService,
33         private circ: CircService,
34         private printer: PrintService,
35         private serverStore: ServerStoreService) {
36         super(modal);
37     }
38
39     open(ops?: NgbModalOptions): Observable<any> {
40         // Depending on various settings, the dialog may never open.
41         // But in some cases we still have to collect the data
42         // for printing.
43
44         return from(this.applySettings())
45
46         .pipe(concatMap(exit => {
47             if (exit) {
48                 return of(exit);
49             } else {
50                 return from(this.collectData());
51             }
52         }))
53
54         .pipe(concatMap(exit => {
55             if (exit) {
56                 return of(exit);
57             } else {
58                 return super.open(ops);
59             }
60         }));
61     }
62
63     collectData(): Promise<boolean> {
64         let promise = Promise.resolve(null);
65         const hold = this.checkin.hold;
66
67         if (this.slip !== 'hold_shelf_slip') {
68
69             // Always fetch the most recent transit for the copy,
70             // regardless of what data the server returns in the payload.
71
72             promise = promise.then(_ => this.circ.findCopyTransit(this.checkin))
73             .then(transit => {
74                 this.checkin.transit = transit;
75                 this.checkin.destOrg = transit.dest();
76                 this.checkin.routeTo = transit.dest().shortname();
77                 return this.circ.getOrgAddr(this.checkin.destOrg.id(), 'holds_address');
78             })
79             .then(addr => {
80                 this.checkin.destAddress = addr;
81                 return this.org.settings('lib.courier_code', this.checkin.destOrg.id());
82             })
83
84             .then(sets => this.checkin.destCourierCode = sets['lib.courier_code']);
85         }
86
87         if (hold) {
88             promise = promise.then(_ => {
89                 return this.pcrud.retrieve('au', hold.usr(),
90                     {flesh: 1, flesh_fields : {'au' : ['card']}}).toPromise()
91                 .then(patron => this.checkin.patron = patron);
92             });
93         }
94
95         if (this.checkin.params.auto_print_holds_transits
96             || this.circ.suppressCheckinPopups) {
97             // Print and exit.
98             return promise.then(_ => this.print()).then(_ => true); // exit
99         }
100
101         return promise.then(_ => false); // keep going
102     }
103
104     applySettings(): Promise<boolean> {
105
106         if (this.checkin.transit) {
107             if (this.checkin.patron && this.checkin.hold &&
108                 // It's possible to recieve a fulfilled hold in the
109                 // checkin response when a checkin results in canceling
110                 // a hold transit for a hold that was fulfilled while
111                 // the item was in transit.
112                 !this.checkin.hold.fulfillment_time()) {
113                 this.slip = 'hold_transit_slip';
114             } else {
115                 this.slip = 'transit_slip';
116             }
117         } else {
118             this.slip = 'hold_shelf_slip';
119         }
120
121         const autoPrintSet = 'circ.staff_client.do_not_auto_attempt_print';
122
123         return this.serverStore.getItemBatch([autoPrintSet]).then(sets => {
124             const autoPrintArr = sets[autoPrintSet];
125
126             if (Array.isArray(autoPrintArr)) {
127                 this.noAutoPrint['hold_shelf_slip'] =
128                     autoPrintArr.includes('Hold Slip');
129
130                 this.noAutoPrint['hold_transit_slip'] =
131                     autoPrintArr.includes('Hold/Transit Slip');
132
133                 this.noAutoPrint['transit_slip'] =
134                     autoPrintArr.includes('Transit Slip');
135             }
136         })
137         .then(_ => this.noAutoPrint[this.slip]);
138     }
139
140     print(): Promise<any> {
141         this.printer.print({
142             templateName: this.slip,
143             contextData: {checkin: this.checkin},
144             printContext: 'default'
145         });
146
147         this.close();
148
149         // TODO printer.print() should return a promise
150         return Promise.resolve();
151     }
152 }
153