[open-ils-commits] [GIT] Evergreen ILS branch master updated. be3de646ad7c8b7ef34c0bcad169d2912ccb4c50

Evergreen Git git at git.evergreen-ils.org
Thu Jun 18 16:27:49 EDT 2020


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  be3de646ad7c8b7ef34c0bcad169d2912ccb4c50 (commit)
       via  3c6617649d86809818e8f86e4e0fcc5d926164a7 (commit)
       via  e2d4b5b4cd42d7210e9671a8585287cd15e78489 (commit)
       via  cf548943e5bda1bf204a591d069ab203248efe5c (commit)
       via  5bc6611bc0255d8d982d92286fe210746c30b5be (commit)
      from  35fca97a4ec4f5009735544a26160060eaff7610 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit be3de646ad7c8b7ef34c0bcad169d2912ccb4c50
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Jun 18 16:27:19 2020 -0400

    LP#1851306: stamp DB update
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index a7c976a3eb..1a2298710c 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,7 +92,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1204', :eg_version); -- jeffdavis/sandbergja/csharp
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1205', :eg_version); -- sandbergja/tmcanna/gmcharlt
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql b/Open-ILS/src/sql/Pg/upgrade/1205.data.port_capture_reservations_to_angular.sql
similarity index 96%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
rename to Open-ILS/src/sql/Pg/upgrade/1205.data.port_capture_reservations_to_angular.sql
index 75293dd28f..a1f872079b 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1205.data.port_capture_reservations_to_angular.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('1205', :eg_version);
 
 INSERT INTO config.print_template 
     (id, name, locale, active, owner, label, template) 

commit 3c6617649d86809818e8f86e4e0fcc5d926164a7
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Jun 18 16:13:21 2020 -0400

    LP#1851306: (follow-up) fix printing of destination
    
    Updated the default template for booking capture
    transit slips to print the shortname of the destination.
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 6370049352..2e7dbbc471 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -20293,8 +20293,10 @@ $TEMPLATE$
     # template_data is data returned from open-ils.booking.resources.capture_for_reservation.
 -%]
 <div>
-  [% IF data.transit %]
-  <div>This item need to be routed to <strong>data.transit.dest</strong></div>
+  [% IF data.transit;
+       dest_ou = helpers.get_org_unit(data.transit.dest);
+  %]
+  <div>This item need to be routed to <strong>[% dest_ou.shortname %]</strong></div>
   [% ELSE %]
   <div>This item need to be routed to <strong>RESERVATION SHELF:</strong></div>
   [% END %]
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
index fbf53fc4ff..75293dd28f 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
@@ -15,8 +15,10 @@ $TEMPLATE$
     # template_data is data returned from open-ils.booking.resources.capture_for_reservation.
 -%]
 <div>
-  [% IF data.transit %]
-  <div>This item need to be routed to <strong>data.transit.dest</strong></div>
+  [% IF data.transit;
+       dest_ou = helpers.get_org_unit(data.transit.dest);
+  %]
+  <div>This item need to be routed to <strong>[% dest_ou.shortname %]</strong></div>
   [% ELSE %]
   <div>This item need to be routed to <strong>RESERVATION SHELF:</strong></div>
   [% END %]

commit e2d4b5b4cd42d7210e9671a8585287cd15e78489
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Jun 18 16:12:08 2020 -0400

    LP#1851306: (follow-up) add get_org_unit() helper to print templates
    
    The immediate use case is allowing the destination library's
    shortname to print on booking capture slips.
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/PrintTemplate.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/PrintTemplate.pm
index be76da0ce4..47dc807c29 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/PrintTemplate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/PrintTemplate.pm
@@ -208,7 +208,14 @@ $helpers = {
         my $tz = shift || 'local';
         my $date = DateTime->now(time_zone => $tz);
         return $helpers->{format_date}->($date);
-    }
+    },
+
+    get_org_unit => sub {
+        my $org_id = shift;
+        return $org_id if ref $org_id;
+        return new_editor()->retrieve_actor_org_unit($org_id);
+    },
+
 };
 
 

commit cf548943e5bda1bf204a591d069ab203248efe5c
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Jun 18 13:56:40 2020 -0400

    LP#1851306: (follow-up) fix AngularJS staff client navbar link
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/templates/staff/navbar.tt2 b/Open-ILS/src/templates/staff/navbar.tt2
index 1a90182afb..35e542332c 100644
--- a/Open-ILS/src/templates/staff/navbar.tt2
+++ b/Open-ILS/src/templates/staff/navbar.tt2
@@ -451,7 +451,7 @@
             </a>
           </li>
           <li>
