Permalink
Browse files

Instead of changing price subtract discount from order total.

This is a first step to allow us to apply discount differently to quantity
portions of the same variant. I.e. sell 3 first units for $10, the next three
for $9 and all the next for $8.
  • Loading branch information...
1 parent 49190d2 commit 21caba756fad785e08125c3ef6539b2152f7feff @amw amw committed Mar 2, 2011
View
@@ -33,31 +33,52 @@ Cart Contents:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 1 20.99 19.99
+ Rails T-Shirt 1 19.99 19.99
+
+Order details:
+
+ Volume Discount: 0.00
+ Subtotal: 19.99
## Example 2
Cart Contents:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 5 18.00 90.00
+ Rails T-Shirt 5 19.99 99.95
+
+Order details:
+
+ Volume Discount: -9.95 # 5 * (19.99 - 18)
+ Subtotal: 90.00
## Example 3
Cart Contents:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 6 18.00 108.00
+ Rails T-Shirt 6 19.99 119.94
+
+Order details:
+
+ Volume Discount: -11.94 # 6 * (19.99 - 18)
+ Subtotal: 108.00
## Example 4
Cart Contents:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 20 15.00 300.00
+ Rails T-Shirt 20 19.99 399.80
+
+Order details:
+
+ Volume Discount: -99.80 # 20 * (19.99 - 15)
+ Subtotal: 300.00
+
Why is it simple
@@ -78,6 +99,7 @@ The original extension had also some issues, such as defining overlapping
ranges. The models were unnecessarily complicated. Why `acts_as_list` if you can
just order volume prices by their lower quantity range end?
+
Volume Customers
================
@@ -105,22 +127,33 @@ Assuming the same volume prices configuration as above. First order:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 8 18.00 144.00
+ Rails T-Shirt 8 19.99 159.92
+
+Order details:
+
+ Volume Discount: -15.92 # 8 * (19.99 - 18)
+ Subtotal: 144.00
+
Next order during the next 31 days:
Product Quantity Price Total
----------------------------------------------------------------
- Rails T-Shirt 4 15.00 60.00
+ Rails T-Shirt 4 19.99 79.96
+
+Order details:
+
+ Volume Discount: -7.96 # 4 * (19.99 - 18)
+ Subtotal: 72.00
Additional Notes
================
-* The volume price is applied based on the total quantity ordered for
- a particular variant. It does not (yet) apply different prices for the portion
- of the quantity that falls within a particular range. Although I plan to
- support such option.
+* The volume discount is calculated by applying the discount price to all
+ ordered units of a particular variant. It does not (yet) apply different
+ prices for the portion of the quantity that falls within a particular range.
+ Although I plan to support such option.
Authors
=======
@@ -1,10 +1,31 @@
LineItem.class_eval do
- before_update :check_volume_pricing
+ before_save :check_update_volume_discount
- private
- def check_volume_pricing
- if changed? && changes.keys.include?("quantity")
- self.price = variant.volume_price quantity, order
+ def update_volume_discount updated_order = nil
+ self.volume_discount = 0
+
+ return if self.quantity < 1 || variant.volume_prices.empty?
+
+ self.order = updated_order if updated_order
+ total_quantity = self.quantity + order.variant_starting_quantity(variant)
+ final_price = default_price = self.price
+
+ variant.volume_prices.each do |vp|
+ break if vp.starting_quantity > total_quantity
+ final_price = vp.price
end
+
+ self.volume_discount = self.quantity * (final_price - default_price)
+ end
+
+ def amount_with_volume_discount
+ update_volume_discount
+ amount_without_volume_discount + self.volume_discount
+ end
+ alias_method_chain :amount, :volume_discount
+
+ private
+ def check_update_volume_discount
+ update_volume_discount if price_changed? || quantity_changed?
end
end
@@ -1,11 +1,7 @@
Order.class_eval do
- def add_variant_with_volume_prices variant, quantity = 1
- current_item = add_variant_without_volume_prices variant, quantity
- current_item.price = variant.volume_price current_item.quantity, self
- raise ActiveRecord::RollBack unless current_item.save
- update!
+ def volume_discount
+ line_items.map(&:volume_discount).sum
end
- alias_method_chain :add_variant, :volume_prices
# By default volume price is calculated based only on quantity of the current
# order. If you want to have "Volume Customers" - people who purchase at
@@ -19,14 +15,12 @@ def variant_starting_quantity variant
end
# This is required for Volume Customers
- # It updates line items prices when user logs in
- def recalculate_prices_on_user_association
- if user_id_changed? || email_changed?
- line_items.each do |li|
- li.price = li.variant.volume_price li.quantity, self
- li.save
- end
- end
+ # It updates item_total when user logs in
+ def update_totals_on_user_association
+ return unless user_id_changed? || email_changed?
+
+ line_items.each {|li| li.update_volume_discount self}
+ update_totals
end
- before_save :recalculate_prices_on_user_association
+ before_save :update_totals_on_user_association
end
@@ -9,18 +9,6 @@
after_create :copy_master_volume_prices
- # calculates the price based on quantity
- def volume_price quantity, order = nil
- quantity += order.variant_starting_quantity self if order
-
- price = self.price
- volume_prices.each do |vp|
- break if vp.starting_quantity > quantity
- price = vp.price
- end
- price
- end
-
def blank_volume_price attributes
attributes['starting_quantity'].blank? && attributes['price'].blank?
end
@@ -0,0 +1,17 @@
+Dear Customer,
+
+Your order has been CANCELED. Please retain this cancellation information for your records.
+
+============================================================
+Order Summary [CANCELED]
+============================================================
+<% for item in @order.line_items %>
+<%=item.variant.sku %> <%=item.variant.product.name%> <%= variant_options(item.variant) %> (<%=item.quantity%>) @ <%= number_to_currency item.price %> = <%= number_to_currency(item.price * item.quantity) %>
+<% end %>
+============================================================
+Volume Discount: <%= number_to_currency @order.volume_discount %>
+Subtotal: <%= number_to_currency @order.item_total %>
+<% @order.adjustments.each do |adjustment| %>
+<%= "#{adjustment.label}: #{number_to_currency adjustment.amount}"%>
+<% end %>
+Order Total: <%= number_to_currency @order.total %>
@@ -0,0 +1,20 @@
+Dear Customer,
+
+Please review and retain the following order information for your records.
+
+============================================================
+Order Summary
+============================================================
+<% for item in @order.line_items %>
+<%=item.variant.sku %> <%=item.variant.product.name%> <%= variant_options(item.variant) %> (<%=item.quantity%>) @ <%= number_to_currency item.price %> = <%= number_to_currency(item.price * item.quantity) %>
+<% end %>
+============================================================
+Volume Discount: <%= number_to_currency @order.volume_discount %>
+Subtotal: <%= number_to_currency @order.item_total %>
+<% @order.adjustments.each do |adjustment| %>
+<%= "#{adjustment.label}: #{number_to_currency adjustment.amount}"%>
+<% end %>
+Order Total: <%= number_to_currency @order.total %>
+
+
+Thank you for your business.
@@ -0,0 +1,18 @@
+<% if @order.volume_discount != 0.0 %>
+ <style>
+ #cart-volume-discount {
+ float: right;
+ width: 30%;
+ text-align: left;
+ }
+ div#subtotal {
+ clear: both;
+ width: 30%;
+ }
+ </style>
+ <div id="cart-volume-discount">
+ <h3>
+ <%= t 'volume_discount' %>: <%= format_price @order.volume_discount %>
+ </h3>
+ </div>
+<% end %>
@@ -0,0 +1,8 @@
+<% if @order.volume_discount != 0.0 %>
+ <tbody id='volume-discount'>
+ <tr class="total" id="volume-discount-row">
+ <td colspan="3"><b><%= t('volume_discount') %>:</b></td>
+ <td class="total"><span><%= number_to_currency @order.volume_discount %></span></td>
+ </tr>
+ </tbody>
+<% end %>
@@ -1,5 +1,6 @@
en:
volume_pricing: Volume Pricing
volume_prices: Volume Prices
+ volume_discount: Volume Discount
starting_from: Starting from
add_volume_price: Add Volume Price
@@ -0,0 +1,10 @@
+class AddVolumeDiscountToLineItems < ActiveRecord::Migration
+ def self.up
+ add_column :line_items, :volume_discount, :decimal,
+ :precision => 8, :scale => 2, :null => false, :default => 0
+ end
+
+ def self.down
+ remove_column :line_items, :volume_discount
+ end
+end
@@ -2,4 +2,6 @@ class VolumePricingHooks < Spree::ThemeSupport::HookListener
insert_after :admin_product_tabs, :partial => "admin/shared/vp_product_tab"
insert_after :admin_variant_edit_form, :partial => "admin/variants/volume_prices"
replace :product_price, :partial => "products/volume_prices"
+ insert_after :cart_items, :partial => "orders/cart_volume_discount"
+ insert_before :order_details_subtotal, :partial => "shared/order_details_volume_discount"
end
@@ -3,7 +3,7 @@
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'spree_simple_volume_pricing'
- s.version = '1.0.0'
+ s.version = '2.0.0'
s.summary = 'Adds volume pricing capabilities to Spree'
s.author = 'Adam Wróbel'

0 comments on commit 21caba7

Please sign in to comment.