mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-14 04:04:23 +00:00
Relevant DiscountOrder tag rules are applied to orders on update
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
angular.module("admin.enterprises").directive "invertNumber", ->
|
||||||
|
restrict: "A"
|
||||||
|
require: "ngModel"
|
||||||
|
link: (scope, element, attrs, ngModel) ->
|
||||||
|
ngModel.$parsers.push (viewValue) ->
|
||||||
|
return -parseInt(viewValue) unless isNaN(parseInt(viewValue))
|
||||||
|
viewValue
|
||||||
|
|
||||||
|
ngModel.$formatters.push (modelValue) ->
|
||||||
|
return -parseInt(modelValue) unless isNaN(parseInt(modelValue))
|
||||||
|
modelValue
|
||||||
@@ -24,13 +24,16 @@
|
|||||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][id]",
|
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][id]",
|
||||||
ng: { value: "rule.calculator.id" } }
|
ng: { value: "rule.calculator.id" } }
|
||||||
|
|
||||||
|
%input{ type: "hidden",
|
||||||
|
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][preferred_flat_percent]",
|
||||||
|
ng: { value: "rule.calculator.preferred_flat_percent" } }
|
||||||
|
|
||||||
%span.text-normal {{ $index + 1 }}. Apply a discount of
|
%span.text-normal {{ $index + 1 }}. Apply a discount of
|
||||||
%span.input-symbol.after
|
%span.input-symbol.after
|
||||||
%span.text-normal %
|
%span.text-normal %
|
||||||
%input.text-big{ type: "number",
|
%input.text-big{ type: "number",
|
||||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_attributes_preferred_flat_percent",
|
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_attributes_preferred_flat_percent",
|
||||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][preferred_flat_percent]",
|
min: -100,
|
||||||
min: 0,
|
|
||||||
max: 100,
|
max: 100,
|
||||||
ng: { model: "rule.calculator.preferred_flat_percent" } }
|
ng: { model: "rule.calculator.preferred_flat_percent" }, 'invert-number' => true }
|
||||||
%span.text-normal to order subtotals
|
%span.text-normal to order subtotals
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ Spree::Order.class_eval do
|
|||||||
attr_accessible :order_cycle_id, :distributor_id
|
attr_accessible :order_cycle_id, :distributor_id
|
||||||
|
|
||||||
before_validation :shipping_address_from_distributor
|
before_validation :shipping_address_from_distributor
|
||||||
before_validation :associate_customer, unless: :customer_is_valid?
|
before_validation :associate_customer, unless: :customer_id?
|
||||||
|
before_validation :ensure_customer, unless: :customer_is_valid?
|
||||||
|
|
||||||
checkout_flow do
|
checkout_flow do
|
||||||
go_to_state :address
|
go_to_state :address
|
||||||
@@ -179,6 +180,10 @@ Spree::Order.class_eval do
|
|||||||
if order_cycle
|
if order_cycle
|
||||||
OpenFoodNetwork::EnterpriseFeeCalculator.new.create_order_adjustments_for self
|
OpenFoodNetwork::EnterpriseFeeCalculator.new.create_order_adjustments_for self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if distributor.present? && customer.present?
|
||||||
|
distributor.apply_tag_rules_to(self, customer: customer)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -289,14 +294,18 @@ Spree::Order.class_eval do
|
|||||||
customer.present? && customer.enterprise_id == distributor_id && customer.email == (user.andand.email || email)
|
customer.present? && customer.enterprise_id == distributor_id && customer.email == (user.andand.email || email)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def email_for_customer
|
||||||
|
user.andand.email || email
|
||||||
|
end
|
||||||
|
|
||||||
def associate_customer
|
def associate_customer
|
||||||
email_for_customer = user.andand.email || email
|
return customer if customer.present?
|
||||||
existing_customer = Customer.of(distributor).find_by_email(email_for_customer)
|
self.customer = Customer.of(distributor).find_by_email(email_for_customer)
|
||||||
if existing_customer
|
end
|
||||||
self.customer = existing_customer
|
|
||||||
else
|
def ensure_customer
|
||||||
new_customer = Customer.create(enterprise: distributor, email: email_for_customer, user: user)
|
unless associate_customer
|
||||||
self.customer = new_customer
|
self.customer = Customer.create(enterprise: distributor, email: email_for_customer, user: user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class TagRule < ActiveRecord::Base
|
|||||||
|
|
||||||
def customer_tags_match?
|
def customer_tags_match?
|
||||||
context_customer_tags = context.andand[:customer].andand.tag_list || []
|
context_customer_tags = context.andand[:customer].andand.tag_list || []
|
||||||
( context_customer_tags & preferred_customer_tags.split(",") ).any?
|
preferred_tags = preferred_customer_tags.split(",")
|
||||||
|
( context_customer_tags & preferred_tags ).any?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ class TagRule::DiscountOrder < TagRule
|
|||||||
|
|
||||||
# Warning: this should only EVER be called via TagRule#apply
|
# Warning: this should only EVER be called via TagRule#apply
|
||||||
def apply!
|
def apply!
|
||||||
percentage = "%.2f" % (calculator.preferred_flat_percent * -1)
|
create_adjustment(I18n.t("tag_rules.discount_order.discount"), subject, subject)
|
||||||
label = I18n.t("tag_rules.discount_order.label", percentage: percentage)
|
|
||||||
create_adjustment(label, subject, subject)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def subject_class
|
def subject_class
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ en:
|
|||||||
# Tag Rules
|
# Tag Rules
|
||||||
tag_rules:
|
tag_rules:
|
||||||
discount_order:
|
discount_order:
|
||||||
label: "%{percentage}% discount"
|
discount: "Discount"
|
||||||
|
|
||||||
logo: "Logo (640x130)" #FIXME
|
logo: "Logo (640x130)" #FIXME
|
||||||
logo_mobile: "Mobile logo (75x26)" #FIXME
|
logo_mobile: "Mobile logo (75x26)" #FIXME
|
||||||
|
|||||||
@@ -301,13 +301,13 @@ feature %q{
|
|||||||
|
|
||||||
expect(page).to have_content 'No rules apply to this tag yet'
|
expect(page).to have_content 'No rules apply to this tag yet'
|
||||||
click_button '+ Add A New Rule'
|
click_button '+ Add A New Rule'
|
||||||
fill_in "enterprise[tag_rules_attributes][0][calculator_attributes][preferred_flat_percent]", with: 22
|
fill_in "enterprise_tag_rules_attributes_0_calculator_attributes_preferred_flat_percent", with: 22
|
||||||
|
|
||||||
click_button 'Update'
|
click_button 'Update'
|
||||||
|
|
||||||
tag_rule = TagRule::DiscountOrder.last
|
tag_rule = TagRule::DiscountOrder.last
|
||||||
expect(tag_rule.preferred_customer_tags).to eq "volunteer"
|
expect(tag_rule.preferred_customer_tags).to eq "volunteer"
|
||||||
expect(tag_rule.calculator.preferred_flat_percent).to eq 22
|
expect(tag_rule.calculator.preferred_flat_percent).to eq -22
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -325,13 +325,13 @@ feature %q{
|
|||||||
expect(first('.customer_tag .header')).to have_content "For customers tagged:"
|
expect(first('.customer_tag .header')).to have_content "For customers tagged:"
|
||||||
expect(first('tags-input .tag-list ti-tag-item')).to have_content "member"
|
expect(first('tags-input .tag-list ti-tag-item')).to have_content "member"
|
||||||
find(:css, "tags-input .tags input").set "volunteer\n"
|
find(:css, "tags-input .tags input").set "volunteer\n"
|
||||||
expect(page).to have_input "enterprise[tag_rules_attributes][0][calculator_attributes][preferred_flat_percent]", with: "0"
|
expect(page).to have_field "enterprise_tag_rules_attributes_0_calculator_attributes_preferred_flat_percent", with: '0'
|
||||||
fill_in "enterprise[tag_rules_attributes][0][calculator_attributes][preferred_flat_percent]", with: 45
|
fill_in "enterprise_tag_rules_attributes_0_calculator_attributes_preferred_flat_percent", with: 45
|
||||||
|
|
||||||
click_button 'Update'
|
click_button 'Update'
|
||||||
|
|
||||||
expect(tag_rule.preferred_customer_tags).to eq "member,volunteer"
|
expect(tag_rule.preferred_customer_tags).to eq "member,volunteer"
|
||||||
expect(tag_rule.calculator.preferred_flat_percent).to eq 45
|
expect(tag_rule.calculator.preferred_flat_percent).to eq -45
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -108,44 +108,76 @@ describe Spree::Order do
|
|||||||
subject.update_distribution_charge!
|
subject.update_distribution_charge!
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "looking up whether a line item can be provided by an order cycle" do
|
context "appying tag rules" do
|
||||||
it "returns true when the variant is provided" do
|
let(:enterprise) { create(:distributor_enterprise) }
|
||||||
v = double(:variant)
|
let(:customer) { create(:customer, enterprise: enterprise, tag_list: "tagtagtag") }
|
||||||
line_item = double(:line_item, variant: v)
|
let(:tag_rule) { create(:tag_rule, enterprise: enterprise, preferred_customer_tags: "tagtagtag") }
|
||||||
order_cycle = double(:order_cycle, variants: [v])
|
let(:order) { create(:order_with_totals_and_distribution, distributor: enterprise, customer: customer) }
|
||||||
subject.stub(:order_cycle) { order_cycle }
|
|
||||||
|
|
||||||
subject.send(:provided_by_order_cycle?, line_item).should be_true
|
before do
|
||||||
|
tag_rule.calculator.update_attribute(:preferred_flat_percent, -10)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false otherwise" do
|
context "when the rule applies" do
|
||||||
v = double(:variant)
|
it "applies the rule" do
|
||||||
line_item = double(:line_item, variant: v)
|
order.update_distribution_charge!
|
||||||
order_cycle = double(:order_cycle, variants: [])
|
order.reload
|
||||||
subject.stub(:order_cycle) { order_cycle }
|
discount = order.adjustments.find_by_label("Discount")
|
||||||
|
expect(discount).to be_a Spree::Adjustment
|
||||||
subject.send(:provided_by_order_cycle?, line_item).should be_false
|
expect(discount.amount).to eq (order.item_total / -10).round(2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false when there is no order cycle" do
|
context "when the rule does not apply" do
|
||||||
v = double(:variant)
|
before { tag_rule.update_attribute(:preferred_customer_tags, "tagtag") }
|
||||||
line_item = double(:line_item, variant: v)
|
|
||||||
subject.stub(:order_cycle) { nil }
|
|
||||||
|
|
||||||
subject.send(:provided_by_order_cycle?, line_item).should be_false
|
it "does not apply the rule" do
|
||||||
|
order.update_distribution_charge!
|
||||||
|
order.reload
|
||||||
|
discount = order.adjustments.find_by_label("Discount")
|
||||||
|
expect(discount).to be_nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "looks up product distribution enterprise fees for a line item" do
|
describe "looking up whether a line item can be provided by an order cycle" do
|
||||||
product = double(:product)
|
it "returns true when the variant is provided" do
|
||||||
variant = double(:variant, product: product)
|
v = double(:variant)
|
||||||
line_item = double(:line_item, variant: variant)
|
line_item = double(:line_item, variant: v)
|
||||||
|
order_cycle = double(:order_cycle, variants: [v])
|
||||||
|
subject.stub(:order_cycle) { order_cycle }
|
||||||
|
|
||||||
product_distribution = double(:product_distribution)
|
subject.send(:provided_by_order_cycle?, line_item).should be_true
|
||||||
product.should_receive(:product_distribution_for).with(subject.distributor) { product_distribution }
|
|
||||||
|
|
||||||
subject.send(:product_distribution_for, line_item).should == product_distribution
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns false otherwise" do
|
||||||
|
v = double(:variant)
|
||||||
|
line_item = double(:line_item, variant: v)
|
||||||
|
order_cycle = double(:order_cycle, variants: [])
|
||||||
|
subject.stub(:order_cycle) { order_cycle }
|
||||||
|
|
||||||
|
subject.send(:provided_by_order_cycle?, line_item).should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when there is no order cycle" do
|
||||||
|
v = double(:variant)
|
||||||
|
line_item = double(:line_item, variant: v)
|
||||||
|
subject.stub(:order_cycle) { nil }
|
||||||
|
|
||||||
|
subject.send(:provided_by_order_cycle?, line_item).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks up product distribution enterprise fees for a line item" do
|
||||||
|
product = double(:product)
|
||||||
|
variant = double(:variant, product: product)
|
||||||
|
line_item = double(:line_item, variant: variant)
|
||||||
|
|
||||||
|
product_distribution = double(:product_distribution)
|
||||||
|
product.should_receive(:product_distribution_for).with(subject.distributor) { product_distribution }
|
||||||
|
|
||||||
|
subject.send(:product_distribution_for, line_item).should == product_distribution
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "getting the admin and handling charge" do
|
describe "getting the admin and handling charge" do
|
||||||
@@ -559,39 +591,76 @@ describe Spree::Order do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "associating a customer" do
|
describe "associating a customer" do
|
||||||
let(:user) { create(:user) }
|
|
||||||
let(:distributor) { create(:distributor_enterprise) }
|
let(:distributor) { create(:distributor_enterprise) }
|
||||||
|
let!(:order) { create(:order, distributor: distributor) }
|
||||||
|
|
||||||
context "when a user has been set on the order" do
|
context "when an email address is available for the order" do
|
||||||
let!(:order) { create(:order, distributor: distributor, user: user) }
|
before { allow(order).to receive(:email_for_customer) { "existing@email.com" }}
|
||||||
context "and a customer for order.distributor and order.user.email already exists" do
|
|
||||||
let!(:customer) { create(:customer, enterprise: distributor, email: user.email) }
|
context "and a customer for order.distributor and order#email_for_customer already exists" do
|
||||||
it "associates the order with the existing customer" do
|
let!(:customer) { create(:customer, enterprise: distributor, email: "existing@email.com" ) }
|
||||||
order.send(:associate_customer)
|
|
||||||
|
it "associates the order with the existing customer, and returns the customer" do
|
||||||
|
result = order.send(:associate_customer)
|
||||||
expect(order.customer).to eq customer
|
expect(order.customer).to eq customer
|
||||||
|
expect(result).to eq customer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "and a customer for order.distributor and order.user.email does not alread exist" do
|
context "and a customer for order.distributor and order.user.email does not alread exist" do
|
||||||
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
||||||
it "creates a new customer" do
|
|
||||||
expect{order.send(:associate_customer)}.to change{Customer.count}.by 1
|
it "does not set the customer and returns nil" do
|
||||||
|
result = order.send(:associate_customer)
|
||||||
|
expect(order.customer).to be_nil
|
||||||
|
expect(result).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when a user has not been set on the order" do
|
context "when an email address is not available for the order" do
|
||||||
let!(:order) { create(:order, distributor: distributor, user: nil) }
|
let!(:customer) { create(:customer, enterprise: distributor) }
|
||||||
context "and a customer for order.distributor and order.email already exists" do
|
before { allow(order).to receive(:email_for_customer) { nil }}
|
||||||
let!(:customer) { create(:customer, enterprise: distributor, email: order.email) }
|
|
||||||
it "creates a new customer" do
|
it "does not set the customer and returns nil" do
|
||||||
order.send(:associate_customer)
|
result = order.send(:associate_customer)
|
||||||
|
expect(order.customer).to be_nil
|
||||||
|
expect(result).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "ensuring a customer is linked" do
|
||||||
|
let(:distributor) { create(:distributor_enterprise) }
|
||||||
|
let!(:order) { create(:order, distributor: distributor) }
|
||||||
|
|
||||||
|
context "when a customer has already been linked to the order" do
|
||||||
|
let!(:customer) { create(:customer, enterprise: distributor, email: "existing@email.com" ) }
|
||||||
|
before { order.update_attribute(:customer_id, customer.id) }
|
||||||
|
|
||||||
|
it "does nothing" do
|
||||||
|
order.send(:ensure_customer)
|
||||||
|
expect(order.customer).to eq customer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a customer not been linked to the order" do
|
||||||
|
context "but one matching order#email_for_customer already exists" do
|
||||||
|
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
||||||
|
before { allow(order).to receive(:email_for_customer) { 'some-other-email@email.com' } }
|
||||||
|
|
||||||
|
it "links the customer customer to the order" do
|
||||||
|
expect(order.customer).to be_nil
|
||||||
|
expect{order.send(:ensure_customer)}.to_not change{Customer.count}
|
||||||
expect(order.customer).to eq customer
|
expect(order.customer).to eq customer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "and a customer for order.distributor and order.email does not alread exist" do
|
|
||||||
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
context "and order#email_for_customer does not match any existing customers" do
|
||||||
it "creates a new customer" do
|
it "creates a new customer" do
|
||||||
expect{order.send(:associate_customer)}.to change{Customer.count}.by 1
|
expect(order.customer).to be_nil
|
||||||
|
expect{order.send(:ensure_customer)}.to change{Customer.count}.by 1
|
||||||
|
expect(order.customer).to be_a Customer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe TagRule::DiscountOrder, type: :model do
|
|||||||
tag_rule.send(:apply!)
|
tag_rule.send(:apply!)
|
||||||
expect(adjustment).to be_a Spree::Adjustment
|
expect(adjustment).to be_a Spree::Adjustment
|
||||||
expect(adjustment.amount).to eq -10.00
|
expect(adjustment.amount).to eq -10.00
|
||||||
expect(adjustment.label).to eq "10.00% discount"
|
expect(adjustment.label).to eq "Discount"
|
||||||
expect(order.adjustment_total).to eq -10.00
|
expect(order.adjustment_total).to eq -10.00
|
||||||
expect(order.total).to eq 90.00
|
expect(order.total).to eq 90.00
|
||||||
end
|
end
|
||||||
@@ -84,7 +84,7 @@ describe TagRule::DiscountOrder, type: :model do
|
|||||||
tag_rule.send(:apply!)
|
tag_rule.send(:apply!)
|
||||||
expect(adjustment).to be_a Spree::Adjustment
|
expect(adjustment).to be_a Spree::Adjustment
|
||||||
expect(adjustment.amount).to eq -10.00
|
expect(adjustment.amount).to eq -10.00
|
||||||
expect(adjustment.label).to eq "10.00% discount"
|
expect(adjustment.label).to eq "Discount"
|
||||||
expect(order.adjustment_total).to eq 15.00
|
expect(order.adjustment_total).to eq 15.00
|
||||||
expect(order.total).to eq 115.00
|
expect(order.total).to eq 115.00
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user