LP1816475: Booking module refresh
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / booking / pull-list.component.ts
1 import {Component, OnInit, ViewChild} from '@angular/core';
2 import {FormControl, FormGroup, Validators} from '@angular/forms';
3 import {from, Observable, of} from 'rxjs';
4 import {switchMap} from 'rxjs/operators';
5 import {AuthService} from '@eg/core/auth.service';
6 import {GridDataSource} from '@eg/share/grid/grid';
7 import {IdlObject} from '@eg/core/idl.service';
8 import {NetService} from '@eg/core/net.service';
9 import {OrgService} from '@eg/core/org.service';
10 import {PcrudService} from '@eg/core/pcrud.service';
11 import {ReservationActionsService} from './reservation-actions.service';
12 import {CancelReservationDialogComponent} from './cancel-reservation-dialog.component';
13
14 // The data that comes from the API, along with some fleshing
15 interface PullListRow {
16     call_number?: string;
17     call_number_sortkey?: string;
18     current_resource: IdlObject;
19     reservations: IdlObject[];
20     shelving_location?: string;
21     target_resource_type: IdlObject;
22 }
23
24 @Component({
25     templateUrl: './pull-list.component.html'
26 })
27
28 export class PullListComponent implements OnInit {
29     @ViewChild('confirmCancelReservationDialog')
30         private cancelReservationDialog: CancelReservationDialogComponent;
31
32     public dataSource: GridDataSource;
33
34     public disableOrgs: () => number[];
35     public fillGrid: (orgId?: number) => void;
36     pullListCriteria: FormGroup;
37
38     constructor(
39         private auth: AuthService,
40         private net: NetService,
41         private org: OrgService,
42         private pcrud: PcrudService,
43         private actions: ReservationActionsService,
44     ) { }
45
46
47     ngOnInit() {
48         this.dataSource = new GridDataSource();
49
50         const defaultDaysHence = 5;
51
52         this.pullListCriteria = new FormGroup({
53             'daysHence': new FormControl(defaultDaysHence, [
54                 Validators.required,
55                 Validators.min(1)])
56         });
57
58         this.pullListCriteria.valueChanges.subscribe(() => this.fillGrid() );
59
60         this.disableOrgs = () => this.org.filterList( { canHaveVolumes : false }, true);
61
62         this.fillGrid = (orgId = this.auth.user().ws_ou()) => {
63             this.dataSource.data = [];
64             const numberOfSecondsInADay = 86400;
65             this.net.request(
66                 'open-ils.booking', 'open-ils.booking.reservations.get_pull_list',
67                 this.auth.token(), null,
68                 (this.daysHence.value * numberOfSecondsInADay),
69                 orgId
70             ).pipe(switchMap((resources) => from(resources)),
71                 switchMap((resource: PullListRow) => this.fleshResource(resource))
72             )
73             .subscribe((resource) => this.dataSource.data.push(resource));
74         };
75     }
76
77     noSelectedRows = (rows: IdlObject[]) => (rows.length === 0);
78
79     notOneResourceSelected = (rows: IdlObject[]) => {
80         return this.actions.notOneUniqueSelected(
81             rows.map(row => { if (row['current_resource']) { return row['current_resource']['id']; }}));
82     }
83
84     notOneCatalogedItemSelected = (rows: IdlObject[]) => {
85         return this.actions.notOneUniqueSelected(
86             rows.filter(row => (row['current_resource'] && row['call_number']))
87             .map(row => row['current_resource'].id())
88         );
89     }
90
91     cancelSelected = (rows: IdlObject[]) => {
92         this.cancelReservationDialog.open(rows.map(row => row['reservations'][0].id()));
93     }
94
95     fleshResource = (resource: PullListRow): Observable<PullListRow> => {
96         if ('t' === resource['target_resource_type'].catalog_item()) {
97             return this.pcrud.search('acp', {
98                 'barcode': resource['current_resource'].barcode()
99                 }, {
100                     limit: 1,
101                     flesh: 1,
102                     flesh_fields: {'acp' : ['call_number', 'location' ]}
103             }).pipe(switchMap((acp) => {
104                 resource['call_number'] = acp.call_number().label();
105                 resource['call_number_sortkey'] = acp.call_number().label_sortkey();
106                 resource['shelving_location'] = acp.location().name();
107                 return of(resource);
108             }));
109         } else {
110             return of(resource);
111         }
112     }
113
114     viewByResource = (reservations: IdlObject[]) => {
115         this.actions.manageReservationsByResource(reservations[0]['current_resource'].barcode());
116     }
117
118     viewItemStatus = (reservations: IdlObject[]) => {
119         this.actions.viewItemStatus(reservations[0]['current_resource'].barcode());
120     }
121
122     get daysHence() {
123         return this.pullListCriteria.get('daysHence');
124     }
125
126 }
127