2018-10-25 16:50:16 +02:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
'use strict';
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
Application.Controllers.controller("PlansIndexController", ["$scope", "$rootScope", "$state", '$uibModal', 'Auth', 'dialogs', 'growl', 'plansPromise', 'groupsPromise', 'Subscription', 'Member', 'subscriptionExplicationsPromise', '_t', 'Wallet', 'helpers'
|
|
|
|
, function($scope, $rootScope, $state, $uibModal, Auth, dialogs, growl, plansPromise, groupsPromise, Subscription, Member, subscriptionExplicationsPromise, _t, Wallet, helpers) {
|
2016-03-23 18:39:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
/* PUBLIC SCOPE */
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# list of groups
|
|
|
|
let plan;
|
|
|
|
$scope.groups = groupsPromise.filter(g => (g.slug !== 'admins') & !g.disabled);
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# default : do not show the group changing form
|
|
|
|
//# group ID of the current/selected user
|
|
|
|
$scope.group = {
|
|
|
|
change: false,
|
2016-04-11 19:26:40 +02:00
|
|
|
id: null
|
2018-10-25 16:50:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
//# list of plans, classified by group
|
|
|
|
$scope.plansClassifiedByGroup = [];
|
|
|
|
for (var group of Array.from($scope.groups)) {
|
|
|
|
const groupObj = { id: group.id, name: group.name, plans: [] };
|
|
|
|
for (plan of Array.from(plansPromise)) {
|
|
|
|
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
|
|
|
}
|
|
|
|
$scope.plansClassifiedByGroup.push(groupObj);
|
|
|
|
}
|
|
|
|
|
|
|
|
//# user to deal with
|
|
|
|
$scope.ctrl = {
|
|
|
|
member: null,
|
2016-03-23 18:39:41 +01:00
|
|
|
member_id: null
|
2018-10-25 16:50:16 +02:00
|
|
|
};
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# already subscribed plan of the current user
|
2016-08-11 18:30:59 +02:00
|
|
|
$scope.paid =
|
2018-10-25 16:50:16 +02:00
|
|
|
{plan: null};
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# plan to subscribe (shopping cart)
|
|
|
|
$scope.selectedPlan = null;
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# Discount coupon to apply to the basket, if any
|
2016-08-11 18:17:28 +02:00
|
|
|
$scope.coupon =
|
2018-10-25 16:50:16 +02:00
|
|
|
{applied: null};
|
2016-08-11 18:17:28 +02:00
|
|
|
|
2018-10-25 16:50:16 +02:00
|
|
|
//# Storage for the total price (plan price + coupon, if any)
|
2016-08-11 18:17:28 +02:00
|
|
|
$scope.cart =
|
2018-10-25 16:50:16 +02:00
|
|
|
{total: null};
|
|
|
|
|
|
|
|
//# text that appears in the bottom-right box of the page (subscriptions rules details)
|
|
|
|
$scope.subscriptionExplicationsAlert = subscriptionExplicationsPromise.setting.value;
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Callback to deal with the subscription of the user selected in the dropdown list instead of the current user's
|
|
|
|
// subscription. (admins only)
|
|
|
|
//#
|
|
|
|
$scope.updateMember = function() {
|
|
|
|
$scope.selectedPlan = null;
|
|
|
|
$scope.paid.plan = null;
|
|
|
|
$scope.group.change = false;
|
|
|
|
return Member.get({id: $scope.ctrl.member.id}, function(member) {
|
|
|
|
$scope.ctrl.member = member;
|
|
|
|
return $scope.group.id = $scope.ctrl.member.group_id;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Add the provided plan to the shopping basket
|
|
|
|
// @param plan {Object} The plan to subscribe to
|
|
|
|
//#
|
|
|
|
$scope.selectPlan = function(plan) {
|
|
|
|
if ($scope.isAuthenticated()) {
|
|
|
|
if ($scope.selectedPlan !== plan) {
|
|
|
|
$scope.selectedPlan = plan;
|
|
|
|
return updateCartPrice();
|
|
|
|
} else {
|
|
|
|
return $scope.selectedPlan = null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $scope.login();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Callback to trigger the payment process of the subscription
|
|
|
|
//#
|
|
|
|
$scope.openSubscribePlanModal = () =>
|
|
|
|
Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}, function(wallet) {
|
|
|
|
const amountToPay = helpers.getAmountToPay($scope.cart.total, wallet.amount);
|
|
|
|
if (($scope.currentUser.role !== 'admin') && (amountToPay > 0)) {
|
|
|
|
return payByStripe();
|
|
|
|
} else {
|
|
|
|
if (($scope.currentUser.role === 'admin') || (amountToPay === 0)) {
|
|
|
|
return payOnSite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Return the group object, identified by the ID set in $scope.group.id
|
|
|
|
//#
|
|
|
|
$scope.getUserGroup = function() {
|
|
|
|
for (group of Array.from($scope.groups)) {
|
|
|
|
if (group.id === $scope.group.id) {
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Change the group of the current/selected user to the one set in $scope.group.id
|
|
|
|
//#
|
|
|
|
$scope.selectGroup = () =>
|
|
|
|
Member.update({id: $scope.ctrl.member.id}, {user: {group_id: $scope.group.id}}, function(user) {
|
|
|
|
$scope.ctrl.member = user;
|
|
|
|
$scope.group.change = false;
|
|
|
|
if ($scope.currentUser.role !== 'admin') {
|
|
|
|
$rootScope.currentUser = user;
|
|
|
|
Auth._currentUser.group_id = user.group_id;
|
|
|
|
return growl.success(_t('your_group_was_successfully_changed'));
|
|
|
|
} else {
|
|
|
|
return growl.success(_t('the_user_s_group_was_successfully_changed'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, function(err) {
|
|
|
|
if ($scope.currentUser.role !== 'admin') {
|
|
|
|
growl.error(_t('an_error_prevented_your_group_from_being_changed'));
|
|
|
|
} else {
|
|
|
|
growl.error(_t('an_error_prevented_to_change_the_user_s_group'));
|
|
|
|
}
|
|
|
|
return console.error(err);
|
|
|
|
})
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Return an enumerable meaninful string for the gender of the provider user
|
|
|
|
// @param user {Object} Database user record
|
|
|
|
// @return {string} 'male' or 'female'
|
|
|
|
//#
|
|
|
|
$scope.getGender = function(user) {
|
|
|
|
if (user && user.profile) {
|
|
|
|
if (user.profile.gender === "true") { return 'male'; } else { return 'female'; }
|
|
|
|
} else { return 'other'; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Test if the provided date is in the future
|
|
|
|
// @param dateTime {Date}
|
|
|
|
// @return {boolean}
|
|
|
|
//#
|
|
|
|
$scope.isInFuture = function(dateTime){
|
|
|
|
if (moment().diff(moment(dateTime)) < 0) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// To use as callback in Array.prototype.filter to get only enabled plans
|
|
|
|
//#
|
|
|
|
$scope.filterDisabledPlans = plan => !plan.disabled;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* PRIVATE SCOPE */
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Kind of constructor: these actions will be realized first when the controller is loaded
|
|
|
|
//#
|
|
|
|
const initialize = function() {
|
|
|
|
if ($scope.currentUser) {
|
|
|
|
if ($scope.currentUser.role !== 'admin') {
|
|
|
|
$scope.ctrl.member = $scope.currentUser;
|
|
|
|
$scope.paid.plan = $scope.currentUser.subscribed_plan;
|
|
|
|
$scope.group.id = $scope.currentUser.group_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$scope.$on('devise:new-session', (event, user)=> $scope.ctrl.member = user);
|
|
|
|
|
|
|
|
// 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 updateCartPrice();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Compute the total amount for the current reservation according to the previously set parameters
|
|
|
|
// and assign the result in $scope.reserve.amountTotal
|
|
|
|
//#
|
|
|
|
var updateCartPrice = function() {
|
|
|
|
// first we check that a user was selected
|
|
|
|
if (Object.keys($scope.ctrl.member).length > 0) {
|
|
|
|
$scope.cart.total = $scope.selectedPlan.amount;
|
|
|
|
// apply the coupon if any
|
|
|
|
if ($scope.coupon.applied) {
|
|
|
|
let discount;
|
|
|
|
if ($scope.coupon.applied.type === 'percent_off') {
|
|
|
|
discount = ($scope.cart.total * $scope.coupon.applied.percent_off) / 100;
|
|
|
|
} else if ($scope.coupon.applied.type === 'amount_off') {
|
|
|
|
discount = $scope.coupon.applied.amount_off;
|
|
|
|
}
|
|
|
|
return $scope.cart.total -= discount;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $scope.reserve.amountTotal = null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Open a modal window which trigger the stripe payment process
|
|
|
|
//#
|
|
|
|
var payByStripe = () =>
|
|
|
|
$uibModal.open({
|
|
|
|
templateUrl: '<%= asset_path "stripe/payment_modal.html" %>',
|
|
|
|
size: 'md',
|
|
|
|
resolve: {
|
|
|
|
selectedPlan() { return $scope.selectedPlan; },
|
|
|
|
member() { return $scope.ctrl.member; },
|
|
|
|
price() { return $scope.cart.total; },
|
|
|
|
wallet() {
|
|
|
|
return Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise;
|
|
|
|
},
|
|
|
|
coupon() { return $scope.coupon.applied; }
|
|
|
|
},
|
2016-11-23 14:27:11 +01:00
|
|
|
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$filter', 'coupon',
|
2018-10-25 16:50:16 +02:00
|
|
|
function($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, CustomAsset, wallet, helpers, $filter, coupon) {
|
|
|
|
// User's wallet amount
|
|
|
|
$scope.walletAmount = wallet.amount;
|
|
|
|
|
|
|
|
// Final price to pay by the user
|
|
|
|
$scope.amount = helpers.getAmountToPay(price, wallet.amount);
|
|
|
|
|
|
|
|
// The plan that the user is about to subscribe
|
|
|
|
$scope.selectedPlan = selectedPlan;
|
|
|
|
|
|
|
|
// Used in wallet info template to interpolate some translations
|
|
|
|
$scope.numberFilter = $filter('number');
|
|
|
|
|
|
|
|
// retrieve the CGV
|
|
|
|
CustomAsset.get({name: 'cgv-file'}, cgv => $scope.cgv = cgv.custom_asset);
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Callback for click on the 'proceed' button.
|
|
|
|
// Handle the stripe's card tokenization process response and save the subscription to the API with the
|
|
|
|
// card token just created.
|
|
|
|
//#
|
|
|
|
return $scope.payment = function(status, response) {
|
|
|
|
if (response.error) {
|
|
|
|
return growl.error(response.error.message);
|
|
|
|
} else {
|
|
|
|
$scope.attempting = true;
|
|
|
|
return Subscription.save({
|
|
|
|
coupon_code: ((coupon ? coupon.code : undefined)),
|
|
|
|
subscription: {
|
|
|
|
plan_id: selectedPlan.id,
|
|
|
|
user_id: member.id,
|
2016-03-23 18:39:41 +01:00
|
|
|
card_token: response.id
|
2018-10-25 16:50:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
, (data, status) => // success
|
2016-03-23 18:39:41 +01:00
|
|
|
$uibModalInstance.close(data)
|
2018-10-25 16:50:16 +02:00
|
|
|
|
|
|
|
, function(data, status) { // failed
|
|
|
|
$scope.alerts = [];
|
|
|
|
$scope.alerts.push({msg: _t('an_error_occured_during_the_payment_process_please_try_again_later'), type: 'danger' });
|
|
|
|
return $scope.attempting = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
]})
|
|
|
|
.result['finally'](null).then(function(subscription){
|
|
|
|
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
|
|
|
|
Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);
|
|
|
|
$scope.paid.plan = angular.copy($scope.selectedPlan);
|
|
|
|
$scope.selectedPlan = null;
|
|
|
|
return $scope.coupon.applied = null;
|
|
|
|
})
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Open a modal window which trigger the local payment process
|
|
|
|
//#
|
|
|
|
var payOnSite = () =>
|
|
|
|
$uibModal.open({
|
|
|
|
templateUrl: '<%= asset_path "plans/payment_modal.html" %>',
|
|
|
|
size: 'sm',
|
|
|
|
resolve: {
|
|
|
|
selectedPlan() { return $scope.selectedPlan; },
|
|
|
|
member() { return $scope.ctrl.member; },
|
|
|
|
price() { return $scope.cart.total; },
|
|
|
|
wallet() {
|
|
|
|
return Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise;
|
|
|
|
},
|
|
|
|
coupon() { return $scope.coupon.applied; }
|
|
|
|
},
|
2016-11-23 14:27:11 +01:00
|
|
|
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'wallet', 'helpers', '$filter', 'coupon',
|
2018-10-25 16:50:16 +02:00
|
|
|
function($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, wallet, helpers, $filter, coupon) {
|
|
|
|
// user wallet amount
|
|
|
|
$scope.walletAmount = wallet.amount;
|
|
|
|
|
|
|
|
// subcription price, coupon subtracted if any
|
|
|
|
$scope.price = price;
|
|
|
|
|
|
|
|
// price to pay
|
|
|
|
$scope.amount = helpers.getAmountToPay($scope.price, wallet.amount);
|
|
|
|
|
|
|
|
// Used in wallet info template to interpolate some translations
|
|
|
|
$scope.numberFilter = $filter('number');
|
|
|
|
|
|
|
|
// The plan that the user is about to subscribe
|
|
|
|
$scope.plan = selectedPlan;
|
|
|
|
|
|
|
|
// The member who is subscribing a plan
|
|
|
|
$scope.member = member;
|
|
|
|
|
|
|
|
// 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 for the 'proceed' button.
|
|
|
|
// Save the subscription to the API
|
|
|
|
//#
|
|
|
|
$scope.ok = function() {
|
|
|
|
$scope.attempting = true;
|
|
|
|
return Subscription.save({
|
|
|
|
coupon_code: ((coupon ? coupon.code : undefined)),
|
|
|
|
subscription: {
|
|
|
|
plan_id: selectedPlan.id,
|
2016-03-23 18:39:41 +01:00
|
|
|
user_id: member.id
|
2018-10-25 16:50:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
, (data, status) => // success
|
2016-03-23 18:39:41 +01:00
|
|
|
$uibModalInstance.close(data)
|
2018-10-25 16:50:16 +02:00
|
|
|
|
|
|
|
, function(data, status) { // failed
|
|
|
|
$scope.alerts = [];
|
|
|
|
$scope.alerts.push({msg: _t('an_error_occured_during_the_payment_process_please_try_again_later'), type: 'danger' });
|
|
|
|
return $scope.attempting = false;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
//#
|
|
|
|
// Callback for the 'cancel' button.
|
|
|
|
// Close the modal box.
|
|
|
|
//#
|
|
|
|
return $scope.cancel = () => $uibModalInstance.dismiss('cancel');
|
|
|
|
}
|
|
|
|
]})
|
|
|
|
.result['finally'](null).then(function(reservation){
|
|
|
|
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
|
|
|
|
Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);
|
|
|
|
$scope.ctrl.member = null;
|
|
|
|
$scope.paid.plan = angular.copy($scope.selectedPlan);
|
|
|
|
$scope.selectedPlan = null;
|
|
|
|
return $scope.coupon.applied = null;
|
|
|
|
})
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//# !!! MUST BE CALLED AT THE END of the controller
|
|
|
|
return initialize();
|
|
|
|
}
|
|
|
|
]);
|