diff --git a/README.md b/README.md index 27638597..1cf8ba7a 100644 --- a/README.md +++ b/README.md @@ -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 ------------ diff --git a/app/controllers/spree/admin/relations_controller.rb b/app/controllers/spree/admin/relations_controller.rb index 982e23e7..ead96d81 100644 --- a/app/controllers/spree/admin/relations_controller.rb +++ b/app/controllers/spree/admin/relations_controller.rb @@ -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]) @@ -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 diff --git a/app/models/spree/calculator/related_product_discount.rb b/app/models/spree/calculator/related_product_discount.rb index 65e48707..d77cc73e 100644 --- a/app/models/spree/calculator/related_product_discount.rb +++ b/app/models/spree/calculator/related_product_discount.rb @@ -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 \ No newline at end of file diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index fc97d7d6..da0e9270 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -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 diff --git a/app/models/spree/relation.rb b/app/models/spree/relation.rb index b90bbf49..ebe73fea 100644 --- a/app/models/spree/relation.rb +++ b/app/models/spree/relation.rb @@ -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 diff --git a/app/views/spree/admin/products/_related_products_table.html.erb b/app/views/spree/admin/products/_related_products_table.html.erb index 747483ed..1de92e77 100644 --- a/app/views/spree/admin/products/_related_products_table.html.erb +++ b/app/views/spree/admin/products/_related_products_table.html.erb @@ -10,8 +10,9 @@
<% product.relations.each do |relation| %>