# jviney/spree-simple-volume-pricing forked from amw/spree-simple-volume-pricing

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.```
1 parent 49190d2 commit 21caba756fad785e08125c3ef6539b2152f7feff amw committed Mar 2, 2011
 @@ -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 %> + +
+

+ <%= t 'volume_discount' %>: <%= format_price @order.volume_discount %> +

+
+<% end %>
 @@ -0,0 +1,8 @@ +<% if @order.volume_discount != 0.0 %> +
<%= t('volume_discount') %>:<%= number_to_currency @order.volume_discount %>
+ + + + + +<% 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'