mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-04-11 01:02:34 +02:00
[bug] wallet usage is noted on subscription invoices even if wallet was not used + use payment confirm API for subscriptions only (sca)
This commit is contained in:
parent
4d0ac9b3ca
commit
ac0489a496
@ -246,6 +246,14 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
|||||||
// Used in wallet info template to interpolate some translations
|
// Used in wallet info template to interpolate some translations
|
||||||
$scope.numberFilter = $filter('number');
|
$scope.numberFilter = $filter('number');
|
||||||
|
|
||||||
|
// Cart items
|
||||||
|
$scope.cartItems = {
|
||||||
|
coupon_code: ((coupon ? coupon.code : undefined)),
|
||||||
|
subscription: {
|
||||||
|
plan_id: selectedPlan.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// retrieve the CGV
|
// retrieve the CGV
|
||||||
CustomAsset.get({ name: 'cgv-file' }, function (cgv) { $scope.cgv = cgv.custom_asset; });
|
CustomAsset.get({ name: 'cgv-file' }, function (cgv) { $scope.cgv = cgv.custom_asset; });
|
||||||
|
|
||||||
@ -254,29 +262,8 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
|||||||
* Handle the stripe's card tokenization process response and save the subscription to the API with the
|
* Handle the stripe's card tokenization process response and save the subscription to the API with the
|
||||||
* card token just created.
|
* card token just created.
|
||||||
*/
|
*/
|
||||||
$scope.payment = function (status, response) {
|
$scope.onPaymentSuccess = function (response) {
|
||||||
if (response.error) {
|
$uibModalInstance.close(response);
|
||||||
growl.error(response.error.message);
|
|
||||||
} else {
|
|
||||||
$scope.attempting = true;
|
|
||||||
Subscription.save({
|
|
||||||
coupon_code: ((coupon ? coupon.code : undefined)),
|
|
||||||
subscription: {
|
|
||||||
plan_id: selectedPlan.id,
|
|
||||||
user_id: member.id,
|
|
||||||
card_token: response.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, function (data) { // success
|
|
||||||
$uibModalInstance.close(data);
|
|
||||||
}
|
|
||||||
, function (data, status) { // failed
|
|
||||||
$scope.alerts = [];
|
|
||||||
$scope.alerts.push({ msg: _t('an_error_occured_during_the_payment_process_please_try_again_later'), type: 'danger' });
|
|
||||||
$scope.attempting = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -367,7 +354,7 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
|||||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}).result['finally'](null).then(function (reservation) {
|
}).result['finally'](null).then(function (subscription) {
|
||||||
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
|
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);
|
||||||
Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);
|
Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);
|
||||||
$scope.ctrl.member = null;
|
$scope.ctrl.member = null;
|
||||||
|
@ -19,28 +19,32 @@ class API::PaymentsController < API::ApiController
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Compute the price
|
# Compute the price
|
||||||
reservable = cart_items_params[:reservable_type].constantize.find(cart_items_params[:reservable_id])
|
if params[:cart_items][:reservation]
|
||||||
price_details = Price.compute(false,
|
reservable = cart_items_params[:reservable_type].constantize.find(cart_items_params[:reservable_id])
|
||||||
current_user,
|
price_details = Price.compute(false,
|
||||||
reservable,
|
current_user,
|
||||||
cart_items_params[:slots_attributes] || [],
|
reservable,
|
||||||
cart_items_params[:plan_id],
|
cart_items_params[:slots_attributes] || [],
|
||||||
cart_items_params[:nb_reserve_places],
|
cart_items_params[:plan_id],
|
||||||
cart_items_params[:tickets_attributes],
|
cart_items_params[:nb_reserve_places],
|
||||||
coupon_params[:coupon_code])
|
cart_items_params[:tickets_attributes],
|
||||||
|
coupon_params[:coupon_code])
|
||||||
# Subtract wallet amount from total
|
|
||||||
total = price_details[:total]
|
|
||||||
wallet_debit = get_wallet_debit(current_user, total)
|
|
||||||
|
|
||||||
|
# Subtract wallet amount from total
|
||||||
|
total = price_details[:total]
|
||||||
|
wallet_debit = get_wallet_debit(current_user, total)
|
||||||
|
amount = total - wallet_debit
|
||||||
|
elsif params[:cart_items][:subscription]
|
||||||
|
amount = 2000 # TODO
|
||||||
|
end
|
||||||
# Create the PaymentIntent
|
# Create the PaymentIntent
|
||||||
intent = Stripe::PaymentIntent.create(
|
intent = Stripe::PaymentIntent.create(
|
||||||
payment_method: params[:payment_method_id],
|
payment_method: params[:payment_method_id],
|
||||||
amount: total - wallet_debit,
|
amount: amount,
|
||||||
currency: Rails.application.secrets.stripe_currency,
|
currency: Rails.application.secrets.stripe_currency,
|
||||||
confirmation_method: 'manual',
|
confirmation_method: 'manual',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
customer: current_user.stp_customer_id,
|
customer: current_user.stp_customer_id
|
||||||
)
|
)
|
||||||
elsif params[:payment_intent_id].present?
|
elsif params[:payment_intent_id].present?
|
||||||
intent = Stripe::PaymentIntent.confirm(params[:payment_intent_id])
|
intent = Stripe::PaymentIntent.confirm(params[:payment_intent_id])
|
||||||
@ -48,20 +52,26 @@ class API::PaymentsController < API::ApiController
|
|||||||
rescue Stripe::CardError => e
|
rescue Stripe::CardError => e
|
||||||
# Display error on client
|
# Display error on client
|
||||||
render(status: 200, json: { error: e.message }) and return
|
render(status: 200, json: { error: e.message }) and return
|
||||||
|
rescue InvalidCouponError
|
||||||
|
render(json: { coupon_code: 'wrong coupon code or expired' }, status: :unprocessable_entity) and return
|
||||||
|
end
|
||||||
|
|
||||||
|
if intent.status == 'succeeded'
|
||||||
|
if params[:cart_items][:reservation]
|
||||||
|
render(on_reservation_success(intent)) and return
|
||||||
|
elsif params[:cart_items][:subscription]
|
||||||
|
render(on_subscription_success(intent)) and return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
render(on_payment_success(intent)) and return if intent.status == 'succeeded'
|
|
||||||
render generate_payment_response(intent)
|
render generate_payment_response(intent)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def on_payment_success(intent)
|
def on_reservation_success(intent)
|
||||||
# TODO create subscription is needed
|
|
||||||
user_id = params[:cart_items][:reservation][:user_id]
|
|
||||||
|
|
||||||
@reservation = Reservation.new(reservation_params)
|
@reservation = Reservation.new(reservation_params)
|
||||||
is_reserve = Reservations::Reserve.new(user_id, current_user.invoicing_profile.id)
|
is_reserve = Reservations::Reserve.new(current_user.id, current_user.invoicing_profile.id)
|
||||||
.pay_and_save(@reservation, coupon: coupon_params[:coupon_code], payment_intent_id: intent.id)
|
.pay_and_save(@reservation, coupon: coupon_params[:coupon_code], payment_intent_id: intent.id)
|
||||||
Stripe::PaymentIntent.update(
|
Stripe::PaymentIntent.update(
|
||||||
intent.id,
|
intent.id,
|
||||||
@ -75,8 +85,23 @@ class API::PaymentsController < API::ApiController
|
|||||||
else
|
else
|
||||||
{ json: @reservation.errors, status: :unprocessable_entity }
|
{ json: @reservation.errors, status: :unprocessable_entity }
|
||||||
end
|
end
|
||||||
rescue InvalidCouponError
|
end
|
||||||
{ json: { coupon_code: 'wrong coupon code or expired' }, status: :unprocessable_entity }
|
|
||||||
|
def on_subscription_success(intent)
|
||||||
|
@subscription = Subscription.new(subscription_params)
|
||||||
|
is_subscribe = Subscriptions::Subscribe.new(current_user.invoicing_profile.id, current_user.id)
|
||||||
|
.pay_and_save(@subscription, coupon: coupon_params[:coupon_code], invoice: true, payment_intent_id: intent.id)
|
||||||
|
|
||||||
|
Stripe::PaymentIntent.update(
|
||||||
|
intent.id,
|
||||||
|
description: "Invoice reference: #{@subscription.invoices.first.reference}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_subscribe
|
||||||
|
{ template: 'api/subscriptions/show', status: :created, location: @subscription }
|
||||||
|
else
|
||||||
|
{ json: @subscription.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_payment_response(intent)
|
def generate_payment_response(intent)
|
||||||
@ -110,6 +135,10 @@ class API::PaymentsController < API::ApiController
|
|||||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def subscription_params
|
||||||
|
params[:cart_items].require(:subscription).permit(:plan_id)
|
||||||
|
end
|
||||||
|
|
||||||
def cart_items_params
|
def cart_items_params
|
||||||
params[:cart_items].require(:reservation).permit(:reservable_id, :reservable_type, :plan_id, :user_id, :nb_reserve_places,
|
params[:cart_items].require(:reservation).permit(:reservable_id, :reservable_type, :plan_id, :user_id, :nb_reserve_places,
|
||||||
tickets_attributes: %i[event_price_category_id booked],
|
tickets_attributes: %i[event_price_category_id booked],
|
||||||
|
@ -57,7 +57,7 @@ class API::ReservationsController < API::ApiController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def reservation_params
|
def reservation_params
|
||||||
params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :card_token, :plan_id, :nb_reserve_places,
|
params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :plan_id, :nb_reserve_places,
|
||||||
tickets_attributes: %i[event_price_category_id booked],
|
tickets_attributes: %i[event_price_category_id booked],
|
||||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||||
end
|
end
|
||||||
|
@ -16,7 +16,7 @@ class API::SubscriptionsController < API::ApiController
|
|||||||
|
|
||||||
@subscription = Subscription.new(subscription_params)
|
@subscription = Subscription.new(subscription_params)
|
||||||
is_subscribe = Subscriptions::Subscribe.new(current_user.invoicing_profile.id, user_id)
|
is_subscribe = Subscriptions::Subscribe.new(current_user.invoicing_profile.id, user_id)
|
||||||
.pay_and_save(@subscription, coupon_params[:coupon_code], true)
|
.pay_and_save(@subscription, coupon: coupon_params[:coupon_code], invoice: true)
|
||||||
|
|
||||||
if is_subscribe
|
if is_subscribe
|
||||||
render :show, status: :created, location: @subscription
|
render :show, status: :created, location: @subscription
|
||||||
@ -51,7 +51,7 @@ class API::SubscriptionsController < API::ApiController
|
|||||||
|
|
||||||
# Never trust parameters from the scary internet, only allow the white list through.
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
def subscription_params
|
def subscription_params
|
||||||
params.require(:subscription).permit(:plan_id, :card_token)
|
params.require(:subscription).permit(:plan_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def coupon_params
|
def coupon_params
|
||||||
@ -61,12 +61,4 @@ class API::SubscriptionsController < API::ApiController
|
|||||||
def subscription_update_params
|
def subscription_update_params
|
||||||
params.require(:subscription).permit(:expired_at)
|
params.require(:subscription).permit(:expired_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO, refactor subscriptions logic and move this in model/validator
|
|
||||||
def valid_card_token?(token)
|
|
||||||
Stripe::Token.retrieve(token)
|
|
||||||
rescue Stripe::InvalidRequestError => e
|
|
||||||
@subscription.errors[:card_token] << e.message
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,7 @@ class Reservation < ActiveRecord::Base
|
|||||||
validate :machine_not_already_reserved, if: -> { reservable.is_a?(Machine) }
|
validate :machine_not_already_reserved, if: -> { reservable.is_a?(Machine) }
|
||||||
validate :training_not_fully_reserved, if: -> { reservable.is_a?(Training) }
|
validate :training_not_fully_reserved, if: -> { reservable.is_a?(Training) }
|
||||||
|
|
||||||
attr_accessor :card_token, :plan_id, :subscription
|
attr_accessor :plan_id, :subscription
|
||||||
|
|
||||||
after_commit :notify_member_create_reservation, on: :create
|
after_commit :notify_member_create_reservation, on: :create
|
||||||
after_commit :notify_admin_member_create_reservation, on: :create
|
after_commit :notify_admin_member_create_reservation, on: :create
|
||||||
|
@ -13,8 +13,6 @@ class Subscription < ActiveRecord::Base
|
|||||||
validates_presence_of :plan_id
|
validates_presence_of :plan_id
|
||||||
validates_with SubscriptionGroupValidator
|
validates_with SubscriptionGroupValidator
|
||||||
|
|
||||||
attr_accessor :card_token
|
|
||||||
|
|
||||||
# creation
|
# creation
|
||||||
after_save :notify_member_subscribed_plan
|
after_save :notify_member_subscribed_plan
|
||||||
after_save :notify_admin_subscribed_plan
|
after_save :notify_admin_subscribed_plan
|
||||||
@ -22,7 +20,7 @@ class Subscription < ActiveRecord::Base
|
|||||||
|
|
||||||
# @param invoice if true then only the subscription is payed, without reservation
|
# @param invoice if true then only the subscription is payed, without reservation
|
||||||
# if false then the subscription is payed with reservation
|
# if false then the subscription is payed with reservation
|
||||||
def save_with_payment(operator_profile_id, invoice = true, coupon_code = nil)
|
def save_with_payment(operator_profile_id, invoice = true, coupon_code = nil, payment_intent_id = nil)
|
||||||
return false unless valid?
|
return false unless valid?
|
||||||
|
|
||||||
set_expiration_date
|
set_expiration_date
|
||||||
@ -35,7 +33,7 @@ class Subscription < ActiveRecord::Base
|
|||||||
# debit wallet
|
# debit wallet
|
||||||
wallet_transaction = debit_user_wallet
|
wallet_transaction = debit_user_wallet
|
||||||
|
|
||||||
invoc = generate_invoice(operator_profile_id, coupon_code)
|
invoc = generate_invoice(operator_profile_id, coupon_code, payment_intent_id)
|
||||||
if wallet_transaction
|
if wallet_transaction
|
||||||
invoc.wallet_amount = @wallet_amount_debit
|
invoc.wallet_amount = @wallet_amount_debit
|
||||||
invoc.wallet_transaction_id = wallet_transaction.id
|
invoc.wallet_transaction_id = wallet_transaction.id
|
||||||
@ -45,7 +43,7 @@ class Subscription < ActiveRecord::Base
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_invoice(operator_profile_id, coupon_code = nil)
|
def generate_invoice(operator_profile_id, coupon_code = nil, payment_intent_id = nil)
|
||||||
coupon_id = nil
|
coupon_id = nil
|
||||||
total = plan.amount
|
total = plan.amount
|
||||||
|
|
||||||
@ -65,7 +63,8 @@ class Subscription < ActiveRecord::Base
|
|||||||
statistic_profile: user.statistic_profile,
|
statistic_profile: user.statistic_profile,
|
||||||
total: total,
|
total: total,
|
||||||
coupon_id: coupon_id,
|
coupon_id: coupon_id,
|
||||||
operator_profile_id: operator_profile_id
|
operator_profile_id: operator_profile_id,
|
||||||
|
stp_payment_intent_id: payment_intent_id
|
||||||
)
|
)
|
||||||
invoice.invoice_items.push InvoiceItem.new(
|
invoice.invoice_items.push InvoiceItem.new(
|
||||||
amount: plan.amount,
|
amount: plan.amount,
|
||||||
@ -194,7 +193,7 @@ class Subscription < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def debit_user_wallet
|
def debit_user_wallet
|
||||||
return unless @wallet_amount_debit.present? || @wallet_amount_debit.zero?
|
return if !@wallet_amount_debit.present? || @wallet_amount_debit.zero?
|
||||||
|
|
||||||
amount = @wallet_amount_debit / 100.0
|
amount = @wallet_amount_debit / 100.0
|
||||||
WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
|
WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
|
||||||
|
@ -9,11 +9,11 @@ class Subscriptions::Subscribe
|
|||||||
@operator_profile_id = operator_profile_id
|
@operator_profile_id = operator_profile_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def pay_and_save(subscription, coupon, invoice)
|
def pay_and_save(subscription, coupon: nil, invoice: nil, payment_intent_id: nil)
|
||||||
return false if user_id.nil?
|
return false if user_id.nil?
|
||||||
|
|
||||||
subscription.statistic_profile_id = StatisticProfile.find_by(user_id: user_id).id
|
subscription.statistic_profile_id = StatisticProfile.find_by(user_id: user_id).id
|
||||||
subscription.save_with_payment(operator_profile_id, invoice, coupon)
|
subscription.save_with_payment(operator_profile_id, invoice, coupon, payment_intent_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def extend_subscription(subscription, new_expiration_date, free_days)
|
def extend_subscription(subscription, new_expiration_date, free_days)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user