</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
+ <create permission="CREATE_PATRON_STAT_CAT" context_field="owner"/>
<retrieve permission="STAFF_LOGIN" global_required="true"/>
+ <update permission="UPDATE_PATRON_STAT_CAT" context_field="owner"/>
+ <delete permission="DELETE_PATRON_STAT_CAT" context_field="owner"/>
</actions>
</permacrud>
</class>
</actions>
</permacrud>
</class>
- <class id="actsce" controller="open-ils.cstore" oils_obj:fieldmapper="actor::stat_cat_entry" oils_persist:tablename="actor.stat_cat_entry" reporter:label="User Stat Cat Entry">
+ <class id="actsce" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::stat_cat_entry" oils_persist:tablename="actor.stat_cat_entry" reporter:label="User Stat Cat Entry">
<fields oils_persist:primary="id" oils_persist:sequence="actor.stat_cat_entry_id_seq">
<field reporter:label="Entry ID" name="id" reporter:datatype="id" />
<field reporter:label="Entry Owner" name="owner" reporter:datatype="link"/>
<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
<link field="default_entries" reltype="has_many" key="stat_cat_entry" map="" class="actsced"/>
</links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </create>
+ <retrieve permission="STAFF_LOGIN" global_required="true"/>
+ <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </update>
+ <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </delete>
+ </actions>
+ </permacrud>
</class>
- <class id="actsced" controller="open-ils.cstore" oils_obj:fieldmapper="actor::stat_cat_entry_default" oils_persist:tablename="actor.stat_cat_entry_default" reporter:label="User Stat Cat Default Entry">
+ <class id="actsced" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::stat_cat_entry_default" oils_persist:tablename="actor.stat_cat_entry_default" reporter:label="User Stat Cat Default Entry">
<fields oils_persist:primary="id" oils_persist:sequence="actor.stat_cat_entry_default_id_seq">
<field reporter:label="Default Entry ID" name="id" reporter:datatype="id" />
<field reporter:label="Default Entry Value" name="stat_cat_entry" reporter:datatype="link"/>
<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
<link field="stat_cat_entry" reltype="has_a" key="id" map="" class="actsce"/>
</links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </create>
+ <retrieve permission="STAFF_LOGIN" global_required="true"/>
+ <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </update>
+ <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </delete>
+ </actions>
+ </permacrud>
</class>
<class id="cubi" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::user_bucket_item" oils_persist:tablename="container.user_bucket_item" reporter:label="User Bucket Item">
<fields oils_persist:primary="id" oils_persist:sequence="container.user_bucket_item_id_seq">
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
+ <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </create>
<retrieve permission="STAFF_LOGIN" global_required="true"/>
+ <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </update>
+ <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+ <context link="stat_cat" field="owner"/>
+ </delete>
</actions>
</permacrud>
</class>
<eg-link-table-link i18n-label label="Standing Penalties"
routerLink="/staff/admin/local/config/standing_penalty"></eg-link-table-link>
<eg-link-table-link i18n-label label="Statistical Categories Editor"
- url="/eg/staff/admin/local/asset/stat_cat_editor"></eg-link-table-link>
+ routerLink="/staff/admin/local/asset/stat_cat_editor"></eg-link-table-link>
<eg-link-table-link i18n-label label="Statistical Popularity Badges"
routerLink="/staff/admin/local/rating/badge"></eg-link-table-link>
<eg-link-table-link i18n-label label="Surveys"
}, {
path: 'actor/address_alert',
component: AddressAlertComponent
+}, {
+ path: 'asset/stat_cat_editor',
+ loadChildren: () =>
+ import('./stat_cat/stat_cat.module').then(m => m.StatCatModule)
}, {
path: 'container/carousel',
component: AdminCarouselComponent
--- /dev/null
+<eg-staff-banner bannerText="Statistical Category Editor" i18n-bannerText></eg-staff-banner>
+<div class="row">
+ <div class="col-lg-12">
+ <ngb-tabset #scTabs [activeId]="currentTab" (tabChange)="onTabChange($event)">
+ <ngb-tab title="Copy Statistical Categories" i18n-title id="'copy'">
+ <ng-template ngbTabContent>
+ <eg-fm-record-editor #copyDialog idlClass="asc"
+ preloadLinkedValues="true" requiredFields="name,owner"
+ readonlyFields="owner"
+ hiddenFieldsList="id"></eg-fm-record-editor>
+ <div class="col-lg-2 offset-lg-5 mt-3 mb-3">
+ <div class="text-center">Focus location</div>
+ <eg-org-select i18n-placeholder #focus
+ (onChange)="orgOnChange($event, 'copy')"
+ [hideOrgs]="disableCopyOrgs()"
+ [initialOrg]="selectedCopyOrg"></eg-org-select>
+ </div>
+ <eg-grid #copyGrid idlClass="asc" [dataSource]="ascDataSource"
+ hideFields="id" (onRowActivate)="editStatCat([$event])">
+ <eg-grid-toolbar-button label="New Copy Statistical Category"
+ i18n-label [action]="newStatCat"
+ [disabled]="!userPerms.canCreateCopy"></eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label
+ [action]="editStatCat"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label
+ [action]="deleteStatCat"></eg-grid-toolbar-action>
+ <ng-template #copyEntriesTmpl let-row="row">
+ <a href="staff/admin/local/asset/stat_cat_editor/copy_entries/{{row.id()}}">
+ Edit Entries
+ </a>
+ </ng-template>
+ <eg-grid-column i18n-label label="Entries"
+ [cellTemplate]="copyEntriesTmpl"></eg-grid-column>
+ </eg-grid>
+ </ng-template>
+ </ngb-tab>
+ <ngb-tab title="Patron Statistical Categories" i18n-title id="'patron'">
+ <ng-template ngbTabContent>
+ <eg-fm-record-editor #patronDialog idlClass="actsc"
+ preloadLinkedValues="true" requiredFields="name,owner"
+ readonlyFields="owner"
+ hiddenFieldsList="id"></eg-fm-record-editor>
+ <div class="col-lg-2 offset-lg-5 mt-3 mb-3">
+ <div class="text-center">Focus location</div>
+ <eg-org-select i18n-placeholder #focus
+ (onChange)="orgOnChange($event, 'patron')"
+ [hideOrgs]="disablePatronOrgs()"
+ [initialOrg]="selectedPatronOrg"></eg-org-select>
+ </div>
+ <eg-grid #patronGrid idlClass="actsc" [dataSource]="actscDataSource"
+ (onRowActivate)="editStatCat([$event])" hideFields="id">
+ <eg-grid-toolbar-button label="New Patron Statistical Category"
+ i18n-label [action]="newStatCat"
+ [disabled]="!userPerms.canCreatePatron"></eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label
+ [action]="editStatCat"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label
+ [action]="deleteStatCat"></eg-grid-toolbar-action>
+ <ng-template #patronEntriesTmpl let-row="row">
+ <a href="staff/admin/local/asset/stat_cat_editor/patron_entries/{{row.id()}}">
+ Edit Entries
+ </a>
+ </ng-template>
+ <eg-grid-column i18n-label label="Entries"
+ [cellTemplate]="patronEntriesTmpl"></eg-grid-column>
+ </eg-grid>
+ </ng-template>
+ </ngb-tab>
+ </ngb-tabset>
+ </div>
+</div>
+
+<eg-confirm-dialog #confirmDialog
+ i18n-dialogTitle i18n-dialogBody
+ dialogTitle="Warning"
+ dialogBody="One or more copy stat cats are currently in use. Delete all anyway?">
+</eg-confirm-dialog>
+
+<eg-string #createSuccessString i18n-text text="New record created"></eg-string>
+<eg-string #createErrString i18n-text text="Failed to create new record"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Deletion failed or was not allowed">
+</eg-string>
+<eg-string #deleteSuccessString i18n-text text="Deletion succeeded"></eg-string>
+<eg-string #updateFailedString i18n-text text="Update failed or was not allowed">
+</eg-string>
+<eg-string #updateSuccessString i18n-text text="Update succeeded"></eg-string>
--- /dev/null
+import {Pager} from '@eg/share/util/pager';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+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 {Component, OnInit, ViewChild} from '@angular/core';
+import {NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {OrgService} from '@eg/core/org.service';
+import {PermService} from '@eg/core/perm.service';
+import {AuthService} from '@eg/core/auth.service';
+import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
+
+@Component({
+ templateUrl: './stat_cat.component.html'
+})
+
+export class StatCatComponent implements OnInit {
+
+ currentTab: String;
+ ascDataSource: GridDataSource = new GridDataSource();
+ actscDataSource: GridDataSource = new GridDataSource();
+ selectedCopyOrg: IdlObject = this.org.get(this.auth.user().ws_ou());
+ selectedPatronOrg: IdlObject = this.org.get(this.auth.user().ws_ou());
+ selectedCopyOrgId: number = this.org.get(this.auth.user().ws_ou()).id();
+ selectedPatronOrgId: number = this.org.get(this.auth.user().ws_ou()).id();
+
+ // list of orgs to retrieve stat cats for
+ copyOrgFamily: any;
+ patronOrgFamily: any;
+
+ // object which has all permissions data for current user
+ userPerms: any = {};
+
+ // orgs that the user doesn't have permission to view.
+ hiddenCopyOrgs: any[];
+ hiddenPatronOrgs: any[];
+
+ newActsc: IdlObject;
+ newAsc: IdlObject;
+
+ // @ViewChild('confirmDialog') private confirmDialog: ConfirmDialogComponent;
+
+ @ViewChild('copyGrid') copyGrid: GridComponent;
+ @ViewChild('patronGrid') patronGrid: GridComponent;
+ @ViewChild('copyDialog') copyDialog: FmRecordEditorComponent;
+ @ViewChild('patronDialog') patronDialog: FmRecordEditorComponent;
+ @ViewChild('updateSuccessString') updateSuccessString: StringComponent;
+ @ViewChild('updateFailedString') updateFailedString: StringComponent;
+ @ViewChild('deleteFailedString') deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString') deleteSuccessString: StringComponent;
+ @ViewChild('createSuccessString') createSuccessString: StringComponent;
+ @ViewChild('createErrString') createErrString: StringComponent;
+
+ constructor(
+ private pcrud: PcrudService,
+ // private router: Router,
+ private route: ActivatedRoute,
+ private org: OrgService,
+ private idl: IdlService,
+ private toast: ToastService,
+ private perm: PermService,
+ private auth: AuthService,
+ ) {
+ }
+
+ ngOnInit() {
+ this.newActsc = this.idl.create('actsc');
+ this.newAsc = this.idl.create('asc');
+ this.perm.hasWorkPermAt(['CREATE_COPY_STAT_CAT', 'CREATE_PATRON_STAT_CAT',
+ 'UPDATE_PATRON_STAT_CAT', 'UPDATE_COPY_STAT_CAT', 'DELETE_COPY_STAT_CAT',
+ 'DELETE_PATRON_STAT_CAT'], true)
+ .then(userPerms => {
+ this.userPerms = userPerms;
+ const allOrgs = this.org.list();
+
+ // View permission is the same as permission to update,
+ // which is how it was handled in the old UI.
+ this.hiddenCopyOrgs = allOrgs.filter(x => {
+ return !this.userPerms.UPDATE_COPY_STAT_CAT.includes(x.id());
+ }).map(x => {
+ return x.id();
+ });
+ this.hiddenPatronOrgs = allOrgs.filter(x => {
+ return !this.userPerms.UPDATE_PATRON_STAT_CAT.includes(x.id());
+ }).map(x => {
+ return x.id();
+ });
+
+ this.setCurrentPerms();
+ this.getOrgFamilyAndData('copy');
+ this.copyGrid.reload();
+ });
+ }
+
+ disableCopyOrgs = () => this.org.filterList( { inList: this.hiddenCopyOrgs }, true);
+
+ disablePatronOrgs = () => this.org.filterList( { inList: this.hiddenCopyOrgs }, true);
+
+ setCurrentPerms() {
+ this.userPerms.canEditCopy =
+ this.userPerms.UPDATE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
+ this.userPerms.canEditPatron =
+ this.userPerms.UPDATE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
+ this.userPerms.canCreateCopy =
+ this.userPerms.CREATE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
+ this.userPerms.canCreatePatron =
+ this.userPerms.CREATE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
+ this.userPerms.canDeleteCopy =
+ this.userPerms.DELETE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
+ this.userPerms.canDeletePatron =
+ this.userPerms.DELETE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
+ }
+
+ onTabChange(event: NgbTabChangeEvent) {
+ this.currentTab = event.nextId;
+ if (this.currentTab === "patron") {
+ this.orgOnChange(this.selectedPatronOrg, 'patron');
+ } else {
+ this.orgOnChange(this.selectedCopyOrg, 'copy');
+ }
+ }
+
+ orgOnChange = (org: IdlObject, type): void => {
+ this.setCurrentPerms();
+ if (type === 'copy') {
+ this.selectedCopyOrg = org;
+ this.selectedCopyOrgId = org.id();
+ this.getOrgFamilyAndData('copy');
+ if (this.copyGrid) {
+ this.copyGrid.reload();
+ }
+ } else {
+ this.selectedPatronOrg = org;
+ this.selectedPatronOrgId = org.id();
+ this.getOrgFamilyAndData('patron');
+ if (this.patronGrid) {
+ this.patronGrid.reload();
+ }
+ }
+ }
+
+ getOrgFamilyAndData(type) {
+ if (type === 'copy') {
+ this.copyOrgFamily = this.org.fullPath(this.selectedCopyOrgId)
+ .map(record => {
+ return record.id();
+ });
+ this.getAscData();
+ } else {
+ this.patronOrgFamily = this.org.fullPath(this.selectedPatronOrgId)
+ .map(record => {
+ return record.id();
+ });
+ this.getActscData();
+ }
+ }
+
+ getAscData() {
+ this.ascDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy = {asc: 'id'};
+ return this.pcrud.search('asc', {owner: this.copyOrgFamily}, orderBy);
+ };
+ }
+
+ getActscData() {
+ this.actscDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy = {actsc: 'id'};
+ return this.pcrud.search('actsc', {owner: this.patronOrgFamily}, orderBy);
+ };
+ }
+
+ editStatCat = (idlThing) => {
+ const idlString = idlThing[0].classname;
+
+ // automatically fail if no permissions
+ if ((!this.userPerms.canEditCopy && idlString === 'asc') ||
+ (!this.userPerms.canEditPatron && idlString === 'actsc')) {
+ this.updateFailedString.current()
+ .then(str => this.toast.danger(str));
+ return;
+ }
+
+ const lookupResponse = this.lookUpType(idlString);
+ const currentGrid = lookupResponse.currentGrid;
+ const currentDialog = lookupResponse.currentDialog;
+ currentDialog.mode = 'update';
+ currentDialog.recordId = idlThing[0].id();
+ currentDialog.open({size: 'lg'}).subscribe(
+ id => {
+ console.debug('Record editor performed action');
+ currentGrid.reload();
+ },
+ err => {
+ console.debug(err);
+ },
+ () => console.debug('Dialog closed')
+ );
+ }
+
+ deleteStatCat = (idlThings: IdlObject[]) => {
+ const idlString = idlThings[0].classname;
+
+ // automatically fail if no permissions
+ if ((!this.userPerms.canDeleteCopy && idlString === 'asc') ||
+ (!this.userPerms.canDeletePatron && idlString === 'actsc')) {
+ this.deleteFailedString.current()
+ .then(str => this.toast.danger(str));
+ return;
+ }
+
+ // check to see if copy stat cat is in use
+ if (idlString === 'asc') {
+ this.checkThenDelete(idlThings, idlString)
+ } else {
+ this.doDelete(idlThings, idlString);
+ }
+ }
+
+ checkThenDelete = (idlThings, idlString) => {
+ let promises: any[] = [];
+ idlThings.forEach(idlThing => { // check one at a time to see if it's used
+ const id = idlThing.id();
+ let promise : any = new Promise((resolve, reject) => {
+ this.pcrud.search('ascecm', {stat_cat: id}, {limit: 1})
+ .toPromise().then(
+ rec => {
+ if (rec) {
+ this.deleteFailedString.current()
+ .then(str => this.toast.danger(str));
+ resolve(false);
+ } else {
+ resolve(true);
+ }
+ });
+ })
+ promises.push(promise);
+ });
+ let result = Promise.all(promises);
+ result.then(responses => {
+ if (!responses.includes(false)) { // only delete if none in use
+ this.doDelete(idlThings, idlString);
+ }
+ });
+ }
+
+ doDelete = (idlThings: IdlObject[], idlString) => {
+ idlThings.forEach(idlThing => {
+ idlThing.isdeleted(true);
+ });
+ const currentGrid = this.lookUpType(idlString).currentGrid;
+ this.pcrud.autoApply(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));
+ },
+ () => {
+ currentGrid.reload();
+ }
+ );
+ }
+
+ lookUpType = (idlString) => {
+ let currentDialog;
+ let currentGrid;
+ if (idlString === 'asc') {
+ currentGrid = this.copyGrid;
+ currentDialog = this.copyDialog;
+ } else {
+ currentGrid = this.patronGrid;
+ currentDialog = this.patronDialog;
+ }
+ return {
+ currentDialog: currentDialog,
+ currentGrid: currentGrid
+ };
+ }
+
+ newStatCat = (type: any) => {
+ let currentDialog;
+ let currentGrid;
+ let newIdlObject;
+ if (this.currentTab === 'patron') {
+ currentGrid = this.patronGrid;
+ currentDialog = this.patronDialog;
+ newIdlObject = this.idl.clone(this.newActsc);
+ newIdlObject.owner(this.selectedPatronOrg);
+ } else {
+ currentGrid = this.copyGrid;
+ currentDialog = this.copyDialog;
+ newIdlObject = this.idl.clone(this.newAsc);
+ newIdlObject.owner(this.selectedCopyOrg);
+ }
+ currentDialog.mode = 'create';
+ currentDialog.recordId = null;
+ currentDialog.record = newIdlObject;
+ currentDialog.open({size: 'lg'}).subscribe(
+ ok => {
+ this.createSuccessString.current()
+ .then(str => this.toast.success(str));
+ currentGrid.reload();
+ },
+ rejection => {
+ if (!rejection.dismissed) {
+ this.createErrString.current()
+ .then(str => this.toast.danger(str));
+ }
+ }
+ );
+ }
+
+}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {StatCatComponent} from './stat_cat.component';
+import {StatCatEntriesComponent} from './stat_cat_entries.component';
+import {StatCatRoutingModule} from './stat_cat_routing.module';
+
+@NgModule({
+ declarations: [
+ StatCatComponent,
+ StatCatEntriesComponent,
+ ],
+ imports: [
+ AdminCommonModule,
+ StatCatRoutingModule,
+ ],
+ exports: [],
+ providers: []
+})
+
+export class StatCatModule {}
--- /dev/null
+<eg-staff-banner bannerText="{{statCatType}} Statistical Category Entry Editor"
+ i18n-bannerText></eg-staff-banner>
+
+<ng-template #orgTemplate>
+ <eg-org-select [hideOrgs]="hiddenOrgs" (onChange)="setOwner($event)"
+ [initialOrgId]="statCatOrgId"></eg-org-select>
+</ng-template>
+
+<eg-fm-record-editor #patronDialog idlClass="actsce"
+ [fieldOptions]="{owner: {customTemplate: {template: orgTemplate}}}"
+ readonlyFieldsList="stat_cat"
+ requiredFields="value,owner" hiddenFieldsList="id"></eg-fm-record-editor>
+<eg-fm-record-editor #copyDialog idlClass="asce"
+ [fieldOptions]="{owner: {customTemplate: {template: orgTemplate}}}"
+ readonlyFieldsList="stat_cat"
+ requiredFields="value,owner" hiddenFieldsList="id"></eg-fm-record-editor>
+
+<div *ngIf="statCatType === 'Copy'">
+ <eg-grid #copyGrid [dataSource]="copyDataSource" idlClass="asce"
+ (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat">
+ <eg-grid-toolbar-button label="New Entry" i18n-label
+ [action]="createNewEntry"
+ [disabled]="!userPerms.canCreate"></eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label
+ [action]="editEntry"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label
+ [action]="deleteEntry"></eg-grid-toolbar-action>
+ </eg-grid>
+</div>
+<div *ngIf="statCatType === 'Patron'">
+ <eg-grid #patronGrid [dataSource]="patronDataSource" idlClass="actsce"
+ (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat">
+ <eg-grid-toolbar-button label="New Entry" i18n-label
+ [action]="createNewEntry"
+ [disabled]="!userPerms.canCreate"></eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label
+ [action]="editEntry"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label
+ [action]="deleteEntry"></eg-grid-toolbar-action>
+ </eg-grid>
+</div>
+
+<eg-string #createSuccessString i18n-text text="New entry Added"></eg-string>
+<eg-string #createErrString i18n-text text="Failed to create new entry"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Deletion failed or was not allowed">
+</eg-string>
+<eg-string #deleteSuccessString i18n-text text="Deletion succeeded"></eg-string>
+<eg-string #updateFailedString i18n-text text="Update failed or was not allowed">
+</eg-string>
+<eg-string #updateSuccessString i18n-text text="Update succeeded"></eg-string>
--- /dev/null
+import {Pager} from '@eg/share/util/pager';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {OrgService} from '@eg/core/org.service';
+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 {Component, OnInit, ViewChild} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {Router} from '@angular/router';
+import {PermService} from '@eg/core/perm.service';
+
+@Component({
+ templateUrl: './stat_cat_entries.component.html'
+})
+
+export class StatCatEntriesComponent implements OnInit {
+
+ statCatId: number; // parent stat cat id
+ statCatOrgId: number; // parent stat cat org id
+ statCatOrg: IdlObject; // parent stat cat org Idl
+ hiddenOrgs: any[]; // List of invalid orgs for a new entry
+ statCatType: 'Copy' | 'Patron'; // parent type
+ defaultNewRecord: IdlObject;
+ copyDataSource: GridDataSource = new GridDataSource();
+ patronDataSource: GridDataSource = new GridDataSource();
+ userPerms: any = {};
+
+ @ViewChild('copyGrid', {static: false}) copyGrid: GridComponent;
+ @ViewChild('patronGrid', {static: false}) patronGrid: GridComponent;
+ @ViewChild('copyDialog', {static: false}) copyDialog: FmRecordEditorComponent;
+ @ViewChild('patronDialog', {static: false}) patronDialog: FmRecordEditorComponent;
+ @ViewChild('updateSuccessString', {static: false}) updateSuccessString: StringComponent;
+ @ViewChild('updateFailedString', {static: false}) updateFailedString: StringComponent;
+ @ViewChild('deleteFailedString', {static: false}) deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString', {static: false}) deleteSuccessString: StringComponent;
+ @ViewChild('createSuccessString', {static: false}) createSuccessString: StringComponent;
+ @ViewChild('createErrString', {static: false}) createErrString: StringComponent;
+
+ constructor(
+ private router: Router,
+ private idl: IdlService,
+ private pcrud: PcrudService,
+ private route: ActivatedRoute,
+ private toast: ToastService,
+ private perm: PermService,
+ private org: OrgService
+ ) {
+ }
+
+ ngOnInit() {
+ this.statCatId = parseInt(this.route.snapshot.paramMap.get('id'), 10);
+ if (this.router.url.includes('copy_entries')) {
+ this.statCatType = 'Copy';
+ this.copyDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy: any = {order_by: {asce: 'id'}};
+ return this.pcrud.search('asce', {stat_cat: this.statCatId}, orderBy);
+ };
+ this.getParentData('asc');
+ } else if (this.router.url.includes('patron_entries')) {
+ this.statCatType = 'Patron';
+ this.patronDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy: any = {order_by: {actsce: 'id'}};
+ return this.pcrud.search('actsce', {stat_cat: this.statCatId}, orderBy);
+ };
+ this.getParentData('actsc');
+ } else {
+ console.debug('Error - unable to determine type of stat cat');
+ }
+ }
+
+ checkPerms = () => {
+ this.perm.hasWorkPermAt(['CREATE_COPY_STAT_CAT_ENTRY',
+ 'CREATE_PATRON_STAT_CAT_ENTRY', 'DELETE_COPY_STAT_CAT_ENTRY',
+ 'DELETE_PATRON_STAT_CAT_ENTRY', 'UPDATE_COPY_STAT_CAT_ENTRY',
+ 'UPDATE_PATRON_STAT_CAT_ENTRY'], true)
+ .then(userPerms => {
+ this.userPerms = userPerms;
+ if (this.statCatType === 'Copy') {
+ this.userPerms.canEdit =
+ this.userPerms.UPDATE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ this.userPerms.canCreate =
+ this.userPerms.CREATE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ this.userPerms.canDelete =
+ this.userPerms.DELETE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ } else {
+ this.userPerms.canEdit =
+ this.userPerms.UPDATE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ this.userPerms.canCreate =
+ this.userPerms.CREATE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ this.userPerms.canDelete =
+ this.userPerms.DELETE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
+ }
+ });
+ }
+
+ getParentData = (searchIdl) => {
+ return this.pcrud.search(searchIdl, {id: this.statCatId}, {}
+ ).subscribe(rec => {
+ this.statCatOrg = rec.owner();
+ this.statCatOrgId = rec.owner();
+ this.checkPerms();
+ const allOrgIds = this.org.list().map(x => x.id());
+ const statCatDescendantIds = this.org.descendants(rec.owner(), true);
+ this.hiddenOrgs = allOrgIds.filter(org => {
+ return !statCatDescendantIds.includes(org);
+ });
+ return rec;
+ });
+ }
+
+ setOwner(e): void {
+ this.defaultNewRecord.owner(e);
+ }
+
+ lookupType() {
+ let currentDialog;
+ let currentGrid;
+ let newIdl;
+ if (this.statCatType === 'Copy') {
+ currentGrid = this.copyGrid;
+ currentDialog = this.copyDialog;
+ newIdl = 'asce';
+ } else {
+ currentGrid = this.patronGrid;
+ currentDialog = this.patronDialog;
+ newIdl = 'actsce';
+ }
+ return {
+ currentGrid: currentGrid,
+ currentDialog: currentDialog,
+ newIdl: newIdl
+ };
+ }
+
+ createNewEntry = () => {
+ // automatically fail if no permissions
+ if (!this.userPerms.canCreate) {
+ this.createErrString.current()
+ .then(str => this.toast.danger(str));
+ return;
+ }
+
+ const lookupResponse = this.lookupType();
+ const currentDialog = lookupResponse.currentDialog;
+ const currentGrid = lookupResponse.currentGrid;
+ this.defaultNewRecord = this.idl.create(lookupResponse.newIdl);
+
+ // pre-populate new record with the current stat_cat and org
+ this.defaultNewRecord.owner(this.statCatOrg);
+ this.defaultNewRecord.stat_cat(this.statCatId);
+ currentDialog.mode = 'create';
+ currentDialog.recordId = null;
+ currentDialog.record = this.defaultNewRecord;
+ currentDialog.open({size: 'lg'}).subscribe(
+ ok => {
+ this.createSuccessString.current()
+ .then(str => this.toast.success(str));
+ currentGrid.reload();
+ },
+ rejection => {
+ if (!rejection.dismissed) {
+ this.createErrString.current()
+ .then(str => this.toast.danger(str));
+ }
+ }
+ );
+ }
+
+ editEntry = (idlThing) => {
+ // automatically fail if no permissions
+ if (!this.userPerms.canEdit) {
+ this.updateFailedString.current()
+ .then(str => this.toast.danger(str));
+ return;
+ }
+
+ const lookupResponse = this.lookupType();
+ const currentDialog = lookupResponse.currentDialog;
+ const currentGrid = lookupResponse.currentGrid;
+ currentDialog.mode = 'update';
+ currentDialog.recordId = idlThing[0].id();
+ currentDialog.open({size: 'lg'}).subscribe(
+ id => {
+ this.updateSuccessString.current()
+ .then(str => this.toast.success(str));
+ console.debug('Record editor performed action');
+ currentGrid.reload();
+ },
+ err => {
+ console.debug(err);
+ this.updateFailedString.current()
+ .then(str => this.toast.danger(str));
+ },
+ () => console.debug('Dialog closed')
+ );
+ }
+
+ deleteEntry = (idlThings: IdlObject[]) => {
+ // automatically fail if no permissions
+ if (!this.userPerms.canDelete) {
+ this.deleteFailedString.current()
+ .then(str => this.toast.danger(str));
+ return;
+ }
+
+ const currentGrid = this.lookupType().currentGrid;
+ idlThings.forEach(idlThing => idlThing.isdeleted(true));
+ this.pcrud.autoApply(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));
+ },
+ () => {
+ currentGrid.reload();
+ }
+ );
+ }
+
+}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {StatCatComponent} from './stat_cat.component';
+import {StatCatEntriesComponent} from './stat_cat_entries.component';
+
+const routes: Routes = [{
+ path: '',
+ component: StatCatComponent
+}, {
+ path: 'copy_entries/:id',
+ component: StatCatEntriesComponent
+}, {
+ path: 'patron_entries/:id',
+ component: StatCatEntriesComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+
+export class StatCatRoutingModule {}