</div>
</div>
+<!--
<hr class="mt-2 mb-2"/>
+-->
-<div class="row border rounded mt-1" *ngFor="let container of containers">
- <div class="col-lg-12 d-flex pt-2 pb-2">
- <div class="">{{container.container_code()}}</div>
- <div class="ml-2">{{container.provider().name()}}</div>
- <div class="ml-2">{{container.recv_date() | date:'short'}}</div>
- <div class="ml-2">{{container.lading_number()}}</div>
- <div class="ml-2">{{container.note()}}</div>
+<!-- TODO Unlikely, but technically possible for multiple containers
+across different vendors to match a container code.
+<div *ngFor="let container of containers">
+...
+</div>
+-->
+
+<div *ngIf="container" class="mt-3 mb-3 p-1 shadow-sm common-form striped-odd">
+ <div class="row">
+ <div class="col-lg-2">
+ <label for="container-code" i18n>Container Code: </label>
+ </div>
+ <div class="col-lg-2">
+ <div id="container-code">{{container.container_code()}}</div>
+ </div>
+ <div class="col-lg-2">
+ <label for="container-provider" i18n>Provider: </label>
+ </div>
+ <div class="col-lg-2">
+ <div>
+ <a target="_blank"
+ id="container-provider"
+ routerLink="/staff/acq/provider/{{container.provider().id()}}/details">
+ {{container.provider().name()}} ({{container.provider().code()}})
+ </a>
+ </div>
+ </div>
+ <div class="col-lg-2">
+ <label for="entry-count" i18n>Affected Lineitems: </label>
+ </div>
+ <div class="col-lg-2">
+ <div id="entry-count">{{entries.length}}</div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-2">
+ <label for="container-lading-number" i18n>Lading #: </label>
+ </div>
+ <div class="col-lg-2">
+ <div id="container-lading-number">{{container.lading_number()}}</div>
+ </div>
+ <div class="col-lg-2">
+ <label for="container-recv-date" i18n>Receive Date: </label>
+ </div>
+ <div class="col-lg-2">
+ <div id="container-recv-date">{{container.recv_date() | date:'short'}}</div>
+ </div>
+ <div class="col-lg-2">
+ <label for="entry-count" i18n>Affected Items: </label>
+ </div>
+ <div class="col-lg-2">
+ <div id="entry-count">{{affectedItemsCount()}}</div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-2">
+ <label for="container-note" i18n>Notes: </label>
+ </div>
+ <div class="col-lg-4">
+ <div class="ml-1">{{container.note()}}</div>
+ </div>
</div>
</div>
+
+<!--
+<hr class="mt-2 mb-2"/>
+-->
+
+<ng-template #titleTmpl let-row="row">
+ <a target="_blank"
+ fragment="{{row.lineitem.id()}}"
+ routerLink="/staff/acq/po/{{row.lineitem.purchase_order().id()}}">
+ {{row.title}}
+ </a>
+</ng-template>
+<ng-template #liIdTmpl let-row="row">
+ <a target="_blank"
+ fragment="{{row.lineitem.id()}}"
+ routerLink="/staff/acq/po/{{row.lineitem.purchase_order().id()}}">
+ {{row.lineitem.id()}}
+ </a>
+</ng-template>
+<ng-template #poNameTmpl let-row="row">
+ <a target="_blank"
+ routerLink="/staff/acq/po/{{row.lineitem.purchase_order().id()}}">
+ {{row.lineitem.purchase_order().name()}}
+ </a>
+</ng-template>
+
+<eg-grid *ngIf="container" #grid [dataSource]="gridDataSource"
+ pageSize="50" (onRowActivate)="openLi($event)">
+
+ <eg-grid-toolbar-button i18n-label label="Receive All Items"
+ (onClick)="receiveAllItems()"></eg-grid-toolbar-button>
+
+ <eg-grid-column i18n-label label="Entry ID" path="entry.id"
+ [index]="true" [hidden]="true"></eg-grid-column>
+ <eg-grid-column i18n-label label="Lineitem ID" name="lineitem_id"
+ [cellTemplate]="liIdTmpl"></eg-grid-column>
+ <eg-grid-column i18n-label label="Purchase Order" name="po_name"
+ [cellTemplate]="poNameTmpl"></eg-grid-column>
+ <eg-grid-column i18n-label label="Title" name="title" flex="4"
+ [cellTemplate]="titleTmpl"></eg-grid-column>
+ <eg-grid-column i18n-label label="ISBN" path="isbn"></eg-grid-column>
+ <eg-grid-column i18n-label label="ISSN" path="issn" [hidden]="true"></eg-grid-column>
+ <eg-grid-column i18n-label label="UPC" path="upc" [hidden]="true"></eg-grid-column>
+ <eg-grid-column i18n-label label="In Shipment" path="entry.item_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Ordered" path="lineitem.order_summary.item_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Pending Receive" path="recievable_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Received" path="lineitem.order_summary.recv_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Invoiced" path="lineitem.order_summary.invoice_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Canceled" path="lineitem.order_summary.cancel_count"></eg-grid-column>
+ <eg-grid-column i18n-label label="Delayed" path="lineitem.order_summary.delay_count"></eg-grid-column>
+</eg-grid>
+
+
-import {Component, OnInit} from '@angular/core';
+import {Component, OnInit, ViewChild} from '@angular/core';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {Location} from '@angular/common';
+import {Observable, Observer, of, from} from 'rxjs';
+import {tap} from 'rxjs/operators';
import {IdlObject} from '@eg/core/idl.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {LineitemService} from '../lineitem/lineitem.service';
+import {Pager} from '@eg/share/util/pager';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
@Component({
templateUrl: 'receive.component.html'
barcode = '';
- // Technically possible for one barcode to match across providers.
+ // Technically possible for one container code to match across providers.
+ container: IdlObject;
+ entries: IdlObject[] = [];
containers: IdlObject[] = [];
+ @ViewChild('grid') private grid: GridComponent;
+ gridDataSource: GridDataSource = new GridDataSource();
+
constructor(
private route: ActivatedRoute,
+ private router: Router,
+ private ngLocation: Location,
private pcrud: PcrudService,
private li: LineitemService
) {}
ngOnInit() {
- }
+ this.barcode = this.route.snapshot.paramMap.get('containerCode') || '';
+ if (this.barcode) {
+ this.findContainer();
+ }
- findContainer() {
+ this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
+ return from(this.entries.map(e => this.gridifyEntry(e)));
+ };
+ }
- console.log('BARCODE', this.barcode);
+ gridifyEntry(entry: IdlObject): any {
+ const li = entry.lineitem();
+ const sum = li.order_summary();
+ return {
+ entry: entry,
+ lineitem: li,
+ title: this.li.getFirstAttributeValue(li, 'title'),
+ author: this.li.getFirstAttributeValue(li, 'author'),
+ isbn: this.li.getFirstAttributeValue(li, 'isbn'),
+ issn: this.li.getFirstAttributeValue(li, 'issn'),
+ upc: this.li.getFirstAttributeValue(li, 'upc'),
+ recievable_count: sum.item_count() - (
+ sum.recv_count() + sum.cancel_count()
+ )
+ };
+ }
+ findContainer() {
+ this.container = null;
this.containers = [];
+ this.entries = [];
this.pcrud.search('acqsn',
{container_code: this.barcode},
{flesh: 1, flesh_fields: {acqsn: ['entries', 'provider']}}
- ).subscribe(sn => this.containers.push(sn));
+ ).subscribe(
+ sn => this.containers.push(sn),
+ _ => {},
+ () => {
+
+ // TODO handle multiple containers w/ same code
+ if (this.containers.length === 1) {
+ this.container = this.containers[0];
+ this.loadContainer();
+ }
+
+ const node = document.getElementById('barcode-search-input');
+ (node as HTMLInputElement).select();
+ }
+ );
+ }
+
+ loadContainer() {
+ if (!this.container) { return; }
+
+ const entries = this.container.entries();
+
+ if (entries.length === 0) { return; }
+
+ this.li.getFleshedLineitems(entries.map(e => e.lineitem()), {})
+ .subscribe(
+ li_struct => {
+ // Flesh the lineitems directly in the shipment entry
+ const entry = entries.filter(e => e.lineitem() === li_struct.id)[0];
+ entry.lineitem(li_struct.lineitem);
+ },
+ _ => {},
+ () => {
+ this.entries = entries;
+ this.grid.reload();
+ }
+ );
+ }
+
+ openLi(row: any) {
+ let url = this.ngLocation.prepareExternalUrl(
+ this.router.serializeUrl(
+ this.router.createUrlTree(
+ ['/staff/acq/po/', row.lineitem.purchase_order().id()]
+ )
+ )
+ );
+
+ // this.router.createUrlTree() documents claim it supports
+ // {fragment: row.lineitem.id()}, but it's not getting added to
+ // the URL. Adding manually.
+ url += '#' + row.lineitem.id();
+
+ window.open(url);
+ }
+
+ affectedItemsCount(): number {
+ if (this.entries.length === 0) { return 0; }
+ return this.entries
+ .map(e => e.item_count())
+ .reduce((pv, cv) => pv + (cv || 0));
+ }
+
+ receiveAllItems() {
+ alert('TODO');
}
}