LP1929749 Finetuning LMOR based on LP comments
authorTiffany Little <tlittle@georgialibraries.org>
Mon, 20 Sep 2021 14:58:29 +0000 (10:58 -0400)
committerJane Sandberg <js7389@princeton.edu>
Sun, 2 Oct 2022 15:02:50 +0000 (08:02 -0700)
Signed-off-by: Tiffany Little <tlittle@georgialibraries.org>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Signed-off-by: Ruth Frasur <rfrasur@library.in.gov>
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Open-ILS/src/eg2/src/app/staff/acq/picklist/upload.component.html
Open-ILS/src/eg2/src/app/staff/acq/picklist/upload.component.ts
Open-ILS/src/eg2/src/app/staff/acq/picklist/upload.service.ts

index 3feac3f..567b8fc 100644 (file)
@@ -5,15 +5,6 @@
   <div class="ml-auto mr-3"><a i18n href="/eg/staff/acq/legacy/picklist/upload">Legacy Upload Interface</a></div>
 </div>
 
-<div class="row mb-3" *ngIf="importSelection()">
-  <div class="col-lg-2" *ngIf="selectedQueue">
-    <button class="btn btn-info label-with-material-icon"
-      routerLink="/staff/cat/vandelay/queue/{{recordType}}/{{selectedQueue.id}}">
-      <span class="material-icons">arrow_back</span>
-      <span i18n>Return to Queue</span>
-    </button>
-  </div>
-</div>
 
 <eg-alert-dialog #dupeQueueAlert i18n-dialogBody 
   dialogBody="A queue with the requested name already exists.">
@@ -78,7 +69,6 @@
     </div>
       <div class="col-lg-3">
         <eg-org-select
-        [initialOrgId]="1"
         [applyOrgId]="orderingAgency"
         (onChange)="orgOnChange($event)">
         </eg-org-select>
         id="year-select"
         [startId]="selectedFiscalYear"
         [entries]="formatEntries('fiscalYears')"
+        [required]="true"
         (onChange)="selectEntry($event, 'fiscalYears')">
       </eg-combobox>
     </div>
         id="sl-select"
         [startId]="selectedSelectionList"
         [entries]="formatEntries('selectionLists')"
-        (onChange)="selectEntry($event, 'selectionLists')">
+        (onChange)="selectedSelectionList=$event" i18n-placeholder
+        [allowFreeText]="true">
       </eg-combobox>
     </div>
   </div>
 
   <div class="row">
     <div class="col-lg-3">
-      <label for="source-select" i18n>Select a Record Source</label>
+      <label for="source-select" i18n>Record Source</label>
     </div>
     <div class="col-lg-3">
       <eg-combobox #bibSourceSelector
         id="source-select"
         [entries]="formatEntries('bibSources')" 
         (onChange)="selectEntry($event, 'bibSources')"
-        [required]="true"
         [startId]="selectedBibSource">
       </eg-combobox>
     </div>
   </div>
   <div class="col-lg-3">
     <input class="form-check-input" type="checkbox" 
-    [required]="true"
       id="import-non-matching"
       [(ngModel)]="importNonMatching">
   </div>
         id="match-set-select"
         [entries]="formatEntries('matchSets')" 
         [disabled]="(selectedQueue && !selectedQueue.freetext) || importSelection()"
-        [required]="true"
         [startId]="selectedMatchSet || defaultMatchSet"
         (onChange)="selectEntry($event, 'matchSets')">
       </eg-combobox>
     <div class="col-lg-3">
       <eg-combobox #mergeProfileSelector
         id="merge-profiles"
-        [required]="true"
         [entries]="formatEntries('mergeProfiles')"
         (onChange)="selectEntry($event, 'mergeProfiles')"
         [startId]="selectedMergeProfile">
     <div class="col-lg-3">
       <eg-combobox [entries]="formatEntries('activeQueues')"
         id="queue-select"
-        [startId]="startQueueId"
         [startIdFiresOnChange]="true"
-        [disabled]="startQueueId"
         (onChange)="selectedQueue=$event" i18n-placeholder
         [required]="true"
         [allowFreeText]="true">
         (click)="upload()" i18n>Upload</button>
     </div>
   </div>
-  <div class="row" [hidden]="!showProgress || importSelection()">
+  <div class="row" [hidden]="!showProgress || uploadComplete">
     <div class="col-lg-3">
