Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed product matching and updated readme for promotions #25

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ You can access all related products regardless of RelationType by:
Discounts
You can optionally specify a discount amount to be applied if a customer purchases both products.

Note: In order for the coupon to be automatically applied, you must create a promotion leaving the __code__ value empty, and adding an Action of type : __RelatedProductDiscount__ (blank codes are required for coupons to be automatically applied).
Note: In order for the coupon to be automatically applied, you must create a promotion and add a "Create adjustment" action with a __Related Product Discount__ calculator. You should be able to add any other criteria or actions that you want as well. If you don't add any rules, it should be applied to all orders w/ matching products.

Note: Item Total Threshold is NOT implemented

Installation
------------
Expand Down
9 changes: 8 additions & 1 deletion app/controllers/spree/admin/relations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Admin
class RelationsController < BaseController
before_filter :load_data, :only => [:create, :destroy]

respond_to :js
respond_to :js, :html

def create
@relation = Relation.new(params[:relation])
Expand All @@ -14,6 +14,13 @@ def create
respond_with(@relation)
end

def update
@relation = Relation.find(params[:id])
@relation.update_attribute :discount_amount, params[:relation][:discount_amount] || 0

redirect_to( related_admin_product_url(@relation.relatable) )
end

def destroy
@relation = Relation.find(params[:id])
@relation.destroy
Expand Down
42 changes: 24 additions & 18 deletions app/models/spree/calculator/related_product_discount.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,38 @@ def compute(object)
order = object
end

return unless eligible?(order)
total = order.line_items.inject(0) do |total, line_item|
relations = Spree::Relation.find(:all, :conditions => ["discount_amount <> 0.0 AND relatable_type = ? AND relatable_id = ?", "Spree::Product", line_item.variant.product.id])
discount_applies_to = relations.map {|rel| rel.related_to.master }

order.line_items.each do |li|
if discount_applies_to.include? li.variant
discount = relations.detect {|rel| rel.related_to.master == li.variant}.discount_amount

total += if li.quantity < line_item.quantity
(discount * li.quantity)
else
(discount * line_item.quantity)
end
# related_to is the one that gets the discount
product_ids = order.line_items.map{|i| i.variant.product_id}.uniq
discounts = Spree::Relation.where(["discount_amount <> 0.0 AND related_to_type = ? AND related_to_id IN (?)", "Spree::Product", product_ids]).all.group_by(&:related_to_id)
return if discounts.empty?

total = 0
order.line_items.each do |line_item|
relations_for_line_item = discounts[line_item.variant.product_id]
next if relations_for_line_item.blank?

discount_percent = 0
relations_for_line_item.each do |relation_for_line_item|
if product_ids.include?( relation_for_line_item.relatable_id )
# Apply the maximum available discount percentage
discount_percent = [discount_percent,
relation_for_line_item.discount_amount].max
end
end

total
discount = ((line_item.price * discount_percent / 100.0) * line_item.quantity).round(2)
if line_item.respond_to?(:discount_percent)
line_item.update_column( :discount_percent, discount_percent )
end
total += discount
end

total == 0 ? nil : total
end

def eligible?(order)
order.line_items.any? { |line_item| Spree::Relation.exists?(["discount_amount <> 0.0 AND relatable_type = ? AND relatable_id = ?", "Spree::Product", line_item.variant.product.id])}
product_ids = order.line_items.map{|i| i.variant.product_id}.uniq
Spree::Relation.where(["discount_amount <> 0.0 AND related_to_type = ? AND related_to_id IN (?)", "Spree::Product", product_ids]).exists?
end

end
end
end
1 change: 1 addition & 0 deletions app/models/spree/product_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Spree::Product.class_eval do
has_many :relations, :as => :relatable
has_many :related_tos, :as => :related_to, :class_name => 'Relation'

# Returns all the Spree::RelationType's which apply_to this class.
def self.relation_types
Expand Down
1 change: 1 addition & 0 deletions app/models/spree/relation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ class Spree::Relation < ActiveRecord::Base
belongs_to :related_to, :polymorphic => true

validates_presence_of :relation_type, :relatable, :related_to
validates_inclusion_of :discount_amount, :in => 0..100
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
<tbody>
<% product.relations.each do |relation| %>
<tr id="<%= dom_id relation %>">
<td><%= relation.related_to.name %></td>
<td><%= relation.discount_amount != 0 ? number_to_currency(relation.discount_amount) : "-" %></td>
<td><%= link_to relation.related_to.name, relation.related_to %></td>
<td><%= form_for(relation, url:admin_product_relation_path(relation.relatable, relation)) do |f| %>
<%= f.text_field :discount_amount, :size => 4 %>% &nbsp; <%= f.submit 'Update' %> <% end %></td>
<td><%= relation.relation_type.name %></td>
<td width="70px">
<%= link_to_delete relation, {:url => admin_product_relation_url(relation.relatable, relation)} %>
Expand Down
8 changes: 4 additions & 4 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
en:
new_relation_type: New Relation Type
discount_amount: Discount Amount
related_product_discount: Related Product Discount
discount_amount: Discount %
related_product_discount: Matching Product Discount
relation_types: Relation Types
applies_to: Applies To
editing_relation_type: Editing Relation Type
related_products: Related Products
add_related_product: Add Related Product
related_products: Matching Products
add_related_product: Add Matching Product
name_or_sku: Name or SKU
manage_relation_types: Manage relation types
no_relation_types: You need to configure Relation Types before you can use this feature.
4 changes: 2 additions & 2 deletions spree_related_products.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Gem::Specification.new do |s|

s.has_rdoc = true

s.add_dependency 'spree_core', '~> 1.0.0'
s.add_dependency 'spree_promo', '~> 1.0.0'
s.add_dependency 'spree_core', '>= 1.0.0'
s.add_dependency 'spree_promo', '>= 1.0.0'

s.add_development_dependency 'factory_girl'
s.add_development_dependency 'rspec-rails', ' ~> 2.8.0.rc1'
Expand Down