spree_additional_calculators 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.
- data/.gitignore +12 -0
- data/LICENSE +23 -0
- data/README.md +61 -0
- data/Rakefile +81 -0
- data/Versionfile +1 -0
- data/app/controllers/admin/additional_calculator_rates_controller.rb +39 -0
- data/app/helpers/admin/additional_calculators_helper.rb +20 -0
- data/app/models/additional_calculator/base.rb +56 -0
- data/app/models/additional_calculator/weight_and_quantity.rb +59 -0
- data/app/models/additional_calculator_rate.rb +37 -0
- data/app/views/admin/additional_calculator_rates/_additional_calculator_rate_fields.html.erb +10 -0
- data/app/views/admin/additional_calculator_rates/edit.html.erb +37 -0
- data/app/views/admin/additional_calculator_rates/index.html.erb +23 -0
- data/app/views/shared/_additional_calculators_admin_head.html.erb +3 -0
- data/app/views/shared/_error_messages.html.erb +11 -0
- data/config/locales/en.yml +19 -0
- data/config/locales/lv.yml +19 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20110430062411_create_additional_calculator_rates.rb +35 -0
- data/lib/spree_additional_calculators.rb +28 -0
- data/lib/spree_additional_calculators_hooks.rb +12 -0
- data/lib/tasks/install.rake +25 -0
- data/lib/tasks/spree_additional_calculators.rake +1 -0
- data/public/javascripts/additional_calculators.js +10 -0
- data/spec/app/models/additional_calculator_rate_spec.rb +7 -0
- data/spec/spec_helper.rb +30 -0
- data/spree_additional_calculators.gemspec +19 -0
- data/test_app.sh +1 -0
- metadata +92 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Redistribution and use in source and binary forms, with or without modification,
|
2
|
+
are permitted provided that the following conditions are met:
|
3
|
+
|
4
|
+
* Redistributions of source code must retain the above copyright notice,
|
5
|
+
this list of conditions and the following disclaimer.
|
6
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
7
|
+
this list of conditions and the following disclaimer in the documentation
|
8
|
+
and/or other materials provided with the distribution.
|
9
|
+
* Neither the name of the Rails Dog LLC nor the names of its
|
10
|
+
contributors may be used to endorse or promote products derived from this
|
11
|
+
software without specific prior written permission.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
14
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
15
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
16
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
17
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
18
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
19
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
20
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
21
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
22
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
23
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
Additional Spree Calculators
|
2
|
+
============================
|
3
|
+
|
4
|
+
This gem contains additional calculators for [Spree Commerce](http://spreecommerce.com)
|
5
|
+
|
6
|
+
Currently there is only a single calculator implemented but the infrastructure allows to easily add more.
|
7
|
+
|
8
|
+
* "Weight And Quantity" calculator determines the shipping and handling cost based on total
|
9
|
+
item weigh and number or items in the order.
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
Usage
|
14
|
+
----
|
15
|
+
|
16
|
+
Add the following line to your Rails 3 application:
|
17
|
+
|
18
|
+
gem 'spree_additional_calculators'
|
19
|
+
|
20
|
+
And then run:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
$ rake spree_additional_calculators:install
|
24
|
+
|
25
|
+
Then go to [Configuration](http://localhost:3000/admin/configurations) and choose [Shipping Methods](http://localhost:3000/admin/shipping_methods)
|
26
|
+
And you will be able to select a new calculator - **Weight and Quantity**
|
27
|
+
Create the calculator and define the **Default item weight**.
|
28
|
+
That value will be used if you do not have defined the weight for your products.
|
29
|
+
|
30
|
+
After that you can go to [Configuration](http://localhost:3000/admin/configurations) and choose
|
31
|
+
[Additional Calculator Rates](http://localhost:3000/admin/additional_calculator_rates)
|
32
|
+
Click **Edit** and you will be able to add new or edit/remove existing weight and quantity ranges.
|
33
|
+
|
34
|
+
*This page is using Javascript to add and remove items in the browser. The changes are made only when you press the* **Update** *button.*
|
35
|
+
|
36
|
+
Development
|
37
|
+
-----------
|
38
|
+
|
39
|
+
In order to add a new calculator or fix a bug in existing one you will need both the spree source
|
40
|
+
and the extension source locally on your computer.
|
41
|
+
|
42
|
+
$ git clone https://jurgis@github.com/jurgis/spree-additional-calculators.git spree_additional_calculators
|
43
|
+
$ git clone https://github.com/spree/spree.git
|
44
|
+
|
45
|
+
You can test the extension by executing following commands:
|
46
|
+
|
47
|
+
$ cd spree_additional_calculators
|
48
|
+
$ rake test_app SPREE_PATH='../spree'
|
49
|
+
$ rake
|
50
|
+
|
51
|
+
|
52
|
+
TODO
|
53
|
+
----
|
54
|
+
|
55
|
+
* Add RSpec tests
|
56
|
+
* Possibly add some cucumber scenarios
|
57
|
+
* Possibly use unobtrusive javascript
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
Copyright (c) 2011 Jurgis Jurksta, released under the New BSD License
|
data/Rakefile
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
gemfile = File.expand_path('../spec/test_app/Gemfile', __FILE__)
|
8
|
+
if File.exists?(gemfile) && (%w(spec cucumber).include?(ARGV.first.to_s) || ARGV.size == 0)
|
9
|
+
require 'bundler'
|
10
|
+
ENV['BUNDLE_GEMFILE'] = gemfile
|
11
|
+
Bundler.setup
|
12
|
+
|
13
|
+
require 'rspec'
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new
|
16
|
+
|
17
|
+
require 'cucumber/rake/task'
|
18
|
+
Cucumber::Rake::Task.new do |t|
|
19
|
+
t.cucumber_opts = %w{--format progress}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
desc "Default Task"
|
25
|
+
task :default => [ :spec ]
|
26
|
+
# task :default => [:spec, :cucumber ]
|
27
|
+
|
28
|
+
spec = eval(File.read('spree_additional_calculators.gemspec'))
|
29
|
+
|
30
|
+
Rake::GemPackageTask.new(spec) do |p|
|
31
|
+
p.gem_spec = spec
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
desc "Release to gemcutter"
|
36
|
+
task :release => :package do
|
37
|
+
require 'rake/gemcutter'
|
38
|
+
Rake::Gemcutter::Tasks.new(spec).define
|
39
|
+
Rake::Task['gem:push'].invoke
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
desc "Regenerates a rails 3 app for testing"
|
44
|
+
task :test_app do
|
45
|
+
SPREE_PATH = ENV['SPREE_PATH']
|
46
|
+
raise "SPREE_PATH should be specified" unless SPREE_PATH
|
47
|
+
require File.join(SPREE_PATH, 'lib/generators/spree/test_app_generator')
|
48
|
+
class SpreeAdditionalCalculatorTestAppGenerator < Spree::Generators::TestAppGenerator
|
49
|
+
|
50
|
+
def tweak_gemfile
|
51
|
+
append_file 'Gemfile' do
|
52
|
+
<<-gems
|
53
|
+
gem 'spree_core', :path => '#{File.join(SPREE_PATH, 'core')}'
|
54
|
+
gem 'spree_auth', :path => '#{File.join(SPREE_PATH, 'auth')}'
|
55
|
+
gem 'spree_additional_calculators', :path => '#{File.dirname(__FILE__)}'
|
56
|
+
gems
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def install_gems
|
61
|
+
inside "test_app" do
|
62
|
+
run 'rake spree_core:install'
|
63
|
+
run 'rake spree_auth:install'
|
64
|
+
run 'rake spree_additional_calculators:install'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def migrate_db
|
69
|
+
run_migrations
|
70
|
+
end
|
71
|
+
end
|
72
|
+
SpreeAdditionalCalculatorTestAppGenerator.start
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
namespace :test_app do
|
77
|
+
desc 'Rebuild test and cucumber databases'
|
78
|
+
task :rebuild_dbs do
|
79
|
+
system("cd spec/test_app && rake db:drop db:migrate RAILS_ENV=test && rake db:drop db:migrate RAILS_ENV=cucumber")
|
80
|
+
end
|
81
|
+
end
|
data/Versionfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
"0.50.x" => { :branch => "master" }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Admin::AdditionalCalculatorRatesController < Admin::BaseController
|
2
|
+
# resource_controller - not using because too much customization required
|
3
|
+
layout 'admin'
|
4
|
+
helper Admin::AdditionalCalculatorsHelper
|
5
|
+
|
6
|
+
before_filter :load_calculator, :only => [:edit, :update]
|
7
|
+
|
8
|
+
def index
|
9
|
+
@calculators = Calculator.where(:is_additional_calculator => true).order('created_at DESC')
|
10
|
+
end
|
11
|
+
|
12
|
+
def edit
|
13
|
+
@rates_by_type = get_rates_by_type(@calculator)
|
14
|
+
end
|
15
|
+
|
16
|
+
def update
|
17
|
+
if @calculator.update_attributes(params[:additional_calculator_weight_and_quantity]) # TODO: this must be changed!!!
|
18
|
+
flash[:notice] = t('resource_controller.successfully_updated')
|
19
|
+
redirect_to edit_admin_additional_calculator_rate_url(@calculator)
|
20
|
+
else
|
21
|
+
@rates_by_type = get_rates_by_type(@calculator, false) # set @rates_by_type before rendering the view
|
22
|
+
render :action => 'edit'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def load_calculator
|
29
|
+
@calculator = Calculator.find(params[:id])
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_rates_by_type(calculator, load_from_db = true)
|
33
|
+
rates_by_type = {}
|
34
|
+
calculator.supported_types.each { |type| rates_by_type[type] = [] }
|
35
|
+
rates = load_from_db ? calculator.sorted_rates : calculator.additional_calculator_rates
|
36
|
+
rates.each { |rate| rates_by_type[rate.rate_type] << rate }
|
37
|
+
rates_by_type
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Admin::AdditionalCalculatorsHelper
|
2
|
+
|
3
|
+
# Removes the rate fields
|
4
|
+
def link_to_remove_additional_calculator_rate_fields(name, f)
|
5
|
+
f.hidden_field(:_destroy) + link_to_function(name, 'remove_additional_calculator_rate_fields(this)')
|
6
|
+
end
|
7
|
+
|
8
|
+
# Adds the rate fields
|
9
|
+
def link_to_add_additional_calculator_rate_fields(name, f, association, attributes ={})
|
10
|
+
new_object = f.object.class.reflect_on_association(association).klass.new
|
11
|
+
new_object.attributes = attributes
|
12
|
+
|
13
|
+
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
|
14
|
+
render(association.to_s.singularize + "_fields", :f => builder)
|
15
|
+
end
|
16
|
+
|
17
|
+
link_to_function(name, %Q[add_additional_calculator_rate_fields(this, "#{association}", "#{escape_javascript(fields)}")])
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class AdditionalCalculator::Base < Calculator
|
2
|
+
has_many :additional_calculator_rates,
|
3
|
+
:as => :calculator,
|
4
|
+
:dependent => :destroy
|
5
|
+
|
6
|
+
accepts_nested_attributes_for :additional_calculator_rates,
|
7
|
+
:allow_destroy => true,
|
8
|
+
:reject_if => lambda {|attr| attr[:from_value].blank? && attr[:to_value].blank? && attr[:rate].blank?}
|
9
|
+
|
10
|
+
before_save :set_is_additional_calculator
|
11
|
+
|
12
|
+
# Register the calculator
|
13
|
+
def self.register
|
14
|
+
super
|
15
|
+
ShippingMethod.register_calculator(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return calculator name
|
19
|
+
def name
|
20
|
+
calculable.respond_to?(:name) ? calculable.name : calculable.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
# supported types for the specified calculator (weight, qnty, ...)
|
24
|
+
# all the types are supported by default
|
25
|
+
def supported_types
|
26
|
+
AdditionalCalculatorRate.all_types
|
27
|
+
end
|
28
|
+
|
29
|
+
def sorted_rates
|
30
|
+
additional_calculator_rates.order("rate_type ASC, from_value ASC")
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
# Get the rate from the database or nil if could not find the rate for the specified rate type
|
36
|
+
def get_rate(value, rate_type)
|
37
|
+
AdditionalCalculatorRate.find_rate(self.id, rate_type, value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the previous rate if rate for the specified value does not exist, return nil if no previous rate can be find
|
41
|
+
def get_previous_rate(value, rate_type)
|
42
|
+
AdditionalCalculatorRate.find_previous_rate(self.id, rate_type, value)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Before saving the record set that this is the additional calculator
|
46
|
+
def set_is_additional_calculator
|
47
|
+
self.is_additional_calculator = true
|
48
|
+
end
|
49
|
+
|
50
|
+
# get the line items
|
51
|
+
def object_to_line_items(object)
|
52
|
+
return object.line_items if object.is_a?(Order)
|
53
|
+
return object.send(:order).line_items if object.respond_to?(:order)
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class AdditionalCalculator::WeightAndQuantity < AdditionalCalculator::Base
|
2
|
+
# if weight is not defined for an item, use this instead
|
3
|
+
preference :default_item_weight, :decimal, :default => 0
|
4
|
+
|
5
|
+
# The description of the calculator
|
6
|
+
def self.description
|
7
|
+
I18n.t('calculator_names.weight_and_quantity')
|
8
|
+
end
|
9
|
+
|
10
|
+
# object can be [Order, Shipment] and maybe something else ...
|
11
|
+
def compute(object)
|
12
|
+
line_items = object_to_line_items(object)
|
13
|
+
return nil if line_items.nil?
|
14
|
+
|
15
|
+
total_qnty = get_total_qnty(line_items)
|
16
|
+
weight_rate = get_rate(get_total_weight(line_items), AdditionalCalculatorRate::WEIGHT)
|
17
|
+
|
18
|
+
# NOTE: Maybe that has been fixed in the spree 0.50.x
|
19
|
+
# # sometimes the compute method is called without checking if the calculator is available
|
20
|
+
# if weight_rate.nil?
|
21
|
+
# logger.warn("The calculator's #{name} weight_rate is nil - returning. Availability is not checked!")
|
22
|
+
# return nil
|
23
|
+
# end
|
24
|
+
|
25
|
+
# quantity rate might be nil if the specified range is not available
|
26
|
+
qnty_rate = get_rate(total_qnty, AdditionalCalculatorRate::QNTY)
|
27
|
+
# find the previous qnty rate or set it to 0 if not found
|
28
|
+
qnty_rate = get_previous_rate(total_qnty, AdditionalCalculatorRate::QNTY) || 0 if qnty_rate.nil?
|
29
|
+
|
30
|
+
# the total rate is sum of weight and quantity rates
|
31
|
+
weight_rate + qnty_rate
|
32
|
+
end
|
33
|
+
|
34
|
+
# check if this calculator is available for the Order
|
35
|
+
def available?(object)
|
36
|
+
line_items = object_to_line_items(object)
|
37
|
+
return false if line_items.nil?
|
38
|
+
|
39
|
+
weight_rate = get_rate(get_total_weight(line_items), AdditionalCalculatorRate::WEIGHT)
|
40
|
+
!weight_rate.nil? # available only if the weight rate is not nil
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# get total weight of the order
|
46
|
+
def get_total_weight(line_items)
|
47
|
+
line_items.map do |li|
|
48
|
+
# use default item weight if the weight is not defined for a product
|
49
|
+
item_weight = li.variant.weight.nil? ? self.preferred_default_item_weight : li.variant.weight
|
50
|
+
item_weight * li.quantity
|
51
|
+
end.sum
|
52
|
+
end
|
53
|
+
|
54
|
+
# get total item quantity of the order
|
55
|
+
def get_total_qnty(line_items)
|
56
|
+
line_items.map(&:quantity).sum
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class AdditionalCalculatorRate < ActiveRecord::Base
|
2
|
+
|
3
|
+
# Types (0 is the default value for the column, therefore I'm not using it)
|
4
|
+
WEIGHT = 1 # Total item weight
|
5
|
+
QNTY = 2 # Total item quantity
|
6
|
+
|
7
|
+
belongs_to :calculator
|
8
|
+
|
9
|
+
scope :for_type, lambda {|type| where(:rate_type => type) }
|
10
|
+
scope :for_calculator, lambda {|calculator_id| where(:calculator_id => calculator_id) }
|
11
|
+
scope :for_value, lambda {|value| where("from_value <= ? AND ? <= to_value", value, value)}
|
12
|
+
|
13
|
+
validates :calculator_id, :rate_type, :from_value, :to_value, :rate, :presence => true
|
14
|
+
validates :from_value, :to_value, :rate, :numericality => true, :allow_blank => true
|
15
|
+
|
16
|
+
def validate
|
17
|
+
errors.add(:base, I18n.t('errors.from_value_greater_than_to_value')) if from_value > to_value
|
18
|
+
end
|
19
|
+
|
20
|
+
# All complex calculator rate types
|
21
|
+
def self.all_types
|
22
|
+
[WEIGHT, QNTY]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Find the rate for the specified value
|
26
|
+
def self.find_rate(calculator_id, rate_type, value)
|
27
|
+
# get the lowes rate if multiple rates are defined (overlaps)
|
28
|
+
rate = for_calculator(calculator_id).for_type(rate_type).for_value(value).order("rate").first()
|
29
|
+
rate.nil? ? nil : rate.rate
|
30
|
+
end
|
31
|
+
|
32
|
+
# Find the previous rate for the specified value
|
33
|
+
def self.find_previous_rate(calculator_id, rate_type, value)
|
34
|
+
rate = for_calculator(calculator_id).for_type(rate_type).where("to_value <= ?", value).order("rate DESC").first()
|
35
|
+
rate.nil? ? nil : rate.rate
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<tr class="additional_calculator_rate_fields">
|
2
|
+
<td width="100px"> </td>
|
3
|
+
<td><%= f.text_field :from_value, :size => 10 %></td>
|
4
|
+
<td><%= f.text_field :to_value, :size => 10 %></td>
|
5
|
+
<td>
|
6
|
+
<%= f.text_field :rate, :size => 10 %>
|
7
|
+
<%= link_to_remove_additional_calculator_rate_fields(t('remove'), f) %>
|
8
|
+
<%= f.hidden_field :rate_type %>
|
9
|
+
</td>
|
10
|
+
</tr>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<%= render "shared/error_messages", :target => @calculator %>
|
2
|
+
<h1><%= t("additional_calculator_rates") %></h1>
|
3
|
+
<h2><%=h "#{@calculator.name} (#{@calculator.description})" %></h2>
|
4
|
+
|
5
|
+
<%= form_for(@calculator, :url => admin_additional_calculator_rate_path, :html => { :method => :put}) do |f| %>
|
6
|
+
|
7
|
+
<table class="edit">
|
8
|
+
<% @calculator.supported_types.each do |rate_type| %>
|
9
|
+
<thead>
|
10
|
+
<tr>
|
11
|
+
<th><%= t("rate_type_#{rate_type}") %>:</th>
|
12
|
+
<th><%= t("from") %></th>
|
13
|
+
<th><%= t("to") %></th>
|
14
|
+
<th><%= t("value") %></th>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
|
18
|
+
<tbody>
|
19
|
+
<%= f.fields_for :additional_calculator_rates, @rates_by_type[rate_type] do |rate_fields| %>
|
20
|
+
<%= render 'additional_calculator_rate_fields', :f => rate_fields %>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<tr>
|
24
|
+
<td colspan="4">
|
25
|
+
<%= link_to_add_additional_calculator_rate_fields(t('add_new'), f, :additional_calculator_rates,
|
26
|
+
{ :rate_type => rate_type, :from_value => nil, :to_value => nil, :rate => nil }) %>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
</tbody>
|
30
|
+
<% end %>
|
31
|
+
</table>
|
32
|
+
|
33
|
+
<p class="form-buttons">
|
34
|
+
<%= button t('update') %>
|
35
|
+
<%= t("or") %> <%= link_to t("cancel"), admin_additional_calculator_rates_path %>
|
36
|
+
</p>
|
37
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h1><%= t("additional_calculators") %></h1>
|
2
|
+
|
3
|
+
<table class="index">
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th><%= t("shipping_method")%></th>
|
7
|
+
<th><%= t("calculator")%></th>
|
8
|
+
<th><%= t("action")%></th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% @calculators.each do |calculator| %>
|
13
|
+
<tr>
|
14
|
+
<td><%= calculator.name %></td>
|
15
|
+
<td><%= calculator.description %></td>
|
16
|
+
<td><%= link_to_with_icon('edit', t("edit"), edit_admin_additional_calculator_rate_path(calculator)) %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
<% if @calculators.empty? %>
|
20
|
+
<tr><td colspan="5"><%= t(:none) %></td></tr>
|
21
|
+
<% end %>
|
22
|
+
</tbody>
|
23
|
+
</table>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if target && target.errors.any? %>
|
2
|
+
<div id="errorExplanation" class="errorExplanation">
|
3
|
+
<h2><%= t(:errors_prohibited_this_record_from_being_saved, :count => target.errors.count) %>:</h2>
|
4
|
+
<p><%= t(:there_were_problems_with_the_following_fields) %>:</p>
|
5
|
+
<ul>
|
6
|
+
<% target.errors.full_messages.each do |msg| %>
|
7
|
+
<li><%= msg %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
calculator_names:
|
4
|
+
weight_and_quantity: Weight and Quantity
|
5
|
+
|
6
|
+
errors:
|
7
|
+
from_value_greater_than_to_value: "'From' value is greater than 'To' value"
|
8
|
+
|
9
|
+
additional_calculator_rates: Additional Calculator Rates
|
10
|
+
additional_calculator_rates_description: Configure rates for additional calculators
|
11
|
+
additional_calculators: Additional Calculators
|
12
|
+
weight: Weight
|
13
|
+
quantity: Quantity
|
14
|
+
add_new: Add New
|
15
|
+
rate_type_1: Weight
|
16
|
+
rate_type_2: Quantity
|
17
|
+
from: From
|
18
|
+
to: To
|
19
|
+
default_item_weight: Default item weight
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
lv:
|
3
|
+
calculator_names:
|
4
|
+
weight_and_quantity: "Svars un skaits"
|
5
|
+
|
6
|
+
errors:
|
7
|
+
from_value_greater_than_to_value: "'No' vērtība ir lielāka par 'Līdz' vērtību"
|
8
|
+
|
9
|
+
additional_calculator_rates: "Papildus kalkulatoru aprēķinu tabula"
|
10
|
+
additional_calculator_rates_description: "Aizpildiet papildus kalkulatoru aprēķinu tabulas"
|
11
|
+
additional_calculators: "Papildus kalkulatori"
|
12
|
+
weight: "Svars"
|
13
|
+
quantity: "Skaits"
|
14
|
+
add_new: "Pievienot jaunu ierakstu"
|
15
|
+
rate_type_1: "Svars"
|
16
|
+
rate_type_2: "Skaits"
|
17
|
+
from: "No"
|
18
|
+
to: "Līdz"
|
19
|
+
default_item_weight: "Noklusētais preces svars"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
class CreateAdditionalCalculatorRates < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :additional_calculator_rates do |t|
|
4
|
+
t.integer :calculator_id, :null => false
|
5
|
+
t.string :calculator_type, :null => false, :limit => 50
|
6
|
+
t.integer :rate_type, :null => false, :default => 0
|
7
|
+
t.decimal :from_value, :null => false, :precision => 8, :scale => 3, :default => 0.0
|
8
|
+
t.decimal :to_value, :null => false, :precision => 8, :scale => 3, :default => 0.0
|
9
|
+
t.decimal :rate, :null => false, :precision => 8, :scale => 2, :default => 0.0
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index(:additional_calculator_rates, :calculator_id)
|
15
|
+
add_index(:additional_calculator_rates, :calculator_type)
|
16
|
+
add_index(:additional_calculator_rates, :rate_type)
|
17
|
+
add_index(:additional_calculator_rates, :from_value)
|
18
|
+
add_index(:additional_calculator_rates, :to_value)
|
19
|
+
|
20
|
+
add_column(:calculators, :is_additional_calculator, :boolean, :default => false)
|
21
|
+
add_index(:calculators, :is_additional_calculator)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
remove_index(:additional_calculator_rates, :calculator_id)
|
26
|
+
remove_index(:additional_calculator_rates, :calculator_type)
|
27
|
+
remove_index(:additional_calculator_rates, :rate_type)
|
28
|
+
remove_index(:additional_calculator_rates, :from_value)
|
29
|
+
remove_index(:additional_calculator_rates, :to_value)
|
30
|
+
drop_table(:additional_calculator_rates)
|
31
|
+
|
32
|
+
remove_index(:calculators, :is_additional_calculator)
|
33
|
+
remove_column(:calculators, :is_additional_calculator)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spree_core'
|
2
|
+
require 'spree_additional_calculators_hooks'
|
3
|
+
|
4
|
+
module SpreeAdditionalCalculators
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
|
7
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
8
|
+
|
9
|
+
def self.activate
|
10
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
|
11
|
+
Rails.env.production? ? require(c) : load(c)
|
12
|
+
end
|
13
|
+
|
14
|
+
#register all calculators
|
15
|
+
[
|
16
|
+
AdditionalCalculator::WeightAndQuantity
|
17
|
+
].each do |c_model|
|
18
|
+
begin
|
19
|
+
c_model.register if c_model.table_exists?
|
20
|
+
rescue Exception => e
|
21
|
+
$stderr.puts "Error registering calculator #{c_model}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
config.to_prepare &method(:activate).to_proc
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class SpreeAdditionalCalculatorsHooks < Spree::ThemeSupport::HookListener
|
2
|
+
# custom hooks go here
|
3
|
+
|
4
|
+
# Add a link on admin configuration page
|
5
|
+
insert_after :admin_configurations_menu do
|
6
|
+
%(<%= configurations_menu_item(t("additional_calculator_rates"), admin_additional_calculator_rates_path, t("additional_calculator_rates_description")) %>)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Add js file to the head section
|
10
|
+
insert_after :admin_inside_head, 'shared/additional_calculators_admin_head'
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
namespace :spree_additional_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_additional_calculators:install:migrations'].invoke
|
5
|
+
Rake::Task['spree_additional_calculators:install:assets'].invoke
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :install do
|
9
|
+
desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
|
10
|
+
task :migrations do
|
11
|
+
source = File.join(File.dirname(__FILE__), '..', '..', 'db')
|
12
|
+
destination = File.join(Rails.root, 'db')
|
13
|
+
Spree::FileUtilz.mirror_files(source, destination)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
|
17
|
+
task :assets do
|
18
|
+
source = File.join(File.dirname(__FILE__), '..', '..', 'public')
|
19
|
+
destination = File.join(Rails.root, 'public')
|
20
|
+
puts "INFO: Mirroring assets from #{source} to #{destination}"
|
21
|
+
Spree::FileUtilz.mirror_files(source, destination)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# add custom rake tasks here
|
@@ -0,0 +1,10 @@
|
|
1
|
+
function remove_additional_calculator_rate_fields(link) {
|
2
|
+
$(link).prev("input[type=hidden]").val("1");
|
3
|
+
$(link).closest(".additional_calculator_rate_fields").hide();
|
4
|
+
}
|
5
|
+
|
6
|
+
function add_additional_calculator_rate_fields(link, association, content) {
|
7
|
+
var new_id = new Date().getTime();
|
8
|
+
var regexp = new RegExp("new_" + association, "g");
|
9
|
+
$(link).parent().parent().before(content.replace(regexp, new_id));
|
10
|
+
}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
|
2
|
+
# from the project root directory.
|
3
|
+
ENV["RAILS_ENV"] ||= 'test'
|
4
|
+
require File.expand_path("../test_app/config/environment", __FILE__)
|
5
|
+
require 'rspec/rails'
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
# == Mock Framework
|
13
|
+
#
|
14
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
15
|
+
#
|
16
|
+
# config.mock_with :mocha
|
17
|
+
# config.mock_with :flexmock
|
18
|
+
# config.mock_with :rr
|
19
|
+
config.mock_with :rspec
|
20
|
+
|
21
|
+
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
22
|
+
|
23
|
+
#config.include Devise::TestHelpers, :type => :controller
|
24
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
25
|
+
# examples within a transaction, comment the following line or assign false
|
26
|
+
# instead of true.
|
27
|
+
config.use_transactional_fixtures = true
|
28
|
+
end
|
29
|
+
|
30
|
+
@configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.platform = Gem::Platform::RUBY
|
3
|
+
s.name = 'spree_additional_calculators'
|
4
|
+
s.version = '0.1.0'
|
5
|
+
s.summary = 'Additional calculators for spree'
|
6
|
+
s.description = 'Allows to calculate shipping costs based on total item weigh and quantity in the order'
|
7
|
+
s.required_ruby_version = '>= 1.8.7'
|
8
|
+
|
9
|
+
s.author = 'Jurgis Jurksta'
|
10
|
+
s.email = 'jurgis@emails.lv'
|
11
|
+
s.homepage = 'https://github.com/jurgis/spree-additional-calculators'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.require_path = 'lib'
|
16
|
+
s.requirements << 'none'
|
17
|
+
|
18
|
+
s.add_dependency('spree_core', '>= 0.50.2')
|
19
|
+
end
|
data/test_app.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rake test_app SPREE_PATH='~/rails/spree'
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_additional_calculators
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jurgis Jurksta
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-03 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: spree_core
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.50.2
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
description: Allows to calculate shipping costs based on total item weigh and quantity in the order
|
27
|
+
email: jurgis@emails.lv
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
|
+
files:
|
35
|
+
- .gitignore
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- Versionfile
|
40
|
+
- app/controllers/admin/additional_calculator_rates_controller.rb
|
41
|
+
- app/helpers/admin/additional_calculators_helper.rb
|
42
|
+
- app/models/additional_calculator/base.rb
|
43
|
+
- app/models/additional_calculator/weight_and_quantity.rb
|
44
|
+
- app/models/additional_calculator_rate.rb
|
45
|
+
- app/views/admin/additional_calculator_rates/_additional_calculator_rate_fields.html.erb
|
46
|
+
- app/views/admin/additional_calculator_rates/edit.html.erb
|
47
|
+
- app/views/admin/additional_calculator_rates/index.html.erb
|
48
|
+
- app/views/shared/_additional_calculators_admin_head.html.erb
|
49
|
+
- app/views/shared/_error_messages.html.erb
|
50
|
+
- config/locales/en.yml
|
51
|
+
- config/locales/lv.yml
|
52
|
+
- config/routes.rb
|
53
|
+
- db/migrate/20110430062411_create_additional_calculator_rates.rb
|
54
|
+
- lib/spree_additional_calculators.rb
|
55
|
+
- lib/spree_additional_calculators_hooks.rb
|
56
|
+
- lib/tasks/install.rake
|
57
|
+
- lib/tasks/spree_additional_calculators.rake
|
58
|
+
- public/javascripts/additional_calculators.js
|
59
|
+
- spec/app/models/additional_calculator_rate_spec.rb
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
- spree_additional_calculators.gemspec
|
62
|
+
- test_app.sh
|
63
|
+
homepage: https://github.com/jurgis/spree-additional-calculators
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.8.7
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
requirements:
|
84
|
+
- none
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.7.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Additional calculators for spree
|
90
|
+
test_files:
|
91
|
+
- spec/app/models/additional_calculator_rate_spec.rb
|
92
|
+
- spec/spec_helper.rb
|