-      <label i18n>Upload to Server</label>
+      <label i18n>Upload File to Server</label>
     </div>
     <div class="col-lg-6">
       <eg-progress-inline #uploadProgress></eg-progress-inline>
     </div>
   </div>
  
-  <div class="col-lg-6" [hidden]="!isUploading">
-    <label i18n>Go To:</label>
+
+  <div class="col-lg-6 offset-lg-3" [hidden]="!uploadProcessing || uploadComplete">
+    <h2><label i18n><i>Processing...</i></label></h2>
   </div>
-  <div class="row" [hidden]="!isUploading">
-    <div class="col-lg-6 offset-lg-3">
-      <a routerLink="/staff/cat/vandelay/queue/{{recordType}}/{{activeQueueId}}" target="_blank" i18n>Queue</a>
+
+  <div class="row" [hidden]="!uploadComplete">
+    <div class="col-lg-3 offset-lg-3">
+      <h2><label i18n>Upload Complete!</label></h2>
+    </div>
+    </div>
+    <div class="row" [hidden]="!uploadComplete">
+      <div class="col-sm-1 offset-lg-3">
+        <label i18n>Go to:</label>
+    </div>
+    <div><a routerLink="/staff/cat/vandelay/queue/{{recordType}}/{{activeQueueId}}" target="_blank" i18n>Queue</a></div>
+    <div class="col-sm-1" [hidden]="!selectedSelectionList"><a href="/eg/staff/acq/legacy/picklist/view/{{activeSelectionListId}}" target="_blank">Selection List</a></div>
+    <div class="col-sm-2" [hidden]="!createPurchaseOrder"><a href="/eg/staff/acq/legacy/po/view/{{newPO}}" target="_blank">Purchase Order</a></div>
     </div>
-  </div>
-</div>
\ No newline at end of file
index 9c1a32d..86b6918 100644 (file)
@@ -26,6 +26,7 @@ const TEMPLATE_SETTING_NAME = 'eg.acq.picklist.upload.templates';
 const TEMPLATE_ATTRS = [
     'createPurchaseOrder',
     'activatePurchaseOrder',
+    'selectedProvider',
     'orderingAgency',
     'selectedFiscalYear',
     'loadItems',
@@ -55,11 +56,6 @@ const ORG_SETTINGS = [
     'acq.upload.default.vandelay.quality_ratio'
 ];
 
-interface ImportOptions {
-    session_key: string;
-    overlay_map?: {[qrId: number]: /* breId */ number};
-    exit_early: boolean;
-}
 
 @Component({
   templateUrl: './upload.component.html'
@@ -68,16 +64,14 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
 
     settings: Object = {};
     recordType: string;
-    selectedQueue: ComboboxEntry; // freetext enabled
+    selectedQueue: ComboboxEntry; 
 
-    // used for applying a default queue ID value when we have
-    // a load-time queue before the queue combobox entries exist.
-    startQueueId: number;
 
+    activeSelectionListId: number;
     activeQueueId: number;
     orderingAgency: number;
     selectedFiscalYear: number;
-    selectedSelectionList: number;
+    selectedSelectionList: ComboboxEntry;
     selectedBibSource: number;
     selectedProvider: number;
     selectedMatchSet: number;
@@ -85,6 +79,7 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
     selectedMergeProfile: number;
     selectedFallThruMergeProfile: number;
     selectedFile: File;
+    newPO: number;
 
     defaultMatchSet: string;
 
@@ -98,20 +93,13 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
     mergeOnBestMatch: boolean;
     minQualityRatio: number;
 
-    // True after the first upload, then remains true.
-    showProgress: boolean;
-
-    // Upload in progress.
     isUploading: boolean;
-
-    // True only after successful upload
+    uploadProcessing: boolean;
     uploadComplete: boolean;
 
-    // Upload / processsing session key
     // Generated by the server
     sessionKey: string;
 
-
     selectedTemplate: string;
     formTemplates: {[name: string]: any};
     newTemplateName: string;
@@ -120,7 +108,6 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
     @ViewChild('uploadProgress', { static: true })
         private uploadProgress: ProgressInlineComponent;
 
-    // Need these refs so values can be applied via external stimuli
     @ViewChild('formTemplateSelector', { static: true })
         private formTemplateSelector: ComboboxComponent;
     @ViewChild('bibSourceSelector', { static: true })
@@ -175,7 +162,6 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
         this.minQualityRatio = 0;
         this.recordType = 'bib';
         this.formTemplates = {};
-//To-do add default for fiscal year
         if (this.vlagent.importSelection) {
 
             if (!this.vlagent.importSelection.queue) {
@@ -185,14 +171,8 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
             }
 
             const queue = this.vlagent.importSelection.queue;
-            this.recordType = queue.queue_type();
             this.selectedMatchSet = queue.match_set();
 
-            // This will be propagated to selectedQueue as a combobox
-            // entry via the combobox
-            this.startQueueId = queue.id();
-
-
         }
     }
 
@@ -203,8 +183,6 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
     }
 
     ngOnDestroy() {
-        // Always clear the import selection when navigating away from
-        // the import page.
         this.clearSelection();
     }
 
@@ -224,8 +202,8 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
             this.vlagent.getProvidersList(),
             this.vlagent.getSelectionLists(),
             this.vlagent.getItemImportDefs(),
-            this.org.settings(['vandelay.default_match_set']).then(
-                s => this.defaultMatchSet = s['vandelay.default_match_set']),
+           this.org.settings(['vandelay.default_match_set']).then(
+               s => this.defaultMatchSet = s['vandelay.default_match_set']),
             this.loadTemplates()
         ];
 
