spree_wholesale 0.40.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +23 -0
- data/README.md +49 -0
- data/app/controllers/admin/orders_controller_decorator.rb +40 -0
- data/app/models/line_item_decorator.rb +12 -0
- data/app/models/order_decorator.rb +43 -0
- data/app/models/product_decorator.rb +13 -0
- data/app/models/products_helper_decorator.rb +64 -0
- data/app/models/spree_current_order_decorator.rb +18 -0
- data/app/models/variant_decorator.rb +7 -0
- data/app/views/admin/hooks/_admin_orders_index_headers.html.erb +1 -0
- data/app/views/admin/hooks/_admin_orders_index_rows.html.erb +1 -0
- data/app/views/admin/hooks/_admin_orders_index_search.html.erb +6 -0
- data/app/views/admin/hooks/_product_form_right.html.erb +65 -0
- data/app/views/admin/variants/_form.html.erb +43 -0
- data/app/views/checkout/_summary.html.erb +25 -0
- data/app/views/hooks/_cart_item_price.html.erb +1 -0
- data/app/views/hooks/_cart_item_total.html.erb +1 -0
- data/app/views/hooks/_wholesale_customer_id.html.erb +1 -0
- data/app/views/orders/show.html.erb +21 -0
- data/app/views/shared/_products.html.erb +35 -0
- data/lib/spree_wholesale.rb +25 -0
- data/lib/spree_wholesale_hooks.rb +15 -0
- data/lib/tasks/install.rake +47 -0
- data/lib/tasks/spree_wholesale.rake +35 -0
- data/lib/wholesale_products_helper.rb +26 -0
- metadata +122 -0
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,49 @@
|
|
1
|
+
Spree Wholesale
|
2
|
+
---------------
|
3
|
+
|
4
|
+
|
5
|
+
Currently still under development! Check back soon for more details..
|
6
|
+
|
7
|
+
To setup a fresh Spree store follow this instructions:
|
8
|
+
|
9
|
+
https://github.com/railsdog/spree/#readme
|
10
|
+
|
11
|
+
|
12
|
+
To get spree_wholesale up and running on your spree store:
|
13
|
+
|
14
|
+
cd your/spree/project
|
15
|
+
git clone git://github.com/citrus/spree_wholesale.git
|
16
|
+
echo "gem 'spree_wholesale', :path => './spree_wholesale'" >> Gemfile
|
17
|
+
rake spree_wholesale:install
|
18
|
+
rake db:migrate
|
19
|
+
rake spree_wholesale:create_role
|
20
|
+
|
21
|
+
If you want to generate sample wholesale prices:
|
22
|
+
|
23
|
+
rake spree_wholesale:assume_wholesale_prices
|
24
|
+
|
25
|
+
This will assume 66% wholesale mark off.
|
26
|
+
|
27
|
+
|
28
|
+
If you'd like run tests: (TO DO: Write some more tests)
|
29
|
+
|
30
|
+
cd your/spree/project/spree_wholesale
|
31
|
+
rake
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
License
|
36
|
+
-------
|
37
|
+
|
38
|
+
Copyright (c) 2011 Spencer Steffen, released under the New BSD License
|
39
|
+
All rights reserved.
|
40
|
+
|
41
|
+
>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
42
|
+
|
43
|
+
> Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
44
|
+
|
45
|
+
> Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution.
|
46
|
+
|
47
|
+
> Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
48
|
+
|
49
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Admin::OrdersController.class_eval do
|
2
|
+
|
3
|
+
def collection
|
4
|
+
params[:search] ||= {}
|
5
|
+
|
6
|
+
if params[:search].present?
|
7
|
+
if params[:search].delete(:completed_at_not_null) == "1"
|
8
|
+
params[:search][:completed_at_not_null] = "1"
|
9
|
+
end
|
10
|
+
else
|
11
|
+
params[:search][:completed_at_not_null] = "1"
|
12
|
+
end
|
13
|
+
|
14
|
+
if !params[:search][:completed_at_greater_than].blank?
|
15
|
+
params[:search][:completed_at_greater_than] = Time.zone.parse(params[:search][:completed_at_greater_than]).beginning_of_day rescue ""
|
16
|
+
end
|
17
|
+
|
18
|
+
if !params[:search][:completed_at_less_than].blank?
|
19
|
+
params[:search][:completed_at_less_than] = Time.zone.parse(params[:search][:completed_at_less_than]).end_of_day rescue ""
|
20
|
+
end
|
21
|
+
|
22
|
+
if params[:search][:wholesale].present?
|
23
|
+
if params[:search].delete(:wholesale) == "1"
|
24
|
+
params[:search][:wholesale] = 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
params[:search][:order] ||= "descend_by_completed_at"
|
29
|
+
|
30
|
+
@search = Order.searchlogic(params[:search])
|
31
|
+
|
32
|
+
# QUERY - get per_page from form ever??? maybe push into model
|
33
|
+
# @search.per_page ||= Spree::Config[:orders_per_page]
|
34
|
+
|
35
|
+
@collection = @search.do_search.paginate(:include => [:user, :shipments, :payments],
|
36
|
+
:per_page => Spree::Config[:orders_per_page],
|
37
|
+
:page => params[:page])
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
LineItem.class_eval do
|
2
|
+
|
3
|
+
delegate_belongs_to :variant, :wholesale_price
|
4
|
+
delegate_belongs_to :variant, :is_wholesaleable?
|
5
|
+
|
6
|
+
def copy_price
|
7
|
+
|
8
|
+
self.price = (order.is_wholesale? && variant.is_wholesaleable? ? variant.wholesale_price : variant.price) if variant && self.price.nil?
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Order.class_eval do
|
2
|
+
|
3
|
+
def is_wholesale?
|
4
|
+
wholesale == true
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
def add_variant(variant, quantity = 1)
|
11
|
+
current_item = contains?(variant)
|
12
|
+
if current_item
|
13
|
+
current_item.quantity += quantity
|
14
|
+
current_item.save
|
15
|
+
else
|
16
|
+
current_item = LineItem.new(:quantity => quantity)
|
17
|
+
current_item.variant = variant
|
18
|
+
current_item.price = is_wholesale? ? variant.wholesale_price : variant.price
|
19
|
+
|
20
|
+
|
21
|
+
self.line_items << current_item
|
22
|
+
end
|
23
|
+
|
24
|
+
# populate line_items attributes for additional_fields entries
|
25
|
+
# that have populate => [:line_item]
|
26
|
+
Variant.additional_fields.select{|f| !f[:populate].nil? && f[:populate].include?(:line_item) }.each do |field|
|
27
|
+
value = ""
|
28
|
+
|
29
|
+
if field[:only].nil? || field[:only].include?(:variant)
|
30
|
+
value = variant.send(field[:name].gsub(" ", "_").downcase)
|
31
|
+
elsif field[:only].include?(:product)
|
32
|
+
value = variant.product.send(field[:name].gsub(" ", "_").downcase)
|
33
|
+
end
|
34
|
+
current_item.update_attribute(field[:name].gsub(" ", "_").downcase, value)
|
35
|
+
end
|
36
|
+
|
37
|
+
current_item
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Product.instance_eval do
|
2
|
+
|
3
|
+
delegate_belongs_to :master, :wholesale_price if Variant.table_exists? && Variant.column_names.include?("wholesale_price")
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
Product.class_eval do
|
8
|
+
|
9
|
+
def is_wholesaleable?
|
10
|
+
0 < master.wholesale_price
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
ProductsHelper.module_eval do
|
2
|
+
|
3
|
+
|
4
|
+
def wholesaler_signed_in?
|
5
|
+
current_user && current_user.has_role?("wholesaler")
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
# returns the price of the product to show for display purposes
|
10
|
+
def product_price(product_or_variant, options={})
|
11
|
+
options.assert_valid_keys(:format_as_currency, :show_vat_text, :hide_labels, :quantity)
|
12
|
+
options.reverse_merge! :format_as_currency => true, :show_vat_text => Spree::Config[:show_price_inc_vat]
|
13
|
+
amount = product_or_variant.price
|
14
|
+
amount += Calculator::Vat.calculate_tax_on(product_or_variant) if Spree::Config[:show_price_inc_vat]
|
15
|
+
prices = [amount]
|
16
|
+
if wholesaler_signed_in? && product_or_variant.is_wholesaleable?
|
17
|
+
prices[0] = [prices[0], "msrp"]
|
18
|
+
prices << [product_or_variant.wholesale_price, "wholesale"]
|
19
|
+
end
|
20
|
+
format_as_currency = options.delete(:format_as_currency)
|
21
|
+
hide_labels = options.delete(:hide_labels)
|
22
|
+
quantity = options.delete(:quantity) || 1
|
23
|
+
prices.collect!{|price|
|
24
|
+
if price.is_a? Array
|
25
|
+
content_tag(:span, :class => "price_#{price[1]}") do
|
26
|
+
price[0] *= quantity
|
27
|
+
price[0] = format_price(price[0], options) if format_as_currency
|
28
|
+
price.slice!(1) if hide_labels
|
29
|
+
price.reverse.join(": ")
|
30
|
+
end
|
31
|
+
else
|
32
|
+
price *= quantity
|
33
|
+
format_as_currency ? format_price(price, options) : price
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
price = prices.first
|
38
|
+
if format_as_currency
|
39
|
+
prices.join(" ").html_safe
|
40
|
+
else
|
41
|
+
if price.is_a? Array
|
42
|
+
price = price.first
|
43
|
+
end
|
44
|
+
price.to_f
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
def order_price(order, options={})
|
52
|
+
options.assert_valid_keys(:format_as_currency, :show_vat_text, :show_price_inc_vat)
|
53
|
+
options.reverse_merge! :format_as_currency => true, :show_vat_text => true
|
54
|
+
|
55
|
+
# overwrite show_vat_text if show_price_inc_vat is false
|
56
|
+
options[:show_vat_text] = Spree::Config[:show_price_inc_vat]
|
57
|
+
|
58
|
+
amount = order.item_total
|
59
|
+
amount += Calculator::Vat.calculate_tax(order) if Spree::Config[:show_price_inc_vat]
|
60
|
+
|
61
|
+
options.delete(:format_as_currency) ? number_to_currency(amount) : amount
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Spree::CurrentOrder.module_eval do
|
2
|
+
|
3
|
+
def before_save_new_order
|
4
|
+
|
5
|
+
if current_user
|
6
|
+
@current_order.user = current_user
|
7
|
+
@current_order.wholesale = current_user.has_role?("wholesaler")
|
8
|
+
end
|
9
|
+
|
10
|
+
#puts "before_save_new_order!!!!!"
|
11
|
+
|
12
|
+
#puts current_user
|
13
|
+
|
14
|
+
#puts @current_order.inspect
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<th><%= order @search, :by => :wholesale, :as => t("wholesale") %></th>
|
@@ -0,0 +1 @@
|
|
1
|
+
<td><%= order.is_wholesale? ? 'yes' : 'no' %></td>
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<%= f.field_container :price do %>
|
2
|
+
<%= f.label :price, t("master_price")%> <span class="required">*</span><br />
|
3
|
+
<%= f.text_field :price, :value => number_with_precision(@product.price, :precision => 2) %>
|
4
|
+
<%= f.error_message_on :price %>
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
<%= f.field_container :wholesale_price do %>
|
8
|
+
<%= f.label :wholesale_price, t(".master_wholesale_price")%> <span class="required">*</span><br />
|
9
|
+
<%= f.text_field :wholesale_price, :value => number_with_precision(@product.wholesale_price, :precision => 2) %>
|
10
|
+
<%= f.error_message_on :wholesale_price %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<%= f.field_container :cost_price do %>
|
14
|
+
<%= f.label :cost_price, t("cost_price")%><br />
|
15
|
+
<%= f.text_field :cost_price, :value => number_with_precision(@product.cost_price, :precision => 2) %>
|
16
|
+
<%= f.error_message_on :cost_price %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<p>
|
20
|
+
<%= f.label :available_on, t("available_on") %><br />
|
21
|
+
<%= f.error_message_on :available_on %>
|
22
|
+
<%= f.spree_date_picker :available_on %>
|
23
|
+
</p>
|
24
|
+
|
25
|
+
<p>
|
26
|
+
<%= f.label :sku, t("sku") %><br />
|
27
|
+
<%= f.text_field :sku, :size => 16 %>
|
28
|
+
</p>
|
29
|
+
<% unless @product.has_variants? %>
|
30
|
+
<% if Spree::Config[:track_inventory_levels] %>
|
31
|
+
<p>
|
32
|
+
<%= f.label :on_hand, t("on_hand")%><br />
|
33
|
+
<%= f.text_field :on_hand, :size => 4 %>
|
34
|
+
</p>
|
35
|
+
<% end %>
|
36
|
+
<ul id="shipping-specs">
|
37
|
+
<li>
|
38
|
+
<%= f.label :weight, t("weight")%>
|
39
|
+
<%= f.text_field :weight, :size => 4 %>
|
40
|
+
</li>
|
41
|
+
<li>
|
42
|
+
<%= f.label :height, t("height")%>
|
43
|
+
<%= f.text_field :height, :size => 4 %>
|
44
|
+
</li>
|
45
|
+
<li>
|
46
|
+
<%= f.label :width, t("width")%>
|
47
|
+
<%= f.text_field :width, :size => 4 %>
|
48
|
+
</li>
|
49
|
+
<li>
|
50
|
+
<%= f.label :depth, t("depth")%>
|
51
|
+
<%= f.text_field :depth, :size => 4 %>
|
52
|
+
</li>
|
53
|
+
</ul>
|
54
|
+
<% end %>
|
55
|
+
<p>
|
56
|
+
<%= f.label :shipping_category_id, t("shipping_categories")%><br />
|
57
|
+
<%= f.collection_select(:shipping_category_id, @shipping_categories, :id, :name, {:include_blank => true}, {"style" => "width:200px"}) %>
|
58
|
+
<%= f.error_message_on :shipping_category %>
|
59
|
+
</p>
|
60
|
+
|
61
|
+
<p>
|
62
|
+
<%= f.label :tax_category_id, t("tax_category")%><br />
|
63
|
+
<%= f.collection_select(:tax_category_id, @tax_categories, :id, :name, {:include_blank => true}, {"style" => "width:200px"}) %>
|
64
|
+
<%= f.error_message_on :tax_category%>
|
65
|
+
</p>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<div class="yui-gb">
|
2
|
+
<div class="yui-u first">
|
3
|
+
|
4
|
+
<% @product.options.each do |option| %>
|
5
|
+
<p>
|
6
|
+
<%= label :new_variant, option.option_type.presentation %><br />
|
7
|
+
<% if @variant.new_record? %>
|
8
|
+
<%= select(:new_variant, option.option_type.presentation,
|
9
|
+
option.option_type.option_values.collect {|ov| [ ov.presentation, ov.id ] },
|
10
|
+
{})
|
11
|
+
%>
|
12
|
+
<% else %>
|
13
|
+
<% opt = @variant.option_values.detect {|o| o.option_type == option.option_type }.presentation %>
|
14
|
+
<%= text_field(:new_variant, option.option_type.presentation, :value => opt, :disabled => 'disabled') %>
|
15
|
+
<% end %>
|
16
|
+
</p>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<p><%= f.label :sku, t("sku") %><br />
|
20
|
+
<%= f.text_field :sku %></p>
|
21
|
+
|
22
|
+
<p><%= f.label :price, t("price") %>:<br />
|
23
|
+
<%= f.text_field :price, :value => number_with_precision(@variant.price, :precision => 2) %></p>
|
24
|
+
|
25
|
+
<p><%= f.label :wholesale_price, t(".wholesale_price") %>:<br />
|
26
|
+
<%= f.text_field :wholesale_price, :value => number_with_precision(@variant.wholesale_price, :precision => 2) %></p>
|
27
|
+
|
28
|
+
<p><%= f.label :cost_price, t("cost_price") %>:<br />
|
29
|
+
<%= f.text_field :cost_price, :value => number_with_precision(@variant.cost_price, :precision => 2) %></p>
|
30
|
+
|
31
|
+
<% if Spree::Config[:track_inventory_levels] %>
|
32
|
+
<p><%= f.label :on_hand, t("on_hand") %>: <br />
|
33
|
+
<%= f.text_field :on_hand %></p>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
<div class="yui-u">
|
37
|
+
|
38
|
+
<% Variant.additional_fields.select{|af| af[:only].nil? || af[:only].include?(:variant) }.each do |field| %>
|
39
|
+
<%= render :partial => "admin/shared/additional_field", :locals => {:field => field, :f => f} %>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
</div>
|
43
|
+
</div>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<h3><%= t(:order_summary) %></h3>
|
2
|
+
<% if order.is_wholesale? %>
|
3
|
+
<%= render 'hooks/wholesale_customer_id' %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<table>
|
7
|
+
<tbody>
|
8
|
+
<tr>
|
9
|
+
<td><strong><%= t('item_total') %>:</strong></td>
|
10
|
+
<td><strong><%= number_to_currency order.item_total %></strong></td>
|
11
|
+
</tr>
|
12
|
+
<tbody id="summary-order-charges">
|
13
|
+
<% order.adjustments.each do |adjustment| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= adjustment.label %>: </td>
|
16
|
+
<td><%= number_to_currency adjustment.amount %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</tbody>
|
20
|
+
<tr>
|
21
|
+
<td><strong><%= t('order_total') %>:</strong></td>
|
22
|
+
<td><strong><span id='summary-order-total'><%= number_to_currency @order.total %></span></strong></td>
|
23
|
+
</tr>
|
24
|
+
</tbody>
|
25
|
+
</table>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= format_price(line_item.price) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= format_price(line_item.price * line_item.quantity) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h4 class="wholesale-customer-id"><%= t('wholesale_customer', { :id => (@order || order).user_id }) %></h4>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<div id="order">
|
2
|
+
|
3
|
+
<h1><%= t("order") %> <%= @order.number %></h1>
|
4
|
+
|
5
|
+
<%= render 'hooks/wholesale_customer_id' if @order.is_wholesale? %>
|
6
|
+
|
7
|
+
<%= link_to t('back_to_store'), products_path %>
|
8
|
+
|
9
|
+
<% if params.has_key? :checkout_complete %>
|
10
|
+
<br/><br/>
|
11
|
+
<h3><%= t('thank_you_for_your_order') %></h3>
|
12
|
+
<% else %>
|
13
|
+
| <%= link_to t('my_account'), user_path(current_user) if current_user%>
|
14
|
+
<% end %>
|
15
|
+
<br/><br/>
|
16
|
+
|
17
|
+
<%= render :partial => 'shared/order_details', :locals => {:order => @order} %>
|
18
|
+
|
19
|
+
<br/>
|
20
|
+
<%= link_to t('back_to_store'), products_path %>
|
21
|
+
</div>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%
|
2
|
+
paginated_products = @searcher.products if params.key?(:keywords)
|
3
|
+
paginated_products ||= products
|
4
|
+
%>
|
5
|
+
<% if products.empty? %>
|
6
|
+
<%= t(:no_products_found) %>
|
7
|
+
<% elsif params.key?(:keywords) %>
|
8
|
+
<h3><%= t(:search_results, :keywords => h(params[:keywords])) %></h3>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% if products.any? %>
|
12
|
+
<ul class="product-listing">
|
13
|
+
<% products.each do |product| %>
|
14
|
+
<% if Spree::Config[:show_zero_stock_products] || product.has_stock? %>
|
15
|
+
<li id="product_<%= product.id %>">
|
16
|
+
<%= link_to small_image(product), product %>
|
17
|
+
<%= link_to raw(product.name + " <span class='price selling'>#{product_price(product)}</span>"), product, :class => 'info' %>
|
18
|
+
</li>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
<hr class="space" />
|
25
|
+
|
26
|
+
<% if paginated_products.respond_to?(:total_pages)
|
27
|
+
params.delete(:search)
|
28
|
+
params.delete(:taxon)
|
29
|
+
|
30
|
+
%><%= will_paginate(paginated_products,
|
31
|
+
:previous_label => "« #{t('previous')}",
|
32
|
+
:next_label => "#{t('next')} »") %>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<hr class="space" />
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spree_core'
|
2
|
+
require 'spree_wholesale_hooks'
|
3
|
+
|
4
|
+
module SpreeWholesale
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
|
7
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
8
|
+
|
9
|
+
initializer "static assets" do |app|
|
10
|
+
app.middleware.insert_after ::ActionDispatch::Static, ::ActionDispatch::Static, "#{config.root}/public"
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def self.activate
|
15
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
|
16
|
+
Rails.env.production? ? require(c) : load(c)
|
17
|
+
end
|
18
|
+
|
19
|
+
Spree::Auth::Config.set :registration_step => false
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
config.to_prepare &method(:activate).to_proc
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SpreeWholesaleHooks < Spree::ThemeSupport::HookListener
|
2
|
+
# custom hooks go here
|
3
|
+
|
4
|
+
replace :admin_product_form_right, 'admin/hooks/product_form_right'
|
5
|
+
|
6
|
+
replace :cart_item_price, 'hooks/cart_item_price'
|
7
|
+
replace :cart_item_total, 'hooks/cart_item_total'
|
8
|
+
|
9
|
+
insert_before :inside_cart_form, 'hooks/wholesale_customer_id'
|
10
|
+
|
11
|
+
insert_after :admin_orders_index_headers, 'admin/hooks/admin_orders_index_headers'
|
12
|
+
insert_after :admin_orders_index_rows, 'admin/hooks/admin_orders_index_rows'
|
13
|
+
insert_after :admin_orders_index_search, 'admin/hooks/admin_orders_index_search'
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
namespace :spree_wholesale do
|
2
|
+
|
3
|
+
def load_environment
|
4
|
+
puts "loading environment..."
|
5
|
+
require File.join(Rails.root, 'config', 'environment')
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
|
9
|
+
task :install do
|
10
|
+
Rake::Task['spree_wholesale:install:migrations'].invoke
|
11
|
+
Rake::Task['spree_wholesale:install:assets'].invoke
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :install do
|
15
|
+
desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
|
16
|
+
task :migrations do
|
17
|
+
|
18
|
+
source = File.expand_path('../../../db/migrate', __FILE__)
|
19
|
+
destination = File.join(Rails.root, 'db', 'migrate')
|
20
|
+
migrations = Dir.entries(destination).select{|file| file.match('.rb') }
|
21
|
+
|
22
|
+
files = Dir.entries(source).select{|file| file.match('.rb') }
|
23
|
+
files.each_with_index do |file,index|
|
24
|
+
time = Time.now + (index * 7)
|
25
|
+
number = [time.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % index].max
|
26
|
+
new_file = [number,file].join('_')
|
27
|
+
src = File.join(source, file)
|
28
|
+
dst = File.join(destination, new_file)
|
29
|
+
if 0 < migrations.select{|migration| migration.match(file) != nil }.length
|
30
|
+
puts "#{file} exists!"
|
31
|
+
else
|
32
|
+
FileUtils.cp(src, dst)
|
33
|
+
puts "#{new_file} copied!"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
|
39
|
+
task :assets do
|
40
|
+
source = File.join(File.dirname(__FILE__), '..', '..', 'public')
|
41
|
+
destination = File.join(Rails.root, 'public')
|
42
|
+
puts "INFO: Mirroring assets from #{source} to #{destination}"
|
43
|
+
Spree::FileUtilz.mirror_files(source, destination)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
namespace :spree_wholesale do
|
2
|
+
|
3
|
+
desc "Creates wholesale role"
|
4
|
+
task :create_role do
|
5
|
+
|
6
|
+
load_environment
|
7
|
+
|
8
|
+
name = "wholesaler"
|
9
|
+
role = Role.find_by_name(name) rescue nil
|
10
|
+
if role
|
11
|
+
puts "Role exists!"
|
12
|
+
else
|
13
|
+
role = Role.create(:name => name)
|
14
|
+
puts "Role created!"
|
15
|
+
end
|
16
|
+
puts role.inspect
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
desc "Assumes 66% wholesale discount for each variant"
|
24
|
+
task :assume_wholesale_prices do
|
25
|
+
|
26
|
+
load_environment
|
27
|
+
|
28
|
+
Variant.all.each do |variant|
|
29
|
+
variant.wholesale_price = variant.price * 0.66
|
30
|
+
variant.save
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#module WholesaleProductsHelper
|
2
|
+
#
|
3
|
+
# # returns the price of the product to show for display purposes
|
4
|
+
# def product_price(product_or_variant, options={})
|
5
|
+
# options.assert_valid_keys(:format_as_currency, :show_vat_text)
|
6
|
+
# options.reverse_merge! :format_as_currency => true, :show_vat_text => Spree::Config[:show_price_inc_vat]
|
7
|
+
#
|
8
|
+
# puts "-----"
|
9
|
+
# puts current_user.roles.inspect
|
10
|
+
#
|
11
|
+
# if current_user.has_role?("wholesaler")
|
12
|
+
# _amount = product_or_variant.wholesale_price
|
13
|
+
# amount = _amount if 0.0 < _amount
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# amount ||= product_or_variant.price
|
17
|
+
#
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# amount += Calculator::Vat.calculate_tax_on(product_or_variant) if Spree::Config[:show_price_inc_vat]
|
21
|
+
# options.delete(:format_as_currency) ? format_price(amount, options) : amount
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
#end
|
25
|
+
#
|
26
|
+
#ProductsHelper.send(:include, WholesaleProductsHelper)
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_wholesale
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 40
|
8
|
+
- 0
|
9
|
+
- beta1
|
10
|
+
version: 0.40.0.beta1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Spencer Steffen
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-11 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: spree_core
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 40
|
31
|
+
- 0
|
32
|
+
version: 0.40.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: spree_auth
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
- 40
|
46
|
+
- 0
|
47
|
+
version: 0.40.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: *id002
|
51
|
+
description: Spree Wholesale adds a wholesale_price field to variants and allows users with a "wholesaler" role to access these prices.
|
52
|
+
email: spencer@citrusme.com
|
53
|
+
executables: []
|
54
|
+
|
55
|
+
extensions: []
|
56
|
+
|
57
|
+
extra_rdoc_files: []
|
58
|
+
|
59
|
+
files:
|
60
|
+
- README.md
|
61
|
+
- LICENSE
|
62
|
+
- lib/spree_wholesale.rb
|
63
|
+
- lib/spree_wholesale_hooks.rb
|
64
|
+
- lib/tasks/install.rake
|
65
|
+
- lib/tasks/spree_wholesale.rake
|
66
|
+
- lib/wholesale_products_helper.rb
|
67
|
+
- app/controllers/admin/orders_controller_decorator.rb
|
68
|
+
- app/models/line_item_decorator.rb
|
69
|
+
- app/models/order_decorator.rb
|
70
|
+
- app/models/product_decorator.rb
|
71
|
+
- app/models/products_helper_decorator.rb
|
72
|
+
- app/models/spree_current_order_decorator.rb
|
73
|
+
- app/models/variant_decorator.rb
|
74
|
+
- app/views/admin/hooks/_admin_orders_index_headers.html.erb
|
75
|
+
- app/views/admin/hooks/_admin_orders_index_rows.html.erb
|
76
|
+
- app/views/admin/hooks/_admin_orders_index_search.html.erb
|
77
|
+
- app/views/admin/hooks/_product_form_right.html.erb
|
78
|
+
- app/views/admin/variants/_form.html.erb
|
79
|
+
- app/views/checkout/_summary.html.erb
|
80
|
+
- app/views/hooks/_cart_item_price.html.erb
|
81
|
+
- app/views/hooks/_cart_item_total.html.erb
|
82
|
+
- app/views/hooks/_wholesale_customer_id.html.erb
|
83
|
+
- app/views/orders/show.html.erb
|
84
|
+
- app/views/shared/_products.html.erb
|
85
|
+
has_rdoc: true
|
86
|
+
homepage: http://citrusme.com
|
87
|
+
licenses: []
|
88
|
+
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 1
|
101
|
+
- 8
|
102
|
+
- 7
|
103
|
+
version: 1.8.7
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ">"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
segments:
|
110
|
+
- 1
|
111
|
+
- 3
|
112
|
+
- 1
|
113
|
+
version: 1.3.1
|
114
|
+
requirements:
|
115
|
+
- none
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.3.7
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Add wholesale functionality to spree
|
121
|
+
test_files: []
|
122
|
+
|