/* eslint-disable no-return-assign, no-undef, */ // TODO: This file was created by bulk-decaffeinate. // Fix any style issues and re-enable lint. /* * decaffeinate suggestions: * DS101: Remove unnecessary use of Array.from * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'Slot', 'AuthService', 'helpers', '_t', function ($rootScope, $uibModal, dialogs, growl, Auth, Price, Wallet, CustomAsset, Slot, AuthService, helpers, _t) { return ({ restrict: 'E', scope: { slot: '=', slotSelectionTime: '=', events: '=', user: '=', modePlans: '=', plan: '=', planSelectionTime: '=', settings: '=', plans: '=', groups: '=', onSlotAddedToCart: '=', onSlotRemovedFromCart: '=', onSlotStartToModify: '=', onSlotModifyDestination: '=', onSlotModifySuccess: '=', onSlotModifyCancel: '=', onSlotModifyUnselect: '=', onSlotCancelSuccess: '=', afterPayment: '=', reservableId: '@', reservableType: '@', reservableName: '@', limitToOneSlot: '@' }, templateUrl: '<%= asset_path "shared/_cart.html" %>', link ($scope, element, attributes) { // will store the user's plan if he choosed to buy one $scope.selectedPlan = null; // total amount of the bill to pay $scope.amountTotal = 0; // total amount of the elements in the cart, without considering any coupon $scope.totalNoCoupon = 0; // once the cart was paid, retain the total amount paid by the customer $scope.amountPaid = 0; // Discount coupon to apply to the basket, if any $scope.coupon = { applied: null }; // Global config: is the user authorized to change his bookings slots? $scope.enableBookingMove = ($scope.settings.booking_move_enable === 'true'); // Global config: delay in hours before a booking while changing the booking slot is forbidden $scope.moveBookingDelay = parseInt($scope.settings.booking_move_delay); // Global config: is the user authorized to cancel his bookings? $scope.enableBookingCancel = ($scope.settings.booking_cancel_enable === 'true'); // Global config: delay in hours before a booking while the cancellation is forbidden $scope.cancelBookingDelay = parseInt($scope.settings.booking_cancel_delay); /** * Add the provided slot to the shopping cart (state transition from free to 'about to be reserved') * and increment the total amount of the cart if needed. * @param slot {Object} fullCalendar event object */ $scope.validateSlot = function (slot) { validateTags(slot, function () { validateSameTimeReservations(slot, function () { slot.isValid = true; updateCartPrice(); }) }) }; /** * Remove the provided slot from the shopping cart (state transition from 'about to be reserved' to free) * and decrement the total amount of the cart if needed. * @param slot {Object} fullCalendar event object * @param index {number} index of the slot in the reservation array * @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.removeSlot = function (slot, index, event) { if (event) { event.preventDefault(); } $scope.events.reserved.splice(index, 1); // if is was the last slot, we remove any plan from the cart if ($scope.events.reserved.length === 0) { $scope.selectedPlan = null; $scope.plan = null; $scope.modePlans = false; } if (typeof $scope.onSlotRemovedFromCart === 'function') { $scope.onSlotRemovedFromCart(slot); } return updateCartPrice(); }; /** * Checks that every selected slots were added to the shopping cart. Ie. will return false if * any checked slot was not validated by the user. */ $scope.isSlotsValid = function () { let isValid = true; angular.forEach($scope.events.reserved, function (m) { if (!m.isValid) { return isValid = false; } }); return isValid; }; /** * Switch the user's view from the reservation agenda to the plan subscription */ $scope.showPlans = function () { // first, we ensure that a user was selected (admin/manager) or logged (member) const isSelectedUser = Object.keys($scope.user).length > 0; // all slots are in future const areFutureSlots = _.every($scope.events.reserved, function(s) { return s.start.isAfter(); }); if (isSelectedUser && areFutureSlots) { return $scope.modePlans = true; } else if (!isSelectedUser){ // otherwise we alert, this error musn't occur when the current user hasn't the admin role return growl.error(_t('app.shared.cart.please_select_a_member_first')); } else if (!areFutureSlots){ return growl.error(_t('app.shared.cart.unable_to_select_plan_if_slots_in_the_past')); } }; /** * Validates the shopping chart and redirect the user to the payment step */ $scope.payCart = function () { // first, we check that a user was selected if (Object.keys($scope.user).length > 0) { // check selected user has a subscription, if any slot is restricted for subscriptions const slotValidations = []; let slotNotValid; let slotNotValidError; $scope.events.reserved.forEach(function (slot) { if (slot.plan_ids.length > 0) { if ( ($scope.selectedPlan && _.include(slot.plan_ids, $scope.selectedPlan.id)) || ($scope.user.subscribed_plan && _.include(slot.plan_ids, $scope.user.subscribed_plan.id)) ) { slotValidations.push(true); } else { slotNotValid = slot; if ($scope.selectedPlan && !_.include(slot.plan_ids, $scope.selectedPlan.id)) { slotNotValidError = 'selectedPlanError'; } if ($scope.user.subscribed_plan && !_.include(slot.plan_ids, $scope.user.subscribed_plan.id)) { slotNotValidError = 'userPlanError'; } if (!$scope.selectedPlan || !$scope.user.subscribed_plan) { slotNotValidError = 'noPlanError'; } slotValidations.push(false); } } }); const hasPlanForSlot = slotValidations.every(function (a) { return a; }); if (!hasPlanForSlot) { if (!AuthService.isAuthorized(['admin', 'manager'])) { return growl.error(_t('app.shared.cart.slot_restrict_subscriptions_must_select_plan')); } else { const modalInstance = $uibModal.open({ animation: true, templateUrl: '<%= asset_path "shared/_reserve_slot_without_plan.html" %>', size: 'md', controller: 'ReserveSlotWithoutPlanController', resolve: { slot: function() { return slotNotValid; }, slotNotValidError: function() { return slotNotValidError; }, } }); modalInstance.result.then(function(res) { return paySlots(); }); } } else { return paySlots(); } } else { // otherwise we alert, this error musn't occur when the current user is not admin or manager return growl.error(_t('app.shared.cart.please_select_a_member_first')); } }; /** * When modifying an already booked reservation, confirm the modification. */ $scope.modifySlot = function () { Slot.update({ id: $scope.events.modifiable.id }, { slot: { start_at: $scope.events.placable.start, end_at: $scope.events.placable.end, availability_id: $scope.events.placable.availability_id } } , function () { // 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, oldSlot: $scope.events.modifiable }; // -> reset the 'moving' status $scope.events.placable = null; return $scope.events.modifiable = null; } , function (err) { // failure growl.error(_t('app.shared.cart.unable_to_change_the_reservation')); return console.error(err); }); }; /** * Cancel the current booking modification, reseting the whole process * @param event {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.cancelModifySlot = function (event) { if (event) { event.preventDefault(); } if (typeof $scope.onSlotModifyCancel === 'function') { $scope.onSlotModifyCancel(); } $scope.events.placable = null; return $scope.events.modifiable = null; }; /** * When modifying an already booked reservation, cancel the choice of the new slot * @param e {Object} see https://docs.angularjs.org/guide/expression#-event- */ $scope.removeSlotToPlace = function (e) { e.preventDefault(); if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect(); } return $scope.events.placable = null; }; /** * Checks if $scope.events.modifiable and $scope.events.placable have tag incompatibilities * @returns {boolean} true in case of incompatibility */ $scope.tagMissmatch = function () { if ($scope.events.placable.tag_ids.length === 0) { return false; } for (let tag of Array.from($scope.events.modifiable.tags)) { if (!Array.from($scope.events.placable.tag_ids).includes(tag.id)) { return true; } } return false; }; /** * Check if the currently logged user has the 'admin' role OR the 'manager' role, but is not taking reseravtion for himself * @returns {boolean} */ $scope.isAuthorized = function () { if (AuthService.isAuthorized('admin')) return true; if (AuthService.isAuthorized('manager')) { return ($rootScope.currentUser.id !== $scope.user.id); } return false; } /* PRIVATE SCOPE */ /** * Kind of constructor: these actions will be realized first when the directive is loaded */ const initialize = function () { // What the bound slot $scope.$watch('slotSelectionTime', function (newValue, oldValue) { if (newValue !== oldValue) { return slotSelectionChanged(); } }); $scope.$watch('user', function (newValue, oldValue) { if (newValue !== oldValue) { resetCartState(); return updateCartPrice(); } }); $scope.$watch('planSelectionTime', function (newValue, oldValue) { if (newValue !== oldValue) { return planSelectionChanged(); } }); // watch when a coupon is applied to re-compute the total price $scope.$watch('coupon.applied', function (newValue, oldValue) { if (newValue !== oldValue) { return updateCartPrice(); } }); }; /** * Validates that the current slot is reserved by a member with an authorized tag. Admin and managers can overpass * the mismatch. * @param slot {Object} fullCalendar event object. * @param callback {function} */ const validateTags = function (slot, callback) { const interTags = _.intersection.apply(null, [slot.tag_ids, $scope.user.tag_ids]); if (slot.tag_ids.length === 0 || interTags.length > 0) { if (typeof callback === 'function') callback(); } else { // ask confirmation const modalInstance = $uibModal.open({ animation: true, templateUrl: '<%= asset_path "shared/_reserve_slot_tags_mismatch.html" %>', size: 'md', controller: 'ReserveSlotTagsMismatchController', resolve: { slotTags: function() { return slot.tags; }, userTags: function () { return $scope.user.tags; }, userName: function () { return $scope.user.name; } } }); modalInstance.result.then(function(res) { if (typeof callback === 'function') callback(res); }); } } /** * Validates that no other reservations were made that conflict the current slot and alert the user about the conflict. * If the user is an administrator or a manager, he can overpass the conflict. * @param slot {Object} fullCalendar event object. * @param callback {function} */ const validateSameTimeReservations = function (slot, callback) { let sameTimeReservations = [ 'training_reservations', 'machine_reservations', 'space_reservations', 'events_reservations' ].map(function (k) { return _.filter($scope.user[k], function(r) { return slot.start.isSame(r.start_at) || (slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) || (slot.start.isAfter(r.start_at) && slot.start.isBefore(r.end_at)) || (slot.start.isBefore(r.start_at) && slot.end.isAfter(r.end_at)); }) }); sameTimeReservations = _.union.apply(null, sameTimeReservations); if (sameTimeReservations.length > 0) { const modalInstance = $uibModal.open({ animation: true, templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>', size: 'md', controller: 'ReserveSlotSameTimeController', resolve: { sameTimeReservations: function() { return sameTimeReservations; }, bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }] } }); modalInstance.result.then(function(res) { if (typeof callback === 'function') callback(res); }); } else { if (typeof callback === 'function') callback(); } } /** * Callback triggered when the selected slot changed */ const slotSelectionChanged = function () { if ($scope.slot) { // if this slot is restricted for subscribers... if ($scope.slot.plan_ids.length > 0) { // ... we select all the plans matching these restrictions... const _plans = _.filter($scope.plans, function (p) { return _.include($scope.slot.plan_ids, p.id) }); // ... and we group these plans, by Group... $scope.slot.plansGrouped = []; $scope.slot.group_ids = []; for (let group of Array.from($scope.groups)) { const groupObj = { id: group.id, name: group.name, plans: [] }; for (let plan of Array.from(_plans)) { if (plan.group_id === group.id) { groupObj.plans.push(plan); } } if (groupObj.plans.length > 0) { // ... Finally, we only keep the plans matching the group of the current user // OR all plans if the current user is admin or manager if (AuthService.isAuthorized(['admin', 'manager'])) { $scope.slot.plansGrouped.push(groupObj); } else if ($scope.user.group_id === groupObj.id) { $scope.slot.plansGrouped.push(groupObj); } } } $scope.slot.group_ids = $scope.slot.plansGrouped.map(function(g) { return g.id; }); } if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) { // slot is not reserved and we are not currently modifying a slot // -> can be added to cart or removed if already present const index = $scope.events.reserved.indexOf($scope.slot); 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 // a slot in the cart, we remove it before adding the new one $scope.removeSlot($scope.events.reserved[0], 0); } // slot is not in the cart, so we add it $scope.events.reserved.push($scope.slot); if (typeof $scope.onSlotAddedToCart === 'function') { $scope.onSlotAddedToCart(); } } else { // slot is in the cart, remove it $scope.removeSlot($scope.slot, index); } // in every cases, because a new reservation has started, we reset the cart content resetCartState(); // finally, we update the prices return updateCartPrice(); } else if (!$scope.slot.is_reserved && !$scope.slot.is_completed && $scope.events.modifiable) { // slot is not reserved but we are currently modifying a slot // -> we request the calender to change the rendering if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect(); } // -> then, we re-affect the destination slot if (!$scope.events.placable || ($scope.events.placable._id !== $scope.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)) { // slot is reserved and currently modified // -> we cancel the modification return $scope.cancelModifySlot(); } else if ($scope.slot.is_reserved && (slotCanBeModified($scope.slot) || slotCanBeCanceled($scope.slot)) && !$scope.events.modifiable && ($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 the affect the modification/cancellation rights attributes to the current slot resetCartState(); $scope.slot.movable = slotCanBeModified($scope.slot); $scope.slot.cancelable = slotCanBeCanceled($scope.slot); // -> then, we open a dialog to ask to the user to choose an action return dialogs.confirm({ templateUrl: '<%= asset_path "shared/confirm_modify_slot_modal.html" %>', resolve: { object () { return $scope.slot; } } } , function (type) { // the user has chosen an action, so we proceed if (type === 'move') { if (typeof $scope.onSlotStartToModify === 'function') { $scope.onSlotStartToModify(); } return $scope.events.modifiable = $scope.slot; } else if (type === 'cancel') { return dialogs.confirm( { resolve: { object () { return { title: _t('app.shared.cart.confirmation_required'), msg: _t('app.shared.cart.do_you_really_want_to_cancel_this_reservation') }; } } }, function () { // cancel confirmed Slot.cancel({ id: $scope.slot.id }, function () { // successfully canceled growl.success(_t('app.shared.cart.reservation_was_cancelled_successfully')); if (typeof $scope.onSlotCancelSuccess === 'function') { return $scope.onSlotCancelSuccess(); } } , function () { // error while canceling growl.error(_t('app.shared.cart.cancellation_failed')); }); } ); } }); } } }; /** * Reset the parameters that may lead to a wrong price but leave the content (events added to cart) */ const resetCartState = function () { $scope.selectedPlan = null; $scope.coupon.applied = null; $scope.events.moved = null; $scope.events.paid = []; $scope.events.modifiable = null; return $scope.events.placable = null; }; /** * Determines if the provided booked slot is able to be modified by the user. * @param slot {Object} fullCalendar event object */ const slotCanBeModified = function (slot) { if (AuthService.isAuthorized(['admin', 'manager'])) { return true; } const slotStart = moment(slot.start); const now = moment(); return (slot.can_modify && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay)); }; /** * Determines if the provided booked slot is able to be canceled by the user. * @param slot {Object} fullCalendar event object */ const slotCanBeCanceled = function (slot) { if (AuthService.isAuthorized(['admin', 'manager'])) { return true; } const slotStart = moment(slot.start); const now = moment(); return (slot.can_modify && $scope.enableBookingCancel && (slotStart.diff(now, 'hours') >= $scope.cancelBookingDelay)); }; /** * Callback triggered when the selected slot changed */ const planSelectionChanged = function () { if (Auth.isAuthenticated()) { if ($scope.selectedPlan !== $scope.plan) { $scope.selectedPlan = $scope.plan; } else { $scope.selectedPlan = null; } return updateCartPrice(); } else { return $rootScope.login(null, function () { $scope.selectedPlan = $scope.plan; return updateCartPrice(); }); } }; /** * Update the total price of the current selection/reservation */ const updateCartPrice = function () { if (Object.keys($scope.user).length > 0) { const r = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan); return Price.compute(mkRequestParams(r, $scope.coupon.applied), function (res) { $scope.amountTotal = res.price; $scope.totalNoCoupon = res.price_without_coupon; setSlotsDetails(res.details); }); } else { // otherwise we alert, this error musn't occur when the current user is not admin growl.warning(_t('app.shared.cart.please_select_a_member_first')); $scope.amountTotal = null; } }; const setSlotsDetails = function (details) { angular.forEach($scope.events.reserved, function (slot) { angular.forEach(details.slots, function (s) { if (moment(s.start_at).isSame(slot.start)) { slot.promo = s.promo; slot.price = s.price; } }); }); }; /** * Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object * @param reservation {Object} as returned by mkReservation() * @param coupon {Object} Coupon as returned from the API * @return {{reservation:Object, coupon_code:string}} */ const mkRequestParams = function (reservation, coupon) { return { reservation, coupon_code: ((coupon ? coupon.code : undefined)) }; }; /** * Create an hash map implementing the Reservation specs * @param member {Object} User as retrieved from the API: current user / selected user if current is admin * @param slots {Array} Array of fullCalendar events: slots selected on the calendar * @param [plan] {Object} Plan as retrieved from the API: plan to buy with the current reservation * @return {{user_id:Number, reservable_id:Number, reservable_type:String, slots_attributes:Array, plan_id:Number|null}} */ const mkReservation = function (member, slots, plan) { const reservation = { user_id: member.id, reservable_id: $scope.reservableId, reservable_type: $scope.reservableType, slots_attributes: [], plan_id: ((plan ? plan.id : undefined)) }; angular.forEach(slots, function (slot) { reservation.slots_attributes.push({ start_at: slot.start, end_at: slot.end, availability_id: slot.availability_id, offered: slot.offered || false }); }); return reservation; }; /** * Open a modal window that allows the user to process a credit card payment for his current shopping cart. */ const payByStripe = function (reservation) { $uibModal.open({ templateUrl: '<%= asset_path "stripe/payment_modal.html" %>', size: 'md', resolve: { reservation () { return reservation; }, price () { return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise; }, wallet () { return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; }, cgv () { return CustomAsset.get({ name: 'cgv-file' }).$promise; }, coupon () { return $scope.coupon.applied; }, cartItems () { return mkRequestParams(reservation, $scope.coupon.applied); }, stripeKey: ['Setting', function (Setting) { return Setting.get({ name: 'stripe_public_key' }).$promise; }] }, controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon', 'cartItems', 'stripeKey', function ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, wallet, helpers, $filter, coupon, cartItems, stripeKey) { // user wallet amount $scope.walletAmount = wallet.amount; // Price $scope.amount = helpers.getAmountToPay(price.price, wallet.amount); // Cart items $scope.cartItems = cartItems; // CGV $scope.cgv = cgv.custom_asset; // Reservation $scope.reservation = reservation; // Used in wallet info template to interpolate some translations $scope.numberFilter = $filter('number'); // stripe publishable key $scope.stripeKey = stripeKey.setting.value; /** * Callback to handle the post-payment and reservation */ $scope.onPaymentSuccess = function (response) { $uibModalInstance.close(response); }; } ] }).result['finally'](null).then(function (reservation) { afterPayment(reservation); }); }; /** * Open a modal window that allows the user to process a local payment for his current shopping cart (admin only). */ const payOnSite = function (reservation) { $uibModal.open({ templateUrl: '<%= asset_path "shared/valid_reservation_modal.html" %>', size: 'sm', resolve: { reservation () { return reservation; }, price () { return Price.compute(mkRequestParams(reservation, $scope.coupon.applied)).$promise; }, wallet () { return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; }, coupon () { return $scope.coupon.applied; } }, controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon', function ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, coupon) { // user wallet amount $scope.walletAmount = wallet.amount; // Global price (total of all items) $scope.price = price.price; // Price to pay (wallet deducted) $scope.amount = helpers.getAmountToPay(price.price, wallet.amount); // Reservation $scope.reservation = reservation; // Used in wallet info template to interpolate some translations $scope.numberFilter = $filter('number'); // Button label if ($scope.amount > 0) { $scope.validButtonName = _t('app.shared.cart.confirm_payment_of_html', { ROLE: $rootScope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) }); } else { if ((price.price > 0) && ($scope.walletAmount === 0)) { $scope.validButtonName = _t('app.shared.cart.confirm_payment_of_html', { ROLE: $rootScope.currentUser.role, AMOUNT: $filter('currency')(price.price) }); } else { $scope.validButtonName = _t('app.shared.buttons.confirm'); } } /** * Callback to process the local payment, triggered on button click */ $scope.ok = function () { $scope.attempting = true; return Reservation.save(mkRequestParams($scope.reservation, coupon), function (reservation) { $uibModalInstance.close(reservation); return $scope.attempting = true; } , function (response) { $scope.alerts = []; $scope.alerts.push({ msg: _t('app.shared.cart.a_problem_occurred_during_the_payment_process_please_try_again_later'), type: 'danger' }); return $scope.attempting = false; }); }; $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; } ] }).result['finally'](null).then(function (reservation) { afterPayment(reservation); }); }; /** * Actions to run after the payment was successful */ const afterPayment = function (reservation) { // we set the cart content as 'paid' to display a summary of the transaction $scope.events.paid = $scope.events.reserved; $scope.amountPaid = $scope.amountTotal; // we call the external callback if present if (typeof $scope.afterPayment === 'function') { $scope.afterPayment(reservation); } // we reset the coupon and the cart content and we unselect the slot $scope.events.reserved = []; $scope.coupon.applied = null; $scope.slot = null; return $scope.selectedPlan = null; }; /** * Actions to pay slots */ const paySlots = function() { const reservation = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan); return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) { const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount); if ((AuthService.isAuthorized(['member']) && amountToPay > 0) || (AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) { if ($scope.settings.online_payment_module !== 'true') { growl.error(_t('app.shared.cart.online_payment_disabled')); } else { return payByStripe(reservation); } } else { if (AuthService.isAuthorized(['admin']) || (AuthService.isAuthorized('manager') && $scope.user.id !== $rootScope.currentUser.id) || amountToPay === 0) { return payOnSite(reservation); } } }); }; // !!! MUST BE CALLED AT THE END of the directive return initialize(); } }); } ]); /** * Controller of the modal showing the reservations the same date at the same time */ Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations', 'bookOverlappingSlotsPromise', function ($scope, $uibModalInstance, AuthService, sameTimeReservations, bookOverlappingSlotsPromise) { $scope.sameTimeReservations = sameTimeReservations; $scope.bookSlotAtSameTime = (bookOverlappingSlotsPromise.setting.value === 'true'); $scope.isAuthorized = AuthService.isAuthorized; /** * Confirmation callback */ $scope.ok = function () { $uibModalInstance.close({}); } /** * Cancellation callback */ $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); } } ]); /** * Controller of the modal showing the slot tags */ Application.Controllers.controller('ReserveSlotTagsMismatchController', ['$scope', '$uibModalInstance', 'AuthService', 'slotTags', 'userTags', 'userName', function ($scope, $uibModalInstance, AuthService, slotTags, userTags, userName) { $scope.slotTags = slotTags; $scope.userTags = userTags; $scope.userName = userName; $scope.isAuthorized = AuthService.isAuthorized; /** * Confirmation callback */ $scope.ok = function () { $uibModalInstance.close({}); } /** * Cancellation callback */ $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); } } ]); /** * Controller used to alert admin reserve slot without plan */ Application.Controllers.controller('ReserveSlotWithoutPlanController', ['$scope', '$uibModalInstance', 'slot', 'slotNotValidError', 'growl', '_t', function ($scope, $uibModalInstance, slot, slotNotValidError, growl, _t) { $scope.slot = slot; $scope.slotNotValidError = slotNotValidError; /** * Confirmation callback */ $scope.ok = function () { $uibModalInstance.close({}); } /** * Cancellation callback */ $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); } } ]);