@@ -260,7 +238,6 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
         return entries;
     }
 
-    // Format typeahead data sets
     formatEntries(etype: string): ComboboxEntry[] {
         const rtype = this.recordType;
         let list;
@@ -290,8 +267,7 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
                  break;
 
             case 'activeQueues':
-                list = (this.vlagent.allQueues[rtype] || [])
-                        .filter(q => q.complete() === 'f');
+                list = (this.vlagent.allQueues[rtype] || []);
                 break;
 
             case 'matchSets':
@@ -356,34 +332,22 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
        this.selectedFile = $event.target.files[0];
     }
 
-    // Required form data varies depending on context.
     hasNeededData(): boolean {
-        if (this.vlagent.importSelection) {
-            return this.importActionSelected();
-        } else {
-            return this.selectedQueue &&
-                Boolean(this.recordType) && Boolean(this.selectedFile);
-        }
-    }
-
-    importActionSelected(): boolean {
-        return this.importNonMatching
-            || this.mergeOnExact
-            || this.mergeOnSingleMatch
-            || this.mergeOnBestMatch;
+        return this.selectedQueue &&
+        Boolean(this.selectedFile) &&
+        Boolean(this.selectedFiscalYear) &&
+        Boolean(this.selectedProvider) &&
+        Boolean(this.orderingAgency);
     }
