spree_advanced_calculators 0.0.1

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,38 @@
1
+ class Admin::BucketRatesController < Admin::BaseController
2
+ resource_controller
3
+ before_filter :load_data
4
+ layout 'admin'
5
+
6
+ update.response do |wants|
7
+ wants.html { redirect_to collection_url }
8
+ end
9
+
10
+ create.response do |wants|
11
+ wants.html {
12
+ if params["create_another"]
13
+ rate = params["bucket_rate"].dup
14
+ rate[:floor] = rate.delete(:ceiling)
15
+ redirect_to new_object_url+"?"+({"bucket_rate" => rate}.to_param)
16
+ else
17
+ redirect_to collection_url
18
+ end
19
+ }
20
+ end
21
+
22
+ private
23
+ def collection
24
+ conditions = params[:calculator_id] ? {:calculator_id => params[:calculator_id]} : {}
25
+ @collection ||= end_of_association_chain.all(
26
+ :conditions => conditions,
27
+ :order => 'calculator_id DESC, floor ASC'
28
+ )
29
+ end
30
+
31
+ def load_data
32
+ @available_calculators = Calculator.find(
33
+ :all,
34
+ :conditions => {:advanced => true},
35
+ :order => 'created_at DESC'
36
+ )
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ class BucketRate < ActiveRecord::Base
2
+ belongs_to :calculator
3
+
4
+ validates_presence_of :floor, :ceiling, :rate, :calculator_id
5
+
6
+ scope :order_by_floor, :order => "floor"
7
+ scope :for_calculator, lambda{ |calc|
8
+ if calc.is_a?(Calculator)
9
+ {:conditions => {:calculator_id => calc.id}}
10
+ else
11
+ {:conditions => {:calculator_id => calc.to_i}}
12
+ end
13
+ }
14
+
15
+ def unit
16
+ calculator && calculator.unit
17
+ end
18
+
19
+ def validate
20
+ if !ceiling.blank? && !floor.blank? && ceiling.to_i < floor.to_i
21
+ errors.add(:ceiling, :higher_or_equal)
22
+ end
23
+ end
24
+
25
+ def <=>(other)
26
+ self.floor <=> other.floor
27
+ end
28
+ end
@@ -0,0 +1,50 @@
1
+ class Calculator::Advanced < Calculator
2
+ has_many :bucket_rates, :foreign_key => :calculator_id, :dependent => :destroy
3
+ preference :default_amount, :decimal, :default => 0
4
+
5
+ before_save :set_advanced
6
+
7
+ def self.register
8
+ super
9
+ # Chetan -> to use with promotions remove below comment
10
+ # Coupon.register_calculator(self)
11
+ ShippingMethod.register_calculator(self)
12
+ # Chetan -> I suppose we are not using shipping rates anymore in recent versions of Spree
13
+ # ShippingRate.register_calculator(self)
14
+ end
15
+
16
+ def set_advanced
17
+ self.advanced = true
18
+ end
19
+
20
+ def name
21
+ calculable.respond_to?(:name) ? calculable.name : calculable.to_s
22
+ end
23
+
24
+ def unit
25
+ self.class.unit
26
+ end
27
+
28
+ def get_rate(value)
29
+ # First try to find where price falls within price floor and ceiling
30
+ bucket = BucketRate.find(:first,
31
+ :conditions => [
32
+ "calculator_id = ? and floor <= ? and ceiling > ?",
33
+ self.id, value, value
34
+ ])
35
+
36
+ if bucket
37
+ return(bucket.rate)
38
+ else
39
+ # find largest one
40
+ bucket = BucketRate.find(:last, :conditions => ['calculator_id = ?', self.id], :order => "ceiling ASC")
41
+ # check if we've found largest one, and item_total is higher then ceiling
42
+ if bucket && value > bucket.ceiling
43
+ return(bucket.rate)
44
+ else
45
+ return(false) # if there's no rates, or we've hit a hole, let calculator use default rate.
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,15 @@
1
+ class Calculator::QuantityBucket < Calculator::Advanced
2
+ def self.description
3
+ I18n.t("quantity_bucket", :scope => :calculator_names)
4
+ end
5
+
6
+ def self.unit
7
+ I18n.t(:qty)
8
+ end
9
+
10
+ # as object we always get line items, as calculable we have Coupon, ShippingMethod
11
+ def compute(object)
12
+ total_quantity = object.line_items.map(&:quantity).sum
13
+ get_rate(total_quantity) || self.preferred_default_amount
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ class Calculator::WeightBucket < Calculator::Advanced
2
+ preference :default_weight, :decimal, :default => 0
3
+
4
+ def self.description
5
+ I18n.t("weight_bucket", :scope => :calculator_names)
6
+ end
7
+
8
+ def self.unit
9
+ I18n.t('weight_unit')
10
+ end
11
+
12
+ # as object we always get line items, as calculable we have Coupon, ShippingMethod
13
+ def compute(object)
14
+ total_weight = object.line_items.map{|li|
15
+ (li.variant.weight || self.preferred_default_weight) * li.quantity
16
+ }.sum
17
+
18
+ get_rate(total_weight) || self.preferred_default_amount
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ <table>
2
+ <% if @bucket_rate.calculator_id.blank? %>
3
+ <tr>
4
+ <td><%=t("calculator")%>:</td>
5
+ <td>
6
+ <%= collection_select(
7
+ :bucket_rate,
8
+ :calculator_id, @available_calculators,
9
+ :id, :name, {}, {"style" => "width:200px"}
10
+ ) %>
11
+ </td>
12
+ </tr>
13
+ <% else %>
14
+ <%= f.hidden_field :calculator_id %>
15
+ <% end %>
16
+ <tr>
17
+ <td><%= t("floor", :scope => 'activerecord.attributes.bucket_rate') %>:</td>
18
+ <td>
19
+ <%= f.text_field :floor, {"style" => "width:60px"} %>
20
+ <%= @bucket_rate.unit %>
21
+ </td>
22
+ </tr>
23
+ <tr>
24
+ <td><%= t("ceiling", :scope => 'activerecord.attributes.bucket_rate') %>:</td>
25
+ <td>
26
+ <%= f.text_field :ceiling, {"style" => "width:60px"} %>
27
+ <%= @bucket_rate.unit %>
28
+ </td>
29
+ </tr>
30
+ <tr>
31
+ <td><%= t("rate", :scope => 'activerecord.attributes.bucket_rate') %>:</td>
32
+ <td>
33
+ <%= f.text_field :rate, {"style" => "width:60px"} %>
34
+ <%= t(:'number.currency.format.unit') %>
35
+ </td>
36
+ </tr>
37
+ </table>
@@ -0,0 +1,8 @@
1
+ <h1><%= t("edit_bucket_rate") %></h1>
2
+ <%= error_messages_for :bucket_rate %>
3
+ <% form_for(:bucket_rate, :url => object_url, :html => { :method => :put }) do |f| %>
4
+ <%= render :partial => "form", :locals => { :f => f } %>
5
+ <p>
6
+ <%=submit_tag t("actions.update")%>
7
+ </p>
8
+ <% end %>
@@ -0,0 +1,49 @@
1
+ <div class='toolbar'>
2
+ <ul class='actions'>
3
+ <li>
4
+ <%= button_link_to t("new_bucket_rate"), new_object_url, :icon => 'add' %>
5
+ </li>
6
+ </ul>
7
+ <br class='clear' />
8
+ </div>
9
+
10
+ <h1><%= t("bucket_rate") %></h1>
11
+ <p>
12
+ In order to use the Bucket Rate calculator, you need to create intervals without gaps between them.
13
+ <br />
14
+ When the order total does not fall within an interval, the default rate will be used.
15
+ Order amounts larger than the largest ceiling will use the last interval rate.
16
+ <br />
17
+ NOTE: The FLOOR value is inclusive and the CEILING value is exclusive.
18
+ </p>
19
+
20
+ <table class="index">
21
+ <thead>
22
+ <tr>
23
+ <th><%= t("name")%></th>
24
+ <th><%= t("shipping_calculator")%></th>
25
+ <th><%= t("floor", :scope => 'activerecord.attributes.bucket_rate') %></th>
26
+ <th><%= t("ceiling", :scope => 'activerecord.attributes.bucket_rate')%></th>
27
+ <th><%= t("rate", :scope => 'activerecord.attributes.bucket_rate') %></th>
28
+ <th><%= t("action")%></th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <% @bucket_rates.sort.each do |rate| %>
33
+ <tr>
34
+ <td><%=rate.calculator ? rate.calculator.name: "-" %></td>
35
+ <td><%=rate.calculator ? rate.calculator.class.description: "-" %></td>
36
+ <td><%=rate.floor %> <%= rate.unit %></td>
37
+ <td><%=rate.ceiling %> <%= rate.unit %></td>
38
+ <td><%=number_to_currency(rate.rate) %></td>
39
+ <td>
40
+ <%= link_to_edit rate %> &nbsp;
41
+ <%= link_to_delete rate %>
42
+ </td>
43
+ </tr>
44
+ <% end %>
45
+ <% if @bucket_rates.empty? %>
46
+ <tr><td colspan="5"><%= t(:none) %></td></tr>
47
+ <% end %>
48
+ </tbody>
49
+ </table>
@@ -0,0 +1,11 @@
1
+ <h1><%= t("new_bucket_rate") %></h1>
2
+
3
+ <%= error_messages_for :bucket_rate %>
4
+
5
+ <% form_for(:bucket_rate, :url => collection_url) do |f| %>
6
+ <%= render :partial => "form", :locals => { :f => f } %>
7
+ <p>
8
+ <%= submit_tag t("actions.create") %>
9
+ <%= submit_tag t("actions.create_another"), :name => "create_another" %>
10
+ </p>
11
+ <% end %>
@@ -0,0 +1,39 @@
1
+ <fieldset id="calculator_fields">
2
+ <legend><%= t('calculator') %></legend>
3
+ <div id="preference-settings">
4
+
5
+ <p>
6
+ <%= f.label(:calc_type, t("calculator")) %>
7
+ <%= f.collection_select(:calculator_type, @calculators, :to_s, :description, {}, {:id => "calc-type"}) %>
8
+ </p>
9
+
10
+ <% if !@object.new_record? %>
11
+ <div class="calculator-settings">
12
+ <%= f.fields_for :calculator do |calculator_form| %>
13
+ <%= preference_fields(@object.calculator, calculator_form) %>
14
+ <% end %>
15
+ </div>
16
+ <% if @object.calculator.respond_to?(:preferences) %>
17
+ <div id="calculator-settings-warning"><%= t('calculator_settings_warning')%></div>
18
+ <% end %>
19
+ <% if @object.calculator.advanced? && !@object.calculator.name.blank? %>
20
+ <% if BucketRate.for_calculator(@calculator).count == 0 %>
21
+ <%= t(:configure_new_bucket_rate) %>
22
+ <%= link_to t(:click_here), {
23
+ :controller => 'admin/bucket_rates',
24
+ :action => 'new',
25
+ :bucket_rate => {:calculator_id => @object.calculator.id}
26
+ } %>
27
+ <% else %>
28
+ <%= t(:configure_bucket_rates) %>
29
+ <%= link_to t(:click_here), {
30
+ :controller => 'admin/bucket_rates',
31
+ :action => 'index',
32
+ :calculator_id => @object.calculator.id
33
+ } %>
34
+ <% end %>
35
+ <% end %>
36
+ <% end %>
37
+
38
+ </div>
39
+ </fieldset>
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ namespace :admin do
3
+ resources :bucket_rates
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ require 'spree_core'
2
+ require 'spree_advanced_calculators_hooks'
3
+
4
+ module SpreeAdvancedCalculators
5
+ class Engine < Rails::Engine
6
+ def self.activate
7
+ [
8
+ Calculator::WeightBucket,
9
+ Calculator::QuantityBucket
10
+ ].each(&:register)
11
+ end
12
+ config.to_prepare &method(:activate).to_proc
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ class SpreeAdvancedCalculatorsHooks < Spree::ThemeSupport::HookListener
2
+ insert_after(:admin_configurations_menu) do
3
+ '<tr>
4
+ <td><%= link_to t("bucket_rates"), admin_bucket_rates_url %></td>
5
+ <td><%= t("bucket_rates") %></td>
6
+ </tr>'
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ namespace :spree_advanced_calculators do
2
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
3
+ task :install do
4
+ Rake::Task['spree_advanced_calculators:install:migrations'].invoke
5
+ end
6
+
7
+ namespace :install do
8
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
9
+ task :migrations do
10
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
11
+ destination = File.join(Rails.root, 'db')
12
+ Spree::FileUtilz.mirror_files(source, destination)
13
+ end
14
+ end
15
+
16
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_advanced_calculators
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Chetan Mittal
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-02 00:00:00 +05:30
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: spree_core
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.40.0
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: Allows advanced calculators such as weight etc to be applied on shipping methods
28
+ email: chetan.mittal@niamtech.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - lib/tasks/install.rake
37
+ - lib/spree_advanced_calculators_hooks.rb
38
+ - lib/spree_advanced_calculators.rb
39
+ - app/views/admin/bucket_rates/edit.html.erb
40
+ - app/views/admin/bucket_rates/new.html.erb
41
+ - app/views/admin/bucket_rates/_form.html.erb
42
+ - app/views/admin/bucket_rates/index.html.erb
43
+ - app/views/admin/shared/_calculator_fields.html.erb
44
+ - app/models/bucket_rate.rb
45
+ - app/models/calculator/advanced.rb
46
+ - app/models/calculator/weight_bucket.rb
47
+ - app/models/calculator/quantity_bucket.rb
48
+ - app/controllers/admin/bucket_rates_controller.rb
49
+ - config/routes.rb
50
+ has_rdoc: true
51
+ homepage: http://www.niamtech.com
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.8.7
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ requirements:
72
+ - none
73
+ rubyforge_project: spree_advanced_calculators
74
+ rubygems_version: 1.5.0
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Allows advanced calculators such as weight etc to be applied on shipping methods
78
+ test_files: []
79
+