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

fix(subscription): Fix generating invoice with pending downgrade #2581

Merged
merged 1 commit into from
Sep 16, 2024
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
9 changes: 6 additions & 3 deletions app/services/subscriptions/dates_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ def to_datetime
return @to_datetime if @to_datetime

@to_datetime = customer_timezone_shift(compute_to_date, end_of_day: true)
terminated_at = subscription.terminated_at&.change(usec: 0)
bill_at = billing_at&.change(usec: 0)
terminated_at = subscription.terminated_at&.to_time&.round

if subscription.terminated? && @to_datetime > terminated_at && bill_at && bill_at >= terminated_at
if subscription.terminated_at?(billing_at) && @to_datetime > terminated_at
@to_datetime = terminated_at
end

@to_datetime = subscription.started_at if @to_datetime < subscription.started_at
@to_datetime
end

Expand All @@ -96,6 +96,7 @@ def charges_from_datetime
def charges_to_datetime
datetime = customer_timezone_shift(compute_charges_to_date, end_of_day: true)
datetime = subscription.terminated_at if subscription.terminated_at?(datetime)
datetime = subscription.started_at if datetime < subscription.started_at

datetime
end
Expand Down Expand Up @@ -151,6 +152,8 @@ def subscription_at
subscription.subscription_at.in_time_zone(customer.applicable_timezone)
end

# NOTE: This method converts a DAY epress in the customer timezone into a proper UTC datetime
# Example: `2024-03-01` in `America/New_York` will be converted to `2024-03-01T05:00:00 UTC`
def customer_timezone_shift(date, end_of_day: false)
result = date.in_time_zone(customer.applicable_timezone)
result = result.end_of_day if end_of_day
Expand Down
4 changes: 2 additions & 2 deletions spec/models/invoice_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,9 @@
end

describe '#charge_pay_in_advance_proration_range' do
let(:invoice_subscription) { create(:invoice_subscription) }
let(:invoice_subscription) { create(:invoice_subscription, subscription:) }
let(:invoice) { invoice_subscription.invoice }
let(:subscription) { invoice_subscription.subscription }
let(:subscription) { create(:subscription, started_at: timestamp - 1.year) }
let(:timestamp) { DateTime.parse('2023-07-25 00:00:00 UTC') }
let(:event) { create(:event, subscription_id: subscription.id, timestamp:) }
let(:billable_metric) { create(:sum_billable_metric, organization: subscription.organization, recurring: true) }
Expand Down
6 changes: 3 additions & 3 deletions spec/scenarios/subscriptions/terminate_ended_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
)
end

let(:creation_time) { DateTime.new(2023, 9, 5, 0, 0) }
let(:subscription_at) { DateTime.new(2023, 9, 5, 0, 0) }
let(:ending_at) { DateTime.new(2023, 9, 6, 0, 0) }
let(:creation_time) { Time.zone.parse('2023-09-05T00:00:00') }
let(:subscription_at) { Time.zone.parse('2023-09-05T00:00:00') }
let(:ending_at) { Time.zone.parse('2023-09-06T00:00:00') }

context 'when timezone is Europe/Paris' do
it 'terminates the subscription when it reaches its ending date' do
Expand Down
39 changes: 30 additions & 9 deletions spec/services/subscriptions/dates/monthly_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,23 +205,44 @@

context 'when subscription is just terminated' do
let(:billing_at) { Time.zone.parse('10 Mar 2022') }
let(:terminated_at) { Time.zone.parse('09 Mar 2022') }

before do
subscription.update!(
status: :terminated,
terminated_at: Time.zone.parse('02 Mar 2022')
)
end
before { subscription.update!(status: :terminated, terminated_at:) }

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end

context 'with pending next subscription' do
let(:subscription_at) { Time.zone.parse('2024-09-09T14:00:01') }
let(:terminated_at) { Time.zone.parse('2024-09-09T16:00:01') }

let(:downgraded_plan) { create(:plan, interval: :monthly, pay_in_advance: false, amount_cents: 0) }

before do
create(
:subscription,
status: :pending,
external_id: subscription.external_id,
plan: downgraded_plan,
customer:,
subscription_at:,
billing_time:,
started_at: nil,
previous_subscription: subscription
)
end

it 'makes sure the to_datetime is not before start date' do
expect(result).to match_datetime(subscription.started_at.utc)
end
end

context 'with customer timezone' do
let(:timezone) { 'America/New_York' }

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down Expand Up @@ -288,7 +309,7 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/services/subscriptions/dates/quarterly_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,14 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end

context 'with customer timezone' do
let(:timezone) { 'America/New_York' }

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down Expand Up @@ -295,7 +295,7 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/services/subscriptions/dates/weekly_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end

context 'with customer timezone' do
let(:timezone) { 'America/New_York' }

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down Expand Up @@ -197,7 +197,7 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/services/subscriptions/dates/yearly_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,14 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end

context 'with customer timezone' do
let(:timezone) { 'America/New_York' }

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down Expand Up @@ -246,7 +246,7 @@
end

it 'returns the termination date' do
expect(result).to eq(subscription.terminated_at.utc.to_s)
expect(result).to match_datetime(subscription.terminated_at.utc)
end
end
end
Expand Down