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';
18 interface BillGridEntry extends CircDisplayInfo {
19 xact: IdlObject // mbt
20 billingLocation?: string;
21 paymentPending?: number;
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'],
39 acn: ['record', 'owning_lib', 'prefix', 'suffix'],
40 bre: ['wide_display_entry']
45 templateUrl: 'bills.component.html',
46 selector: 'eg-patron-bills',
47 styleUrls: ['bills.component.css']
49 export class BillsComponent implements OnInit, AfterViewInit {
51 @Input() patronId: number;
54 paymentType = 'cash_payment';
57 annotatePayment = false;
58 entries: BillGridEntry[];
60 gridDataSource: GridDataSource = new GridDataSource();
61 cellTextGenerator: GridCellTextGenerator;
63 @ViewChild('billGrid') private billGrid: GridComponent;
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
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() : ''
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(); }
91 this.entries.slice(pager.offset, pager.offset + pager.limit)
92 .filter(entry => entry !== undefined);
101 const node = document.getElementById('pay-amount');
102 if (node) { node.focus(); }
109 this.gridDataSource.requestingData = true;
111 this.net.request('open-ils.actor',
112 'open-ils.actor.user.transactions.for_billing',
113 this.auth.token(), this.patronId
116 if (!this.summary) { // 1st response is summary
119 this.entries.push(this.formatForDisplay(resp));
124 this.gridDataSource.requestingData = false;
125 this.billGrid.reload();
130 formatForDisplay(xact: IdlObject): BillGridEntry {
132 const entry: BillGridEntry = {
137 if (xact.summary().xact_type() !== 'circulation') {
138 entry.title = xact.summary().last_billing_type();
139 entry.billingLocation =
140 xact.grocery().billing_location().shortname();
144 const circDisplay: CircDisplayInfo =
145 this.circ.getDisplayInfo(xact.circulation());
147 entry.billingLocation =
148 xact.circulation().circ_lib().shortname();
150 return Object.assign(entry, circDisplay);
153 patron(): IdlObject {
154 return this.context.patron;
157 disablePayment(): boolean {
158 if (!this.billGrid) { return true; } // still loading
160 // TODO: pay amount can be zero when refunding
162 this.payAmount <= 0 ||
163 this.billGrid.context.rowSelector.selected().length === 0
168 refundsAvailable(): number {
173 paidSelected(): number {
178 owedSelected(): number {
183 billedSelected(): number {
187 pendingPayment(): number {
191 pendingChange(): number {