LP#1929587 Place hold button in staff client
authorDan Briem <dbriem@wlsmail.org>
Thu, 3 Jun 2021 00:53:44 +0000 (20:53 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 20 Sep 2021 14:48:00 +0000 (10:48 -0400)
Disables and gray's out the place hold button on records in the
Angular catalog that are deleted or have no holdable copies
unless the user has the perm PLACE_UNFILLABLE_HOLD.

To test:
* Search for records with and without any copies
* Search for records with and without holdable copies
* Search as user with and without the permission
  PLACE_UNFILLABLE_HOLD

Signed-off-by: Dan Briem <dbriem@wlsmail.org>
Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Signed-off-by: Bill Erickson <berickxx@gmail.com>

Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm

index c64357d..a4dd0b0 100644 (file)
@@ -6,6 +6,7 @@ import {UnapiService} from '@eg/share/catalog/unapi.service';
 import {IdlService, IdlObject} from '@eg/core/idl.service';
 import {NetService} from '@eg/core/net.service';
 import {PcrudService} from '@eg/core/pcrud.service';
+import {PermService} from '@eg/core/perm.service';
 
 export const NAMESPACE_MAPS = {
     'mods':     'http://www.loc.gov/mods/v3',
@@ -50,6 +51,7 @@ export class BibRecordSummary {
     displayHighlights: {[name: string]: string | string[]} = {};
     eResourceUrls: EResourceUrl[] = [];
     copies: any[];
+    isHoldable: boolean;
 
     constructor(record: IdlObject, orgId: number, orgDepth?: number) {
         this.id = Number(record.id());
@@ -91,15 +93,21 @@ export class BibRecordService {
     // Cache of bib editor / creator objects
     // Assumption is this list will be limited in size.
     userCache: {[id: number]: IdlObject};
+    allowUnfillableHolds: boolean;
 
     constructor(
         private idl: IdlService,
         private net: NetService,
         private org: OrgService,
         private unapi: UnapiService,
-        private pcrud: PcrudService
+        private pcrud: PcrudService,
+        private perm: PermService
     ) {
         this.userCache = {};
+        this.perm.hasWorkPermHere(['PLACE_UNFILLABLE_HOLD'])
+            .then(perms => {
+                this.allowUnfillableHolds = perms.PLACE_UNFILLABLE_HOLD;
+            });
     }
 
     getBibSummary(id: number,
@@ -129,6 +137,10 @@ export class BibRecordService {
             summary.firstCallNumber = bibSummary.first_call_number;
             summary.prefOuHoldingsSummary = bibSummary.pref_ou_copy_counts;
 
+            summary.isHoldable = bibSummary.record.deleted() === 'f'
+                && bibSummary.has_holdable_copy
+                || this.allowUnfillableHolds;
+
             return summary;
         }));
     }
@@ -156,6 +168,10 @@ export class BibRecordService {
             summary.firstCallNumber = metabibSummary.first_call_number;
             summary.prefOuHoldingsSummary = metabibSummary.pref_ou_copy_counts;
 
+            summary.isHoldable = metabibSummary.record.deleted() === 'f'
+                && metabibSummary.has_holdable_copy
+                || this.allowUnfillableHolds;
+
             return summary;
         }));
     }
index 78f4695..8634f82 100644 (file)
     <button class="btn btn-outline-primary ml-1" i18n>Patron View</button>
   </a>
 
-  <a routerLink="/staff/catalog/hold/T" [queryParams]="{target: recId}">
+  <a routerLink="/staff/catalog/hold/T" [queryParams]="{target: recId}"
+    *ngIf="isHoldable">
     <button class="btn btn-outline-primary ml-1" i18n>Place Hold</button>
   </a>
+  <button class="btn btn-outline-secondary ml-1" *ngIf="!isHoldable" disabled i18n>
+    Place Hold
+  </button>
 
   <button class="btn btn-outline-primary ml-1" (click)="addHoldings()" i18n>
     Add Holdings
index bb4eca1..bc50745 100644 (file)
@@ -52,6 +52,8 @@ export class RecordActionsComponent implements OnInit {
         }
     }
 
+    @Input() isHoldable: boolean;
+
     constructor(
         private router: Router,
         private store: StoreService,
index 693c288..c245e88 100644 (file)
@@ -23,6 +23,7 @@
     <div class="flex-1"></div>
     <div id='staff-catalog-bib-navigation'>
       <eg-catalog-record-actions [recordId]="recordId"
+        [isHoldable]="summary && summary.isHoldable"
         (addHoldingsRequested)="addHoldingsRequested()">
       </eg-catalog-record-actions>
     </div>
index 115d92a..868d6fe 100644 (file)
               <ng-container *ngIf="summary.record.deleted() == 't'">
                 <span class="text-danger" i18n>(Deleted)</span>
               </ng-container>
-              <ng-container *ngIf="summary.record.deleted() == 'f'">
-                <span>
-                  <button (click)="placeHold()"
-                    class="btn btn-sm btn-success label-with-material-icon small-text-1">
-                    <span class="material-icons">check</span>
-                    <span i18n>Place Hold</span>
-                  </button>
-                </span>
-              </ng-container>
+              <span>
+                <button (click)="placeHold()" [disabled]="!summary.isHoldable"
+                  [ngClass]="summary.isHoldable ? 'btn-success' : 'btn-secondary'"
+                  class="btn btn-sm label-with-material-icon small-text-1">
+                  <span class="material-icons">check</span>
+                  <span i18n>Place Hold</span>
+                </button>
+              </span>
             </div>
           </div>
         </div>
index ab372c8..912e626 100644 (file)
@@ -3088,6 +3088,12 @@ sub catalog_record_summary {
 
     $copy_method = $self->method_lookup($copy_method); # local method
 
+    my $holdable_method = $is_meta ?
+        'open-ils.search.biblio.metarecord.has_holdable_copy':
+        'open-ils.search.biblio.record.has_holdable_copy';
+
+    $holdable_method = $self->method_lookup($holdable_method); # local method
+
     for my $rec_id (@$record_ids) {
 
         my $response = $is_meta ? 
@@ -3121,6 +3127,8 @@ sub catalog_record_summary {
                 $e, $rec_id, $org_id, $is_staff, $is_meta, $options);
         }
 
+        ($response->{has_holdable_copy}) = $holdable_method->run($rec_id);
+
         $client->respond($response);
     }