Class: SpreePromo::Engine

Inherits:
Rails::Engine
  • Object
show all
Defined in:
lib/spree_promo.rb

Class Method Summary collapse

Class Method Details

.activateObject



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/spree_promo.rb', line 6

def self.activate
  # put class_eval and other logic that depends on classes outside of the engine inside this block
  Product.class_eval do
    has_and_belongs_to_many :promotion_rules

    def possible_promotions
      rules_with_matching_product_groups = product_groups.map(&:promotion_rules).flatten
      all_rules = promotion_rules + rules_with_matching_product_groups
      promotion_ids = all_rules.map(&:promotion_id).uniq
      Promotion.automatic.scoped(:conditions => {:id => promotion_ids})
    end
  end

  ProductGroup.class_eval do
    has_many :promotion_rules
  end

  Order.class_eval do

    has_many :promotion_credits, :conditions => "source_type='Promotion'", :dependent => :destroy

    attr_accessible :coupon_code
    attr_accessor :coupon_code
    before_save :process_coupon_code, :if => "@coupon_code.present?"

    def promotion_credit_exists?(credit)
      promotion_credits.reload.detect { |c| c.source_id == credit.id }
    end

    def process_coupon_code
      coupon = Promotion.find(:first, :conditions => ["UPPER(code) = ?", @coupon_code.upcase])
      if coupon
        coupon.create_discount(self)
      end
    end

    def products
      line_items.map {|li| li.variant.product}
    end

    def update_totals(force_adjustment_recalculation=false)
      self.payment_total = payments.completed.map(&:amount).sum
      self.item_total = line_items.map(&:amount).sum

      process_automatic_promotions

      if force_adjustment_recalculation
        applicable_adjustments, adjustments_to_destroy = adjustments.partition{|a| a.applicable?}
        self.adjustments = applicable_adjustments
        adjustments_to_destroy.each(&:destroy)
      end

      self.adjustment_total = self.adjustments.map(&:amount).sum
      self.total            = self.item_total   + self.adjustment_total
    end


    def process_automatic_promotions
      # recalculate amount
      self.promotion_credits.each do |credit|
        if credit.source.eligible?(self)
          amount = -credit.source.calculator.compute(self).abs
          if credit.amount != amount
            # avoid infinite callbacks
            PromotionCredit.update_all("amount = #{amount}", { :id => credit.id })
          end
        else
          credit.destroy
        end
      end
      
      current_promotions = self.promotion_credits.map(&:source)
      # return if current promotions can not be combined
      return if current_promotions.any? { |promotion| !promotion.combine? }
      
      new_promotions = eligible_automatic_promotions - current_promotions
      new_promotions.each do |promotion|
        next if current_promotions.present? && !promotion.combine?
        amount = promotion.calculator.compute(self).abs
        amount = item_total if amount > item_total
        if amount > 0
          self.promotion_credits.create(
              :source => promotion,
              :amount => -amount,
              :label  => promotion.name
            )
        end
      end
    end

    def eligible_automatic_promotions
      @eligible_automatic_coupons ||= Promotion.automatic.select{|c| c.eligible?(self)}
    end
  end

  if File.basename( $0 ) != "rake"
    # register promotion rules
    [Promotion::Rules::ItemTotal, Promotion::Rules::Product, Promotion::Rules::User, Promotion::Rules::FirstOrder].each &:register

    # register default promotion calculators
    [
      Calculator::FlatPercentItemTotal,
      Calculator::FlatRate,
      Calculator::FlexiRate,
      Calculator::PerItem,
      Calculator::FreeShipping
    ].each{|c_model|
      begin
        Promotion.register_calculator(c_model) if c_model.table_exists?
      rescue Exception => e
        $stderr.puts "Error registering promotion calculator #{c_model}"
      end
    }
  end
end