+++ /dev/null
-import {NgModule} from '@angular/core';
-import {StaffCommonModule} from '@eg/staff/common.module';
-import {CatalogCommonModule} from '@eg/share/catalog/catalog-common.module';
-import {PicklistRoutingModule} from './routing.module';
-import {HttpClientModule} from '@angular/common/http';
-import {UploadComponent} from './upload.component';
-
-@NgModule({
- declarations: [
- UploadComponent
- ],
- imports: [
- StaffCommonModule,
- CatalogCommonModule,
- PicklistRoutingModule,
- HttpClientModule
- ]
-})
-
-export class AcqPicklistModule {}
\ No newline at end of file
+++ /dev/null
-import {NgModule} from '@angular/core';
-import {RouterModule, Routes} from '@angular/router';
-import {UploadComponent} from './upload.component';
-import {VandelayService} from '@eg/staff/cat/vandelay/vandelay.service';
-import {PicklistUploadService} from './upload.service'
-
-
-const routes: Routes = [{
- path: 'upload',
- component: UploadComponent
-}];
-
-@NgModule({
- imports: [RouterModule.forChild(routes)],
- exports: [RouterModule],
- providers: [VandelayService, PicklistUploadService]
-})
-
-export class PicklistRoutingModule {}
\ No newline at end of file
+++ /dev/null
-<eg-staff-banner bannerText="Load MARC Order Records" i18n-bannerText>
-</eg-staff-banner>
-
-<div class="row">
- <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.">
-</eg-alert-dialog>
-
-<div class="common-form striped-odd form-validated ml-3 mr-3">
- <div class="row">
- <div class="col-lg-3">
- <label for="template-select" i18n>Apply/Create Form Template</label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #formTemplateSelector
- id="template-select"
- (onChange)="templateSelectorChange($event)"
- [allowFreeText]="true"
- [startId]="selectedTemplate"
- [startIdFiresOnChange]="true"
- [entries]="formatTemplateEntries()">
- </eg-combobox>
- </div>
- <div class="col-lg-6">
- <button class="btn btn-success"
- [disabled]="!selectedTemplate"
- (click)="saveTemplate()" i18n>Save As New Template</button>
- <button class="btn btn-outline-primary ml-3"
- [disabled]="!selectedTemplate"
- (click)="markTemplateDefault()" i18n>Mark Template as Default</button>
- <button class="btn btn-danger ml-3"
- [disabled]="!selectedTemplate"
- (click)="deleteTemplate()" i18n>Delete Template</button>
- </div>
- </div>
-
- <h2>Purchase Order</h2>
- <div class="row">
- <div class="col-lg-3">
- <label for="provider-select" i18n>Provider</label>
- </div>
-
- <div class="col-lg-3">
- <eg-combobox #providerSelector
- id="provider-select"
- [entries]="formatEntries('providersList')"
- (onChange)="selectEntry($event, 'providersList')"
- [required]="true"
- [startId]="selectedProvider">
- </eg-combobox>
- </div>
-
- <div class="col-lg-3">
- <label for="create-po" i18n>Create Purchase Order</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="create-po"
- [(ngModel)]="createPurchaseOrder">
- </div>
-</div>
- <div class="row">
- <div class="col-lg-3">
- <label for="type-select" i18n>Ordering Agency</label>
- </div>
- <div class="col-lg-3">
- <eg-org-select
- [initialOrgId]="1"
- [applyOrgId]="orderingAgency"
- (onChange)="orgOnChange($event)">
- </eg-org-select>
- </div>
-
- <div class="col-lg-3">
- <label for="activate-po" i18n>Activate Purchase Order</label>
- </div>
-
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="activate-po"
- [(ngModel)]="activatePurchaseOrder">
- </div>
- </div>
-
- <div class="row">
- <div class="col-lg-3">
- <label for="year-select" i18n>Fiscal Year</label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #fiscalYearSelector
- id="year-select"
- [startId]="selectedFiscalYear"
- [entries]="formatEntries('fiscalYears')"
- (onChange)="selectEntry($event, 'fiscalYears')">
- </eg-combobox>
- </div>
- </div>
-
- <div class="row">
- <div class="col-lg-3">
- <label for="sl-select" i18n>Add to Selection List?</label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #selectionListSelector
- id="sl-select"
- [startId]="selectedSelectionList"
- [entries]="formatEntries('selectionLists')"
- (onChange)="selectEntry($event, 'selectionLists')">
- </eg-combobox>
- </div>
- </div>
-
-
- <h2>Upload Settings</h2>
-
- <div class="row">
- <div class="col-lg-3">
- <label for="source-select" i18n>Select a 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 class="col-lg-3">
- <label for="import-non-matching" i18n>Import Non-Matching Records</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- [required]="true"
- id="import-non-matching"
- [(ngModel)]="importNonMatching">
- </div>
- </div>
-
- <div class="row">
- <div class="col-lg-3">
- <label for="match-set-select" i18n>Record Match Set</label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #matchSetSelector
- id="match-set-select"
- [entries]="formatEntries('matchSets')"
- [disabled]="(selectedQueue && !selectedQueue.freetext) || importSelection()"
- [required]="true"
- [startId]="selectedMatchSet || defaultMatchSet"
- (onChange)="selectEntry($event, 'matchSets')">
- </eg-combobox>
- </div>
- <div class="col-lg-3">
- <label for="merge-on-exact" i18n>Merge On Exact Match (901c)</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="merge-on-exact" [(ngModel)]="mergeOnExact">
- </div>
- </div>
-
- <div class="row">
- <div class="col-lg-3">
- <label for="merge-profiles" i18n>Merge Profile</label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #mergeProfileSelector
- id="merge-profiles"
- [required]="true"
- [entries]="formatEntries('mergeProfiles')"
- (onChange)="selectEntry($event, 'mergeProfiles')"
- [startId]="selectedMergeProfile">
- </eg-combobox>
- </div>
- <div class="col-lg-3">
- <label for="merge-on-single" i18n>Merge On Single Match</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="merge-on-single" [(ngModel)]="mergeOnSingleMatch">
- </div>
- </div>
- <div class="row">
- <div class="col-lg-3">
- <label for="insuff-merge-profiles" i18n>
- Insufficient Quality Fall-Through Profile
- </label>
- </div>
- <div class="col-lg-3">
- <eg-combobox #fallThruMergeProfileSelector
- id="insuff-merge-profiles"
- [entries]="formatEntries('mergeProfiles')"
- (onChange)="selectEntry($event, 'FallThruMergeProfile')"
- [startId]="selectedFallThruMergeProfile">
- </eg-combobox>
- </div>
- <div class="col-lg-3">
- <label for="merge-on-best" i18n>Merge On Best Match</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="merge-on-best" [(ngModel)]="mergeOnBestMatch">
- </div>
- </div>
- <div class="row">
- <div class="col-lg-3">
- <label for="min-quality-ratio" i18n>
- Best/Single Match Minimum Quality Ratio
- </label>
- </div>
- <div class="col-lg-3">
- <input type="number" step="0.1" id="min-quality-ratio"
- class="form-control" [(ngModel)]="minQualityRatio">
- </div>
- <div class="col-lg-3">
- <label for="load-items" i18n>Load Items for Imported Records</label>
- </div>
- <div class="col-lg-3">
- <input class="form-check-input" type="checkbox"
- id="load-items"
- [(ngModel)]="loadItems">
- </div>
- </div>
-
- <h2>This Upload</h2>
- <div class="row">
- <div class="col-lg-3">
- <label for="queue-select" i18n>Select or Create a Queue</label>
- </div>
- <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">
- </eg-combobox>
- </div>
- </div>
- <div class="row" *ngIf="!importSelection()">
- <div class="col-lg-3">
- <label for="upload-file" i18n>File to Upload:</label>
- </div>
- <div class="col-lg-3">
- <input #fileSelector (change)="fileSelected($event)"
- id="upload-file" required class="form-control" type="file"/>
- </div>
- </div>
- <div class="row" *ngIf="importSelection()">
- <div class="col-lg-3">
- <label>Import Selected</label>
- </div>
- <div class="col-lg-3">
- <span *ngIf="!importSelection().importQueue" i18n>
- Importing {{importSelection().recordIds.length}} Record(s)</span>
- <span *ngIf="importSelection().importQueue" i18n>
- Importing Queue {{importSelection().queue.name()}}</span>
- </div>
- <div class="col-lg-3">
- <button class="btn btn-outline-info ml-2" (click)="clearSelection()" i18n>
- Clear Selection
- </button>
- </div>
- </div>
- <div class="row">
- <div class="col-lg-6 offset-lg-3">
- <button class="btn btn-success btn-lg btn-block font-weight-bold"
- [disabled]="isUploading || !hasNeededData()"
- (click)="upload()" i18n>Upload</button>
- </div>
- </div>
- <div class="row" [hidden]="!showProgress || importSelection()">
- <div class="col-lg-3">
- <label i18n>Upload 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>
- <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>
- </div>
-</div>
\ No newline at end of file
+++ /dev/null
-import {Component, OnInit, AfterViewInit, Input,
- ViewChild, OnDestroy} from '@angular/core';
-import {Subject} from 'rxjs';
-import {tap} from 'rxjs/operators';
-import {IdlObject} from '@eg/core/idl.service';
-import {NetService} from '@eg/core/net.service';
-import {EventService} from '@eg/core/event.service';
-import {OrgService} from '@eg/core/org.service';
-import {AuthService} from '@eg/core/auth.service';
-import {ToastService} from '@eg/share/toast/toast.service';
-import {ComboboxComponent,
- ComboboxEntry} from '@eg/share/combobox/combobox.component';
-import {VandelayImportSelection,
- VANDELAY_UPLOAD_PATH} from '@eg/staff/cat/vandelay/vandelay.service';
-import {HttpClient, HttpRequest, HttpEventType} from '@angular/common/http';
-import {HttpResponse, HttpErrorResponse} from '@angular/common/http';
-import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component';
-import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
-import {ServerStoreService} from '@eg/core/server-store.service';
-import {PicklistUploadService} from './upload.service';
-import {OrgSelectComponent} from '@eg/share/org-select/org-select.component'
-
-
-const TEMPLATE_SETTING_NAME = 'eg.acq.picklist.upload.templates';
-
-const TEMPLATE_ATTRS = [
- 'createPurchaseOrder',
- 'activatePurchaseOrder',
- 'orderingAgency',
- 'selectedFiscalYear',
- 'loadItems',
- 'selectedBibSource',
- 'selectedMatchSet',
- 'mergeOnExact',
- 'importNonMatching',
- 'mergeOnBestMatch',
- 'mergeOnSingleMatch',
- 'selectedMergeProfile',
- 'selectedFallThruMergeProfile',
- 'minQualityRatio'
-];
-
-interface ImportOptions {
- session_key: string;
- overlay_map?: {[qrId: number]: /* breId */ number};
- // import_no_match?: boolean;
- // auto_overlay_exact?: boolean;
- // auto_overlay_best_match?: boolean;
- // auto_overlay_1match?: boolean;
- // merge_profile?: any;
- // fall_through_merge_profile?: any;
-// match_quality_ratio: number;
- // match_set: number;
- // bib_source: number;
- exit_early: boolean;
-}
-
-@Component({
- templateUrl: './upload.component.html'
-})
-export class UploadComponent implements OnInit, AfterViewInit, OnDestroy {
-
- recordType: string;
- selectedQueue: ComboboxEntry; // freetext enabled
-
- // used for applying a default queue ID value when we have
- // a load-time queue before the queue combobox entries exist.
- startQueueId: number;
-
- activeQueueId: number;
- orderingAgency: number;
- selectedFiscalYear: number;
- selectedSelectionList: number;
- selectedBibSource: number;
- selectedProvider: number;
- selectedMatchSet: number;
- importDefId: number;
- selectedMergeProfile: number;
- selectedFallThruMergeProfile: number;
- selectedFile: File;
-
- defaultMatchSet: string;
-
- createPurchaseOrder: boolean;
- activatePurchaseOrder: boolean;
- loadItems: boolean;
-
- importNonMatching: boolean;
- mergeOnExact: boolean;
- mergeOnSingleMatch: boolean;
- mergeOnBestMatch: boolean;
- minQualityRatio: number;
-
- // True after the first upload, then remains true.
- showProgress: boolean;
-
- // Upload in progress.
- isUploading: boolean;
-
- // True only after successful upload
- uploadComplete: boolean;
-
- // Upload / processsing session key
- // Generated by the server
- sessionKey: string;
-
-
- selectedTemplate: string;
- formTemplates: {[name: string]: any};
- newTemplateName: string;
-
- @ViewChild('fileSelector', { static: false }) private fileSelector;
- @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 })
- private bibSourceSelector: ComboboxComponent;
- @ViewChild('providerSelector', {static: true})
- private providerSelector: ComboboxComponent;
- @ViewChild('fiscalYearSelector', { static: true })
- private fiscalYearSelector: ComboboxComponent;
- @ViewChild('selectionListSelector', { static: true })
- private selectionListSelector: ComboboxComponent;
- @ViewChild('matchSetSelector', { static: true })
- private matchSetSelector: ComboboxComponent;
- @ViewChild('mergeProfileSelector', { static: true })
- private mergeProfileSelector: ComboboxComponent;
- @ViewChild('fallThruMergeProfileSelector', { static: true })
- private fallThruMergeProfileSelector: ComboboxComponent;
- @ViewChild('dupeQueueAlert', { static: true })
- private dupeQueueAlert: AlertDialogComponent;
-
- constructor(
- private http: HttpClient,
- private toast: ToastService,
- private evt: EventService,
- private net: NetService,
- private auth: AuthService,
- private org: OrgService,
- private store: ServerStoreService,
- private vlagent: PicklistUploadService
- ) {
- this.applyDefaults();
- }
-
- applyDefaults() {
- this.minQualityRatio = 0;
- this.selectedBibSource = 1; // default to system local
- this.recordType = 'bib';
- this.formTemplates = {};
-//To-do add default for fiscal year
- if (this.vlagent.importSelection) {
-
- if (!this.vlagent.importSelection.queue) {
- // Incomplete import selection, clear it.
- this.vlagent.importSelection = null;
- return;
- }
-
- 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();
-
-
- }
- }
-
- ngOnInit() {}
-
- ngAfterViewInit() {
- this.loadStartupData();
- }
-
- ngOnDestroy() {
- // Always clear the import selection when navigating away from
- // the import page.
- this.clearSelection();
- }
-
- importSelection(): VandelayImportSelection {
- return this.vlagent.importSelection;
- }
-
- loadStartupData(): Promise<any> {
-
-
- const promises = [
- this.vlagent.getMergeProfiles(),
- this.vlagent.getAllQueues('bib'),
- this.vlagent.getMatchSets('bib'),
- this.vlagent.getBibSources(),
- this.vlagent.getFiscalYears(),
- 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.loadTemplates()
- ];
-
- return Promise.all(promises);
- }
-
- orgOnChange(org: IdlObject) {
- this.orderingAgency = org.id()
- }
-
- loadTemplates() {
- this.store.getItem(TEMPLATE_SETTING_NAME).then(
- templates => {
- this.formTemplates = templates || {};
-
- Object.keys(this.formTemplates).forEach(name => {
- if (this.formTemplates[name].default) {
- this.selectedTemplate = name;
- }
- });
- }
- );
- }
-
- formatTemplateEntries(): ComboboxEntry[] {
- const entries = [];
-
- Object.keys(this.formTemplates || {}).forEach(
- name => entries.push({id: name, label: name}));
-
- return entries;
- }
-
- // Format typeahead data sets
- formatEntries(etype: string): ComboboxEntry[] {
- const rtype = this.recordType;
- let list;
-
- switch (etype) {
- case 'bibSources':
- return (this.vlagent.bibSources || []).map(
- s => {
- return {id: s.id(), label: s.source()};
- });
-
- case 'providersList':
- return (this.vlagent.providersList || []).map(
- p => {
- return {id: p.id(), label: p.code()};
- });
-
- case 'fiscalYears':
- return (this.vlagent.fiscalYears || []).map(
- fy => {
- return {id: fy.id(), label: fy.year()};
- });
- break;
-
- case 'selectionLists':
- list = this.vlagent.selectionLists;
- break;
-
- case 'activeQueues':
- list = (this.vlagent.allQueues[rtype] || [])
- .filter(q => q.complete() === 'f');
- break;
-
- case 'matchSets':
- list = this.vlagent.matchSets['bib'];
- break;
-
-
- case 'importItemDefs':
- list = this.vlagent.importItemAttrDefs;
- break;
-
- case 'mergeProfiles':
- list = this.vlagent.mergeProfiles;
- break;
- }
-
- return (list || []).map(item => {
- return {id: item.id(), label: item.name()};
- });
- }
-
- selectEntry($event: ComboboxEntry, etype: string) {
- const id = $event ? $event.id : null;
-
- switch (etype) {
- case 'recordType':
- this.recordType = id;
- break;
-
- case 'providersList':
- this.selectedProvider = id;
- break;
-
- case 'bibSources':
- this.selectedBibSource = id;
- break;
-
- case 'fiscalYears':
- this.selectedFiscalYear = id;
- break;
-
- case 'selectionLists':
- this.selectedSelectionList = id;
- break;
-
- case 'matchSets':
- this.selectedMatchSet = id;
- break;
-
-
- case 'mergeProfiles':
- this.selectedMergeProfile = id;
- break;
-
- case 'FallThruMergeProfile':
- this.selectedFallThruMergeProfile = id;
- break;
- }
- }
-
- fileSelected($event) {
- 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;
- }
-
- // 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.resolveQueue()
- .then(
- queueId => {
- this.activeQueueId = queueId;
- return this.uploadFile();
- },
- err => Promise.reject('queue create failed')
- ).then(
- ok => this.processUpload(),
- err => Promise.reject('process spool failed')
- ).then(
- ok => {
- this.isUploading = false;
- this.uploadComplete = true;
- },
- err => {
- console.log('file upload failed: ', err);
- this.isUploading = false;
- this.resetProgressBars();
-
- }
- );
- }
-
- resetProgressBars() {
- 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,
- this.importDefId,
- this.selectedMatchSet,
- ).then(
- id => id,
- err => {
- const evt = this.evt.parse(err);
- if (evt) {
- if (evt.textcode.match(/QUEUE_EXISTS/)) {
- this.dupeQueueAlert.open();
- } else {
- alert(evt); // server error
- }
- }
-
- return Promise.reject('Queue Create Failed');
- }
- );
- } else {
- return Promise.resolve(this.selectedQueue.id);
- }
- }
-
- uploadFile(): Promise<any> {
-
- if (this.vlagent.importSelection) {
- // Nothing to upload when processing pre-queued records.
- return Promise.resolve();
- }
-
- const formData: FormData = new FormData();
-
- formData.append('ses', this.auth.token());
- formData.append('marc_upload',
- this.selectedFile, this.selectedFile.name);
-
- if (this.selectedBibSource) {
- formData.append('bib_source', '' + this.selectedBibSource);
- }
-
- const req = new HttpRequest('POST', VANDELAY_UPLOAD_PATH, formData,
- {reportProgress: true, responseType: 'text'});
-
- return this.http.request(req).pipe(tap(
- evt => {
- if (evt.type === HttpEventType.UploadProgress) {
- this.uploadProgress.update(
- {value: evt.loaded, max: evt.total});
-
- } else if (evt instanceof HttpResponse) {
- this.sessionKey = evt.body as string;
- console.log(
- 'vlagent file uploaded OK with key ' + this.sessionKey);
- }
- },
-
- (err: HttpErrorResponse) => {
- console.error(err);
- this.toast.danger(err.error);
- }
- )).toPromise();
- }
-
- processUpload(): Promise<any> {
-
- if (this.vlagent.importSelection) {
- return Promise.resolve();
- }
-
- let spoolType = this.recordType;
-
- const vandelayOptions = {
- import_no_match: this.importNonMatching,
- auto_overlay_exact: this.mergeOnExact,
- auto_overlay_best_match: this.mergeOnBestMatch,
- auto_overlay_1match: this.mergeOnSingleMatch,
- merge_profile: this.selectedMergeProfile,
- fall_through_merge_profile: this.selectedFallThruMergeProfile,
- match_quality_ratio: this.minQualityRatio,
- bib_source: this.selectedBibSource,
- create_assets: this.loadItems,
- queue_name: this.selectedQueue.label
-
- }
-
-
- const args = {
-
- provider: this.selectedProvider,
- ordering_agency: this.orderingAgency,
- create_po: this.createPurchaseOrder,
- activate_po: this.activatePurchaseOrder,
- fiscal_year: this.selectedFiscalYear,
- picklist: this.selectedSelectionList,
- vandelay: vandelayOptions
- }
-
-
- const method = `open-ils.acq.process_upload_records`;
-
- return new Promise((resolve, reject) => {
- this.net.request(
- '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(); }
- }
- );
- });
- }
-
- clearSelection() {
- this.vlagent.importSelection = null;
- this.startQueueId = null;
- }
-
- openQueue() {
- console.log('opening queue ' + this.activeQueueId);
- }
-
- saveTemplate() {
-
- const template = {};
- TEMPLATE_ATTRS.forEach(key => template[key] = this[key]);
-
- console.debug('Saving import profile', template);
-
- this.formTemplates[this.selectedTemplate] = template;
- return this.store.setItem(TEMPLATE_SETTING_NAME, this.formTemplates);
- }
-
- markTemplateDefault() {
-
- Object.keys(this.formTemplates).forEach(
- name => delete this.formTemplates.default
- );
-
- this.formTemplates[this.selectedTemplate].default = true;
-
- return this.store.setItem(TEMPLATE_SETTING_NAME, this.formTemplates);
- }
-
- templateSelectorChange(entry: ComboboxEntry) {
-
- if (!entry) {
- this.selectedTemplate = '';
- return;
- }
-
- 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);
- }
-
- deleteTemplate() {
- delete this.formTemplates[this.selectedTemplate];
- this.formTemplateSelector.selected = null;
- return this.store.setItem(TEMPLATE_SETTING_NAME, this.formTemplates);
- }
-}
-
+++ /dev/null
-import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs';
-import {tap, map} from 'rxjs/operators';
-import {HttpClient} from '@angular/common/http';
-import {saveAs} from 'file-saver';
-import {IdlService, IdlObject} from '@eg/core/idl.service';
-import {OrgService} from '@eg/core/org.service';
-import {NetService} from '@eg/core/net.service';
-import {AuthService} from '@eg/core/auth.service';
-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'
-
-
-@Injectable()
-export class PicklistUploadService {
-
- allQueues: {[qtype: string]: IdlObject[]};
- attrDefs: {[atype: string]: IdlObject[]};
- bibSources: IdlObject[];
- matchSets: {[stype: string]: IdlObject[]};
- importItemAttrDefs: IdlObject[];
- mergeProfiles: IdlObject[];
- providersList: IdlObject[];
- fiscalYears: IdlObject[];
- selectionLists: IdlObject[];
-
- // 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;
-
- constructor(
- private http: HttpClient,
- private idl: IdlService,
- private org: OrgService,
- private evt: EventService,
- private net: NetService,
- private auth: AuthService,
- private pcrud: PcrudService,
- private perm: PermService
- ) {
- this.attrDefs = {};
- this.allQueues = {};
- this.matchSets = {};
- this.importSelection = null;
- this.queuePageOffset = 0;
- }
-
- getAttrDefs(dtype: string): Promise<IdlObject[]> {
- if (this.attrDefs[dtype]) {
- return Promise.resolve(this.attrDefs[dtype]);
- }
- const cls = (dtype === 'bib') ? 'vqbrad' : 'vqarad';
- const orderBy = {};
- orderBy[cls] = 'id';
- return this.pcrud.retrieveAll(cls,
- {order_by: orderBy}, {atomic: true}).toPromise()
- .then(list => {
- this.attrDefs[dtype] = list;
- return list;
- });
- }
-
- getMergeProfiles(): Promise<IdlObject[]> {
- if (this.mergeProfiles) {
- return Promise.resolve(this.mergeProfiles);
- }
-
- const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
- return this.pcrud.search('vmp',
- {owner: owners}, {order_by: {vmp: ['name']}}, {atomic: true})
- .toPromise().then(profiles => {
- this.mergeProfiles = profiles;
- return profiles;
- });
- }
-
- getProvidersList(): Promise<IdlObject[]> {
- if (this.providersList) {
- return Promise.resolve(this.providersList);
- }
-
- const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
- return this.pcrud.search('acqpro',
- {owner: owners}, {order_by: {acqpro: ['code']}}, {atomic: true})
- .toPromise().then(providers => {
- this.providersList = providers;
- return providers;
- });
- }
-
- getSelectionLists(): Promise<IdlObject[]> {
- if (this.selectionLists) {
- return Promise.resolve(this.selectionLists);
- }
-
- const owners = this.auth.user().id();
- return this.pcrud.search('acqpl',
- {owner: owners}, {order_by: {acqpl: ['name']}}, {atomic: true})
- .toPromise().then(lists => {
- this.selectionLists = lists;
- 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]);
- } else {
- 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`,
- this.auth.token()
- ).pipe(tap(
- queue => this.allQueues[qtype].push(queue)
- )).toPromise().then(() => this.allQueues[qtype]);
- }
-
- getBibSources(): Promise<IdlObject[]> {
- if (this.bibSources) {
- return Promise.resolve(this.bibSources);
- }
-
- return this.pcrud.retrieveAll('cbs',
- {order_by: {cbs: 'id'}},
- {atomic: true}
- ).toPromise().then(sources => {
- this.bibSources = sources;
- return sources;
- });
- }
-
- getFiscalYears(): Promise<IdlObject[]> {
- if (this.fiscalYears) {
- return Promise.resolve(this.fiscalYears);
- }
-
- return this.pcrud.retrieveAll('acqfy',
- {order_by: {acqfy: 'year'}},
- {atomic: true}
- ).toPromise().then(years => {
- this.fiscalYears = years;
- return years;
- });
- }
-
- getItemImportDefs(): Promise<IdlObject[]> {
- if (this.importItemAttrDefs) {
- return Promise.resolve(this.importItemAttrDefs);
- }
-
- const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
- return this.pcrud.search('viiad', {owner: owners}, {}, {atomic: true})
- .toPromise().then(defs => {
- this.importItemAttrDefs = defs;
- return defs;
- });
- }
-
- // todo: differentiate between biblio and authority a la queue api
- getMatchSets(mtype: string): Promise<IdlObject[]> {
-
- const mstype = mtype.match(/bib/) ? 'biblio' : 'authority';
-
- if (this.matchSets[mtype]) {
- return Promise.resolve(this.matchSets[mtype]);
- } else {
- this.matchSets[mtype] = [];
- }
-
- const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
-
- return this.pcrud.search('vms',
- {owner: owners, mtype: mstype}, {}, {atomic: true})
- .toPromise().then(sets => {
- this.matchSets[mtype] = sets;
- return sets;
- });
- }
-
-
-
-
-
-
- // Create a queue and return the ID of the new queue via promise.
- createQueue(
- queueName: string,
- recordType: string,
- importDefId: number,
- matchSet: number): Promise<number> {
-
- const method = `open-ils.vandelay.${recordType}_queue.create`;
-
- 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,
- 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);
- 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';
- }
-
- saveName += '.mrc';
-
- this.http.get(url, {responseType: 'text'}).subscribe(
- data => {
- saveAs(
- new Blob([data], {type: 'application/octet-stream'}),
- saveName
- );
- },
- err => {
- console.error(err);
- }
- );
- }
-}
-
{ path: 'provider',
loadChildren: () =>
import('./provider/acq-provider.module').then(m => m.AcqProviderModule)
- },
- { path: 'picklist',
- loadChildren: () =>
- import('./picklist/acq-picklist.module').then(m => m.AcqPicklistModule)
}
];
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
- routerLink="/staff/acq/picklist/upload">
- <span class="material-icons" aria-hidden="true">cloud_upload</span>
- <span i18n>Load MARC Order Records</span>
- </a>
+ href="/eg/staff/acq/legacy/picklist/upload">
+ <span class="material-icons" aria-hidden="true">cloud_upload</span>
+ <span i18n>Load MARC Order Records</span>
+ </a>
<a class="dropdown-item"
routerLink="/staff/acq/search/purchaseorders">
<span class="material-icons" aria-hidden="true">shopping_cart</span>
(2,'usrname'),
(3,'fullname')
;
-
-INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
-VALUES (
- 'eg.acq.picklist.upload.templates', 'acq', 'object',
- oils_i18n_gettext(
- 'eg.acq.picklist.upload.templates',
- 'Picklist Upload Form Templates',
- 'cwst', 'label'
- )
-);
+++ /dev/null
-BEGIN;
-
-SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
-
-INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
-VALUES (
- 'eg.acq.picklist.upload.templates','acq','object',
- oils_i18n_gettext(
- 'eg.acq.picklist.upload.templates',
- 'Acq Picklist Uploader Templates',
- 'cwst','label'
- )
-);
-
-COMMIT;
\ No newline at end of file
</li>
<li class="divider"></li>
<li>
- <a href="/eg2/staff/acq/picklist/upload" target="_self">
+ <a href="./acq/legacy/picklist/upload" target="_self">
<span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span>
[% l('Load MARC Order Records') %]
</a>