mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-04 15:24:23 +01:00
807 lines
29 KiB
Plaintext
807 lines
29 KiB
Plaintext
/* eslint-disable
|
|
camelcase,
|
|
handle-callback-err,
|
|
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.Controllers.controller('EventsController', ['$scope', '$state', 'Event', 'categoriesPromise', 'themesPromise', 'ageRangesPromise',
|
|
function ($scope, $state, Event, categoriesPromise, themesPromise, ageRangesPromise) {
|
|
/* PUBLIC SCOPE */
|
|
|
|
// The events displayed on the page
|
|
$scope.events = [];
|
|
|
|
// The currently displayed page number
|
|
$scope.page = 1;
|
|
|
|
// List of categories for the events
|
|
$scope.categories = categoriesPromise;
|
|
|
|
// List of events themes
|
|
$scope.themes = themesPromise;
|
|
|
|
// List of age ranges
|
|
$scope.ageRanges = ageRangesPromise;
|
|
|
|
// Hide or show the 'load more' button
|
|
$scope.noMoreResults = false;
|
|
|
|
// Active filters for the events list
|
|
$scope.filters = {
|
|
category_id: null,
|
|
theme_id: null,
|
|
age_range_id: null
|
|
};
|
|
|
|
$scope.monthNames = [<%= t('date.month_names')[1..-1].map { |m| "\"#{m}\"" }.join(', ') %>];
|
|
|
|
/**
|
|
* Adds a resultset of events to the bottom of the page, grouped by month
|
|
*/
|
|
$scope.loadMoreEvents = function () {
|
|
$scope.page += 1;
|
|
return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) {
|
|
$scope.events = $scope.events.concat(data);
|
|
groupEvents($scope.events);
|
|
|
|
if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) {
|
|
return $scope.noMoreResults = true;
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Callback to redirect the user to the specified event page
|
|
* @param event {{id:number}}
|
|
*/
|
|
$scope.showEvent = function (event) { $state.go('app.public.events_show', { id: event.id }); };
|
|
|
|
/**
|
|
* Callback to refresh the events list according to the filters set
|
|
*/
|
|
$scope.filterEvents = function () {
|
|
// reinitialize results datasets
|
|
$scope.page = 1;
|
|
$scope.eventsGroupByMonth = {};
|
|
$scope.events = [];
|
|
$scope.monthOrder = [];
|
|
$scope.noMoreResults = false;
|
|
|
|
// run a search query
|
|
return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) {
|
|
$scope.events = data;
|
|
groupEvents(data);
|
|
|
|
if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) {
|
|
return $scope.noMoreResults = true;
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Test if the provided event occurs on a single day or on many days
|
|
* @param event {{start_date:Date, end_date:Date}} Event object as retreived from the API
|
|
* @return {boolean} false if the event occurs on many days
|
|
*/
|
|
$scope.onSingleDay = function (event) { moment(event.start_date).isSame(event.end_date, 'day'); };
|
|
|
|
/* PRIVATE SCOPE */
|
|
|
|
/**
|
|
* Kind of constructor: these actions will be realized first when the controller is loaded
|
|
*/
|
|
const initialize = function () {
|
|
$scope.filterEvents();
|
|
};
|
|
|
|
/**
|
|
* Group the provided events by month/year and concat them with existing results
|
|
* Then compute the ordered list of months for the complete resultset.
|
|
* Affect the resulting events groups in $scope.eventsGroupByMonth and the ordered month keys in $scope.monthOrder.
|
|
* @param events {Array} Events retrieved from the API
|
|
*/
|
|
const groupEvents = function (events) {
|
|
if (events.length > 0) {
|
|
const eventsGroupedByMonth = _.groupBy(events, function (obj) {
|
|
return _.map(['month_id', 'year'], function (key) {
|
|
return obj[key];
|
|
});
|
|
});
|
|
$scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth);
|
|
return $scope.monthOrder = Object.keys($scope.eventsGroupByMonth);
|
|
}
|
|
};
|
|
|
|
// # !!! MUST BE CALLED AT THE END of the controller
|
|
initialize();
|
|
}
|
|
]);
|
|
|
|
Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$stateParams', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'Slot', 'eventPromise', 'growl', '_t', 'Wallet', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise',
|
|
function ($scope, $state, $stateParams, $rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, Slot, eventPromise, growl, _t, Wallet, helpers, dialogs, priceCategoriesPromise, settingsPromise) {
|
|
/* PUBLIC SCOPE */
|
|
|
|
// reservations for the currently shown event
|
|
$scope.reservations = [];
|
|
|
|
// user to deal with
|
|
$scope.ctrl =
|
|
{ member: {} };
|
|
|
|
// parameters for a new reservation
|
|
$scope.reserve = {
|
|
nbPlaces: {
|
|
normal: []
|
|
},
|
|
nbReservePlaces: 0,
|
|
tickets: {},
|
|
toReserve: false,
|
|
amountTotal: 0,
|
|
totalNoCoupon: 0,
|
|
totalSeats: 0
|
|
};
|
|
|
|
// Discount coupon to apply to the basket, if any
|
|
$scope.coupon =
|
|
{ applied: null };
|
|
|
|
// Get the details for the current event (event's id is recovered from the current URL)
|
|
$scope.event = eventPromise;
|
|
|
|
// List of price categories for the events
|
|
$scope.priceCategories = priceCategoriesPromise;
|
|
|
|
// Global config: is the user authorized to change his bookings slots?
|
|
$scope.enableBookingMove = (settingsPromise.booking_move_enable === 'true');
|
|
|
|
// Global config: delay in hours before a booking while changing the booking slot is forbidden
|
|
$scope.moveBookingDelay = parseInt(settingsPromise.booking_move_delay);
|
|
|
|
// Global config: is the user authorized to cancel his booking slots?
|
|
$scope.enableBookingCancel = settingsPromise.booking_cancel_enable === 'true';
|
|
|
|
// Global config: delay in hours from now when restrictions occurs about cancelling reservations
|
|
$scope.cancelBookingDelay = parseInt(settingsPromise.booking_cancel_delay);
|
|
|
|
// Message displayed to the end user about rules that applies to events reservations
|
|
$scope.eventExplicationsAlert = settingsPromise.event_explications_alert;
|
|
|
|
/**
|
|
* Callback to delete the provided event (admins only)
|
|
* @param event {$resource} angular's Event $resource
|
|
*/
|
|
$scope.deleteEvent = function (event) {
|
|
dialogs.confirm({
|
|
resolve: {
|
|
object () {
|
|
return {
|
|
title: _t('confirmation_required'),
|
|
msg: _t('do_you_really_want_to_delete_this_event')
|
|
};
|
|
}
|
|
}
|
|
}, function () {
|
|
// the admin has confirmed, delete
|
|
event.$delete(function () {
|
|
$state.go('app.public.events_list');
|
|
return growl.info(_t('event_successfully_deleted'));
|
|
}, function (error) {
|
|
console.error(error);
|
|
growl.error(_t('unable_to_delete_the_event_because_some_users_alredy_booked_it'));
|
|
});
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Callback to call when the number of tickets to book changes in the current booking
|
|
*/
|
|
$scope.changeNbPlaces = function () {
|
|
// compute the total remaning places
|
|
let remain = $scope.event.nb_free_places - $scope.reserve.nbReservePlaces;
|
|
for (let ticket in $scope.reserve.tickets) {
|
|
remain -= $scope.reserve.tickets[ticket];
|
|
}
|
|
// we store the total number of seats booked, this is used to know if the 'pay' button must be shown
|
|
$scope.reserve.totalSeats = $scope.event.nb_free_places - remain;
|
|
|
|
// update the available seats for full price tickets
|
|
const fullPriceRemains = $scope.reserve.nbReservePlaces + remain;
|
|
$scope.reserve.nbPlaces.normal = __range__(0, fullPriceRemains, true);
|
|
|
|
// update the available seats for other prices tickets
|
|
for (let key in $scope.reserve.nbPlaces) {
|
|
if (key !== 'normal') {
|
|
const priceRemain = $scope.reserve.tickets[key] + remain;
|
|
$scope.reserve.nbPlaces[key] = __range__(0, priceRemain, true);
|
|
}
|
|
}
|
|
|
|
// recompute the total price
|
|
return $scope.computeEventAmount();
|
|
};
|
|
|
|
/**
|
|
* Callback to reset the current reservation parameters
|
|
* @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
|
|
*/
|
|
$scope.cancelReserve = function (e) {
|
|
e.preventDefault();
|
|
return resetEventReserve();
|
|
};
|
|
|
|
/**
|
|
* Callback to allow the user to set the details for his reservation
|
|
*/
|
|
$scope.reserveEvent = function () {
|
|
if ($scope.event.nb_total_places > 0) {
|
|
$scope.reserveSuccess = false;
|
|
if (!$scope.isAuthenticated()) {
|
|
return $scope.login(null, function (user) {
|
|
$scope.reserve.toReserve = !$scope.reserve.toReserve;
|
|
if (user.role !== 'admin') {
|
|
return $scope.ctrl.member = user;
|
|
}
|
|
});
|
|
} else {
|
|
return $scope.reserve.toReserve = !$scope.reserve.toReserve;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
|
|
* reservations. (admins only)
|
|
*/
|
|
$scope.updateMember = function () {
|
|
resetEventReserve();
|
|
$scope.reserveSuccess = false;
|
|
if ($scope.ctrl.member) {
|
|
return Member.get({ id: $scope.ctrl.member.id }, function (member) {
|
|
$scope.ctrl.member = member;
|
|
return getReservations($scope.event.id, 'Event', $scope.ctrl.member.id);
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Callback to trigger the payment process of the current reservation
|
|
*/
|
|
$scope.payEvent = function () {
|
|
// first, we check that a user was selected
|
|
if (Object.keys($scope.ctrl.member).length > 0) {
|
|
const reservation = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event);
|
|
|
|
return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }, function (wallet) {
|
|
const amountToPay = helpers.getAmountToPay($scope.reserve.amountTotal, wallet.amount);
|
|
if (($scope.currentUser.role !== 'admin') && (amountToPay > 0)) {
|
|
if ($rootScope.fablabWithoutOnlinePayment) {
|
|
growl.error(_t('online_payment_disabled'));
|
|
} else {
|
|
return payByStripe(reservation);
|
|
}
|
|
} else {
|
|
if (($scope.currentUser.role === 'admin') || (amountToPay === 0)) {
|
|
return payOnSite(reservation);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
// otherwise we alert, this error musn't occur when the current user is not admin
|
|
return growl.error(_t('please_select_a_member_first'));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Callback to validate the booking of a free event
|
|
*/
|
|
$scope.validReserveEvent = function () {
|
|
const reservation = {
|
|
user_id: $scope.ctrl.member.id,
|
|
reservable_id: $scope.event.id,
|
|
reservable_type: 'Event',
|
|
slots_attributes: [],
|
|
nb_reserve_places: $scope.reserve.nbReservePlaces,
|
|
tickets_attributes: []
|
|
};
|
|
// a single slot is used for events
|
|
reservation.slots_attributes.push({
|
|
start_at: $scope.event.start_date,
|
|
end_at: $scope.event.end_date,
|
|
availability_id: $scope.event.availability.id
|
|
});
|
|
// iterate over reservations per prices
|
|
for (let price_id in $scope.reserve.tickets) {
|
|
const seats = $scope.reserve.tickets[price_id];
|
|
reservation.tickets_attributes.push({
|
|
event_price_category_id: price_id,
|
|
booked: seats
|
|
});
|
|
}
|
|
// set the attempting marker
|
|
$scope.attempting = true;
|
|
// save the reservation to the API
|
|
return Reservation.save({ reservation }, function (reservation) {
|
|
// reservation successfull
|
|
afterPayment(reservation);
|
|
return $scope.attempting = false;
|
|
}
|
|
, function (response) {
|
|
// reservation failed
|
|
$scope.alerts = [];
|
|
$scope.alerts.push({
|
|
msg: response.data.card[0],
|
|
type: 'danger'
|
|
});
|
|
// unset the attempting marker
|
|
return $scope.attempting = false;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Callback to cancel a reservation
|
|
* @param reservation {{id:number, reservable_id:number, nb_reserve_places:number}}
|
|
*/
|
|
$scope.cancelReservation = function(reservation) {
|
|
return dialogs.confirm({
|
|
resolve: {
|
|
object: function() {
|
|
return {
|
|
title: _t('cancel_the_reservation'),
|
|
msg: _t('do_you_really_want_to_cancel_this_reservation_this_apply_to_all_booked_tickets')
|
|
};
|
|
}
|
|
}
|
|
}, function() { // cancel confirmed
|
|
return Slot.cancel({
|
|
id: reservation.slots[0].id
|
|
}, function() { // successfully canceled
|
|
var index;
|
|
growl.success(_t('reservation_was_successfully_cancelled'));
|
|
index = $scope.reservations.indexOf(reservation);
|
|
$scope.event.nb_free_places = $scope.event.nb_free_places + reservation.total_booked_seats;
|
|
return $scope.reservations.splice(index, 1);
|
|
}, function(error) {
|
|
return growl.warning(_t('cancellation_failed'));
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose
|
|
* a new date for his reservation (if any available)
|
|
* @param reservation {{id:number, reservable_id:number, nb_reserve_places:number}}
|
|
*/
|
|
$scope.modifyReservation = function (reservation) {
|
|
const index = $scope.reservations.indexOf(reservation);
|
|
return $uibModal.open({
|
|
templateUrl: '<%= asset_path "events/modify_event_reservation_modal.html" %>',
|
|
resolve: {
|
|
event () { return $scope.event; },
|
|
reservation () { return reservation; }
|
|
},
|
|
controller: ['$scope', '$uibModalInstance', 'event', 'reservation', 'Reservation', function ($scope, $uibModalInstance, event, reservation, Reservation) {
|
|
// we copy the controller's resolved parameters into the scope
|
|
$scope.event = event;
|
|
$scope.reservation = angular.copy(reservation);
|
|
|
|
// set the reservable_id to the first available event
|
|
for (evt of Array.from(event.recurrence_events)) {
|
|
if (evt.nb_free_places > reservation.total_booked_seats) {
|
|
$scope.reservation.reservable_id = evt.id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Callback to validate the new reservation's date
|
|
$scope.ok = function () {
|
|
let eventToPlace = null;
|
|
angular.forEach(event.recurrence_events, function (e) {
|
|
if (e.id === parseInt($scope.reservation.reservable_id, 10)) {
|
|
return eventToPlace = e;
|
|
}
|
|
});
|
|
$scope.reservation.slots[0].start_at = eventToPlace.start_date;
|
|
$scope.reservation.slots[0].end_at = eventToPlace.end_date;
|
|
$scope.reservation.slots[0].availability_id = eventToPlace.availability_id;
|
|
$scope.reservation.slots_attributes = $scope.reservation.slots;
|
|
$scope.attempting = true;
|
|
Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) {
|
|
$uibModalInstance.close(reservation);
|
|
$scope.attempting = true;
|
|
}
|
|
, function (response) {
|
|
$scope.alerts = [];
|
|
angular.forEach(response, function (v, k) {
|
|
angular.forEach(v, function (err) {
|
|
$scope.alerts.push({ msg: k + ': ' + err, type: 'danger' });
|
|
});
|
|
});
|
|
$scope.attempting = false;
|
|
});
|
|
};
|
|
|
|
// Callback to cancel the modification
|
|
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
|
}
|
|
] })
|
|
.result['finally'](null).then(function (reservation) {
|
|
// remove the reservation from the user's reservations list for this event (occurrence)
|
|
$scope.reservations.splice(index, 1);
|
|
// add the number of places transfered (to the new date) to the total of free places for this event
|
|
$scope.event.nb_free_places = $scope.event.nb_free_places + reservation.total_booked_seats;
|
|
// remove the number of places transfered from the total of free places of the receiving occurrance
|
|
angular.forEach($scope.event.recurrence_events, function (e) {
|
|
if (e.id === parseInt(reservation.reservable.id, 10)) {
|
|
return e.nb_free_places = e.nb_free_places - reservation.total_booked_seats;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Checks if the provided reservation is able to be moved (date change)
|
|
* @param reservation {{slots:[], total_booked_seats:number}}
|
|
*/
|
|
$scope.reservationCanModify = function (reservation) {
|
|
const slotStart = moment(reservation.slots[0].start_at);
|
|
const now = moment();
|
|
|
|
let isAble = false;
|
|
angular.forEach($scope.event.recurrence_events, function (e) {
|
|
if (e.nb_free_places >= reservation.total_booked_seats) { return isAble = true; }
|
|
});
|
|
return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay));
|
|
};
|
|
|
|
/**
|
|
* Checks if the provided reservation is able to be cancelled
|
|
* @param reservation {{slots:[]}}
|
|
*/
|
|
$scope.reservationCanCancel = function(reservation) {
|
|
var now, slotStart;
|
|
slotStart = moment(reservation.slots[0].start_at);
|
|
now = moment();
|
|
return $scope.enableBookingCancel && slotStart.diff(now, "hours") >= $scope.cancelBookingDelay;
|
|
};
|
|
|
|
/**
|
|
* Compute the total amount for the current reservation according to the previously set parameters
|
|
* and assign the result in $scope.reserve.amountTotal
|
|
*/
|
|
$scope.computeEventAmount = function () {
|
|
// first we check that a user was selected
|
|
if (Object.keys($scope.ctrl.member).length > 0) {
|
|
const r = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event);
|
|
return Price.compute(mkRequestParams(r, $scope.coupon.applied), function (res) {
|
|
$scope.reserve.amountTotal = res.price;
|
|
return $scope.reserve.totalNoCoupon = res.price_without_coupon;
|
|
});
|
|
} else {
|
|
return $scope.reserve.amountTotal = null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Return the URL allowing to share the current project on the Facebook social network
|
|
*/
|
|
$scope.shareOnFacebook = function () { return `https://www.facebook.com/share.php?u=${$state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }).replace('#', '%23')}`; };
|
|
|
|
/**
|
|
* Return the URL allowing to share the current project on the Twitter social network
|
|
*/
|
|
$scope.shareOnTwitter = function () { return `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }))}&text=${encodeURIComponent($scope.event.title)}`; };
|
|
|
|
/**
|
|
* Return the textual description of the conditions applyable to the given price's category
|
|
* @param category_id {number} ID of the price's category
|
|
*/
|
|
$scope.getPriceCategoryConditions = function (category_id) {
|
|
for (let cat of Array.from($scope.priceCategories)) {
|
|
if (cat.id === category_id) {
|
|
return cat.conditions;
|
|
}
|
|
}
|
|
};
|
|
|
|
/* PRIVATE SCOPE */
|
|
|
|
/**
|
|
* Kind of constructor: these actions will be realized first when the controller is loaded
|
|
*/
|
|
const initialize = function () {
|
|
// set the controlled user as the current user if the current user is not an admin
|
|
if ($scope.currentUser) {
|
|
if ($scope.currentUser.role !== 'admin') {
|
|
$scope.ctrl.member = $scope.currentUser;
|
|
}
|
|
}
|
|
|
|
// initialize the "reserve" object with the event's data
|
|
resetEventReserve();
|
|
|
|
// if non-admin, get the current user's reservations into $scope.reservations
|
|
if ($scope.currentUser) {
|
|
getReservations($scope.event.id, 'Event', $scope.currentUser.id);
|
|
}
|
|
|
|
// watch when a coupon is applied to re-compute the total price
|
|
return $scope.$watch('coupon.applied', function (newValue, oldValue) {
|
|
if ((newValue !== null) || (oldValue !== null)) {
|
|
return $scope.computeEventAmount();
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Retrieve the reservations for the couple event / user
|
|
* @param reservable_id {number} the current event id
|
|
* @param reservable_type {string} 'Event'
|
|
* @param user_id {number} the user's id (current or managed)
|
|
*/
|
|
var getReservations = function (reservable_id, reservable_type, user_id) {
|
|
Reservation.query({
|
|
reservable_id,
|
|
reservable_type,
|
|
user_id
|
|
}).$promise.then(function (reservations) { $scope.reservations = reservations; });
|
|
};
|
|
|
|
/**
|
|
* Create an hash map implementing the Reservation specs
|
|
* @param member {Object} User as retreived from the API: current user / selected user if current is admin
|
|
* @param reserve {Object} Reservation parameters (places...)
|
|
* @param event {Object} Current event
|
|
* @return {{user_id:number, reservable_id:number, reservable_type:string, slots_attributes:Array<Object>, nb_reserve_places:number}}
|
|
*/
|
|
var mkReservation = function (member, reserve, event) {
|
|
const reservation = {
|
|
user_id: member.id,
|
|
reservable_id: event.id,
|
|
reservable_type: 'Event',
|
|
slots_attributes: [],
|
|
nb_reserve_places: reserve.nbReservePlaces,
|
|
tickets_attributes: []
|
|
};
|
|
|
|
reservation.slots_attributes.push({
|
|
start_at: event.start_date,
|
|
end_at: event.end_date,
|
|
availability_id: event.availability.id,
|
|
offered: event.offered || false
|
|
});
|
|
|
|
for (let evt_px_cat of Array.from(event.prices)) {
|
|
const booked = reserve.tickets[evt_px_cat.id];
|
|
if (booked > 0) {
|
|
reservation.tickets_attributes.push({
|
|
event_price_category_id: evt_px_cat.id,
|
|
booked
|
|
});
|
|
}
|
|
}
|
|
|
|
return reservation;
|
|
};
|
|
|
|
/**
|
|
* 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}}
|
|
*/
|
|
var mkRequestParams = function (reservation, coupon) {
|
|
const params = {
|
|
reservation,
|
|
coupon_code: ((coupon ? coupon.code : undefined))
|
|
};
|
|
|
|
return params;
|
|
};
|
|
|
|
/**
|
|
* Set the current reservation to the default values. This implies the reservation form to be hidden.
|
|
*/
|
|
var resetEventReserve = function () {
|
|
if ($scope.event) {
|
|
$scope.reserve = {
|
|
nbPlaces: {
|
|
normal: __range__(0, $scope.event.nb_free_places, true)
|
|
},
|
|
nbReservePlaces: 0,
|
|
tickets: {},
|
|
toReserve: false,
|
|
amountTotal: 0,
|
|
totalSeats: 0
|
|
};
|
|
|
|
for (let evt_px_cat of Array.from($scope.event.prices)) {
|
|
$scope.reserve.nbPlaces[evt_px_cat.id] = __range__(0, $scope.event.nb_free_places, true);
|
|
$scope.reserve.tickets[evt_px_cat.id] = 0;
|
|
}
|
|
|
|
return $scope.event.offered = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Open a modal window which trigger the stripe payment process
|
|
* @param reservation {Object} to book
|
|
*/
|
|
var 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;
|
|
},
|
|
objectToPay () {
|
|
return {
|
|
eventToReserve: $scope.event,
|
|
reserve: $scope.reserve,
|
|
member: $scope.ctrl.member
|
|
};
|
|
},
|
|
coupon () {
|
|
return $scope.coupon.applied;
|
|
},
|
|
cartItems () {
|
|
return mkRequestParams(reservation, $scope.coupon.applied);
|
|
}
|
|
},
|
|
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', 'wallet', 'helpers', '$filter', 'coupon', 'cartItems',
|
|
function ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl, wallet, helpers, $filter, coupon, cartItems) {
|
|
// User's 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');
|
|
|
|
// Callback to handle the post-payment and reservation
|
|
return $scope.onPaymentSuccess = function (reservation) {
|
|
$uibModalInstance.close(reservation);
|
|
};
|
|
}
|
|
]
|
|
}).result['finally'](null).then(function (reservation) { afterPayment(reservation); });
|
|
};
|
|
|
|
/**
|
|
* Open a modal window which trigger the local payment process
|
|
* @param reservation {Object} to book
|
|
*/
|
|
var 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's wallet amount
|
|
$scope.walletAmount = wallet.amount;
|
|
|
|
// Price
|
|
$scope.price = price.price;
|
|
|
|
// price to pay
|
|
$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('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) }, 'messageformat');
|
|
} else {
|
|
if ((price.price > 0) && ($scope.walletAmount === 0)) {
|
|
$scope.validButtonName = _t('confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')(price.price) }, 'messageformat');
|
|
} else {
|
|
$scope.validButtonName = _t('confirm');
|
|
}
|
|
}
|
|
|
|
// Callback to validate the payment
|
|
$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 = [];
|
|
angular.forEach(response, function (v, k) {
|
|
angular.forEach(v, function (err) {
|
|
$scope.alerts.push({
|
|
msg: k + ': ' + err,
|
|
type: 'danger'
|
|
});
|
|
});
|
|
});
|
|
return $scope.attempting = false;
|
|
});
|
|
};
|
|
|
|
// Callback to cancel the payment
|
|
return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
|
}
|
|
] })
|
|
.result['finally'](null).then(function (reservation) { afterPayment(reservation); });
|
|
};
|
|
|
|
/**
|
|
* What to do after the payment was successful
|
|
* @param resveration {Object} booked reservation
|
|
*/
|
|
var afterPayment = function (reservation) {
|
|
$scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats;
|
|
resetEventReserve();
|
|
$scope.reserveSuccess = true;
|
|
$scope.coupon.applied = null;
|
|
$scope.reservations.push(reservation);
|
|
if ($scope.currentUser.role === 'admin') {
|
|
return $scope.ctrl.member = null;
|
|
}
|
|
};
|
|
|
|
// !!! MUST BE CALLED AT THE END of the controller
|
|
return initialize();
|
|
}
|
|
]);
|
|
|
|
function __range__ (left, right, inclusive) {
|
|
let range = [];
|
|
let ascending = left < right;
|
|
let end = !inclusive ? right : ascending ? right + 1 : right - 1;
|
|
for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {
|
|
range.push(i);
|
|
}
|
|
return range;
|
|
}
|