From: Bill Erickson Date: Wed, 2 Feb 2022 18:04:34 +0000 (-0500) Subject: LP1952931 ASN Receiving... X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=58e8ee5ba16b89ddb99249cba29fe6aacf11cae9;p=working%2FEvergreen.git LP1952931 ASN Receiving... Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.html b/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.html index 68d400581f..03b9053a20 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.html +++ b/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.html @@ -14,6 +14,11 @@ +
+ + +
@@ -111,11 +116,55 @@ across different vendors to match a container code. - +
+
+
Receiving Items (Dry Run)
+
+
    +
  • + +
  • + +
  • +
    Lineitem
    +
    Notified
    +
    Received
    +
  • + +
  • + +
    {{liWantedCount(li.id)}}
    +
    + {{li.lids.length}}
    +
  • +
+
+ +
+
+ + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.ts index 0f5ad15af2..4108a050ef 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/asn/receive.component.ts @@ -5,10 +5,20 @@ 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 {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.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'; +import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component'; + +interface ReceiveResponse { + progress: number; + lineitems: any[]; + complete: boolean; + po: number; +} @Component({ templateUrl: 'receive.component.html' @@ -16,13 +26,19 @@ import {GridComponent} from '@eg/share/grid/grid.component'; export class AsnReceiveComponent implements OnInit { barcode = ''; + receiving = false; + dryRun = true; + receiveOnScan = false; // Technically possible for one container code to match across providers. container: IdlObject; entries: IdlObject[] = []; containers: IdlObject[] = []; + receiveResponse: ReceiveResponse; @ViewChild('grid') private grid: GridComponent; + @ViewChild('progress') private progress: ProgressInlineComponent; + gridDataSource: GridDataSource = new GridDataSource(); constructor( @@ -30,6 +46,8 @@ export class AsnReceiveComponent implements OnInit { private router: Router, private ngLocation: Location, private pcrud: PcrudService, + private net: NetService, + private auth: AuthService, private li: LineitemService ) {} @@ -62,6 +80,7 @@ export class AsnReceiveComponent implements OnInit { } findContainer() { + this.receiving = false; this.container = null; this.containers = []; this.entries = []; @@ -70,19 +89,22 @@ export class AsnReceiveComponent implements OnInit { {container_code: this.barcode}, {flesh: 1, flesh_fields: {acqsn: ['entries', 'provider']}} ).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(); - } + sn => this.containers.push(sn), + _ => {}, + () => { + + // TODO handle multiple containers w/ same code + if (this.containers.length === 1) { + this.container = this.containers[0]; + this.loadContainer(); + if (this.receiveOnScan) { + this.receiveAllItems(); + } + } + + const node = document.getElementById('barcode-search-input'); + (node as HTMLInputElement).select(); + } ); } @@ -103,7 +125,11 @@ export class AsnReceiveComponent implements OnInit { _ => {}, () => { this.entries = entries; - this.grid.reload(); + + if (this.grid) { + // Hidden of receiveOnScan + this.grid.reload(); + } } ); } @@ -133,7 +159,44 @@ export class AsnReceiveComponent implements OnInit { } receiveAllItems() { - alert('TODO'); + this.receiving = true; + + this.receiveResponse = { + progress: 0, + lineitems: [], + complete: false, + po: null + }; + + setTimeout(() => // Allow time to render + this.progress.update({value: 0, max: this.affectedItemsCount()})); + + let method = 'open-ils.acq.shipment_notification.receive_items'; + if (this.dryRun) { method += '.dry_run'; } + + this.net.request('open-ils.acq', + method, this.auth.token(), this.container.id()) + .subscribe( + resp => { + this.progress.update({value: resp.progress}); + console.debug('ASN Receive returned', resp); + this.receiveResponse = resp; + }, + err => {}, + () => { + } + ); + } + + clearReceiving() { + this.receiving = false; + this.findContainer(); + } + + liWantedCount(liId: number): number { + const entry = this.entries.filter(e => e.lineitem().id())[0]; + if (entry) { return entry.item_count(); } + return 0; } } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm index 807a2756a9..f66325644d 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm @@ -4388,5 +4388,129 @@ sub li_existing_copies { } +__PACKAGE__->register_method( + method => 'asn_receive_items', + api_name => 'open-ils.acq.shipment_notification.receive_items', + max_bundle_count => 1, + signature => { + desc => q/ + Mark items from a shipment notification as received. + /, + params => [ + {desc => 'Authentication token', type => 'string'}, + {desc => 'Shipment Notification ID', type => 'number'} + ], + return => {desc => q/Stream of status updates, event on error/} + } +); + +__PACKAGE__->register_method( + method => 'asn_receive_items', + api_name => 'open-ils.acq.shipment_notification.receive_items.dry_run', + max_bundle_count => 1, + signature => q/dry_run variant of open-ils.acq.shipment_notification.receive_items/ +); + +sub asn_receive_items { + my ($self, $client, $auth, $asn_id) = @_; + + my $e = new_editor(xact => 1, authtoken => $auth); + return $e->die_event unless $e->checkauth; + + my $mgr = OpenILS::Application::Acq::BatchManager->new( + editor => $e, conn => $client, throttle => 1); + + my $asn = $e->retrieve_acq_shipment_notification([$asn_id, + {flesh => 1, flesh_fields => {acqsn => ['provider', 'entries']}} + ]) || return $e->die_event; + + return $e->die_event unless + $e->allowed('MANAGE_SHIPMENT_NOTIFICATION', $asn->provider->owner); + + my $resp = { + lineitems => [], + progress => 0, + }; + + my @entries = sort {$a->lineitem cmp $b->lineitem} @{$asn->entries}; + + for my $entry (@entries) { + + my $li = $e->retrieve_acq_lineitem($entry->lineitem) + or return $e->die_event; + + my $li_resp = { + id => $entry->lineitem, + po => $li->purchase_order, + lids => [] + }; + + push(@{$resp->{lineitems}}, $li_resp); + + # Include canceled items. + my $lids = $e->search_acq_lineitem_detail([{ + lineitem => $entry->lineitem, + recv_time => undef + }, { + flesh => 1, + flesh_fields => {acqlid => ['cancel_reason']} + }]); + + # Start by receiving un-canceled items. + # Then try "delayed" items if it comes to that. + # Apply sorting for consistency with dry-run. + + my @active_lids = sort {$a->id cmp $b->id} + grep {!$_->cancel_reason} @$lids; + + my @canceled_lids = sort {$a->id cmp $b->id} + grep { $_->cancel_reason && $U->is_true($_->cancel_reason->keep_debits) + } @$lids; + + my @potential_lids = (@active_lids, @canceled_lids); + + if (scalar(@potential_lids) < $entry->item_count) { + $logger->warn(sprintf( + "ASN $asn_id entry %d found %d receivable items for lineitem %d, but wanted %d", + $entry->id, scalar(@potential_lids), $entry->lineitem, $entry->item_count + )); + } + + my $recv_count = 0; + + for my $lid (@potential_lids) { + + return $e->die_event unless receive_lineitem_detail($mgr, $lid->id); + + # Get an updated copy to pick up the recv_time + $lid = $e->retrieve_acq_lineitem_detail($lid->id); + + my $note = $lid->note ? $lid->note . "\n" : ''; + $note .= "Received via shipment notification #$asn_id"; + $lid->note($note); + + $e->update_acq_lineitem_detail($lid) or return $e->die_event; + + push(@{$li_resp->{lids}}, $lid->id); + $resp->{progress}++; + $client->respond($resp); + + last if ++$recv_count >= $entry->item_count; + } + } + + if ($self->api_name =~ /dry_run/) { + $e->rollback; + } else { + $e->commit; + } + + $resp->{complete} = 1; + $client->respond_complete($resp); + + undef; +} + + 1;