<label class="form-check-label" for="annotate" i18n>Annotate</label>
</div>
<div class="ml-2">
- <button class="btn btn-outline-dark" (click)="applyPayment()" i18n>Apply Payment</button>
+ <button class="btn btn-outline-dark" (click)="applyPayment()"
+ [disabled]="disablePayment()" i18n>Apply Payment</button>
</div>
</div>
</div>
import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
import {from, empty} from 'rxjs';
-import {concatMap, tap} from 'rxjs/operators';
+import {concatMap, tap, takeLast} from 'rxjs/operators';
import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
import {IdlObject} from '@eg/core/idl.service';
import {NetService} from '@eg/core/net.service';
-import {PcrudService} from '@eg/core/pcrud.service';
+import {PcrudService, PcrudContext} from '@eg/core/pcrud.service';
import {AuthService} from '@eg/core/auth.service';
import {ServerStoreService} from '@eg/core/server-store.service';
import {PatronService} from '@eg/staff/share/patron/patron.service';
sessionVoided = 0;
paymentType = 'cash_payment';
checkNumber: string;
+ payAmount: number;
annotatePayment = false;
entries: BillGridEntry[];
load() {
- const xactIds = [];
-
-
- // TODO: run this in a single pcrud transaction
-
- this.pcrud.retrieve('mous', this.patronId, {}, {authoritative : true})
- .pipe(tap(sum => this.summary = sum))
- .pipe(concatMap(_ => {
- return this.pcrud.search('mbts',
- {usr: this.patronId, balance_owed: {'<>' : 0}},
- {select: {mbts: ['id']}}, {authoritative : true}
- ).pipe(tap(summary => xactIds.push(summary.id())));
- }))
- .pipe(concatMap(_ => {
- this.entries = [];
- return this.pcrud.search('mbt', {id: xactIds}, {
- flesh: XACT_FLESH_DEPTH,
- flesh_fields: XACT_FLESH_FIELDS,
- order_by: {mbts : ['xact_start']},
- select: {bre : ['id']}
- }, {authoritative : true}
- ).pipe(tap(xact => this.entries.push(this.formatForDisplay(xact))));
- }))
- .subscribe(null, null, () => this.billGrid.reload());
+ this.summary = null;
+ this.entries = [];
+ this.gridDataSource.requestingData = true;
+
+ this.net.request('open-ils.actor',
+ 'open-ils.actor.user.transactions.for_billing',
+ this.auth.token(), this.patronId
+ ).subscribe(
+ resp => {
+ if (!this.summary) { // 1st response is summary
+ this.summary = resp;
+ } else {
+ this.entries.push(this.formatForDisplay(resp));
+ }
+ },
+ null,
+ () => {
+ this.gridDataSource.requestingData = false;
+ this.billGrid.reload();
+ }
+ );
}
formatForDisplay(xact: IdlObject): BillGridEntry {
return this.context.patron;
}
+ disablePayment(): boolean {
+ if (!this.billGrid) { return true; } // still loading
+
+ // TODO: pay amount can be zero when refunding
+ return (
+ this.payAmount <= 0 ||
+ this.billGrid.context.rowSelector.selected().length === 0
+ );
+ }
+
// TODO
refundsAvailable(): number {
return 0;
fetchSettings(): Promise<any> {
- // Some of these are used by the shared circ service.
- // Go ahead and precache them since we're making the call anyway.
+ // Some of these are used by the shared circ services.
+ // Precache them since we're making the call anyway.
return this.store.getItemBatch([
'eg.circ.patron.summary.collapse',
'circ.do_not_tally_claims_returned',
'ui.admin.patron_log.max_entries',
'circ.staff_client.do_not_auto_attempt_print',
'circ.clear_hold_on_checkout',
- 'ui.circ.suppress_checkin_popups'
+ 'ui.circ.suppress_checkin_popups',
+ 'ui.circ.billing.uncheck_bills_and_unfocus_payment_box',
+ 'ui.circ.billing.amount_warn',
+ 'ui.circ.billing.amount_limit',
+ 'circ.staff_client.do_not_auto_attempt_print',
+ 'circ.disable_patron_credit',
+ 'credit.processor.default'
]).then(settings => {
this.context.noTallyClaimsReturned =
settings['circ.do_not_tally_claims_returned'];
}
}
+
+__PACKAGE__->register_method(
+ method => 'user_billing_xacts',
+ api_name => 'open-ils.actor.user.transactions.for_billing',
+ signature => {
+ desc => q/Returns a stream of user billing data appropriate for
+ display in the user bills UI. API is natively "authoritative"./,
+ params => [
+ {desc => 'Authentication token', type => 'string'},
+ {desc => 'User ID', type => 'number'}
+ ],
+ return => {
+ desc => q/First response is the user money summary, following
+ responses are fleshed billable transactions/
+ }
+ }
+);
+
+sub user_billing_xacts {
+ my ($self, $client, $auth, $user_id) = @_;
+
+ my $e = new_editor(authtoken => $auth, xact => 1);
+ return $e->die_event unless $e->checkauth;
+
+ my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
+
+ return $e->die_event unless
+ $e->allowed('VIEW_USER_TRANSACTIONS', $user->home_ou);
+
+ # Start with the user summary.
+ $client->respond($e->retrieve_money_user_summary($user_id));
+
+ my $xact_ids = $e->json_query({
+ select => {mbts => ['id']},
+ from => 'mbts',
+ where => {
+ usr => $user_id,
+ balance_owed => {'<>' => 0}
+ },
+ order_by => {mbts => {xact_start => 'asc'}}
+ });
+
+ for my $xact_id (map { $_->{id} } @$xact_ids) {
+
+ my $xact = $e->retrieve_money_billable_transaction([
+ $xact_id, {
+ flesh => 5,
+ flesh_fields => {
+ mbt => [qw/summary circulation grocery/],
+ circ => [qw/
+ target_copy
+ workstation
+ checkin_workstation
+ circ_lib
+ /],
+ acp => [qw/
+ call_number
+ holds_count
+ status
+ circ_lib
+ location
+ floating
+ age_protect
+ parts
+ /],
+ acpm => [qw/part/],
+ acn => [qw/record owning_lib prefix suffix/],
+ bre => [qw/wide_display_entry/]
+ },
+ # Avoid adding the MARXML
+ # Fleshed fields are implicitly included.
+ select => {bre => ['id']}
+ }
+ ]);
+
+ $client->respond($xact);
+ }
+
+ $e->rollback;
+
+ return undef;
+}
+
1;