-<h2>Resources</h2>
-{{resources | json}}
-<h2>Grid</h2>
-{{scheduleSource.data | json}}
<eg-staff-banner bannerText="Create Reservation" i18n-bannerText>
</eg-staff-banner>
<eg-title i18n-prefix i18n-suffix prefix="Booking" suffix="Create Reservation"></eg-title>
<span class="input-group-prepend">
<label class="input-group-text" for="start-time" i18n>Start time</label>
</span>
- <ngb-timepicker [(ngModel)]="startOfDay" (ngModelChange)="fetchData()" [meridian]="true"></ngb-timepicker>
+ <ngb-timepicker [(ngModel)]="startOfDay" (ngModelChange)="fetchData()" [minuteStep]="minuteStep()" [meridian]="true"></ngb-timepicker>
</span>
</li>
<li class="list-group-item">
<span class="input-group-prepend">
<label class="input-group-text" for="end-time" i18n>End time</label>
</span>
- <ngb-timepicker [(ngModel)]="endOfDay" (ngModelChange)="fetchData()" [meridian]="true"></ngb-timepicker>
+ <ngb-timepicker [(ngModel)]="endOfDay" (ngModelChange)="fetchData()" [minuteStep]="minuteStep()" [meridian]="true"></ngb-timepicker>
</span>
</li>
<li class="list-group-item">
[rowFlairIsEnabled]="true"
[rowFlairCallback]="resourceAvailabilityIcon"
[disablePager]="true"
- [disableSaveSettings]="true"
- [cellClassCallback]="isBooked">
+ [disableSaveSettings]="true">
<eg-grid-toolbar-action label="Create Reservation" i18n-label [action]="openCreateDialog"></eg-grid-toolbar-action>
<eg-grid-column path="time" [index]="true" ></eg-grid-column>
<eg-grid-column *ngFor="let resource of resources" path="{{resource.barcode()}}" [cellTemplate]="reservationsTemplate"></eg-grid-column>
<eg-fm-record-editor #newDialog
idlClass="bresv"
- datetimeFields="start_time,end_time"
- [fieldOptions]="{usr:{customTemplate:{template:patronTemplate}},start_time:{customTemplate:{template:datetimeWithDefaults}},end_time:{customTemplate:{template:datetimeWithDefaults}},pickup_lib:{customTemplate:{template:pickupLibrary}}}"
- hiddenFields="id,xact_start,request_time,capture_time,pickup_time,return_time,capture_staff,xact_finish,cancel_time,booking_interval,target_resource,unrecovered,request_lib,fine_interval,fine_amount,max_fine">
+ [fieldOptions]="{usr:{customTemplate:{template:patronTemplate}},start_time:{customTemplate:{template:datetimeWithDefaults}},end_time:{customTemplate:{template:datetimeWithDefaults}},pickup_lib:{customTemplate:{template:pickupLibrary}},target_resource:{customTemplate:{template:targetResource}}}"
+ hiddenFields="id,xact_start,request_time,capture_time,pickup_time,return_time,capture_staff,xact_finish,cancel_time,booking_interval,target_resource,unrecovered,request_lib,fine_interval,fine_amount,max_fine,target_resource,target_resource_type">
</eg-fm-record-editor>
<ng-template #reservationsTemplate let-row="row" let-col="col">
<ng-container *ngIf="row[col.name]">
- <ul>
+ <ul class="alert alert-primary">
<li *ngFor="let reservation of row[col.name]">
<a href="staff/booking/manage_reservations/by_patron/{{reservation['patronId']}}">{{reservation['patronLabel']}}</a>
</li>
</eg-org-select>
<div *ngIf="pickupLibUsesDifferentTz" class="alert alert-primary" i18n>Pickup library uses a different timezone than your library does. Please choose times in the pickup library's timezone.</div>
</ng-template>
+<ng-template #targetResource let-record="record">
+ <input type="hidden" value="{{record.target_resource_type(resourceTypeId)}}">
+ <ng-container *ngIf="resourceId">
+ <input type="text" disabled value="{{resourceBarcode}}" class="form-control">
+ <input type="hidden" value="{{record.target_resource(resourceId)}}">
+ <input type="hidden" value="{{record.current_resource(resourceId)}}">
+ </ng-container>
+ <ng-container *ngIf="!resourceId">
+ <eg-combobox (onChange)="handleTargetResourceChange($event.id)" startId="any">
+ <eg-combobox-entry entryId="any" entryLabel="Any resource"
+ i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry *ngFor="let r of resources" entryId="{{r.id()}}" entryLabel="{{r.barcode()}}">
+ </eg-combobox-entry>
+ </eg-combobox>
+ </ng-container>
+</ng-template>
attributes: IdlObject[] = [];
multiday = false;
handleDateChange: ($event: Date) => void;
- isBooked: (col: any, row: any) => string;
resourceAvailabilityIcon: (row: any) => GridRowFlairEntry;
patronBarcode: string;
resourceBarcode: string;
resourceId: number;
resourceTypeId: number;
+ transferable: boolean;
+ resourceOwner: number;
pickupLibUsesDifferentTz: string;
minuteStep: () => number;
openCreateDialog: (rows: IdlObject[]) => void;
+ openTheDialog: (rows: IdlObject[]) => any;
resources: IdlObject[] = [];
limitByAttr: (attributeId: number, $event: ComboboxEntry) => void;
handleSingleDayReservation: () => void;
changeGranularity: ($event: ComboboxEntry) => void;
handlePickupLibChange: ($event: IdlObject) => void;
+ handleTargetResourceChange: ($event: string | number) => void;
@ViewChildren('dateLimiter') dateLimiters: QueryList<DateSelectComponent>;
@ViewChildren('dateRangeLimiter') dateRangeLimiters: QueryList<DateRangeSelectComponent>;
'start_time': Moment.tz([], this.format.wsOrgTimezone),
'end_time': Moment.tz([], this.format.wsOrgTimezone).add(this.granularity, 'minutes')
};
+
+ this.store.getItem('eg.booking.create.multiday').then(multiday => {
+ if (multiday) { this.multiday = multiday; }
+ }
+
this.route.paramMap.subscribe((params: ParamMap) => {
this.patronId = +params.get('patron_id');
this.resourceBarcode = params.get('resource_barcode');
}
});
- this.isBooked = (row: any, col: any) => {
- if ((col.name !== 'time') && (row[col.name])) {
- return 'bg-warning';
- }
- };
-
this.limitByAttr = (attributeId: number, $event: ComboboxEntry) => {
console.log('LIMIT');
console.log('id: ' + attributeId);
this.handleMultiDayReservation = () => {
this.multiday = true;
+ this.store.setItem('eg.booking.create.multiday', true);
this.setGranularity();
this.fetchData();
};
this.handleSingleDayReservation = () => {
this.multiday = false;
+ this.store.setItem('eg.booking.create.multiday', false);
this.setGranularity();
this.handleDateChange(new Date());
};
});
};
+ this.handleTargetResourceChange = ($event) => {
+ if ('any' !== $event) {
+ this.newDialog.record.current_resource($event);
+ this.newDialog.record.target_resource($event);
+ }
+ }
+
this.useCurrentResourceBarcode = () => {
if (this.resourceBarcode) {
this.router.navigate(['/staff', 'booking', 'create_reservation', 'for_resource', this.resourceBarcode]);
this.setGranularity();
this.fetchData();
+ this.openTheDialog = (rows: IdlObject[]) => {
+ return this.newDialog.open({size: 'lg'}).then(
+ response => {
+ this.toast.success('Reservation successfully created'); // TODO: needs i18n, pluralization
+ this.fetchData();
+ return response.id();
+ },
+ err => {}
+ );
+ }
+
this.openCreateDialog = (rows: IdlObject[]) => {
if (rows.length) {
if (this.multiday) {
} else {
if (this.multiday) { this.defaultTimes['end_time'] = this.defaultTimes['start_time'].clone().add(1, 'days'); }
}
- return this.newDialog.open({size: 'lg'}).then(
- response => {
- console.log(response);
- this.toast.success('Reservation successfully created'); // TODO: needs i18n, pluralization
- this.fetchData();
- },
- err => {}
- );
+ if (this.resourceId) {
+ this.pcrud.search('brsrc', {id: this.resourceId}, {
+ flesh: 1,
+ limit: 1,
+ flesh_fields: {'brsrc': ['type']}
+ }).subscribe( r => {
+ this.transferable = r.type().transferable();
+ this.resourceTypeId = r.type().id();
+ this.resourceOwner = r.owner();
+ this.openTheDialog(rows);
+ });
+ } else if (this.resourceTypeId) {
+ this.pcrud.search('brt', {id: this.resourceTypeId}, {
+ }).subscribe( t => {
+ this.transferable = t.transferable();
+ this.openTheDialog(rows).then(
+ newId => { this.net.request('open-ils.storage', 'open-ils.storage.booking.reservation.resource_targeter', [newId]); }
+ );
+ });
+ }
}
}
handleResourceTypeChange($event: ComboboxEntry) {
this.noSelectedRows = (rows: IdlObject[]) => (rows.length === 0);
this.notOnePatronSelected = (rows: IdlObject[]) => (new Set(rows.map(row => row.usr().id())).size !== 1);
- this.notOneResourceSelected = (rows: IdlObject[]) => (new Set(rows.map(row => row.current_resource().id())).size !== 1);
+ this.notOneResourceSelected = (rows: IdlObject[]) => (new Set(rows.map(row => {if (row.current_resource()) {return row.current_resource().id();}})).size !== 1);
this.cancelNotAppropriate = (rows: IdlObject[]) => (this.noSelectedRows(rows) || ['pickedUp', 'returnReady', 'returnedToday'].includes(this.status));
this.pickupNotAppropriate = (rows: IdlObject[]) => (this.noSelectedRows(rows) || ('pickupReady' !== this.status));
this.editNotAppropriate = (rows: IdlObject[]) => (this.noSelectedRows(rows) || ('returnedToday' === this.status));
.subscribe(type => {
if (!this.resourceTypes) { this.resourceTypes = []; }
this.resourceTypes.push({id: type.id(), label: type.name()});
- });
+ }, (err) => {},
+ () => {this.resourceTypes.sort((a, b) => a.label.localeCompare(b.label));});
this.clear = () => {
this.resourceTypeCombobox.selected = {id: '', label: ''};
};
Booking
</a>
<div class="dropdown-menu" ngbDropdownMenu>
- <a class="dropdown-item" href="/eg/staff/booking/legacy/booking/reservation">
+ <a class="dropdown-item" href="staff/booking/create_reservation">
<span class="material-icons">add</span>
<span i18n>Create Reservations</span>
</a>
'Sticky setting for granularity combobox in Booking Create',
'cwst', 'label')
), (
+ 'eg.booking.create.multiday', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'booking.create.multiday',
+ 'Default to creating multiday booking reservations',
+ 'cwst', 'label')
+), (
'eg.booking.pickup.ready.only_show_captured', 'gui', 'bool',
oils_i18n_gettext(
'booking.pickup.ready.only_show_captured',
'Sticky setting for granularity combobox in Booking Create',
'cwst', 'label')
), (
+ 'eg.booking.create.multiday', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'booking.create.multiday',
+ 'Default to creating multiday booking reservations',
+ 'cwst', 'label')
+), (
'eg.booking.pickup.ready.only_show_captured', 'gui', 'bool',
oils_i18n_gettext(
'booking.pickup.ready.only_show_captured',
</a>
</li>
<li>
+ <a href="/eg2/staff/booking/create_reservation/for_patron/{{patron().id()}}" target="_top">
+ [% l('Booking: Create Reservation') %]
+ </a>
+ </li>
+ <li>
<a href="/eg2/staff/booking/pickup/by_patron/{{patron().id()}}" target="_top">
[% l('Booking: Pick Up Reservations') %]
</a>
</a>
<ul uib-dropdown-menu>
<li>
- <a href="./booking/legacy/booking/reservation" target="_self">
+ <a href="/eg2/staff/booking/create_reservation" target="_self">
<span class="glyphicon glyphicon-plus"></span>
[% l('Create Reservations') %]
</a>
});
}
- $scope.book_copies_now = function() {
- var copies_by_record = {};
- var record_list = [];
- angular.forEach(
- $scope.holdingsGridControls.selectedItems(),
- function (item) {
- var record_id = item['call_number.record.id'];
- if (typeof copies_by_record[ record_id ] == 'undefined') {
- copies_by_record[ record_id ] = [];
- record_list.push( record_id );
- }
- copies_by_record[ record_id ].push(item.id);
- }
- );
-
- var promises = [];
- var combined_brt = [];
- var combined_brsrc = [];
- angular.forEach(record_list, function(record_id) {
- promises.push(
- egCore.net.request(
- 'open-ils.booking',
- 'open-ils.booking.resources.create_from_copies',
- egCore.auth.token(),
- copies_by_record[record_id]
- ).then(function(results) {
- if (results && results['brt']) {
- combined_brt = combined_brt.concat(results['brt']);
- }
- if (results && results['brsrc']) {
- combined_brsrc = combined_brsrc.concat(results['brsrc']);
- }
- })
- );
- });
-
- $q.all(promises).then(function() {
- if (combined_brt.length > 0 || combined_brsrc.length > 0) {
- $uibModal.open({
- template: '<eg-embed-frame url="booking_admin_url" handlers="funcs"></eg-embed-frame>',
- backdrop: 'static',
- animation: true,
- size: 'md',
- controller:
- ['$scope','$location','egCore','$uibModalInstance',
- function($scope , $location , egCore , $uibModalInstance) {
-
- $scope.funcs = {
- ses : egCore.auth.token(),
- bresv_interface_opts : {
- booking_results : {
- brt : combined_brt
- ,brsrc : combined_brsrc
- }
- }
- }
-
- var booking_path = '/eg/booking/reservation';
-
- $scope.booking_admin_url =
- $location.absUrl().replace(/\/eg\/staff.*/, booking_path);
-
- }]
- });
- }
- });
+ $scope.book_copies_now = function(barcode) {
+ location.href = "/eg2/staff/booking/create_reservation/for_resource/" + barcode;
}
-
$scope.requestItems = function() {
var copy_list = gatherSelectedHoldingsIds();
if (copy_list.length == 0) return;
}
$scope.book_copies_now = function() {
- itemSvc.book_copies_now([{
- id : $scope.args.copyId,
- 'call_number.record.id' : $scope.args.recordId
- }]);
+ itemSvc.book_copies_now([$scope.args.copyBarcode]);
}
$scope.findAcquisition = function() {
}
$scope.book_copies_now = function() {
- itemSvc.book_copies_now(copyGrid.selectedItems());
+ var item = copyGrid.selectedItems()[0];
+ if (item)
+ itemSvc.book_copies_now(item.barcode);
}
$scope.manage_reservations = function() {
});
}
- service.book_copies_now = function(items) {
- var copies_by_record = {};
- var record_list = [];
- angular.forEach(
- items,
- function (item) {
- var record_id = item['call_number.record.id'];
- if (typeof copies_by_record[ record_id ] == 'undefined') {
- copies_by_record[ record_id ] = [];
- record_list.push( record_id );
- }
- copies_by_record[ record_id ].push(item.id);
- }
- );
-
- var promises = [];
- var combined_brt = [];
- var combined_brsrc = [];
- angular.forEach(record_list, function(record_id) {
- promises.push(
- egCore.net.request(
- 'open-ils.booking',
- 'open-ils.booking.resources.create_from_copies',
- egCore.auth.token(),
- copies_by_record[record_id]
- ).then(function(results) {
- if (results && results['brt']) {
- combined_brt = combined_brt.concat(results['brt']);
- }
- if (results && results['brsrc']) {
- combined_brsrc = combined_brsrc.concat(results['brsrc']);
- }
- })
- );
- });
-
- $q.all(promises).then(function() {
- if (combined_brt.length > 0 || combined_brsrc.length > 0) {
- $uibModal.open({
- template: '<eg-embed-frame url="booking_admin_url" handlers="funcs"></eg-embed-frame>',
- backdrop: 'static',
- animation: true,
- size: 'md',
- controller:
- ['$scope','$location','egCore','$uibModalInstance',
- function($scope , $location , egCore , $uibModalInstance) {
-
- $scope.funcs = {
- ses : egCore.auth.token(),
- bresv_interface_opts : {
- booking_results : {
- brt : combined_brt
- ,brsrc : combined_brsrc
- }
- }
- }
-
- var booking_path = '/eg/booking/reservation';
-
- $scope.booking_admin_url =
- $location.absUrl().replace(/\/eg\/staff.*/, booking_path);
-
- }]
- });
- }
- });
+ service.book_copies_now = function(barcode) {
+ location.href = "/eg2/staff/booking/create_reservation/for_resource/" + barcode;
}
service.manage_reservations = function(barcode) {