spree_zone_pricing 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ class ZonePrice < ActiveRecord::Base
2
+ belongs_to :zone
3
+ belongs_to :variant
4
+
5
+ validates_presence_of :price
6
+ validates_numericality_of :price
7
+ validates_presence_of :variant
8
+ validates_presence_of :zone
9
+
10
+ end
@@ -0,0 +1,20 @@
1
+ <table class="index">
2
+ <thead>
3
+ <tr>
4
+ <th><%= t("zone") %></th>
5
+ <th><%= t("price") %></th>
6
+ </tr>
7
+ </thead>
8
+ <tbody id="zone_prices">
9
+ <% for zone in Zone.all %>
10
+ <tr>
11
+ <td>
12
+ <%= zone.name %>
13
+ </td>
14
+ <td>
15
+ <%= text_field_tag "variant[zone_price_attributes][#{zone.id}][price]", zone.zone_prices.find_by_variant_id(@variant.id).try(:price) %>
16
+ </td>
17
+ </tr>
18
+ <% end %>
19
+ </tbody>
20
+ </table>
@@ -0,0 +1,5 @@
1
+ <% if url_options_authenticate?(:controller => 'admin/taxons') %>
2
+ <li <%= ' class="active"' if current == t("zone_pricing") %>>
3
+ <%= link_to(t("zone_pricing"), zone_prices_admin_product_variant_url(@product, @product.master)) %>
4
+ </li>
5
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <%= render :partial => 'admin/shared/product_sub_menu' %>
2
+
3
+ <%= render :partial => 'admin/shared/product_tabs', :locals => {:current => t("zone_pricing")} %>
4
+
5
+ <%= error_messages_for :variant %>
6
+
7
+ <% form_for(:variant, :url => admin_product_variant_url(@product, @variant), :html => { :method => :put }) do |f| %>
8
+
9
+ <h3><%= t("zone_pricing") %></h3>
10
+ <%= render 'admin/shared/zone_prices' %>
11
+ <br/><br/>
12
+
13
+ <%= render :partial => 'admin/shared/edit_resource_links' %>
14
+ <% end %>
15
+
@@ -0,0 +1,7 @@
1
+ <% form_tag :controller => 'countries', :action => 'set' do %>
2
+ <%= label_tag t('country') %>
3
+ <%= select_tag 'id',
4
+ options_for_select(Country.order_by_name.collect{ |c| [c.name, c.id] }, get_user_country_id),
5
+ :onchange => "this.form.submit();" %>
6
+ <%= content_tag(:noscript, submit_tag(t('change'))) %>
7
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <li><%= link_to t("home") , root_path %></li>
2
+ <li class="cart-indicator"><%= link_to_cart %></li>
3
+ <br>
4
+ <li><%= render 'shared/country_select' %></li>
@@ -0,0 +1,5 @@
1
+ ---
2
+ en:
3
+ zone_pricing: "Zone Pricing"
4
+ country_changed: "Country changed"
5
+ country_not_changed: "Country was not changed"
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ map.namespace :admin do |admin|
2
+ admin.resources :products do |product|
3
+ product.resources :variants, :member => {:zone_prices => :get}
4
+ end
5
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Use this file to load your own seed data from extensions.
2
+ # See the db/seeds.rb file in the Spree core for some ideas on what you can do here.
@@ -0,0 +1,30 @@
1
+ module Spree::ZonePricing::Admin::VariantsController
2
+
3
+ def self.included(target)
4
+ target.class_eval do
5
+
6
+ create.before do
7
+ # Set zone product to default if they exist
8
+ object.set_default_zone_prices(get_user_country_id)
9
+ # Make sure to call original code to save
10
+ create_before
11
+ end
12
+
13
+ update.response do |wants|
14
+ wants.html do
15
+ redirect_to object.is_master ? zone_prices_admin_product_variant_url(object.product, object) : collection_url
16
+ end
17
+ end
18
+
19
+ def object
20
+ @object ||= Variant.find(params[:id])
21
+ end
22
+
23
+ def zone_prices
24
+ @variant = object
25
+ @product = @variant.product
26
+ end
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,21 @@
1
+ module Spree::ZonePricing::CheckoutsController
2
+ def self.included(target)
3
+ target.class_eval do
4
+ address.update_hook :update_zone_prices
5
+ end
6
+ end
7
+
8
+ private
9
+
10
+ # Check the ship country and compare against the currently selected country,
11
+ # if different update the order line items with the prices from the ship country
12
+ def update_zone_prices
13
+ # Same country do not update prices
14
+ return if get_user_country_id == object.ship_address.country.id
15
+ # Update the order prices using the ship to country
16
+ @order.update_zone_prices(object.ship_address.country.id)
17
+ # Update selected country with ship to country
18
+ session[:zone_pricing_country] = object.ship_address.country.id
19
+ end
20
+
21
+ end
@@ -0,0 +1,30 @@
1
+ module Spree::ZonePricing::CountriesController
2
+
3
+ def self.included(target)
4
+ target.class_eval do
5
+
6
+ # Change the currently selected country
7
+ def set
8
+ country = Country.find(params[:id])
9
+ if request.referer && request.referer.starts_with?("http://" + request.host)
10
+ session[:return_to] = request.referer
11
+ end
12
+ if country
13
+ # Store country in the session
14
+ session[:zone_pricing_country] = country.id
15
+ # Update prices for the current order
16
+ if session[:order_id]
17
+ order = Order.find(session[:order_id])
18
+ order.update_zone_prices(get_user_country_id)
19
+ end
20
+ flash[:notice] = t("country_changed")
21
+ else
22
+ flash[:error] = t("country_not_changed")
23
+ end
24
+ redirect_back_or_default(root_path)
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,17 @@
1
+ module Spree::ZonePricing::GetCountry
2
+ def self.included(base)
3
+ base.class_eval do
4
+ # This method will retrieve the users country
5
+ def get_user_country_id
6
+ # Check if set in session
7
+ country = session[:zone_pricing_country] if session.has_key?(:zone_pricing_country)
8
+ # If no country in session, check if user has a bill address, if so use
9
+ # the country from the address
10
+ country ||= (current_user && current_user.respond_to?('ship_address') &&
11
+ current_user.ship_address) ? current_user.ship_address.country.id : nil
12
+ # If no bill address country use default country
13
+ country ||= Spree::Config[:default_country_id]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ module Spree::ZonePricing::Order
2
+
3
+ def self.included(target)
4
+ target.class_eval do
5
+ # Override add_variant method so that we can use zone pricing
6
+ alias :spree_add_variant :add_variant unless method_defined?(:spree_add_variant)
7
+ alias :add_variant :site_add_variant
8
+
9
+ # Method to update prices in the current order when country changes
10
+ def update_zone_prices(country_id); order_update_zone_prices(country_id); end
11
+
12
+ # We need to know what the currently selected country is so that we can
13
+ # determine the zone price
14
+ attr_accessor :country_id
15
+ end
16
+ end
17
+
18
+ # Override the add_variant functionality so that we can adjust the price based on
19
+ # the country and therefore zone selected
20
+ def site_add_variant(variant, quantity=1)
21
+ current_item = contains?(variant)
22
+ # Added: Check if country specified, if so check if zone price defined,
23
+ # if no country specified use normal price
24
+ if @country_id
25
+ price = variant.zone_price(@country_id)
26
+ else
27
+ price = variant.price
28
+ end
29
+ if current_item
30
+ current_item.increment_quantity unless quantity > 1
31
+ current_item.quantity = (current_item.quantity + quantity) if quantity > 1
32
+ current_item.price = price # Added
33
+ current_item.save
34
+ else
35
+ current_item = LineItem.new(:quantity => quantity)
36
+ current_item.variant = variant
37
+ current_item.price = price
38
+ self.line_items << current_item
39
+ end
40
+
41
+ # populate line_items attributes for additional_fields entries
42
+ # that have populate => [:line_item]
43
+ Variant.additional_fields.select{|f| !f[:populate].nil? && f[:populate].include?(:line_item) }.each do |field|
44
+ value = ""
45
+
46
+ if field[:only].nil? || field[:only].include?(:variant)
47
+ value = variant.send(field[:name].gsub(" ", "_").downcase)
48
+ elsif field[:only].include?(:product)
49
+ value = variant.product.send(field[:name].gsub(" ", "_").downcase)
50
+ end
51
+ current_item.update_attribute(field[:name].gsub(" ", "_").downcase, value)
52
+ end
53
+
54
+ current_item
55
+ end
56
+
57
+ private
58
+
59
+ # Update price of line items in current order on change
60
+ # of country
61
+ def order_update_zone_prices(country_id)
62
+ self.line_items.each {|li| li.update_attribute(:price, li.variant.zone_price(country_id))}
63
+ update_totals!
64
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ module Spree::ZonePricing::OrdersController
2
+ def self.included(target)
3
+ target.class_eval do
4
+ alias_method :spree_create_before, :create_before unless method_defined?(:spree_create_before)
5
+ alias_method :create_before, :site_create_before
6
+ end
7
+ end
8
+
9
+ # The order object needs to know which country has been selected
10
+ # by the user so that we can calculate the zone prices. This informations
11
+ # may be stored in the session which we do not have access to in the model
12
+ # so this method will get the currently selected country and provide it to
13
+ # the Order model
14
+ def site_create_before
15
+ @order.country_id = get_user_country_id if @order
16
+ spree_create_before
17
+ end
18
+
19
+ end
@@ -0,0 +1,30 @@
1
+ module Spree::ZonePricing::ProductsHelper
2
+ def self.included(base)
3
+ base.class_eval do
4
+ alias_method :spree_product_price, :product_price unless method_defined?(:spree_product_price)
5
+ alias_method :product_price, :site_product_price
6
+ end
7
+ end
8
+
9
+ # returns the price of the product to show for display purposes
10
+ def site_product_price(product_or_variant, options={})
11
+ options.assert_valid_keys(:format_as_currency, :show_vat_text)
12
+ options.reverse_merge! :format_as_currency => true, :show_vat_text => Spree::Config[:show_price_inc_vat]
13
+
14
+ # Check if this object is a product, if so then access the master variant
15
+ # record for the product to get the zone pricing
16
+ object = product_or_variant.is_a?(Product) ? product_or_variant.master : product_or_variant
17
+
18
+ # Get the zone price for this variant/product if one is defined
19
+ # otherwise use the normal price
20
+ if object.respond_to?(:zone_price)
21
+ amount = object.zone_price(get_user_country_id)
22
+ else
23
+ amount = object.price
24
+ end
25
+
26
+ amount += Calculator::Vat.calculate_tax_on(product_or_variant) if Spree::Config[:show_price_inc_vat]
27
+ options.delete(:format_as_currency) ? format_price(amount, options) : ("%0.2f" % amount).to_f
28
+ end
29
+
30
+ end
@@ -0,0 +1,52 @@
1
+ module Spree::ZonePricing::Variant
2
+
3
+ def self.included(target)
4
+ target.class_eval do
5
+ has_many :zone_prices, :dependent => :destroy
6
+ has_many :zones, :through => :zone_prices
7
+
8
+ # Update zone prices for variant from attributes
9
+ # passed to us from the form
10
+ def zone_price_attributes=(price_attributes)
11
+ price_attributes.each do |key, value|
12
+ # Check if record exists, if so update. If value of price
13
+ # is blank or 0 then delete record
14
+ zone_price = ZonePrice.first(:conditions => {:zone_id => key, :variant_id => self.id})
15
+ if zone_price
16
+ # Record exists, update or delete if no price specified
17
+ if value['price'].to_f != 0
18
+ zone_price.update_attribute(:price, value['price'].to_f)
19
+ else
20
+ zone_price.destroy
21
+ end
22
+ elsif value['price'].to_f != 0
23
+ # Record does not exist, create
24
+ ZonePrice.create(:zone_id => key, :variant => self, :price => value['price'].to_f)
25
+ end
26
+ end
27
+ end
28
+
29
+ # Return zone price if defined otherwise return normal price
30
+ def zone_price(country_id)
31
+ # Find zone and check if zone price set for the product/variant
32
+ zone = Country.find(country_id).zone
33
+ zone_price = self.zone_prices.find_by_zone_id(zone.id) if zone && self.respond_to?('zone_prices')
34
+ if zone_price
35
+ # Zone price set us it
36
+ amount = zone_price.price
37
+ else
38
+ amount = self.price
39
+ end
40
+ end
41
+
42
+ # Method to default variant zone prices to the product zone prices
43
+ def set_default_zone_prices(country_id)
44
+ return if self.product.master.zone_prices.size <= 0 # No zone prices specified for product
45
+ # Assign product zone prices as defaults
46
+ self.product.master.zone_prices.each {|zp| self.zone_prices.build(zp.attributes)}
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,10 @@
1
+ module Spree::ZonePricing::Zone
2
+
3
+ def self.included(target)
4
+ target.class_eval do
5
+ has_many :zone_prices, :dependent => :destroy
6
+ has_many :variants, :through => :zone_prices
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,5 @@
1
+ class SpreeZonePrincing
2
+ def self.hi
3
+ puts "Hello world!"
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ namespace :spree do
2
+ namespace :extensions do
3
+ namespace :zone_pricing do
4
+ desc "Copies public assets of the Zone Pricing to the instance public/ directory."
5
+ task :update => :environment do
6
+ is_svn_git_or_dir = proc {|path| path =~ /\.svn/ || path =~ /\.git/ || File.directory?(path) }
7
+ Dir[ZonePricingExtension.root + "/public/**/*"].reject(&is_svn_git_or_dir).each do |file|
8
+ path = file.sub(ZonePricingExtension.root, '')
9
+ directory = File.dirname(path)
10
+ puts "Copying #{path}..."
11
+ mkdir_p RAILS_ROOT + directory
12
+ cp file, RAILS_ROOT + path
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ unless defined? SPREE_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["SPREE_ENV_FILE"]
5
+ require ENV["SPREE_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/SPREE/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{SPREE_ROOT}/spec/spec_helper"
13
+
14
+ if File.directory?(File.dirname(__FILE__) + "/scenarios")
15
+ Scenario.load_paths.unshift File.dirname(__FILE__) + "/scenarios"
16
+ end
17
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
18
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
19
+ end
20
+
21
+ Spec::Runner.configure do |config|
22
+ # config.use_transactional_fixtures = true
23
+ # config.use_instantiated_fixtures = false
24
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
25
+
26
+ # You can declare fixtures for each behaviour like this:
27
+ # describe "...." do
28
+ # fixtures :table_a, :table_b
29
+ #
30
+ # Alternatively, if you prefer to declare them only once, you can
31
+ # do so here, like so ...
32
+ #
33
+ # config.global_fixtures = :table_a, :table_b
34
+ #
35
+ # If you declare global fixtures, be aware that they will be declared
36
+ # for all of your examples, even those that don't use them.
37
+ end
@@ -0,0 +1,44 @@
1
+ # Uncomment this if you reference any of your controllers in activate
2
+ # require_dependency 'application'
3
+
4
+ class ZonePricingExtension < Spree::Extension
5
+ version "1.0"
6
+ description "Allows prices to be set by zone"
7
+ url "http://yourwebsite.com/zone_pricing"
8
+
9
+ # Please use zone_pricing/config/routes.rb instead for extension routes.
10
+
11
+ # def self.require_gems(config)
12
+ # config.gem "gemname-goes-here", :version => '1.2.3'
13
+ # end
14
+
15
+ def activate
16
+
17
+ # Add helper to retrieve the users country
18
+ ApplicationHelper.send(:include, Spree::ZonePricing::GetCountry)
19
+ # Add helper to retrieve the users country, used by a number of controllers
20
+ Spree::BaseController.send(:include, Spree::ZonePricing::GetCountry)
21
+
22
+ # Add additional associations to allow m:m relationship
23
+ # between zones<->variants
24
+ Zone.send(:include, Spree::ZonePricing::Zone)
25
+ Variant.send(:include, Spree::ZonePricing::Variant)
26
+
27
+ # Override add_variant method so that we can use zone pricing
28
+ Order.send(:include, Spree::ZonePricing::Order)
29
+
30
+ # Override price
31
+ ProductsHelper.send(:include, Spree::ZonePricing::ProductsHelper)
32
+
33
+ # Add action to countries controller to handle country selection
34
+ CountriesController.send(:include, Spree::ZonePricing::CountriesController)
35
+ # Add code to set the currently country in the order
36
+ OrdersController.send(:include, Spree::ZonePricing::OrdersController)
37
+ # Add code to save zone prices
38
+ Admin::VariantsController.send(:include, Spree::ZonePricing::Admin::VariantsController)
39
+ # Add code to check zone prices after address is saved during checkout, if ship
40
+ # country not the same change prices in order
41
+ CheckoutsController.send(:include, Spree::ZonePricing::CheckoutsController)
42
+
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ class ZonePricingHooks < Spree::ThemeSupport::HookListener
2
+
3
+ # Add zone pricing tab to products admin area
4
+ insert_after :admin_product_tabs, :partial => "admin/shared/zp_product_tab"
5
+
6
+ # Add zone pricing to variant edit form
7
+ insert_after :admin_variant_edit_form, :partial => 'admin/shared/zone_prices'
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_zone_pricing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Henrique Ferreira
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Set different price zones within Spree (Based in spree-zone-pricing)
15
+ email: henriquebf@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - app/models/zone_price.rb
21
+ - app/views/admin/shared/_zone_prices.html.erb
22
+ - app/views/admin/shared/_zp_product_tab.html.erb
23
+ - app/views/admin/variants/zone_prices.html.erb
24
+ - app/views/shared/_country_select.html.erb
25
+ - app/views/shared/_store_menu.html.erb
26
+ - config/routes.rb
27
+ - config/locales/en_spree.yml
28
+ - db/seeds.rb
29
+ - lib/spree_zone_pricing.rb
30
+ - lib/spree/zone_pricing/checkouts_controller.rb
31
+ - lib/spree/zone_pricing/countries_controller.rb
32
+ - lib/spree/zone_pricing/get_country.rb
33
+ - lib/spree/zone_pricing/order.rb
34
+ - lib/spree/zone_pricing/orders_controller.rb
35
+ - lib/spree/zone_pricing/products_helper.rb
36
+ - lib/spree/zone_pricing/variant.rb
37
+ - lib/spree/zone_pricing/zone.rb
38
+ - lib/spree/zone_pricing/admin/variants_controller.rb
39
+ - lib/tasks/zone_pricing_extension_tasks.rake
40
+ - spec/spec.opts
41
+ - spec/spec_helper.rb
42
+ - zone_pricing_extension.rb
43
+ - zone_pricing_hooks.rb
44
+ homepage: http://rubygems.org/gems/spree_zone_pricing
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.24
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Spree Zone Pricing
68
+ test_files: []