Skip to content

Commit

Permalink
Close #769 discount maximum cap
Browse files Browse the repository at this point in the history
  • Loading branch information
kimsrung committed Dec 8, 2023
1 parent fd1076c commit 9797e3a
Show file tree
Hide file tree
Showing 15 changed files with 390 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module SpreeCmCommissioner
module Calculator
module FlatPercentItemTotalDecorator
def compute(object)
computed_amount = (object.amount * preferred_flat_percent / 100).round(2)
computed_amount = cap if cap && computed_amount > cap

[computed_amount, object.amount].min
end
end
end
end

unless Spree::Calculator::FlatPercentItemTotal.included_modules.include?(SpreeCmCommissioner::Calculator::FlatPercentItemTotalDecorator)
Spree::Calculator::FlatPercentItemTotal.prepend(SpreeCmCommissioner::Calculator::FlatPercentItemTotalDecorator)
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module SpreeCmCommissioner
module Calculator
module PercentOnLineItemDecorator
def compute(object)
computed_amount = (object.amount * preferred_percent / 100).round(2)
computed_amount = cap if cap && computed_amount > cap

[computed_amount, object.amount].min
end
end
end
end

unless Spree::Calculator::PercentOnLineItem.included_modules.include?(SpreeCmCommissioner::Calculator::PercentOnLineItemDecorator)
Spree::Calculator::PercentOnLineItem.prepend(SpreeCmCommissioner::Calculator::PercentOnLineItemDecorator)
end
17 changes: 17 additions & 0 deletions app/models/spree_cm_commissioner/order_updater_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ def update_item_total
order.item_total = line_items.sum(&:amount)
update_order_total
end

# override
def update_adjustment_total
super

promotion_adjustment = adjustments.promotion.eligible.first

return if promotion_adjustment.blank? # Check if the order has a promotion adjustment

promotion = promotion_adjustment.source.promotion

return unless promotion&.cap && order.adjustment_total.abs > promotion&.cap # Check if cap exist

order.adjustment_total = order.promo_total = promotion.cap * -1

update_order_total
end
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ def compute_amount(line_item)
def compute_line_item_amount(line_item)
line_item.date_range.filter_map do |date|
if promotion.date_eligible?(date)
line_item_per_unit = Struct.new(:amount, :currency, :quantity)
.new(line_item.amount_per_date_unit, line_item.currency, line_item.quantity)
line_item_per_unit = Struct.new(:amount, :currency, :quantity, :price)
.new(line_item.amount_per_date_unit, line_item.currency,
line_item.quantity, line_item.price
)

compute(line_item_per_unit)
end
end.sum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!-- replace "[data-hook='order_details_adjustments']" -->
<% eligible_adjustments = adjustments.eligible%>
<tbody id="order-charges">
<% eligible_adjustments.group_by(&:label).each do |label, adjustments| %>
<tr class="total">
<td>
<strong><%= label %>:</strong>
</td>
<td class="total">
<span>
<%= Spree::Money.new(
adjustments.sum(&:amount),
currency: adjustments.first.order.try(:currency)
) %>

<% if eligible_adjustments.promotion.present? %>
~ (Cap
<%= Spree::Money.new(
eligible_adjustments.promotion.first.source.calculator&.cap,
currency: adjustments.first.order.try(:currency)
) %>)
<%end%>
</span>
</td>
</tr>
<% end %>
</tbody>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- insert_before "erb[loud]:contains('field_container :usage_limit')" -->

<div id="cap_field" class="form-group">
<%= f.field_container :cap do %>
<%= f.label :cap %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><%= currency_symbol(current_currency) %></span>
</div>
<%= f.text_field :cap, value: number_to_currency(@promotion.cap, unit: ''), class: 'form-control' %>
</div>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- insert_after ".calculator-fields > .row > .settings" -->

<div class="form-group col-12 col-md-6 mt-3 mb-0" id="cap_field">
<%= label_tag "#{param_prefix}[calculator_attributes][cap]", "Cap" %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><%= currency_symbol(current_currency) %></span>
</div>
<%= text_field_tag "#{param_prefix}[calculator_attributes][cap]", number_to_currency(promotion_action.calculator.cap, unit: ''), class: 'form-control' %>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- insert_after ".calculator-fields > .row > .settings" -->

