import {BarcodesModule} from '@eg/staff/share/barcodes/barcodes.module';
import {CircModule} from '@eg/staff/share/circ/circ.module';
import {ItemSummaryComponent} from './summary.component';
+import {ItemRecentHistoryComponent} from './recent-history.component';
@NgModule({
declarations: [
MarkItemMissingPiecesComponent,
ItemSummaryComponent,
- ItemStatusComponent
+ ItemStatusComponent,
+ ItemRecentHistoryComponent
],
imports: [
StaffCommonModule,
--- /dev/null
+
+<div class="row pt-3" *ngIf="circInfo">
+ <div class="col-lg-6">
+ <div *ngIf="!circInfo.prevCircSummary" class="alert alert-info" i18n>
+ No Previous Circ Group
+ </div>
+ <div class="well-table" *ngIf="item && !loading && circInfo.prevCircSummary">
+ </div>
+ </div>
+ <div class="col-lg-6">
+ <div *ngIf="!circInfo.circSummary" class="alert alert-info" i18n>
+ No Recent Circ Group
+ </div>
+ <div class="well-table" *ngIf="item && !loading && circInfo.currentCirc">
+ <div class="well-row">
+ <div class="well-label" i18n>Patron</div>
+ <div class="well-value" *ngIf="circInfo.currentCirc">
+ <a i18n
+ routerLink="/staff/circInfo.currentCirc/patron/{{circInfo.currentCirc.usr().id()}}">
+ {{circInfo.currentCirc.usr().family_name()}},
+ {{circInfo.currentCirc.usr().first_given_name()}},
+ {{circInfo.currentCirc.usr().second_given_name()}}
+ </a>
+ </div>
+ </div>
+
+ <div class="well-row">
+ <div class="well-label" i18n>Total Circs</div>
+ <div class="well-value">{{circInfo.totalCircs}}</div>
+ </div>
+
+ <div class="well-row">
+ <div class="well-label" i18n>Checkout Date</div>
+ <div class="well-value">
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.circSummary.start_time() | date:format.dateTimeFormat}}
+ </ng-container>
+ </div>
+ </div>
+
+ <div class="well-row">
+ <div class="well-label" i18n>Checkout Workstation</div>
+ <div class="well-value">
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.circSummary.checkout_workstation()}}
+ </ng-container>
+ </div>
+ </div>
+
+ <div class="well-row">
+ <div class="well-label" i18n>Last Renewed On</div>
+ <div class="well-value">
+ <ng-container *ngIf="circInfo.prevCircSummary">
+ {{circInfo.prevCircSummary.last_renewal_time() | date:format.dateTimeFormat}}
+ </ng-container>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
+
--- /dev/null
+import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {OrgService} from '@eg/core/org.service';
+import {PrintService} from '@eg/share/print/print.service';
+import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
+import {EventService} from '@eg/core/event.service';
+import {PermService} from '@eg/core/perm.service';
+import {PatronPenaltyDialogComponent} from '@eg/staff/share/patron/penalty-dialog.component';
+import {BarcodeSelectComponent} from '@eg/staff/share/barcodes/barcode-select.component';
+import {CatalogService} from '@eg/share/catalog/catalog.service';
+import {CircService, ItemCircInfo} from '@eg/staff/share/circ/circ.service';
+import {CopyAlertsDialogComponent
+ } from '@eg/staff/share/holdings/copy-alerts-dialog.component';
+import {FormatService} from '@eg/core/format.service';
+
+@Component({
+ selector: 'eg-item-recent-history',
+ templateUrl: 'recent-history.component.html'
+})
+
+export class ItemRecentHistoryComponent implements OnInit {
+
+ @Input() item: IdlObject;
+
+ loading = false;
+ circInfo: ItemCircInfo;
+
+ @ViewChild('copyAlertsDialog') private copyAlertsDialog: CopyAlertsDialogComponent;
+
+ constructor(
+ private router: Router,
+ private route: ActivatedRoute,
+ private net: NetService,
+ private org: OrgService,
+ private printer: PrintService,
+ private pcrud: PcrudService,
+ private auth: AuthService,
+ private perms: PermService,
+ private idl: IdlService,
+ private evt: EventService,
+ private cat: CatalogService,
+ private holdings: HoldingsService,
+ private circs: CircService,
+ public format: FormatService
+ ) { }
+
+ ngOnInit() {
+ this.loading = true;
+ this.loadCircInfo()
+ .then(_ => this.loading = false);
+ }
+
+ loadCircInfo(): Promise<any> {
+ return this.circs.getItemCircInfo(this.item)
+ .then(info => this.circInfo = info);
+ }
+}
+
+
<eg-item-summary [item]="item"></eg-item-summary>
</ng-template>
</li>
+ <li ngbNavItem="recent-history">
+ <a ngbNavLink i18n>Recent Circ History</a>
+ <ng-template ngbNavContent>
+ <eg-item-recent-history [item]="item"></eg-item-recent-history>
+ </ng-template>
+ </li>
</ul>
<div [ngbNavOutlet]="itemNav"></div>
<div class="well-label" i18n>Due Date</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.due_date() | date:'shortDate'}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.due_date() | date:'shortDate'}}
</ng-container>
</div>
</div>
<div class="well-label" i18n>Checkout Date</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circSummary.start_time() | date:'shortDate'}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.circSummary.start_time() | date:'shortDate'}}
</ng-container>
</div>
</div>
<div class="well-label" i18n>Renewal Type</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- <div *ngIf="circ.opac_renewal() == 't'" i18n>OPAC</div>
- <div *ngIf="circ.desk_renewal() == 't'" i18n>Desk</div>
- <div *ngIf="circ.phone_renewal() == 't'" i18n>Phone</div>
- <div *ngIf="circ.auto_renewal() == 't'" i18n>Automatic</div>
+ <ng-container *ngIf="circInfo.currentCirc">
+ <div *ngIf="circInfo.currentCirc.opac_renewal() == 't'" i18n>OPAC</div>
+ <div *ngIf="circInfo.currentCirc.desk_renewal() == 't'" i18n>Desk</div>
+ <div *ngIf="circInfo.currentCirc.phone_renewal() == 't'" i18n>Phone</div>
+ <div *ngIf="circInfo.currentCirc.auto_renewal() == 't'" i18n>Automatic</div>
</ng-container>
</div>
<div class="well-label" i18n>Checkout Workstation</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circSummary.checkout_workstation()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.circSummary.checkout_workstation()}}
</ng-container>
</div>
</div>
</div>
<div class="well-label" i18n>Total Circs</div>
- <div class="well-value">{{total_circs}}</div>
+ <div class="well-value">{{circInfo.totalCircs}}</div>
<div class="well-label" i18n>Duration Rule</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.duration_rule().name()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.duration_rule().name()}}
</ng-container>
</div>
</div>
<div class="well-value"><eg-bool [value]="item.ref()"></eg-bool></div>
<div class="well-label" i18n>Total Circs - Current Year</div>
- <div class="well-value">{{total_circs_this_year}}</div>
+ <div class="well-value">{{circInfo.circsThisYear}}</div>
<div class="well-label" i18n>Recurring Fine Rule</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.recurring_fine_rule().name()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.recurring_fine_rule().name()}}
</ng-container>
</div>
</div>
<div class="well-value"><eg-bool [value]="item.opac_visible()"></eg-bool></div>
<div class="well-label" i18n>Total Circs - Prev Year</div>
- <div class="well-value">{{total_circs_prev_year}}</div>
+ <div class="well-value">{{circInfo.circsPrevYear}}</div>
<div class="well-label" i18n>Max Fine Rule</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.max_fine_rule().name()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.max_fine_rule().name()}}
</ng-container>
</div>
</div>
<div class="well-label" i18n>Checkin Time</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.checkin_time() ||
- circSummary.last_checkin_time() | date:'shortDate'}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.checkin_time() ||
+ circInfo.circSummary.last_checkin_time() | date:'shortDate'}}
</ng-container>
</div>
</div>
<div class="well-label" i18n>Renewal Workstation</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circSummary.last_renewal_workstation()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.circSummary.last_renewal_workstation()}}
</ng-container>
</div>
<div class="well-label" i18n>Remaining Renewals</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.renewal_remaining()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.renewal_remaining()}}
</ng-container>
</div>
<div class="well-label" i18n>Checkin Scan Time</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- {{circ.checkin_scan_time() ||
- circSummary.last_checkin_scan_time() | date:'shortDate'}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ {{circInfo.currentCirc.checkin_scan_time() ||
+ circInfo.circSummary.last_checkin_scan_time() | date:'shortDate'}}
</ng-container>
</div>
</div>
<div class="well-label" i18n>Checkin Workstation</div>
<div class="well-value">
- <ng-container *ngIf="circ">
- <ng-container *ngIf="circ.checkin_workstation()">
- {{circ.checkin_workstation().name()}}
+ <ng-container *ngIf="circInfo.currentCirc">
+ <ng-container *ngIf="circInfo.currentCirc.checkin_workstation()">
+ {{circInfo.currentCirc.checkin_workstation().name()}}
</ng-container>
<ng-container
- *ngIf="!circ.checkin_workstation() && circSummary.last_checkin_workstation()">
- {{circSummary.last_checkin_workstation().name()}}
+ *ngIf="!circInfo.currentCirc.checkin_workstation() && circInfo.circSummary.last_checkin_workstation()">
+ {{circInfo.circSummary.last_checkin_workstation().name()}}
</ng-container>
</ng-container>
</div>
<div class="well-label" i18n>Item Alerts</div>
<div class="well-value" id="item-status-alert-msg">
<button class="btn btn-outline-dark" (click)="addItemAlerts()" i18n>Add</button>
- <button class="btn btn-outline-dark" [disabled]="item.copy_alerts().length == 0"
+ <button class="btn btn-outline-dark ml-2" [disabled]="item.copy_alerts().length == 0"
(click)="manageItemAlerts()" i18n>Manage</button>
</div>
import {PatronPenaltyDialogComponent} from '@eg/staff/share/patron/penalty-dialog.component';
import {BarcodeSelectComponent} from '@eg/staff/share/barcodes/barcode-select.component';
import {CatalogService} from '@eg/share/catalog/catalog.service';
-import {CircService} from '@eg/staff/share/circ/circ.service';
+import {CircService, ItemCircInfo} from '@eg/staff/share/circ/circ.service';
import {CopyAlertsDialogComponent
} from '@eg/staff/share/holdings/copy-alerts-dialog.component';
@Input() item: IdlObject;
- circ: IdlObject;
- circSummary: IdlObject;
- prevCircSummary: IdlObject;
- prevCircUser: IdlObject;
- maxHistoryCount: number;
loading = false;
+ circInfo: ItemCircInfo;
@ViewChild('copyAlertsDialog') private copyAlertsDialog: CopyAlertsDialogComponent;
}
loadCircInfo(): Promise<any> {
-
- const copyOrg =
- this.item.call_number().id() === -1 ?
- this.item.circ_lib().id() :
- this.item.call_number().owning_lib().id();
-
- return this.perms.hasWorkPermAt(['VIEW_COPY_CHECKOUT_HISTORY'], copyOrg)
- .then(hasPerm => {
- if (hasPerm) {
- return this.org.settings('circ.item_checkout_history.max')
- .then(sets => {
- this.maxHistoryCount = sets['circ.item_checkout_history.max'] || 4;
- });
- }
- })
-
- .then(_ => this.circs.getLatestCirc(this.item.id()))
-
- .then(circ => {
- this.circ = circ;
-
- if (!circ) { return Promise.resolve(); }
-
- return this.circs.getCircChain(this.circ.id())
- .then(summary => {
- this.circSummary = summary;
-
- if (this.maxHistoryCount <= 1) { return; }
-
- return this.circs.getPrevCircChain(this.circ.id())
- .then(prevSummary => {
- if (!prevSummary) { return; }
-
- this.prevCircSummary = prevSummary.summary;
-
- if (prevSummary.usr) { // aged circs have no 'usr'.
-
- return this.pcrud.retrieve('au', prevSummary.usr,
- {flesh : 1, flesh_fields : {au : ['card']}})
- .toPromise().then(user => this.prevCircUser = user);
- }
- });
- });
- });
+ return this.circs.getItemCircInfo(this.item)
+ .then(info => this.circInfo = info);
}
-
addItemAlerts() {
this.copyAlertsDialog.copyIds = [this.item.id()];
this.copyAlertsDialog.mode = 'create';
import {ServerStoreService} from '@eg/core/server-store.service';
import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
import {WorkLogService, WorkLogEntry} from '@eg/staff/share/worklog/worklog.service';
+import {PermService} from '@eg/core/perm.service';
export interface CircDisplayInfo {
title?: string;
destCourierCode?: string;
}
+export interface ItemCircInfo {
+ maxHistoryCount: number;
+ circSummary?: IdlObject;
+ prevCircSummary?: IdlObject;
+ currentCirc?: IdlObject;
+ prevCircUser?: IdlObject;
+ totalCircs: number;
+ circsThisYear: number;
+ circsPrevYear: number;
+}
+
@Injectable()
export class CircService {
static resultIndex = 0;
private auth: AuthService,
private holdings: HoldingsService,
private worklog: WorkLogService,
+ private perms: PermService,
private bib: BibRecordService
) {}
return this.pcrud.search('aacs', {target_copy : copyId}, ops).toPromise();
}
+
+ getItemCircInfo(item: IdlObject): Promise<ItemCircInfo> {
+
+ const response: ItemCircInfo = {
+ maxHistoryCount: 0,
+ totalCircs: 0,
+ circsThisYear: 0,
+ circsPrevYear: 0
+ };
+
+ const copyOrg: number =
+ item.call_number().id() === -1 ?
+ item.circ_lib().id() :
+ item.call_number().owning_lib().id();
+
+ return this.pcrud.search('circbyyr',
+ {copy : item.id()}, null, {atomic : true}).toPromise()
+
+ .then(counts => {
+
+ const curYear = new Date().getFullYear();
+ const prevYear = curYear - 1;
+
+ counts.forEach(c => {
+ response.totalCircs += Number(c.count());
+ if (c.year() === curYear) {
+ response.circsThisYear += Number(c.count());
+ }
+ if (c.year() === prevYear) {
+ response.circsPrevYear += Number(c.count());
+ }
+ });
+ })
+ .then(_ => this.perms.hasWorkPermAt(['VIEW_COPY_CHECKOUT_HISTORY'], true))
+ .then(hasPerm => {
+ if (hasPerm['VIEW_COPY_CHECKOUT_HISTORY'].includes(copyOrg)) {
+ return this.org.settings('circ.item_checkout_history.max')
+ .then(sets => {
+ response.maxHistoryCount = sets['circ.item_checkout_history.max'] || 4;
+ });
+ } else {
+ response.maxHistoryCount = 0;
+ }
+ })
+
+ .then(_ => this.getLatestCirc(item.id()))
+
+ .then(circ => {
+
+ if (!circ) { return response; }
+
+ response.currentCirc = circ;
+
+ return this.getCircChain(circ.id())
+ .then(summary => {
+ response.circSummary = summary;
+
+ if (response.maxHistoryCount <= 1) {
+ return response;
+ }
+
+ return this.getPrevCircChain(circ.id())
+ .then(prevSummary => {
+ if (!prevSummary) { return response; }
+
+ response.prevCircSummary = prevSummary.summary;
+
+ if (prevSummary.usr) { // aged circs have no 'usr'.
+
+ return this.pcrud.retrieve('au', prevSummary.usr,
+ {flesh : 1, flesh_fields : {au : ['card']}})
+ .toPromise().then(user => response.prevCircUser = user);
+ }
+ });
+ });
+ });
+ }
}
+