From f5b0dc1ed49159112e677b9dbef3f788bbef367a Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 11 May 2021 11:31:47 -0400 Subject: [PATCH] LP1904036 Checkout/renew receipts Signed-off-by: Bill Erickson Signed-off-by: Jane Sandberg Signed-off-by: Galen Charlton --- .../app/staff/circ/patron/checkout.component.html | 54 +++++++++++ .../app/staff/circ/patron/checkout.component.ts | 106 ++++++++++++++++++++- .../src/app/staff/circ/renew/renew.component.ts | 4 +- .../holdings/copy-alert-manager.component.html | 54 +++++++---- .../share/holdings/copy-alert-manager.component.ts | 12 ++- .../src/app/staff/share/worklog/worklog.service.ts | 9 -- .../sql/Pg/upgrade/XXXX.data.angular-patron.sql | 82 ++++++++++++++++ 7 files changed, 286 insertions(+), 35 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.html index e9a1e889fa..7d48b78610 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.html @@ -2,6 +2,8 @@ + + +
+
+
+
+
+ + +
+
+
+
+ +
+
+ +
+ + +
+
+
+
+
+
+
+ +
+
+ +
+ + +
+
+
+
+
+
+
+ diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.ts index ee90e0cfa9..fc4a46a73e 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.ts @@ -1,6 +1,6 @@ import {Component, OnInit, AfterViewInit, Input, ViewChild} from '@angular/core'; import {Router, ActivatedRoute, ParamMap} from '@angular/router'; -import {Observable, empty, of, from} from 'rxjs'; +import {Subscription, Observable, empty, of, from} from 'rxjs'; import {tap, switchMap} from 'rxjs/operators'; import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap'; import {IdlObject} from '@eg/core/idl.service'; @@ -22,6 +22,10 @@ import {CopyAlertsDialogComponent } from '@eg/staff/share/holdings/copy-alerts-dialog.component'; import {BarcodeSelectComponent } from '@eg/staff/share/barcodes/barcode-select.component'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {StringComponent} from '@eg/share/string/string.component'; +import {AuthService} from '@eg/core/auth.service'; +import {PrintService} from '@eg/share/print/print.service'; const SESSION_DUE_DATE = 'eg.circ.checkout.is_until_logout'; @@ -38,6 +42,7 @@ export class CheckoutComponent implements OnInit, AfterViewInit { cellTextGenerator: GridCellTextGenerator; dueDate: string; dueDateOptions: 0 | 1 | 2 = 0; // auto date; specific date; session date + printOnComplete = true; private copiesInFlight: {[barcode: string]: boolean} = {}; @@ -49,8 +54,11 @@ export class CheckoutComponent implements OnInit, AfterViewInit { private copyAlertsDialog: CopyAlertsDialogComponent; @ViewChild('barcodeSelect') private barcodeSelect: BarcodeSelectComponent; + @ViewChild('receiptEmailed') + private receiptEmailed: StringComponent; constructor( + private router: Router, private store: StoreService, private serverStore: ServerStoreService, private org: OrgService, @@ -59,6 +67,9 @@ export class CheckoutComponent implements OnInit, AfterViewInit { public circ: CircService, public patronService: PatronService, public context: PatronContextService, + private toast: ToastService, + private auth: AuthService, + private printer: PrintService, private audio: AudioService ) {} @@ -77,6 +88,14 @@ export class CheckoutComponent implements OnInit, AfterViewInit { this.dueDate = this.store.getSessionItem('eg.circ.checkout.due_date'); this.toggleDateOptions(2); } + + this.serverStore.getItem('circ.staff_client.do_not_auto_attempt_print') + .then(noPrint => { + this.printOnComplete = !( + noPrint && + noPrint.includes('Checkout') + ); + }); } ngAfterViewInit() { @@ -290,5 +309,90 @@ export class CheckoutComponent implements OnInit, AfterViewInit { } ); } + + toggleStrictBarcode(active: boolean) { + if (active) { + this.serverStore.setItem('circ.checkout.strict_barcode', true); + } else { + this.serverStore.removeItem('circ.checkout.strict_barcode'); + } + } + + patronHasEmail(): boolean { + if (!this.context.summary) { return false; } + const patron = this.context.summary.patron; + return ( + patron.email() && + patron.email().match(/.*@.*/) !== null + ); + } + + mayEmailReceipt(): boolean { + if (!this.context.summary) { return false; } + const patron = this.context.summary.patron; + const setting = patron.settings() + .filter(s => s.name() === 'circ.send_email_checkout_receipts')[0]; + + return ( + this.patronHasEmail() && + setting && + setting.value() === 'true' // JSON encoded + ); + } + + quickReceipt() { + if (this.mayEmailReceipt()) { + this.emailReceipt(); + } else { + this.printReceipt(); + } + } + + doneAutoReceipt() { + if (this.mayEmailReceipt()) { + this.emailReceipt(true); + } else if (this.printOnComplete) { + this.printReceipt(true); + } + } + + emailReceipt(redirect?: boolean) { + if (this.patronHasEmail() && this.context.checkouts.length > 0) { + return this.net.request( + 'open-ils.circ', + 'open-ils.circ.checkout.batch_notify.session.atomic', + this.auth.token(), + this.context.summary.id, + this.context.checkouts.map(c => c.circ.id()) + ).subscribe(_ => { + this.toast.success(this.receiptEmailed.text); + if (redirect) { this.doneRedirect(); } + }); + } + } + + printReceipt(redirect?: boolean) { + if (this.context.checkouts.length === 0) { return; } + + if (redirect) { + // Wait for the print job to be queued before redirecting + const sub: Subscription = + this.printer.printJobQueued$.subscribe(_ => { + sub.unsubscribe(); + this.doneRedirect(); + }); + } + + this.printer.print({ + printContext: 'default', + templateName: 'checkout', + contextData: {checkouts: this.context.checkouts} + }); + } + + doneRedirect() { + this.router.navigate(['/staff/circ/patron/bcsearch']); + } + } diff --git a/Open-ILS/src/eg2/src/app/staff/circ/renew/renew.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/renew/renew.component.ts index ea40697a9e..7cd30eacd9 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/renew/renew.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/renew/renew.component.ts @@ -181,9 +181,9 @@ export class RenewComponent implements OnInit, AfterViewInit { toggleStrictBarcode(active: boolean) { if (active) { - this.store.setItem('circ.checkin.strict_barcode', true); + this.store.setItem('circ.renew.strict_barcode', true); } else { - this.store.removeItem('circ.checkin.strict_barcode'); + this.store.removeItem('circ.renew.strict_barcode'); } } diff --git a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.html b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.html index 8bf3be0302..99b51ee539 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.html @@ -1,39 +1,57 @@ - - - - - - - - - - - - - - - - + + + + + + + + + +
-
-
Next item status:
diff --git a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.ts b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.ts index 528875336e..df0698e774 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alert-manager.component.ts @@ -79,11 +79,13 @@ export class CopyAlertManagerDialogComponent if (copyAlert.temp() === 'f') { return promise; } - copyAlert.alert_type().next_status().forEach(statId => { - if (!nextStatuses.includes(statId)) { - nextStatuses.push(statId); - } - }); + if (copyAlert.alert_type().next_status()) { + copyAlert.alert_type().next_status().forEach(statId => { + if (!nextStatuses.includes(statId)) { + nextStatuses.push(statId); + } + }); + } if (this.mode === 'checkin' && nextStatuses.length > 0) { diff --git a/Open-ILS/src/eg2/src/app/staff/share/worklog/worklog.service.ts b/Open-ILS/src/eg2/src/app/staff/share/worklog/worklog.service.ts index af0818bb3d..8fe3cc1ff5 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/worklog/worklog.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/worklog/worklog.service.ts @@ -44,7 +44,6 @@ export class WorkLogService { record(entry: WorkLogEntry) { -console.log('1'); if (this.maxEntries === null) { throw new Error('WorkLogService.loadSettings() required'); return; @@ -55,35 +54,27 @@ console.log('1'); 'Add to your component for worklog support'); return; } -console.log('1'); entry.when = new Date(); entry.actor = this.auth.user().usrname(); - console.log(`worklog_${entry.action}`); - console.log(this.workLogStrings[`worklog_${entry.action}`]); entry.msg = this.workLogStrings[`worklog_${entry.action}`].text; -console.log('1'); const workLog: WorkLogEntry[] = this.store.getLocalItem('eg.work_log') || []; let patronLog: WorkLogEntry[] = this.store.getLocalItem('eg.patron_log') || []; -console.log('1'); workLog.push(entry); if (workLog.length > this.maxEntries) { workLog.shift(); } -console.log('1'); this.store.setLocalItem('eg.work_log', workLog); -console.log('1'); if (entry.patron_id) { // Remove existing entries that match this patron patronLog = patronLog.filter(e => e.patron_id !== entry.patron_id); -console.log('1'); patronLog.push(entry); if (patronLog.length > this.maxPatrons) { diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.angular-patron.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.angular-patron.sql index 09919decc6..e22f88fbb2 100644 --- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.angular-patron.sql +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.angular-patron.sql @@ -1,6 +1,8 @@ BEGIN; +/* + -- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version); -- insert then update for easier iterative development tweaks @@ -563,6 +565,86 @@ UPDATE config.print_template SET template = $TEMPLATE$
$TEMPLATE$ WHERE name = 'bills_historical'; +*/ + +INSERT INTO config.print_template + (name, label, owner, active, locale, content_type, template) +VALUES ('checkout', 'Checkout', 1, TRUE, 'en-US', 'text/html', ''); + +UPDATE config.print_template SET template = $TEMPLATE$ +[% + USE date; + USE money = format('$%.2f'); + SET checkouts = template_data.checkouts; +%] + +
+
Welcome to [% staff_org.name %]
+
You checked out the following items:
+
+
    + [% FOR checkout IN checkouts %] +
  1. +
    [% checkout.title %]
    + Barcode: + [% checkout.copy.barcode %] + Call Number: + + [% IF checkout.volume %] + [% volume.prefix.label %] [% volume.label %] [% volume.suffix.label %] + [% ELSE %] + Not Cataloged + [% END %] + +
  2. + [% END %] +
+
+
Slip Date: [% date.format(date.now, '%x %r') %]
+
Printed by [% staff.first_given_name %] at [% staff_org.shortname %]
+
+ +$TEMPLATE$ WHERE name = 'checkout'; + +INSERT INTO config.print_template + (name, label, owner, active, locale, content_type, template) +VALUES ('renew', 'renew', 1, TRUE, 'en-US', 'text/html', ''); + +UPDATE config.print_template SET template = $TEMPLATE$ +[% + USE date; + USE money = format('$%.2f'); + SET renewals = template_data.renewals; +%] + +
+
Welcome to [% staff_org.name %]
+
You renewed the following items:
+
+
    + [% FOR renewal IN renewals %] +
  1. +
    [% renewal.title %]
    + Barcode: + [% renewal.copy.barcode %] + Call Number: + + [% IF renewal.volume %] + [% volume.prefix.label %] [% volume.label %] [% volume.suffix.label %] + [% ELSE %] + Not Cataloged + [% END %] + +
  2. + [% END %] +
+
+
Slip Date: [% date.format(date.now, '%x %r') %]
+
Printed by [% staff.first_given_name %] at [% staff_org.shortname %]
+
+ +$TEMPLATE$ WHERE name = 'renew'; + COMMIT; -- 2.11.0