LP1904036 more checkin
authorBill Erickson <berickxx@gmail.com>
Thu, 15 Apr 2021 19:42:56 +0000 (15:42 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:31 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/circ/checkin/checkin.component.html
Open-ILS/src/eg2/src/app/staff/circ/checkin/checkin.component.ts
Open-ILS/src/sql/Pg/upgrade/XXXX.data.angular-patron.sql

index c2f2aeb..8ce201b 100644 (file)
@@ -4,6 +4,37 @@
 <eg-barcode-select #barcodeSelect></eg-barcode-select>
 <eg-copy-alerts-dialog #copyAlertsDialog></eg-copy-alerts-dialog>
 
+<div class="row" *ngIf="hasAlerts()">
+  <div class="col-lg-12 alert alert-danger p-1">
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="backdate" i18n>Backdated Check In {{backdate | date:'shortDate'}}</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="backdate && backdateUntilLogout" i18n>Use Effective Date Until Logout</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.no_precat_alert" i18n>Ignore Pre-Cataloged Items</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.noop" i18n>Suppress Holds and Transits</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.void_overdues" i18n>Amnesty Mode</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.auto_print_holds_transits" i18n>Auto-Print Hold and Transit Slips</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.clear_expired" i18n>Clear Holds Shelf</span>
+    <ng-container *ngIf="modifiers.retarget_holds">
+      <span class="mr-2 pr-2 border-right border-dark" 
+        *ngIf="modifiers.retarget_holds_all" i18n>Always Retarget Local Holds</span>
+      <span class="mr-2 pr-2 border-right border-dark" 
+        *ngIf="!modifiers.retarget_holds_all" i18n>Retarget Local Holds</span>
+    </ng-container>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.hold_as_transit" i18n>Capture Local Holds As Transits</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.manual_float" i18n>Manual Floating Active</span>
+    <span class="mr-2 pr-2 border-right border-dark" 
+      *ngIf="modifiers.do_inventory_update" i18n>Update Inventory</span>
+  </div>
+</div>
+
 <div class="row mb-3 pb-3 border-bottom">
   <div class="col-lg-12 d-flex">
     <div class="form-inline">
       </div>
     </div>
     <div class="flex-1"></div>
-    <div>
-      <span class="mr-2" i18n>Effective Date:</span>
-      <eg-date-select [initialIso]="backdate" 
-        (onChangeAsIso)="backdate = $event"></eg-date-select>
+    <div class="mr-2">
+      <div class="form-check form-check-inline">
+        <input class="form-check-input" type="checkbox" 
+          id="use-date-cbox" [(ngModel)]="backdateUntilLogout"/>
+        <label class="form-check-label" 
+          for="use-date-cbox" i18n>Use effective date until logout</label>
+      </div>
     </div>
+    <div class="mr-2" i18n>Effective Date:</div>
+    <eg-date-select [initialIso]="backdate" 
+      (onChangeAsIso)="backdate = $event"></eg-date-select>
   </div>
 </div>
 
   </div>
 </div>
 
+<div class="row mt-3 pt-3 border-top">
+  <div class="col-lg-12 d-flex">
+    <div class="flex-1"></div>
+    <div class="mr-3">
+      <button class="btn btn-outline-dark" 
+        (click)="printReceipt()" i18n>Print Receipt</button>
+    </div>
+    <div class="mr-3">
+      <div class="form-check form-check-inline">
+        <input class="form-check-input" type="checkbox" 
+          id="trim-list-cbox" [(ngModel)]="trimList"/>
+        <label class="form-check-label" 
+          for="trim-list-cbox" i18n>Trim List (20)</label>
+      </div>
+    </div>
+    <div class="mr-3">
+      <div class="form-check form-check-inline">
+        <input class="form-check-input" type="checkbox" 
+          (ngModelChange)="toggleStrictBarcode($event)"
+          id="strict-barcode-cbox" [(ngModel)]="strictBarcode"/>
+        <label class="form-check-label" 
+          for="strict-barcode-cbox" i18n>Strict Barcode</label>
+      </div>
+    </div>
+    <div>
+      <div ngbDropdown>
+        <button class="btn btn-outline-dark" 
+          ngbDropdownToggle i18n>Checkin Modifiers</button>
+        <div ngbDropdownMenu>
+          <a ngbDropdownItem (click)="toggleMod('no_precat_alert')">
+            <span *ngIf="modifiers.no_precat_alert" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.no_precat_alert" 
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Ignore Pre-cataloged Items</span>
+          </a>
+          <a ngbDropdownItem *ngIf="!isHoldCapture" (click)="toggleMod('noop')">
+            <span *ngIf="modifiers.noop" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.noop" 
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Suppress Holds and Transits</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('void_overdues')">
+            <span *ngIf="modifiers.void_overdues" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.void_overdues"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Amnesty Mode</span>
+          </a>
+          <a ngbDropdownItem *ngIf="!isHoldCapture"
+            (click)="toggleMod('auto_print_holds_transits')">
+            <span *ngIf="modifiers.auto_print_holds_transits" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.auto_print_holds_transits"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span>Auto-Print Hold and Transit Slips</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('clear_expired')">
+            <span *ngIf="modifiers.clear_expired" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.clear_expired"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Clear Holds Shelf</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('retarget_holds')">
+            <span *ngIf="modifiers.retarget_holds" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.retarget_holds"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Retarget Local Holds</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('retarget_holds_all')">
+            <span *ngIf="modifiers.retarget_holds_all" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.retarget_holds_all"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Retarget All Statuses</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('hold_as_transit')">
+            <span *ngIf="modifiers.hold_as_transit" 
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.hold_as_transit"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Capture Local Holds As Transits</span>
+          </a>
+          <a ngbDropdownItem (click)="toggleMod('manual_float')">
+            <span *ngIf="modifiers.manual_float"
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.manual_float"
+              class="badge badge-warning mr-2">&#x2717;</span>
+            <span i18n>Manual Floating Active</span>
+          </a>
+          <a ngbDropdownItem *ngIf="!isHoldCapture"
+            (click)="toggleMod('do_inventory_update')">
+            <span *ngIf="modifiers.do_inventory_update"
+              class="badge badge-success mr-2">&#x2713;</span>
+            <span *ngIf="!modifiers.do_inventory_update"
+              class="badge badge-warning">&#x2717;</span>
+            <span i18n>Update Inventory</span>
+          </a>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+
index f07d5ed..f8be484 100644 (file)
@@ -13,12 +13,29 @@ import {CircService, CircDisplayInfo, CheckinParams, CheckinResult
 import {Pager} from '@eg/share/util/pager';
 import {BarcodeSelectComponent
     } from '@eg/staff/share/barcodes/barcode-select.component';
+import {PrintService} from '@eg/share/print/print.service';
 
 interface CheckinGridEntry extends CheckinResult {
     // May need to extend...
     foo?: number; // Empty interfaces are not allowed.
 }
 
+const TRIM_LIST_TO = 20;
+
+const CHECKIN_MODIFIERS = [
+    'void_overdues',
+    'clear_expired',
+    'hold_as_transit',
+    'manual_float',
+    'no_precat_alert',
+    'retarget_holds',
+    'retarget_holds_all'
+];
+
+const SETTINGS = [
+    'circ.checkin.strict_barcode'
+]
+
 @Component({
   templateUrl: 'checkin.component.html',
   styleUrls: ['checkin.component.css']
@@ -28,12 +45,18 @@ export class CheckinComponent implements OnInit, AfterViewInit {
     autoIndex = 0;
 
     barcode: string;
-    backdate: string; // ISO
+    backdate: string;
+    backdateUntilLogout = false;
     fineTally = 0;
+    isHoldCapture = false;
+    strictBarcode = false;
+    trimList = false;
 
     gridDataSource: GridDataSource = new GridDataSource();
     cellTextGenerator: GridCellTextGenerator;
 
+    modifiers: {[key: string]: boolean} = {};
+
     private copiesInFlight: {[barcode: string]: boolean} = {};
 
     @ViewChild('grid') private grid: GridComponent;
@@ -47,6 +70,7 @@ export class CheckinComponent implements OnInit, AfterViewInit {
         private auth: AuthService,
         private store: ServerStoreService,
         private circ: CircService,
+        private printer: PrintService,
         public patronService: PatronService
     ) {}
 
@@ -54,6 +78,23 @@ export class CheckinComponent implements OnInit, AfterViewInit {
         this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
             return from(this.checkins);
         };
+
+        const setNames =
+            CHECKIN_MODIFIERS.map(mod => `eg.circ.checkin.${mod}`)
+            .concat(SETTINGS);
+
+        this.store.getItemBatch(setNames).then(sets => {
+            CHECKIN_MODIFIERS.forEach(mod =>
+                this.modifiers[mod] = sets[`eg.circ.checkin.${mod}`]);
+
+            this.strictBarcode = sets['circ.checkin.strict_barcode'];
+
+            if (this.isHoldCapture) {
+                this.modifiers.noop = false;
+                this.modifiers.auto_print_holds_transits = true;
+            }
+
+        });
     }
 
     ngAfterViewInit() {
@@ -133,7 +174,54 @@ export class CheckinComponent implements OnInit, AfterViewInit {
         }
 
         this.checkins.unshift(entry);
+
+        if (this.trimList && this.checkins.length >= TRIM_LIST_TO) {
+            this.checkins.length = TRIM_LIST_TO;
+        }
         this.grid.reload();
     }
+
+    toggleMod(mod: string) {
+        if (this.modifiers[mod]) {
+            this.modifiers[mod] = false;
+            this.store.removeItem('eg.circ.checkin.' + mod);
+        } else {
+            this.modifiers[mod] = true;
+            this.store.setItem('eg.circ.checkin.' + mod, true);
+        }
+    }
+
+    toggleStrictBarcode(active: boolean) {
+        if (active) {
+            this.store.setItem('circ.checkin.strict_barcode', true);
+        } else {
+            this.store.removeItem('circ.checkin.strict_barcode');
+        }
+    }
+
+    printReceipt() {
+        if (this.checkins.length === 0) { return; }
+
+        this.printer.print({
+            printContext: 'default',
+            templateName: 'checkin',
+            contextData: {checkins: this.checkins}
+        });
+    }
+
+    hasAlerts(): boolean {
+        return (
+            Boolean(this.backdate)              ||
+            this.modifiers.noop                 ||
+            this.modifiers.manual_float         ||
+            this.modifiers.void_overdues        ||
+            this.modifiers.clear_expired        ||
+            this.modifiers.retarget_holds       ||
+            this.modifiers.hold_as_transit      ||
+            this.modifiers.no_precat_alert      ||
+            this.modifiers.do_inventory_update  ||
+            this.modifiers.auto_print_holds_transits
+        );
+    }
 }
 
index 68e4ece..af05cdc 100644 (file)
@@ -390,8 +390,6 @@ UPDATE config.print_template SET template = $TEMPLATE$
 
 $TEMPLATE$ WHERE name = 'transit_slip';
 
-*/
-
  
 INSERT INTO config.print_template 
     (name, label, owner, active, locale, content_type, template)
@@ -442,6 +440,47 @@ UPDATE config.print_template SET template = $TEMPLATE$
 
 $TEMPLATE$ WHERE name = 'transit_slip';
 
+INSERT INTO config.print_template 
+    (name, label, owner, active, locale, content_type, template)
+VALUES ('checkin', 'Checkin', 1, TRUE, 'en-US', 'text/html', '');
+
+*/
+
+UPDATE config.print_template SET template = $TEMPLATE$
+[% 
+  USE date;
+  USE money = format('$%.2f');
+  SET checkins = template_data.checkins;
+%] 
+
+<div>
+  <div>Welcome to [% staff_org.name %]</div>
+  <div>You checked in the following items:</div>
+  <hr/>
+  <ol>
+       [% FOR checkin IN checkins %]
+    <li>
+      <div>[% checkin.title %]</div>
+      <span>Barcode: </span>
+      <span>[% checkin.copy.barcode %]</span>
+      <span>Call Number: </span>
+      <span>
+      [% IF checkin.volume %]
+           [% volume.prefix.label %] [% volume.label %] [% volume.suffix.label %]
+      [% ELSE %]
+        Not Cataloged
+      [% END %]
+      </span>
+    </li>
+  [% END %]
+  </ol>
+  <hr/>
+  <div>Slip Date: [% date.format(date.now, '%x %r') %]</div>
+  <div>Printed by [% staff.first_given_name %] at [% staff_org.shortname %]</div>
+</div>
+
+$TEMPLATE$ WHERE name = 'checkin';
+
 
 COMMIT;