<div class="form-group col-12 col-md-6 mt-3 mb-0" id="cap_field">
<%= label_tag "#{param_prefix}[calculator_attributes][cap]", "Cap" %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><%= currency_symbol(current_currency) %></span>
</div>
<%= text_field_tag "#{param_prefix}[calculator_attributes][cap]", number_to_currency(promotion_action.calculator.cap, unit: ''), class: 'form-control' %>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
<%= hidden_field_tag "#{param_prefix}[calculator_attributes][id]", promotion_action.calculator.id %>
</div>
<% end %>
<div class="form-group col-12 col-md-6 mb-0" id="cap_field">
<%= label_tag "#{param_prefix}[calculator_attributes][cap]", "Cap" %>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><%= currency_symbol(current_currency) %></span>
</div>
<%= text_field_tag "#{param_prefix}[calculator_attributes][cap]", number_to_currency(promotion_action.calculator.cap, unit: ''), class: 'form-control' %>
</div>
</div>
</div>
<% if promotion_action.calculator.respond_to?(:preferences) %>
<div class="alert alert-info js-warning mt-3 mb-0">
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20231114015730_add_cap_to_spree_promotion.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddCapToSpreePromotion < ActiveRecord::Migration[7.0]
def change
add_column :spree_promotions, :cap, :float, if_not_exists: true
end
end
5 changes: 5 additions & 0 deletions db/migrate/20231117032031_add_cap_to_spree_calculator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddCapToSpreeCalculator < ActiveRecord::Migration[7.0]
def change
add_column :spree_calculators, :cap, :float, if_not_exists: true
end
end
47 changes: 47 additions & 0 deletions spec/models/spree/calculator/flat_percent_item_total_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'spec_helper'

RSpec.describe Spree::Calculator::FlatPercentItemTotal, type: :model do
let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new }
let(:order) { create(:order) }

before { allow(calculator).to receive_messages preferred_flat_percent: 10 }

describe '#compute' do
context 'without cap' do
it 'rounds result correctly' do
allow(order).to receive_messages amount: 31.08
expect(calculator.compute(order)).to eq 3.11

allow(order).to receive_messages amount: 31.00
expect(calculator.compute(order)).to eq 3.10
end

it 'returns object.amount if computed amount is greater' do
allow(order).to receive_messages amount: 30.00
allow(calculator).to receive_messages preferred_flat_percent: 110

expect(calculator.compute(order)).to eq 30.0
end
end

context 'with cap' do
before do
calculator.update(cap: 10)
end

it 'returns cap if computed amount is greater' do
allow(order).to receive_messages amount: 50.00
allow(calculator).to receive_messages preferred_flat_percent: 50

expect(calculator.compute(order)).to eq 10.00
end

it 'returns computed amount if cap is greater' do
allow(order).to receive_messages amount: 15.00
allow(calculator).to receive_messages preferred_flat_percent: 50

expect(calculator.compute(order)).to eq 7.50
end
end
end
end
27 changes: 27 additions & 0 deletions spec/models/spree/calculator/percent_on_line_item_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require 'spec_helper'

RSpec.describe Spree::Calculator::PercentOnLineItem, type: :model do
let(:calculator) { Spree::Calculator::PercentOnLineItem.new }
let(:line_item) { create(:line_item) }

before { allow(calculator).to receive_messages preferred_percent: 10 }

describe '#compute' do
context 'without cap' do
it 'rounds result correctly' do
allow(line_item).to receive_messages amount: 31.08
expect(calculator.compute(line_item)).to eq 3.11

allow(line_item).to receive_messages amount: 31.00
expect(calculator.compute(line_item)).to eq 3.10
end

it 'returns object.amount if computed amount is greater' do
allow(line_item).to receive_messages amount: 30.00
allow(calculator).to receive_messages preferred_percent: 110

expect(calculator.compute(line_item)).to eq 30.0
end
end
end
end
114 changes: 114 additions & 0 deletions spec/models/spree/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,120 @@
end
end

describe '#FlatPercentItemTotal' do
let(:calculator) { Spree::Calculator::FlatPercentItemTotal.create(preferred_flat_percent: 50) }
let!(:promotion) { create(:promotion_with_order_adjustment, starts_at: Date.today - 1.day, expires_at: Date.today + 5.day, match_policy: "any")}
let!(:order) { create(:order_with_totals, line_items_price: 30, total: 30, item_total: 30) }
let!(:promotion_action) { Spree::Promotion::Actions::CreateAdjustment.create!(promotion: promotion, calculator: calculator) }
let!(:order_promotion) { create(:order_promotion, order: order, promotion: promotion)}
let!(:order_adjustment) { create(:adjustment, order: order, source: promotion_action, adjustable: order)}

