diff --git a/app/models/voucher.rb b/app/models/voucher.rb index 109ffd2965..6391b997f1 100644 --- a/app/models/voucher.rb +++ b/app/models/voucher.rb @@ -11,7 +11,20 @@ class Voucher < ApplicationRecord dependent: :nullify validates :code, presence: true, uniqueness: { scope: :enterprise_id } - validates :amount, presence: true, numericality: { greater_than: 0 } + validates :amount, + presence: true, + numericality: { greater_than: 0 }, + if: ->(v) { v.voucher_type == FLAT_RATE } + validates :amount, + presence: true, + numericality: { greater_than: 0, less_than_or_equal_to: 100 }, + if: ->(v) { v.voucher_type == PERCENTAGE_RATE } + + FLAT_RATE = 'flat'.freeze + PERCENTAGE_RATE = 'percentage'.freeze + TYPES = [FLAT_RATE, PERCENTAGE_RATE].freeze + + validates :voucher_type, inclusion: TYPES def code=(value) super(value.to_s.strip) diff --git a/db/migrate/20230508035306_add_type_to_vouchers.rb b/db/migrate/20230508035306_add_type_to_vouchers.rb new file mode 100644 index 0000000000..54a6cceec4 --- /dev/null +++ b/db/migrate/20230508035306_add_type_to_vouchers.rb @@ -0,0 +1,5 @@ +class AddTypeToVouchers < ActiveRecord::Migration[7.0] + def change + add_column :vouchers, :voucher_type, :string, limit: 255 + end +end diff --git a/db/schema.rb b/db/schema.rb index c58419991e..84fef13ddd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1081,6 +1081,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_09_201542) do t.bigint "enterprise_id" t.datetime "deleted_at", precision: nil t.decimal "amount", precision: 10, scale: 2, default: "0.0", null: false + t.string "voucher_type", limit: 255 t.index ["code", "enterprise_id"], name: "index_vouchers_on_code_and_enterprise_id", unique: true t.index ["deleted_at"], name: "index_vouchers_on_deleted_at" t.index ["enterprise_id"], name: "index_vouchers_on_enterprise_id" diff --git a/spec/factories/voucher_factory.rb b/spec/factories/voucher_factory.rb index c02de3fb52..d9076b91f7 100644 --- a/spec/factories/voucher_factory.rb +++ b/spec/factories/voucher_factory.rb @@ -1,8 +1,15 @@ # frozen_string_literal: true FactoryBot.define do - factory :voucher do + factory :voucher_flat_rate, class: Voucher do enterprise { build(:distributor_enterprise) } + voucher_type { Voucher::FLAT_RATE } amount { 15 } end + + factory :voucher_percentage, class: Voucher do + enterprise { build(:distributor_enterprise) } + voucher_type { Voucher::PERCENTAGE_RATE } + amount { rand(1..100) } + end end diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index 0899a3623f..9c9d63593f 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -1466,7 +1466,7 @@ describe Spree::Order do describe "#voucher_adjustments" do let(:distributor) { create(:distributor_enterprise) } let(:order) { create(:order, user: user, distributor: distributor) } - let(:voucher) { create(:voucher, code: 'new_code', enterprise: order.distributor) } + let(:voucher) { create(:voucher_flat_rate, code: 'new_code', enterprise: order.distributor) } context "when no voucher adjustment" do it 'returns an empty array' do diff --git a/spec/models/voucher_spec.rb b/spec/models/voucher_spec.rb index 05992db2d8..8af6daa029 100644 --- a/spec/models/voucher_spec.rb +++ b/spec/models/voucher_spec.rb @@ -19,15 +19,31 @@ describe Voucher do end describe 'validations' do - subject { build(:voucher, code: 'new_code', enterprise: enterprise) } + subject { build(:voucher_flat_rate, code: 'new_code', enterprise: enterprise) } it { is_expected.to validate_presence_of(:code) } it { is_expected.to validate_uniqueness_of(:code).scoped_to(:enterprise_id) } it { is_expected.to validate_presence_of(:amount) } - it { is_expected.to validate_numericality_of(:amount).is_greater_than(0) } + it { is_expected.to validate_inclusion_of(:voucher_type).in_array(Voucher::TYPES) } + + context "when voucher_type is flat rate" do + it { is_expected.to validate_numericality_of(:amount).is_greater_than(0) } + end + + context "when voucher_type is percentage rate" do + subject { build(:voucher_percentage, code: 'new_code', enterprise: enterprise) } + + it do + is_expected.to validate_numericality_of(:amount) + .is_greater_than(0) + .is_less_than_or_equal_to(100) + end + end end describe '#compute_amount' do + subject { create(:voucher_flat_rate, code: 'new_code', enterprise: enterprise, amount: 10) } + let(:order) { create(:order_with_totals) } context 'when order total is more than the voucher' do @@ -50,7 +66,9 @@ describe Voucher do describe '#create_adjustment' do subject(:adjustment) { voucher.create_adjustment(voucher.code, order) } - let(:voucher) { create(:voucher, code: 'new_code', enterprise: enterprise, amount: 25) } + let(:voucher) do + create(:voucher_flat_rate, code: 'new_code', enterprise: enterprise, amount: 25) + end let(:order) { create(:order_with_line_items, line_items_count: 3, distributor: enterprise) } it 'includes an amount of 0' do diff --git a/spec/requests/voucher_adjustments_spec.rb b/spec/requests/voucher_adjustments_spec.rb index 0188236cbe..42ce434f38 100644 --- a/spec/requests/voucher_adjustments_spec.rb +++ b/spec/requests/voucher_adjustments_spec.rb @@ -19,7 +19,7 @@ describe VoucherAdjustmentsController, type: :request do ) end let(:shipping_method) { distributor.shipping_methods.first } - let(:voucher) { create(:voucher, code: 'some_code', enterprise: distributor) } + let(:voucher) { create(:voucher_flat_rate, code: 'some_code', enterprise: distributor) } before do order.update!(created_by: user) diff --git a/spec/system/consumer/split_checkout_spec.rb b/spec/system/consumer/split_checkout_spec.rb index 3f0761eaa0..e2f962a13f 100644 --- a/spec/system/consumer/split_checkout_spec.rb +++ b/spec/system/consumer/split_checkout_spec.rb @@ -696,7 +696,7 @@ describe "As a consumer, I want to checkout my order" do context "with voucher available" do let!(:voucher) do - create(:voucher, code: 'some_code', enterprise: distributor, amount: 15) + create(:voucher_flat_rate, code: 'some_code', enterprise: distributor, amount: 15) end it "shows voucher input" do @@ -1150,7 +1150,9 @@ describe "As a consumer, I want to checkout my order" do end describe "vouchers" do - let(:voucher) { create(:voucher, code: 'some_code', enterprise: distributor, amount: 6) } + let(:voucher) do + create(:voucher_flat_rate, code: 'some_code', enterprise: distributor, amount: 6) + end before do add_voucher_to_order(voucher, order)