-            <a href="/eg2/booking/capture" target="_self">
+            <a href="/eg2/staff/booking/capture" target="_self">
               <span class="glyphicon glyphicon-pushpin"></span>
               [% l('Capture Resources') %]
             </a>

commit 5bc6611bc0255d8d982d92286fe210746c30b5be
Author: Jane Sandberg <sandbej at linnbenton.edu>
Date:   Sat Nov 16 20:50:00 2019 -0800

    LP1851306: Port Capture Booking Resource to Angular
    
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Terran McCanna <tmccanna at georgialibraries.org>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/booking/booking.module.ts b/Open-ILS/src/eg2/src/app/staff/booking/booking.module.ts
index dbcfb03b8f..bb3d1b1006 100644
--- a/Open-ILS/src/eg2/src/app/staff/booking/booking.module.ts
+++ b/Open-ILS/src/eg2/src/app/staff/booking/booking.module.ts
@@ -3,6 +3,7 @@ import {ReactiveFormsModule} from '@angular/forms';
 import {StaffCommonModule} from '@eg/staff/common.module';
 import {BookingRoutingModule} from './routing.module';
 import {CancelReservationDialogComponent} from './cancel-reservation-dialog.component';
+import {CaptureComponent} from './capture.component';
 import {CreateReservationComponent} from './create-reservation.component';
 import {CreateReservationDialogComponent} from './create-reservation-dialog.component';
 import {ManageReservationsComponent} from './manage-reservations.component';
