diff --git a/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.html b/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.html
index aa5c668e8..ddaaaf91f 100644
--- a/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.html
+++ b/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.html
@@ -1,6 +1,6 @@
+
+
+
+
+
+
+
+
diff --git a/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.ts b/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.ts
index 59c3c1253..3a5de46d4 100644
--- a/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.ts
+++ b/projects/admin/src/app/circulation/patron/pending/pending-item/pending-item.component.ts
@@ -1,6 +1,6 @@
/*
* RERO ILS UI
- * Copyright (C) 2020 RERO
+ * Copyright (C) 2020-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
@@ -14,8 +14,12 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { LoanService } from '@app/admin/service/loan.service';
+import { TranslateService } from '@ngx-translate/core';
import { RecordService } from '@rero/ng-core';
+import { UserService } from '@rero/shared';
+import { ToastrService } from 'ngx-toastr';
import { forkJoin } from 'rxjs';
import { ItemsService } from '../../../../service/items.service';
@@ -33,16 +37,26 @@ export class PendingItemComponent implements OnInit {
document = undefined;
/** detail is collapsed */
isCollapsed = true;
+ /** Informs parent component to remove request when it is cancelled */
+ @Output() cancelRequestEvent = new EventEmitter();
// CONSTRUCTOR & HOOKS ======================================================
/**
* Constructor
* @param _recordService - RecordService
* @param _itemService - ItemService
+ * @param _translateService - TranslateService
+ * @param _loanService - LoanService
+ * @param _userService - UserService
+ * @param _toastrService - ToastrService
*/
constructor(
private _recordService: RecordService,
- private _itemService: ItemsService
+ private _itemService: ItemsService,
+ private _translateService: TranslateService,
+ private _loanService: LoanService,
+ private _userService: UserService,
+ private _toastrService: ToastrService,
) { }
/** OnInit hook */
@@ -58,4 +72,31 @@ export class PendingItemComponent implements OnInit {
);
}
}
+
+ /**
+ * Can cancel a loan request
+ * @returns true if it is possible to cancel a loan
+ */
+ canCancelRequest(): boolean {
+ return this._loanService.canCancelRequest(this.loan);
+ }
+
+ /** Show a confirmation dialog box for cancel request. */
+ showCancelRequestDialog(): void {
+ this._loanService.cancelRequestDialog().subscribe((confirm: boolean) => {
+ if (confirm) {
+ this._loanService.cancelLoan(
+ this.loan.metadata.item.pid,
+ this.loan.metadata.pid,
+ this._userService.user.currentLibrary
+ ).subscribe(() => {
+ this._toastrService.warning(
+ this._translateService.instant('The pending request has been cancelled.'),
+ this._translateService.instant('Request')
+ );
+ this.cancelRequestEvent.emit(this.loan.id);
+ });
+ }
+ });
+ }
}
diff --git a/projects/admin/src/app/circulation/patron/pending/pending.component.html b/projects/admin/src/app/circulation/patron/pending/pending.component.html
index b03542e98..5cc0daa55 100644
--- a/projects/admin/src/app/circulation/patron/pending/pending.component.html
+++ b/projects/admin/src/app/circulation/patron/pending/pending.component.html
@@ -1,6 +1,6 @@
Item
-
Title
+
Title
Request date
Expected availability
+
diff --git a/projects/admin/src/app/circulation/patron/pending/pending.component.ts b/projects/admin/src/app/circulation/patron/pending/pending.component.ts
index 9fdd33fea..aeb92b411 100644
--- a/projects/admin/src/app/circulation/patron/pending/pending.component.ts
+++ b/projects/admin/src/app/circulation/patron/pending/pending.component.ts
@@ -1,6 +1,6 @@
/*
* RERO ILS UI
- * Copyright (C) 2020 RERO
+ * Copyright (C) 2020-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
@@ -17,6 +17,7 @@
import { Component, OnInit } from '@angular/core';
import { PatronService } from '../../../service/patron.service';
+import { CirculationService } from '../../services/circulation.service';
@Component({
selector: 'admin-pending',
@@ -31,7 +32,10 @@ export class PendingComponent implements OnInit {
* Constructor
* @param _patronService - PatronService
*/
- constructor(private _patronService: PatronService) {}
+ constructor(
+ private _patronService: PatronService,
+ private _circulationService: CirculationService
+ ) {}
/**
* Init
@@ -46,4 +50,16 @@ export class PendingComponent implements OnInit {
}
});
}
+
+ /**
+ * Remove the canceled request on the loans list.
+ * @param loanId, the canceled loan id
+ */
+ cancelRequest(loanId: any): void {
+ // Remove loan in list
+ const index = this.loans.findIndex((element: any) => element.id == loanId);
+ this.loans.splice(index, 1);
+ // Update count on tab
+ this._circulationService.circulationInformations.statistics['pending'] -= 1;
+ }
}
diff --git a/projects/admin/src/app/record/detail-view/item-detail-view/item-transaction/item-transaction.component.ts b/projects/admin/src/app/record/detail-view/item-detail-view/item-transaction/item-transaction.component.ts
index 3794d9026..fa505c1f2 100644
--- a/projects/admin/src/app/record/detail-view/item-detail-view/item-transaction/item-transaction.component.ts
+++ b/projects/admin/src/app/record/detail-view/item-detail-view/item-transaction/item-transaction.component.ts
@@ -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
@@ -16,11 +16,10 @@
*/
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
+import { ItemsService } from '@app/admin/service/items.service';
+import { LoanService } from '@app/admin/service/loan.service';
import { TranslateService } from '@ngx-translate/core';
-import { DialogService } from '@rero/ng-core';
import { UserService } from '@rero/shared';
-import { LoanState } from '@app/admin/classes/loans';
-import { ItemsService } from '@app/admin/service/items.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -33,7 +32,7 @@ export class ItemTransactionComponent implements OnInit, OnDestroy {
// COMPONENTS ATTRIBUTES ===============================================================
/** Loan Record */
@Input() transaction: any;
- /** Ressource type */
+ /** Resource type */
@Input() type: string;
/** Flag for cell background */
@Input() background: boolean;
@@ -54,7 +53,7 @@ export class ItemTransactionComponent implements OnInit, OnDestroy {
/** Pickup locations observable reference */
private _pickupLocations$: any;
/** Authorized Transaction Type to load pickup locations */
- private _autorizedTypeToLoadPickupLocations = [
+ private _authorizedTypeToLoadPickupLocations = [
'loan_request'
];
@@ -77,20 +76,20 @@ export class ItemTransactionComponent implements OnInit, OnDestroy {
* constructor
* @param _userService - User service
* @param _translateService - TranslateService
- * @param _dialogService: DialogService
- * @param _itemService: ItemsService
+ * @param _itemService - ItemsService
+ * @param _loanService - LoanService
*/
constructor(
private _userService: UserService,
private _translateService: TranslateService,
- private _dialogService: DialogService,
- private _itemService: ItemsService
+ private _itemService: ItemsService,
+ private _loanService: LoanService
) {}
/** OnInit hook */
ngOnInit() {
this._currentUser = this._userService.user;
- if (this._autorizedTypeToLoadPickupLocations.includes(this.type)) {
+ if (this._authorizedTypeToLoadPickupLocations.includes(this.type)) {
this._pickupLocations$ = this.getPickupLocations().subscribe((pickups) => {
this.pickupLocations = pickups;
});
@@ -99,43 +98,32 @@ export class ItemTransactionComponent implements OnInit, OnDestroy {
/** OnDestroy hook */
ngOnDestroy() {
- if (this._autorizedTypeToLoadPickupLocations.includes(this.type)) {
+ if (this._authorizedTypeToLoadPickupLocations.includes(this.type)) {
this._pickupLocations$.unsubscribe();
}
}
// COMPONENT FUNCTIONS ==================================================================
- /** Check if request can be cancelled. */
+ /**
+ * Check if request can be cancelled.
+ * @returns true if it is possible to cancel a loan
+ */
canCancelRequest(): boolean {
- // No permission API in backend
- // Allowed when loan state is PENDING or ITEM_IN_TRANSIT_FOR_PICKUP according to actions.md
- const itemStatus = [LoanState.PENDING, LoanState.ITEM_IN_TRANSIT_FOR_PICKUP, LoanState.ITEM_AT_DESK];
- return itemStatus.some((element) => element === this.transaction.metadata.state);
-
+ return this._loanService.canCancelRequest(this.transaction);
}
- /** Check if request pickup location can be changed. */
+ /**
+ * Check if request pickup location can be changed.
+ * @returns true if it is possible to update pickup location.
+ */
canUpdateRequestPickupLocation(): boolean {
- // No permission API in backend
- // Allowed when loan state is PENDING or ITEM_IN_TRANSIT_FOR_PICKUP according to actions.md
- const itemStatus = [LoanState.PENDING, LoanState.ITEM_IN_TRANSIT_FOR_PICKUP];
- return itemStatus.some((element) => element === this.transaction.metadata.state);
+ return this._loanService.canUpdateRequestPickupLocation(this.transaction);
}
/** Show a confirmation dialog box for cancel request. */
showCancelRequestDialog(): void {
- const config = {
- ignoreBackdropClick: true,
- initialState: {
- title: this._translateService.instant('Cancel request'),
- body: this._translateService.instant('Do you really want to delete this request?'),
- confirmButton: true,
- cancelTitleButton: this._translateService.instant('No'),
- confirmTitleButton: this._translateService.instant('Yes')
- }
- };
- this._dialogService.show(config).subscribe((confirm: boolean) => {
+ this._loanService.cancelRequestDialog().subscribe((confirm: boolean) => {
if (confirm) {
this.emitCancelRequest();
}
diff --git a/projects/admin/src/app/record/detail-view/item-detail-view/item-transactions/item-transactions.component.ts b/projects/admin/src/app/record/detail-view/item-detail-view/item-transactions/item-transactions.component.ts
index 52ade80e3..2fcc5cff3 100644
--- a/projects/admin/src/app/record/detail-view/item-detail-view/item-transactions/item-transactions.component.ts
+++ b/projects/admin/src/app/record/detail-view/item-detail-view/item-transactions/item-transactions.component.ts
@@ -96,7 +96,7 @@ export class ItemTransactionsComponent implements OnInit {
.subscribe((itemData: any) => {
const status = this._translateService.instant(itemData.status);
this._toastrService.warning(
- this._translateService.instant('The item is {{ status }}', { status }),
+ this._translateService.instant('The pending request has been cancelled.'),
this._translateService.instant('Request')
);
this.cancelRequestEvent.emit();
diff --git a/projects/admin/src/app/service/loan.service.spec.ts b/projects/admin/src/app/service/loan.service.spec.ts
index ce70f5ddb..847fcd91a 100644
--- a/projects/admin/src/app/service/loan.service.spec.ts
+++ b/projects/admin/src/app/service/loan.service.spec.ts
@@ -19,13 +19,15 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { LoanService } from './loan.service';
+import { RecordModule } from '@rero/ng-core';
describe('LoanService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
- TranslateModule.forRoot()
+ TranslateModule.forRoot(),
+ RecordModule
]
}));
diff --git a/projects/admin/src/app/service/loan.service.ts b/projects/admin/src/app/service/loan.service.ts
index 0fa0f59ac..bc807aa61 100644
--- a/projects/admin/src/app/service/loan.service.ts
+++ b/projects/admin/src/app/service/loan.service.ts
@@ -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
@@ -17,13 +17,14 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
-import { RecordService } from '@rero/ng-core';
+import { DialogService, RecordService } from '@rero/ng-core';
import { Record } from '@rero/ng-core/lib/record/record';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CircPolicy } from '../classes/circ-policy';
import { LoanState } from '../classes/loans';
import { UserService } from '@rero/shared';
+import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root'
@@ -49,11 +50,14 @@ export class LoanService {
* @param _recordService - RecordService
* @param _http - HttpClient
* @param _userService - UserService
+ * @param _translateService - TranslateService
*/
constructor(
private _recordService: RecordService,
private _http: HttpClient,
- private _userService: UserService
+ private _userService: UserService,
+ private _translateService: TranslateService,
+ private _dialogService: DialogService
) { }
// SERVICES FUNCTIONS =======================================================
@@ -81,6 +85,17 @@ export class LoanService {
);
}
+ /**
+ * Can cancel a request
+ * @param loan - Loan record
+ * @returns true if it is possible to cancel a loan
+ */
+ canCancelRequest(loan: any): boolean {
+ // TODO: To increase the complexity, it is better to implement a backend api
+ return [LoanState.PENDING, LoanState.ITEM_IN_TRANSIT_FOR_PICKUP, LoanState.ITEM_AT_DESK]
+ .some((element) => element === loan.metadata.state)
+ }
+
/**
* Cancel a loan related to an item
* @param itemPid - item pid related to the loan to cancel
@@ -105,6 +120,16 @@ export class LoanService {
);
}
+ /**
+ * Check if request pickup location can be changed.
+ * @returns true if it is possible to update pickup location.
+ */
+ canUpdateRequestPickupLocation(transaction: any): boolean {
+ // TODO: To increase the complexity, it is better to implement a backend api
+ return [LoanState.PENDING, LoanState.ITEM_IN_TRANSIT_FOR_PICKUP]
+ .some((element) => element === transaction.metadata.state)
+ }
+
/**
* Update the pickup location of a loan
* @param loanPid - loan pid to update
@@ -129,13 +154,30 @@ export class LoanService {
return this._http.get(apiUrl);
}
+ /**
+ * Cancel request dialog.
+ * @returns Observable (true if the user confirms the cancellation)
+ */
+ cancelRequestDialog(): Observable {
+ const config = {
+ ignoreBackdropClick: true,
+ initialState: {
+ title: this._translateService.instant('Cancel request'),
+ body: this._translateService.instant('Do you really want to cancel the request?'),
+ confirmButton: true,
+ cancelTitleButton: this._translateService.instant('No'),
+ confirmTitleButton: this._translateService.instant('Yes')
+ }
+ };
+ return this._dialogService.show(config);
+ }
// PRIVATES SERVICE FUNCTIONS ===============================================
/**
* Search about loans related to an item
* @param itemPid - the item pid to search
* @param statuses - a list of loan states to filter result.
- * @returns Observable with loans corresponding to search critieria
+ * @returns Observable with loans corresponding to search criteria
*/
private loans$(itemPid: string, statuses?: Array): Observable {
let query = `item_pid.value:${itemPid}`;