Skip to content

Commit

Permalink
circulation: item on check-in list without loan
Browse files Browse the repository at this point in the history
Show item information on check-in list with no active loan.

* Closes rero/rero-ils#3512.

Co-Authored-by: Bertrand Zuchuat <[email protected]>
  • Loading branch information
Garfield-fr committed Nov 29, 2023
1 parent 59c36fa commit 339c22e
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 58 deletions.
66 changes: 38 additions & 28 deletions projects/admin/src/app/circulation/checkin/checkin.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export class CheckinComponent implements OnInit {
/** Disabled attribute of the search input */
searchInputDisabled = false;

/** current called item */
private item: any;

/** Constructor
* @param _userService: UserService
* @param _recordService: RecordService
Expand Down Expand Up @@ -140,9 +143,23 @@ export class CheckinComponent implements OnInit {
this._resetSearchInput();
},
error => {
// If no action could be done by the '/item/checkin' api, an error will be raised.
// catch this error to display it as a toastr message.
this._checkinErrorManagement(error, itemBarcode);
if (this.item && this.items.findIndex(i => i.barcode === this.item.barcode) === -1) {
// Reload item to have data up to date.
this._itemsService.getItem(this.item.barcode).subscribe((item: any) => {
delete item.actions;
if (!item.notes) {
item.notes = [];
}
item.notes.push({
content: error.error.status.replace(/^error:/, '').trim(),
type: ItemNoteType.API
});
this.items.unshift(item);
// If no action could be done by the '/item/checkin' api, an error will be raised.
// catch this error to display it as a toastr message.
this._checkinErrorManagement(error, item);
});
}
}
);
}
Expand Down Expand Up @@ -175,6 +192,7 @@ export class CheckinComponent implements OnInit {
* @param barcode: item or patron barcode
*/
getPatronOrItem(barcode: string) {
this.item = undefined;
const loggerOrg = this._loggedUser.currentOrganisation;
const query = `patron.barcode:${barcode} AND organisation.pid:${loggerOrg}`;
const patronQuery = this._recordService
Expand Down Expand Up @@ -218,6 +236,7 @@ export class CheckinComponent implements OnInit {
}
});
} else if (item.total.value === 1) {
this.item = item.hits[0].metadata;
// Check if the item is already into the item list. If it happens,
// just notify the user and clear the form.
if (this.items.find(it => it.barcode === barcode)) {
Expand Down Expand Up @@ -265,38 +284,29 @@ export class CheckinComponent implements OnInit {
/** create the most relevant message concerning a checkin operation error and display it as a toastr
*
* @param error: the raised error
* @param barcode: the item barcode searched
* @param item: the current item
*/
private _checkinErrorManagement(error: any, barcode: string) {
private _checkinErrorManagement(error: any, item: Item) {
// get the error message from the raised error. This will be the toastr message core.
let message = (error.hasOwnProperty('error') && error.error.hasOwnProperty('status'))
? error.error.status.replace(/^error:/, '').trim()
: error.message;
message = this._translate.instant(message);

// the message could contains some data information from the item. So we need to load the item
this._itemsService.getItem(barcode).pipe(
finalize(() => {
this._toastService.warning(
this._translate.instant(message),
this._translate.instant('Checkin'),
{ enableHtml: true }
);
this._resetSearchInput();
})
).subscribe(
item => {
message += `<br/>${this._translate.instant('Status')}: ${this._translate.instant(item.status.toString())}`;
if (item.status === ItemStatus.IN_TRANSIT && item.loan && item.loan.item_destination) {
const library_name = item.loan.item_destination.library_name;
message += ` (${this._translate.instant('to')} ${library_name})`;
this.items.unshift(item); // Display item info
}
},
() => {
message += '<br/>' + this._translate.instant('Item not found!');
}
message += `<br/>${this._translate.instant('Status')}: ${this._translate.instant(item.status.toString())}`;
if (item.status === ItemStatus.IN_TRANSIT && item.loan && item.loan.item_destination) {
const { library_name } = item.loan.item_destination;
message += ` (${this._translate.instant('to')} ${library_name})`;
}
const checkinNote = item.getNote(ItemNoteType.CHECKIN);
if (checkinNote) {
message += `<br/>${this._translate.instant('Note')}: ${checkinNote.content}`
}
this._toastService.warning(
this._translate.instant(message),
this._translate.instant('Checkin'),
{ enableHtml: true }
);
this._resetSearchInput();
}

hasFees(event: boolean) {
Expand Down
69 changes: 46 additions & 23 deletions projects/admin/src/app/circulation/item/item.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<div *ngIf="item && !(item.loading || false)"
[ngClass]="{
'callout callout-warning': needCallout(item, 'warning') || (item.actionDone === itemAction.checkin && totalAmountOfFee > 0),
'callout callout-warning': needCallout(item, 'warning') || (item.actionDone === itemAction.checkin && totalAmountOfFee > 0) || !item.loan,
'text-secondary': item.status !== ItemStatus.ON_LOAN
}"
class="row d-flex align-items-start item">
Expand All @@ -37,7 +37,7 @@
</div>
<!-- BARCODE -->
<div name="barcode" class="col-2 d-flex">
<button *ngIf="item.loan || totalAmountOfFee || item.pending_loans || notifications$"
<button *ngIf="!item.actions || item.loan || totalAmountOfFee || item.pending_loans || notifications$"
type="button" class="btn-show-more"
[ngClass]="{'btn-expanded': !isCollapsed, 'btn-collapsed': isCollapsed}"
(click)="isCollapsed = !isCollapsed"
Expand All @@ -47,23 +47,31 @@
<a [routerLink]="['/records','items','detail', item.pid]">{{ item.barcode }}</a>
<shared-inherited-call-number class="d-block small" *ngIf="isCollapsed" [item]="item"></shared-inherited-call-number>
</div>
<ng-container *ngIf="item.actionDone">
<ng-container *ngIf="item.actionDone; else warningItemOnly">
<ng-container *ngIf="(item.actionDone === itemAction.checkin && item.getNote('checkin_note')) ||
(item.actionDone === itemAction.checkout && item.getNote('checkout_note'))">
<i class="fa fa-exclamation-triangle text-warning mt-1 ml-auto"></i>
</ng-container>
</ng-container>
<ng-template #warningItemOnly>
<i *ngIf="!item.actions" class="fa fa-exclamation-triangle text-warning mt-1 ml-auto"></i>
</ng-template>
</div>
<!-- TITLE -->
<div name="title" class="col-lg-6">
<a [routerLink]="['/records','documents','detail', item.document.pid]" *ngIf="item.document.title | mainTitle as title ">
{{ isCollapsed ? (title | truncateText: 12) : title }}
<a [routerLink]="['/records','documents','detail', item.document.pid]">
<ng-container *ngIf="item.document?.title; else itemDocumentTitle">
{{ isCollapsed ? (item.document.title | mainTitle | truncateText: 12) : item.document.title | mainTitle }}
</ng-container>
<ng-template #itemDocumentTitle>
<ng-container *ngIf="document">{{ document.title[0]._text }}</ng-container>
</ng-template>
</a>
<shared-contribution *ngIf="document" [contributions]="document?.contribution"></shared-contribution>
</div>
<!-- CIRCULATION INFO -->
<div name="circ-info" class="col-2">
<ul class="list-unstyled mb-0">
<ul class="list-unstyled mb-0" *ngIf="item.loan; else itemStatus">
<ng-container [ngSwitch]="item.status">
<li name="status" *ngSwitchCase="'on_loan'" >
{{ item.status | translate }}
Expand Down Expand Up @@ -113,6 +121,7 @@
</span>
</li>
</ul>
<ng-template #itemStatus>{{ item.status | translate }}</ng-template>
</div>
<!-- ACTION DONE -->
<div name="action-done" class="col-2">
Expand Down Expand Up @@ -144,7 +153,8 @@
<ng-container *ngIf="item.location.pid | getRecord: 'locations' | async as location">
<dt class="offset-1 col-sm-3 col-md-2 col-lg-1 label-title" translate>Location</dt>
<dd class="col-sm-8 col-md-9 col-lg-10">
{{ location.metadata.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}: {{ item.location.name }}
{{ location.metadata.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}:
{{ location.metadata.name }}
</dd>
</ng-container>
<ng-container *ngIf="item.loan && item.loan.extension_count">
Expand All @@ -156,21 +166,21 @@
</span>
</dd>
</ng-container>
<ng-container *ngIf="item.actionDone === 'checkin' && item?.loan?.last_end_date">
<ng-container *ngIf="item.loan && item.actionDone === 'checkin' && item?.loan?.last_end_date">
<dt class="offset-1 col-sm-3 col-md-2 col-lg-1 label-title" translate>Due date</dt>
<dd name="due_date" class="col-sm-8 col-md-9 col-lg-10">
{{ item.loan.last_end_date | dateTranslate :'shortDate' }}
</dd>
</ng-container>
<ng-container *ngIf="totalAmountOfFee > 0">
<ng-container *ngIf="item.loan && totalAmountOfFee > 0">
<dt class="offset-1 col-sm-3 col-md-getTransitLocationPid2 col-lg-1 label-title" translate>Fees</dt>
<dd name="fees" class="col-sm-8 col-md-9 col-lg-10">
<span class="badge badge-warning font-weight-normal">
{{ totalAmountOfFee | currency: organisation.default_currency }}
</span>
</dd>
</ng-container>
<ng-container *ngIf="notifications$ | async as notifications">
<ng-container *ngIf="item.loan && notifications$ | async as notifications">
<ng-container *ngIf="notifications.length > 0">
<dt class="offset-1 col-sm-3 col-md-2 col-lg-1 label-title" translate>Notifications</dt>
<dd name="notifications" class="col-sm-8 col-md-9 col-lg-10">
Expand Down Expand Up @@ -203,24 +213,37 @@
</span>
</dd>
</ng-container>
<ng-container *ngIf="getCirculationNoteForAction() as note">
<dd class="col-1 text-right pr-1"><i class="fa fa-sticky-note-o text-warning"></i></dd>
<dt class="col-sm-3 col-md-2 col-lg-1 label-title" translate>{{ note.type }}</dt>
<ng-container *ngFor="let note of getCirculationNoteForAction()">
<ng-container *ngIf="note.type !== NOTEAPI; else notDisplayType">
<dd class="col-1 text-right pr-1"><i class="fa fa-sticky-note-o text-warning"></i></dd>
<dt class="col-sm-3 col-md-2 col-lg-1 label-title" translate>{{ note.type }}</dt>
</ng-container>
<ng-template #notDisplayType>
<dd class="col-1 text-right pr-1"><i class="fa fa-sticky-note-o text-warning"></i></dd>
<dt class="col-sm-3 col-md-2 col-lg-1 label-title" translate>Note</dt>
</ng-template>
<dd name="checkin-note" class="col-sm-8 col-md-9 col-lg-10 text-justify">{{ note.content }}</dd>
</ng-container>
<ng-container *ngIf="debugMode">
<dd class="col-1 text-right pr-1"><i class="fa fa-bug text-danger"></i></dd>
<dt class="col-1 label-title text-danger" translate>Debug</dt>
<dd class="col-5">
<pre class="border p-3">{{ loan | json }}<legend>loan</legend></pre>
</dd>
<dd class="col-5" *ngIf="loan | getLoanCipo | async as cipo">
<pre class="border p-3">{{ cipo | json }}<legend>
<a [routerLink]="['/records', 'circ_policies', 'detail', cipo.pid]" target="_circulation">
<i class="fa fa-external-link pr-2"></i>cipo
</a>
</legend></pre>
</dd>
<ng-container *ngIf="loan; else itemNoLoan">
<dd class="col-5">
<pre class="border p-3">{{ loan | json }}<legend>loan</legend></pre>
</dd>
<dd class="col-5" *ngIf="loan | getLoanCipo | async as cipo">
<pre class="border p-3">{{ cipo | json }}<legend>
<a [routerLink]="['/records', 'circ_policies', 'detail', cipo.pid]" target="_circulation">
<i class="fa fa-external-link pr-2"></i>cipo
</a>
</legend></pre>
</dd>
</ng-container>
<ng-template #itemNoLoan>
<dd class="col-5">
<pre class="border p-3">{{ item | json }}<legend>item</legend></pre>
</dd>
</ng-template>
</ng-container>
</dl>
<ng-container *ngIf="canUseDebugMode">
Expand Down
20 changes: 14 additions & 6 deletions projects/admin/src/app/circulation/item/item.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import { PatronTransactionService } from '@app/admin/circulation/services/patron
})
export class ItemComponent implements OnInit {

NOTEAPI = ItemNoteType.API;

// COMPONENT ATTRIBUTES ====================================================
/** Current item */
@Input() item: any;
Expand Down Expand Up @@ -116,6 +118,8 @@ export class ItemComponent implements OnInit {
).pipe(
map((results: any) => results.hits.hits)
);
}
if (this.item?.document?.pid) {
this._recordService.getRecord('documents', this.item.document.pid, 1, {
Accept: 'application/rero+json, application/json'
}).subscribe(document => this.document = document.metadata);
Expand Down Expand Up @@ -149,19 +153,23 @@ export class ItemComponent implements OnInit {
}

/**
* Get a note related to the item for the itemAction done.
* Get a note related to the item for the itemAction done or only item.
* @return the corresponding note if the corresponding action has been done.
*/
getCirculationNoteForAction(): ItemNote|null {
getCirculationNoteForAction(): ItemNote[] {
if (this.item.actionDone) {
if (this.item.actionDone === this.itemAction.checkin) {
return this.item.getNote(ItemNoteType.CHECKIN);
return [this.item.getNote(ItemNoteType.CHECKIN)];
}
if (this.item.actionDone === this.itemAction.checkout) {
return this.item.getNote(ItemNoteType.CHECKOUT);
return [this.item.getNote(ItemNoteType.CHECKOUT)];
}
} else if (this.item.notes) {
// Notes for item without loan.
// This api note is pushed on error exception.
return this.item?.notes.filter(i => [ItemNoteType.CHECKIN, ItemNoteType.API].includes(i.type));
}
return null;
return [];
}

/**
Expand All @@ -175,7 +183,7 @@ export class ItemComponent implements OnInit {

/**
* Is a callout wrapper is required for this item.
* @param item: the item to analyse
* @param item: the item to analyze
* @param type: the callout type (error, warning, info, ...)
*/
needCallout(item: Item, type?: string): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--
RERO ILS UI
Copyright (C) 2019 RERO
Copyright (C) 2019-2023 RERO
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
Expand Down Expand Up @@ -57,6 +57,7 @@
[patron]="patron"
[item]="item"
[attr.id]="item.barcode | idAttribute:{prefix: 'item'}"
[isCollapsed]="allCollapsed"
(hasFeesEmitter)="hasFees($event)">
</admin-item>
</div>
1 change: 1 addition & 0 deletions projects/admin/src/app/classes/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export enum ItemNoteType {
CONDITION = 'condition_note',
PATRIMONIAL = 'patrimonial_note',
ACQUISITION = 'acquisition_note',
API = 'api' // Only used to return the api message (component item)
}

export interface Organisation {
Expand Down

0 comments on commit 339c22e

Please sign in to comment.