-
-    // 1. create queue if necessary
-    // 2. upload MARC file
-    // 3. Enqueue MARC records
-    // 4. Import records
+    
     upload() {
         this.sessionKey = null;
-        this.showProgress = true;
         this.isUploading = true;
         this.uploadComplete = false;
         this.resetProgressBars();
 
+        this.resolveSelectionList(),
         this.resolveQueue()
         .then(
             queueId => {
@@ -412,13 +376,9 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
         this.uploadProgress.update({value: 0, max: 1});
     }
 
-    // Extract selected queue ID or create a new queue when requested.
     resolveQueue(): Promise<number> {
 
         if (this.selectedQueue.freetext) {
-            // Free text queue selector means create a new entry.
-            // TODO: first check for name dupes
-
             return this.vlagent.createQueue(
                 this.selectedQueue.label,
                 this.recordType,
@@ -444,10 +404,28 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
         }
     }
 
+    resolveSelectionList(): Promise<any> {
+        if (!this.selectedSelectionList) {
+            return Promise.resolve()
+        }
+        if (this.selectedSelectionList.id) {
+            this.activeSelectionListId = this.selectedSelectionList.id
+        }
+        if (this.selectedSelectionList.freetext) {
+
+            return this.vlagent.createSelectionList(
+                this.selectedSelectionList.label,
+                this.orderingAgency
+            ).then(
+                value => this.activeSelectionListId = value
+            );
+        }
+        return Promise.resolve(this.activeSelectionListId); 
+    }
+
     uploadFile(): Promise<any> {
 
         if (this.vlagent.importSelection) {
-            // Nothing to upload when processing pre-queued records.
             return Promise.resolve();
         }
 
@@ -486,10 +464,12 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
 
     processUpload():  Promise<any> {
 
+        this.uploadProcessing = true;
+
         if (this.vlagent.importSelection) {
             return Promise.resolve();
         }
-
+        
         let spoolType = this.recordType;
 
         const vandelayOptions = {
@@ -503,10 +483,8 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
             bib_source: this.selectedBibSource,
             create_assets: this.loadItems,
             queue_name: this.selectedQueue.label
-
         }
 
-        
         const args = {
             
             provider: this.selectedProvider,
@@ -514,7 +492,7 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
             create_po: this.createPurchaseOrder,
             activate_po: this.activatePurchaseOrder,
             fiscal_year: this.selectedFiscalYear,
-            picklist: this.selectedSelectionList,
+            picklist: this.activeSelectionListId,
             vandelay: vandelayOptions
         }
 
@@ -526,9 +504,15 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
                 'open-ils.acq', method,
                 this.auth.token(), this.sessionKey, args
             ).subscribe(
-                tracker => {
-                    const e = this.evt.parse(tracker);
-                    if (e) { console.error(e); return reject(); }
+                progress => {
+                    const resp = this.evt.parse(progress);
+                    console.log(progress);
+                    if (resp) { console.error(resp); return reject();}
+                    if (progress.complete) {
+                        this.uploadProcessing = false;
+                        this.uploadComplete = true;
+                    }
+                    if (progress.purchase_order) {this.newPO = progress.purchase_order.id();}
                 }
             );
         });
@@ -536,12 +520,9 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
 
     clearSelection() {
         this.vlagent.importSelection = null;
-        this.startQueueId = null;
+        this.activeSelectionListId = null;
     }
 
-    openQueue() {
-        console.log('opening queue ' + this.activeQueueId);
-    }
 
     saveTemplate() {
 
@@ -575,27 +556,19 @@ export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
         this.selectedTemplate = entry.label; // label == name
 
         if (entry.freetext) {
-            // User is entering a new template name.
-            // Nothing to apply.
             return;
         }
 
-        // User selected an existing template, apply it to the form.
-
         const template = this.formTemplates[entry.id];
 
-        // Copy the template values into "this"
         TEMPLATE_ATTRS.forEach(key => this[key] = template[key]);
 
-        // Some values must be manually passed to the combobox'es
-
         this.bibSourceSelector.applyEntryId(this.selectedBibSource);
         this.matchSetSelector.applyEntryId(this.selectedMatchSet);
         this.providerSelector.applyEntryId(this.selectedProvider);
         this.fiscalYearSelector.applyEntryId(this.selectedFiscalYear);
         this.mergeProfileSelector.applyEntryId(this.selectedMergeProfile);
-        this.fallThruMergeProfileSelector
-            .applyEntryId(this.selectedFallThruMergeProfile);
+        this.fallThruMergeProfileSelector.applyEntryId(this.selectedFallThruMergeProfile);
     }
 
     deleteTemplate() {
index a586166..0cf0718 100644 (file)
@@ -11,7 +11,7 @@ import {PcrudService} from '@eg/core/pcrud.service';
 import {PermService} from '@eg/core/perm.service';
 import {EventService} from '@eg/core/event.service';
 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
-import {VandelayImportSelection, VANDELAY_EXPORT_PATH} from '@eg/staff/cat/vandelay/vandelay.service'
+import {VandelayImportSelection} from '@eg/staff/cat/vandelay/vandelay.service'
 
 
 @Injectable()
@@ -26,15 +26,11 @@ export class PicklistUploadService {
     providersList: IdlObject[];
     fiscalYears: IdlObject[];
     selectionLists: IdlObject[];
+    queueType: string;
+    recordType: string;
 
-    // Used for tracking records between the queue page and
-    // the import page.  Fields managed externally.
-    importSelection: VandelayImportSelection;
 
-    // Track the last grid offset in the queue page so we
-    // can return the user to the same page of data after
-    // going to the matches page.
-    queuePageOffset: number;
+    importSelection: VandelayImportSelection;
 
     constructor(
         private http: HttpClient,
@@ -50,7 +46,8 @@ export class PicklistUploadService {
         this.allQueues = {};
         this.matchSets = {};
         this.importSelection = null;
-        this.queuePageOffset = 0;
+        this.queueType = 'acq';
+        this.recordType = 'bib';
     }
 
     getAttrDefs(dtype: string): Promise<IdlObject[]> {
@@ -109,7 +106,7 @@ export class PicklistUploadService {
             return lists;
         });
     }
-    // Returns a promise resolved with the list of queues.
+
     getAllQueues(qtype: string): Promise<IdlObject[]> {
         if (this.allQueues[qtype]) {
             return Promise.resolve(this.allQueues[qtype]);
@@ -117,10 +114,9 @@ export class PicklistUploadService {
             this.allQueues[qtype] = [];
         }
 
-        // could be a big list, invoke in streaming mode
         return this.net.request(
             'open-ils.vandelay',
-            `open-ils.vandelay.${qtype}_queue.owner.retrieve`,
+            `open-ils.vandelay.bib_queue.owner.retrieve`,
             this.auth.token()
         ).pipe(tap(
             queue => this.allQueues[qtype].push(queue)
@@ -168,10 +164,9 @@ export class PicklistUploadService {
         });
     }
 
-    // todo: differentiate between biblio and authority a la queue api
     getMatchSets(mtype: string): Promise<IdlObject[]> {
 
-        const mstype = mtype.match(/bib/) ? 'biblio' : 'authority';
+        const mstype = 'biblio'
 
         if (this.matchSets[mtype]) {
             return Promise.resolve(this.matchSets[mtype]);
@@ -190,88 +185,57 @@ export class PicklistUploadService {
     }
 
 
-
-
-
-
-    // Create a queue and return the ID of the new queue via promise.
     createQueue(
         queueName: string,
-        recordType: string,
+        queueType: string,
         importDefId: number,
         matchSet: number): Promise<number> {
 
-        const method = `open-ils.vandelay.${recordType}_queue.create`;
+        const method = `open-ils.vandelay.bib_queue.create`;
+        queueType = 'acq';
 
-        let qType = recordType;
-        if (recordType.match(/acq/)) {
-            qType = 'bib';
-        }
 
         return new Promise((resolve, reject) => {
             this.net.request(
                 'open-ils.vandelay', method,
-                this.auth.token(), queueName, null, qType,
+                this.auth.token(), queueName, null, queueType,
                 matchSet, importDefId
             ).subscribe(queue => {
                 const e = this.evt.parse(queue);
                 if (e) {
                     reject(e);
                 } else {
-                    // createQueue is always called after queues have
-                    // been fetched and cached.
-                    this.allQueues[qType].push(queue);
+                    this.allQueues['bib'].push(queue);
                     resolve(queue.id());
                 }
             });
         });
     }
 
-    getQueuedRecords(queueId: number, queueType: string,
-      options?: any, limitToMatches?: boolean): Observable<any> {
-
-        const qtype = queueType.match(/bib/) ? 'bib' : 'auth';
-
-        let method =
-          `open-ils.vandelay.${qtype}_queue.records.retrieve`;
-
-        if (limitToMatches) {
-            method =
-              `open-ils.vandelay.${qtype}_queue.records.matches.retrieve`;
-        }
-
-        return this.net.request('open-ils.vandelay',
-            method, this.auth.token(), queueId, options);
-    }
-
-    // Download a queue as a MARC file.
-    exportQueue(queue: IdlObject, nonImported?: boolean) {
-
-        const etype = queue.queue_type().match(/auth/) ? 'auth' : 'bib';
-
-        let url =
-          `${VANDELAY_EXPORT_PATH}?type=bib&queueid=${queue.id()}`;
-
-        let saveName = queue.name();
-
-        if (nonImported) {
-            url += '&nonimported=1';
-            saveName += '_nonimported';
-        }
+    createSelectionList(
+        picklistName: string,
+        picklistOrg: number
+    ): Promise<number> {
 
-        saveName += '.mrc';
-
-        this.http.get(url, {responseType: 'text'}).subscribe(
-            data => {
-                saveAs(
-                    new Blob([data], {type: 'application/octet-stream'}),
-                    saveName
-                );
-            },
-            err  => {
-                console.error(err);
-            }
-        );
+        const newpicklist = this.idl.create('acqpl');
+        newpicklist.owner(this.auth.user().id());
+        newpicklist.name(picklistName);
+        newpicklist.org_unit(picklistOrg)
+        
+        return new Promise((resolve, reject) => {
+            this.net.request(
+                'open-ils.acq', 'open-ils.acq.picklist.create',
+                this.auth.token(), newpicklist
+            ).subscribe((picklist) => {
+                if (this.evt.parse(picklist)) {
+                    console.error(picklist);
+                } else {
+                    console.log(picklist);
+                    resolve(picklist);
+                }
+            });
+        });
     }
+    
 }