@@ -28,6 +29,7 @@ import {OrgFamilySelectModule} from '@eg/share/org-family-select/org-family-sele
     ],
     declarations: [
         CancelReservationDialogComponent,
+        CaptureComponent,
         CreateReservationComponent,
         CreateReservationDialogComponent,
         ManageReservationsComponent,
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/capture.component.html b/Open-ILS/src/eg2/src/app/staff/booking/capture.component.html
new file mode 100644
index 0000000000..b840f4140c
--- /dev/null
+++ b/Open-ILS/src/eg2/src/app/staff/booking/capture.component.html
@@ -0,0 +1,22 @@
+<eg-string #noResourceString i18n-text text="No resource found with this barcode"></eg-string>
+<eg-string #captureSuccessString i18n-text text="Resource successfully captured"></eg-string>
+<eg-string #captureFailureString i18n-text text="Could not capture this resource"></eg-string>
+
+<eg-staff-banner bannerText="Booking Capture" i18n-bannerText>
+</eg-staff-banner>
+<eg-title i18n-prefix i18n-suffix prefix="Booking" suffix="Capture"></eg-title>
+
+<form [formGroup]="findResource" class="row">
+  <div class="col-md-4">
+    <div class="input-group flex-nowrap">
+      <div class="input-group-prepend">
+        <label class="input-group-text" for="resource-barcode" i18n>Resource barcode</label>
+        <input type="text" id="resource-barcode" class="form-control" formControlName="resourceBarcode">
+      </div>
+    </div>
+  </div>
+</form>
+
+<h2 class="text-center mt-2" i18n>Captured today</h2>
+<eg-reservations-grid #capturedTodayGrid status="capturedToday" persistSuffix="captured"></eg-reservations-grid>
+
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/capture.component.ts b/Open-ILS/src/eg2/src/app/staff/booking/capture.component.ts
new file mode 100644
index 0000000000..5e4b7b3cf4
--- /dev/null
+++ b/Open-ILS/src/eg2/src/app/staff/booking/capture.component.ts
@@ -0,0 +1,89 @@
+import {Component, OnInit, OnDestroy, ViewChild} from '@angular/core';
+import {FormGroup, FormControl} from '@angular/forms';
+import {of, Subscription} from 'rxjs';
+import {debounceTime, single, switchMap, tap} from 'rxjs/operators';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {BookingResourceBarcodeValidator} from './booking_resource_validator.directive';
+import {ReservationActionsService} from './reservation-actions.service';
+import {ReservationsGridComponent} from './reservations-grid.component';
+
+ at Component({
+  templateUrl: './capture.component.html'
+})
+
+export class CaptureComponent implements OnInit, OnDestroy {
+
+    findResource: FormGroup;
+    subscriptions: Subscription[] = [];
+
+    @ViewChild('capturedTodayGrid', { static: false }) capturedTodayGrid: ReservationsGridComponent;
+    @ViewChild('noResourceString', { static: true }) noResourceString: StringComponent;
+    @ViewChild('captureSuccessString', { static: true }) captureSuccessString: StringComponent;
+    @ViewChild('captureFailureString', { static: true }) captureFailureString: StringComponent;
+
+    constructor(
+        private auth: AuthService,
+        private net: NetService,
+        private resourceValidator: BookingResourceBarcodeValidator,
+        private toast: ToastService,
+        private actions: ReservationActionsService
+    ) {
+    }
+
+    ngOnInit() {
+        this.findResource = new FormGroup({
+            'resourceBarcode': new FormControl(null, [], this.resourceValidator.validate)
+        });
+
+        const debouncing = 1500;
+        this.subscriptions.push(
+            this.resourceBarcode.valueChanges.pipe(
+                debounceTime(debouncing),
+                switchMap((val) => {
+                    if ('INVALID' === this.resourceBarcode.status) {
+                        this.noResourceString.current()
+                            .then(str => this.toast.danger(str));
+                        return of();
+                    } else {
+                        return this.net.request( 'open-ils.booking',
+                        'open-ils.booking.resources.capture_for_reservation',
+                        this.auth.token(), this.resourceBarcode.value )
+                        .pipe(switchMap((result: any) => {
+                            if (result && result.ilsevent !== undefined) {
+                                if (result.payload && result.payload.captured > 0) {
+                                    this.captureSuccessString.current()
+                                        .then(str => this.toast.success(str));
+                                    this.actions.printCaptureSlip(result.payload);
+                                    this.capturedTodayGrid.reloadGrid();
+                                } else {
+                                    this.captureFailureString.current()
+                                        .then(str => this.toast.danger(str));
+                                }
+                            } else {
+                                this.captureFailureString.current()
+                                    .then(str => this.toast.danger(str));
+                            }
+                            return of();
+                        }));
+                    }
+                })
+            )
+            .subscribe());
+
+    }
+
+    get resourceBarcode() {
+        return this.findResource.get('resourceBarcode');
+    }
+
+
+    ngOnDestroy(): void {
+        this.subscriptions.forEach((subscription) => {
+            subscription.unsubscribe();
+        });
+    }
+
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/reservation-actions.service.ts b/Open-ILS/src/eg2/src/app/staff/booking/reservation-actions.service.ts
index 5545d06225..79f5b33994 100644
--- a/Open-ILS/src/eg2/src/app/staff/booking/reservation-actions.service.ts
+++ b/Open-ILS/src/eg2/src/app/staff/booking/reservation-actions.service.ts
@@ -1,14 +1,33 @@
 import {Injectable} from '@angular/core';
 import {Router} from '@angular/router';
+import {Observable, of} from 'rxjs';
+import {mergeMap, switchMap, tap} from 'rxjs/operators';
+import {IdlObject} from '@eg/core/idl.service';
+import {AuthService} from '@eg/core/auth.service';
+import {PrintService} from '@eg/share/print/print.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 
 // Some grid actions that are shared across booking grids
 
+export interface CaptureInformation {
+    captured: number;
+    reservation: IdlObject;
+    mvr?: IdlObject;
+    new_copy_status?: number;
+    transit?: IdlObject;
+    resource?: IdlObject;
+    type?: IdlObject;
+    staff?: IdlObject;
+    workstation?: string;
+}
+
 @Injectable({providedIn: 'root'})
 export class ReservationActionsService {
 
     constructor(
+        private auth: AuthService,
         private pcrud: PcrudService,
+        private printer: PrintService,
         private router: Router,
     ) {
     }
@@ -17,6 +36,21 @@ export class ReservationActionsService {
         this.router.navigate(['/staff', 'booking', 'manage_reservations', 'by_resource', barcode]);
     }
 
+    printCaptureSlip = (templateData: CaptureInformation) => {
+        templateData.staff = this.auth.user();
+        templateData.workstation = this.auth.workstation();
+        this.printer.print({
+            templateName: 'booking_capture',
+            contextData: templateData,
+            printContext: 'receipt'
+        });
+    }
+
+    reprintCaptureSlip = (ids: number[]): Observable<CaptureInformation> => {
+        return this.fetchDataForCaptureSlip$(ids)
+        .pipe(tap((data) => this.printCaptureSlip(data)));
+    }
+
     viewItemStatus = (barcode: string) => {
         this.pcrud.search('acp', { 'barcode': barcode }, { limit: 1 })
         .subscribe((acp) => {
@@ -28,5 +62,34 @@ export class ReservationActionsService {
         return (new Set(ids).size !== 1);
     }
 
+    private fetchDataForCaptureSlip$ = (ids: number[]): Observable<CaptureInformation> => {
+        return this.pcrud.search('bresv', {'id': ids}, {
+            flesh: 2,
+            flesh_fields : {
+                'bresv': ['usr', 'current_resource', 'type'],
+                'au': ['card'],
+                'brsrc': ['type']
+            }
+        }).pipe(mergeMap((reservation: IdlObject) => this.assembleDataForCaptureSlip$(reservation)));
+    }
+
+    private assembleDataForCaptureSlip$ = (reservation: IdlObject): Observable<CaptureInformation> => {
+        let observable$ = of({
+            reservation: reservation,
+            captured: 1
+        });
+        if (reservation.pickup_lib() === this.auth.user().ws_ou()) {
+            observable$ = this.pcrud.search('artc', {'reservation': reservation.id()}, {limit: 1})
+            .pipe(switchMap(transit => {
+                return of({
+                    reservation: reservation,
+                    captured: 1,
+                    transit: transit
+                });
+            }));
+        }
+        return observable$;
+    }
+
 }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.html b/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.html
index b8b5b51e8d..42f4b3eef3 100644
--- a/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.html
@@ -5,6 +5,7 @@
   persistKey="booking.{{persistSuffix}}" >
   <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)" [disableOnRows]="editNotAppropriate"></eg-grid-toolbar-action>
   <eg-grid-toolbar-action label="Cancel Selected" i18n-label (onClick)="cancelSelected($event)" [disableOnRows]="cancelNotAppropriate"></eg-grid-toolbar-action>
+  <eg-grid-toolbar-action label="Reprint Capture Slip" i18n-label (onClick)="reprintCaptureSlip($event)" [disableOnRows]="reprintNotAppropriate"></eg-grid-toolbar-action>
   <eg-grid-toolbar-action label="Pick Up Selected" i18n-label (onClick)="pickupSelected($event)" [disableOnRows]="pickupNotAppropriate"></eg-grid-toolbar-action>
   <eg-grid-toolbar-action label="Return Selected" i18n-label (onClick)="returnSelected($event)" [disableOnRows]="returnNotAppropriate"></eg-grid-toolbar-action>
   <eg-grid-toolbar-action label="View Patron Record" i18n-label (onClick)="viewPatronRecord($event)" [disableOnRows]="notOnePatronSelected"></eg-grid-toolbar-action>
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.ts b/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.ts
index 4e75a61503..79caf7ce75 100644
--- a/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/booking/reservations-grid.component.ts
@@ -31,7 +31,7 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
     @Input() resourceBarcode: string;
     @Input() resourceType: number;
     @Input() pickupLibIds: number[];
-    @Input() status: 'pickupReady' | 'pickedUp' | 'returnReady' | 'returnedToday';
+    @Input() status: 'capturedToday' | 'pickupReady' | 'pickedUp' | 'returnReady' | 'returnedToday';
     @Input() persistSuffix: string;
     @Input() onlyCaptured = false;
 
@@ -51,6 +51,7 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
     editSelected: (rows: IdlObject[]) => void;
     pickupSelected: (rows: IdlObject[]) => void;
     pickupResource: (rows: IdlObject) => Observable<any>;
+    reprintCaptureSlip: (rows: IdlObject[]) => void;
     returnSelected: (rows: IdlObject[]) => void;
     returnResource: (rows: IdlObject) => Observable<any>;
     cancelSelected: (rows: IdlObject[]) => void;
@@ -63,14 +64,13 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
     handleRowActivate: (row: IdlObject) => void;
     redirectToCreate: () => void;
 
-    reloadGrid: () => void;
-
     noSelectedRows: (rows: IdlObject[]) => boolean;
     notOnePatronSelected: (rows: IdlObject[]) => boolean;
     notOneResourceSelected: (rows: IdlObject[]) => boolean;
     notOneCatalogedItemSelected: (rows: IdlObject[]) => boolean;
     cancelNotAppropriate: (rows: IdlObject[]) => boolean;
     pickupNotAppropriate: (rows: IdlObject[]) => boolean;
+    reprintNotAppropriate: (rows: IdlObject[]) => boolean;
     editNotAppropriate: (rows: IdlObject[]) => boolean;
     returnNotAppropriate: (rows: IdlObject[]) => boolean;
 
@@ -122,6 +122,9 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
                     where['return_time'] = null;
                 } else if ('returnedToday' === this.status) {
                     where['return_time'] = {'>': Moment().startOf('day').toISOString()};
+                } else if ('capturedToday' === this.status) {
+                    where['capture_time'] = {'between': [Moment().startOf('day').toISOString(),
+                        Moment().add(1, 'day').startOf('day').toISOString()]};
                 }
             } else {
                 where['return_time'] = null;
@@ -185,12 +188,23 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
         };
         this.cancelNotAppropriate = (rows: IdlObject[]) =>
             (this.noSelectedRows(rows) || ['pickedUp', 'returnReady', 'returnedToday'].includes(this.status));
-        this.pickupNotAppropriate = (rows: IdlObject[]) => (this.noSelectedRows(rows) || ('pickupReady' !== this.status));
+        this.pickupNotAppropriate = (rows: IdlObject[]) =>
+            (this.noSelectedRows(rows) || !('pickupReady' === this.status || 'capturedToday' === this.status));
         this.editNotAppropriate = (rows: IdlObject[]) => (this.noSelectedRows(rows) || ('returnedToday' === this.status));
+        this.reprintNotAppropriate = (rows: IdlObject[]) => {
+            if (this.noSelectedRows(rows)) {
+                return true;
+            } else if ('capturedToday' === this.status) {
+                return false;
+            } else if (rows.filter(row => !(row.capture_time())).length) { // If any of the rows have not been captured
+                return true;
+            }
+            return false;
+        };
         this.returnNotAppropriate = (rows: IdlObject[]) => {
             if (this.noSelectedRows(rows)) {
                 return true;
-            } else if (this.status && ('pickupReady' === this.status)) {
+            } else if (this.status && ('pickupReady' === this.status || 'capturedToday' === this.status)) {
                 return true;
             } else {
                 rows.forEach(row => {
@@ -200,8 +214,6 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
             return false;
         };
 
-        this.reloadGrid = () => { this.grid.reload(); };
-
         this.pickupSelected = (reservations: IdlObject[]) => {
             const pickupOne = (thing: IdlObject) => {
                 if (!thing) { return; }
@@ -220,6 +232,10 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
             returnOne(reservations.shift());
         };
 
+        this.reprintCaptureSlip = (reservations: IdlObject[]) => {
+            this.actions.reprintCaptureSlip(reservations.map((r) => r.id())).subscribe();
+        };
+
         this.pickupResource = (reservation: IdlObject) => {
             return this.net.request(
                'open-ils.circ',
@@ -278,6 +294,8 @@ export class ReservationsGridComponent implements OnChanges, OnInit {
 
     ngOnChanges() { this.reloadGrid(); }
 
+    reloadGrid() { this.grid.reload(); }
+
     enrichRow$ = (row: IdlObject): Observable<IdlObject> => {
         return from(this.org.settings('lib.timezone', row.pickup_lib().id())).pipe(
             switchMap((tz) => {
diff --git a/Open-ILS/src/eg2/src/app/staff/booking/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/booking/routing.module.ts
index bc12e96a45..75e34ba7e3 100644
--- a/Open-ILS/src/eg2/src/app/staff/booking/routing.module.ts
+++ b/Open-ILS/src/eg2/src/app/staff/booking/routing.module.ts
@@ -1,5 +1,6 @@
 import {NgModule} from '@angular/core';
 import {RouterModule, Routes} from '@angular/router';
+import {CaptureComponent} from './capture.component';
 import {CreateReservationComponent} from './create-reservation.component';
 import {ManageReservationsComponent} from './manage-reservations.component';
 import {PickupComponent} from './pickup.component';
@@ -20,6 +21,9 @@ const routes: Routes = [{
       {path: 'by_resource/:resource_barcode', component: ManageReservationsComponent},
       {path: 'by_resource_type/:resource_type_id', component: ManageReservationsComponent},
   ]}, {
+  path: 'capture',
+  component: CaptureComponent
+  }, {
   path: 'pickup',
     children: [
       {path: '', component: PickupComponent},
diff --git a/Open-ILS/src/eg2/src/app/staff/nav.component.html b/Open-ILS/src/eg2/src/app/staff/nav.component.html
index 5310b5b340..b6641b4b44 100644
--- a/Open-ILS/src/eg2/src/app/staff/nav.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/nav.component.html
@@ -318,7 +318,7 @@
             <span class="material-icons">list</span>
             <span i18n>Pull List</span>
           </a>
-          <a class="dropdown-item" href="/eg/staff/booking/legacy/booking/capture">
+          <a class="dropdown-item" routerLink="/staff/booking/capture">
             <span class="material-icons">pin_drop</span>
             <span i18n>Capture Resources</span>
           </a>
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index b6959bb20e..6370049352 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -20280,6 +20280,42 @@ $TEMPLATE$
 $TEMPLATE$
 );
 
+INSERT INTO config.print_template
+    (id, name, locale, active, owner, label, template)
+VALUES (
+    3, 'booking_capture', 'en-US', TRUE,
+    (SELECT id FROM actor.org_unit WHERE parent_ou IS NULL),
+    oils_i18n_gettext(3, 'Booking capture slip', 'cpt', 'label'),
+$TEMPLATE$
+[%-
+    USE date;
+    SET data = template_data;
+    # template_data is data returned from open-ils.booking.resources.capture_for_reservation.
+-%]
+<div>
+  [% IF data.transit %]
+  <div>This item need to be routed to <strong>data.transit.dest</strong></div>
+  [% ELSE %]
+  <div>This item need to be routed to <strong>RESERVATION SHELF:</strong></div>
+  [% END %]
+  <div>Barcode: [% data.reservation.current_resource.barcode %]</div>
+  <div>Title: [% data.reservation.current_resource.type.name %]</div>
+  <div>Note: [% data.reservation.note %]</div>
+  <br/>
+  <p><strong>Reserved for patron</strong> [% data.reservation.usr.family_name %], [% data.reservation.usr.first_given_name %] [% data.reservation.usr.second_given_name %]
+  <br/>Barcode: [% data.reservation.usr.card.barcode %]</p>
+  <p>Request time: [% date.format(helpers.format_date(data.reservation.request_time, client_timezone), '%x %r', locale) %]
+  <br/>Reserved from:
+    [% date.format(helpers.format_date(data.reservation.start_time, client_timezone), '%x %r', locale) %]
+    - [% date.format(helpers.format_date(data.reservation.end_time, client_timezone), '%x %r', locale) %]</p>
+  <p>Slip date: [% date.format(helpers.current_date(client_timezone), '%x %r', locale) %]<br/>
+  Printed by [% data.staff.family_name %], [% data.staff.first_given_name %] [% data.staff.second_given_name %]
+    at [% data.workstation %]</p>
+</div>
+<br/>
+
+$TEMPLATE$
+);
 
 -- Allow for 1k stock templates
 SELECT SETVAL('config.print_template_id_seq'::TEXT, 1000);
@@ -20328,6 +20364,12 @@ VALUES (
         'Grid Config: Booking Return Resource tab Returned Today grid',
         'cwst', 'label')
 ), (
+    'eg.grid.booking.captured', 'gui', 'object',
+    oils_i18n_gettext(
+        'booking.manage',
+        'Grid Config: Booking Captured Reservations',
+        'cwst', 'label')
+), (
     'eg.booking.manage.selected_org_family', 'gui', 'object',
     oils_i18n_gettext(
         'booking.manage.selected_org_family',
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
new file mode 100644
index 0000000000..fbf53fc4ff
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.port_capture_reservations_to_angular.sql
@@ -0,0 +1,52 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.print_template 
+    (id, name, locale, active, owner, label, template) 
+VALUES (
+    3, 'booking_capture', 'en-US', TRUE,
+    (SELECT id FROM actor.org_unit WHERE parent_ou IS NULL),
+    oils_i18n_gettext(3, 'Booking capture slip', 'cpt', 'label'),
+$TEMPLATE$
+[%-
+    USE date;
+    SET data = template_data;
+    # template_data is data returned from open-ils.booking.resources.capture_for_reservation.
+-%]
+<div>
+  [% IF data.transit %]
+  <div>This item need to be routed to <strong>data.transit.dest</strong></div>
+  [% ELSE %]
+  <div>This item need to be routed to <strong>RESERVATION SHELF:</strong></div>
+  [% END %]
+  <div>Barcode: [% data.reservation.current_resource.barcode %]</div>
+  <div>Title: [% data.reservation.current_resource.type.name %]</div>
+  <div>Note: [% data.reservation.note %]</div>
+  <br/>
+  <p><strong>Reserved for patron</strong> [% data.reservation.usr.family_name %], [% data.reservation.usr.first_given_name %] [% data.reservation.usr.second_given_name %]
+  <br/>Barcode: [% data.reservation.usr.card.barcode %]</p>
+  <p>Request time: [% date.format(helpers.format_date(data.reservation.request_time, client_timezone), '%x %r', locale) %]
+  <br/>Reserved from:
+    [% date.format(helpers.format_date(data.reservation.start_time, client_timezone), '%x %r', locale) %]
+    - [% date.format(helpers.format_date(data.reservation.end_time, client_timezone), '%x %r', locale) %]</p>
+  <p>Slip date: [% date.format(helpers.current_date(client_timezone), '%x %r', locale) %]<br/>
+  Printed by [% data.staff.family_name %], [% data.staff.first_given_name %] [% data.staff.second_given_name %]
+    at [% data.workstation %]</p>
+</div>
+<br/>
+
+$TEMPLATE$
+);
+
+INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
+VALUES (
+    'eg.grid.booking.captured', 'gui', 'object',
+    oils_i18n_gettext(
+        'booking.manage',
+        'Grid Config: Booking Captured Reservations',
+        'cwst', 'label')
+);
+
+
+COMMIT;
diff --git a/Open-ILS/src/templates/staff/navbar.tt2 b/Open-ILS/src/templates/staff/navbar.tt2
index 220c3d1d1f..1a90182afb 100644
--- a/Open-ILS/src/templates/staff/navbar.tt2
+++ b/Open-ILS/src/templates/staff/navbar.tt2
@@ -451,7 +451,7 @@
             </a>
           </li>
           <li>
-            <a href="./booking/legacy/booking/capture" target="_self">
+            <a href="/eg2/booking/capture" target="_self">
               <span class="glyphicon glyphicon-pushpin"></span>
               [% l('Capture Resources') %]
             </a>
diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/angular-booking-capture.adoc b/docs/RELEASE_NOTES_NEXT/Circulation/angular-booking-capture.adoc
new file mode 100644
index 0000000000..3d2aca728d
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Circulation/angular-booking-capture.adoc
@@ -0,0 +1,13 @@
+Booking Capture is now in Angular
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The interface to capture resources for booking
+reservations has been re-implemented in Angular.
+Other booking screens, such as Pick Up and
+Manage Reservations, now include an option to 
+re-print capture slips.
+
+System administrators can now edit the template
+for booking capture slips in Administration ->
+Server administration -> Print templates.
+

-----------------------------------------------------------------------

Summary of changes:
 .../eg2/src/app/staff/booking/booking.module.ts    |  2 +
 .../src/app/staff/booking/capture.component.html   | 22 ++++++
 .../eg2/src/app/staff/booking/capture.component.ts | 89 ++++++++++++++++++++++
 .../staff/booking/reservation-actions.service.ts   | 63 +++++++++++++++
 .../staff/booking/reservations-grid.component.html |  1 +
 .../staff/booking/reservations-grid.component.ts   | 32 ++++++--
 .../eg2/src/app/staff/booking/routing.module.ts    |  4 +
 Open-ILS/src/eg2/src/app/staff/nav.component.html  |  2 +-
 .../src/perlmods/lib/OpenILS/WWW/PrintTemplate.pm  |  9 ++-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |  2 +-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       | 44 +++++++++++
 ...5.data.port_capture_reservations_to_angular.sql | 54 +++++++++++++
 Open-ILS/src/templates/staff/navbar.tt2            |  2 +-
 .../Circulation/angular-booking-capture.adoc       | 13 ++++
 14 files changed, 328 insertions(+), 11 deletions(-)
 create mode 100644 Open-ILS/src/eg2/src/app/staff/booking/capture.component.html
 create mode 100644 Open-ILS/src/eg2/src/app/staff/booking/capture.component.ts
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1205.data.port_capture_reservations_to_angular.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/angular-booking-capture.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list