context 'when order has a promotion with a cap' do
before do
calculator.update(cap: 20)
end

it 'does not adjust promotion order adjustment if within the cap' do
order.update_with_updater!
order.reload

expect(order.item_total.to_f).to eq(30.0)
expect(order.total.to_f).to eq(15.0)
expect(order.adjustment_total.to_f).to eq(-15.0)
end

it 'adjusts promotion order adjustment to cap if exceeded' do
create(:line_item, order: order, price: 100)
order.reload.update_with_updater!
order.reload

expect(order.item_total.to_f).to eq(130.0)
expect(order.total.to_f).to eq(110.0)
expect(order.adjustment_total.to_f).to eq(-20.0)
end
end

context 'when order has a promotion without a cap' do
it 'adjust promotion order adjustment' do
order.reload.update_with_updater!

expect(order.item_total.to_f).to eq(30.0)
expect(order.total.to_f).to eq(15.0)
expect(order.adjustment_total.to_f).to eq(-15.0)
end

it 'adjusts promotion order adjustment 50%' do
create(:line_item, order: order, price: 100)

order.reload.update_with_updater!
order.update_totals

expect(order.item_total.to_f).to eq(130.0)
expect(order.total.to_f).to eq(65.0)
expect(order.adjustment_total.to_f).to eq(-65.0)
end
end
end

describe '#PercentOnLineItem' do
let(:calculator) { Spree::Calculator::PercentOnLineItem.create(preferred_percent: 20) }
let!(:promotion) { create(:promotion_with_order_adjustment, starts_at: Date.today - 1.day, expires_at: Date.today + 5.day, match_policy: "any")}
let!(:order) { create(:order) }
let!(:line_item) { create(:line_item, order: order, quantity: 2, price: 30.0)}
let!(:promotion_action) { Spree::Promotion::Actions::CreateItemAdjustments.create!(promotion: promotion, calculator: calculator) }
let!(:order_promotion) { create(:order_promotion, order: order, promotion: promotion)}
let!(:order_adjustment) { create(:adjustment, order: order, source: promotion_action, adjustable: line_item)}

context 'when order has a promotion with a cap' do
before do
calculator.update(cap: 20)
end

it 'does not adjust promotion line item if within the cap' do
order.update_with_updater!
order.reload

expect(order.item_total.to_f).to eq(60.0)
expect(order.total.to_f).to eq(48.0)
expect(order.adjustment_total.to_f).to eq(-12.0)
end

it 'adjusts promotion line item to cap if exceeded' do
line_item2 = create(:line_item, order: order, quantity: 2, price: 60)
create(:adjustment, order: order, source: promotion_action, adjustable: line_item2)
order.reload.update_with_updater!
order.reload

# line_item1 discount 60x0.2 = 12 < cap 20, line_item2 discount 120x0.2 = 24 > cap 20
expect(order.item_total.to_f).to eq(180.0)
expect(order.total.to_f).to eq(148.0)
expect(order.adjustment_total.to_f).to eq(-32.0)
end
end

context 'when order has a promotion without a cap' do
it 'adjust promotion line item adjustment' do
order.reload.update_with_updater!

expect(order.item_total.to_f).to eq(60.0)
expect(order.total.to_f).to eq(48.0)
expect(order.adjustment_total.to_f).to eq(-12.0)
end

it 'adjusts promotion line item adjustment 20% ' do
line_item2 = create(:line_item, order: order, quantity: 2, price: 60)
create(:adjustment, order: order, source: promotion_action, adjustable: line_item2)

order.reload.update_with_updater!
order.update_totals

# line_item1 discount 60x0.2 = 12 , line_item2 discount 120x0.2 = 24
expect(order.item_total.to_f).to eq(180.0)
expect(order.total.to_f).to eq(144.0)
expect(order.adjustment_total.to_f).to eq(-36.0)
end
end
end
describe '#valid_promotion_ids' do
let!(:order) { create(:order, total: 100) }
let!(:promotion) { create(:promotion, :with_order_adjustment) }
Expand Down
Loading

0 comments on commit 9797e3a

Please sign in to comment.