]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/circ/patron/bills.component.ts
LP1904036 Billing continued
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / circ / patron / bills.component.ts
1 import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
2 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
3 import {from, empty} from 'rxjs';
4 import {concatMap, tap, takeLast} from 'rxjs/operators';
5 import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
6 import {IdlObject} from '@eg/core/idl.service';
7 import {NetService} from '@eg/core/net.service';
8 import {PcrudService, PcrudContext} from '@eg/core/pcrud.service';
9 import {AuthService} from '@eg/core/auth.service';
10 import {ServerStoreService} from '@eg/core/server-store.service';
11 import {PatronService} from '@eg/staff/share/patron/patron.service';
12 import {PatronContextService} from './patron.service';
13 import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
14 import {GridComponent} from '@eg/share/grid/grid.component';
15 import {Pager} from '@eg/share/util/pager';
16 import {CircService, CircDisplayInfo} from '@eg/staff/share/circ/circ.service';
17
18 interface BillGridEntry extends CircDisplayInfo {
19     xact: IdlObject // mbt
20     billingLocation?: string;
21     paymentPending?: number;
22 }
23
24 const XACT_FLESH_DEPTH = 5;
25 const XACT_FLESH_FIELDS = {
26   mbt: ['summary', 'circulation', 'grocery'],
27   circ: ['target_copy', 'workstation', 'checkin_workstation', 'circ_lib'],
28   acp:  [
29     'call_number',
30     'holds_count',
31     'status',
32     'circ_lib',
33     'location',
34     'floating',
35     'age_protect',
36     'parts'
37   ],
38   acpm: ['part'],
39   acn:  ['record', 'owning_lib', 'prefix', 'suffix'],
40   bre:  ['wide_display_entry']
41 };
42
43
44 @Component({
45   templateUrl: 'bills.component.html',
46   selector: 'eg-patron-bills',
47   styleUrls: ['bills.component.css']
48 })
49 export class BillsComponent implements OnInit, AfterViewInit {
50
51     @Input() patronId: number;
52     summary: IdlObject;
53     sessionVoided = 0;
54     paymentType = 'cash_payment';
55     checkNumber: string;
56     payAmount: number;
57     annotatePayment = false;
58     entries: BillGridEntry[];
59
60     gridDataSource: GridDataSource = new GridDataSource();
61     cellTextGenerator: GridCellTextGenerator;
62
63     @ViewChild('billGrid') private billGrid: GridComponent;
64
65     constructor(
66         private router: Router,
67         private route: ActivatedRoute,
68         private net: NetService,
69         private pcrud: PcrudService,
70         private auth: AuthService,
71         private store: ServerStoreService,
72         private circ: CircService,
73         public patronService: PatronService,
74         public context: PatronContextService
75     ) {}
76
77     ngOnInit() {
78
79         this.cellTextGenerator = {
80             title: row => row.title,
81             copy_barcode: row => row.copy ? row.copy.barcode() : '',
82             call_number: row => row.volume ? row.volume.label() : ''
83         };
84
85         // The grid never fetches data directly, it only serves what
86         // we have manually retrieved.
87         this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
88             if (!this.entries) { return empty(); }
89
90             const page =
91                 this.entries.slice(pager.offset, pager.offset + pager.limit)
92                 .filter(entry => entry !== undefined);
93
94             return from(page);
95         };
96
97         this.load();
98     }
99
100     ngAfterViewInit() {
101         const node = document.getElementById('pay-amount');
102         if (node) { node.focus(); }
103     }
104
105     load() {
106
107         this.summary = null;
108         this.entries = [];
109         this.gridDataSource.requestingData = true;
110
111         this.net.request('open-ils.actor',
112             'open-ils.actor.user.transactions.for_billing',
113             this.auth.token(), this.patronId
114         ).subscribe(
115             resp => {
116                 if (!this.summary) { // 1st response is summary
117                     this.summary = resp;
118                 } else {
119                     this.entries.push(this.formatForDisplay(resp));
120                 }
121             },
122             null,
123             () => {
124                 this.gridDataSource.requestingData = false;
125                 this.billGrid.reload();
126             }
127         );
128     }
129
130     formatForDisplay(xact: IdlObject): BillGridEntry {
131
132         const entry: BillGridEntry = {
133             xact: xact,
134             paymentPending: 0
135         };
136
137         if (xact.summary().xact_type() !== 'circulation') {
138             entry.title = xact.summary().last_billing_type();
139             entry.billingLocation =
140                 xact.grocery().billing_location().shortname();
141             return entry;
142         }
143
144         const circDisplay: CircDisplayInfo =
145             this.circ.getDisplayInfo(xact.circulation());
146
147         entry.billingLocation =
148             xact.circulation().circ_lib().shortname();
149
150         return Object.assign(entry, circDisplay);
151     }
152
153     patron(): IdlObject {
154         return this.context.patron;
155     }
156
157     disablePayment(): boolean {
158         if (!this.billGrid) { return true; } // still loading
159
160         // TODO: pay amount can be zero when refunding
161         return (
162             this.payAmount <= 0 ||
163             this.billGrid.context.rowSelector.selected().length === 0
164         );
165     }
166
167     // TODO
168     refundsAvailable(): number {
169         return 0;
170     }
171
172     // TODO
173     paidSelected(): number {
174         return 0;
175     }
176
177     // TODO
178     owedSelected(): number {
179         return 0;
180     }
181
182     // TODO
183     billedSelected(): number {
184         return 0;
185     }
186
187     pendingPayment(): number {
188         return 0;
189     }
190
191     pendingChange(): number {
192         return 0;
193     }
194
195 }
196