From 2858d0649b50b86549488d78b582df0b3a54c766 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 29 Mar 2021 12:31:20 -0400 Subject: [PATCH] LP1904036 Dupe searches wip Signed-off-by: Bill Erickson Signed-off-by: Jane Sandberg Signed-off-by: Galen Charlton --- .../app/staff/circ/patron/barcodes.component.html | 3 +- .../app/staff/circ/patron/barcodes.component.ts | 19 +++-- .../staff/circ/patron/edit-toolbar.component.html | 18 +++++ .../staff/circ/patron/edit-toolbar.component.ts | 49 +++++++++++++ .../src/app/staff/circ/patron/edit.component.ts | 83 +++++++++++++++++++++- .../app/staff/circ/patron/patron.component.html | 3 +- 6 files changed, 164 insertions(+), 11 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.html index aa0cf1ed8f..dd838031d4 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.html @@ -20,12 +20,13 @@ {{card.barcode()}}
-
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.ts index b252284ee6..913e760603 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/barcodes.component.ts @@ -1,5 +1,5 @@ import {Component, OnInit, Input, ViewChild} from '@angular/core'; -import {Observable, empty} from 'rxjs'; +import {Observable, from, empty} from 'rxjs'; import {switchMap, tap} from 'rxjs/operators'; import {IdlObject, IdlService} from '@eg/core/idl.service'; import {NetService} from '@eg/core/net.service'; @@ -12,6 +12,9 @@ import {DialogComponent} from '@eg/share/dialog/dialog.component'; import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; import {StringComponent} from '@eg/share/string/string.component'; import {PatronContextService} from './patron.service'; +import {PermService} from '@eg/core/perm.service'; + +const PERMS = ['UPDATE_PATRON_ACTIVE_CARD', 'UPDATE_PATRON_PRIMARY_CARD']; /* Add/Remove Secondary Groups */ @@ -25,6 +28,7 @@ export class PatronBarcodesDialogComponent @Input() patron: IdlObject; primaryCard: number; + myPerms: {[name: string]: boolean} = {}; constructor( private modal: NgbModal, @@ -35,17 +39,13 @@ export class PatronBarcodesDialogComponent private pcrud: PcrudService, private org: OrgService, private auth: AuthService, + private perms: PermService, private context: PatronContextService ) { super(modal); } ngOnInit() { } - /* todo check perms - 'UPDATE_PATRON_ACTIVE_CARD', - 'UPDATE_PATRON_PRIMARY_CARD' - */ - open(ops: NgbModalOptions): Observable { this.patron.cards().some(card => { if (card.id() === this.patron.card().id()) { @@ -53,6 +53,13 @@ export class PatronBarcodesDialogComponent return true; } }); + + this.perms.hasWorkPermAt(PERMS, true).then(perms => { + PERMS.forEach(p => { + this.myPerms[p] = perms[p].includes(this.patron.home_ou()); + }); + }) + return super.open(ops); } diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.html index 1655dd82e0..5af7748763 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.html @@ -24,3 +24,21 @@ + +
+
+
+
+ {{dupe.count}} patron(s) with same + + phone + email + name + identifier + address + +
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.ts index 0569ce39f4..32a3329f44 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit-toolbar.component.ts @@ -3,8 +3,10 @@ import {Router, ActivatedRoute, ParamMap} from '@angular/router'; import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap'; import {OrgService} from '@eg/core/org.service'; import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; import {PatronService} from '@eg/staff/share/patron/patron.service'; import {PatronContextService} from './patron.service'; +import {PatronSearchFieldSet} from '@eg/staff/share/patron/search.component'; export enum VisibilityLevel { ALL_FIELDS = 0, @@ -12,12 +14,22 @@ export enum VisibilityLevel { REQUIRED_FIELDS = 2 } +type SearchCategory = 'name' | 'email' | 'phone' | 'ident' | 'address'; + +interface DupeSearch { + category: SearchCategory; + count: number; + search: PatronSearchFieldSet; +} + @Component({ templateUrl: 'edit-toolbar.component.html', selector: 'eg-patron-edit-toolbar' }) export class EditToolbarComponent implements OnInit { + @Input() patronId: number; + disableSave = false; visibilityLevel: VisibilityLevel = VisibilityLevel.ALL_FIELDS; @@ -27,9 +39,12 @@ export class EditToolbarComponent implements OnInit { saveCloneClicked: EventEmitter = new EventEmitter(); printClicked: EventEmitter = new EventEmitter(); + dupeSearches: DupeSearch[] = []; + constructor( private org: OrgService, private net: NetService, + private auth: AuthService, private patronService: PatronService, public context: PatronContextService ) {} @@ -42,5 +57,39 @@ export class EditToolbarComponent implements OnInit { changeFields(v: VisibilityLevel) { this.visibilityLevel = v; } + + checkDupes(category: string, search: PatronSearchFieldSet) { + + this.net.request( + 'open-ils.actor', + 'open-ils.actor.patron.search.advanced', + this.auth.token(), + search, + 1000, // limit + null, // sort + true // as id + ).subscribe(ids => { + ids = ids.filter(id => Number(id) !== this.patronId); + const count = ids.length; + + if (count > 0) { + const existing = + this.dupeSearches.filter(s => s.category === category)[0]; + if (existing) { + existing.search = search; + existing.count = count; + } else { + this.dupeSearches.push({ + category: category as SearchCategory, + search: search, + count: count + }); + } + } else { + this.dupeSearches = + this.dupeSearches.filter(s => s.category !== category); + } + }); + } } diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts index afa4d6a205..50553da4d3 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts @@ -19,6 +19,7 @@ import {PermService} from '@eg/core/perm.service'; import {SecondaryGroupsDialogComponent} from './secondary-groups.component'; import {ServerStoreService} from '@eg/core/server-store.service'; import {EditToolbarComponent, VisibilityLevel} from './edit-toolbar.component'; +import {PatronSearchFieldSet} from '@eg/staff/share/patron/search.component'; const COMMON_USER_SETTING_TYPES = [ 'circ.holds_behind_desk', @@ -247,10 +248,13 @@ export class EditComponent implements OnInit, AfterViewInit { 'open-ils.actor.user.get_groups', this.auth.token(), this.patronId - ).pipe(concatMap(maps => this.pcrud.search('pgt', - {id: maps.map(m => m.grp())}, {}, {atomic: true}) + ).pipe(concatMap(maps => { + if (maps.length === 0) { return []; } - )).pipe(tap(grps => this.secondaryGroups = grps)).toPromise(); + return this.pcrud.search('pgt', + {id: maps.map(m => m.grp())}, {}, {atomic: true}); + + })).pipe(tap(grps => this.secondaryGroups = grps)).toPromise(); } setIdentTypes(): Promise { @@ -508,14 +512,87 @@ export class EditComponent implements OnInit, AfterViewInit { switch (field) { // TODO: do many more + // open-ils.actor.barcode.exists / ditto username case 'profile': this.setExpireDate(); break; + + case 'day_phone': + // TODO: patron.password.use_phone + // TODO: hold related contact info + this.dupeValueChange(field, value); + break; + + case 'evening_phone': + case 'other_phone': + // TODO hold related contact info + this.dupeValueChange(field, value); + break; + + case 'ident_value': + case 'ident_value2': + case 'first_given_name': + case 'family_name': + case 'email': + this.dupeValueChange(field, value); + break; + + case 'street1': + case 'street2': + case 'city': + // dupe search on address wants the address object as the value. + this.dupeValueChange('address', obj); + // TODO address_alert(obj); + break; } + this.adjustSaveSate(); } + dupeValueChange(name: string, value: any) { + + if (name.match(/phone/)) { name = 'phone'; } + if (name.match(/name/)) { name = 'name'; } + if (name.match(/ident/)) { name = 'ident'; } + + let search: PatronSearchFieldSet; + switch (name) { + + case 'name': + const fname = this.patron.first_given_name(); + const lname = this.patron.family_name(); + search = { + first_given_name : {value : fname, group : 0}, + family_name : {value : lname, group : 0} + }; + break; + + case 'email': + search = {email : {value : value, group : 0}}; + break; + + case 'ident': + search = {ident : {value : value, group : 2}}; + break; + + case 'phone': + search = {phone : {value : value, group : 2}}; + break; + + case 'address': + search = {}; + ['street1', 'street2', 'city', 'post_code'].forEach(field => { + if (value[field]()) { + search[field] = {value : value[field](), group: 1}; + } + }); + break; + } + + this.toolbar.checkDupes(name, search); + } + showField(field: string): boolean { if (this.fieldVisibility[field] === undefined) { diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html index c67b31e524..e21324aadc 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html @@ -191,7 +191,8 @@ - + + -- 2.11.0