url="/eg/staff/admin/local/config/circ_matrix_matchpoint"></eg-link-table-link>
<eg-link-table-link i18n-label label="Closed Dates Editor"
url="/eg/staff/admin/local/actor/closed_dates"></eg-link-table-link>
+ <eg-link-table-link i18n-label label="Course Reserves List"
+ routerLink="/staff/admin/local/asset/course_list"></eg-link-table-link>
<eg-link-table-link i18n-label label="Event Definition Group Members"
routerLink="/staff/admin/local/action_trigger/event_def_group_member"></eg-link-table-link>
<eg-link-table-link i18n-label label="Event Definition Groups"
--- /dev/null
+<eg-string #deleteFailedString i18n-text text="Disassociation of Course Material failed or was not allowed"></eg-string>
+<eg-string #deleteSuccessString i18n-text text="Disassociation of Course Material succeeded"></eg-string>
+<eg-string #successString i18n-text text="Association of Course Material succeeded"></eg-string>
+<eg-string #failedString i18n-text text="Association of Course Material failed or was not allowed"></eg-string>
+<eg-string #differentLibraryString i18n-text text="Material exists at a different library"></eg-string>
+
+<ng-template #dialogContent>
+ <div class="modal-header bg-info">
+ <h4 class="modal-title" i18n>Course Materials</h4>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close" (click)="close()">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="row mt-3">
+ <div class="col-md-4">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Barcode</span>
+ </div>
+ <input type="text" [(ngModel)]="barcodeInput" />
+ </div>
+ </div>
+ <div class="col-md-5">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Relationship</span>
+ </div>
+ <input type="text" [(ngModel)]="relationshipInput" placeholder-i18n placeholder="e.g. Required" />
+ </div>
+ </div>
+ <div class="col-md-3">
+ <button class="btn btn-outline-dark" (click)="associateItem(barcodeInput, relationshipInput)" i18n [disabled]="!barcodeInput">Add Material</button>
+ </div>
+ </div>
+ <div class="row justify-content-center mt-3">
+ <div class="col">
+ <h5 i18n>The following fields will be applied to the material added, and reverted once the course is no longer associated with the material.</h5>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-md-6">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <div class="input-group-text">
+ <span i18n>Call Number</span>
+ </div>
+ </div>
+ <input type="text" [(ngModel)]="tempCallNumber"
+ (input)="isModifyingCallNumber = true"/>
+ <div class="input-group-append">
+ <div class="input-group-text">
+ <input type="checkbox" [(ngModel)]="isModifyingCallNumber"
+ aria-label="Checkbox for setting a temporary Call Number" />
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <div class="input-group-text">
+ <span i18n>Circulation Modifier</span>
+ </div>
+ </div>
+ <eg-combobox i18n-placeholder placeholder="Circulation Modifier..."
+ idlClass="ccm" idlField="name" [displayTemplate]="idlClassLabel"
+ [asyncSupportsEmptyTermClick]="true"
+ (onChange)="tempCircMod = $event.id; isModifyingCircMod = true">
+ </eg-combobox>
+ <div class="input-group-append">
+ <div class="input-group-text">
+ <input type="checkbox" [(ngModel)]="isModifyingCircMod"
+ aria-label="Checkbox for setting a temporary Circulation Modifier" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-md-6">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <div class="input-group-text">
+ <span i18n>Item Status</span>
+ </div>
+ </div>
+ <eg-combobox i18n-placeholder placeholder="Item Status..."
+ idlClass="ccs" idlField="name" [displayTemplate]="idlClassLabel"
+ [asyncSupportsEmptyTermClick]="true"
+ (onChange)="tempStatus = $event.id; isModifyingStatus = true">
+ </eg-combobox>
+ <div class="input-group-append">
+ <div class="input-group-text">
+ <input type="checkbox" [(ngModel)]="isModifyingStatus"
+ aria-label="Checkbox for setting a temporary Item Status" />
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <div class="input-group-text">
+ <span i18n>Shelving Location</span>
+ </div>
+ </div>
+ <eg-item-location-select permFilter="MANAGE_RESERVES"
+ [(ngModel)]="tempLocation" (oninput)="isModifyingLocation = true">
+ </eg-item-location-select>
+ <div class="input-group-append">
+ <div class="input-group-text">
+ <input type="checkbox" [(ngModel)]="isModifyingLocation"
+ aria-label="Checkbox for setting a temporary Shelving Location" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="mt-3">
+ <eg-grid #materialGrid [dataSource]="gridDataSource">
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
+ </eg-grid-toolbar-action>
+
+ <eg-grid-column path="id" [index]=true [hidden]="true" label="ID" i18n-label></eg-grid-column>
+ <eg-grid-column label="Barcode" i18n-label name="barcode" [cellTemplate]="barcodeCellTemplate"></eg-grid-column>
+ <eg-grid-column label="Title" i18n-label name="title" [cellTemplate]="titleCellTemplate"></eg-grid-column>
+ <eg-grid-column path="call_number.label" label="Call Number" i18n-label></eg-grid-column>
+ <eg-grid-column path="call_number.prefix.label" [hidden]="true" label="Call Number Prefix" i18n-label hidden></eg-grid-column>
+ <eg-grid-column path="call_number.suffix.label" [hidden]="true" label="Call Number Suffix" i18n-label hidden></eg-grid-column>
+ <eg-grid-column path="circ_modifier" [hidden]="true" label="Circulation Modifier" i18n-label></eg-grid-column>
+ <eg-grid-column path="circ_lib.shortname" label="Circulation Library" i18n-label></eg-grid-column>
+ <eg-grid-column path="location.name" [hidden]="true" label="Shelving Location" i18n-label></eg-grid-column>
+ <eg-grid-column path="status.name" [hidden]="true" label="Copy Status" i18n-label></eg-grid-column>
+ <eg-grid-column path="_relationship" label="Relationship" i18n-label></eg-grid-column>
+ </eg-grid>
+ </div>
+ </div>
+ <ng-template #barcodeCellTemplate let-entry="row">
+ <span>
+ <a class="pl-1"
+ href="/eg/staff/cat/item/{{entry.id()}}">
+ {{entry.barcode()}}
+ </a>
+ </span>
+ </ng-template>
+ <ng-template #titleCellTemplate let-entry="row">
+ <span>
+ <a class="pl-1"
+ href="/eg/staff/cat/catalog/record/{{entry.call_number().record()}}">
+ {{entry._title}}
+ </a>
+ </span>
+ </ng-template>
+ <ng-template #idlClassLabel let-r="result" i18n>
+ {{r.label}}
+ </ng-template>
+</ng-template>
\ No newline at end of file
--- /dev/null
+import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core';
+import {Observable, Observer, of} from 'rxjs';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {EventService} from '@eg/core/event.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {Pager} from '@eg/share/util/pager';
+import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {CourseService} from './course.service';
+
+@Component({
+ selector: 'eg-course-associate-material-dialog',
+ templateUrl: './course-associate-material.component.html'
+})
+
+export class CourseAssociateMaterialComponent extends DialogComponent {
+
+ @ViewChild('materialsGrid', {static: true}) materialsGrid: GridComponent;
+ @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
+ @ViewChild('successString', { static: true }) successString: StringComponent;
+ @ViewChild('failedString', { static: true }) failedString: StringComponent;
+ @ViewChild('differentLibraryString', { static: true }) differentLibraryString: StringComponent;
+ @Input() table_name = "Course Materials";
+ @Input() barcodeInput: String;
+ @Input() relationshipInput: String;
+ @Input() tempCallNumber: String;
+ @Input() tempStatus: Number;
+ @Input() tempLocation: Number;
+ @Input() tempCircMod: String;
+ @Input() isModifyingStatus: Boolean;
+ @Input() isModifyingCircMod: Boolean;
+ @Input() isModifyingCallNumber: Boolean;
+ @Input() isModifyingLocation: Boolean;
+ currentCourse: IdlObject;
+ materials: any[];
+ gridDataSource: GridDataSource;
+
+ constructor(
+ private auth: AuthService,
+ private idl: IdlService,
+ private net: NetService,
+ private pcrud: PcrudService,
+ private org: OrgService,
+ private evt: EventService,
+ private modal: NgbModal,
+ private toast: ToastService,
+ private courseSvc: CourseService
+ ) {
+ super(modal);
+ this.gridDataSource = new GridDataSource();
+ }
+
+ ngOnInit() {
+ this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
+ return this.fetchMaterials(pager);
+ }
+ }
+
+ deleteSelected(items) {
+ let item_ids = [];
+ items.forEach(item => {
+ this.gridDataSource.data.splice(this.gridDataSource.data.indexOf(item, 0), 1);
+ item_ids.push(item.id())
+ });
+ this.pcrud.search('acmcm', {course: this.currentCourse.id(), item: item_ids}).subscribe(material => {
+ material.isdeleted(true);
+ this.pcrud.autoApply(material).subscribe(
+ val => {
+ this.courseSvc.resetItemFields(material, this.currentCourse.owning_lib());
+ console.debug('deleted: ' + val);
+ this.deleteSuccessString.current().then(str => this.toast.success(str));
+ },
+ err => {
+ this.deleteFailedString.current()
+ .then(str => this.toast.danger(str));
+ }
+ );
+ });
+ }
+
+ associateItem(barcode, relationship) {
+ if (barcode) {
+ this.pcrud.search('acp', {barcode: barcode},
+ {flesh: 3, flesh_fields: {acp: ['call_number']}}).subscribe(item => {
+ let material = this.idl.create('acmcm');
+ material.item(item.id());
+ material.course(this.currentCourse.id());
+ if (relationship) material.relationship(relationship);
+ if (this.isModifyingStatus && this.tempStatus) {
+ material.original_status(item.status());
+ item.status(this.tempStatus);
+ }
+ if (this.isModifyingLocation && this.tempLocation) {
+ material.original_location(item.location());
+ item.location(this.tempLocation);
+ }
+ if (this.isModifyingCircMod) {
+ material.original_circ_modifier(item.circ_modifier());
+ item.circ_modifier(this.tempCircMod);
+ if (!this.tempCircMod) item.circ_modifier(null);
+ }
+ if (this.isModifyingCallNumber) {
+ material.original_callnumber(item.call_number());
+ }
+ this.pcrud.create(material).subscribe(
+ val => {
+ console.debug('created: ' + val);
+ let new_cn = item.call_number().label();
+ if (this.tempCallNumber) new_cn = this.tempCallNumber;
+ this.courseSvc.updateItem(item, this.currentCourse.owning_lib(), new_cn, this.isModifyingCallNumber).then(res => {
+ this.fetchItem(item.id(), relationship);
+ if (item.circ_lib() != this.currentCourse.owning_lib()) {
+ this.differentLibraryString.current().then(str => this.toast.warning(str));
+ } else {
+ this.successString.current().then(str => this.toast.success(str));
+ }
+ });
+
+ // Cleaning up inputs
+ this.barcodeInput = "";
+ this.relationshipInput = "";
+ this.tempStatus = null;
+ this.tempCircMod = null;
+ this.tempCallNumber = null;
+ this.tempLocation = null;
+ this.isModifyingCallNumber = false;
+ this.isModifyingCircMod = false;
+ this.isModifyingLocation = false;
+ this.isModifyingStatus = false;
+ }, err => {
+ this.failedString.current().then(str => this.toast.danger(str));
+ });
+ });
+ }
+ }
+
+ fetchMaterials(pager: Pager): Observable<any> {
+ return new Observable<any>(observer => {
+ this.materials.forEach(material => {
+ this.fetchItem(material.item, material.relationship);
+ });
+ observer.complete();
+ });
+ }
+
+ fetchItem(itemId, relationship): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.copy_details.retrieve',
+ this.auth.token(), itemId
+ ).subscribe(res => {
+ if (res) {
+ let item = res.copy;
+ item.call_number(res.volume);
+ item.circ_lib(this.org.get(item.circ_lib()));
+ item._title = res.mvr.title();
+ item._relationship = relationship;
+ this.gridDataSource.data.push(item);
+ }
+ }, err => {
+ reject(err);
+ }, () => resolve(this.gridDataSource.data));
+ });
+ }
+}
\ No newline at end of file
--- /dev/null
+<eg-staff-banner bannerText="Course List" i18n-bannerText>
+</eg-staff-banner>
+
+<eg-string #successString i18n-text text="{{table_name}} Update Succeeded"></eg-string>
+<eg-string #createString i18n-text text="{{table_name}} Was Created Successfully"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Delete of {{table_name}} failed or was not allowed"></eg-string>
+<eg-string #deleteSucailedString i18n-text text="Delete of {{table_name}} failed or was not allowed"></eg-string>
+<eg-string #archiveFailedString i18n-text text="Archival of {{table_name}} failed or was not allowed"></eg-string>
+<eg-string #archiveSuccessString i18n-text text="Archival of {{table_name}} succeeded"></eg-string>
+<eg-string #flairTooltip i18n-text text="Limited Editing"></eg-string>
+
+<eg-course-associate-material-dialog #courseMaterialDialog>
+</eg-course-associate-material-dialog>
+<div class="w-100 mt-2 mb-2">
+ <eg-grid #grid idlClass={{idl_class}}
+ [dataSource]="grid_source"
+ [sortable]="true">
+ <eg-grid-toolbar-button
+ label="Create {{table_name}}" (onClick)="createNew()" i18n-label>
+ </eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="View Materials" i18n-label (onClick)="openMaterialsDialog($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
+ </eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Archive Selected" i18n-label (onClick)="archiveSelected($event)">
+ </eg-grid-toolbar-action>
+ </eg-grid>
+</div>
+
+<eg-fm-record-editor #editDialog
+ idlClass={{idl_class}}
+ [preloadLinkedValues]="true"
+ hiddenFields="is_archived,id">
+</eg-fm-record-editor>
--- /dev/null
+import {Component, Input, ViewChild, OnInit} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {CourseService} from './course.service';
+import {NetService} from '@eg/core/net.service';
+import {OrgService} from '@eg/core/org.service';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {Pager} from '@eg/share/util/pager';
+import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+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 {CourseAssociateMaterialComponent
+ } from './course-associate-material.component';
+
+@Component({
+ templateUrl: './course-list.component.html'
+})
+
+export class CourseListComponent implements OnInit {
+
+ @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
+ @ViewChild('grid', { static: true }) grid: GridComponent;
+ @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('archiveFailedString', { static: true }) archiveFailedString: StringComponent;
+ @ViewChild('archiveSuccessString', { static: true }) archiveSuccessString: StringComponent;
+ @ViewChild('courseMaterialDialog', {static: true})
+ private courseMaterialDialog: CourseAssociateMaterialComponent;
+ @Input() sort_field: string;
+ @Input() idl_class = "acmc";
+ @Input() dialog_size: 'sm' | 'lg' = 'lg';
+ @Input() table_name = "Course";
+ grid_source: GridDataSource = new GridDataSource();
+ currentMaterials: any[] = [];
+ search_value = '';
+
+ constructor(
+ private auth: AuthService,
+ private courseSvc: CourseService,
+ private net: NetService,
+ private org: OrgService,
+ private pcrud: PcrudService,
+ private toast: ToastService,
+ ){}
+
+ ngOnInit() {
+ this.getSource();
+ }
+
+ /**
+ * Gets the data, specified by the class, that is available.
+ */
+ getSource() {
+ this.grid_source.getRows = (pager: Pager, sort: any[]) => {
+ const orderBy: any = {};
+ if (sort.length) {
+ // Sort specified from grid
+ orderBy[this.idl_class] = sort[0].name + ' ' + sort[0].dir;
+ } else if (this.sort_field) {
+ // Default sort field
+ orderBy[this.idl_class] = this.sort_field;
+ }
+ const searchOps = {
+ offset: pager.offset,
+ limit: pager.limit,
+ order_by: orderBy
+ };
+ return this.pcrud.retrieveAll(this.idl_class, searchOps, {fleshSelectors: true});
+ };
+ }
+
+ showEditDialog(standingPenalty: IdlObject): Promise<any> {
+ this.editDialog.mode = 'update';
+ this.editDialog.recordId = standingPenalty['id']();
+ return new Promise((resolve, reject) => {
+ this.editDialog.open({size: this.dialog_size}).subscribe(
+ result => {
+ this.successString.current()
+ .then(str => this.toast.success(str));
+ this.grid.reload();
+ resolve(result);
+ },
+ error => {
+ this.updateFailedString.current()
+ .then(str => this.toast.danger(str));
+ reject(error);
+ }
+ );
+ });
+ }
+
+ createNew() {
+ this.editDialog.mode = 'create';
+ this.editDialog.recordId = null;
+ this.editDialog.record = null;
+ this.editDialog.open({size: this.dialog_size}).subscribe(
+ ok => {
+ this.createString.current()
+ .then(str => this.toast.success(str));
+ this.grid.reload();
+ },
+ rejection => {
+ if (!rejection.dismissed) {
+ this.createErrString.current()
+ .then(str => this.toast.danger(str));
+ }
+ }
+ );
+ }
+
+ editSelected(fields: IdlObject[]) {
+ // Edit each IDL thing one at a time
+ const editOneThing = (field_object: IdlObject) => {
+ if (!field_object) { return; }
+ this.showEditDialog(field_object).then(
+ () => editOneThing(fields.shift()));
+ };
+ editOneThing(fields.shift());
+ }
+
+ archiveSelected(course: IdlObject[]) {
+ this.courseSvc.disassociateMaterials(course).then(res => {
+ course.forEach(course => {
+ console.log(course);
+ course.is_archived(true);
+ });
+ this.pcrud.update(course).subscribe(
+ val => {
+ console.debug('archived: ' + val);
+ this.archiveSuccessString.current()
+ .then(str => this.toast.success(str));
+ }, err => {
+ this.archiveFailedString.current()
+ .then(str => this.toast.danger(str));
+ }, () => {
+ this.grid.reload();
+ }
+ );
+ });
+ }
+
+ deleteSelected(idl_object: IdlObject[]) {
+ this.courseSvc.disassociateMaterials(idl_object).then(res => {
+ idl_object.forEach(idl_object => {
+ idl_object.isdeleted(true)
+ });
+ this.pcrud.autoApply(idl_object).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.grid.reload()
+ );
+ });
+ };
+
+ fetchCourseMaterials(course, currentMaterials): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.pcrud.search('acmcm', {course: course}).subscribe(res => {
+ if (res) this.fleshItemDetails(res.item(), res.relationship());
+ }, err => {
+ reject(err);
+ }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
+ });
+ }
+
+ fleshItemDetails(itemId, relationship): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.copy_details.retrieve',
+ this.auth.token(), itemId
+ ).subscribe(res => {
+ if (res) {
+ let item = res.copy;
+ item.call_number(res.volume);
+ item._title = res.mvr.title();
+ item.circ_lib(this.org.get(item.circ_lib()));
+ item._relationship = relationship;
+ this.courseMaterialDialog.gridDataSource.data.push(item);
+ }
+ }, err => {
+ reject(err);
+ }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
+ });
+ }
+
+ openMaterialsDialog(course) {
+ let currentMaterials = []
+ this.courseMaterialDialog.gridDataSource.data = [];
+ this.fetchCourseMaterials(course[0].id(), currentMaterials).then(res => {
+ this.courseMaterialDialog.currentCourse = course[0];
+ this.courseMaterialDialog.materials = currentMaterials;
+ this.courseMaterialDialog.open({size: 'lg'}).subscribe(res => {
+ console.log(res);
+ });
+ });
+ }
+}
+
--- /dev/null
+import {NgModule} from '@angular/core';
+import {TreeModule} from '@eg/share/tree/tree.module';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {CourseListComponent} from './course-list.component';
+import {CourseAssociateMaterialComponent} from './course-associate-material.component';
+import {CourseReservesRoutingModule} from './routing.module';
+import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-location-select.module';
+import {CourseService} from './course.service'
+@NgModule({
+ declarations: [
+ CourseListComponent,
+ CourseAssociateMaterialComponent
+ ],
+ imports: [
+ AdminCommonModule,
+ CourseReservesRoutingModule,
+ ItemLocationSelectModule,
+ TreeModule
+ ],
+ exports: [
+ ],
+ providers: [
+ CourseService
+ ]
+})
+
+export class CourseReservesModule {
+}
--- /dev/null
+import {AuthService} from '@eg/core/auth.service';
+import {EventService} from '@eg/core/event.service';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {NetService} from '@eg/core/net.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+
+export class CourseService {
+
+ constructor(
+ private auth: AuthService,
+ private evt: EventService,
+ private idl: IdlService,
+ private net: NetService,
+ private pcrud: PcrudService
+ ) {}
+
+ disassociateMaterials(courses) {
+ return new Promise((resolve, reject) => {
+ let course_ids = [];
+ let course_library_hash = {};
+ courses.forEach(course => {
+ course_ids.push(course.id());
+ course_library_hash[course.id()] = course.owning_lib();
+ });
+ this.pcrud.search('acmcm', {course: course_ids}).subscribe(material => {
+ material.isdeleted(true);
+ this.resetItemFields(material, course_library_hash[material.course()]);
+ this.pcrud.autoApply(material).subscribe(res => {
+ console.log(res);
+ }, err => {
+ reject(err);
+ }, () => {
+ resolve(material);
+ });
+ }, err => {
+ reject(err)
+ }, () => {
+ resolve(courses);
+ });
+ });
+ }
+
+ resetItemFields(material, course_lib) {
+ this.pcrud.retrieve('acp', material.item(),
+ {flesh: 3, flesh_fields: {acp: ['call_number']}}).subscribe(copy => {
+ if (material.original_status()) {
+ copy.status(material.original_status());
+ }
+ if (copy.circ_modifier() != material.original_circ_modifier()) {
+ copy.circ_modifier(material.original_circ_modifier());
+ }
+ if (material.original_location()) {
+ copy.location(material.original_location());
+ }
+ if (material.original_callnumber()) {
+ this.pcrud.retrieve('acn', material.original_callnumber()).subscribe(cn => {
+ this.updateItem(copy, course_lib, cn.label(), true);
+ });
+ } else {
+ this.updateItem(copy, course_lib, copy.call_number().label(), false);
+ }
+ });
+ }
+
+ updateItem(item: IdlObject, course_lib, call_number, updatingVolume) {
+ return new Promise((resolve, reject) => {
+ this.pcrud.update(item).subscribe(item_id => {
+ if (updatingVolume) {
+ let cn = item.call_number();
+ return this.net.request(
+ 'open-ils.cat', 'open-ils.cat.call_number.find_or_create',
+ this.auth.token(), call_number, cn.record(),
+ course_lib, cn.prefix(), cn.suffix(),
+ cn.label_class()
+ ).subscribe(res => {
+ let event = this.evt.parse(res);
+ if (event) return;
+ return this.net.request(
+ 'open-ils.cat', 'open-ils.cat.transfer_copies_to_volume',
+ this.auth.token(), res.acn_id, [item.id()]
+ ).subscribe(transfered_res => {
+ console.debug("Copy transferred to volume with code " + transfered_res);
+ }, err => {
+ reject(err);
+ }, () => {
+ resolve(item);
+ });
+ }, err => {
+ reject(err);
+ }, () => {
+ resolve(item);
+ });
+ } else {
+ return this.pcrud.update(item);
+ }
+ });
+ });
+ }
+
+}
\ No newline at end of file
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {CourseListComponent} from './course-list.component';
+
+const routes: Routes = [{
+ path: '',
+ component: CourseListComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+
+export class CourseReservesRoutingModule {}
\ No newline at end of file
path: 'container/carousel',
component: AdminCarouselComponent
}, {
+ path: 'asset/course_list',
+ loadChildren: '@eg/staff/admin/local/course-reserves/course-reserves.module#CourseReservesModule'
+}, {
path: 'config/standing_penalty',
component: StandingPenaltyComponent
}, {
routerLink="/staff/admin/server/config/circ_modifier"></eg-link-table-link>
<eg-link-table-link i18n-label label="Circulation Recurring Fine Rules"
routerLink="/staff/admin/server/config/rule_recurring_fine"></eg-link-table-link>
- <eg-link-table-link i18n-label label="Course Reserves List"
- routerLink="/staff/admin/server/asset/course_list"></eg-link-table-link>
<eg-link-table-link i18n-label label="Custom Org Unit Trees"
url="/eg/staff/admin/server/actor/org_unit_custom_tree"></eg-link-table-link>
<eg-link-table-link i18n-label label="Floating Groups"
+++ /dev/null
-<eg-string #deleteFailedString i18n-text text="Disassociation of Course Material failed or was not allowed"></eg-string>
-<eg-string #deleteSuccessString i18n-text text="Disassociation of Course Material succeeded"></eg-string>
-<eg-string #successString i18n-text text="Association of Course Material succeeded"></eg-string>
-<eg-string #failedString i18n-text text="Association of Course Material failed or was not allowed"></eg-string>
-<eg-string #differentLibraryString i18n-text text="Material exists at a different library"></eg-string>
-
-<ng-template #dialogContent>
- <div class="modal-header bg-info">
- <h4 class="modal-title" i18n>Course Materials</h4>
- <button type="button" class="close"
- i18n-aria-label aria-label="Close" (click)="close()">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <div class="modal-body">
- <div class="row mt-3">
- <div class="col-md-4">
- <div class="input-group">
- <div class="input-group-prepend">
- <span class="input-group-text" i18n>Barcode</span>
- </div>
- <input type="text" [(ngModel)]="barcodeInput" />
- </div>
- </div>
- <div class="col-md-5">
- <div class="input-group">
- <div class="input-group-prepend">
- <span class="input-group-text" i18n>Relationship</span>
- </div>
- <input type="text" [(ngModel)]="relationshipInput" placeholder-i18n placeholder="e.g. Required" />
- </div>
- </div>
- <div class="col-md-3">
- <button class="btn btn-outline-dark" (click)="associateItem(barcodeInput, relationshipInput)" i18n [disabled]="!barcodeInput">Add Material</button>
- </div>
- </div>
- <div class="row justify-content-center mt-3">
- <div class="col">
- <h5 i18n>The following fields will be applied to the material added, and reverted once the course is no longer associated with the material.</h5>
- </div>
- </div>
- <div class="row mt-3">
- <div class="col-md-6">
- <div class="input-group">
- <div class="input-group-prepend">
- <div class="input-group-text">
- <span i18n>Call Number</span>
- </div>
- </div>
- <input type="text" [(ngModel)]="tempCallNumber"
- (input)="isModifyingCallNumber = true"/>
- <div class="input-group-append">
- <div class="input-group-text">
- <input type="checkbox" [(ngModel)]="isModifyingCallNumber"
- aria-label="Checkbox for setting a temporary Call Number" />
- </div>
- </div>
- </div>
- </div>
- <div class="col-md-6">
- <div class="input-group">
- <div class="input-group-prepend">
- <div class="input-group-text">
- <span i18n>Circulation Modifier</span>
- </div>
- </div>
- <eg-combobox i18n-placeholder placeholder="Circulation Modifier..."
- idlClass="ccm" idlField="name" [displayTemplate]="idlClassLabel"
- [asyncSupportsEmptyTermClick]="true"
- (onChange)="tempCircMod = $event.id; isModifyingCircMod = true">
- </eg-combobox>
- <div class="input-group-append">
- <div class="input-group-text">
- <input type="checkbox" [(ngModel)]="isModifyingCircMod"
- aria-label="Checkbox for setting a temporary Circulation Modifier" />
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="row mt-3">
- <div class="col-md-6">
- <div class="input-group">
- <div class="input-group-prepend">
- <div class="input-group-text">
- <span i18n>Item Status</span>
- </div>
- </div>
- <eg-combobox i18n-placeholder placeholder="Item Status..."
- idlClass="ccs" idlField="name" [displayTemplate]="idlClassLabel"
- [asyncSupportsEmptyTermClick]="true"
- (onChange)="tempStatus = $event.id; isModifyingStatus = true">
- </eg-combobox>
- <div class="input-group-append">
- <div class="input-group-text">
- <input type="checkbox" [(ngModel)]="isModifyingStatus"
- aria-label="Checkbox for setting a temporary Item Status" />
- </div>
- </div>
- </div>
- </div>
- <div class="col-md-6">
- <div class="input-group">
- <div class="input-group-prepend">
- <div class="input-group-text">
- <span i18n>Shelving Location</span>
- </div>
- </div>
- <eg-item-location-select permFilter="MANAGE_RESERVES"
- [(ngModel)]="tempLocation" (oninput)="isModifyingLocation = true">
- </eg-item-location-select>
- <div class="input-group-append">
- <div class="input-group-text">
- <input type="checkbox" [(ngModel)]="isModifyingLocation"
- aria-label="Checkbox for setting a temporary Shelving Location" />
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="mt-3">
- <eg-grid #materialGrid [dataSource]="gridDataSource">
- <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
- </eg-grid-toolbar-action>
-
- <eg-grid-column path="id" [index]=true [hidden]="true" label="ID" i18n-label></eg-grid-column>
- <eg-grid-column label="Barcode" i18n-label name="barcode" [cellTemplate]="barcodeCellTemplate"></eg-grid-column>
- <eg-grid-column label="Title" i18n-label name="title" [cellTemplate]="titleCellTemplate"></eg-grid-column>
- <eg-grid-column path="call_number.label" label="Call Number" i18n-label></eg-grid-column>
- <eg-grid-column path="call_number.prefix.label" [hidden]="true" label="Call Number Prefix" i18n-label hidden></eg-grid-column>
- <eg-grid-column path="call_number.suffix.label" [hidden]="true" label="Call Number Suffix" i18n-label hidden></eg-grid-column>
- <eg-grid-column path="circ_modifier" [hidden]="true" label="Circulation Modifier" i18n-label></eg-grid-column>
- <eg-grid-column path="circ_lib.shortname" label="Circulation Library" i18n-label></eg-grid-column>
- <eg-grid-column path="location.name" [hidden]="true" label="Shelving Location" i18n-label></eg-grid-column>
- <eg-grid-column path="status.name" [hidden]="true" label="Copy Status" i18n-label></eg-grid-column>
- <eg-grid-column path="_relationship" label="Relationship" i18n-label></eg-grid-column>
- </eg-grid>
- </div>
- </div>
- <ng-template #barcodeCellTemplate let-entry="row">
- <span>
- <a class="pl-1"
- href="/eg/staff/cat/item/{{entry.id()}}">
- {{entry.barcode()}}
- </a>
- </span>
- </ng-template>
- <ng-template #titleCellTemplate let-entry="row">
- <span>
- <a class="pl-1"
- href="/eg/staff/cat/catalog/record/{{entry.call_number().record()}}">
- {{entry._title}}
- </a>
- </span>
- </ng-template>
- <ng-template #idlClassLabel let-r="result" i18n>
- {{r.label}}
- </ng-template>
-</ng-template>
\ No newline at end of file
+++ /dev/null
-import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core';
-import {Observable, Observer, of} from 'rxjs';
-import {DialogComponent} from '@eg/share/dialog/dialog.component';
-import {AuthService} from '@eg/core/auth.service';
-import {NetService} from '@eg/core/net.service';
-import {EventService} from '@eg/core/event.service';
-import {OrgService} from '@eg/core/org.service';
-import {PcrudService} from '@eg/core/pcrud.service';
-import {Pager} from '@eg/share/util/pager';
-import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
-import {GridDataSource} from '@eg/share/grid/grid';
-import {GridComponent} from '@eg/share/grid/grid.component';
-import {IdlObject, IdlService} from '@eg/core/idl.service';
-import {StringComponent} from '@eg/share/string/string.component';
-import {ToastService} from '@eg/share/toast/toast.service';
-import {CourseService} from './course.service';
-
-@Component({
- selector: 'eg-course-associate-material-dialog',
- templateUrl: './course-associate-material.component.html'
-})
-
-export class CourseAssociateMaterialComponent extends DialogComponent {
-
- @ViewChild('materialsGrid', {static: true}) materialsGrid: GridComponent;
- @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
- @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
- @ViewChild('successString', { static: true }) successString: StringComponent;
- @ViewChild('failedString', { static: true }) failedString: StringComponent;
- @ViewChild('differentLibraryString', { static: true }) differentLibraryString: StringComponent;
- @Input() table_name = "Course Materials";
- @Input() barcodeInput: String;
- @Input() relationshipInput: String;
- @Input() tempCallNumber: String;
- @Input() tempStatus: Number;
- @Input() tempLocation: Number;
- @Input() tempCircMod: String;
- @Input() isModifyingStatus: Boolean;
- @Input() isModifyingCircMod: Boolean;
- @Input() isModifyingCallNumber: Boolean;
- @Input() isModifyingLocation: Boolean;
- currentCourse: IdlObject;
- materials: any[];
- gridDataSource: GridDataSource;
-
- constructor(
- private auth: AuthService,
- private idl: IdlService,
- private net: NetService,
- private pcrud: PcrudService,
- private org: OrgService,
- private evt: EventService,
- private modal: NgbModal,
- private toast: ToastService,
- private courseSvc: CourseService
- ) {
- super(modal);
- this.gridDataSource = new GridDataSource();
- }
-
- ngOnInit() {
- this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
- return this.fetchMaterials(pager);
- }
- }
-
- deleteSelected(items) {
- let item_ids = [];
- items.forEach(item => {
- this.gridDataSource.data.splice(this.gridDataSource.data.indexOf(item, 0), 1);
- item_ids.push(item.id())
- });
- this.pcrud.search('acmcm', {course: this.currentCourse.id(), item: item_ids}).subscribe(material => {
- material.isdeleted(true);
- this.pcrud.autoApply(material).subscribe(
- val => {
- this.courseSvc.resetItemFields(material, this.currentCourse.owning_lib());
- console.debug('deleted: ' + val);
- this.deleteSuccessString.current().then(str => this.toast.success(str));
- },
- err => {
- this.deleteFailedString.current()
- .then(str => this.toast.danger(str));
- }
- );
- });
- }
-
- associateItem(barcode, relationship) {
- if (barcode) {
- this.pcrud.search('acp', {barcode: barcode},
- {flesh: 3, flesh_fields: {acp: ['call_number']}}).subscribe(item => {
- let material = this.idl.create('acmcm');
- material.item(item.id());
- material.course(this.currentCourse.id());
- if (relationship) material.relationship(relationship);
- if (this.isModifyingStatus && this.tempStatus) {
- material.original_status(item.status());
- item.status(this.tempStatus);
- }
- if (this.isModifyingLocation && this.tempLocation) {
- material.original_location(item.location());
- item.location(this.tempLocation);
- }
- if (this.isModifyingCircMod) {
- material.original_circ_modifier(item.circ_modifier());
- item.circ_modifier(this.tempCircMod);
- if (!this.tempCircMod) item.circ_modifier(null);
- }
- if (this.isModifyingCallNumber) {
- material.original_callnumber(item.call_number());
- }
- this.pcrud.create(material).subscribe(
- val => {
- console.debug('created: ' + val);
- let new_cn = item.call_number().label();
- if (this.tempCallNumber) new_cn = this.tempCallNumber;
- this.courseSvc.updateItem(item, this.currentCourse.owning_lib(), new_cn, this.isModifyingCallNumber).then(res => {
- this.fetchItem(item.id(), relationship);
- if (item.circ_lib() != this.currentCourse.owning_lib()) {
- this.differentLibraryString.current().then(str => this.toast.warning(str));
- } else {
- this.successString.current().then(str => this.toast.success(str));
- }
- });
-
- // Cleaning up inputs
- this.barcodeInput = "";
- this.relationshipInput = "";
- this.tempStatus = null;
- this.tempCircMod = null;
- this.tempCallNumber = null;
- this.tempLocation = null;
- this.isModifyingCallNumber = false;
- this.isModifyingCircMod = false;
- this.isModifyingLocation = false;
- this.isModifyingStatus = false;
- }, err => {
- this.failedString.current().then(str => this.toast.danger(str));
- });
- });
- }
- }
-
- fetchMaterials(pager: Pager): Observable<any> {
- return new Observable<any>(observer => {
- this.materials.forEach(material => {
- this.fetchItem(material.item, material.relationship);
- });
- observer.complete();
- });
- }
-
- fetchItem(itemId, relationship): Promise<any> {
- return new Promise((resolve, reject) => {
- this.net.request(
- 'open-ils.circ',
- 'open-ils.circ.copy_details.retrieve',
- this.auth.token(), itemId
- ).subscribe(res => {
- if (res) {
- let item = res.copy;
- item.call_number(res.volume);
- item.circ_lib(this.org.get(item.circ_lib()));
- item._title = res.mvr.title();
- item._relationship = relationship;
- this.gridDataSource.data.push(item);
- }
- }, err => {
- reject(err);
- }, () => resolve(this.gridDataSource.data));
- });
- }
-}
\ No newline at end of file
+++ /dev/null
-<eg-staff-banner bannerText="Course List" i18n-bannerText>
-</eg-staff-banner>
-
-<eg-string #successString i18n-text text="{{table_name}} Update Succeeded"></eg-string>
-<eg-string #createString i18n-text text="{{table_name}} Was Created Successfully"></eg-string>
-<eg-string #deleteFailedString i18n-text text="Delete of {{table_name}} failed or was not allowed"></eg-string>
-<eg-string #deleteSucailedString i18n-text text="Delete of {{table_name}} failed or was not allowed"></eg-string>
-<eg-string #archiveFailedString i18n-text text="Archival of {{table_name}} failed or was not allowed"></eg-string>
-<eg-string #archiveSuccessString i18n-text text="Archival of {{table_name}} succeeded"></eg-string>
-<eg-string #flairTooltip i18n-text text="Limited Editing"></eg-string>
-
-<eg-course-associate-material-dialog #courseMaterialDialog>
-</eg-course-associate-material-dialog>
-<div class="w-100 mt-2 mb-2">
- <eg-grid #grid idlClass={{idl_class}}
- [dataSource]="grid_source"
- [sortable]="true">
- <eg-grid-toolbar-button
- label="Create {{table_name}}" (onClick)="createNew()" i18n-label>
- </eg-grid-toolbar-button>
- <eg-grid-toolbar-action label="View Materials" i18n-label (onClick)="openMaterialsDialog($event)">
- </eg-grid-toolbar-action>
- <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
- </eg-grid-toolbar-action>
- <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
- </eg-grid-toolbar-action>
- <eg-grid-toolbar-action label="Archive Selected" i18n-label (onClick)="archiveSelected($event)">
- </eg-grid-toolbar-action>
- </eg-grid>
-</div>
-
-<eg-fm-record-editor #editDialog
- idlClass={{idl_class}}
- [preloadLinkedValues]="true"
- hiddenFields="is_archived,id">
-</eg-fm-record-editor>
+++ /dev/null
-import {Component, Input, ViewChild, OnInit} from '@angular/core';
-import {IdlObject} from '@eg/core/idl.service';
-import {PcrudService} from '@eg/core/pcrud.service';
-import {AuthService} from '@eg/core/auth.service';
-import {CourseService} from './course.service';
-import {NetService} from '@eg/core/net.service';
-import {OrgService} from '@eg/core/org.service';
-import {GridComponent} from '@eg/share/grid/grid.component';
-import {Pager} from '@eg/share/util/pager';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
-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 {CourseAssociateMaterialComponent
- } from './course-associate-material.component';
-
-@Component({
- templateUrl: './course-list.component.html'
-})
-
-export class CourseListComponent implements OnInit {
-
- @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
- @ViewChild('grid', { static: true }) grid: GridComponent;
- @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('archiveFailedString', { static: true }) archiveFailedString: StringComponent;
- @ViewChild('archiveSuccessString', { static: true }) archiveSuccessString: StringComponent;
- @ViewChild('courseMaterialDialog', {static: true})
- private courseMaterialDialog: CourseAssociateMaterialComponent;
- @Input() sort_field: string;
- @Input() idl_class = "acmc";
- @Input() dialog_size: 'sm' | 'lg' = 'lg';
- @Input() table_name = "Course";
- grid_source: GridDataSource = new GridDataSource();
- currentMaterials: any[] = [];
- search_value = '';
-
- constructor(
- private auth: AuthService,
- private courseSvc: CourseService,
- private net: NetService,
- private org: OrgService,
- private pcrud: PcrudService,
- private toast: ToastService,
- ){}
-
- ngOnInit() {
- this.getSource();
- }
-
- /**
- * Gets the data, specified by the class, that is available.
- */
- getSource() {
- this.grid_source.getRows = (pager: Pager, sort: any[]) => {
- const orderBy: any = {};
- if (sort.length) {
- // Sort specified from grid
- orderBy[this.idl_class] = sort[0].name + ' ' + sort[0].dir;
- } else if (this.sort_field) {
- // Default sort field
- orderBy[this.idl_class] = this.sort_field;
- }
- const searchOps = {
- offset: pager.offset,
- limit: pager.limit,
- order_by: orderBy
- };
- return this.pcrud.retrieveAll(this.idl_class, searchOps, {fleshSelectors: true});
- };
- }
-
- showEditDialog(standingPenalty: IdlObject): Promise<any> {
- this.editDialog.mode = 'update';
- this.editDialog.recordId = standingPenalty['id']();
- return new Promise((resolve, reject) => {
- this.editDialog.open({size: this.dialog_size}).subscribe(
- result => {
- this.successString.current()
- .then(str => this.toast.success(str));
- this.grid.reload();
- resolve(result);
- },
- error => {
- this.updateFailedString.current()
- .then(str => this.toast.danger(str));
- reject(error);
- }
- );
- });
- }
-
- createNew() {
- this.editDialog.mode = 'create';
- this.editDialog.recordId = null;
- this.editDialog.record = null;
- this.editDialog.open({size: this.dialog_size}).subscribe(
- ok => {
- this.createString.current()
- .then(str => this.toast.success(str));
- this.grid.reload();
- },
- rejection => {
- if (!rejection.dismissed) {
- this.createErrString.current()
- .then(str => this.toast.danger(str));
- }
- }
- );
- }
-
- editSelected(fields: IdlObject[]) {
- // Edit each IDL thing one at a time
- const editOneThing = (field_object: IdlObject) => {
- if (!field_object) { return; }
- this.showEditDialog(field_object).then(
- () => editOneThing(fields.shift()));
- };
- editOneThing(fields.shift());
- }
-
- archiveSelected(course: IdlObject[]) {
- this.courseSvc.disassociateMaterials(course).then(res => {
- course.forEach(course => {
- console.log(course);
- course.is_archived(true);
- });
- this.pcrud.update(course).subscribe(
- val => {
- console.debug('archived: ' + val);
- this.archiveSuccessString.current()
- .then(str => this.toast.success(str));
- }, err => {
- this.archiveFailedString.current()
- .then(str => this.toast.danger(str));
- }, () => {
- this.grid.reload();
- }
- );
- });
- }
-
- deleteSelected(idl_object: IdlObject[]) {
- this.courseSvc.disassociateMaterials(idl_object).then(res => {
- idl_object.forEach(idl_object => {
- idl_object.isdeleted(true)
- });
- this.pcrud.autoApply(idl_object).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.grid.reload()
- );
- });
- };
-
- fetchCourseMaterials(course, currentMaterials): Promise<any> {
- return new Promise((resolve, reject) => {
- this.pcrud.search('acmcm', {course: course}).subscribe(res => {
- if (res) this.fleshItemDetails(res.item(), res.relationship());
- }, err => {
- reject(err);
- }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
- });
- }
-
- fleshItemDetails(itemId, relationship): Promise<any> {
- return new Promise((resolve, reject) => {
- this.net.request(
- 'open-ils.circ',
- 'open-ils.circ.copy_details.retrieve',
- this.auth.token(), itemId
- ).subscribe(res => {
- if (res) {
- let item = res.copy;
- item.call_number(res.volume);
- item._title = res.mvr.title();
- item.circ_lib(this.org.get(item.circ_lib()));
- item._relationship = relationship;
- this.courseMaterialDialog.gridDataSource.data.push(item);
- }
- }, err => {
- reject(err);
- }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
- });
- }
-
- openMaterialsDialog(course) {
- let currentMaterials = []
- this.courseMaterialDialog.gridDataSource.data = [];
- this.fetchCourseMaterials(course[0].id(), currentMaterials).then(res => {
- this.courseMaterialDialog.currentCourse = course[0];
- this.courseMaterialDialog.materials = currentMaterials;
- this.courseMaterialDialog.open({size: 'lg'}).subscribe(res => {
- console.log(res);
- });
- });
- }
-}
-
+++ /dev/null
-import {NgModule} from '@angular/core';
-import {TreeModule} from '@eg/share/tree/tree.module';
-import {AdminCommonModule} from '@eg/staff/admin/common.module';
-import {CourseListComponent} from './course-list.component';
-import {CourseAssociateMaterialComponent} from './course-associate-material.component';
-import {CourseReservesRoutingModule} from './routing.module';
-import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-location-select.module';
-import {CourseService} from './course.service'
-@NgModule({
- declarations: [
- CourseListComponent,
- CourseAssociateMaterialComponent
- ],
- imports: [
- AdminCommonModule,
- CourseReservesRoutingModule,
- ItemLocationSelectModule,
- TreeModule
- ],
- exports: [
- ],
- providers: [
- CourseService
- ]
-})
-
-export class CourseReservesModule {
-}
+++ /dev/null
-import {AuthService} from '@eg/core/auth.service';
-import {EventService} from '@eg/core/event.service';
-import {IdlObject, IdlService} from '@eg/core/idl.service';
-import {NetService} from '@eg/core/net.service';
-import {PcrudService} from '@eg/core/pcrud.service';
-
-export class CourseService {
-
- constructor(
- private auth: AuthService,
- private evt: EventService,
- private idl: IdlService,
- private net: NetService,
- private pcrud: PcrudService
- ) {}
-
- disassociateMaterials(courses) {
- return new Promise((resolve, reject) => {
- let course_ids = [];
- let course_library_hash = {};
- courses.forEach(course => {
- course_ids.push(course.id());
- course_library_hash[course.id()] = course.owning_lib();
- });
- this.pcrud.search('acmcm', {course: course_ids}).subscribe(material => {
- material.isdeleted(true);
- this.resetItemFields(material, course_library_hash[material.course()]);
- this.pcrud.autoApply(material).subscribe(res => {
- console.log(res);
- }, err => {
- reject(err);
- }, () => {
- resolve(material);
- });
- }, err => {
- reject(err)
- }, () => {
- resolve(courses);
- });
- });
- }
-
- resetItemFields(material, course_lib) {
- this.pcrud.retrieve('acp', material.item(),
- {flesh: 3, flesh_fields: {acp: ['call_number']}}).subscribe(copy => {
- if (material.original_status()) {
- copy.status(material.original_status());
- }
- if (copy.circ_modifier() != material.original_circ_modifier()) {
- copy.circ_modifier(material.original_circ_modifier());
- }
- if (material.original_location()) {
- copy.location(material.original_location());
- }
- if (material.original_callnumber()) {
- this.pcrud.retrieve('acn', material.original_callnumber()).subscribe(cn => {
- this.updateItem(copy, course_lib, cn.label(), true);
- });
- } else {
- this.updateItem(copy, course_lib, copy.call_number().label(), false);
- }
- });
- }
-
- updateItem(item: IdlObject, course_lib, call_number, updatingVolume) {
- return new Promise((resolve, reject) => {
- this.pcrud.update(item).subscribe(item_id => {
- if (updatingVolume) {
- let cn = item.call_number();
- return this.net.request(
- 'open-ils.cat', 'open-ils.cat.call_number.find_or_create',
- this.auth.token(), call_number, cn.record(),
- course_lib, cn.prefix(), cn.suffix(),
- cn.label_class()
- ).subscribe(res => {
- let event = this.evt.parse(res);
- if (event) return;
- return this.net.request(
- 'open-ils.cat', 'open-ils.cat.transfer_copies_to_volume',
- this.auth.token(), res.acn_id, [item.id()]
- ).subscribe(transfered_res => {
- console.debug("Copy transferred to volume with code " + transfered_res);
- }, err => {
- reject(err);
- }, () => {
- resolve(item);
- });
- }, err => {
- reject(err);
- }, () => {
- resolve(item);
- });
- } else {
- return this.pcrud.update(item);
- }
- });
- });
- }
-
-}
\ No newline at end of file
+++ /dev/null
-import {NgModule} from '@angular/core';
-import {RouterModule, Routes} from '@angular/router';
-import {CourseListComponent} from './course-list.component';
-
-const routes: Routes = [{
- path: '',
- component: CourseListComponent
-}];
-
-@NgModule({
- imports: [RouterModule.forChild(routes)],
- exports: [RouterModule]
-})
-
-export class CourseReservesRoutingModule {}
\ No newline at end of file
path: 'permission/grp_tree',
component: PermGroupTreeComponent
}, {
- path: 'asset/course_list',
- loadChildren: '@eg/staff/admin/server/course-reserves/course-reserves.module#CourseReservesModule'
-}, {
path: 'actor/org_unit',
loadChildren: () =>
import('./org-unit.module').then(m => m.OrgUnitModule)