Skip to content

Commit

Permalink
feat(dunning): Create dunning thresholds when creating the campaign
Browse files Browse the repository at this point in the history
  • Loading branch information
rsempe committed Oct 11, 2024
1 parent ec283dc commit f27737a
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 12 deletions.
12 changes: 12 additions & 0 deletions app/graphql/types/dunning_campaign_thresholds/create_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module Types
module DunningCampaignThresholds
class CreateInput < Types::BaseInputObject
graphql_name "CreateDunningCampaignThresholdInput"

argument :amount_cents, GraphQL::Types::BigInt, required: true
argument :currency, Types::CurrencyEnum, required: true
end
end
end
1 change: 1 addition & 0 deletions app/graphql/types/dunning_campaigns/create_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class CreateInput < Types::BaseInputObject
argument :days_between_attempts, Integer, required: true
argument :max_attempts, Integer, required: true
argument :name, String, required: true
argument :thresholds, [Types::DunningCampaignThresholds::CreateInput], required: true

argument :description, String, required: false
end
Expand Down
1 change: 1 addition & 0 deletions app/models/dunning_campaign.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class DunningCampaign < ApplicationRecord

belongs_to :organization
has_many :thresholds, class_name: "DunningCampaignThreshold", dependent: :destroy
accepts_nested_attributes_for :thresholds

validates :name, presence: true
validates :days_between_attempts, numericality: {greater_than: 0}
Expand Down
28 changes: 16 additions & 12 deletions app/services/dunning_campaigns/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,22 @@ def initialize(organization:, params:)
end

def call
dunning_campaign = organization.dunning_campaigns.new(
applied_to_organization: params[:applied_to_organization],
code: params[:code],
days_between_attempts: params[:days_between_attempts],
max_attempts: params[:max_attempts],
name: params[:name],
description: params[:description]
)

dunning_campaign.save!

result.dunning_campaign = dunning_campaign
ActiveRecord::Base.transaction do
dunning_campaign = organization.dunning_campaigns.create!(
applied_to_organization: params[:applied_to_organization],
code: params[:code],
days_between_attempts: params[:days_between_attempts],
max_attempts: params[:max_attempts],
name: params[:name],
description: params[:description],
thresholds_attributes: params[:thresholds]
)

# TODO: If the dunning campaign is applied to the organization, we need to remove the flag from all other dunning campaigns.

result.dunning_campaign = dunning_campaign
end

result
rescue ActiveRecord::RecordInvalid => e
result.record_validation_failure!(record: e.record)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Types::DunningCampaignThresholds::CreateInput do
subject { described_class }

it { is_expected.to accept_argument(:amount_cents).of_type("BigInt!") }
it { is_expected.to accept_argument(:currency).of_type("CurrencyEnum!") }
end
1 change: 1 addition & 0 deletions spec/graphql/types/dunning_campaigns/create_input_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
it { is_expected.to accept_argument(:days_between_attempts).of_type('Int!') }
it { is_expected.to accept_argument(:max_attempts).of_type('Int!') }
it { is_expected.to accept_argument(:name).of_type('String!') }
it { is_expected.to accept_argument(:thresholds).of_type('[CreateDunningCampaignThresholdInput!]!') }

it { is_expected.to accept_argument(:description).of_type('String') }
end
55 changes: 55 additions & 0 deletions spec/services/dunning_campaigns/create_service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe DunningCampaigns::CreateService, type: :service do
subject(:create_service) { described_class.new(organization:, params:) }

let(:membership) { create(:membership) }
let(:organization) { membership.organization }
let(:params) do
{
name: "Dunning Campaign",
code: "dunning-campaign",
days_between_attempts: 1,
max_attempts: 3,
description: "Dunning Campaign Description",
applied_to_organization: true,
thresholds:
}
end

let(:thresholds) do
[
{ amount_cents: 10000, currency: "USD" },
{ amount_cents: 20000, currency: "EUR" }
]
end

describe "#call" do
it "creates a dunning campaign" do
expect { create_service.call }.to change(DunningCampaign, :count).by(1)
.and change(DunningCampaignThreshold, :count).by(2)
end

it "returns dunning campaign in the result" do
result = create_service.call
expect(result.dunning_campaign).to be_a(DunningCampaign)
expect(result.dunning_campaign.thresholds.first).to be_a(DunningCampaignThreshold)
end

context "with validation error" do
before { create(:dunning_campaign, organization: organization, code: "dunning-campaign") }

it "returns an error" do
result = create_service.call

aggregate_failures do
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
expect(result.error.messages[:code]).to eq(["value_already_exist"])
end
end
end
end
end

0 comments on commit f27737a

Please sign in to comment.