From 65ec045dd35639db0da2316fb4085d885de93cba Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 26 Jan 2021 13:26:35 -0500 Subject: [PATCH] LP1929741 View/Place Orders UI View/Place orders from a bib record and add/create selection lists or PO's from the record. Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton Signed-off-by: Jane Sandberg --- .../acq/lineitem/lineitem-list.component.html | 13 +- .../staff/acq/lineitem/lineitem-list.component.ts | 14 +- .../app/staff/acq/related/related.component.html | 68 +++++++++ .../src/app/staff/acq/related/related.component.ts | 166 +++++++++++++++++++++ .../src/app/staff/acq/related/related.module.ts | 24 +++ .../src/app/staff/acq/related/routing.module.ts | 41 +++++ .../src/eg2/src/app/staff/acq/routing.module.ts | 4 + .../staff/catalog/record/actions.component.html | 5 + .../lib/OpenILS/Application/Acq/Lineitem.pm | 20 ++- 9 files changed, 346 insertions(+), 9 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/related/related.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/related/related.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/related/related.module.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/related/routing.module.ts diff --git a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html index ce7c5e8273..db9d35b16d 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html +++ b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html @@ -2,7 +2,7 @@ -
+
@@ -62,7 +62,8 @@ -
+
@@ -130,6 +131,14 @@ + +
+
+ No items to display. +
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts index 46765a2257..883d0b9d25 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts @@ -22,6 +22,7 @@ export class LineitemListComponent implements OnInit { picklistId: number = null; poId: number = null; + recordId: number = null; // lineitems related to a bib. loading = false; pager: Pager = new Pager(); @@ -81,6 +82,7 @@ export class LineitemListComponent implements OnInit { this.route.parent.paramMap.subscribe((params: ParamMap) => { this.picklistId = +params.get('picklistId'); this.poId = +params.get('poId'); + this.recordId = +params.get('recordId'); this.load(); }); @@ -111,8 +113,8 @@ export class LineitemListComponent implements OnInit { load(): Promise { this.pageOfLineitems = []; - if (!this.loading && - this.pager.limit && (this.poId || this.picklistId)) { + if (!this.loading && this.pager.limit && + (this.poId || this.picklistId || this.recordId)) { this.loading = true; @@ -136,10 +138,18 @@ export class LineitemListComponent implements OnInit { let handler = (po) => po.lineitems(); if (this.picklistId) { + id = this.picklistId; options = {idlist: true, limit: 1000}; method = 'open-ils.acq.lineitem.picklist.retrieve.atomic'; handler = (ids) => ids; + + } else if (this.recordId) { + + id = this.recordId; + method = 'open-ils.acq.lineitems_for_bib.by_bib_id.atomic'; + options = {idlist: true, limit: 1000}; + handler = (ids) => ids; } return this.net.request( diff --git a/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.html b/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.html new file mode 100644 index 0000000000..6d7ed1f040 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + +
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+ + +
+
+
+ + + diff --git a/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.ts new file mode 100644 index 0000000000..6e91d523cf --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/related/related.component.ts @@ -0,0 +1,166 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {Router, ActivatedRoute, ParamMap} from '@angular/router'; +import {tap} from 'rxjs/operators'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {EventService} from '@eg/core/event.service'; +import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {PromptDialogComponent} from '@eg/share/dialog/prompt.component'; +import {AlertDialogComponent} from '@eg/share/dialog/alert.component'; +import {ComboboxEntry} from '@eg/share/combobox/combobox.component'; + +@Component({ + templateUrl: 'related.component.html' +}) +export class RelatedComponent implements OnInit { + + recordId: number; + addingToPl = false; + addingToPo = false; + selectedPl: ComboboxEntry; + selectedPo: ComboboxEntry; + + @ViewChild('newPlDialog') newPlDialog: PromptDialogComponent; + @ViewChild('plNameExists') plNameExists: AlertDialogComponent; + + constructor( + private router: Router, + private route: ActivatedRoute, + private idl: IdlService, + private evt: EventService, + private net: NetService, + private auth: AuthService, + private pcrud: PcrudService + ) {} + + ngOnInit() { + this.route.paramMap.subscribe((params: ParamMap) => { + this.recordId = +params.get('recordId'); + }); + } + + isBasePage(): boolean { + return !this.route.firstChild || + this.route.firstChild.snapshot.url.length === 0; + } + + // Create a new selection list + // Create and add the lineitem. + // Navigate to the new SL + createPicklist() { + + this.newPlDialog.open().toPromise() + .then(name => { + if (!name) { return; } + + return this.pcrud.search('acqpl', + {owner: this.auth.user().id(), name: name}, null, {idlist: true} + ).toPromise().then(existing => { + return {existing: existing, name: name}; + }); + + }).then(info => { + if (!info) { return; } + + if (info.existing) { + // Alert the user the requested name is already in + // use and reopen the create dialog. + this.plNameExists.open().toPromise().then(_ => this.createPicklist()); + return; + } + + const pl = this.idl.create('acqpl'); + pl.name(info.name); + pl.owner(this.auth.user().id()); + + return this.net.request( + 'open-ils.acq', + 'open-ils.acq.picklist.create', this.auth.token(), pl + ).toPromise(); + + }).then(plId => { + if (!plId) { return; } + + const evt = this.evt.parse(plId); + if (evt) { alert(evt); return; } + + this.addToPicklist(plId); + }); + } + + createLineitem(options?: any): Promise { + + return this.net.request( + 'open-ils.acq', + 'open-ils.acq.biblio.create_by_id', + this.auth.token(), [this.recordId], options + + ).pipe(tap(resp => { + + if (Number(resp) > 0) { + // The API first responds with the picklist ID. + // Avoid navigating away from this page until the API + // completes and we know the lineitem has been created. + return; + } + + const evt = this.evt.parse(resp); + if (evt) { + alert(evt); + + } else { + return resp; + } + + })).toPromise(); + } + + // Add a lineitem based on our bib record to the selected + // picklist by ID then navigate to that picklist's page. + addToPicklist(plId: number) { + if (!plId) { return; } + + this.createLineitem({reuse_picklist: plId}) + .then(li => { + if (li) { + this.router.navigate(['/staff/acq/picklist', plId]); + } + }); + } + + // Create the lineitem, then send the user to the new PO UI. + createPo() { + this.createLineitem().then(li => { + if (li) { + this.router.navigate( + ['/staff/acq/po/create'], {queryParams: {li: li.id()}}); + } + }); + } + + addToPo(poId: number) { + if (!poId) { return; } + + this.createLineitem().then(li => { + if (!li) { return null; } + + return this.net.request( + 'open-ils.acq', + 'open-ils.acq.purchase_order.add_lineitem', + this.auth.token(), poId, li.id() + + ).toPromise(); + + }).then(resp => { + if (!resp) { return; } + const evt = this.evt.parse(resp); + if (evt) { + alert(evt); + } else { + this.router.navigate(['/staff/acq/po/', poId]); + } + }); + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/acq/related/related.module.ts b/Open-ILS/src/eg2/src/app/staff/acq/related/related.module.ts new file mode 100644 index 0000000000..a02996a976 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/related/related.module.ts @@ -0,0 +1,24 @@ +import {NgModule} from '@angular/core'; +import {StaffCommonModule} from '@eg/staff/common.module'; +import {HttpClientModule} from '@angular/common/http'; +import {CatalogCommonModule} from '@eg/share/catalog/catalog-common.module'; +import {LineitemModule} from '@eg/staff/acq/lineitem/lineitem.module'; +import {HoldingsModule} from '@eg/staff/share/holdings/holdings.module'; +import {RelatedRoutingModule} from './routing.module'; +import {RelatedComponent} from './related.component'; + +@NgModule({ + declarations: [ + RelatedComponent + ], + imports: [ + StaffCommonModule, + CatalogCommonModule, + LineitemModule, + HoldingsModule, + RelatedRoutingModule + ] +}) + +export class RelatedModule { +} diff --git a/Open-ILS/src/eg2/src/app/staff/acq/related/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/acq/related/routing.module.ts new file mode 100644 index 0000000000..b4221bc862 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/related/routing.module.ts @@ -0,0 +1,41 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {LineitemListComponent} from '../lineitem/lineitem-list.component'; +import {LineitemDetailComponent} from '../lineitem/detail.component'; +import {LineitemCopiesComponent} from '../lineitem/copies.component'; +import {BriefRecordComponent} from '../lineitem/brief-record.component'; +import {LineitemHistoryComponent} from '../lineitem/history.component'; +import {LineitemWorksheetComponent} from '../lineitem/worksheet.component'; +import {RelatedComponent} from './related.component'; + +const routes: Routes = [{ + path: ':recordId', + component: RelatedComponent, + children : [{ + path: '', + component: LineitemListComponent + }, { + path: 'brief-record', + component: BriefRecordComponent + }, { + path: 'lineitem/:lineitemId/detail', + component: LineitemDetailComponent + }, { + path: 'lineitem/:lineitemId/history', + component: LineitemHistoryComponent + }, { + path: 'lineitem/:lineitemId/items', + component: LineitemCopiesComponent + }, { + path: 'lineitem/:lineitemId/worksheet', + component: LineitemWorksheetComponent + }] +}]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [] +}) + +export class RelatedRoutingModule {} diff --git a/Open-ILS/src/eg2/src/app/staff/acq/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/acq/routing.module.ts index 7848bccc2b..0c9afce86d 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/routing.module.ts @@ -16,6 +16,10 @@ const routes: Routes = [{ path: 'picklist', loadChildren: () => import('./picklist/picklist.module').then(m => m.PicklistModule) +}, { + path: 'related', + loadChildren: () => + import('./related/related.module').then(m => m.RelatedModule) }]; @NgModule({ diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html index 810a470bcd..1009410091 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html @@ -101,6 +101,11 @@ href="/eg/staff/acq/legacy/lineitem/related/{{recId}}?target=bib"> View/Place Orders +
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm index cfc2fcc635..e510286adc 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm @@ -526,11 +526,21 @@ sub lineitems_related_by_bib { return scalar(@$results); } else { for my $result (@$results) { - # retrieve_lineitem takes care of POs and PLs and also handles - # options like flesh_notes and permissions checking. - $conn->respond( - retrieve_lineitem($self, $conn, $auth, $result->{"id"}, $options) - ); + + # Let retrieve_lineitem_impl handle the permission checks + # and fleshing where needed. + my $li = retrieve_lineitem_impl($e, $result->{id}, $options) + or return $e->die_event; + + if ($options->{idlist}) { + $conn->respond($li->id); + + } else { + + # retrieve_lineitem takes care of POs and PLs and also handles + # options like flesh_notes and permissions checking. + $conn->respond($li); + } } } -- 2.11.0