routerLink="/staff/admin/local/config/hold_matrix_matchpoint"></eg-link-table-link>
<eg-link-table-link i18n-label label="Holdings Template Editor"
url="/eg/staff/cat/volcopy/edit_templates"></eg-link-table-link>
+ <eg-link-table-link i18n-label label="Hopeless Holds"
+ routerLink="/staff/hopeless"></eg-link-table-link>
<eg-link-table-link i18n-label label="Item Alert Suppression"
routerLink="/staff/admin/local/actor/copy_alert_suppress"></eg-link-table-link>
<eg-link-table-link i18n-label label="Item Alert Types"
--- /dev/null
+
+<eg-staff-banner bannerText="Hopeless Holds" i18n-bannerText>
+</eg-staff-banner>
+<eg-title i18n-prefix prefix="Hopeless Holds">
+</eg-title>
+
+<div class="input-group"><div class="input-group-prepend">
+ <div class="input-group-text" i18n>Hopeless Date, Start Range:</div>
+ <eg-date-select [initialIso]="startDate" (onChangeAsDate)="changeStartDate($event)">
+ </eg-date-select>
+ <div class="input-group-text" i18n>Hopeless Date, End Range:</div>
+ <eg-date-select [initialIso]="endDate" (onChangeAsDate)="changeEndDate($event)">
+ </eg-date-select>
+</div></div>
+
+<eg-holds-grid
+ hopeless="true" [showHopelessAfter]="startDate" [showHopelessBefore]="endDate"
+ preFetchSetting="hopeless.holds.prefetch"
+ persistKey="hopeless.wide_holds"
+ [defaultSort]="[{name:'request_time',dir:'asc'}]"
+ [initialPickupLib]="workstation_lib"
+ showFields="id,request_time,ucard_barcode,pl_shortname,hold_type,holdable_formats,title,p_label,hold_status,hopeless_date"
+>
+</eg-holds-grid>
+
--- /dev/null
+
+import {Component, OnInit, ViewChild, Input, TemplateRef} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {FormatService} from '@eg/core/format.service';
+import {Pager} from '@eg/share/util/pager';
+import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
+import {BibRecordService, BibRecordSummary} from '@eg/share/catalog/bib-record.service';
+
+@Component({
+ templateUrl: 'hopeless.component.html'
+})
+export class HopelessComponent implements OnInit {
+
+ startDate: any;
+ endDate: any;
+ workstation_lib: IdlObject;
+
+ changeStartDate(date) {
+ this.startDate = date;
+ }
+
+ changeEndDate(date) {
+ date.setHours(23);
+ date.setMinutes(59);
+ date.setSeconds(59);
+ this.endDate = date;
+ }
+
+ constructor(
+ private pcrud: PcrudService,
+ private auth: AuthService,
+ private format: FormatService,
+ private bib: BibRecordService,
+ ) {}
+
+ ngOnInit() {
+
+ // for the pickup library selector
+ this.workstation_lib = this.auth.user().ws_ou();
+
+ // Default startDate to today - 10 years
+ const sd = new Date();
+ sd.setFullYear( sd.getFullYear() - 10 );
+ this.startDate = sd.toISOString();
+
+ // Default endDate to today.
+ const ed = new Date();
+ ed.setHours(23);
+ ed.setMinutes(59);
+ ed.setSeconds(59);
+ this.endDate = ed.toISOString();
+
+ }
+
+}
+
+
--- /dev/null
+import {NgModule} from '@angular/core';
+import {StaffCommonModule} from '@eg/staff/common.module';
+import {CatalogCommonModule} from '@eg/share/catalog/catalog-common.module';
+import {HopelessRoutingModule} from './routing.module';
+import {HopelessComponent} from './hopeless.component';
+import {HoldsModule} from '@eg/staff/share/holds/holds.module';
+
+@NgModule({
+ declarations: [
+ HopelessComponent
+ ],
+ imports: [
+ StaffCommonModule,
+ CatalogCommonModule,
+ HopelessRoutingModule,
+ HoldsModule
+ ],
+ providers: [
+ ]
+})
+
+export class HopelessModule {
+
+}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {HopelessComponent} from './hopeless.component';
+
+const routes: Routes = [{
+ path: '',
+ component: HopelessComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: []
+})
+
+export class HopelessRoutingModule {}
loadChildren: () =>
import('./sandbox/sandbox.module').then(m => m.SandboxModule)
}, {
+ path: 'hopeless',
+ loadChildren : '@eg/staff/hopeless/hopeless.module#HopelessModule'
+ }, {
path: 'admin',
loadChildren: () =>
import('./admin/routing.module').then(m => m.AdminRoutingModule)
<eg-grid #holdsGrid [dataSource]="gridDataSource" [sortable]="true"
[useLocalSort]="enablePreFetch" [cellTextGenerator]="cellTextGenerator"
+ [showFields]="showFields"
[multiSortable]="true" [persistKey]="persistKey"
(onRowActivate)="showDetail($event)">
i18-group group="Hold" i18n-label label="Print Holds"
(onClick)="printHolds()"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action *ngIf="hopeless"
+ i18-group group="Item" i18n-label label="View/Place Orders"
+ [disableOnRows]="metaRecordHoldsSelected"
+ (onClick)="showOrder($event)"></eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action *ngIf="hopeless"
+ i18-group group="Item" i18n-label label="Add Holdings"
+ [disableOnRows]="metaRecordHoldsSelected"
+ (onClick)="addVolume($event)"></eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action *ngIf="hopeless"
+ i18-group group="Item" i18n-label label="Show in Catalog"
+ (onClick)="showTitle($event)"></eg-grid-toolbar-action>
+
<eg-grid-column i18n-label label="Hold ID" path='id' [index]="true" datatype="id">
</eg-grid-column>
import {HoldCancelDialogComponent} from './cancel-dialog.component';
import {HoldManageDialogComponent} from './manage-dialog.component';
import {PrintService} from '@eg/share/print/print.service';
+import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
/** Holds grid with access to detail page and other actions */
@Input() initialPickupLib: number | IdlObject;
@Input() hidePickupLibFilter: boolean;
+ // If true, only retrieve holds with a Hopeless Date
+ // and enable related Actions
+ @Input() hopeless: boolean;
+
// Grid persist key
@Input() persistKey: string;
// [{name: fname, dir: 'asc'}, {name: fname2, dir: 'desc'}]
@Input() defaultSort: any[];
+ // To pass through to the underlying eg-grid
+ @Input() showFields: string;
+
mode: 'list' | 'detail' | 'manage' = 'list';
initDone = false;
holdsCount: number;
}
}
+
cellTextGenerator: GridCellTextGenerator;
+ // Include holds marked Hopeless on or after this date.
+ _showHopelessAfter: Date;
+ @Input() set showHopelessAfter(show: Date) {
+ this._showHopelessAfter = show;
+ if (this.initDone) { // reload on update
+ this.holdsGrid.reload();
+ }
+ }
+
+ // Include holds marked Hopeless on or before this date.
+ _showHopelessBefore: Date;
+ @Input() set showHopelessBefore(show: Date) {
+ this._showHopelessBefore = show;
+ if (this.initDone) { // reload on update
+ this.holdsGrid.reload();
+ }
+ }
+
constructor(
private net: NetService,
private org: OrgService,
private store: ServerStoreService,
private auth: AuthService,
- private printer: PrintService
+ private printer: PrintService,
+ private holdings: HoldingsService
) {
this.gridDataSource = new GridDataSource();
this.enablePreFetch = null;
}
applyFilters(): any {
+
const filters: any = {
is_staff_request: true,
fulfillment_time: this._showFulfilledSince ?
this._showCanceledSince.toISOString() : null,
};
+ if (this.hopeless) {
+ filters['hopeless_holds'] = {
+ 'start_date' : this._showHopelessAfter
+ ? (
+ // FIXME -- consistency desired, string or object
+ typeof this._showHopelessAfter === 'object'
+ ? this._showHopelessAfter.toISOString()
+ : this._showHopelessAfter
+ )
+ : '1970-01-01T00:00:00.000Z',
+ 'end_date' : this._showHopelessBefore
+ ? (
+ // FIXME -- consistency desired, string or object
+ typeof this._showHopelessBefore === 'object'
+ ? this._showHopelessBefore.toISOString()
+ : this._showHopelessBefore
+ )
+ : (new Date()).toISOString()
+ };
+ }
+
if (this.pickupLib) {
filters.pickup_lib =
this.org.descendants(this.pickupLib, true);
return observable;
}
+ metaRecordHoldsSelected(rows: IdlObject[]) {
+ var found = false;
+ rows.forEach( row => {
+ if (row.hold_type == 'M') {
+ found = true;
+ }
+ });
+ return found;
+ }
+
showDetails(rows: any[]) {
this.showDetail(rows[0]);
}
}
}
+ showOrder(rows: any[]) {
+ //Doesn't work in Typescript currently without compiler option:
+ // const bibIds = [...new Set( rows.map(r => r.record_id) )];
+ const bibIds = Array.from(
+ new Set( rows.filter(r => r.hold_type!='M').map(r => r.record_id) ));
+ bibIds.forEach( bibId => {
+ const url =
+ '/eg/staff/acq/legacy/lineitem/related/' + bibId + '?target=bib';
+ window.open(url, '_blank');
+ });
+ }
+
+ addVolume(rows: any[]) {
+ const bibIds = Array.from(
+ new Set( rows.filter(r => r.hold_type!='M').map(r => r.record_id) ));
+ bibIds.forEach( bibId => {
+ this.holdings.spawnAddHoldingsUi(bibId);
+ });
+ }
+
+ showTitle(rows: any[]) {
+ const bibIds = Array.from(new Set( rows.map(r => r.record_id) ));
+ bibIds.forEach( bibId => {
+ //const url = '/eg/staff/cat/catalog/record/' + bibId;
+ const url = '/eg2/staff/catalog/record/' + bibId;
+ window.open(url, '_blank');
+ });
+ }
+
showManageDialog(rows: any[]) {
const holdIds = rows.map(r => r.id).filter(id => Boolean(id));
if (holdIds.length > 0) {
my $last_captured_hold = delete($$restrictions{last_captured_hold}) || 'false';
$last_captured_hold = $last_captured_hold eq 'true' ? 1 : 0;
+ # option to filter for hopeless holds by date range
+ my $hopeless_holds = delete($$restrictions{hopeless_holds}) || 'false';
+
my $initial_condition = 'TRUE';
if ($last_captured_hold) {
$initial_condition = <<" SQL";
SQL
}
+ if (ref($hopeless_holds) =~ /HASH/ && $$hopeless_holds{start_date} && $$hopeless_holds{end_date}) {
+ my $start_date = DateTime::Format::ISO8601->parse_datetime(clean_ISO8601($$hopeless_holds{start_date}));
+ my $end_date = DateTime::Format::ISO8601->parse_datetime(clean_ISO8601($$hopeless_holds{end_date}));
+ my $hopeless_condition = "(frozen IS FALSE AND h.hopeless_date >= '$start_date' AND h.hopeless_date <= '$end_date')";
+ $initial_condition .= " AND $hopeless_condition";
+ }
+
my $select = <<" SQL";
WITH
t_field AS (SELECT field FROM config.display_field_map WHERE name = 'title'),
,[ l('Group Penalty Thresholds'), "./admin/local/permission/grp_penalty_threshold" ]
,[ l('Hold Policies'), "./admin/local/config/hold_matrix_matchpoint" ]
,[ l('Holdings Template Editor'), "./cat/volcopy/edit_templates" ]
+ ,[ l('Hopeless Holds'), "/eg2/staff/hopeless" ]
,[ l('Item Alert Suppression'), "./admin/local/actor/copy_alert_suppress" ]
,[ l('Item Alert Types'), "./admin/local/config/copy_alert_types" ]
,[ l('Item Tags'), "./admin/local/asset/copy_tag" ]