]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts
LP1913604: Alert staff when associating item with course at a different library
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / admin / local / course-reserves / course-associate-material.component.ts
1 import {Component, Input, ViewChild, OnInit} from '@angular/core';
2 import {Observable, merge, of, EMPTY} from 'rxjs';
3 import {switchMap} from 'rxjs/operators';
4 import {DialogComponent} from '@eg/share/dialog/dialog.component';
5 import {AuthService} from '@eg/core/auth.service';
6 import {NetService} from '@eg/core/net.service';
7 import {PcrudService} from '@eg/core/pcrud.service';
8 import {Pager} from '@eg/share/util/pager';
9 import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
10 import {GridDataSource} from '@eg/share/grid/grid';
11 import {GridComponent} from '@eg/share/grid/grid.component';
12 import {IdlObject} from '@eg/core/idl.service';
13 import {StringComponent} from '@eg/share/string/string.component';
14 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
15 import {ToastService} from '@eg/share/toast/toast.service';
16 import {CourseService} from '@eg/staff/share/course.service';
17
18 @Component({
19     selector: 'eg-course-associate-material-dialog',
20     templateUrl: './course-associate-material.component.html'
21 })
22
23 export class CourseAssociateMaterialComponent extends DialogComponent implements OnInit {
24     @Input() currentCourse: IdlObject;
25     @Input() courseId: any;
26     @Input() courseIsArchived: string;
27     @Input() displayMode: string;
28     materials: any[] = [];
29     @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
30     @ViewChild('materialsGrid', {static: false}) materialsGrid: GridComponent;
31     @ViewChild('materialDeleteFailedString', { static: true })
32         materialDeleteFailedString: StringComponent;
33     @ViewChild('materialDeleteSuccessString', { static: true })
34         materialDeleteSuccessString: StringComponent;
35     @ViewChild('materialAddSuccessString', { static: true })
36         materialAddSuccessString: StringComponent;
37     @ViewChild('materialAddFailedString', { static: true })
38         materialAddFailedString: StringComponent;
39     @ViewChild('materialEditSuccessString', { static: true })
40         materialEditSuccessString: StringComponent;
41     @ViewChild('materialEditFailedString', { static: true })
42         materialEditFailedString: StringComponent;
43     @ViewChild('materialAddDifferentLibraryString', { static: true })
44         materialAddDifferentLibraryString: StringComponent;
45     @ViewChild('confirmOtherLibraryDialog') confirmOtherLibraryDialog: DialogComponent;
46     materialsDataSource: GridDataSource;
47     @Input() barcodeInput: string;
48     @Input() relationshipInput: string;
49     @Input() tempCallNumber: string;
50     @Input() tempStatus: number;
51     @Input() tempLocation: number;
52     @Input() tempCircMod: string;
53     @Input() isModifyingStatus: boolean;
54     @Input() isModifyingCircMod: boolean;
55     @Input() isModifyingCallNumber: boolean;
56     @Input() isModifyingLocation: boolean;
57     bibId: number;
58     itemCircLib: string;
59
60     associateBriefRecord: (newRecord: string) => void;
61     associateElectronicBibRecord: () => void;
62
63     constructor(
64         private auth: AuthService,
65         private course: CourseService,
66         private net: NetService,
67         private pcrud: PcrudService,
68         private toast: ToastService,
69         private modal: NgbModal
70     ) {
71         super(modal);
72         this.materialsDataSource = new GridDataSource();
73
74         this.materialsDataSource.getRows = (pager: Pager, sort: any[]) => {
75             return this.net.request(
76                 'open-ils.courses',
77                 'open-ils.courses.course_materials.retrieve.fleshed',
78                 {course: this.courseId}
79             );
80         };
81     }
82
83     ngOnInit() {
84         this.associateBriefRecord = (newRecord: string) => {
85             return this.net.request(
86                 'open-ils.courses',
87                 'open-ils.courses.attach.biblio_record',
88                 this.auth.token(),
89                 newRecord,
90                 this.courseId,
91                 this.relationshipInput
92             ).subscribe(() => {
93                 this.materialsGrid.reload();
94                 this.materialAddSuccessString.current()
95                     .then(str => this.toast.success(str));
96             });
97         };
98
99         this.associateElectronicBibRecord = () => {
100             return this.net.request(
101                 'open-ils.courses',
102                 'open-ils.courses.attach.electronic_resource',
103                 this.auth.token(),
104                 this.bibId,
105                 this.courseId,
106                 this.relationshipInput
107             ).subscribe(() => {
108                 this.materialsGrid.reload();
109                 this.materialAddSuccessString.current()
110                     .then(str => this.toast.success(str));
111             });
112          };
113
114     }
115
116     isDialog(): boolean {
117         return this.displayMode === 'dialog';
118     }
119
120     editSelectedMaterials(itemFields: IdlObject[]) {
121         // Edit each IDL thing one at a time
122         const editOneThing = (item: IdlObject) => {
123             if (!item) { return; }
124
125             this.showEditDialog(item).then(
126                 () => editOneThing(itemFields.shift()));
127         };
128
129         editOneThing(itemFields.shift());
130     }
131
132     showEditDialog(courseMaterial: IdlObject): Promise<any> {
133         this.editDialog.mode = 'update';
134         this.editDialog.recordId = courseMaterial.id();
135         return new Promise((resolve, reject) => {
136             this.editDialog.open({size: 'lg'}).subscribe(
137                 result => {
138                     this.materialEditSuccessString.current()
139                         .then(str => this.toast.success(str));
140                     this.pcrud.retrieve('acmcm', result).subscribe(material => {
141                         if (material.course() !== this.courseId) {
142                             this.materialsGrid.reload();
143                         } else {
144                             courseMaterial.relationship = material.relationship();
145                         }
146                     });
147                     resolve(result);
148                 },
149                 error => {
150                     this.materialEditFailedString.current()
151                         .then(str => this.toast.danger(str));
152                     reject(error);
153                 }
154             );
155         });
156     }
157
158     associateItem(barcode, relationship) {
159         if (barcode) {
160             const args = {
161                 barcode: barcode.trim(),
162                 relationship: relationship,
163                 isModifyingCallNumber: this.isModifyingCallNumber,
164                 isModifyingCircMod: this.isModifyingCircMod,
165                 isModifyingLocation: this.isModifyingLocation,
166                 isModifyingStatus: this.isModifyingStatus,
167                 tempCircMod: this.tempCircMod,
168                 tempLocation: this.tempLocation,
169                 tempStatus: this.tempStatus,
170                 currentCourse: this.currentCourse
171             };
172             this.barcodeInput = null;
173
174             this.pcrud.search('acp', {barcode: args.barcode}, {
175                 flesh: 3, flesh_fields: {acp: ['call_number', 'circ_lib']}
176             }).pipe(switchMap(item => this.handleItemAtDifferentLibrary$(item)))
177             .subscribe((originalItem) => {
178                 const associatedMaterial = this.course.associateMaterials(originalItem, args);
179                 associatedMaterial.material.then(res => {
180                     const item = associatedMaterial.item;
181                     let new_cn = item.call_number().label();
182                     if (this.tempCallNumber) { new_cn = this.tempCallNumber; }
183                     this.course.updateItem(item, this.currentCourse.owning_lib(),
184                         new_cn, args.isModifyingCallNumber
185                     ).then(resp => {
186                         this.materialsGrid.reload();
187                         this.materialAddSuccessString.current()
188                         .then(str => this.toast.success(str));
189                     });
190                 }, err => {
191                     this.materialAddFailedString.current()
192                     .then(str => this.toast.danger(str));
193                 });
194             });
195         }
196     }
197
198     deleteSelectedMaterials(items) {
199         let deleteRequest$ = this.course.detachMaterials(items);
200         merge(...deleteRequest$).subscribe(
201             val => {
202                 this.materialDeleteSuccessString.current().then(str => this.toast.success(str));
203             },
204             err => {
205                 this.materialDeleteFailedString.current()
206                     .then(str => this.toast.danger(str));
207             }
208         ).add(() => {
209             this.materialsGrid.reload();
210         });
211     }
212
213     handleItemAtDifferentLibrary$(item: IdlObject): Observable<any> {
214         this.itemCircLib = item.circ_lib().shortname();
215         if (item.circ_lib().id() !== this.currentCourse.owning_lib().id()) {
216             return this.confirmOtherLibraryDialog.open()
217             .pipe(switchMap(confirmed => {
218                 if (!confirmed) { return EMPTY; }
219                 return of(item);
220             }));
221         }
222         return of(item);
223     }
224 }