]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/share/holdings/mark-damaged-dialog.component.ts
LP1904036 Billing / payments
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / share / holdings / mark-damaged-dialog.component.ts
1 import {Component, Input, ViewChild} from '@angular/core';
2 import {Observable, throwError, from} from 'rxjs';
3 import {switchMap} from 'rxjs/operators';
4 import {NetService} from '@eg/core/net.service';
5 import {IdlObject} from '@eg/core/idl.service';
6 import {EventService} from '@eg/core/event.service';
7 import {ToastService} from '@eg/share/toast/toast.service';
8 import {AuthService} from '@eg/core/auth.service';
9 import {PcrudService} from '@eg/core/pcrud.service';
10 import {OrgService} from '@eg/core/org.service';
11 import {StringComponent} from '@eg/share/string/string.component';
12 import {DialogComponent} from '@eg/share/dialog/dialog.component';
13 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
14 import {BibRecordService, BibRecordSummary} from '@eg/share/catalog/bib-record.service';
15 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
16 import {BillingService} from '@eg/staff/share/billing/billing.service';
17
18 /**
19  * Dialog for marking items damaged and asessing related bills.
20  */
21
22 @Component({
23   selector: 'eg-mark-damaged-dialog',
24   templateUrl: 'mark-damaged-dialog.component.html'
25 })
26
27 export class MarkDamagedDialogComponent
28     extends DialogComponent {
29
30     @Input() copyId: number;
31
32     // If the item is checked out, ask the API to check it in first.
33     @Input() handleCheckin = false;
34
35     copy: IdlObject;
36     bibSummary: BibRecordSummary;
37     billingTypes: ComboboxEntry[];
38
39     // Overide the API suggested charge amount
40     amountChangeRequested: boolean;
41     newCharge: number;
42     newNote: string;
43     newBtype: number;
44
45     @ViewChild('successMsg', { static: true }) private successMsg: StringComponent;
46     @ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent;
47
48
49     // Charge data returned from the server requesting additional charge info.
50     chargeResponse: any;
51
52     constructor(
53         private modal: NgbModal, // required for passing to parent
54         private toast: ToastService,
55         private net: NetService,
56         private evt: EventService,
57         private pcrud: PcrudService,
58         private org: OrgService,
59         private billing: BillingService,
60         private bib: BibRecordService,
61         private auth: AuthService) {
62         super(modal); // required for subclassing
63     }
64
65     /**
66      * Fetch the item/record, then open the dialog.
67      * Dialog promise resolves with true/false indicating whether
68      * the mark-damanged action occured or was dismissed.
69      */
70     open(args: NgbModalOptions): Observable<boolean> {
71         this.reset();
72
73         if (!this.copyId) {
74             return throwError('copy ID required');
75         }
76
77         // Map data-loading promises to an observable
78         const obs = from(
79             this.getBillingTypes().then(_ => this.getData()));
80
81         // Fire data loading observable and replace results with
82         // dialog opener observable.
83         return obs.pipe(switchMap(_ => super.open(args)));
84     }
85
86     // Fetch-cache billing types
87     getBillingTypes(): Promise<any> {
88         return this.billing.getUserBillingTypes().then(types => {
89             this.billingTypes =
90                 types.map(bt => ({id: bt.id(), label: bt.name()}));
91         });
92     }
93
94     getData(): Promise<any> {
95         return this.pcrud.retrieve('acp', this.copyId,
96             {flesh: 1, flesh_fields: {acp: ['call_number']}}).toPromise()
97         .then(copy => {
98             this.copy = copy;
99             return this.bib.getBibSummary(
100                 copy.call_number().record()).toPromise();
101         }).then(summary => {
102                 this.bibSummary = summary;
103         });
104     }
105
106     reset() {
107         this.copy = null;
108         this.bibSummary = null;
109         this.chargeResponse = null;
110         this.newCharge = null;
111         this.newNote = null;
112         this.amountChangeRequested = false;
113     }
114
115     bTypeChange(entry: ComboboxEntry) {
116         this.newBtype = entry.id;
117     }
118
119     markDamaged(args: any) {
120         this.chargeResponse = null;
121
122         if (args.apply_fines === 'apply') {
123             args.override_amount = this.newCharge;
124             args.override_btype = this.newBtype;
125             args.override_note = this.newNote;
126         }
127
128         if (this.handleCheckin) {
129             args.handle_checkin = true;
130         }
131
132         this.net.request(
133             'open-ils.circ', 'open-ils.circ.mark_item_damaged',
134             this.auth.token(), this.copyId, args
135         ).subscribe(
136             result => {
137                 console.debug('Mark damaged returned', result);
138
139                 if (Number(result) === 1) {
140                     this.successMsg.current().then(msg => this.toast.success(msg));
141                     this.close(true);
142                     return;
143                 }
144
145                 const evt = this.evt.parse(result);
146
147                 if (evt.textcode === 'DAMAGE_CHARGE') {
148                     // More info needed from staff on how to hangle charges.
149                     this.chargeResponse = evt.payload;
150                     this.newCharge = this.chargeResponse.charge;
151                 }
152             },
153             err => {
154                 this.errorMsg.current().then(m => this.toast.danger(m));
155                 console.error(err);
156             }
157         );
158     }
159 }
160