1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

(bug) unable to move or cancel reservations

This commit is contained in:
Sylvain 2022-07-20 14:59:42 +02:00
parent e0944746a9
commit 165b3e17b9
5 changed files with 119 additions and 246 deletions

View File

@ -451,6 +451,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
*/
$scope.markSlotAsAdded = function () {
$scope.selectedEvent.backgroundColor = FREE_SLOT_BORDER_COLOR;
$scope.selectedEvent.oldTitle = $scope.selectedEvent.title;
$scope.selectedEvent.title = _t('app.logged.machines_reserve.i_reserve');
updateEvents($scope.selectedEvent);
};
@ -461,19 +462,14 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
$scope.markSlotAsRemoved = function (slot) {
slot.backgroundColor = 'white';
slot.borderColor = FREE_SLOT_BORDER_COLOR;
slot.title = '';
slot.isValid = false;
slot.slot_id = null;
slot.is_reserved = false;
slot.can_modify = false;
slot.offered = false;
slot.title = slot.oldTitle;
updateEvents(slot);
};
/**
* Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
*/
$scope.slotCancelled = function () { $scope.markSlotAsRemoved($scope.selectedEvent); };
$scope.slotCancelled = function () { refreshCalendar() };
/**
* Change the last selected slot's appearance to looks like 'currently looking for a new destination to exchange'
@ -506,31 +502,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
* When modifying an already booked reservation, callback when the modification was successfully done.
*/
$scope.modifyMachineSlot = function () {
const save = {
slotId: $scope.events.modifiable.slot_id,
borderColor: $scope.events.modifiable.borderColor,
users: angular.copy($scope.events.modifiable.users),
title: (!$scope.events.modifiable.users || $scope.events.modifiable.users.map(u => u.id).includes($scope.currentUser.id)) ? _t('app.logged.machines_reserve.i_ve_reserved') : _t('app.logged.machines_reserve.not_available')
};
$scope.events.modifiable.backgroundColor = 'white';
$scope.events.modifiable.title = '';
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
$scope.events.modifiable.slot_id = null;
$scope.events.modifiable.is_reserved = false;
$scope.events.modifiable.can_modify = false;
updateEvents($scope.events.modifiable);
$scope.events.placable.title = save.title;
$scope.events.placable.backgroundColor = 'white';
$scope.events.placable.borderColor = save.borderColor;
$scope.events.placable.slot_id = save.slotId;
$scope.events.placable.is_reserved = true;
$scope.events.placable.can_modify = true;
$scope.events.placable.users = angular.copy(save.users);
updateEvents($scope.events.placable);
refetchCalendar();
refreshCalendar();
};
/**
@ -556,21 +528,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
$scope.selectedPlan = null;
Member.get({ id: $scope.ctrl.member.id }, function (member) {
$scope.ctrl.member = member;
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
return Availability.machine({
machineId: $scope.machine.id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (slots) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
events: slots,
textColor: 'black'
}
);
});
refreshCalendar();
});
};
@ -626,23 +584,6 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
*/
$scope.afterPayment = function (paymentDocument) {
Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {
angular.forEach($scope.events.reserved, function (machineSlot, key) {
machineSlot.is_reserved = true;
machineSlot.can_modify = true;
if ($scope.currentUser.role === 'admin' || ($scope.currentUser.role === 'manager' && reservation.user_id !== $scope.currentUser.id)) {
// an admin or a manager booked for someone else
machineSlot.title = _t('app.logged.machines_reserve.not_available');
machineSlot.borderColor = UNAVAILABLE_SLOT_BORDER_COLOR;
updateMachineSlot(machineSlot, reservation, $scope.ctrl.member);
} else {
// booked for "myself"
machineSlot.title = _t('app.logged.machines_reserve.i_ve_reserved');
machineSlot.borderColor = BOOKED_SLOT_BORDER_COLOR;
updateMachineSlot(machineSlot, reservation, $scope.currentUser);
}
machineSlot.backgroundColor = 'white';
});
if ($scope.selectedPlan) {
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
if ($scope.ctrl.member.id === Auth._currentUser.id) {
@ -651,8 +592,14 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
$scope.plansAreShown = false;
$scope.selectedPlan = null;
}
$scope.ctrl.member.training_credits = angular.copy(reservation.user.training_credits);
$scope.ctrl.member.machine_credits = angular.copy(reservation.user.machine_credits);
if ($scope.ctrl.member.id === Auth._currentUser.id) {
Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);
}
refetchCalendar();
refreshCalendar();
// trigger the refresh of react components
setTimeout(() => {
@ -718,6 +665,27 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
$scope.selectionTime = new Date();
};
/**
* Refetch all events from the API and re-populate the calendar with the resulting slots
*/
const refreshCalendar = function () {
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
return Availability.machine({
machineId: $scope.machine.id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (slots) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
events: slots,
textColor: 'black'
}
);
});
}
/**
* Triggered when fullCalendar tries to graphically render an event block.
* Append the event tag into the block, just after the event title.
@ -733,24 +701,6 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$tran
}
};
/**
* After payment, update the id of the newly reserved slot with the id returned by the server.
* This will allow the user to modify the reservation he just booked. The associated user will also be registered
* with the slot.
* @param slot {Object}
* @param reservation {Object}
* @param user {Object} user associated with the slot
*/
const updateMachineSlot = function (slot, reservation, user) {
angular.forEach(reservation.slots, function (s) {
if (slot.start.isSame(s.start_at)) {
slot.slot_id = s.id;
slot.users = [user];
}
});
updateEvents(slot);
};
/**
* Update the calendar's display to render the new attributes of the events
* @param events Object[] events to update in full-calendar

View File

@ -391,6 +391,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
*/
$scope.markSlotAsAdded = function () {
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR;
$scope.selectedEvent.oldTitle = $scope.selectedEvent.title;
updateEvents($scope.selectedEvent);
};
@ -399,27 +400,22 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
*/
$scope.markSlotAsRemoved = function (slot) {
slot.backgroundColor = 'white';
slot.title = '';
slot.title = slot.oldTitle;
slot.borderColor = FREE_SLOT_BORDER_COLOR;
slot.slot_id = null;
slot.isValid = false;
slot.is_reserved = false;
slot.can_modify = false;
slot.offered = false;
if (slot.is_completed) { slot.is_completed = false; }
updateEvents(slot);
};
/**
* Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
*/
$scope.slotCancelled = function () { $scope.markSlotAsRemoved($scope.selectedEvent); };
$scope.slotCancelled = function () { refreshCalendar(); };
/**
* Change the last selected slot's appearance to looks like 'currently looking for a new destination to exchange'
*/
$scope.markSlotAsModifying = function () {
$scope.selectedEvent.backgroundColor = '#eee';
$scope.selectedEvent.oldTitle = $scope.selectedEvent.title;
$scope.selectedEvent.title = _t('app.logged.space_reserve.i_change');
updateEvents($scope.selectedEvent);
};
@ -445,30 +441,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
* When modifying an already booked reservation, callback when the modification was successfully done.
*/
$scope.modifySpaceSlot = function () {
const save = {
slotId: $scope.events.modifiable.slot_id,
borderColor: $scope.events.modifiable.borderColor,
title: _t('app.logged.space_reserve.i_ve_reserved')
};
$scope.events.modifiable.backgroundColor = 'white';
$scope.events.modifiable.title = '';
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
$scope.events.modifiable.slot_id = null;
$scope.events.modifiable.is_reserved = false;
$scope.events.modifiable.can_modify = false;
if ($scope.events.modifiable.is_completed) { $scope.events.modifiable.is_completed = false; }
updateEvents($scope.events.modifiable);
$scope.events.placable.title = save.title;
$scope.events.placable.backgroundColor = 'white';
$scope.events.placable.borderColor = save.borderColor;
$scope.events.placable.slot_id = save.slotId;
$scope.events.placable.is_reserved = true;
$scope.events.placable.can_modify = true;
updateEvents($scope.events.placable);
refetchCalendar();
refreshCalendar();
};
/**
@ -493,21 +466,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) {
$scope.ctrl.member = member;
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
return Availability.spaces({
spaceId: $scope.space.id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (spaces) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
events: spaces,
textColor: 'black'
}
);
});
refreshCalendar();
});
}
// as the events are re-fetched for the new user, we must re-init the cart
@ -568,16 +527,6 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
*/
$scope.afterPayment = function (paymentDocument) {
Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {
angular.forEach($scope.events.paid, function (spaceSlot, key) {
spaceSlot.is_reserved = true;
spaceSlot.can_modify = true;
spaceSlot.title = _t('app.logged.space_reserve.i_ve_reserved');
spaceSlot.backgroundColor = 'white';
spaceSlot.borderColor = RESERVED_SLOT_BORDER_COLOR;
updateSpaceSlotId(spaceSlot, reservation);
updateEvents(spaceSlot);
});
if ($scope.selectedPlan) {
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
if ($scope.ctrl.member.id === Auth._currentUser.id) {
@ -593,7 +542,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);
}
refetchCalendar();
refreshCalendar();
});
};
@ -634,6 +583,27 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
$scope.selectionTime = new Date();
};
/**
* Refetch all events from the API and re-populate the calendar with the resulting slots
*/
const refreshCalendar = function () {
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
return Availability.spaces({
spaceId: $scope.space.id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (spaces) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
events: spaces,
textColor: 'black'
}
);
});
};
/**
* Triggered when fullCalendar tries to graphically render an event block.
* Append the event tag into the block, just after the event title.
@ -649,20 +619,6 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transi
}
};
/**
* After payment, update the id of the newly reserved slot with the id returned by the server.
* This will allow the user to modify the reservation he just booked.
* @param slot {Object}
* @param reservation {Object}
*/
const updateSpaceSlotId = function (slot, reservation) {
angular.forEach(reservation.slots, function (s) {
if (slot.start.isSame(s.start_at)) {
slot.slot_id = s.id;
}
});
};
/**
* Update the calendar's display to render the new attributes of the events
* @param events Object[] events to update in full-calendar

View File

@ -188,19 +188,13 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
slot.backgroundColor = 'white';
slot.title = slot.training.name;
slot.borderColor = FREE_SLOT_BORDER_COLOR;
slot.id = null;
slot.isValid = false;
slot.is_reserved = false;
slot.can_modify = false;
slot.offered = false;
if (slot.is_completed) { slot.is_completed = false; }
updateEvents(slot);
};
/**
* Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
*/
$scope.slotCancelled = function () { $scope.markSlotAsRemoved($scope.selectedEvent); };
$scope.slotCancelled = function () { refreshCalendar() };
/**
* Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'
@ -234,30 +228,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
* When modifying an already booked reservation, callback when the modification was successfully done.
*/
$scope.modifyTrainingSlot = function () {
const save = {
slotId: $scope.events.modifiable.slot_id,
borderColor: $scope.events.modifiable.borderColor,
title: !AuthService.isAuthorized(['admin', 'manager']) ? $scope.events.placable.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved') : $scope.events.placable.training.name,
};
$scope.events.modifiable.backgroundColor = 'white';
$scope.events.modifiable.title = $scope.events.modifiable.training.name;
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR;
$scope.events.modifiable.slot_id = null;
$scope.events.modifiable.is_reserved = false;
$scope.events.modifiable.can_modify = false;
if ($scope.events.modifiable.is_completed) { $scope.events.modifiable.is_completed = false; }
updateEvents($scope.events.modifiable);
$scope.events.placable.title = save.title;
$scope.events.placable.backgroundColor = 'white';
$scope.events.placable.borderColor = save.borderColor;
$scope.events.placable.slot_id = save.slotId;
$scope.events.placable.is_reserved = true;
$scope.events.placable.can_modify = true;
updateEvents($scope.events.placable);
refetchCalendar();
refreshCalendar();
};
/**
@ -282,22 +253,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) {
$scope.ctrl.member = member;
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
const id = $transition$.params().id === 'all' ? $transition$.params().id : $scope.training.id;
Availability.trainings({
trainingId: id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (trainings) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
$scope.eventSources.splice(0, 1, {
events: trainings,
textColor: 'black'
}
);
});
refreshCalendar();
});
}
// as the events are re-fetched for the new user, we must re-init the cart
@ -358,16 +314,6 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
*/
$scope.afterPayment = function (paymentDocument) {
Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {
angular.forEach($scope.events.paid, function (trainingSlot, key) {
trainingSlot.backgroundColor = 'white';
trainingSlot.is_reserved = true;
trainingSlot.can_modify = true;
updateTrainingSlotId(trainingSlot, reservation);
trainingSlot.borderColor = '#b2e774';
trainingSlot.title = trainingSlot.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved');
updateEvents(trainingSlot);
});
if ($scope.selectedPlan) {
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
if ($scope.ctrl.member.id === Auth._currentUser.id) {
@ -383,7 +329,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);
}
refetchCalendar();
refreshCalendar();
});
};
@ -427,6 +373,27 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
return $scope.selectionTime = new Date();
};
/**
* Refetch all events from the API and re-populate the calendar with the resulting slots
*/
const refreshCalendar = function () {
const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');
const id = $transition$.params().id === 'all' ? $transition$.params().id : $scope.training.id;
Availability.trainings({
trainingId: id,
member_id: $scope.ctrl.member.id,
start: view.start,
end: view.end,
timezone: Fablab.timezone
}, function (trainings) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
$scope.eventSources.splice(0, 1, {
events: trainings,
textColor: 'black'
});
});
}
/**
* Triggered when fullCalendar tries to graphicaly render an event block.
* Append the event tag into the block, just after the event title.

View File

@ -233,16 +233,16 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
*/
$scope.modifySlot = function () {
SlotsReservation.update({ id: $scope.events.modifiable.slots_reservations_ids[0] }, {
slot: {
slots_reservation: {
slot_id: $scope.events.placable.slot_id
}
}
, function () { // success
, function (slotReservation) { // success
// -> run the callback
if (typeof $scope.onSlotModifySuccess === 'function') { $scope.onSlotModifySuccess(); }
// -> set the events as successfully moved (to display a summary)
$scope.events.moved = {
newSlot: $scope.events.placable,
newSlot: Object.assign($scope.events.placable, { slots_reservations_ids: [slotReservation.id] }),
oldSlot: $scope.events.modifiable
};
// -> reset the 'moving' status
@ -517,10 +517,10 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
$scope.slot.group_ids = $scope.slot.plansGrouped.map(function (g) { return g.id; });
}
if (!$scope.slot.is_completed && !$scope.events.modifiable) {
// slot is not fully reserved, and we are not currently modifying a slot
if (!$scope.slot.is_completed && $scope.slot.slots_reservations_ids.length === 0 && !$scope.events.modifiable) {
// slot is not fully reserved, and not reserved by the current user, and we are not currently modifying a slot
// -> can be added to cart or removed if already present
const index = _.findIndex($scope.events.reserved, (e) => e._id === $scope.slot._id);
const index = _.findIndex($scope.events.reserved, (e) => e.slot_id === $scope.slot.slot_id);
if (index === -1) {
if (($scope.limitToOneSlot === 'true') && $scope.events.reserved[0]) {
// if we limit the number of slots in the cart to 1, and there is already
@ -538,8 +538,8 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
resetCartState();
// finally, we update the prices
return updateCartPrice();
} else if (!$scope.slot.is_completed && $scope.events.modifiable) {
// slot is not fully reserved, but we are currently modifying a slot
} else if (!$scope.slot.is_completed && $scope.slot.slots_reservations_ids.length === 0 && $scope.events.modifiable) {
// slot is not fully reserved, not reserved by the current user, and we are currently modifying a slot
// -> we request the calendar to change the rendering
if (typeof $scope.onSlotModifyUnselect === 'function') {
// if the callback return false, cancel the selection for the current modification
@ -547,21 +547,21 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
if (!res) return;
}
// -> then, we re-affect the destination slot
if (!$scope.events.placable || ($scope.events.placable._id !== $scope.slot._id)) {
if (!$scope.events.placable || ($scope.events.placable.slot_id !== $scope.slot.slot_id)) {
return $scope.events.placable = $scope.slot;
} else {
return $scope.events.placable = null;
}
} else if ($scope.slot.is_reserved && $scope.events.modifiable && ($scope.slot.is_reserved._id === $scope.events.modifiable._id)) {
} else if ($scope.slot.slots_reservations_ids.length > 0 &&
$scope.events.modifiable &&
($scope.slot._id === $scope.events.modifiable._id)) {
// slot is reserved and currently modified
// -> we cancel the modification
$scope.cancelModifySlot();
} else if ($scope.slot.is_reserved &&
} else if ($scope.slot.slots_reservations_ids.length > 0 &&
(slotCanBeModified($scope.slot) || slotCanBeCanceled($scope.slot)) &&
!$scope.events.modifiable &&
($scope.events.reserved.length === 0) &&
$scope.user &&
$scope.slot.users.map(u => u.id).includes($scope.user.id)) {
$scope.events.reserved.length === 0) {
// slot is reserved and is ok to be modified or cancelled
// but we are not currently running a modification or having any slots in the cart
// -> first affect the modification/cancellation rights attributes to the current slot

View File

@ -10,30 +10,30 @@ json.trainings @member.trainings do |t|
json.id t.id
json.name t.name
end
json.training_reservations @member.reservations.where(reservable_type: 'Training') do |r|
json.id r.id
json.start_at r.slots.first.start_at
json.end_at r.slots.first.end_at
json.reservable r.reservable
json.training_reservations @member.reservations.where(reservable_type: 'Training').map(&:slots_reservations).flatten do |sr|
json.id sr.id
json.start_at sr.slot.start_at
json.end_at sr.slot.end_at
json.reservable sr.reservation.reservable
json.reservable_type 'Training'
json.is_valid @member.statistic_profile.training_ids.include?(r.reservable_id)
json.canceled_at r.slots_reservations.first.canceled_at
json.is_valid @member.statistic_profile.training_ids.include?(sr.reservation.reservable_id)
json.canceled_at sr.canceled_at
end
json.machine_reservations @member.reservations.where(reservable_type: 'Machine') do |r|
json.id r.id
json.start_at r.slots.first.start_at
json.end_at r.slots.first.end_at
json.reservable r.reservable
json.machine_reservations @member.reservations.where(reservable_type: 'Machine').map(&:slots_reservations).flatten do |sr|
json.id sr.id
json.start_at sr.slot.start_at
json.end_at sr.slot.end_at
json.reservable sr.reservation.reservable
json.reservable_type 'Machine'
json.canceled_at r.slots_reservations.first.canceled_at
json.canceled_at sr.canceled_at
end
json.space_reservations @member.reservations.where(reservable_type: 'Space') do |r|
json.id r.id
json.start_at r.slots.first.start_at
json.end_at r.slots.first.end_at
json.reservable r.reservable
json.space_reservations @member.reservations.where(reservable_type: 'Space').map(&:slots_reservations).flatten do |sr|
json.id sr.id
json.start_at sr.slot.start_at
json.end_at sr.slot.end_at
json.reservable sr.reservation.reservable
json.reservable_type 'Space'
json.canceled_at r.slots_reservations.first.canceled_at
json.canceled_at sr.canceled_at
end
json.all_projects @member.all_projects do |project|