<!-- BATCH ACTIONS -->
<eg-acq-cancel-dialog #cancelDialog></eg-acq-cancel-dialog>
-<div class="row mt-3">
+<div class="row mt-3" *ngIf="poId || picklistId">
<div class="col-lg-1">
<div ngbDropdown>
<button class="btn btn-info btn-sm" ngbDropdownToggle i18n>Actions</button>
<!-- NAVIGATION / EXPANDY -->
-<div class="row mt-3 mb-1 border border-info rounded toolbar">
+<div *ngIf="poId || picklistId"
+ class="row mt-3 mb-1 border border-info rounded toolbar">
<div class="col-lg-12 d-flex">
<div class="d-flex justify-content-center flex-column h-100">
<div class="form-check">
<!-- LINEITEM LIST -->
+<ng-container *ngIf="pageOfLineitems.length === 0 && !loading">
+ <div class="row mt-2">
+ <div class="col-lg-6 offset-lg-3 alert alert-warning" i18n>
+ No items to display.
+ </div>
+ </div>
+</ng-container>
+
<ng-container *ngFor="let li of pageOfLineitems">
<div class="row mt-2 border-bottom pt-2 pb-2 li-state-{{li.state()}}">
<div class="col-lg-12 d-flex">
picklistId: number = null;
poId: number = null;
+ recordId: number = null; // lineitems related to a bib.
loading = false;
pager: Pager = new Pager();
this.route.parent.paramMap.subscribe((params: ParamMap) => {
this.picklistId = +params.get('picklistId');
this.poId = +params.get('poId');
+ this.recordId = +params.get('recordId');
this.load();
});
load(): Promise<any> {
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;
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(
--- /dev/null
+
+<eg-staff-banner i18n-bannerText bannerText="Linetiems Related to Bib Record">
+</eg-staff-banner>
+
+<eg-bib-summary [recordId]="recordId"></eg-bib-summary>
+
+<eg-prompt-dialog #newPlDialog
+ i18n-dialogTitle dialogTitle="New Selection List"
+ i18n-dialogBody dialogBody="Enter Selection List Name">
+</eg-prompt-dialog>
+
+<eg-alert-dialog #plNameExists
+ i18n-dialogBody dialogBody="Selection List Name Already In Use">
+</eg-alert-dialog>
+
+<div class="row mt-2 mb-2 border border-info">
+ <div class="col-lg-2 p-1">
+ <button class="btn btn-outline-dark label-with-material-icon"
+ (click)="createPicklist()" i18n>
+ <span class="material-icons mr-1">create_new_folder</span>
+ Create Selection List
+ </button>
+ </div>
+ <div class="col-lg-2 p-1">
+ <button class="btn btn-outline-dark label-with-material-icon"
+ (click)="addingToPl=!addingToPl" i18n>
+ <span class="material-icons mr-1">add_circle</span>
+ Add To Selection List
+ </button>
+ </div>
+ <div class="col-lg-2 p-1">
+ <div *ngIf="addingToPl" class="d-flex">
+ <eg-combobox [(ngModel)]="selectedPl" idlClass="acqpl"
+ placeholder="Select List..." i18n-placeHolder></eg-combobox>
+ <button class="btn btn-outline-primary btn-sm"
+ (click)="addToPicklist(selectedPl ? selectedPl.id : null)" i18n>
+ Apply
+ </button>
+ </div>
+ </div>
+ <div class="col-lg-2 p-1">
+ <button class="btn btn-outline-dark label-with-material-icon"
+ (click)="createPo()" i18n>
+ <span class="material-icons mr-1">create_new_folder</span>
+ Create Purchase Order
+ </button>
+ </div>
+ <div class="col-lg-2 p-1">
+ <button class="btn btn-outline-dark label-with-material-icon"
+ (click)="addingToPo=!addingToPo" i18n>
+ <span class="material-icons mr-1">add_circle_outline</span>
+ Add To Purchase Order
+ </button>
+ </div>
+ <div class="col-lg-2 p-1">
+ <div *ngIf="addingToPo" class="d-flex">
+ <eg-combobox [(ngModel)]="selectedPo" idlClass="acqpo"
+ placeholder="Select Order..." i18n-placeHolder></eg-combobox>
+ <button class="btn btn-outline-primary btn-sm"
+ (click)="addToPo(selectedPo ? selectedPo.id : null)" i18n>
+ Apply
+ </button>
+ </div>
+ </div>
+</div>
+
+<router-outlet></router-outlet>
+
--- /dev/null
+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<IdlObject> {
+
+ 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]);
+ }
+ });
+ }
+}
+
--- /dev/null
+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 {
+}
--- /dev/null
+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 {}
path: 'picklist',
loadChildren: () =>
import('./picklist/picklist.module').then(m => m.PicklistModule)
+}, {
+ path: 'related',
+ loadChildren: () =>
+ import('./related/related.module').then(m => m.RelatedModule)
}];
@NgModule({
href="/eg/staff/acq/legacy/lineitem/related/{{recId}}?target=bib">
<span i18n>View/Place Orders</span>
</a>
+ <!-- SETTING?
+ <a class="dropdown-item" routerLink="/staff/acq/related/{{recId}}">
+ <span i18n>View/Place Orders</span>
+ </a>
+ -->
</div>
</div>
</div>
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);
+ }
}
}