Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

circulation: display circulation notes automatically. #280

Merged
merged 1 commit into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions projects/admin/src/app/circulation/checkin/checkin.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import { RecordService } from '@rero/ng-core';
import { ToastrService } from 'ngx-toastr';
import { map } from 'rxjs/operators';
import { User } from '../../class/user';
import { ItemsService } from '../../service/items.service';
import { PatronService } from '../../service/patron.service';
import { UserService } from '../../service/user.service';
import { ItemAction, ItemStatus } from '../items';
import { ItemsService } from '../../service/items.service';
import { Item, ItemAction, ItemNoteType, ItemStatus } from '../items';

@Component({
selector: 'admin-circulation-checkout',
Expand Down Expand Up @@ -56,7 +56,7 @@ export class CheckinComponent implements OnInit {
* @param _itemsService: Items Service
* @param _router: Router
* @param _translate: Translate Service
* @param toastService: Toastr Service
* @param _toastService: Toastr Service
* @param _patronService: Patron Service
*/
constructor(
Expand Down Expand Up @@ -122,6 +122,7 @@ export class CheckinComponent implements OnInit {
);
break;
case ItemAction.checkin:
this._displayCirculationNote(item, ItemNoteType.CHECKIN);
if (item.action_applied.checkin) {
this.getPatronInfo(item.action_applied.checkin.patron.barcode);
}
Expand Down Expand Up @@ -173,14 +174,8 @@ export class CheckinComponent implements OnInit {
this._recordService
.getRecords('patrons', `barcode:${barcode}`, 1, 1)
.pipe(
map((response: any) => {
if (response.hits.total === 0) {
return null;
}
return response.hits.hits[0].metadata;
})
)
.subscribe(
map((response: any) => (response.hits.total === 0) ? null : response.hits.hits[0].metadata)
).subscribe(
patron => {
if (
patron !== null &&
Expand Down Expand Up @@ -218,6 +213,26 @@ export class CheckinComponent implements OnInit {
);
}
}

/** display a circulation note about an item as a permanent toastr message
*
* @param item: the item
* @param noteType: the note type to display
*/
private _displayCirculationNote(item: Item, noteType: ItemNoteType): void {
const note = item.getNote(noteType);
if (note != null) {
this._toastService.warning(
note.content, null,
{
closeButton: true, // add a close button to the toastr message
disableTimeOut: true, // permanent toastr message (until click on 'close' button)
tapToDismiss: false // toastr message only close when click on the 'close' button.
}
);
}
}

hasFees(event: boolean) {
if (event) {
this._toastService.error(
Expand Down
79 changes: 55 additions & 24 deletions projects/admin/src/app/circulation/item/item.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,26 @@
 along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<div [ngClass]="{'callout callout-warning': item.actionDone === itemAction.checkin && (item.status === 'in_transit' || item.pending_loans || totalAmountOfFee > 0),
'text-secondary': item.status !== 'on_loan'}"
class="row p-2 mb-1 border rounded align-middle"
*ngIf="item">
<div *ngIf="item"
[ngClass]="{
'callout callout-warning': needCallout(item, 'warning') || (item.actionDone === itemAction.checkin && totalAmountOfFee > 0),
'text-secondary': item.status !== 'on_loan'
}"
class="row p-2 mb-1 border rounded align-middle">
<!-- BARCODE -->
<div class="col-lg-2">
<div class="col-lg-3">
<button *ngIf="item.loan || totalAmountOfFee || item.pending_loans || notifications$" type="button"
class="pl-0 pt-0 btn" (click)="isCollapsed = !isCollapsed" [attr.aria-expanded]="!isCollapsed"
aria-controls="collapse">
<i [ngClass]="{ 'fa-caret-down': !isCollapsed, 'fa-caret-right': isCollapsed }" class="fa" aria-hidden="true"></i>
</button>
<a [routerLink]="['/records','items','detail', item.pid]">{{ item.barcode }}</a>
<ng-container *ngIf="item.actionDone">
<ng-container *ngIf="(item.actionDone === itemAction.checkin && item.getNote('checkin_note')) ||
(item.actionDone === itemAction.checkout && item.getNote('checkout_note'))">
<i class="fa fa-sticky-note-o text-warning pt-1 float-right"></i>
</ng-container>
</ng-container>
</div>
<!-- TITLE -->
<div class="col-lg-4">
Expand Down Expand Up @@ -87,26 +95,49 @@
</ng-container>
</div>
<!-- COLLAPSED DETAILS -->
<div class="col-sm-6 mt-2">
<ul class="list-unstyled mb-0" id="collapse" [collapse]="isCollapsed" [isAnimated]="true">
<li *ngIf="item.loan && item.loan.pickup_location_pid">{{ 'Location' | translate }}:
{{ item.loan.pickup_location_pid | getRecord: 'locations' : 'field' : 'code' | async }} {{ item.location.name }}
</li>
<li *ngIf="item.loan && item.loan.extension_count">{{ 'Renewals' | translate }}: {{ item.loan.extension_count }}
</li>
<li *ngIf="totalAmountOfFee > 0">{{ 'Fees' | translate }}:
{{ totalAmountOfFee | currency: organisation.default_currency }}</li>
<div class="col-sm-12 mt-2" *ngIf="!isCollapsed">
<dl class="row">
<ng-container *ngIf="item.loan && item.loan.pickup_location_pid">
<dt class="col-sm-5 col-md-3 label-title" translate>Location</dt>
<dd class="col-sm-7 col-md-9">
{{ item.loan.pickup_location_pid | getRecord: 'locations' : 'field' : 'code' | async }} {{ item.location.name }}
</dd>
</ng-container>
<ng-container *ngIf="item.loan && item.loan.extension_count">
<dt class="col-sm-5 col-md-3 label-title" translate>Renewals</dt>
<dd class="col-sm-7 col-md-9">{{ item.loan.extension_count }}</dd>
</ng-container>
<ng-container *ngIf="totalAmountOfFee > 0">
<dt class="col-sm-5 col-md-3 label-title" translate>Fees</dt>
<dd class="col-sm-7 col-md-9">{{ totalAmountOfFee | currency: organisation.default_currency }}</dd>
</ng-container>
<ng-container *ngIf="notifications$ | async as notifications">
<li *ngIf="notifications.length > 0">{{ 'Notifications' | translate }}:
<ul class="list-unstyled pl-2 mb-0">
<li *ngFor="let notification of notifications">
{{ notification.metadata.process_date | dateTranslate :'shortDate' }}:
{{ notification.metadata.notification_type | translate}}</li>
</ul>
</li>
<ng-container *ngIf="notifications.length > 0">
<dt class="col-sm-5 col-md-3 label-title" translate>Notifications</dt>
<dd class="col-sm-7 col-md-9">
<ul class="list-unstyled pl-2 mb-0">
<li *ngFor="let notification of notifications">
{{ notification.metadata.process_date | dateTranslate :'shortDate' }}:
{{ notification.metadata.notification_type | translate }}
</li>
</ul>
</dd>
</ng-container>
</ng-container>
<li *ngIf="item.pending_loans">{{ 'Requests' | translate }}: {{ item.pending_loans.length }}</li>
<li *ngIf="item.pending_loans">{{ 'For' | translate }}: {{ item.pending_loans[0].patron.name }}</li>
</ul>
<ng-container *ngIf="item.pending_loans">
<dt class="col-sm-5 col-md-3 label-title" translate>Requests</dt>
<dd class="col-sm-7 col-md-9">{{ item.pending_loans.length }}</dd>
<dt class="col-sm-5 col-md-3 label-title" translate="">For</dt>
<dd class="col-sm-7 col-md-9">{{ item.pending_loans[0].patron.name }}</dd>
</ng-container>
<ng-container *ngIf="item.actionDone && item.actionDone === itemAction.checkin && item.getNote('checkin_note') as note">
<dt class="col-sm-5 col-md-3 label-title" translate>{{ note.type }}</dt>
<dd class="col-sm-7 col-md-9 text-justify">{{ note.content }}</dd>
</ng-container>
<ng-container *ngIf="item.actionDone && item.actionDone === itemAction.checkout && item.getNote('checkout_note') as note">
<dt class="col-sm-5 col-md-3 label-title" translate>{{ note.type }}</dt>
<dd class="col-sm-7 col-md-9 text-justify">{{ note.content }}</dd>
</ng-container>
</dl>
</div>
</div>
16 changes: 14 additions & 2 deletions projects/admin/src/app/circulation/item/item.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { RecordService } from '@rero/ng-core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ItemsService } from '../../service/items.service';
import { OrganisationService } from '../../service/organisation.service';
import { Item, ItemAction, Loan, LoanState } from '../items';
import { PatronTransactionService } from '../patron-transaction.service';
Expand Down Expand Up @@ -55,12 +56,14 @@ export class ItemComponent implements OnInit {
* @param _recordService: Record Service
* @param _organisationService: Organisation Service
* @param _patronTransactionService: Patron transaction Service
* @param _itemService: Item Service
*/
constructor(
private _recordService: RecordService,
private _organisationService: OrganisationService,
private _patronTransactionService: PatronTransactionService
) { }
private _patronTransactionService: PatronTransactionService,
private _itemService: ItemsService
) { }

/**
* On init hook
Expand Down Expand Up @@ -116,4 +119,13 @@ export class ItemComponent implements OnInit {
get organisation() {
return this._organisationService.organisation;
}

/** Is a callout wrapper is required for this item.
*
* @param item: the item to analyse
* @param type: the callout type (error, warning, info, ...)
*/
needCallout(item: Item, type?: string): boolean {
return this._itemService.needCallout(item, type);
}
}
29 changes: 29 additions & 0 deletions projects/admin/src/app/circulation/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export enum ItemStatus {
MISSING = _('missing')
}

export enum ItemNoteType {
PUBLIC = _('public_note'),
STAFF = _('staff_note'),
CHECKIN = _('checkin_note'),
CHECKOUT = _('checkout_note')
}

export enum LoanState {
CREATED = _('CREATED'),
PENDING = _('PENDING'),
Expand Down Expand Up @@ -117,6 +124,12 @@ export class Loan {
return false;
}
}

export class ItemNote {
type: ItemNoteType;
content: string;
}

export class Item {
available: boolean;
barcode: string;
Expand All @@ -134,6 +147,7 @@ export class Item {
pending_loans: Loan[];
number_of_extensions: number;
location: any;
notes: ItemNote[];

constructor(obj?: any) {
Object.assign(this, obj);
Expand Down Expand Up @@ -176,4 +190,19 @@ export class Item {
public get hasRequests() {
return (this.pending_loans && this.pending_loans.length > 0);
}

/** Search on item notes a note corresponding to the note type
*
* @param type: the note type
* @return Return the corresponding note or null if not found
*/
public getNote(type: ItemNoteType): ItemNote | null {
if (this.notes == null) {
return null;
}
const filteredNotes = this.notes.filter(note => note.type === type);
return (filteredNotes)
? filteredNotes[0]
: null;
}
}
30 changes: 27 additions & 3 deletions projects/admin/src/app/circulation/patron/loan/loan.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import { TranslateService } from '@ngx-translate/core';
import { ToastrService } from 'ngx-toastr';
import { forkJoin } from 'rxjs';
import { User } from '../../../class/user';
import { PatronBlockedMessagePipe } from '../../../pipe/patron-blocked-message.pipe';
import { ItemsService } from '../../../service/items.service';
import { PatronService } from '../../../service/patron.service';
import { UserService } from '../../../service/user.service';
import { Item, ItemAction, ItemStatus } from '../../items';
import { ItemsService } from '../../../service/items.service';
import { PatronBlockedMessagePipe } from '../../../pipe/patron-blocked-message.pipe';
import { Item, ItemAction, ItemNoteType, ItemStatus } from '../../items';

@Component({
selector: 'admin-loan',
Expand Down Expand Up @@ -186,11 +186,13 @@ export class LoanComponent implements OnInit {
newItems.map(newItem => {
switch (newItem.actionDone) {
case ItemAction.checkin: {
this._displayCirculationNote(newItem, ItemNoteType.CHECKIN);
this.checkedOutItems = this.checkedOutItems.filter(currItem => currItem.pid !== newItem.pid);
this.checkedInItems.unshift(newItem);
break;
}
case ItemAction.checkout: {
this._displayCirculationNote(newItem, ItemNoteType.CHECKOUT);
this.checkedOutItems.unshift(newItem);
this.checkedInItems = this.checkedInItems.filter(currItem => currItem.pid !== newItem.pid);
break;
Expand Down Expand Up @@ -236,6 +238,25 @@ export class LoanComponent implements OnInit {
);
}

/** display a circulation note about an item as a permanent toastr message
*
* @param item: the item
* @param noteType: the note type to display
*/
private _displayCirculationNote(item: Item, noteType: ItemNoteType): void {
const note = item.getNote(noteType);
if (note != null) {
this._toastService.warning(
note.content, null,
{
closeButton: true, // add a close button to the toastr message
disableTimeOut: true, // permanent toastr message (until click on 'close' button)
tapToDismiss: false // toastr message only close when click on the 'close' button.
}
);
}
}

hasFees(event: boolean) {
if (event) {
this._toastService.error(
Expand All @@ -244,4 +265,7 @@ export class LoanComponent implements OnInit {
);
}
}


}

7 changes: 7 additions & 0 deletions projects/admin/src/app/routes/items-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ export class ItemsRoute extends BaseRoute implements RouteInterface {
}
return data;
},
postprocessRecordEditor: (record: any) => {
// If we try to save an item with without any notes, then remove the empty array notes array from record
if (record.notes && record.notes.length === 0) {
delete record.notes;
}
return record;
},
formFieldMap: (field: FormlyFieldConfig, jsonSchema: JSONSchema7): FormlyFieldConfig => {
return this.populateLocationsByCurrentUserLibrary(
field, jsonSchema
Expand Down
4 changes: 3 additions & 1 deletion projects/admin/src/app/scss/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ header {
content: " \f08e";
}


.toast-container .ngx-toastr {
width: 450px !important; // override width for all toastr message
}

json-schema-form {
input.ng-valid,
Expand Down
Loading