diff --git a/backend/app/views/spree/admin/promotions/calculators/weighted_rate/_fields.html.erb b/backend/app/views/spree/admin/promotions/calculators/weighted_rate/_fields.html.erb
new file mode 100644
index 0000000000..05f7308b33
--- /dev/null
+++ b/backend/app/views/spree/admin/promotions/calculators/weighted_rate/_fields.html.erb
@@ -0,0 +1,54 @@
+<%= fields_for "#{prefix}[calculator_attributes]", calculator do |f| %>
+ <%= f.label :preferred_amount %>
+ <%= render "spree/admin/shared/number_with_currency", f: f, amount_attr: :preferred_amount, currency_attr: :preferred_currency %>
+<% end %>
+
+
+
+ <%= admin_hint(
+ calculator.model_name.human,
+ """
+
+ This amount will distributed to line items weighted relative to their
+ price. More expensive line items will receive a greater share of the
+ adjustment.
+
+
+
+ For example, with three line items and a preferred amount of $15 we
+ would end up with the following distribution:
+
+
+
+
+
+ |
+ Price |
+ Weighted Adj. |
+
+
+
+
+ Socks |
+ $5 |
+ -$1.5 |
+
+
+ Shoes |
+ $30 |
+ -$9 |
+
+
+ Slippers |
+ $15 |
+ -$4.5 |
+
+
+
+ """
+ ) %>
+
+ This amount will be the
total discount spread amongst all
+ of the line items.
+
+
diff --git a/core/app/models/spree/calculator/distributed_amount.rb b/core/app/models/spree/calculator/distributed_amount.rb
new file mode 100644
index 0000000000..aff818e79a
--- /dev/null
+++ b/core/app/models/spree/calculator/distributed_amount.rb
@@ -0,0 +1,24 @@
+require_dependency 'spree/calculator'
+
+# This is a calculator for line item adjustment actions. It accepts a line item
+# and calculates its weighted adjustment amount based on the value of the
+# preferred amount and the price of the other line items. More expensive line
+# items will receive a greater share of the preferred amount.
+
+module Spree
+ class Calculator::DistributedAmount < Calculator
+ preference :amount, :decimal, default: 0
+ preference :currency, :string, default: -> { Spree::Config[:currency] }
+
+ def compute_line_item(line_item)
+ if line_item && preferred_currency.casecmp(line_item.currency).zero?
+ Spree::DistributedAmountsHandler.new(
+ line_item,
+ preferred_amount
+ ).amount
+ else
+ 0
+ end
+ end
+ end
+end
diff --git a/core/config/locales/en.yml b/core/config/locales/en.yml
index ccdc31968b..d7ce8c3abf 100644
--- a/core/config/locales/en.yml
+++ b/core/config/locales/en.yml
@@ -401,6 +401,9 @@ en:
spree/calculator/default_tax:
one: Default Tax
other: Default Tax
+ spree/calculator/distributed_amount:
+ one: Distributed Amount
+ other: Distributed Amount
spree/calculator/flat_percent_item_total:
one: Flat Percent
other: Flat Percent
diff --git a/core/lib/spree/core/engine.rb b/core/lib/spree/core/engine.rb
index 3f7ae0af6c..f098b013fc 100644
--- a/core/lib/spree/core/engine.rb
+++ b/core/lib/spree/core/engine.rb
@@ -67,9 +67,10 @@ class Engine < ::Rails::Engine
]
app.config.spree.calculators.promotion_actions_create_item_adjustments = %w[
- Spree::Calculator::PercentOnLineItem
+ Spree::Calculator::DistributedAmount
Spree::Calculator::FlatRate
Spree::Calculator::FlexiRate
+ Spree::Calculator::PercentOnLineItem
Spree::Calculator::TieredPercent
]
diff --git a/core/spec/models/spree/calculator/distributed_amount_spec.rb b/core/spec/models/spree/calculator/distributed_amount_spec.rb
new file mode 100644
index 0000000000..9b6da114b6
--- /dev/null
+++ b/core/spec/models/spree/calculator/distributed_amount_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+require 'shared_examples/calculator_shared_examples'
+
+describe Spree::Calculator::DistributedAmount, type: :model do
+ describe "#compute_line_item" do
+ subject { calculator.compute_line_item(order.line_items.first) }
+
+ let(:calculator) { Spree::Calculator::DistributedAmount.new }
+
+ let(:order) do
+ FactoryGirl.create(
+ :order_with_line_items,
+ line_items_attributes: [{ price: 50 }, { price: 50 }, { price: 50 }]
+ )
+ end
+
+ before do
+ calculator.preferred_amount = 15
+ calculator.preferred_currency = currency
+ end
+
+ context "when the order currency matches the store's currency" do
+ let(:currency) { "USD" }
+ it { is_expected.to eq 5 }
+ end
+
+ context "when the order currency does not match the store's currency" do
+ let(:currency) { "CAD" }
+ it { is_expected.to eq 0 }
+ end
+ end
+end