From: Bill Erickson Date: Thu, 24 Sep 2020 19:39:45 +0000 (-0400) Subject: LP1888723 Item notes dialog and volcopy entry point X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=3f1563d71cca37b546e65563352db16ee06dd778;p=evergreen%2Ftadl.git LP1888723 Item notes dialog and volcopy entry point Support for adding new item notes to one or more items in the copy editor interface. Signed-off-by: Bill Erickson Signed-off-by: Ruth Frasur Signed-off-by: Galen Charlton --- diff --git a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html index 1fc031a01f..f6bb8548ac 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html +++ b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html @@ -547,6 +547,16 @@
  • + +
    +
  • +
  • +
    +
    +
    + +
    Add Item Notes
    +
    + +
    +
    +
    Stat Cat Filter
    diff --git a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts index fdd8365910..ed49aae61d 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts @@ -19,6 +19,8 @@ import {CopyAlertsDialogComponent } from '@eg/staff/share/holdings/copy-alerts-dialog.component'; import {CopyTagsDialogComponent } from '@eg/staff/share/holdings/copy-tags-dialog.component'; +import {CopyNotesDialogComponent + } from '@eg/staff/share/holdings/copy-notes-dialog.component'; import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component'; import {BatchItemAttrComponent, BatchChangeSelection } from '@eg/staff/share/holdings/batch-item-attr.component'; @@ -75,6 +77,9 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit { @ViewChild('copyTagsDialog', {static: false}) private copyTagsDialog: CopyTagsDialogComponent; + @ViewChild('copyNotesDialog', {static: false}) + private copyNotesDialog: CopyNotesDialogComponent; + @ViewChild('copyTemplateCbox', {static: false}) copyTemplateCbox: ComboboxComponent; @@ -458,6 +463,25 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit { }); } + openCopyNotes() { + this.copyNotesDialog.inPlaceMode = true; + this.copyNotesDialog.copyIds = this.context.copyList().map(c => c.id()); + + this.copyNotesDialog.open({size: 'lg'}).subscribe(newNotes => { + if (!newNotes || newNotes.length === 0) { return; } + + console.log(newNotes); + newNotes.forEach(note => { + this.context.copyList().forEach(copy => { + const n = this.idl.clone(note); + n.owning_copy(copy.id()); + copy.notes().push(n); + copy.ischanged(true); + }); + }); + }); + } + applyTemplate() { const entry = this.copyTemplateCbox.selected; if (!entry) { return; } diff --git a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts index 1864f767c7..397cc2f1b7 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts @@ -20,7 +20,7 @@ const COPY_FLESH = { flesh_fields: { acp: [ 'call_number', 'location', 'parts', 'tags', - 'creator', 'editor', 'stat_cat_entries' + 'creator', 'editor', 'stat_cat_entries', 'notes' ], acptcm: ['tag'], acpt: ['tag_type'] diff --git a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.service.ts b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.service.ts index 8f3559fc3b..85b16e4be2 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.service.ts @@ -234,6 +234,7 @@ export class VolCopyService { copy.parts([]); copy.tags([]); + copy.notes([]); copy.stat_cat_entries([]); return copy; diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts index 4c0564d8fd..c150b73dc3 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts @@ -56,7 +56,7 @@ export class BibSummaryComponent implements OnInit { .then(_ => { if (this.summary) { return this.loadCourseInformation(this.summary.record.id()) - .then(_ => this.summary.getBibCallNumber()); + .then(__ => this.summary.getBibCallNumber()); } else { if (this.recordId) { return this.loadSummary(); diff --git a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.html new file mode 100644 index 0000000000..f71b9f55ae --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.html @@ -0,0 +1,77 @@ + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.ts new file mode 100644 index 0000000000..3f9fff5214 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.ts @@ -0,0 +1,172 @@ +import {Component, OnInit, Input, ViewChild} from '@angular/core'; +import {Observable, throwError, from, empty} from 'rxjs'; +import {tap, map, switchMap} from 'rxjs/operators'; +import {NetService} from '@eg/core/net.service'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {EventService} from '@eg/core/event.service'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {AuthService} from '@eg/core/auth.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {StringComponent} from '@eg/share/string/string.component'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; + +/** + * Dialog for managing copy notes. + */ + +@Component({ + selector: 'eg-copy-notes-dialog', + templateUrl: 'copy-notes-dialog.component.html' +}) + +export class CopyNotesDialogComponent + extends DialogComponent implements OnInit { + + // If there are multiple copyIds, only new notes may be applied. + // If there is only one copyId, then notes may be applied or removed. + @Input() copyIds: number[] = []; + + mode: string; // create | manage + + // If true, no attempt is made to save the new notes to the + // database. It's assumed this takes place in the calling code. + // This is useful for creating notes for new copies. + @Input() inPlaceMode = false; + + // In 'create' mode, we may be adding notes to multiple copies. + copies: IdlObject[] = []; + + // In 'manage' mode we only handle a single copy. + copy: IdlObject; + + curNote: string; + curNoteTitle: string; + curNotePublic = false; + newNotes: IdlObject[] = []; + delNotes: IdlObject[] = []; + + autoId = -1; + + @ViewChild('successMsg', { static: true }) private successMsg: StringComponent; + @ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent; + + constructor( + private modal: NgbModal, // required for passing to parent + private toast: ToastService, + private net: NetService, + private idl: IdlService, + private pcrud: PcrudService, + private org: OrgService, + private auth: AuthService) { + super(modal); // required for subclassing + } + + ngOnInit() { + } + + /** + */ + open(args: NgbModalOptions): Observable { + this.copy = null; + this.copies = []; + this.newNotes = []; + + if (this.copyIds.length === 0 && !this.inPlaceMode) { + return throwError('copy ID required'); + } + + // In manage mode, we can only manage a single copy. + // But in create mode, we can add notes to multiple copies. + + if (this.copyIds.length === 1 && !this.inPlaceMode) { + this.mode = 'manage'; + } else { + this.mode = 'create'; + } + + // Observify data loading + const obs = from(this.getCopies()); + + // Return open() observable to caller + return obs.pipe(switchMap(_ => super.open(args))); + } + + getCopies(): Promise { + if (this.inPlaceMode) { return Promise.resolve(); } + + return this.pcrud.search('acp', {id: this.copyIds}, + {flesh: 1, flesh_fields: {acp: ['notes']}}, + {atomic: true} + ) + .toPromise().then(copies => { + this.copies = copies; + if (copies.length === 1) { + this.copy = copies[0]; + } + }); + } + + removeNote(note: IdlObject) { + this.newNotes = this.newNotes.filter(t => t.id() !== note.id()); + + if (note.isnew() || this.mode === 'create') { return; } + + const existing = this.copy.notes().filter(n => n.id() === note.id())[0]; + if (!existing) { return; } + + existing.isdeleted(true); + this.delNotes.push(existing); + + // Remove from copy for dialog display + this.copy.notes(this.copy.notes().filter(n => n.id() !== note.id())); + } + + addNew() { + if (!this.curNoteTitle || !this.curNote) { return; } + + const note = this.idl.create('acpn'); + note.isnew(true); + note.creator(this.auth.user().id()); + note.pub(this.curNotePublic ? 't' : 'f'); + note.title(this.curNoteTitle); + note.value(this.curNote); + note.id(this.autoId--); + + this.newNotes.push(note); + + this.curNote = ''; + this.curNoteTitle = ''; + this.curNotePublic = false; + } + + applyChanges() { + + if (this.inPlaceMode) { + this.close(this.newNotes); + return; + } + + const notes = []; + this.newNotes.forEach(note => { + this.copies.forEach(copy => { + const n = this.idl.clone(note); + n.id(null); // remove temp ID, it will be duped + n.owning_copy(copy.id()); + notes.push(n); + }); + }); + + this.pcrud.create(notes).toPromise() + .then(_ => { + if (this.delNotes.length) { + return this.pcrud.remove(this.delNotes).toPromise(); + } + }).then(_ => { + this.successMsg.current().then(msg => this.toast.success(msg)); + this.close(this.newNotes.length > 0 || this.delNotes.length > 0); + }); + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/share/holdings/holdings.module.ts b/Open-ILS/src/eg2/src/app/staff/share/holdings/holdings.module.ts index b84a4abacc..d8272ba3cf 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holdings/holdings.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/holdings/holdings.module.ts @@ -5,6 +5,7 @@ import {MarkDamagedDialogComponent} from './mark-damaged-dialog.component'; import {MarkMissingDialogComponent} from './mark-missing-dialog.component'; import {CopyAlertsDialogComponent} from './copy-alerts-dialog.component'; import {CopyTagsDialogComponent} from './copy-tags-dialog.component'; +import {CopyNotesDialogComponent} from './copy-notes-dialog.component'; import {ReplaceBarcodeDialogComponent} from './replace-barcode-dialog.component'; import {DeleteHoldingDialogComponent} from './delete-volcopy-dialog.component'; import {ConjoinedItemsDialogComponent} from './conjoined-items-dialog.component'; @@ -18,6 +19,7 @@ import {BatchItemAttrComponent} from './batch-item-attr.component'; MarkMissingDialogComponent, CopyAlertsDialogComponent, CopyTagsDialogComponent, + CopyNotesDialogComponent, ReplaceBarcodeDialogComponent, DeleteHoldingDialogComponent, ConjoinedItemsDialogComponent, @@ -33,6 +35,7 @@ import {BatchItemAttrComponent} from './batch-item-attr.component'; MarkMissingDialogComponent, CopyAlertsDialogComponent, CopyTagsDialogComponent, + CopyNotesDialogComponent, ReplaceBarcodeDialogComponent, DeleteHoldingDialogComponent, ConjoinedItemsDialogComponent,