From 34f206765e7ab8ebc4a2baad62ddb91115870296 Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Wed, 1 Apr 2020 18:02:25 -0400 Subject: [PATCH] basic EDI account management Signed-off-by: Galen Charlton --- .../staff/acq/provider/acq-provider.component.html | 4 +- .../staff/acq/provider/acq-provider.component.ts | 7 +- .../app/staff/acq/provider/acq-provider.module.ts | 2 + .../provider/provider-edi-accounts.component.html | 39 ++++ .../provider/provider-edi-accounts.component.ts | 213 +++++++++++++++++++++ .../staff/acq/provider/provider-record.service.ts | 22 ++- .../staff/acq/provider/summary-pane.component.ts | 4 +- 7 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.ts diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.html b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.html index 6493d24c45..ec691f6d9d 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.html +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.html @@ -59,7 +59,9 @@ - PROVIDER EDI TAB + + + diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.ts index bd009de421..6441229edf 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.component.ts @@ -31,7 +31,7 @@ export class AcqProviderComponent implements OnInit, AfterViewInit { onTabChange: ($event: NgbTabChangeEvent) => void; - onDesireSummarize: ($event: number) => void; + onDesireSummarize: ($event: number, updateSummaryOnly?: boolean) => void; onSummaryToggled: ($event: boolean) => void; constructor( @@ -81,12 +81,15 @@ export class AcqProviderComponent implements OnInit, AfterViewInit { } }; - this.onDesireSummarize = ($event) => { + this.onDesireSummarize = ($event, updateSummaryOnly = false) => { // $event is a provider ID this.providerSummaryPane.update($event); if (this.providerDetails) { this.providerDetails.refresh(); } + if (updateSummaryOnly) { + return; + } this.id = $event; this.providerRecord.fetch(this.id); this.showSearchForm = false; diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.module.ts b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.module.ts index fe1a25c7e7..cbfd46d9d0 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider.module.ts @@ -11,6 +11,7 @@ import {ProviderContactsComponent} from './provider-contacts.component'; import {ProviderContactAddressesComponent} from './provider-contact-addresses.component'; import {ProviderHoldingsComponent} from './provider-holdings.component'; import {ProviderAttributesComponent} from './provider-attributes.component'; +import {ProviderEdiAccountsComponent} from './provider-edi-accounts.component'; import {ProviderInvoicesComponent} from './provider-invoices.component'; import {ProviderPurchaseOrdersComponent} from './provider-purchase-orders.component'; import {OrgFamilySelectModule} from '@eg/share/org-family-select/org-family-select.module'; @@ -29,6 +30,7 @@ import {ProviderRecordService} from './provider-record.service'; ProviderContactAddressesComponent, ProviderHoldingsComponent, ProviderAttributesComponent, + ProviderEdiAccountsComponent, ProviderInvoicesComponent, ProviderPurchaseOrdersComponent, AcqProviderSummaryPaneComponent diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.html b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.html new file mode 100644 index 0000000000..34e5a31b42 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.ts new file mode 100644 index 0000000000..365faddd8b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-edi-accounts.component.ts @@ -0,0 +1,213 @@ +import {Component, OnInit, AfterViewInit, Input, Output, EventEmitter, ViewChild} from '@angular/core'; +import {empty, throwError, Observable, from} from 'rxjs'; +import {map} from 'rxjs/operators'; +import {Router, ActivatedRoute, ParamMap} from '@angular/router'; +import {Pager} from '@eg/share/util/pager'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridDataSource, GridCellTextGenerator} from '@eg/share/grid/grid'; +import {ProviderRecord, ProviderRecordService} from './provider-record.service'; +import {AcqProviderSearchFormComponent} from './acq-provider-search-form.component'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component'; + +@Component({ + selector: 'eg-provider-edi-accounts', + templateUrl: 'provider-edi-accounts.component.html', +}) +export class ProviderEdiAccountsComponent implements OnInit, AfterViewInit { + + edi_accounts: any[] = []; + + gridSource: GridDataSource; + @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent; + @ViewChild('acqProviderEdiAccountsGrid', { static: true }) providerEdiAccountsGrid: GridComponent; + @ViewChild('confirmSetAsDefault', { static: true }) confirmSetAsDefault: ConfirmDialogComponent; + @ViewChild('successString', { static: true }) successString: StringComponent; + @ViewChild('createString', { static: false }) createString: StringComponent; + @ViewChild('createErrString', { static: false }) createErrString: StringComponent; + @ViewChild('updateFailedString', { static: false }) updateFailedString: StringComponent; + @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent; + @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent; + @ViewChild('setAsDefaultSuccessString', { static: true }) setAsDefaultSuccessString: StringComponent; + @ViewChild('setAsDefaultFailedString', { static: true }) setAsDefaultFailedString: StringComponent; + + cellTextGenerator: GridCellTextGenerator; + provider: IdlObject; + selected: IdlObject; + + canCreate: boolean; + canDelete: boolean; + notOneSelectedRow: (rows: IdlObject[]) => boolean; + deleteSelected: (rows: IdlObject[]) => void; + + permissions: {[name: string]: boolean}; + + // Size of create/edito dialog. Uses large by default. + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + @Output('desireSummarize') summarize: EventEmitter = new EventEmitter(); + + constructor( + private router: Router, + private route: ActivatedRoute, + private net: NetService, + private idl: IdlService, + private auth: AuthService, + private providerRecord: ProviderRecordService, + private toast: ToastService) { + } + + ngOnInit() { + this.gridSource = this.getDataSource() + this.cellTextGenerator = {}; + this.notOneSelectedRow = (rows: IdlObject[]) => (rows.length !== 1); + this.deleteSelected = (idlThings: IdlObject[]) => { + idlThings.forEach(idlThing => idlThing.isdeleted(true)); + this.providerRecord.batchUpdate(idlThings).subscribe( + val => { + console.debug('deleted: ' + val); + this.deleteSuccessString.current() + .then(str => this.toast.success(str)); + }, + err => { + this.deleteFailedString.current() + .then(str => this.toast.danger(str)); + }, + () => { + this.providerRecord.refreshCurrent().then( + () => { + this.providerEdiAccountsGrid.reload(); + } + ); + } + ); + }; + this.providerEdiAccountsGrid.onRowActivate.subscribe( + (idlThing: IdlObject) => this.showEditDialog(idlThing) + ); + } + + ngAfterViewInit() { + console.log('this.providerRecord',this.providerRecord); + } + + getDataSource(): GridDataSource { + const gridSource = new GridDataSource(); + + gridSource.getRows = (pager: Pager, sort: any[]) => { + this.provider = this.providerRecord.current(); + if (!this.provider) { + return empty(); + } + let edi_accounts = this.provider.edi_accounts() + + if (sort.length > 0) { + edi_accounts = edi_accounts.sort((a, b) => { + for (let i = 0; i < sort.length; i++) { + let lt = -1; + let sfield = sort[i].name; + if (sort[i].dir.substring(0,1).toLowerCase() === 'd') { + lt *= -1; + } + if (a[sfield]() < b[sfield]()) { return lt } + if (a[sfield]() > b[sfield]()) { return lt * -1 } + } + return 0; + }); + + } + + return from(edi_accounts.slice(pager.offset, pager.offset + pager.limit - 1)); + }; + return gridSource; + } + + showEditDialog(providerEdiAccount: IdlObject): Promise { + this.editDialog.mode = 'update'; + this.editDialog.recordId = providerEdiAccount['id'](); + return new Promise((resolve, reject) => { + this.editDialog.open({size: this.dialogSize}).subscribe( + result => { + this.successString.current() + .then(str => this.toast.success(str)); + this.providerRecord.refreshCurrent().then( + () => this.providerEdiAccountsGrid.reload() + ); + resolve(result); + }, + error => { + this.updateFailedString.current() + .then(str => this.toast.danger(str)); + reject(error); + } + ); + }); + } + + editSelected(providerEdiAccountFields: IdlObject[]) { + // Edit each IDL thing one at a time + const editOneThing = (providerEdiAccount: IdlObject) => { + if (!providerEdiAccount) { return; } + + this.showEditDialog(providerEdiAccount).then( + () => editOneThing(providerEdiAccountFields.shift())); + }; + + editOneThing(providerEdiAccountFields.shift()); + } + + setAsDefault(providerEdiAccountFields: IdlObject[]) { + this.selected = providerEdiAccountFields[0]; + this.confirmSetAsDefault.open().subscribe(confirmed => { + if (!confirmed) { return; } + this.providerRecord.refreshCurrent().then(() => { + this.provider.edi_default(providerEdiAccountFields[0].id()); + this.provider.ischanged(true); + this.providerRecord.batchUpdate(this.provider).subscribe( + val => { + this.setAsDefaultSuccessString.current() + .then(str => this.toast.success(str)); + }, + err => { + this.setAsDefaultFailedString.current() + .then(str => this.toast.danger(str)); + }, + () => { + this.providerRecord.refreshCurrent(), + this.summarize.emit(this.provider.id()); + } + ); + }); + }); + } + + createNew() { + this.editDialog.mode = 'create'; + const edi_account = this.idl.create('acqedi'); + edi_account.provider(this.provider.id()); + edi_account.owner(this.auth.user().ws_ou()) + edi_account.use_attrs(true); + this.editDialog.record = edi_account; + this.editDialog.recordId = null; + this.editDialog.open({size: this.dialogSize}).subscribe( + ok => { + this.createString.current() + .then(str => this.toast.success(str)); + this.providerRecord.refreshCurrent().then( + () => this.providerEdiAccountsGrid.reload() + ); + }, + rejection => { + if (!rejection.dismissed) { + this.createErrString.current() + .then(str => this.toast.danger(str)); + } + } + ); + } + +} diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-record.service.ts b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-record.service.ts index bf971960de..be2b5e628b 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-record.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/provider-record.service.ts @@ -39,11 +39,16 @@ export class ProviderRecordService { return this.pcrud.search('acqpro', { id: id }, { flesh: 3, - flesh_fields: { acqpro: ['attributes','holdings_subfields', 'contacts', 'addresses', 'provider_notes'], + flesh_fields: { acqpro: [ + 'attributes', 'holdings_subfields', 'contacts', + 'addresses', 'provider_notes', + 'edi_accounts', + ], acqpa: ['provider'], acqpc: ['provider','addresses'], acqphsm: ['provider'], acqlipad:['provider'], + acqedi: ['attr_set'], } }, {} @@ -58,6 +63,21 @@ export class ProviderRecordService { return this.currentProvider ? this.currentProvider.record : null; } + // FIXME: ultimately, this is needed because eg-fm-record-editor currently can't + // handle records that have linked fields fleshed; if/when it could, + // we could just flesh edi_default and be done + currentEdiDefault(): Promise { + if (this.currentProviderId) { + if (this.currentProvider.record.edi_default()) { + return this.pcrud.retrieve('acqedi', this.currentProvider.record.edi_default()).toPromise(); + } else { + return Promise.resolve(null); + } + } else { + return Promise.reject(); + } + } + fetch(id: number): Promise { return new Promise((resolve, reject) => { this.getProviderRecord(id).subscribe( diff --git a/Open-ILS/src/eg2/src/app/staff/acq/provider/summary-pane.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/provider/summary-pane.component.ts index bc8b447d1a..38de105ef7 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/provider/summary-pane.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/provider/summary-pane.component.ts @@ -141,7 +141,9 @@ export class AcqProviderSummaryPaneComponent implements OnInit, AfterViewInit { this.provider_addresses = provider.addresses(); this.provider_san = provider.san(); if (provider.edi_default()) { - this.provider_edi_default = provider.edi_default().label(); + this.prov.currentEdiDefault().then(acqedi => { + this.provider_edi_default = acqedi.label(); + }); } else { this.provider_edi_default = ''; } -- 2.11.0