diff --git a/app/assets/javascripts/controllers/plans.coffee.erb b/app/assets/javascripts/controllers/plans.coffee.erb index ba7456780..3e3966c79 100644 --- a/app/assets/javascripts/controllers/plans.coffee.erb +++ b/app/assets/javascripts/controllers/plans.coffee.erb @@ -35,6 +35,14 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop ## plan to subscribe (shopping cart) $scope.selectedPlan = null + ## Discount coupon to apply to the basket, if any + $scope.coupon = + applied: null + + ## Storage for the total price (plan price + coupon, if any) + $scope.cart = + total: null + ## text that appears in the bottom-right box of the page (subscriptions rules details) $scope.subscriptionExplicationsAlert = subscriptionExplicationsPromise.setting.value @@ -61,6 +69,7 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop if $scope.isAuthenticated() if $scope.selectedPlan != plan $scope.selectedPlan = plan + updateCartPrice() else $scope.selectedPlan = null else @@ -153,6 +162,27 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop $scope.$on 'devise:new-session', (event, user)-> $scope.ctrl.member = user + # watch when a coupon is applied to re-compute the total price + $scope.$watch 'coupon.applied', (newValue, oldValue) -> + unless newValue == null and oldValue == null + updateCartPrice() + + + + ## + # Compute the total amount for the current reservation according to the previously set parameters + # and assign the result in $scope.reserve.amountTotal + ## + updateCartPrice = -> + # 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 + discount = $scope.cart.total * $scope.coupon.applied.percent_off / 100 + $scope.cart.total -= discount + else + $scope.reserve.amountTotal = null ## @@ -165,29 +195,43 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop resolve: selectedPlan: -> $scope.selectedPlan member: -> $scope.ctrl.member + price: -> $scope.cart.total wallet: -> Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise - controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription, CustomAsset, wallet, helpers, $locale, $filter) -> + coupon: -> $scope.coupon.applied + controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$locale', '$filter', 'coupon', + ($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, CustomAsset, wallet, helpers, $locale, $filter, coupon) -> # user wallet amount $scope.walletAmount = wallet.amount - $scope.amount = helpers.getAmountToPay(selectedPlan.amount, 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 + # Currency symbol or abreviation for the current locale $scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM + # 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. + ## $scope.payment = (status, response) -> if response.error growl.error(response.error.message) else $scope.attempting = true Subscription.save + coupon_code: coupon.code subscription: plan_id: selectedPlan.id user_id: member.id @@ -217,22 +261,31 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop resolve: selectedPlan: -> $scope.selectedPlan member: -> $scope.ctrl.member + price: -> $scope.cart.total wallet: -> Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise - controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription, wallet, helpers, $locale, $filter) -> + coupon: -> $scope.coupon.applied + controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'wallet', 'helpers', '$locale', '$filter', 'coupon', + ($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, wallet, helpers, $locale, $filter, coupon) -> # user wallet amount $scope.walletAmount = wallet.amount - $scope.price = selectedPlan.amount + # subcription price, coupon subtracted if any + $scope.price = price # price to pay $scope.amount = helpers.getAmountToPay($scope.price, wallet.amount) + # Currency symbol or abreviation for the current locale $scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM + # 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 @@ -244,9 +297,14 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop else $scope.validButtonName = _t('confirm') + ## + # Callback for the 'proceed' button. + # Save the subscription to the API + ## $scope.ok = -> $scope.attempting = true Subscription.save + coupon_code: coupon.code subscription: plan_id: selectedPlan.id user_id: member.id @@ -257,6 +315,10 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop $scope.alerts.push({msg: _t('an_error_occured_during_the_payment_process_please_try_again_later'), type: 'danger' }) $scope.attempting = false + ## + # Callback for the 'cancel' button. + # Close the modal box. + ## $scope.cancel = -> $uibModalInstance.dismiss('cancel') ] diff --git a/app/assets/javascripts/router.coffee.erb b/app/assets/javascripts/router.coffee.erb index 0c7146bdd..f9c32c06a 100644 --- a/app/assets/javascripts/router.coffee.erb +++ b/app/assets/javascripts/router.coffee.erb @@ -478,7 +478,8 @@ angular.module('application.router', ['ui.router']). Group.query().$promise ] translations: [ 'Translations', (Translations) -> - Translations.query(['app.public.plans', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.wallet']).$promise + Translations.query(['app.public.plans', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.wallet', + 'app.shared.coupon_input']).$promise ] # events diff --git a/app/assets/templates/plans/index.html.erb b/app/assets/templates/plans/index.html.erb index 7f30b641b..b9e2ba78d 100644 --- a/app/assets/templates/plans/index.html.erb +++ b/app/assets/templates/plans/index.html.erb @@ -140,10 +140,12 @@ {{ selectedPlan | humanReadablePlanName }}
{{ 'here_is_the_NAME_subscription_summary' | translate:{NAME:member.name} }}
diff --git a/app/assets/templates/shared/valid_reservation_modal.html.erb b/app/assets/templates/shared/valid_reservation_modal.html.erb index 73318045a..510b44029 100644 --- a/app/assets/templates/shared/valid_reservation_modal.html.erb +++ b/app/assets/templates/shared/valid_reservation_modal.html.erb @@ -3,6 +3,7 @@{{ 'here_is_the_summary_of_the_slots_to_book_for_the_current_user' }}
diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb index efcef23b1..017c9b0d3 100644 --- a/app/controllers/api/subscriptions_controller.rb +++ b/app/controllers/api/subscriptions_controller.rb @@ -16,7 +16,7 @@ class API::SubscriptionsController < API::ApiController @subscription = Subscription.find_or_initialize_by(user_id: subscription_params[:user_id]) @subscription.update_column(:expired_at, nil) unless @subscription.new_record? # very important @subscription.attributes = subscription_params - is_subscribe = @subscription.save_with_local_payment(!User.find(subscription_params[:user_id]).invoicing_disabled?) + is_subscribe = @subscription.save_with_local_payment(!User.find(subscription_params[:user_id]).invoicing_disabled?, coupon_params[:coupon_code]) else member = User.find(subscription_params[:user_id]) plan = Plan.find(subscription_params[:plan_id]) @@ -24,7 +24,7 @@ class API::SubscriptionsController < API::ApiController if valid_card_token?(subscription_params[:card_token]) or (member.wallet.amount >= plan.amount / 100.0) @subscription.update_column(:expired_at, nil) unless @subscription.new_record? # very important @subscription.attributes = subscription_params.merge(user_id: current_user.id) - is_subscribe = @subscription.save_with_payment + is_subscribe = @subscription.save_with_payment(true, coupon_params[:coupon_code]) else is_subscribe = false end @@ -62,6 +62,10 @@ class API::SubscriptionsController < API::ApiController params.require(:subscription).permit(:plan_id, :user_id, :card_token) end + def coupon_params + params.permit(:coupon_code) + end + def subscription_update_params params.require(:subscription).permit(:expired_at) end diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 9ea2a2110..5717a1dce 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -18,7 +18,7 @@ class Subscription < ActiveRecord::Base after_save :notify_partner_subscribed_plan, if: :of_partner_plan? # Stripe subscription payment - def save_with_payment(invoice = true) + def save_with_payment(invoice = true, coupon_code = nil) if valid? customer = Stripe::Customer.retrieve(user.stp_customer_id) begin @@ -33,6 +33,17 @@ class Subscription < ActiveRecord::Base description: "wallet -#{@wallet_amount_debit / 100.0}" ) end + + unless coupon_code.nil? + cp = Coupon.find_by_code(coupon_code) + total = plan.amount + Stripe::InvoiceItem.create( + customer: user.stp_customer_id, + amount: -(total * cp.percent_off / 100), + currency: Rails.application.secrets.stripe_currency, + description: "coupon #{cp.code}" + ) + end end new_subscription = customer.subscriptions.create(plan: plan.stp_plan_id, source: card_token) @@ -46,7 +57,7 @@ class Subscription < ActiveRecord::Base # generate invoice stp_invoice = Stripe::Invoice.all(customer: user.stp_customer_id, limit: 1).data.first if invoice - invoc = generate_invoice(stp_invoice.id) + invoc = generate_invoice(stp_invoice.id, coupon_code) # debit wallet wallet_transaction = debit_user_wallet if wallet_transaction @@ -93,7 +104,7 @@ class Subscription < ActiveRecord::Base end end - def save_with_local_payment(invoice = true) + def save_with_local_payment(invoice = true, coupon_code = nil) if valid? @wallet_amount_debit = get_wallet_amount_debit if invoice @@ -103,7 +114,7 @@ class Subscription < ActiveRecord::Base save! UsersCredits::Manager.new(user: self.user).reset_credits if expired_date_changed if invoice - invoc = generate_invoice + invoc = generate_invoice(nil, coupon_code) # debit wallet wallet_transaction = debit_user_wallet if wallet_transaction @@ -118,8 +129,17 @@ class Subscription < ActiveRecord::Base end end - def generate_invoice(stp_invoice_id = nil) - invoice = Invoice.new(invoiced_id: id, invoiced_type: 'Subscription', user: user, total: plan.amount, stp_invoice_id: stp_invoice_id) + def generate_invoice(stp_invoice_id = nil, coupon_code = nil) + coupon_id = nil + total = plan.amount + + unless coupon_code.nil? + coupon = Coupon.find_by_code(coupon_code) + coupon_id = coupon.id + total = plan.amount - (plan.amount * coupon.percent_off / 100) + end + + invoice = Invoice.new(invoiced_id: id, invoiced_type: 'Subscription', user: user, total: total, stp_invoice_id: stp_invoice_id, coupon_id: coupon_id) invoice.invoice_items.push InvoiceItem.new(amount: plan.amount, stp_invoice_item_id: stp_subscription_id, description: plan.name, subscription_id: self.id) invoice end