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(charge): Allow creation of graduated percentage charges #1238

Merged
merged 1 commit into from
Aug 14, 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
1 change: 1 addition & 0 deletions app/models/charge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Charge < ApplicationRecord
validate :validate_graduated_percentage, if: -> { graduated_percentage? && group_properties.empty? }

validates :min_amount_cents, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
validates :charge_model, presence: true

validate :validate_group_properties
validate :validate_pay_in_advance
Expand Down
9 changes: 8 additions & 1 deletion app/services/plans/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def create(**args)
def create_charge(plan, args)
charge = plan.charges.new(
billable_metric_id: args[:billable_metric_id],
charge_model: args[:charge_model]&.to_sym,
charge_model: charge_model(args),
pay_in_advance: args[:pay_in_advance] || false,
prorated: args[:prorated] || false,
properties: args[:properties] || {},
Expand All @@ -73,6 +73,13 @@ def create_charge(plan, args)
charge
end

def charge_model(args)
model = args[:charge_model]&.to_sym
return if model == :graduated_percentage && !License.premium?

model
end

def track_plan_created(plan)
count_by_charge_model = plan.charges.group(:charge_model).count

Expand Down
9 changes: 8 additions & 1 deletion app/services/plans/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def create_charge(plan, params)
charge = plan.charges.new(
billable_metric_id: params[:billable_metric_id],
amount_currency: params[:amount_currency],
charge_model: params[:charge_model]&.to_sym,
charge_model: charge_model(params),
pay_in_advance: params[:pay_in_advance] || false,
prorated: params[:prorated] || false,
properties: params[:properties] || {},
Expand All @@ -88,6 +88,13 @@ def create_charge(plan, params)
charge
end

def charge_model(params)
model = params[:charge_model]&.to_sym
return if model == :graduated_percentage && !License.premium?

model
end

def process_charges(plan, params_charges)
created_charges_ids = []

Expand Down
156 changes: 122 additions & 34 deletions spec/services/plans/create_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,47 @@
amount_cents: 200,
amount_currency: 'EUR',
tax_codes: [plan_tax.code],
charges: [
{
billable_metric_id: billable_metric.id,
charge_model: 'standard',
min_amount_cents: 100,
tax_codes: [charge_tax.code],
group_properties: [
charges: charges_args,
}
end

let(:charges_args) do
[
{
billable_metric_id: billable_metric.id,
charge_model: 'standard',
min_amount_cents: 100,
tax_codes: [charge_tax.code],
group_properties: [
{
group_id: group.id,
values: { amount: '100' },
},
],
},
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'graduated',
pay_in_advance: true,
invoiceable: false,
properties: {
graduated_ranges: [
{
group_id: group.id,
values: { amount: '100' },
from_value: 0,
to_value: 10,
per_unit_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
per_unit_amount: '3',
flat_amount: '3',
},
],
},
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'graduated',
pay_in_advance: true,
invoiceable: false,
properties: {
graduated_ranges: [
{
from_value: 0,
to_value: 10,
per_unit_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
per_unit_amount: '3',
flat_amount: '3',
},
],
},
},
],
}
},
]
end

before do
Expand Down Expand Up @@ -129,6 +133,47 @@
context 'when premium' do
around { |test| lago_premium!(&test) }

let(:charges_args) do
[
{
billable_metric_id: billable_metric.id,
charge_model: 'standard',
min_amount_cents: 100,
tax_codes: [charge_tax.code],
group_properties: [
{
group_id: group.id,
values: { amount: '100' },
},
],
},
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'graduated_percentage',
pay_in_advance: true,
invoiceable: false,
properties: {
graduated_percentage_ranges: [
{
from_value: 0,
to_value: 10,
rate: '3',
fixed_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
rate: '2',
fixed_amount: '3',
flat_amount: '3',
},
],
},
},
]
end

it 'saves premium attributes' do
plan = plans_service.create(**create_args).plan

Expand All @@ -139,10 +184,11 @@
invoiceable: true,
},
)
expect(plan.charges.graduated.first).to have_attributes(
expect(plan.charges.graduated_percentage.first).to have_attributes(
{
pay_in_advance: true,
invoiceable: false,
charge_model: 'graduated_percentage',
},
)
end
Expand Down Expand Up @@ -172,6 +218,48 @@
expect(result.error.messages[:name]).to eq(['value_is_mandatory'])
end
end

context 'with premium charge model' do
let(:plan_name) { 'foo' }
let(:charges_args) do
[
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'graduated_percentage',
pay_in_advance: true,
invoiceable: false,
properties: {
graduated_ranges: [
{
from_value: 0,
to_value: 10,
rate: '3',
fixed_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
rate: '2',
fixed_amount: '3',
flat_amount: '3',
},
],
},
},
]
end

it 'returns an error' do
result = plans_service.create(**create_args)

aggregate_failures do
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
expect(result.error.messages[:charge_model]).to eq(['value_is_mandatory'])
end
end
end
end

context 'with metrics from other organization' do
Expand Down
125 changes: 94 additions & 31 deletions spec/services/plans/update_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,41 +25,45 @@
amount_cents: 200,
amount_currency: 'EUR',
tax_codes: [tax2.code],
charges: [
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'standard',
min_amount_cents: 100,
group_properties: [
charges: charges_args,
}
end

let(:charges_args) do
[
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'standard',
min_amount_cents: 100,
group_properties: [
{
group_id: group.id,
values: { amount: '100' },
},
],
tax_codes: [tax1.code],
},
{
billable_metric_id: billable_metric.id,
charge_model: 'graduated',
properties: {
graduated_ranges: [
{
from_value: 0,
to_value: 10,
per_unit_amount: '2',
flat_amount: '0',
},
{
group_id: group.id,
values: { amount: '100' },
from_value: 11,
to_value: nil,
per_unit_amount: '3',
flat_amount: '3',
},
],
tax_codes: [tax1.code],
},
{
billable_metric_id: billable_metric.id,
charge_model: 'graduated',
properties: {
graduated_ranges: [
{
from_value: 0,
to_value: 10,
per_unit_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
per_unit_amount: '3',
flat_amount: '3',
},
],
},
},
],
}
},
]
end

describe 'call' do
Expand Down Expand Up @@ -130,6 +134,65 @@
expect(result.error.messages[:name]).to eq(['value_is_mandatory'])
end
end

context 'with premium charge model' do
let(:plan_name) { 'foo' }

let(:charges_args) do
[
{
billable_metric_id: sum_billable_metric.id,
charge_model: 'graduated_percentage',
pay_in_advance: true,
invoiceable: false,
properties: {
graduated_percentage_ranges: [
{
from_value: 0,
to_value: 10,
rate: '3',
fixed_amount: '2',
flat_amount: '0',
},
{
from_value: 11,
to_value: nil,
rate: '2',
fixed_amount: '3',
flat_amount: '3',
},
],
},
},
]
end

it 'returns an error' do
result = plans_service.call

aggregate_failures do
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
expect(result.error.messages[:charge_model]).to eq(['value_is_mandatory'])
end
end

context 'when premium' do
around { |test| lago_premium!(&test) }

it 'saves premium charge model' do
plans_service.call

expect(plan.charges.graduated_percentage.first).to have_attributes(
{
pay_in_advance: true,
invoiceable: false,
charge_model: 'graduated_percentage',
},
)
end
end
end
end

context 'with metrics from other organization' do
Expand Down
Loading