diff --git a/app/controllers/api/plans_controller.rb b/app/controllers/api/plans_controller.rb index 33252ac63..e0d1769de 100644 --- a/app/controllers/api/plans_controller.rb +++ b/app/controllers/api/plans_controller.rb @@ -68,7 +68,7 @@ class API::PlansController < API::ApiController @parameters = @parameters.require(:plan) .permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling, - :training_credit_nb, :ui_weight, :disabled, + :training_credit_nb, :ui_weight, :disabled, :monthly_payment, plan_file_attributes: %i[id attachment _destroy], prices_attributes: %i[id amount]) end diff --git a/app/frontend/src/javascript/controllers/admin/plans.js b/app/frontend/src/javascript/controllers/admin/plans.js index 32bef24d3..8c57522ca 100644 --- a/app/frontend/src/javascript/controllers/admin/plans.js +++ b/app/frontend/src/javascript/controllers/admin/plans.js @@ -28,15 +28,15 @@ class PlanController { // groups list $scope.groups = groups .filter(function (g) { return (g.slug !== 'admins') && !g.disabled; }) - .map(e => Object.assign({}, e, { category: 'app.shared.plan.groups', id: `${e.id}` })) + .map(e => Object.assign({}, e, { category: 'app.shared.plan.groups', id: `${e.id}` })); $scope.groups.push({ id: 'all', name: 'app.shared.plan.transversal_all_groups', category: 'app.shared.plan.all' }); // dynamically translate a label if needed $scope.translateLabel = function (group, prop) { return group[prop] && group[prop].match(/^app\./) ? _t(group[prop]) : group[prop]; - } + }; - // users with role 'partner', notifiables for a partner plan + // users with role 'partner', notifiable for a partner plan $scope.partners = partners.users; // Subscriptions prices, machines prices and training prices, per groups @@ -93,7 +93,8 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal', is_rolling: false, partnerId: null, partnerContact: null, - ui_weight: 0 + ui_weight: 0, + monthly_payment: false }; // API URL where the form will be posted @@ -144,6 +145,22 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal', }); }; + /** + * This will update the monthly_payment value when the user toggles the switch button + * @param checked {Boolean} + */ + $scope.toggleMonthlyPayment = function (checked) { + toggle('monthly_payment', checked); + }; + + /** + * This will update the is_rolling value when the user toggles the switch button + * @param checked {Boolean} + */ + $scope.toggleIsRolling = function (checked) { + toggle('is_rolling', checked); + }; + /** * Display some messages and redirect the user, once the form was submitted, depending on the result status * (failed/succeeded). @@ -164,6 +181,19 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal', } }; + /* PRIVATE SCOPE */ + /** + * Asynchronously updates the given property with the new provided value + * @param property {string} + * @param value {*} + */ + const toggle = function (property, value) { + setTimeout(() => { + $scope.plan[property] = value; + $scope.$apply(); + }, 50); + }; + return new PlanController($scope, groups, prices, partners, CSRF, _t); } ]); @@ -204,7 +234,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p $scope.selectedGroup = function () { const group = $scope.groups.filter(g => g.id === $scope.plan.group_id); return $scope.translateLabel(group[0], 'name'); - } + }; /** * If a parent plan was set ($scope.plan.parent), the prices will be copied from this parent plan into @@ -216,7 +246,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p Array.from(parentPlan.prices).map(function (parentPrice) { return (function () { const result = []; - for (let childKey in $scope.plan.prices) { + for (const childKey in $scope.plan.prices) { const childPrice = $scope.plan.prices[childKey]; if ((childPrice.priceable_type === parentPrice.priceable_type) && (childPrice.priceable_id === parentPrice.priceable_id)) { $scope.plan.prices[childKey].amount = parentPrice.amount; @@ -235,7 +265,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p } else { return (function () { const result = []; - for (let key in $scope.plan.prices) { + for (const key in $scope.plan.prices) { const price = $scope.plan.prices[key]; result.push($scope.plan.prices[key].amount = 0); } @@ -273,7 +303,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p * @returns {Object} Machine */ $scope.getMachine = function (machine_id) { - for (let machine of Array.from($scope.machines)) { + for (const machine of Array.from($scope.machines)) { if (machine.id === machine_id) { return machine; } @@ -286,7 +316,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p * @returns {Object} Space */ $scope.getSpace = function (space_id) { - for (let space of Array.from($scope.spaces)) { + for (const space of Array.from($scope.spaces)) { if (space.id === space_id) { return space; } diff --git a/app/frontend/src/javascript/directives/settings/boolean-setting.js b/app/frontend/src/javascript/directives/settings/boolean-setting.js index 95a532f75..6fb46768d 100644 --- a/app/frontend/src/javascript/directives/settings/boolean-setting.js +++ b/app/frontend/src/javascript/directives/settings/boolean-setting.js @@ -23,10 +23,8 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t', /** * This will update the value when the user toggles the switch button * @param checked {Boolean} - * @param event {string} - * @param id {string} */ - $scope.toggleSetting = (checked, event, id) => { + $scope.toggleSetting = (checked) => { setTimeout(() => { $scope.setting.value = checked; $scope.$apply(); diff --git a/app/frontend/templates/admin/plans/_form.html b/app/frontend/templates/admin/plans/_form.html index eeae32643..a8534f179 100644 --- a/app/frontend/templates/admin/plans/_form.html +++ b/app/frontend/templates/admin/plans/_form.html @@ -89,6 +89,10 @@ ng-model="plan.amount"/> {{ 'app.shared.plan.price_is_required' }} + + + {{ 'app.shared.plan.edit_amount_info' | translate }} + @@ -106,17 +110,7 @@
- + {{ (plan.is_rolling ? 'app.shared.buttons.yes' : 'app.shared.buttons.no') | translate }} @@ -125,6 +119,13 @@
+
+ + + {{ (plan.monthly_payment ? 'app.shared.buttons.yes' : 'app.shared.buttons.no') | translate }} + + {{ 'app.shared.plan.monthly_payment_info' }} +
diff --git a/app/frontend/templates/plans/index.html b/app/frontend/templates/plans/index.html index 1faa46cb2..3575b5623 100644 --- a/app/frontend/templates/plans/index.html +++ b/app/frontend/templates/plans/index.html @@ -16,7 +16,6 @@
-
diff --git a/app/views/api/plans/_plan.json.jbuilder b/app/views/api/plans/_plan.json.jbuilder index 04fcd4e86..6abf0f2c3 100644 --- a/app/views/api/plans/_plan.json.jbuilder +++ b/app/views/api/plans/_plan.json.jbuilder @@ -1,7 +1,7 @@ # frozen_string_literal: true json.extract! plan, :id, :base_name, :name, :interval, :interval_count, :group_id, :training_credit_nb, :is_rolling, :description, :type, - :ui_weight, :disabled + :ui_weight, :disabled, :monthly_payment json.amount plan.amount / 100.00 json.prices plan.prices, partial: 'api/prices/price', as: :price if plan.plan_file @@ -17,4 +17,4 @@ if plan.respond_to?(:partners) json.last_name partner.last_name json.email partner.email end -end \ No newline at end of file +end diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index a246e8dc2..d92656993 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -175,12 +175,15 @@ en: period_is_required: "Period is required." subscription_price: "Subscription price" price_is_required: "Price is required." + edit_amount_info: "Please note that if you change the price of this plan, the new price will only apply to new subscribers. Current subscriptions will stay unchanged, even those with running payment schedule." visual_prominence_of_the_subscription: "Visual prominence of the subscription" on_the_subscriptions_page_the_most_prominent_subscriptions_will_be_placed_at_the_top_of_the_list: "On the subscriptions page, the most prominent subscriptions will be placed at the top of the list." an_evelated_number_means_a_higher_prominence: "An elevated number means a higher prominence." rolling_subscription: "Rolling subscription?" a_rolling_subscription_will_begin_the_day_of_the_first_training: "A rolling subscription will begin the day of the first trainings." otherwise_it_will_begin_as_soon_as_it_is_bought: "Otherwise, it will begin as soon as it is bought." + monthly_payment: "Monthly payment?" + monthly_payment_info: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months." information_sheet: "Information sheet" attach_an_information_sheet: "Attach an information sheet" notified_partner: "Notified partner" diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index ba46e4698..b32f7a3df 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -175,12 +175,15 @@ fr: period_is_required: "La période est requise." subscription_price: "Coût de l'abonnement" price_is_required: "Le prix est requis." + edit_amount_info: "Veuillez noter que si vous modifiez le prix de cette formule d'abonnement, le nouveau prix ne s'appliquera qu'aux nouveaux abonnés. Les abonnements actuels resteront inchangés, y-compris ceux ayant un échéancier de paiement est en cours." visual_prominence_of_the_subscription: "Importance visuelle de l'abonnement" on_the_subscriptions_page_the_most_prominent_subscriptions_will_be_placed_at_the_top_of_the_list: "Sur la page des abonnements, les abonnements les plus importants seront placés en haut de la liste." an_evelated_number_means_a_higher_prominence: "Un nombre plus élevé traduit une importance plus élevée." rolling_subscription: "Abonnement glissant ?" a_rolling_subscription_will_begin_the_day_of_the_first_training: "Un abonnement glissant prendra effet seulement le jour de la première formation." otherwise_it_will_begin_as_soon_as_it_is_bought: "Dans le cas contraire, il prendra effet dès sa date d'achat." + monthly_payment: "Paiement mensuel ?" + monthly_payment_info: "Si le paiement mensuel est activé, les membres pourront choisir entre un paiement unique ou un échéancier de paiement échelonné chaque mois." information_sheet: "Fiche descriptive" attach_an_information_sheet: "Joindre une fiche descriptive" notified_partner: "Partenaire notifié"