mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
(bug) cannot cancel a subscription after offering free days
This commit is contained in:
parent
6c53b01741
commit
8740c4971d
@ -10,6 +10,7 @@
|
||||
- Filter projects by status
|
||||
- Maximum validity period for trainings authorizations
|
||||
- Automatically cancel trainings with insufficient attendees
|
||||
- Fix a bug: cannot cancel a subscription after offering free days
|
||||
- Fix a bug: event image updates are not reflected unless the browser's cache is purged
|
||||
- Fix a bug: schedules jobs are not launched at the right time
|
||||
- Fix a bug: unable to update the title of a training
|
||||
|
@ -11,7 +11,7 @@ class API::SlotsReservationsController < API::ApiController
|
||||
def update
|
||||
authorize @slot_reservation
|
||||
if @slot_reservation.update(slot_params)
|
||||
SubscriptionExtensionAfterReservation.new(@slot_reservation.reservation).extend_subscription_if_eligible
|
||||
Subscriptions::ExtensionAfterReservation.new(@slot_reservation.reservation).extend_subscription_if_eligible
|
||||
render :show, status: :ok, location: @slot_reservation
|
||||
else
|
||||
render json: @slot_reservation.errors, status: :unprocessable_entity
|
||||
|
@ -15,7 +15,7 @@ class API::SubscriptionsController < API::ApiController
|
||||
|
||||
def cancel
|
||||
authorize @subscription
|
||||
if @subscription.expire(Time.current)
|
||||
if @subscription.expire
|
||||
render :show, status: :ok, location: @subscription
|
||||
else
|
||||
render json: { error: 'already expired' }, status: :unprocessable_entity
|
||||
|
@ -17,7 +17,7 @@ class Avoir < Invoice
|
||||
end
|
||||
|
||||
def expire_subscription
|
||||
user.subscription.expire(Time.current)
|
||||
user.subscription.expire
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -121,7 +121,7 @@ class Reservation < ApplicationRecord
|
||||
end
|
||||
|
||||
def extend_subscription
|
||||
SubscriptionExtensionAfterReservation.new(self).extend_subscription_if_eligible
|
||||
Subscriptions::ExtensionAfterReservation.new(self).extend_subscription_if_eligible
|
||||
end
|
||||
|
||||
def notify_member_create_reservation
|
||||
|
@ -29,15 +29,8 @@ class Subscription < ApplicationRecord
|
||||
generate_invoice(operator_profile_id).save
|
||||
end
|
||||
|
||||
def expire(time)
|
||||
if expired?
|
||||
false
|
||||
else
|
||||
update_columns(expiration_date: time, canceled_at: time) # rubocop:disable Rails/SkipsModelValidations
|
||||
notify_admin_subscription_canceled
|
||||
notify_member_subscription_canceled
|
||||
true
|
||||
end
|
||||
def expire
|
||||
Subscriptions::ExpireService.call(self)
|
||||
end
|
||||
|
||||
def expired?
|
||||
@ -78,18 +71,6 @@ class Subscription < ApplicationRecord
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
def notify_admin_subscription_canceled
|
||||
NotificationCenter.call type: 'notify_admin_subscription_canceled',
|
||||
receiver: User.admins_and_managers,
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
def notify_member_subscription_canceled
|
||||
NotificationCenter.call type: 'notify_member_subscription_canceled',
|
||||
receiver: user,
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
def notify_partner_subscribed_plan
|
||||
NotificationCenter.call type: 'notify_partner_subscribed_plan',
|
||||
receiver: plan.partners,
|
||||
|
@ -170,7 +170,7 @@ class PaymentScheduleService
|
||||
end
|
||||
# cancel subscription
|
||||
subscription = payment_schedule.payment_schedule_objects.find { |pso| pso.object_type == Subscription.name }.subscription
|
||||
subscription.expire(Time.current)
|
||||
subscription.expire
|
||||
|
||||
subscription.canceled_at
|
||||
end
|
||||
|
38
app/services/subscriptions/expire_service.rb
Normal file
38
app/services/subscriptions/expire_service.rb
Normal file
@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Expire the given subscription
|
||||
class Subscriptions::ExpireService
|
||||
class << self
|
||||
# @param subscription [Subscription]
|
||||
def call(subscription)
|
||||
expiration = Time.current
|
||||
if subscription.expired?
|
||||
false
|
||||
else
|
||||
subscription.update_columns(expiration_date: expiration, canceled_at: expiration) # rubocop:disable Rails/SkipsModelValidations
|
||||
subscription.offer_days.find_each do |od|
|
||||
od.update(start_at: expiration, end_at: expiration)
|
||||
end
|
||||
notify_admin_subscription_canceled(subscription)
|
||||
notify_member_subscription_canceled(subscription)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @param subscription [Subscription]
|
||||
def notify_admin_subscription_canceled(subscription)
|
||||
NotificationCenter.call type: 'notify_admin_subscription_canceled',
|
||||
receiver: User.admins_and_managers,
|
||||
attached_object: subscription
|
||||
end
|
||||
|
||||
# @param subscription [Subscription]
|
||||
def notify_member_subscription_canceled(subscription)
|
||||
NotificationCenter.call type: 'notify_member_subscription_canceled',
|
||||
receiver: subscription.user,
|
||||
attached_object: subscription
|
||||
end
|
||||
end
|
||||
end
|
@ -2,7 +2,7 @@
|
||||
|
||||
# Extend the user's current subscription after his first training reservation if
|
||||
# he subscribed to a rolling plan
|
||||
class SubscriptionExtensionAfterReservation
|
||||
class Subscriptions::ExtensionAfterReservation
|
||||
attr_accessor :user, :reservation
|
||||
|
||||
def initialize(reservation)
|
||||
@ -25,7 +25,7 @@ class SubscriptionExtensionAfterReservation
|
||||
end
|
||||
|
||||
def extend_subscription
|
||||
user.subscription.update_columns(
|
||||
user.subscription.update_columns( # rubocop:disable Rails/SkipsModelValidations
|
||||
expiration_date: reservation.slots_reservations.first.slot.start_at + user.subscribed_plan.duration
|
||||
)
|
||||
end
|
68
test/integration/subscriptions/cancel_test.rb
Normal file
68
test/integration/subscriptions/cancel_test.rb
Normal file
@ -0,0 +1,68 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
module Subscriptions; end
|
||||
|
||||
class Subscriptions::CancelTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'admin cancel a subscription for a user' do
|
||||
subscription = Subscription.find(1)
|
||||
|
||||
patch "/api/subscriptions/#{subscription.id}/cancel", headers: default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_response :success
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the subscription was canceled
|
||||
subscription.reload
|
||||
assert subscription.expiration_date < Time.current
|
||||
assert subscription.canceled_at < Time.current
|
||||
assert subscription.expired_at < Time.current
|
||||
assert subscription.expired?
|
||||
assert_nil subscription.user.subscribed_plan
|
||||
|
||||
# Notifications
|
||||
notifications = Notification.where(notification_type: NotificationType.find_by(name: 'notify_admin_subscription_canceled'),
|
||||
attached_object: subscription)
|
||||
notified_users_ids = notifications.map(&:receiver_id)
|
||||
assert_not_empty notifications
|
||||
assert(User.admins.map(&:id).all? { |admin| notified_users_ids.include?(admin) })
|
||||
|
||||
user_notification = Notification.where(notification_type: NotificationType.find_by(name: 'notify_member_subscription_canceled'),
|
||||
attached_object: subscription)
|
||||
assert_equal 1, user_notification.count
|
||||
end
|
||||
|
||||
test 'admin offer free days then cancel the subscription' do
|
||||
subscription = Subscription.find(1)
|
||||
new_date = 1.month.from_now.utc
|
||||
|
||||
post '/api/local_payment/confirm_payment',
|
||||
params: {
|
||||
customer_id: subscription.user.id,
|
||||
items: [{ free_extension: { end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') } }]
|
||||
}.to_json, headers: default_headers
|
||||
|
||||
assert_response :success
|
||||
|
||||
patch "/api/subscriptions/#{subscription.id}/cancel", headers: default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_response :success
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the subscription was canceled
|
||||
subscription.reload
|
||||
assert subscription.expiration_date < Time.current
|
||||
assert subscription.canceled_at < Time.current
|
||||
assert subscription.expired_at < Time.current
|
||||
assert subscription.expired?
|
||||
assert_nil subscription.user.subscribed_plan
|
||||
end
|
||||
end
|
@ -31,31 +31,31 @@ class SubscriptionExtensionAfterReservationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'is eligible for extension because all conditions are met by default (test setup)' do
|
||||
assert SubscriptionExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
assert Subscriptions::ExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
end
|
||||
|
||||
test 'not eligible if reservable is a machine' do
|
||||
@reservation_machine.save!
|
||||
refute SubscriptionExtensionAfterReservation.new(@reservation_machine).eligible_to_extension?
|
||||
assert_not Subscriptions::ExtensionAfterReservation.new(@reservation_machine).eligible_to_extension?
|
||||
end
|
||||
|
||||
test "not eligible if user doesn't have subscription" do
|
||||
@user.subscriptions.destroy_all
|
||||
refute SubscriptionExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
assert_not Subscriptions::ExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
end
|
||||
|
||||
test 'not eligible if subscription is expired' do
|
||||
@user.subscription.update!(expiration_date: 10.years.ago)
|
||||
refute SubscriptionExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
assert_not Subscriptions::ExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
end
|
||||
|
||||
test "not eligible if plan attribute 'is_rolling' is false/nil" do
|
||||
@plan.update!(is_rolling: false)
|
||||
refute SubscriptionExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
assert_not Subscriptions::ExtensionAfterReservation.new(@reservation_training).eligible_to_extension?
|
||||
end
|
||||
|
||||
test 'method extend_subscription' do
|
||||
SubscriptionExtensionAfterReservation.new(@reservation_training).extend_subscription
|
||||
Subscriptions::ExtensionAfterReservation.new(@reservation_training).extend_subscription
|
||||
assert_equal @reservation_training.slots_reservations.first.slot.start_at + @plan.duration, @user.subscription.expired_at
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user