Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Send started and terminated subscription webhooks #1399

Merged
merged 2 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions app/services/subscriptions/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,10 @@ def upgrade_subscription

# NOTE: When upgrading, the new subscription becomes active immediatly
# The previous one must be terminated
current_subscription.mark_as_terminated!
new_subscription.mark_as_active!

if current_subscription.plan.pay_in_advance?
# NOTE: As subscription was payed in advance and terminated before the end of the period,
# we have to create a credit note for the days that were not consumed
credit_note_result = CreditNotes::CreateFromTermination.new(subscription: current_subscription).call
credit_note_result.raise_if_error!
end
Subscriptions::TerminateService.call(subscription: current_subscription)
vincent-pochet marked this conversation as resolved.
Show resolved Hide resolved

# NOTE: Create an invoice for the terminated subscription
# if it has not been billed yet
# or only for the charges if subscription was billed in advance
# We do not set offset anymore but instead retry jobs
perform_later(job_class: BillSubscriptionJob, arguments: [[current_subscription], Time.zone.now.to_i + 1.second])
new_subscription.mark_as_active!
perform_later(job_class: SendWebhookJob, arguments: ['subscription.started', new_subscription])

if plan.pay_in_advance?
# NOTE: Since job is launched from inside a db transaction
Expand Down
27 changes: 10 additions & 17 deletions app/services/subscriptions/terminate_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ def call
# NOTE: Pending next subscription should be canceled as well
subscription.next_subscription&.mark_as_canceled!

SendWebhookJob.perform_later(
'subscription.terminated',
subscription,
)
# NOTE: Wait to ensure job is performed at the end of the database transaction.
# See https://github.com/getlago/lago-api/blob/main/app/services/subscriptions/create_service.rb#L46.
SendWebhookJob.set(wait: 2.seconds).perform_later('subscription.terminated', subscription)

result.subscription = subscription
result
Expand All @@ -60,23 +59,15 @@ def terminate_and_start_next(timestamp:)
# NOTE: Create an invoice for the terminated subscription
# if it has not been billed yet
# or only for the charges if subscription was billed in advance
BillSubscriptionJob.perform_later(
[subscription],
timestamp,
)
BillSubscriptionJob.perform_later([subscription], timestamp)

SendWebhookJob.perform_later(
'subscription.terminated',
subscription,
)
SendWebhookJob.perform_later('subscription.terminated', subscription)
SendWebhookJob.perform_later('subscription.started', next_subscription)

result.subscription = next_subscription
return result unless next_subscription.plan.pay_in_advance?

BillSubscriptionJob.perform_later(
[next_subscription],
timestamp,
)
BillSubscriptionJob.perform_later([next_subscription], timestamp)

result
rescue ActiveRecord::RecordInvalid => e
Expand All @@ -89,7 +80,9 @@ def terminate_and_start_next(timestamp:)

def bill_subscription
if async
BillSubscriptionJob.perform_later([subscription], subscription.terminated_at)
# NOTE: Wait to ensure job is performed at the end of the database transaction.
# See https://github.com/getlago/lago-api/blob/main/app/services/subscriptions/create_service.rb#L46.
BillSubscriptionJob.set(wait: 2.seconds).perform_later([subscription], subscription.terminated_at)
else
BillSubscriptionJob.perform_now([subscription], subscription.terminated_at)
end
Expand Down
15 changes: 11 additions & 4 deletions spec/services/subscriptions/create_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,13 @@
let(:name) { 'invoice display name new' }

it 'terminates the existing subscription' do
expect { create_service.call }.to have_enqueued_job(BillSubscriptionJob)
expect(subscription.reload).to be_terminated
expect { create_service.call }.to change { subscription.reload.status }.from('active').to('terminated')
end

it 'sends terminated and started subscription webhooks', :aggregate_failures do
result = create_service.call
expect(SendWebhookJob).to have_been_enqueued.with('subscription.terminated', subscription)
expect(SendWebhookJob).to have_been_enqueued.with('subscription.started', result.subscription)
end

it 'creates a new subscription' do
Expand Down Expand Up @@ -396,7 +401,8 @@
let(:old_plan) { create(:plan, amount_cents: 100, organization:, pay_in_advance: false) }

it 'enqueues a job to bill the existing subscription' do
expect { create_service.call }.to have_enqueued_job(BillSubscriptionJob)
create_service.call
expect(BillSubscriptionJob).to have_been_enqueued.at_least(1).times
end
end

Expand Down Expand Up @@ -452,7 +458,8 @@
let(:plan) { create(:plan, amount_cents: 200, organization:, pay_in_advance: true) }

it 'enqueues a job to bill the existing subscription' do
expect { create_service.call }.to have_enqueued_job(BillSubscriptionJob).twice
create_service.call
expect(BillSubscriptionJob).to have_been_enqueued.at_least(2).times
end
end

Expand Down
6 changes: 3 additions & 3 deletions spec/services/subscriptions/terminate_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@
end

it 'enqueues a SendWebhookJob' do
expect do
terminate_service.terminate_and_start_next(timestamp:)
end.to have_enqueued_job(SendWebhookJob)
terminate_service.terminate_and_start_next(timestamp:)
expect(SendWebhookJob).to have_been_enqueued.with('subscription.terminated', subscription)
expect(SendWebhookJob).to have_been_enqueued.with('subscription.started', next_subscription)
end

context 'when terminated subscription is payed in arrear' do
Expand Down
Loading