Skip to content

Commit

Permalink
Merge pull request solidusio#2579 from jhawthorn/promotion_batch_options
Browse files Browse the repository at this point in the history
Add options to PromotionCode::BatchBuilder and spec for unique promotion code contention
  • Loading branch information
jhawthorn authored Feb 16, 2018
2 parents 5bebfdf + 17f0ef0 commit 637db0b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
40 changes: 29 additions & 11 deletions core/app/models/spree/promotion_code/batch_builder.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
class ::Spree::PromotionCode::BatchBuilder
attr_reader :promotion_code_batch
attr_reader :promotion_code_batch, :options
delegate :promotion, :number_of_codes, :base_code, to: :promotion_code_batch

class_attribute :random_code_length, :batch_size, :sample_characters, :join_characters
self.random_code_length = 6
self.batch_size = 1_000
self.sample_characters = ('a'..'z').to_a + (2..9).to_a.map(&:to_s)
self.join_characters = "_"
DEFAULT_OPTIONS = {
random_code_length: 6,
batch_size: 1000,
sample_characters: ('a'..'z').to_a + (2..9).to_a.map(&:to_s),
join_characters: "_"
}

def initialize(promotion_code_batch)
[:random_code_length, :batch_size, :sample_characters, :join_characters].each do |attr|
define_singleton_method(attr) do
Spree::Deprecation.warn "#{name}.#{attr} is deprecated. Use #{name}::DEFAULT_OPTIONS[:#{attr}] instead"
DEFAULT_OPTIONS[attr]
end

define_singleton_method(:"#{attr}=") do |val|
Spree::Deprecation.warn "#{name}.#{attr}= is deprecated. Use #{name}::DEFAULT_OPTIONS[:#{attr}]= instead"
DEFAULT_OPTIONS[attr] = val
end

delegate attr, to: self
end

def initialize(promotion_code_batch, options = {})
@promotion_code_batch = promotion_code_batch
options.assert_valid_keys(*DEFAULT_OPTIONS.keys)
@options = DEFAULT_OPTIONS.merge(options)
end

def build_promotion_codes
Expand All @@ -27,9 +44,10 @@ def build_promotion_codes

def generate_random_codes
created_codes = 0
batch_size = @options[:batch_size]

while created_codes < number_of_codes
max_codes_to_generate = [self.class.batch_size, number_of_codes - created_codes].min
max_codes_to_generate = [batch_size, number_of_codes - created_codes].min

new_codes = Array.new(max_codes_to_generate) { generate_random_code }.uniq
codes_for_current_batch = get_unique_codes(new_codes)
Expand All @@ -46,11 +64,11 @@ def generate_random_codes
end

def generate_random_code
suffix = Array.new(self.class.random_code_length) do
sample_characters.sample
suffix = Array.new(@options[:random_code_length]) do
@options[:sample_characters].sample
end.join

"#{base_code}#{join_characters}#{suffix}"
"#{base_code}#{@options[:join_characters]}#{suffix}"
end

def get_unique_codes(code_set)
Expand Down
28 changes: 21 additions & 7 deletions core/spec/models/spree/promotion_code/batch_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
RSpec.describe Spree::PromotionCode::BatchBuilder do
let(:promotion) { create(:promotion) }
let(:base_code) { "abc" }
let(:options) { {} }
let(:number_of_codes) { 10 }
let(:promotion_code_batch) do
Spree::PromotionCodeBatch.create!(
promotion_id: promotion.id,
base_code: base_code,
number_of_codes: 10,
number_of_codes: number_of_codes,
email: "test@email.com"
)
end

subject { described_class.new(promotion_code_batch) }
subject { described_class.new(promotion_code_batch, options) }

describe "#build_promotion_codes" do
context "with a failed build" do
Expand Down Expand Up @@ -53,6 +55,22 @@
expect(promotion_code_batch.state).to eq("completed")
end
end

context "with likely code contention" do
let(:number_of_codes) { 50 }
let(:options) do
{
batch_size: 10,
sample_characters: (0..9).to_a.map(&:to_s),
random_code_length: 2
}
end

it "creates the correct number of codes" do
subject.build_promotion_codes
expect(promotion.codes.size).to eq(number_of_codes)
end
end
end

describe "#join_character" do
Expand All @@ -66,11 +84,7 @@
end

context "with a custom join separator" do
around do |example|
Spree::PromotionCode::BatchBuilder.join_characters = "x"
example.run
Spree::PromotionCode::BatchBuilder.join_characters = "_"
end
let(:options) { { join_characters: "x" } }

it "builds codes with the same base prefix" do
subject.build_promotion_codes
Expand Down

0 comments on commit 637db0b

Please sign in to comment.