-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add handler to create weighted adjustments
We'll be introducing a new calculator for promotions that will allow order-level promotion values to be applied through line item adjustments. This class keeps some of the more complicated logic out of the calculator as it has to reach up to the order and calculate values on multiple line items.
- Loading branch information
1 parent
ef63800
commit f3d600e
Showing
2 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
module Spree | ||
class DistributedAmountsHandler | ||
attr_reader :line_item, :order, :total_amount | ||
|
||
def initialize(line_item, total_amount) | ||
@line_item = line_item | ||
@order = line_item.order | ||
@total_amount = total_amount | ||
end | ||
|
||
# @return [Float] the weighted adjustment for the initialized line item | ||
def amount | ||
distributed_amounts[@line_item.id].to_f | ||
end | ||
|
||
private | ||
|
||
# @private | ||
# @return [Hash<Integer, BigDecimal>] a hash of line item IDs and their | ||
# corresponding weighted adjustments | ||
def distributed_amounts | ||
remaining_amount = @total_amount | ||
|
||
@order.line_items.each_with_index.map do |line_item, i| | ||
if i == @order.line_items.length - 1 | ||
# If this is the last line item on the order we want to use the | ||
# remaining preferred amount to ensure our total adjustment is what | ||
# has been set as the preferred amount. | ||
[line_item.id, remaining_amount] | ||
else | ||
# Calculate the weighted amount by getting this line item's share of | ||
# the order's total and multiplying it with the preferred amount. | ||
weighted_amount = ((line_item.amount / @order.item_total) * total_amount).round(2) | ||
|
||
# Subtract this line item's weighted amount from the total. | ||
remaining_amount -= weighted_amount | ||
|
||
[line_item.id, weighted_amount] | ||
end | ||
end.to_h | ||
end | ||
end | ||
end |
79 changes: 79 additions & 0 deletions
79
core/spec/models/spree/distributed_amounts_handler_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
require "spec_helper" | ||
|
||
RSpec.describe Spree::DistributedAmountsHandler, type: :model do | ||
let(:order) do | ||
FactoryGirl.create( | ||
:order_with_line_items, | ||
line_items_attributes: line_items_attributes | ||
) | ||
end | ||
|
||
describe "#amount" do | ||
let(:total_amount) { 15 } | ||
|
||
subject { described_class.new(line_item, total_amount).amount } | ||
|
||
context "when there is only one line item" do | ||
let(:line_items_attributes) { [{ price: 100 }] } | ||
let(:line_item) { order.line_items.first } | ||
|
||
it "applies the entire amount to the line item" do | ||
expect(subject).to eq(15) | ||
end | ||
end | ||
|
||
context "when there are multiple line items" do | ||
let(:line_items_attributes) do | ||
[{ price: 50 }, { price: 50 }, { price: 50 }] | ||
end | ||
|
||
context "and the line items are equally priced" do | ||
it "evenly distributes the total amount" do | ||
expect( | ||
[ | ||
described_class.new(order.line_items[0], total_amount).amount, | ||
described_class.new(order.line_items[1], total_amount).amount, | ||
described_class.new(order.line_items[2], total_amount).amount | ||
] | ||
).to eq( | ||
[5, 5, 5] | ||
) | ||
end | ||
|
||
context "and the total amount cannot be equally distributed" do | ||
let(:total_amount) { 10 } | ||
|
||
it "applies the remainder of the total amount to the last item" do | ||
expect( | ||
[ | ||
described_class.new(order.line_items[0], total_amount).amount, | ||
described_class.new(order.line_items[1], total_amount).amount, | ||
described_class.new(order.line_items[2], total_amount).amount | ||
] | ||
).to eq( | ||
[3.33, 3.33, 3.34] | ||
) | ||
end | ||
end | ||
end | ||
|
||
context "and the line items are not equally priced" do | ||
let(:line_items_attributes) do | ||
[{ price: 150 }, { price: 50 }, { price: 100 }] | ||
end | ||
|
||
it "distributes the total amount relative to the item's price" do | ||
expect( | ||
[ | ||
described_class.new(order.line_items[0], total_amount).amount, | ||
described_class.new(order.line_items[1], total_amount).amount, | ||
described_class.new(order.line_items[2], total_amount).amount | ||
] | ||
).to eq( | ||
[7.5, 2.5, 5] | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |