Skip to content

Commit

Permalink
feat(ProgressiveBilling): Add label on invoice
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-pochet committed Aug 23, 2024
1 parent 3593c31 commit a6c6967
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 18 deletions.
16 changes: 10 additions & 6 deletions app/models/applied_usage_threshold.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# frozen_string_literal: true

class AppliedUsageThreshold < ApplicationRecord
belongs_to :usage_threshold
belongs_to :usage_threshold, -> { with_discarded }
belongs_to :invoice

validates :usage_threshold_id, uniqueness: {scope: :invoice_id}

monetize :lifetime_usage_amount_cents,
with_currency: ->(applied_usage_threshold) { applied_usage_threshold.invoice.currency }
end

# == Schema Information
#
# Table name: applied_usage_thresholds
#
# id :uuid not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# invoice_id :uuid not null
# usage_threshold_id :uuid not null
# id :uuid not null, primary key
# lifetime_usage_amount_cents :bigint default(0), not null
# created_at :datetime not null
# updated_at :datetime not null
# invoice_id :uuid not null
# usage_threshold_id :uuid not null
#
# Indexes
#
Expand Down
5 changes: 5 additions & 0 deletions app/models/lifetime_usage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ class LifetimeUsage < ApplicationRecord

monetize :current_usage_amount_cents,
:invoiced_usage_amount_cents,
:historical_usage_amount_cents,
with_currency: ->(lifetime_usage) { lifetime_usage.subscription.plan.amount_currency }

default_scope -> { kept }

scope :needs_recalculation, -> { where(recalculate_current_usage: true).or(where(recalculate_invoiced_usage: true)) }

def total_amount_cents
historical_usage_amount_cents + invoiced_usage_amount_cents + current_usage_amount_cents
end
end

# == Schema Information
Expand Down
15 changes: 7 additions & 8 deletions app/services/invoices/progressive_billing_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def call
Credits::AppliedCouponsService.call(invoice:)
Invoices::ComputeAmountsFromFees.call(invoice:)

create_credit_note_credit
create_applied_prepaid_credit

invoice.payment_status = invoice.total_amount_cents.positive? ? :pending : :succeeded
Expand Down Expand Up @@ -109,19 +108,19 @@ def boundaries
end

def create_applied_usage_thresholds
usage_thresholds.each { AppliedUsageThreshold.create!(invoice:, usage_threshold: _1) }
usage_thresholds.each do
AppliedUsageThreshold.create!(
invoice:,
usage_threshold: _1,
lifetime_usage_amount_cents: lifetime_usage.total_amount_cents
)
end
end

def should_deliver_email?
License.premium? && subscription.organization.email_settings.include?('invoice.finalized')
end

def create_credit_note_credit
credit_result = Credits::CreditNoteService.call(invoice:).raise_if_error!

invoice.total_amount_cents -= credit_result.credits.sum(&:amount_cents) if credit_result.credits
end

def create_applied_prepaid_credit
wallet = subscription.customer.wallets.active.first
return unless wallet&.active?
Expand Down
5 changes: 5 additions & 0 deletions app/views/templates/invoices/v4.slim
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ html

== SlimHelper.render('templates/invoices/v4/_eu_tax_management', self)

- if progressive_billing?
p.body-3.mb-24
- applied_usage_threshold = applied_usage_thresholds.order(created_at: :asc).last
= I18n.t('invoice.reached_usage_threshold', usage_amount: MoneyHelper. applied_usage_threshold.lifetime_usage_amount, threshold_amount: MoneyHelper.format(applied_usage_threshold.threshold.amount_cents)

p.body-3.mb-24 = LineBreakHelper.break_lines(organization.invoice_footer)

.powered-by
Expand Down
1 change: 1 addition & 0 deletions config/locales/en/invoice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ en:
progressive_billing_credit: Usage already billed
quarter: quarter
quarterly: Quarterly
reached_usage_threshold: This progressive billing invoice is generated because your lifetime usage has reached %{usage_amount}, exceeding the ${threshold_amount} threshold.
see_breakdown: See breakdown for total unit
sub_total: Subtotal
sub_total_with_tax: Subtotal (incl. tax)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ def change
create_table :applied_usage_thresholds, id: :uuid do |t|
t.references :usage_threshold, null: false, foreign_key: true, type: :uuid
t.references :invoice, null: false, foreign_key: true, type: :uuid
t.bigint :lifetime_usage_amount_cents, null: false, default: 0

t.timestamps

Expand Down
1 change: 1 addition & 0 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions spec/factories/applied_usage_thresholds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
factory :applied_usage_threshold do
usage_threshold
invoice

lifetime_usage_amount_cents { 100 }
end
end
7 changes: 3 additions & 4 deletions spec/models/applied_usage_threshold_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
require 'rails_helper'

RSpec.describe AppliedUsageThreshold, type: :model do
subject(:applied_usage_threshold) { build(:applied_usage_threshold) }
subject(:applied_usage_threshold) { create(:applied_usage_threshold, invoice:) }

it { is_expected.to belong_to(:usage_threshold) }
it { is_expected.to belong_to(:invoice) }
let(:invoice) { create(:invoice) }

it { is_expected.to validate_uniqueness_of(:usage_threshold_id).scoped_to(:invoice_id).case_insensitive }
it { is_expected.to belong_to(:usage_threshold) }
end
10 changes: 10 additions & 0 deletions spec/models/lifetime_usage_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,14 @@
expect(described_class.needs_recalculation).to match_array([lifetime_usage1, lifetime_usage2])
end
end

describe '#total_amount_cents' do
it 'returns the sum of the historical, invoiced, and current usage' do
lifetime_usage.historical_usage_amount_cents = 100
lifetime_usage.invoiced_usage_amount_cents = 200
lifetime_usage.current_usage_amount_cents = 300

expect(lifetime_usage.total_amount_cents).to eq(600)
end
end
end
3 changes: 3 additions & 0 deletions spec/services/invoices/progressive_billing_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
expect(invoice.invoice_subscriptions.count).to eq(1)
expect(invoice.fees.count).to eq(1)
expect(invoice.applied_usage_thresholds.count).to eq(1)

expect(invoice.applied_usage_thresholds.first.lifetime_usage_amount_cents)
.to eq(lifetime_usage.total_amount_cents)
end

context 'with multiple thresholds' do
Expand Down

0 comments on commit a6c6967

Please sign in to comment.