diff --git a/projects/admin/src/app/circulation/checkin/checkin-action/checkin-action.component.html b/projects/admin/src/app/circulation/checkin/checkin-action/checkin-action.component.html index 447fb1c2d..55593f073 100644 --- a/projects/admin/src/app/circulation/checkin/checkin-action/checkin-action.component.html +++ b/projects/admin/src/app/circulation/checkin/checkin-action/checkin-action.component.html @@ -14,15 +14,14 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -
-
+
One item and one patron were found. -
-
+
Checkout/checkin [focus]="searchInputFocus" [disabled]="searchInputDisabled" (search)="searchValueUpdated($event)" - > - + />
Checkout/checkin [barcode]="barcode" [linkMode]="'circulation'" [clearPatronButton]="false" - > - + />
@@ -43,8 +41,8 @@

Checkout/checkin

- + (hasFeesEmitter)="hasFees($event)" + />
diff --git a/projects/admin/src/app/circulation/checkin/checkin.component.ts b/projects/admin/src/app/circulation/checkin/checkin.component.ts index 90b497cbb..b02630e76 100644 --- a/projects/admin/src/app/circulation/checkin/checkin.component.ts +++ b/projects/admin/src/app/circulation/checkin/checkin.component.ts @@ -155,7 +155,7 @@ export class CheckinComponent implements OnInit { item.notes = []; } item.notes.push({ - content: error.error.status.replace(/^error:/, '').trim(), + content: this.processErrorMessage(error.error.status), type: ItemNoteType.API }); this.items.unshift(item); @@ -163,6 +163,14 @@ export class CheckinComponent implements OnInit { // catch this error to display it as a Toast message. this._checkinErrorManagement(error, item); }); + } else if (error.error) { + this.messageService.add({ + severity: 'warn', + summary: this.translate.instant('Checkin'), + detail: this.processErrorMessage(error.error.status), + life: CONFIG.MESSAGE_LIFE + }); + this._resetSearchInput(); } } }); @@ -227,7 +235,7 @@ export class CheckinComponent implements OnInit { if (patron.total.value === 1 && item.total.value === 1) { const ref: DynamicDialogRef = this.dialogService.open(CheckinActionComponent, { header: this.translate.instant('Circulation action'), - width: '50vw', + width: '25vw', }) ref.onClose.subscribe((action: string) => { if (action) { @@ -316,7 +324,7 @@ export class CheckinComponent implements OnInit { private _checkinErrorManagement(error: any, item: Item) { // get the error message from the raised error. This will be the Toast message core. let message = (error.hasOwnProperty('error') && error.error.hasOwnProperty('status')) - ? error.error.status.replace(/^error:/, '').trim() + ? this.processErrorMessage(error.error.status) : error.message; message = this.translate.instant(message); message += `
${this.translate.instant('Status')}: ${this.translate.instant(item.status.toString())}`; @@ -372,6 +380,10 @@ export class CheckinComponent implements OnInit { } } + private processErrorMessage(message: string): string { + return message.replace(/^error:/, '').trim(); + } + /** Reset search input */ private _resetSearchInput(): void { setTimeout(() => { diff --git a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.scss b/projects/admin/src/app/circulation/circulation-main.component.ts similarity index 52% rename from projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.scss rename to projects/admin/src/app/circulation/circulation-main.component.ts index ab7813f28..b841f059f 100644 --- a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.scss +++ b/projects/admin/src/app/circulation/circulation-main.component.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2019 RERO + * Copyright (C) 2024 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,24 +14,24 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +import { Component } from '@angular/core'; - @import 'bootstrap/scss/functions'; - @import 'bootstrap/scss/variables'; - -.item { - margin-bottom: $spacer * .25 !important; - padding: $spacer * .25 !important; - border: $border-width solid $border-color; - border-radius: $border-radius; - position: relative; - - &:hover{ - background-color: $light; - } - - div.actions { - position: absolute; - top: $spacer * .25; - right: 15px; - } +@Component({ + selector: 'admin-circulation-main', + template: ` + + + +
+
+ {{ message.summary }} +
+

+
+
+
+ + ` +}) +export class CirculationMainComponent { } diff --git a/projects/admin/src/app/circulation/circulation-routing.module.ts b/projects/admin/src/app/circulation/circulation-routing.module.ts index c2de9654c..e0a76f98a 100644 --- a/projects/admin/src/app/circulation/circulation-routing.module.ts +++ b/projects/admin/src/app/circulation/circulation-routing.module.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2019-2023 RERO + * Copyright (C) 2019-2024 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,7 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PERMISSIONS } from '@rero/shared'; @@ -30,67 +29,76 @@ import { PendingComponent } from './patron/pending/pending.component'; import { PickupComponent } from './patron/pickup/pickup.component'; import { ProfileComponent } from './patron/profile/profile.component'; import { keepHistoryGuard } from './guard/keep-history.guard'; +import { CirculationMainComponent } from './circulation-main.component'; const routes: Routes = [ { path: '', - redirectTo: 'checkout', - pathMatch: 'full' - }, - { - path: 'patron/:barcode', - component: MainComponent, + component: CirculationMainComponent, children: [ { path: '', - redirectTo: 'loan', - pathMatch: 'full' - }, - { - path: 'loan', - component: LoanComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + redirectTo: 'checkout', + pathMatch: 'full', }, { - path: 'pickup', - component: PickupComponent, + path: 'checkout', + component: CheckinComponent, canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } }, { - path: 'pending', - component: PendingComponent, + path: 'requests', + component: MainRequestComponent, canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } }, { - path: 'ill', - component: IllRequestComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + path: 'patron/:barcode', + component: MainComponent, + children: [ + { + path: '', + redirectTo: 'loan', + pathMatch: 'full' + }, + { + path: 'loan', + component: LoanComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'pickup', + component: PickupComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'pending', + component: PendingComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'ill', + component: IllRequestComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'profile', + component: ProfileComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'fees', + component: PatronTransactionsComponent, + canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + }, + { + path: 'history', + component: HistoryComponent, + canActivate: [ keepHistoryGuard, PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } + } + ] }, - { - path: 'profile', - component: ProfileComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } - }, - { - path: 'fees', - component: PatronTransactionsComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } - }, - { - path: 'history', - component: HistoryComponent, - canActivate: [ keepHistoryGuard, PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } - } ] - }, { - path: 'checkout', - component: CheckinComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } - }, { - path: 'requests', - component: MainRequestComponent, - canActivate: [ PermissionGuard ], data: { permissions: [ PERMISSIONS.CIRC_ADMIN ] } - } + }, ]; @NgModule({ diff --git a/projects/admin/src/app/circulation/circulation.module.ts b/projects/admin/src/app/circulation/circulation.module.ts index 833bf3791..32ef718a9 100644 --- a/projects/admin/src/app/circulation/circulation.module.ts +++ b/projects/admin/src/app/circulation/circulation.module.ts @@ -20,6 +20,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormlyModule } from '@ngx-formly/core'; import { RecordModule } from '@rero/ng-core'; import { SharedModule } from '@rero/shared'; +import { AccordionModule } from 'primeng/accordion'; import { ButtonModule } from 'primeng/button'; import { DynamicDialogModule } from 'primeng/dynamicdialog'; import { InputSwitchModule } from 'primeng/inputswitch'; @@ -32,6 +33,7 @@ import { TagModule } from 'primeng/tag'; import { JournalVolumePipe } from 'projects/public-search/src/app/pipe/journal-volume.pipe'; import { CheckinActionComponent } from './checkin/checkin-action/checkin-action.component'; import { CheckinComponent } from './checkin/checkin.component'; +import { CirculationMainComponent } from './circulation-main.component'; import { CirculationRoutingModule } from './circulation-routing.module'; import { ItemComponent } from './item/item.component'; import { ItemsListComponent } from './items-list/items-list.component'; @@ -54,7 +56,7 @@ import { PatronFeeComponent } from './patron/patron-transactions/patron-fee/patr import { PatronTransactionEventFormComponent } from './patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component'; -import { PatronTransactionEventComponent } from './patron/patron-transactions/patron-transaction-event/patron-transaction-event.component'; +import { PatronTransactionHistoryComponent } from './patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component'; import { DefaultTransactionDetailComponent } from './patron/patron-transactions/patron-transaction/default-transaction-detail/default-transaction-detail.component'; @@ -69,6 +71,7 @@ import { PickupItemComponent } from './patron/pickup/pickup-item/pickup-item.com import { PickupComponent } from './patron/pickup/pickup.component'; import { ProfileComponent } from './patron/profile/profile.component'; import { GetLoanCipoPipe } from './pipe/get-loan-cipo.pipe'; +import { ScrollPanelModule } from 'primeng/scrollpanel'; @NgModule({ declarations: [ @@ -87,7 +90,6 @@ import { GetLoanCipoPipe } from './pipe/get-loan-cipo.pipe'; PickupItemComponent, PatronTransactionsComponent, PatronTransactionComponent, - PatronTransactionEventComponent, PatronTransactionEventFormComponent, OverdueTransactionComponent, DefaultTransactionDetailComponent, @@ -106,7 +108,9 @@ import { GetLoanCipoPipe } from './pipe/get-loan-cipo.pipe'; IllRequestComponent, IllRequestItemComponent, JournalVolumePipe, - CirculationSettingsComponent + CirculationSettingsComponent, + CirculationMainComponent, + PatronTransactionHistoryComponent ], imports: [ CirculationRoutingModule, @@ -124,8 +128,10 @@ import { GetLoanCipoPipe } from './pipe/get-loan-cipo.pipe'; RippleModule, MessagesModule, InputSwitchModule, - SplitButtonModule - ], + SplitButtonModule, + AccordionModule, + ScrollPanelModule + ], providers: [ CurrencyPipe ] diff --git a/projects/admin/src/app/circulation/circulation.scss b/projects/admin/src/app/circulation/circulation.scss deleted file mode 100644 index 2e8057c8b..000000000 --- a/projects/admin/src/app/circulation/circulation.scss +++ /dev/null @@ -1,37 +0,0 @@ -/* - * RERO ILS UI - * Copyright (C) 2023-2024 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 - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - - @import 'bootstrap/scss/functions'; - @import 'bootstrap/scss/variables'; - - .item { - margin-bottom: map-get($spacers, 1) !important; - padding: map-get($spacers, 1) !important; - border: $border-width solid $border-color; - border-radius: $border-radius; - position: relative; - - &:hover{ - background-color: $light; - } - - div.actions { - position: absolute; - top: map-get($spacers, 1); - right: 15px; - } - } diff --git a/projects/admin/src/app/circulation/items-list/items-list.component.scss b/projects/admin/src/app/circulation/circulationStatistics.ts similarity index 70% rename from projects/admin/src/app/circulation/items-list/items-list.component.scss rename to projects/admin/src/app/circulation/circulationStatistics.ts index 8fc910644..c48a4c7e8 100644 --- a/projects/admin/src/app/circulation/items-list/items-list.component.scss +++ b/projects/admin/src/app/circulation/circulationStatistics.ts @@ -1,7 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2022 RERO - * Copyright (C) 2022 UCLouvain + * Copyright (C) 2019-2025 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 @@ -15,11 +14,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - -@import 'bootstrap/scss/functions'; -@import 'bootstrap/scss/variables'; - -.btn-show-more { - background-color: transparent !important; - color: $white; +export class CirculationStatistics { + static FEES = 'fees'; + static FEES_ENGAGED = 'fees_engaged'; + static HISTORY = 'history'; + static ILL = 'ill'; + static LOAN = 'loan'; + static PENDING = 'pending'; + static PICKUP = 'pickup'; } diff --git a/projects/admin/src/app/circulation/item/item.component.html b/projects/admin/src/app/circulation/item/item.component.html index 3f520a4a4..cfc497916 100644 --- a/projects/admin/src/app/circulation/item/item.component.html +++ b/projects/admin/src/app/circulation/item/item.component.html @@ -1,6 +1,6 @@ @if (item && !(item.loading || false)) { -
- - -
- @if (patron) { - - } -
+
-
+
@if (!item.actions || item.loan || totalAmountOfFee || item.pending_loans || notifications$) { } -
+
{{ item.barcode }} @if (isCollapsed) { - + }
@if (item.actionDone) { @@ -59,7 +44,7 @@ }
-
+ - -
- @if (item.loan) { - - } @else { - {{ item.status | translate }} - } -
- -
- @if (item.actionDone) { - @switch (item.actionDone) { - @case (itemAction.checkin) { - - checked in - } - @case (itemAction.checkout) { - - checked out - } - @case (itemAction.extend_loan) { - - renewed - } - @default { - {{ item.actionDone | translate }} - } - } - } -
- + @if (!isCollapsed) { -
-
-
Call number
-
- +
+ +
+ } +
+ +
+ @if (item.loan) { +
    + @switch (item.status) { + @case ('on_loan') { +
  • + {{ item.status | translate }} + + + {{ item.loan.dueDate | dateTranslate :'shortDate' }} + +
  • + } + @case ('in_transit') { +
  • + {{ item.status | translate }} + @if (getTransitLocationPid() | getRecord: 'locations' | async; as location) { + ({{ 'to' | translate }} + @if (item.loan && item.loan.state === 'ITEM_IN_TRANSIT_FOR_PICKUP') { + {{ $any(location).metadata.pickup_name }} + } @else { + {{ $any(location).metadata.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }} + }) + } +
  • + } + @case ('on_shelf') { +
  • {{ item.status | translate }}
  • + } + @case ('at_desk') { +
  • + {{ item.status | translate }} + @if (item.loan && item.loan.pickup_location) { + ({{ item.loan.pickup_location.pickup_name }}) + } + @if (!item.loan && item.pending_loans && item.pending_loans.length > 0 && item.pending_loans[0].pickup_location) { + ({{ item.pending_loans[0].pickup_location.pickup_name }}) + + } +
  • + } + @default { +
  • {{ item.status | translate }}
  • } } - - @if (canUseDebugMode) { - + +
  • + @if (isCollapsed && item.loan && item.loan.extension_count && (!item.actionDone || item.actionDone !== itemAction.checkin)) { + + {{ item.loan.extension_count }} + + } + @if (isCollapsed && totalAmountOfFee > 0) { + + {{ totalAmountOfFee | currency: organisation.default_currency }} + + } + @if (isCollapsed && item.pending_loans && item.pending_loans.length) { + + + + {{ item.pending_loans[0].patron.name }} + + + } +
  • +
+ } @else { + {{ item.status | translate }} + } +
+ +
+
+ @if (item.actionDone) { +
+ @switch (item.actionDone) { + @case (itemAction.checkin) { + + checked in + } + @case (itemAction.checkout) { + + checked out + } + @case (itemAction.extend_loan) { + + renewed + } + @default { + {{ item.actionDone | translate }} + } + } +
+ } @else { +
+ +
}
+ @if (canUseDebugMode && !isCollapsed) { +
+ + + +
+ } +
+ @if (debugMode && !isCollapsed) { +
+
 {{ 'Debug' | translate }}
+
+ @if (loan) { +
+
+

Loan

+ +
{{ loan | json }}
+
+
+
+
+ @if (loan | getLoanCipo | async; as cipo) { +
+

+ {{ 'Circulation policy' | translate }}  + + + +

+ +
{{ cipo | json }}
+
+
+ } +
+ } @else { +
+
+

Item

+ +
{{ item | json }}
+
+
+
+ } +
+
}
} diff --git a/projects/admin/src/app/circulation/item/item.component.ts b/projects/admin/src/app/circulation/item/item.component.ts index f2bc990cb..1998972ba 100644 --- a/projects/admin/src/app/circulation/item/item.component.ts +++ b/projects/admin/src/app/circulation/item/item.component.ts @@ -30,8 +30,7 @@ import { map } from 'rxjs/operators'; @Component({ selector: 'admin-item', - templateUrl: './item.component.html', - styleUrls: ['../circulation.scss'] + templateUrl: './item.component.html' }) export class ItemComponent implements OnInit { diff --git a/projects/admin/src/app/circulation/items-list/items-list.component.html b/projects/admin/src/app/circulation/items-list/items-list.component.html index 6e58e63a3..129c2b028 100644 --- a/projects/admin/src/app/circulation/items-list/items-list.component.html +++ b/projects/admin/src/app/circulation/items-list/items-list.component.html @@ -21,44 +21,52 @@ } @if ((checkedOutItems && checkedOutItems.length > 0) || (checkedInItems && checkedInItems.length > 0)) { -
-
- - {{ 'Items' | translate }} -
-
Document
-
Circulation info
-
- @if (patron) { - + + + + +
+ + @for (item of checkedOutItems; track item) { + } -
-
- - @for (item of checkedOutItems; track item) { - - - } - - - - @for (item of checkedInItems; track item) { - - - } + + + @for (item of checkedInItems; track item) { + + } +
+ } diff --git a/projects/admin/src/app/circulation/items-list/items-list.component.ts b/projects/admin/src/app/circulation/items-list/items-list.component.ts index 6b90bcd1b..a755f7e98 100644 --- a/projects/admin/src/app/circulation/items-list/items-list.component.ts +++ b/projects/admin/src/app/circulation/items-list/items-list.component.ts @@ -21,7 +21,6 @@ import { ItemAction } from '../../classes/items'; @Component({ selector: 'admin-circulation-items-list', - styleUrls: ['./items-list.component.scss'], templateUrl: './items-list.component.html' }) export class ItemsListComponent implements OnInit{ diff --git a/projects/admin/src/app/circulation/main-request/main-request.component.html b/projects/admin/src/app/circulation/main-request/main-request.component.html index dd265ff9c..0c73d4620 100644 --- a/projects/admin/src/app/circulation/main-request/main-request.component.html +++ b/projects/admin/src/app/circulation/main-request/main-request.component.html @@ -25,30 +25,49 @@ />
-
- -
- - -
+
-
- - +
+
+ + +
+
+ @if (refreshInterval > 0) { + + +
+ +
{{ item.label }}
+
+
+ +
+ +
{{ item.label }}
+
+
+
+ + } + + + +
+ +
{{ item.label }}
+
+
+ +
+ +
{{ item.label }}
+
+
+
+
+
- @if (refreshInterval > 0) { - - } - -
@@ -56,7 +75,6 @@
diff --git a/projects/admin/src/app/circulation/main-request/main-request.component.ts b/projects/admin/src/app/circulation/main-request/main-request.component.ts index 433da8321..31d466297 100644 --- a/projects/admin/src/app/circulation/main-request/main-request.component.ts +++ b/projects/admin/src/app/circulation/main-request/main-request.component.ts @@ -38,24 +38,24 @@ export class MainRequestComponent implements OnInit, OnDestroy { // COMPONENT ATTRIBUTES ================================================================== /** options used for auto-refresh select box */ public refreshOptions = [ - {value: '15000', label: '15 s', icon: 'fa-clock-o'}, - {value: '30000', label: '30 s', icon: 'fa-clock-o'}, - {value: '60000', label: '1 m', icon: 'fa-clock-o'}, - {value: '300000', label: '5 m', icon: 'fa-clock-o'}, - {value: '600000', label: '10 m', icon: 'fa-clock-o'}, - {value: '3000000', label: '30 m', icon: 'fa-clock-o'} + {value: '15000', label: '15 s', icon: 'fa fa-clock-o'}, + {value: '30000', label: '30 s', icon: 'fa fa-clock-o'}, + {value: '60000', label: '1 m', icon: 'fa fa-clock-o'}, + {value: '300000', label: '5 m', icon: 'fa fa-clock-o'}, + {value: '600000', label: '10 m', icon: 'fa fa-clock-o'}, + {value: '3000000', label: '30 m', icon: 'fa fa-clock-o'} ]; /** options used to sort requested items list */ public sortingCriteria = [ - {value: 'requestdate', label: this.translateService.instant('Request date'), icon: 'fa-sort-numeric-asc'}, - {value: '-requestdate', label: this.translateService.instant('Request date (desc)'), icon: 'fa-sort-numeric-desc'}, - {value: 'callnumber', label: this.translateService.instant('Call number'), icon: 'fa-sort-alpha-asc'}, - {value: '-callnumber', label: this.translateService.instant('Call number (desc)'), icon: 'fa-sort-alpha-desc'}, - {value: 'location', label: this.translateService.instant('Location'), icon: 'fa-sort-alpha-asc'}, - {value: '-location', label: this.translateService.instant('Location (desc)'), icon: 'fa-sort-alpha-desc'}, - {value: 'pickuplocation', label: this.translateService.instant('Pick-up location'), icon: 'fa-sort-alpha-asc'}, - {value: '-pickuplocation', label: this.translateService.instant('Pick-up location (desc)'), icon: 'fa-sort-alpha-desc'}, + {value: 'requestdate', label: this.translateService.instant('Request date'), icon: 'fa fa-sort-numeric-asc'}, + {value: '-requestdate', label: this.translateService.instant('Request date (desc)'), icon: 'fa fa-sort-numeric-desc'}, + {value: 'callnumber', label: this.translateService.instant('Call number'), icon: 'fa fa-sort-alpha-asc'}, + {value: '-callnumber', label: this.translateService.instant('Call number (desc)'), icon: 'fa fa-sort-alpha-desc'}, + {value: 'location', label: this.translateService.instant('Location'), icon: 'fa fa-sort-alpha-asc'}, + {value: '-location', label: this.translateService.instant('Location (desc)'), icon: 'fa fa-sort-alpha-desc'}, + {value: 'pickuplocation', label: this.translateService.instant('Pick-up location'), icon: 'fa fa-sort-alpha-asc'}, + {value: '-pickuplocation', label: this.translateService.instant('Pick-up location (desc)'), icon: 'fa fa-sort-alpha-desc'}, ]; /** the placeholder string used on the */ @@ -66,8 +66,6 @@ export class MainRequestComponent implements OnInit, OnDestroy { public items = null; /** the interval (in millis) between 2 calls of requested items (0 = no refresh) */ public refreshInterval = 0; - /** is the requested items detail should be collapsed or not */ - public isDetailCollapsed = true; /** Focus attribute of the search input */ public searchInputFocus = true; /** Disabled attribute of the search input */ diff --git a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.html b/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.html index 1ee714091..c36f6a38f 100644 --- a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.html +++ b/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.html @@ -1,6 +1,6 @@ @if (document) { -
-
+
+
+ +
+
+ @if (document.title | mainTitle; as title) { + + {{ title }} +
+ } + +
+
+ +
+
{{ item.loan.creation_date | dateTranslate :'medium' }}
+
@if (item.loan.state === LoanState.PENDING) { }
- - -
- @if (document.title | mainTitle; as title) { - - {{ title }} -
+ @if (!isCollapsed) { +
-
- -
-
{{ item.loan.creation_date | dateTranslate :'medium' }}
- - @if (!isCollapsed) { -
-
- - @if (item.enumerationAndChronology) { -
Unit
-
{{ item.enumerationAndChronology }}
- } - -
Requested by
-
- - {{ item.loan.patron.name }} - -
- -
Location
-
- {{ item.library.name }} - - @if (item.temporary_location?.name) { - {{ item.temporary_location.name }} - } @else { - {{ item.location.name }} - } + +
Requested by
+
+ + {{ item.loan.patron.name }} + +
+ +
Location
+
+ {{ item.library.name }} - + @if (item.temporary_location?.name) { + {{ item.temporary_location.name }} + } @else { + {{ item.location.name }} + } -
-
Pick-up location
-
- - - @if (item.loan.pickup_location.pickup_name) { - {{ item.loan.pickup_location.pickup_name }} - } @else { - {{ item.loan.pickup_location.library_name }}: {{ item.loan.pickup_location.name }} - } -
-
-
- } + +
Pick-up location
+
+ + + @if (item.loan.pickup_location.pickup_name) { + {{ item.loan.pickup_location.pickup_name }} + } @else { + {{ item.loan.pickup_location.library_name }}: {{ item.loan.pickup_location.name }} + } +
+ + }
} diff --git a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.ts b/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.ts index 1cac3d87b..f71920aee 100644 --- a/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.ts +++ b/projects/admin/src/app/circulation/main-request/requested-item/requested-item.component.ts @@ -21,8 +21,7 @@ import { RecordService } from '@rero/ng-core'; @Component({ selector: 'admin-requested-item', - templateUrl: './requested-item.component.html', - styleUrls: ['./requested-item.component.scss'] + templateUrl: './requested-item.component.html' }) export class RequestedItemComponent implements OnInit { @@ -67,7 +66,6 @@ export class RequestedItemComponent implements OnInit { getCallout() { return (this.callout !== null) ? `callout ${this.callout}` - : 'border rounded'; + : null; } - } diff --git a/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.html b/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.html index 5eaee360f..a6154ec86 100644 --- a/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.html +++ b/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.html @@ -14,25 +14,42 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> +@defer (when items) { + + + + + @if (items.length > 0) { +
+ @for (item of items; track item) { + + } +
+ } @else { +
+ {{ 'no request to validate' | translate }} +
} - } @else { - {{ 'no request to validate' | translate }} - } +
+} @placeholder { +
Loading in progress
} diff --git a/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.ts b/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.ts index c0bc2cb0e..e31dd851c 100644 --- a/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.ts +++ b/projects/admin/src/app/circulation/main-request/requested-items-list/requested-items-list.component.ts @@ -28,11 +28,12 @@ export class RequestedItemsListComponent implements OnChanges { // COMPONENT ATTRIBUTES ==================================================== /** Item list */ @Input() items: any[]; - /** Is the item detail should be collapsed */ - @Input() isCollapsed: boolean; + /** event emit when a request is validated */ @Output() requestValidated = new EventEmitter(); + /** Is the item detail should be collapsed */ + isCollapsed: boolean = true; /** the know item barcode list */ private knownItemBarcodes: Array = null; @@ -68,5 +69,4 @@ export class RequestedItemsListComponent implements OnChanges { validateRequest(itemBarcode: string) { this.requestValidated.emit(itemBarcode); } - } diff --git a/projects/admin/src/app/circulation/patron/cancel-request-button.component.ts b/projects/admin/src/app/circulation/patron/cancel-request-button.component.ts index 35061e00c..ada05bbd7 100644 --- a/projects/admin/src/app/circulation/patron/cancel-request-button.component.ts +++ b/projects/admin/src/app/circulation/patron/cancel-request-button.component.ts @@ -24,22 +24,17 @@ import { MessageService } from 'primeng/api'; @Component({ selector: 'admin-cancel-request-button', template: ` - @if (canCancelRequest()) { - } @else { - - } ` }) export class CancelRequestButtonComponent { diff --git a/projects/admin/src/app/circulation/patron/card/card.component.html b/projects/admin/src/app/circulation/patron/card/card.component.html index 5f66fdb1b..fbc2e9d2d 100644 --- a/projects/admin/src/app/circulation/patron/card/card.component.html +++ b/projects/admin/src/app/circulation/patron/card/card.component.html @@ -15,11 +15,11 @@ along with this program. If not, see . --> @if (patron?.patron) { -
+
-
+
-
+
@@ -63,10 +63,10 @@

@if (patron.notes) { -
    +
      @for (note of patron.notes; track note) {
    • - {{ note.type | translate | ucfirst }} + {{ note.type | translate | ucfirst }}

    • } @@ -75,7 +75,7 @@

      }

-
+
@if (displayCirculationMessages) { @if (patron.circulation_information) { @@ -88,14 +88,12 @@

/> } } - @for (message of circulationMessages; track message) { - - } + }

diff --git a/projects/admin/src/app/circulation/patron/card/card.component.scss b/projects/admin/src/app/circulation/patron/card/card.component.scss index a3ed182c0..220c186e6 100644 --- a/projects/admin/src/app/circulation/patron/card/card.component.scss +++ b/projects/admin/src/app/circulation/patron/card/card.component.scss @@ -29,3 +29,7 @@ visibility: hidden; } } + +.p-message { + @extend .mt-0; +} diff --git a/projects/admin/src/app/circulation/patron/card/card.component.ts b/projects/admin/src/app/circulation/patron/card/card.component.ts index a0ee6920d..d9de70be1 100644 --- a/projects/admin/src/app/circulation/patron/card/card.component.ts +++ b/projects/admin/src/app/circulation/patron/card/card.component.ts @@ -14,17 +14,16 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core'; import { DateTime } from 'luxon'; import { getSeverity } from '../../../utils/utils'; import { CirculationService } from '../../services/circulation.service'; @Component({ selector: 'admin-circulation-patron-detailed', - templateUrl: './card.component.html', - styleUrls: ['./card.component.scss'] + templateUrl: './card.component.html' }) -export class CardComponent { +export class CardComponent implements OnInit { private circulationService: CirculationService = inject(CirculationService); @@ -42,40 +41,38 @@ export class CardComponent { /** event emitter when the close button are fired */ @Output() clearPatron = new EventEmitter(); - // GETTER & SETTER ========================================================== - /** Build the link used on the patron name */ - get patronLink(): string { + /** Link used on the patron name */ + patronLink: string; + /** it's the birthday of the patron */ + isBirthday: boolean = false; + /** Patron age */ + patronAge: number; + /** circulation messages about the loaded patron if exists */ + circulationMessages: {severity: string, detail: string}[] = []; + + ngOnInit(): void { if (this.patron) { - return (this.linkMode === 'detail') + this.patronLink = (this.linkMode === 'detail') ? '/records/patrons/detail/' + this.patron.pid : '/circulation/patron/' + this.barcode + '/loan'; } - } - /** Get the patron age */ - get patronAge(): number { if (this.patron && this.patron.birth_date) { - const birthDate = DateTime.fromISO(this.patron.birth_date); - return Math.floor(DateTime.now().diff(birthDate, 'years').years); + const today = DateTime.now().toFormat('M-dd'); + const birthDate = DateTime.fromISO(this.patron.birth_date).toFormat('M-dd'); + if (today === birthDate) { + this.isBirthday = true; + } } - } - /** Defined if it's the birthday of the patron */ - get isBirthday(): boolean { if (this.patron && this.patron.birth_date) { - const today = DateTime.fromISO(DateTime.now().toFormat('yyyy-M-d')); const birthDate = DateTime.fromISO(this.patron.birth_date); - return today.diff(birthDate, 'years').years % 1 === 0; + this.patronAge = Math.floor(DateTime.now().diff(birthDate, 'years').years); } - return false; - } - /** Get the circulation messages about the loaded patron if exists */ - get circulationMessages(): Array<{type: string, content: string}> { - return this.circulationService.messages(); + this.circulationMessages = this.circulationService.messages(); } - // COMPONENT FUNCTIONS ====================================================== /** Clear current patron */ clear(): void { if (this.patron) { @@ -91,5 +88,4 @@ export class CardComponent { getMessageSeverity(level: string): string { return getSeverity(level); } - } diff --git a/projects/admin/src/app/circulation/patron/change-password-form/change-password-form.component.html b/projects/admin/src/app/circulation/patron/change-password-form/change-password-form.component.html index 8e105c0bf..b80a3f2a0 100644 --- a/projects/admin/src/app/circulation/patron/change-password-form/change-password-form.component.html +++ b/projects/admin/src/app/circulation/patron/change-password-form/change-password-form.component.html @@ -16,8 +16,8 @@ --> @if (form) {
- -
+ +
. --> -
+
-
-
+
+ -
+
@if (document?.metadata?.contribution && document.metadata.contribution.length > 0) { - } @else { -   }
-
+
{{ log.metadata.date | dateTranslate: 'short' }}
@if (!isCollapsed) { -
+
@if (log.metadata.loan.item.pid | getRecord:'items' | async; as item) { - diff --git a/projects/admin/src/app/circulation/patron/history/history-log/history-log.component.ts b/projects/admin/src/app/circulation/patron/history/history-log/history-log.component.ts index 9987dcc62..16685b006 100644 --- a/projects/admin/src/app/circulation/patron/history/history-log/history-log.component.ts +++ b/projects/admin/src/app/circulation/patron/history/history-log/history-log.component.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2021-2024 RERO + * Copyright (C) 2021-2025 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 @@ -37,15 +37,23 @@ export class HistoryLogComponent { provisionActivityType = ProvisionActivityType; /** Checkout record operation logs */ - checkout: any = null; + checkoutLoaded: boolean = false; + + events: any[] = []; /** Load checkout */ loadCheckout() { - if (this.checkout === null) { + if (!this.checkoutLoaded) { this.operationLogsApiService .getHistoryByLoanPid(this.log.metadata.loan.pid, 'checkout') .subscribe((log: any) => { - this.checkout = log; + this.checkoutLoaded = true; + this.log.metadata['type'] = 'Checkin'; + this.events = [this.log.metadata]; + if (log) { + log.metadata['type'] = 'Checkout'; + this.events.push(log.metadata); + } }); } } diff --git a/projects/admin/src/app/circulation/patron/history/history.component.html b/projects/admin/src/app/circulation/patron/history/history.component.html index 5b3188c9c..58c8dad00 100644 --- a/projects/admin/src/app/circulation/patron/history/history.component.html +++ b/projects/admin/src/app/circulation/patron/history/history.component.html @@ -17,18 +17,20 @@ @if (historyLogs$ | async; as logs) {
@if (logs.length > 0) { - -
-
Title
-
Authors
-
Return date
+ +
+ @for (log of logs; track log) { + + }
- - @for (log of logs; track log) { - - } } @else { - {{ 'No history.' | translate }} +
+ {{ 'No history.' | translate }} +
}
} diff --git a/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.html b/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.html index 128f8a1aa..a100d8cbf 100644 --- a/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.html +++ b/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.html @@ -15,9 +15,9 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -
+
-
+
{{ record.metadata.document.title }} @@ -39,35 +39,35 @@
@if (!isCollapsed) { -
-
+
+ diff --git a/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.ts b/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.ts index effe50a4f..42d9d33a2 100644 --- a/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.ts +++ b/projects/admin/src/app/circulation/patron/ill-request/ill-request-item/ill-request-item.component.ts @@ -20,8 +20,7 @@ import { getTagSeverityFromStatus } from '@app/admin/utils/utils'; @Component({ selector: 'admin-ill-request-item', - templateUrl: './ill-request-item.component.html', - styleUrls: ['../../../circulation.scss'] + templateUrl: './ill-request-item.component.html' }) export class IllRequestItemComponent { diff --git a/projects/admin/src/app/circulation/patron/ill-request/ill-request.component.html b/projects/admin/src/app/circulation/patron/ill-request/ill-request.component.html index 1b0c09676..0d67ae468 100644 --- a/projects/admin/src/app/circulation/patron/ill-request/ill-request.component.html +++ b/projects/admin/src/app/circulation/patron/ill-request/ill-request.component.html @@ -14,22 +14,31 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -@if (illRequests$ | async; as illRequests) { -
- @if (illRequests.length > 0) { - -
-
Document
+@if(illRequests$ | async; as illRequests) { + + + + + @if (illRequests.length > 0) { +
+ @for (record of illRequests; track record) { + + }
- @for (record of illRequests; track record) { - - } } @else { - {{ 'No ill request.' | translate }} +
+ No ill request. +
} -
+ +} @else { +
Loading in progress
} diff --git a/projects/admin/src/app/circulation/patron/loan/circulation-settings/circulation-settings.component.ts b/projects/admin/src/app/circulation/patron/loan/circulation-settings/circulation-settings.component.ts index a267a1731..7b7794923 100644 --- a/projects/admin/src/app/circulation/patron/loan/circulation-settings/circulation-settings.component.ts +++ b/projects/admin/src/app/circulation/patron/loan/circulation-settings/circulation-settings.component.ts @@ -64,7 +64,6 @@ export class CirculationSettingsComponent implements OnInit { this.dialogRef = this.dialogService.open(FixedDateFormComponent, { header: this.translateService.instant('Choose a due date'), width: '30vw', - height: '600px' }); this.dialogRef.onClose.subscribe((result?: any) => { if (result && 'action' in result && result.action === 'submit') { diff --git a/projects/admin/src/app/circulation/patron/loan/fixed-date-form/fixed-date-form.component.html b/projects/admin/src/app/circulation/patron/loan/fixed-date-form/fixed-date-form.component.html index 833e66cfe..c1e8dab5f 100644 --- a/projects/admin/src/app/circulation/patron/loan/fixed-date-form/fixed-date-form.component.html +++ b/projects/admin/src/app/circulation/patron/loan/fixed-date-form/fixed-date-form.component.html @@ -16,50 +16,54 @@ along with this program. If not, see . --> -
+
- @if (formGroup.controls.endDate.valid || !formGroup.controls.endDate.touched) { - - - {{ 'This date will override the circulation policy behavior' | translate }} - - } - @if (formGroup.controls.endDate.touched && formGroup.controls.endDate.hasError('required')) { - - - } - @if (formGroup.controls.endDate.touched && formGroup.controls.endDate.hasError('minimum-date')) { - - - } -
-
- - +
+ @if (formGroup.controls.endDate.valid || !formGroup.controls.endDate.touched) { + + + {{ 'This date will override the circulation policy behavior' | translate }} + + } + @if (formGroup.controls.endDate.touched && formGroup.controls.endDate.hasError('required')) { + + + } + @if (formGroup.controls.endDate.touched && formGroup.controls.endDate.hasError('minimum-date')) { + + + } +
+
+ + +
- {{ formGroup.controls.endDate['errorMessages'] | json }} -
+ } +
} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.html index f343f9dcb..d3c0c57e3 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.html @@ -1,6 +1,6 @@ @defer (when formFields) {
- -
+ +
- +
} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.ts index 2a757c498..fb6309b78 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.ts +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-fee/patron-fee.component.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2022-2024 RERO + * Copyright (C) 2022-2025 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 { getCurrencySymbol } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { CirculationStatistics } from '@app/admin/circulation/circulationStatistics'; import { CirculationService } from '@app/admin/circulation/services/circulation.service'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; @@ -30,8 +31,7 @@ import { OrganisationService } from 'projects/admin/src/app/service/organisation @Component({ selector: 'admin-patron-fee', - templateUrl: './patron-fee.component.html', - styles: ['.p-inputtext { width: 100%; padding: 0 }'] + templateUrl: './patron-fee.component.html' }) export class PatronFeeComponent implements OnInit { @@ -74,7 +74,8 @@ export class PatronFeeComponent implements OnInit { } this.patronTransactionApiService.addFee(model).subscribe({ next: () => { - this.circulationService.statisticsIncrease('fees', model.total_amount); + this.circulationService.statisticsIncrease(CirculationStatistics.FEES_ENGAGED, model.total_amount); + this.circulationService.statisticsIncrease(CirculationStatistics.FEES, model.total_amount); this.closeModal(); this.messageService.add({ severity: 'success', @@ -132,7 +133,7 @@ export class PatronFeeComponent implements OnInit { props: { label: 'Date', required: true, - dateFormat: 'yy-mm-dd', + dateFormat: 'yy-mm-dd' } }]; diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.html index e5a5f41e8..212e400f8 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.html @@ -1,6 +1,6 @@ @if (transactions) {
+ + + @for (transaction of transactions; track transaction) {
@@ -36,7 +39,8 @@
} - +
+
diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.ts index 92eb05191..3833d9e63 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.ts +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event-form/patron-transaction-event-form.component.ts @@ -17,6 +17,8 @@ import { getCurrencySymbol } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; +import { CirculationStatistics } from '@app/admin/circulation/circulationStatistics'; +import { CirculationService } from '@app/admin/circulation/services/circulation.service'; import { PatronTransactionService } from '@app/admin/circulation/services/patron-transaction.service'; import { PatronTransaction } from '@app/admin/classes/patron-transaction'; import { OrganisationService } from '@app/admin/service/organisation.service'; @@ -36,6 +38,7 @@ export class PatronTransactionEventFormComponent implements OnInit { private translateService: TranslateService = inject(TranslateService); private organisationService: OrganisationService = inject(OrganisationService); private patronTransactionService: PatronTransactionService = inject(PatronTransactionService); + private circulationService: CirculationService = inject(CirculationService); /** the transactions to perform with this form */ transactions: Array; @@ -191,6 +194,8 @@ export class PatronTransactionEventFormComponent implements OnInit { ? transaction.total_amount : residualAmount; this.patronTransactionService.payPatronTransaction(transaction, transactionAmount, formValues.method); + this.circulationService.statisticsDecrease(CirculationStatistics.FEES_ENGAGED, transactionAmount); + this.circulationService.statisticsDecrease(CirculationStatistics.FEES, transactionAmount); // DEV NOTES : We use the below syntax to avoid floating-number precision drift. // on each iteration we 'round' the residual amount to a float with 2 decimals precision. // --> with this syntax : (7.8 - 2 - 2 - 2) = 1.8 @@ -207,6 +212,8 @@ export class PatronTransactionEventFormComponent implements OnInit { } else if (this.action === 'cancel') { for (const transaction of this.transactions) { this.patronTransactionService.cancelPatronTransaction(transaction, formValues.amount, formValues.comment); + this.circulationService.statisticsDecrease(CirculationStatistics.FEES_ENGAGED, formValues.amount); + this.circulationService.statisticsDecrease(CirculationStatistics.FEES, formValues.amount); } } this.dynamicDialogRef.close(); diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.html deleted file mode 100644 index 3f4450bda..000000000 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.html +++ /dev/null @@ -1,109 +0,0 @@ - -@if (event !== undefined) { -
- {{ event.creation_date | dateTranslate: 'shortDate' }} - {{ event.creation_date | dateTranslate: 'HH:mm:ss' }} -
-
-
-
{{ label }}
-
- @if (event.type !== patronTransactionEventType.DISPUTE) { - - {{ event.amount | currency: organisation.default_currency }} - - } -
-
- @if (event.pid) { - - } -
-
- @if (!isCollapsed) { - @if (event.note) { -
-
- - {{ 'Note' | translate }} -
-
{{ event.note }}
-
- } - @if (event.operator) { - @if (event.operator.pid | getRecord:'patrons' | async; as operator) { -
-
- - {{ 'Operator' | translate }} -
-
- @if ($any(operator).metadata.last_name) { - {{ $any(operator).metadata.last_name }} - } - @if ($any(operator).metadata.last_name && $any(operator).metadata.first_name) { - , - } - @if ($any(operator).metadata.first_name) { - {{ $any(operator).metadata.first_name }} - } -
-
- } - } - @if (event.library) { - @if (event.library.pid | getRecord:'libraries' | async; as library) { -
-
- - {{ 'Library' | translate }} -
-
{{ $any(library).metadata.name }}
-
- } - } - @if (event.steps) { - @for (step of event.steps; track step; let first = $first) { -
-
- @if (first) { - {{ 'Steps' | translate }} - } -
-
{{ step.timestamp | dateTranslate: 'shortDate' }}
-
- @if (event.type !== patronTransactionEventType.DISPUTE) { - - {{ step.amount | currency: organisation.default_currency }} - - } -
-
- } - } - } -
-} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.spec.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.spec.ts deleted file mode 100644 index 143223d7d..000000000 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * RERO ILS UI - * Copyright (C) 2019-2024 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 - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { CirculationModule } from '../../../circulation.module'; -import { PatronTransactionEventComponent } from './patron-transaction-event.component'; - -describe('PatronTransactionEventComponent', () => { - let component: PatronTransactionEventComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - HttpClientTestingModule, - CirculationModule - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PatronTransactionEventComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.ts deleted file mode 100644 index 84f07b5ea..000000000 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction-event/patron-transaction-event.component.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * RERO ILS UI - * Copyright (C) 2019-2024 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 - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -import { Component, inject, Input } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { OrganisationService } from '@app/admin/service/organisation.service'; -import { PatronTransactionEvent, PatronTransactionEventType } from '@app/admin/classes/patron-transaction'; - -@Component({ - selector: 'admin-patron-transaction-event', - templateUrl: './patron-transaction-event.component.html' -}) -export class PatronTransactionEventComponent { - - private organisationService: OrganisationService = inject(OrganisationService); - private translateService: TranslateService = inject(TranslateService); - - /** the event ot display */ - @Input() event: PatronTransactionEvent; - - /** is the transaction event is collapsed */ - isCollapsed = true; - - /** store a reference to enum to use in html template */ - patronTransactionEventType = PatronTransactionEventType; - - /** Get current organisation - * @return: current organisation - */ - get organisation() { - return this.organisationService.organisation; - } - - /** - * Get the best possible label of the transaction event - * @return label to display as string - */ - get label(): string { - return (this.event.subtype) - ? `${this.translateService.instant(this.event.type.toString())} [${this.translateService.instant(this.event.subtype)}]` - : this.translateService.instant(this.event.type.toString()); - } -} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/default-transaction-detail/default-transaction-detail.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/default-transaction-detail/default-transaction-detail.component.html index 217a94711..691e36d5b 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/default-transaction-detail/default-transaction-detail.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/default-transaction-detail/default-transaction-detail.component.html @@ -15,8 +15,8 @@ along with this program. If not, see . --> @if (transaction?.note) { -
-
Note
-
{{ transaction.note }}
+
+
Note
+
{{ transaction.note }}
} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/overdue-transaction-detail/overdue-transaction-detail.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/overdue-transaction-detail/overdue-transaction-detail.component.html index ff3a9ae17..7e03f7079 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/overdue-transaction-detail/overdue-transaction-detail.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/overdue-transaction-detail/overdue-transaction-detail.component.html @@ -1,6 +1,6 @@ @if (transaction) { - @if (transaction.note) { -
Note
-
{{ transaction.note }}
- } - @if (transaction.document !== null) { - @if (transaction.document.pid | getRecord:'documents' | async; as document) { -
-
Document
-
- @if ($any(document).metadata.title | mainTitle; as title) { - - {{ title | truncateText: 15 }} - - } -
+
+ @if (transaction.note) { +
Note
+
{{ transaction.note }}
+ } + @if (transaction.document !== null && transaction.document.pid | getRecord:'documents' | async; as document) { +
Document
+
+ @if ($any(document).metadata.title | mainTitle; as title) { + + {{ title | truncateText: 15 }} + + }
} - } - @if (item) { -
-
Item
-
+ @if (item) { +
Item
+ -
- } - @if (transaction.loan !== null) { - @if (transaction.loan.pid | getRecord: 'loans' | async; as loan) { -
-
Loan started at
-
{{ $any(loan).metadata.start_date | dateTranslate: 'shortDate' }}
-
} - } + @if (transaction.loan !== null) { + @if (transaction.loan.pid | getRecord: 'loans' | async; as loan) { +
Loan started at
+
{{ $any(loan).metadata.start_date | dateTranslate: 'shortDate' }}
+ } + } +
} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.html new file mode 100644 index 000000000..343ffd569 --- /dev/null +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.html @@ -0,0 +1,121 @@ + + + + + + + +
+
{{ eventLabel(event) }}
+ @if (event.type !== patronTransactionEventType.DISPUTE) { + + } + @if (event.pid) { + + } +
+
+ @if (event.note) { +
+
+   + {{ 'Note' | translate }} +
+
{{ event.note }}
+
+ } + @if (event.operator) { + @if (event.operator.pid | getRecord:'patrons' | async; as operator) { +
+
+   + {{ 'Operator' | translate }} +
+
+ @if ($any(operator).metadata.last_name) { + {{ $any(operator).metadata.last_name }} + } + @if ($any(operator).metadata.last_name && $any(operator).metadata.first_name) { + , + } + @if ($any(operator).metadata.first_name) { + {{ $any(operator).metadata.first_name }} + } +
+
+ } + } + @if (event.library) { + @if (event.library.pid | getRecord:'libraries' | async; as library) { +
+
+   + {{ 'Library' | translate }} +
+
{{ $any(library).metadata.name }}
+
+ } + } + @if (event.steps) { + @for (step of event.steps; track step; let first = $first) { +
+
+ @if (first) { +   + {{ 'Steps' | translate }} + } +
+
{{ step.timestamp | dateTranslate: 'shortDate' }}
+
+ @if (event.type !== patronTransactionEventType.DISPUTE) { + + {{ step.amount | currency: organisation.default_currency }} + + } +
+
+ } + } +
+
+ + + + {{ event.creation_date | dateTranslate: 'shortDate' }} + {{ event.creation_date | dateTranslate: 'HH:mm:ss' }} + + +
diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.spec.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.spec.ts new file mode 100644 index 000000000..621919342 --- /dev/null +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.spec.ts @@ -0,0 +1,39 @@ +/* + * RERO ILS UI + * Copyright (C) 2019-2025 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 + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PatronTransactionHistoryComponent } from './patron-transaction-history.component'; + +describe('PatronTransactionHistoryComponent', () => { + let component: PatronTransactionHistoryComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PatronTransactionHistoryComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PatronTransactionHistoryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.ts new file mode 100644 index 000000000..5806e3db2 --- /dev/null +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction-history/patron-transaction-history.component.ts @@ -0,0 +1,64 @@ +/* + * RERO ILS UI + * Copyright (C) 2019-2025 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 + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import { Component, inject, input } from '@angular/core'; +import { PatronTransactionEventType } from '@app/admin/classes/patron-transaction'; +import { OrganisationService } from '@app/admin/service/organisation.service'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'admin-patron-transaction-history', + templateUrl: './patron-transaction-history.component.html' +}) +export class PatronTransactionHistoryComponent { + + private translateService: TranslateService = inject(TranslateService); + private organisationService: OrganisationService = inject(OrganisationService); + + events = input.required<[]>(); + + patronTransactionEventType = PatronTransactionEventType; + + get organisation() { + return this.organisationService.organisation; + } + + eventLabel(event: any): string { + return (event.subtype) + ? `${this.translateService.instant(event.type.toString())} [${this.translateService.instant(event.subtype)}]` + : this.translateService.instant(event.type.toString()); + } + + tagSeverity(event: any) { + switch(event.type) { + case this.patronTransactionEventType.FEE: + return 'danger'; + case this.patronTransactionEventType.PAYMENT: + return 'success'; + case this.patronTransactionEventType.CANCEL: + return 'info'; + } + } + + hideShowEye(event: string): boolean { + return document.getElementById(event).hidden; + } + + hideShowEvent(event: string): void { + const element = document.getElementById(event); + element.hidden = !element.hidden; + } +} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.html index 200725bb6..b7e8ed4c4 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.html @@ -1,6 +1,6 @@ @if (transaction !== undefined) { -
-
-
+
+
+
- {{ transaction.creation_date | dateTranslate :'shortDate' }} +
+ {{ transaction.creation_date | dateTranslate :'shortDate' }} +
-
{{ transaction.type | translate }}
-
+
{{ transaction.type | translate }}
+
@if (transaction.library) { {{ transaction.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }} }
-
{{ transactionAmount | currency: organisation.default_currency }}
-
+
{{ transactionAmount | currency: organisation.default_currency }}
+
@if (transaction.status === patronTransactionStatus.OPEN) {
Details
-
+
Transaction history
-
- @for (event of transaction.get_events(); track event) { - - } -
+
}
diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.ts index b9d971d99..1c76b9646 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.ts +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transaction/patron-transaction.component.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2021-2024 RERO + * Copyright (C) 2021-2025 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 @@ -54,6 +54,9 @@ export class PatronTransactionComponent implements OnInit { menuItems: MenuItem[] = []; menuSelectedAction = undefined; + /** store a reference to enum to use in html template */ + patronTransactionEventType = PatronTransactionEventType; + // GETTER & SETTER ================================================ /** get the total amount for a patron transaction : * If transaction is still open, then return the total transaction amount @@ -151,4 +154,30 @@ export class PatronTransactionComponent implements OnInit { } ]; } + + eventLabel(event: any): string { + return (event.subtype) + ? `${this.translateService.instant(event.type.toString())} [${this.translateService.instant(event.subtype)}]` + : this.translateService.instant(event.type.toString()); + } + + tagSeverity(event: any) { + switch(event.type) { + case this.patronTransactionEventType.FEE: + return 'danger'; + case this.patronTransactionEventType.PAYMENT: + return 'success'; + case this.patronTransactionEventType.CANCEL: + return 'info'; + } + } + + hideShowEye(event: string): boolean { + return document.getElementById(event).hidden; + } + + hideShowEvent(event: string): void { + const element = document.getElementById(event); + element.hidden = !element.hidden; + } } diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.html b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.html index 65cb5f2ff..9bd8ce93a 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.html +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.html @@ -1,6 +1,6 @@
- - + + - Engaged fees - @if (statistics()['fees'] > 0) { - - {{ statistics()['fees'] | currency: organisation.default_currency }} - - } +
+
Engaged fees
+ @if (statistics()['fees_engaged'] > 0) { + + {{ statistics()['fees_engaged'] | currency: organisation.default_currency }} + + } +
- +
@if (tabs.engagedFees.transactions.length > 0) { -
-
Date
-
Category
+
diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.scss b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.scss deleted file mode 100644 index 98691563d..000000000 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.scss +++ /dev/null @@ -1,81 +0,0 @@ -/* - * RERO ILS UI - * Copyright (C) 2021 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 - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -@import 'bootstrap/scss/functions'; -@import 'bootstrap/scss/variables'; -@import '../../../scss/variables'; - -.vertical-tabs-panes{ - min-height: 400px; - margin: map_get($spacers, 3); - - .tabs-list{ - - padding: 0; - border-right: 1px solid $border-color; - - ul { - list-style: none; - padding: 0; - margin: 0; - - li{ - padding: map-get($spacers, 1); - border-bottom: 1px solid $border-color; - border-right: 1px solid $border-color; - margin-right: -1px; - - .btn { - text-align: left; - strong { - text-transform: uppercase; - font-size: 0.75rem; - } - .float-right{ - margin-top: map-get($spacers, 1); - } - .badge{ - font-weight: normal !important; - } - .badge-secondary.badge-opacity-30{ - background-color: rgba($secondary, .3); - } - &:focus{ - box-shadow: none; - } - &:hover{ - text-decoration: none; - color: $link-color; - } - } - - &.open-tab { - background-color: white; - border-right-color: white; - } - &:not(.open-tab):hover { - background-color: #DDD; - } - } - - } - } - - .tabs-content { - padding: map_get($spacers, 2) map-get($spacers, 4); - } -} diff --git a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.ts b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.ts index a533320c6..dd297cd8e 100644 --- a/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.ts +++ b/projects/admin/src/app/circulation/patron/patron-transactions/patron-transactions.component.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2021-2024 RERO + * Copyright (C) 2021-2025 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 @@ -24,17 +24,16 @@ import { TranslateService } from '@ngx-translate/core'; import { UserService } from '@rero/shared'; import { MenuItem } from 'primeng/api'; import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { TabViewChangeEvent } from 'primeng/tabview'; import { Subscription } from 'rxjs'; import { CirculationService } from '../../services/circulation.service'; import { PatronTransactionService } from '../../services/patron-transaction.service'; import { PatronFeeComponent } from './patron-fee/patron-fee.component'; import { PatronTransactionEventFormComponent } from './patron-transaction-event-form/patron-transaction-event-form.component'; +import { AccordionTabOpenEvent } from 'primeng/accordion'; @Component({ selector: 'admin-patron-transactions', - templateUrl: './patron-transactions.component.html', - styleUrls: ['./patron-transactions.component.scss'] + templateUrl: './patron-transactions.component.html' }) export class PatronTransactionsComponent implements OnInit, OnDestroy { @@ -138,8 +137,9 @@ export class PatronTransactionsComponent implements OnInit, OnDestroy { ]; } - tabChange(event: TabViewChangeEvent) { - if (event.index !== 0) { + accordionOpen(event: AccordionTabOpenEvent): void { + // 2 = Transaction history + if (event.index === 2) { this.loadFeesHistory(); } } 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 9a2265f31..e3b570caf 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 @@ -15,45 +15,50 @@ along with this program. If not, see . --> @if (item && document) { - - -
- @if (document.title | mainTitle; as title) { - - {{ title }} - - @if (item.enumerationAndChronology) { - {{ item.enumerationAndChronology }} +
+ +
+
+
+ +
+ +
+
+
+ @if (document.title | mainTitle; as title) { + + {{ title }} + + @if (item.enumerationAndChronology) { + + } +
} -
- } - -
-
{{ loan.created | dateTranslate: 'short' }}
-
-
-
- -
- - @if (!isCollapsed) { -
-
- -
Position
-
- -
- - @if (item.location.pid | getRecord: 'locations' | async; as location) { -
Location
-
- {{ $any(location).metadata.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}: {{ item.location.name }} + + + @if (!isCollapsed) { + + + @if (item.location.pid | getRecord: 'locations' | async; as location) { +
Location
+
+ {{ $any(location).metadata.library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}: {{ item.location.name }} +
+ } +
+ }
- } +
{{ loan.created | dateTranslate: 'short' }}
+
+ +
+
} 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 eba34eaff..fbb1fd5d1 100644 --- a/projects/admin/src/app/circulation/patron/pending/pending.component.html +++ b/projects/admin/src/app/circulation/patron/pending/pending.component.html @@ -14,28 +14,34 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -
- @if (loans && loans.length > 0) { -
- -
-
Item
-
Title
-
Request date
-
Expected availability
-
 
+@defer(when loans) { + + + - @for (loan of loans; track loan) { -
+ + @if (loans.length > 0) { +
+ @for (loan of loans; track loan) { -
- } -
- } @else { - {{ 'No items' | translate }} - } -
+ } +
+ } @else { +
+ No items +
+ } + +} @placeholder { +
Loading in progress
+} + 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 18ca2ca79..8337eb89c 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-2024 RERO + * Copyright (C) 2020-2025 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, inject, OnInit } from '@angular/core'; import { PatronService } from '../../../service/patron.service'; +import { CirculationStatistics } from '../../circulationStatistics'; import { CirculationService } from '../../services/circulation.service'; @Component({ @@ -54,7 +55,6 @@ export class PendingComponent implements OnInit { const index = this.loans.findIndex((element: any) => element.id == loanId); this.loans.splice(index, 1); // Update count on tab - this.circulationService.statisticsDecrease('pending', 1); - //this.circulationService.circulationInformations.statistics['pending'] -= 1; + this.circulationService.statisticsDecrease(CirculationStatistics.PENDING, 1); } } diff --git a/projects/admin/src/app/circulation/patron/pickup/pickup-item/pickup-item.component.html b/projects/admin/src/app/circulation/patron/pickup/pickup-item/pickup-item.component.html index 5a923f076..8f7e77451 100644 --- a/projects/admin/src/app/circulation/patron/pickup/pickup-item/pickup-item.component.html +++ b/projects/admin/src/app/circulation/patron/pickup/pickup-item/pickup-item.component.html @@ -14,32 +14,34 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -@if (item && loan) { - -
- @if (document.title | mainTitle; as title) { - - {{ title }} - - @if (item.enumerationAndChronology) { - {{ item.enumerationAndChronology }} - }
- } - -
-
- {{ loan.metadata.pickup_location_pid | getRecord: 'locations' : 'field' : 'pickup_name' | async }} -
-
- @if (loan.metadata.request_expire_date) { - {{ loan.metadata.request_expire_date | dateTranslate:'shortDate' }} - } @else { - {{ 'Unknown' | translate }} - } -
-
- +@if (item) { +
+ +
+ @if (document.title | mainTitle; as title) { + + {{ title }} + + @if (item.enumerationAndChronology) { + + }
+ } + +
+
+ {{ loan.metadata.pickup_location_pid | getRecord: 'locations' : 'field' : 'pickup_name' | async }} +
+
+ @if (loan.metadata.request_expire_date) { + {{ loan.metadata.request_expire_date | dateTranslate:'shortDate' }} + } @else { + {{ 'Unknown' | translate }} + } +
+
+ +
} diff --git a/projects/admin/src/app/circulation/patron/pickup/pickup.component.html b/projects/admin/src/app/circulation/patron/pickup/pickup.component.html index 8949f7df8..890c2051b 100644 --- a/projects/admin/src/app/circulation/patron/pickup/pickup.component.html +++ b/projects/admin/src/app/circulation/patron/pickup/pickup.component.html @@ -14,26 +14,34 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -
- @if (loans && loans.length > 0) { -
- -
-
Item
-
Title
-
Pickup location
-
To pick-up until
-
 
+@defer(when loans) { + + + - @for (loan of loans; track loan) { - - } -
- } @else { - {{ 'No items' | translate }} - } -
+ + @if (loans.length > 0) { +
+ @for (loan of loans; track loan) { + + } +
+ } @else { +
+ No items +
+ } + +} @placeholder { +
Loading in progress
+} diff --git a/projects/admin/src/app/circulation/patron/pickup/pickup.component.ts b/projects/admin/src/app/circulation/patron/pickup/pickup.component.ts index fd254e435..8a7f42605 100644 --- a/projects/admin/src/app/circulation/patron/pickup/pickup.component.ts +++ b/projects/admin/src/app/circulation/patron/pickup/pickup.component.ts @@ -17,6 +17,7 @@ import { Component, inject, OnInit } from '@angular/core'; import { PatronService } from '../../../service/patron.service'; +import { CirculationStatistics } from '../../circulationStatistics'; import { CirculationService } from '../../services/circulation.service'; @Component({ @@ -52,6 +53,6 @@ export class PickupComponent implements OnInit { const index = this.loans.findIndex((element: any) => element.id == loanId); this.loans.splice(index, 1); // Update count on tab - this.circulationService.statisticsDecrease('pickup', 1); + this.circulationService.statisticsDecrease(CirculationStatistics.PICKUP, 1); } } diff --git a/projects/admin/src/app/circulation/patron/profile/profile.component.html b/projects/admin/src/app/circulation/patron/profile/profile.component.html index 3825e4f1c..5a5262ff3 100644 --- a/projects/admin/src/app/circulation/patron/profile/profile.component.html +++ b/projects/admin/src/app/circulation/patron/profile/profile.component.html @@ -1,6 +1,6 @@ -@if (currentPatron$ | async; as patron) { -
-
- -
-
Username
-
- {{ $any(patron).username }} -
-
- -
-
Street
-
- {{ $any(patron).street }} -
-
- -
-
City
-
- {{ $any(patron).postal_code }} {{ $any(patron).city }} +@defer(when patron) { + + + @if ($any(patron).second_address) { +

Second address

+ - - @if ($any(patron).country) { -
-
Country
-
- {{ 'country_' + $any(patron).country | translate }} -
-
- } - - @if ($any(patron).home_phone) { -
-
Home phone number
-
- {{ $any(patron).home_phone }} -
-
- } - @if ($any(patron).business_phone) { -
-
Business phone number
-
- {{ $any(patron).business_phone }} -
-
- } - @if ($any(patron).mobile_phone) { -
-
Mobile phone
-
- {{ $any(patron).mobile_phone }} -
-
- } - @if ($any(patron).other_phone) { -
-
Other phone
-
- {{ $any(patron).other_phone }} -
-
- } - - @if ($any(patron).email) { -
-
Email
-
- {{ $any(patron).email }} -
-
} - - @if ($any(patron).source) { -
-
Source
-
- {{ $any(patron).source }} -
-
- } - - @if ($any(patron).local_code) { -
-
Local code
-
- {{ $any(patron).local_code }} -
-
+ @if ($any(patron).second_address.postal_code || $any(patron).second_address.city) { +
City
+
+ @if ($any(patron).second_address.postal_code) { + {{ $any(patron).second_address.postal_code }} + } + @if ($any(patron).second_address.city) { + {{ $any(patron).second_address.city }} + } +
} - -
-
Keep history
-
- + @if ($any(patron).second_address.country) { +
Country
+
+ {{ 'country_' + $any(patron).second_address.country | translate }}
-
- @if (canUpdate()) { - } -
+
+ } - @if ($any(patron).second_address) { -
-
Second address
- - @if ($any(patron).second_address.street) { -
-
Street
-
- {{ $any(patron).second_address.street }} -
-
- } - - @if ($any(patron).second_address.postal_code || $any(patron).second_address.city) { -
-
City
-
- @if ($any(patron).second_address.postal_code) { - {{ $any(patron).second_address.postal_code }} - } - @if ($any(patron).second_address.city) { - {{ $any(patron).second_address.city }} - } -
-
- } - - @if ($any(patron).second_address.country) { -
-
Country
-
- {{ 'country_' + $any(patron).second_address.country | translate }} -
-
+ @if ($any(patron).isLibrarian) { +

Librarian Information

+ + } + @if ($any(patron).patron) { +

Patron Information

+
- } - - @if ($any(patron).isLibrarian) { -
-
Librarian Information
- -
-
- Library -
-
- {{ $any(patron).library.pid | getRecord: 'libraries' : 'field' : 'name' | async }} -
-
-
- } - @if ($any(patron).patron) { -
-
Patron Information
- -
-
- - Role - Role - Roles - -
-
- @for (role of $any(patron).roles; track role; let last=$last) { - {{ role | translate }}{{ last ? '' : ', ' }} +
+
Patron's barcodes or cards number
+
+ + {{ $any(patron).patron.barcode | join: ', '}} + +
+
Type
+
+ {{ $any(patron).patron.type.pid | getRecord: 'patron_types' : 'field' : 'name' | async }} +
+
Account expiration
+
+ {{ $any(patron).patron.expiration_date | dateTranslate:'mediumDate' }} +
+ @if ($any(patron).libraries && $any(patron).libraries.length > 0) { +
Affiliation libraries
+
+
    + @for (library of $any(patron).libraries; track library) { +
  • {{ library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}
  • } -
-
- -
-
Patron's barcodes or cards number
-
- - {{ $any(patron).patron.barcode | join: ', '}} - -
-
- -
-
Type
-
- {{ $any(patron).patron.type.pid | getRecord: 'patron_types' : 'field' : 'name' | async }} -
-
- -
-
Account expiration
-
- {{ $any(patron).patron.expiration_date | dateTranslate:'mediumDate' }} -
-
- @if ($any(patron).libraries && $any(patron).libraries.length > 0) { -
-
Affiliation libraries
-
-
    - @for (library of $any(patron).libraries; track library) { -
  • {{ library.pid | getRecord: 'libraries' : 'field' : 'name' | async }}
  • - } -
-
-
- } -
- } + + + } + + } - @if (canUpdate()) { + @if (canUpdate()) { +
+ - } - - +
+ } +} @placeholder { +
Loading in progress
} diff --git a/projects/admin/src/app/circulation/patron/profile/profile.component.ts b/projects/admin/src/app/circulation/patron/profile/profile.component.ts index 7f035d573..09833b83c 100644 --- a/projects/admin/src/app/circulation/patron/profile/profile.component.ts +++ b/projects/admin/src/app/circulation/patron/profile/profile.component.ts @@ -34,7 +34,7 @@ export class ProfileComponent implements OnInit, OnDestroy { private translateService: TranslateService = inject(TranslateService); /** Current patron */ - currentPatron$: any; + patron: any; /** Observable subscription */ private subscription = new Subscription(); @@ -42,12 +42,9 @@ export class ProfileComponent implements OnInit, OnDestroy { /** Patron permission */ private permissions: any; - /** - * Component initialization. - */ ngOnInit() { - this.currentPatron$ = this.patronService.currentPatron$; - this.subscription = this.currentPatron$.subscribe((patron: any) => { + this.subscription = this.patronService.currentPatron$.subscribe((patron: any) => { + this.patron = patron; if (patron && patron.pid) { this.recordPermission.getPermission('patrons', patron.pid).subscribe( perm => { @@ -80,6 +77,8 @@ export class ProfileComponent implements OnInit, OnDestroy { updatePatronPassword(patron) { this.dialogService.open(ChangePasswordFormComponent, { header: this.translateService.instant('Update Patron Password'), + width: '30vw', + dismissableMask: true, data: { patron } diff --git a/projects/admin/src/app/circulation/services/circulation.service.ts b/projects/admin/src/app/circulation/services/circulation.service.ts index 7d9653f86..d8325c43b 100644 --- a/projects/admin/src/app/circulation/services/circulation.service.ts +++ b/projects/admin/src/app/circulation/services/circulation.service.ts @@ -21,7 +21,7 @@ import { Injectable, signal, WritableSignal } from '@angular/core'; }) export class CirculationService { - messages: WritableSignal<{type: string, content: string}[]> = signal([]); + messages: WritableSignal<{severity: string, detail: string}[]> = signal([]); statistics: WritableSignal<{[key: string]: number}> = signal({}); statisticsIncrease(type: string, increment: number = 1): void { @@ -45,7 +45,7 @@ export class CirculationService { this.statistics.set(stats); } - addCirculationMessage(message: {type: string, content: string}): void { + addCirculationMessage(message: {severity: string, detail: string}): void { this.messages.set([...this.messages(), message]); } diff --git a/projects/admin/src/app/circulation/services/patron-transaction.service.ts b/projects/admin/src/app/circulation/services/patron-transaction.service.ts index 935aa385c..a51893330 100644 --- a/projects/admin/src/app/circulation/services/patron-transaction.service.ts +++ b/projects/admin/src/app/circulation/services/patron-transaction.service.ts @@ -1,6 +1,6 @@ /* * RERO ILS UI - * Copyright (C) 2020-2024 RERO + * Copyright (C) 2020 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 @@ -28,7 +28,6 @@ import { UserService } from '@rero/shared'; import { MessageService } from 'primeng/api'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { map } from 'rxjs/operators'; -import { CirculationService } from './circulation.service'; @Injectable({ providedIn: 'root' @@ -39,11 +38,12 @@ export class PatronTransactionService { private userService: UserService = inject(UserService); private routeToolService: RouteToolService = inject(RouteToolService); private translateService: TranslateService = inject(TranslateService); - private messageService = inject(MessageService); - private circulationService: CirculationService = inject(CirculationService); + private messageService: MessageService = inject(MessageService); /** subject containing current loaded PatronTransactions */ patronTransactionsSubject$: BehaviorSubject> = new BehaviorSubject([]); + /** subject emitting accounting transaction about patron fees */ + patronFeesOperationSubject$: Subject = new Subject(); /** * Allow to build the query to send through the API to retrieve desired data @@ -89,7 +89,7 @@ export class PatronTransactionService { ).pipe( map((data: Record) => data.hits), map(hits => this.recordService.totalHits(hits.total) === 0 ? [] : hits.hits), - map(hits => hits.map(hit => new PatronTransaction(hit.metadata))) + map(hits => hits.map( hit => new PatronTransaction(hit.metadata))) ); } @@ -105,7 +105,7 @@ export class PatronTransactionService { return this.recordService.getRecords('patron_transactions', query, 1, RecordService.MAX_REST_RESULTS_SIZE).pipe( map((data: Record) => data.hits), map(hits => this.recordService.totalHits(hits.total) === 0 ? [] : hits.hits), - map(hits => hits.map( hit => new PatronTransaction(hit.metadata))) + map(hits => hits.map(hit => new PatronTransaction(hit.metadata))) ); } @@ -195,7 +195,8 @@ export class PatronTransactionService { record.type = PatronTransactionEventType.PAYMENT; record.subtype = paymentMethod; record.amount = amount; - this._createTransactionEvent(record, transaction.patron.pid, amount); + this.patronFeesOperationSubject$.next(0 - amount); + this._createTransactionEvent(record, transaction.patron.pid); } /** @@ -221,7 +222,8 @@ export class PatronTransactionService { record.type = PatronTransactionEventType.CANCEL; record.amount = amount; record.note = reason; - this._createTransactionEvent(record, transaction.patron.pid, amount); + this.patronFeesOperationSubject$.next(0 - amount); + this._createTransactionEvent(record, transaction.patron.pid); } /** @@ -229,12 +231,11 @@ export class PatronTransactionService { * @param record - data to send through the API * @param affectedPatron - the user pid affected by this new transaction event */ - private _createTransactionEvent(record: any, affectedPatron: string, amount: number = 0) { - const translateType = this.translateService.instant(record.type); + private _createTransactionEvent(record: any, affectedPatron: string) { this.recordService.create('patron_transaction_events', record).subscribe({ next: () => { - this.circulationService.statisticsDecrease('fees', amount); this.emitPatronTransactionByPatron(affectedPatron, undefined, 'open'); + const translateType = this.translateService.instant(record.type); this.messageService.add({ severity: 'success', summary: this.translateService.instant('Patron'), @@ -247,6 +248,7 @@ export class PatronTransactionService { ? error.message.message : 'Server error :: ' + (error.title || error.toString()); const message = '[' + error.status + ' - ' + error.statusText + '] ' + errorMessage; + const translateType = this.translateService.instant(record.type); this.messageService.add({ severity: 'error', summary: this.translateService.instant('{{ type }} creation failed!', { type: translateType }), @@ -255,6 +257,6 @@ export class PatronTransactionService { closable: true }); } - }); + }); } } diff --git a/projects/admin/src/app/record/detail-view/document-detail-view/item-request/item-request.component.ts b/projects/admin/src/app/record/detail-view/document-detail-view/item-request/item-request.component.ts index a4031a085..8d9d8f596 100644 --- a/projects/admin/src/app/record/detail-view/document-detail-view/item-request/item-request.component.ts +++ b/projects/admin/src/app/record/detail-view/document-detail-view/item-request/item-request.component.ts @@ -212,6 +212,7 @@ export class ItemRequestComponent implements OnInit { key: 'pickupPid', type: 'select', props: { + appendTo: 'body', label: this.translateService.instant('Pickup location'), required: true, placeholder: this.translateService.instant('Select…'), diff --git a/projects/admin/src/app/scss/styles.scss b/projects/admin/src/app/scss/styles.scss index 265c47084..63228ad3b 100644 --- a/projects/admin/src/app/scss/styles.scss +++ b/projects/admin/src/app/scss/styles.scss @@ -41,6 +41,7 @@ @import '../record/detail-view/entities-detail-view/remote/entities-remote-detail-view.component.scss'; @import '../record/detail-view/permission-detail-view/permission-detail-view.component.scss'; @import '../migration/conversion/record/detail-view/migration-data/migration-data.component.scss'; + @import '../circulation/patron/card/card.component.scss'; } @layer rero-ils-ui { @@ -59,3 +60,7 @@ background: transparent; } } + +ng-core-editor-field-password-generator { + @extend .w-full; +} diff --git a/projects/admin/src/app/service/loan.service.ts b/projects/admin/src/app/service/loan.service.ts index 8993720f1..8d3899537 100644 --- a/projects/admin/src/app/service/loan.service.ts +++ b/projects/admin/src/app/service/loan.service.ts @@ -152,11 +152,11 @@ export class LoanService { cancelRequestDialog(event: Event, accept?: Function, reject?: Function): void { const confirmation: Confirmation = { target: event.target as EventTarget, + icon: 'fa fa-exclamation-triangle', header: this.translateService.instant('Cancel request'), message: this.translateService.instant('Do you really want to cancel the request?'), acceptLabel: this.translateService.instant('Yes'), - rejectLabel: this.translateService.instant('No'), - dismissableMask: true, + rejectLabel: this.translateService.instant('No') }; if (accept) { confirmation.accept = accept; diff --git a/projects/shared/src/scss/styles.scss b/projects/shared/src/scss/styles.scss index ff7fd8a88..e73232ad2 100644 --- a/projects/shared/src/scss/styles.scss +++ b/projects/shared/src/scss/styles.scss @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +@import "node_modules/@rero/ng-core/assets/scss/variables"; @import "node_modules/@rero/ng-core/assets/scss/ng-core"; @import "../lib/component/documents/files/files.component.scss"; @import "../lib/view/contribution/contribution.component.scss";