solidus_volume_pricing 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.hound.yml +40 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +81 -0
- data/Gemfile +13 -0
- data/Guardfile +9 -0
- data/LICENSE.md +26 -0
- data/README.md +112 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/backend/solidus_volume_pricing.js +16 -0
- data/app/controllers/spree/admin/variants_controller_decorator.rb +32 -0
- data/app/controllers/spree/admin/volume_price_models_controller.rb +27 -0
- data/app/controllers/spree/admin/volume_prices_controller.rb +11 -0
- data/app/helpers/spree/base_helper_decorator.rb +19 -0
- data/app/models/spree/line_item_decorator.rb +27 -0
- data/app/models/spree/user_decorator.rb +10 -0
- data/app/models/spree/variant_decorator.rb +104 -0
- data/app/models/spree/volume_price.rb +35 -0
- data/app/models/spree/volume_price_model.rb +8 -0
- data/app/overrides/spree/admin/shared/sub_menu/_configuration/add_volume_price_model_admin_menu_links.html.erb.deface +3 -0
- data/app/overrides/views_decorator.rb +13 -0
- data/app/views/spree/admin/shared/_vp_product_tab.html.erb +3 -0
- data/app/views/spree/admin/variants/_edit_fields.html.erb +33 -0
- data/app/views/spree/admin/variants/volume_prices.html.erb +39 -0
- data/app/views/spree/admin/volume_price_models/_form.html.erb +9 -0
- data/app/views/spree/admin/volume_price_models/_list.html.erb +23 -0
- data/app/views/spree/admin/volume_price_models/edit.html.erb +12 -0
- data/app/views/spree/admin/volume_price_models/index.html.erb +18 -0
- data/app/views/spree/admin/volume_price_models/new.html.erb +12 -0
- data/app/views/spree/admin/volume_prices/_edit_fields.html.erb +31 -0
- data/app/views/spree/admin/volume_prices/_volume_price_fields.html.erb +33 -0
- data/app/views/spree/products/_volume_pricing.html.erb +15 -0
- data/bin/rails +7 -0
- data/config/locales/de.yml +18 -0
- data/config/locales/en.yml +18 -0
- data/config/locales/pt.yml +18 -0
- data/config/locales/ru.yml +18 -0
- data/config/locales/sv.yml +18 -0
- data/config/locales/tr.yml +18 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20081119145604_create_volume_prices.rb +16 -0
- data/db/migrate/20110203174010_change_display_name_for_volume_prices.rb +9 -0
- data/db/migrate/20111206173307_prefix_volume_pricing_table_names.rb +5 -0
- data/db/migrate/20121115043422_add_discount_type_column.rb +5 -0
- data/db/migrate/20150513200904_add_role_to_volume_price.rb +5 -0
- data/db/migrate/20150603143015_create_spree_volume_price_models.rb +18 -0
- data/lib/generators/solidus_volume_pricing/install/install_generator.rb +24 -0
- data/lib/solidus_volume_pricing.rb +6 -0
- data/lib/solidus_volume_pricing/engine.rb +42 -0
- data/lib/solidus_volume_pricing/version.rb +18 -0
- data/solidus_volume_pricing.gemspec +40 -0
- data/spec/controllers/spree/admin/variants_controller_spec.rb +27 -0
- data/spec/factories/volume_price_factory.rb +12 -0
- data/spec/helpers/base_helper_spec.rb +22 -0
- data/spec/models/spree/line_item_spec.rb +34 -0
- data/spec/models/spree/order_spec.rb +49 -0
- data/spec/models/spree/variant_spec.rb +306 -0
- data/spec/models/spree/volume_price_spec.rb +121 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/capybara.rb +12 -0
- data/spec/support/database_cleaner.rb +24 -0
- data/spec/support/factory_girl.rb +7 -0
- data/spec/support/spree.rb +10 -0
- metadata +337 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
Spree::BaseHelper.class_eval do
|
2
|
+
def display_volume_price(variant, quantity = 1, user = nil)
|
3
|
+
Spree::Money.new(
|
4
|
+
variant.volume_price(quantity, user),
|
5
|
+
currency: Spree::Config[:currency]
|
6
|
+
).to_html
|
7
|
+
end
|
8
|
+
|
9
|
+
def display_volume_price_earning_percent(variant, quantity = 1, user = nil)
|
10
|
+
variant.volume_price_earning_percent(quantity, user).round.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def display_volume_price_earning_amount(variant, quantity = 1, user = nil)
|
14
|
+
Spree::Money.new(
|
15
|
+
variant.volume_price_earning_amount(quantity, user),
|
16
|
+
currency: Spree::Config[:currency]
|
17
|
+
).to_html
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Spree::LineItem.class_eval do
|
2
|
+
# pattern grabbed from: http://stackoverflow.com/questions/4470108/
|
3
|
+
|
4
|
+
# the idea here is compatibility with spree_sale_products
|
5
|
+
# trying to create a 'calculation stack' wherein the best valid price is
|
6
|
+
# chosen for the product. This is mainly for compatibility with spree_sale_products
|
7
|
+
#
|
8
|
+
# Assumption here is that the volume price currency is the same as the product currency
|
9
|
+
old_copy_price = instance_method(:copy_price)
|
10
|
+
define_method(:copy_price) do
|
11
|
+
old_copy_price.bind(self).call
|
12
|
+
return unless variant
|
13
|
+
|
14
|
+
if variant
|
15
|
+
if changed? && changes.keys.include?('quantity')
|
16
|
+
vprice = variant.volume_price(quantity, order.user)
|
17
|
+
if price.present? && vprice <= variant.price
|
18
|
+
self.price = vprice and return
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
self.price = variant.price if price.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
self.price = variant.price if price.nil?
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
Spree::Variant.class_eval do
|
2
|
+
has_and_belongs_to_many :volume_price_models
|
3
|
+
has_many :volume_prices, -> { order(position: :asc) }, dependent: :destroy
|
4
|
+
has_many :model_volume_prices, -> { order(position: :asc) }, class_name: 'Spree::VolumePrice', through: :volume_price_models, source: :volume_prices
|
5
|
+
accepts_nested_attributes_for :volume_prices, allow_destroy: true,
|
6
|
+
reject_if: proc { |volume_price|
|
7
|
+
volume_price[:amount].blank? && volume_price[:range].blank?
|
8
|
+
}
|
9
|
+
|
10
|
+
def join_volume_prices(user = nil)
|
11
|
+
table = Spree::VolumePrice.arel_table
|
12
|
+
|
13
|
+
if user
|
14
|
+
Spree::VolumePrice.where(
|
15
|
+
(table[:variant_id].eq(id)
|
16
|
+
.or(table[:volume_price_model_id].in(volume_price_models.ids)))
|
17
|
+
.and(table[:role_id].eq(user.resolve_role))
|
18
|
+
)
|
19
|
+
.order(position: :asc)
|
20
|
+
else
|
21
|
+
Spree::VolumePrice.where(
|
22
|
+
(table[:variant_id]
|
23
|
+
.eq(id)
|
24
|
+
.or(table[:volume_price_model_id].in(volume_price_models.ids)))
|
25
|
+
.and(table[:role_id].eq(nil))
|
26
|
+
).order(position: :asc)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# calculates the price based on quantity
|
31
|
+
def volume_price(quantity, user = nil)
|
32
|
+
compute_volume_price_quantities :volume_price, price, quantity, user
|
33
|
+
end
|
34
|
+
|
35
|
+
# return percent of earning
|
36
|
+
def volume_price_earning_percent(quantity, user = nil)
|
37
|
+
compute_volume_price_quantities :volume_price_earning_percent, 0, quantity, user
|
38
|
+
end
|
39
|
+
|
40
|
+
# return amount of earning
|
41
|
+
def volume_price_earning_amount(quantity, user = nil)
|
42
|
+
compute_volume_price_quantities :volume_price_earning_amount, 0, quantity, user
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def use_master_variant_volume_pricing?
|
48
|
+
Spree::Config.use_master_variant_volume_pricing && !(product.master.join_volume_prices.count == 0)
|
49
|
+
end
|
50
|
+
|
51
|
+
def compute_volume_price_quantities(type, default_price, quantity, user)
|
52
|
+
volume_prices = join_volume_prices user
|
53
|
+
if volume_prices.count == 0
|
54
|
+
if use_master_variant_volume_pricing?
|
55
|
+
product.master.send(type, quantity, user)
|
56
|
+
else
|
57
|
+
return default_price
|
58
|
+
end
|
59
|
+
else
|
60
|
+
volume_prices.each do |volume_price|
|
61
|
+
if volume_price.include?(quantity)
|
62
|
+
return send "compute_#{type}".to_sym, volume_price
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# No price ranges matched.
|
67
|
+
default_price
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def compute_volume_price(volume_price)
|
72
|
+
case volume_price.discount_type
|
73
|
+
when 'price'
|
74
|
+
return volume_price.amount
|
75
|
+
when 'dollar'
|
76
|
+
return price - volume_price.amount
|
77
|
+
when 'percent'
|
78
|
+
return price * (1 - volume_price.amount)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def compute_volume_price_earning_percent(volume_price)
|
83
|
+
case volume_price.discount_type
|
84
|
+
when 'price'
|
85
|
+
diff = price - volume_price.amount
|
86
|
+
return (diff * 100 / price).round
|
87
|
+
when 'dollar'
|
88
|
+
return (volume_price.amount * 100 / price).round
|
89
|
+
when 'percent'
|
90
|
+
return (volume_price.amount * 100).round
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def compute_volume_price_earning_amount(volume_price)
|
95
|
+
case volume_price.discount_type
|
96
|
+
when 'price'
|
97
|
+
return price - volume_price.amount
|
98
|
+
when 'dollar'
|
99
|
+
return volume_price.amount
|
100
|
+
when 'percent'
|
101
|
+
return price - (price * (1 - volume_price.amount))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Spree::VolumePrice < ActiveRecord::Base
|
2
|
+
belongs_to :variant, touch: true
|
3
|
+
belongs_to :volume_price_model, touch: true
|
4
|
+
belongs_to :spree_role, class_name: 'Spree::Role', foreign_key: 'role_id'
|
5
|
+
acts_as_list scope: [:variant_id, :volume_price_model_id]
|
6
|
+
|
7
|
+
validates :amount, presence: true
|
8
|
+
validates :discount_type,
|
9
|
+
presence: true,
|
10
|
+
inclusion: {
|
11
|
+
in: %w(price dollar percent),
|
12
|
+
message: I18n.t(:'activerecord.errors.messages.is_not_a_valid_volume_price_type', value: self)
|
13
|
+
}
|
14
|
+
validates :range,
|
15
|
+
format: {
|
16
|
+
with: /\(?[0-9]+(?:\.{2,3}[0-9]+|\+\)?)/,
|
17
|
+
message: I18n.t(:'activerecord.errors.messages.must_be_in_format')
|
18
|
+
}
|
19
|
+
|
20
|
+
OPEN_ENDED = /\(?[0-9]+\+\)?/
|
21
|
+
|
22
|
+
def include?(quantity)
|
23
|
+
if open_ended?
|
24
|
+
bound = /\d+/.match(range)[0].to_i
|
25
|
+
return quantity >= bound
|
26
|
+
else
|
27
|
+
range.to_range === quantity
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# indicates whether or not the range is a true Ruby range or an open ended range with no upper bound
|
32
|
+
def open_ended?
|
33
|
+
OPEN_ENDED =~ range
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class Spree::VolumePriceModel < ActiveRecord::Base
|
2
|
+
has_many :variants
|
3
|
+
has_many :volume_prices, -> { order(position: :asc) }, dependent: :destroy
|
4
|
+
accepts_nested_attributes_for :volume_prices, allow_destroy: true,
|
5
|
+
reject_if: proc { |volume_price|
|
6
|
+
volume_price[:amount].blank? && volume_price[:range].blank?
|
7
|
+
}
|
8
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Deface::Override.new(
|
2
|
+
virtual_path: 'spree/admin/shared/_product_tabs',
|
3
|
+
name: 'add_volume_pricing_admin_tab',
|
4
|
+
insert_bottom: '[data-hook="admin_product_tabs"]',
|
5
|
+
partial: 'spree/admin/shared/vp_product_tab'
|
6
|
+
)
|
7
|
+
|
8
|
+
Deface::Override.new(
|
9
|
+
virtual_path: 'spree/admin/variants/edit',
|
10
|
+
name: 'add_volume_pricing_field_to_variant',
|
11
|
+
insert_after: '[data-hook="admin_variant_edit_form"]',
|
12
|
+
partial: 'spree/admin/variants/edit_fields'
|
13
|
+
)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<% content_for :page_actions do %>
|
2
|
+
<span id="new_add_volume_price" data-hook>
|
3
|
+
<%= button_link_to Spree.t(:add_volume_price), 'javascript:;', {
|
4
|
+
icon: 'add', :'data-target' => 'tbody#volume_prices', class: 'btn-success spree_add_fields', id: 'add_volume_price' } %>
|
5
|
+
</span>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<h3><%= Spree.t(:volume_prices) %></h3>
|
9
|
+
<table class="table">
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<th><%= Spree.t(:name) %></th>
|
13
|
+
<th><%= Spree.t(:discount_type) %></th>
|
14
|
+
<th><%= Spree.t(:range) %></th>
|
15
|
+
<th><%= Spree.t(:amount) %></th>
|
16
|
+
<th><%= Spree.t(:position) %></th>
|
17
|
+
<th><%= Spree.t(:role) %></th>
|
18
|
+
<th><%= Spree.t(:action) %></th>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody id="volume_prices">
|
22
|
+
<%= f.fields_for :volume_prices do |vp_form| %>
|
23
|
+
<%= render partial: 'spree/admin/volume_prices/volume_price_fields', locals: { f: vp_form } %>
|
24
|
+
<% end %>
|
25
|
+
</tbody>
|
26
|
+
<tbody id="volume_price_models">
|
27
|
+
<%= f.field_container :volume_price_model, class: ['form-group'] do %>
|
28
|
+
<%= f.label :volume_price_model_id, Spree.t(:volume_price_model) %>
|
29
|
+
<%= f.collection_select(:volume_price_model_ids, Spree::VolumePriceModel.all, :id, :name, { include_blank: Spree.t('match_choices.none') }, { class: 'select2', disabled: (cannot? :edit, Spree::VolumePriceModel) }) %>
|
30
|
+
<%= f.error_message_on :volume_price_model %>
|
31
|
+
<% end %>
|
32
|
+
</tbody>
|
33
|
+
</table>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<%= render 'spree/admin/shared/product_tabs', current: Spree.t(:volume_pricing) %>
|
2
|
+
<%= render 'spree/shared/error_messages', target: @variant %>
|
3
|
+
|
4
|
+
<% content_for :page_actions do %>
|
5
|
+
<span id="new_add_volume_price" data-hook>
|
6
|
+
<%= button_link_to Spree.t(:add_volume_price), 'javascript:;', {
|
7
|
+
icon: 'add', :'data-target' => 'tbody#volume_prices', class: 'btn-success spree_add_fields', id: 'add_volume_price'} %>
|
8
|
+
</span>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= form_for(@variant, url: admin_product_variant_path(@product, @variant), html: { method: :put }) do |f| %>
|
12
|
+
<h3><%= Spree.t(:volume_prices) %></h3>
|
13
|
+
<table class="table">
|
14
|
+
<thead>
|
15
|
+
<tr>
|
16
|
+
<th><%= Spree.t(:name) %></th>
|
17
|
+
<th><%= Spree.t(:discount_type) %></th>
|
18
|
+
<th><%= Spree.t(:range) %></th>
|
19
|
+
<th><%= Spree.t(:amount) %></th>
|
20
|
+
<th><%= Spree.t(:position) %></th>
|
21
|
+
<th><%= Spree.t(:role) %></th>
|
22
|
+
<th class="actions"></th>
|
23
|
+
</tr>
|
24
|
+
</thead>
|
25
|
+
<tbody id="volume_prices">
|
26
|
+
<%= f.fields_for :volume_prices do |vp_form| %>
|
27
|
+
<%= render partial: 'spree/admin/volume_prices/volume_price_fields', locals: { f: vp_form } %>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
<tbody id="volume_price_models">
|
31
|
+
<%= f.field_container :volume_price_model, class: ['form-group'] do %>
|
32
|
+
<%= f.label :volume_price_model_id, Spree.t(:volume_price_model) %>
|
33
|
+
<%= f.collection_select(:volume_price_model_ids, Spree::VolumePriceModel.all, :id, :name, { include_blank: Spree.t('match_choices.none') }, { class: 'select2', disabled: (cannot? :edit, Spree::VolumePriceModel) }) %>
|
34
|
+
<%= f.error_message_on :volume_price_model %>
|
35
|
+
<% end %>
|
36
|
+
</tbody>
|
37
|
+
</table>
|
38
|
+
<%= render 'spree/admin/shared/edit_resource_links' %>
|
39
|
+
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div data-hook="admin_inside_volume_price_model_form" class="form-group">
|
2
|
+
<%= f.field_container :name, class: ['form-group'] do %>
|
3
|
+
<%= f.label :name, Spree.t(:name) %> <span class="required">*</span>
|
4
|
+
<%= error_message_on :volume_price_model, :name, :class => 'error-message' %>
|
5
|
+
<%= text_field :volume_price_model, :name, :class => 'form-control' %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= render 'spree/admin/volume_prices/edit_fields', f: f %>
|
9
|
+
</div>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<table class="table sortable" id='listing_volume_price_models' data-hook data-sortable-link="<%#= update_positions_admin_volume_price_models_url %>">
|
2
|
+
<thead>
|
3
|
+
<tr data-hook="volume_price_models_header">
|
4
|
+
<th class="no-border"></th>
|
5
|
+
<th><%= Spree.t(:name) %></th>
|
6
|
+
<th class="actions"></th>
|
7
|
+
</tr>
|
8
|
+
</thead>
|
9
|
+
<tbody>
|
10
|
+
<% @volume_price_models.each do |price_model| %>
|
11
|
+
<tr id="<%= spree_dom_id price_model %>" data-hook="volume_price_models_row">
|
12
|
+
<td class="move-handle">
|
13
|
+
<span class="icon icon-sort handle"></span>
|
14
|
+
</td>
|
15
|
+
<td><%= price_model.name %></td>
|
16
|
+
<td class="actions actions-2 text-right">
|
17
|
+
<%= link_to_edit price_model.id, no_text: true %>
|
18
|
+
<%= link_to_delete price_model, no_text: true %>
|
19
|
+
</td>
|
20
|
+
</tr>
|
21
|
+
<% end %>
|
22
|
+
</tbody>
|
23
|
+
</table>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t(:volume_price_model_edit) %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= form_for [:admin, @volume_price_model] do |f| %>
|
6
|
+
<fieldset>
|
7
|
+
<%= render partial: 'form', locals: { f: f } %>
|
8
|
+
</fieldset>
|
9
|
+
|
10
|
+
<%= render 'spree/admin/shared/edit_resource_links' %>
|
11
|
+
|
12
|
+
<% end %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= "Volume Price Models" %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for :page_actions do %>
|
6
|
+
<%= button_link_to Spree.t(:new_volume_price_model), new_object_url, class: "btn-success", icon: 'add', id: 'admin_new_volume_price_model_link' %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% if @volume_price_models.any? %>
|
10
|
+
<div id="list-volume-price-models" data-hook>
|
11
|
+
<%= render 'list' %>
|
12
|
+
</div>
|
13
|
+
<% else %>
|
14
|
+
<div class="alert alert-info no-objects-found">
|
15
|
+
<%= Spree.t(:no_resource_found, resource: "Volume Price Models") %>,
|
16
|
+
<%= link_to Spree.t(:add_one), new_object_url %>!
|
17
|
+
</div>
|
18
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t(:new_volume_price_model) %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= form_for [:admin, @volume_price_model] do |f| %>
|
6
|
+
<fieldset>
|
7
|
+
<%= render partial: 'form', locals: { f: f } %>
|
8
|
+
<div class="form-actions" data-hook="buttons">
|
9
|
+
<%= button Spree.t(:create), 'save' %>
|
10
|
+
</div>
|
11
|
+
</fieldset>
|
12
|
+
<% end %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% content_for :page_actions do %>
|
2
|
+
<span id="new_add_volume_price" data-hook>
|
3
|
+
<%= button_link_to Spree.t(:add_volume_price), 'javascript:;', {
|
4
|
+
icon: 'add',
|
5
|
+
:'data-target' => 'tbody#volume_prices',
|
6
|
+
class: 'btn-success spree_add_fields',
|
7
|
+
id: 'add_volume_price'
|
8
|
+
} %>
|
9
|
+
</span>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<h3><%= Spree.t(:volume_prices) %></h3>
|
13
|
+
<table class="table">
|
14
|
+
<thead>
|
15
|
+
<tr>
|
16
|
+
<th><%= Spree.t(:name) %></th>
|
17
|
+
<th><%= Spree.t(:discount_type) %></th>
|
18
|
+
<th><%= Spree.t(:range) %></th>
|
19
|
+
<th><%= Spree.t(:amount) %></th>
|
20
|
+
<th><%= Spree.t(:position) %></th>
|
21
|
+
<th><%= Spree.t(:role) %></th>
|
22
|
+
<th><%= Spree.t(:action) %></th>
|
23
|
+
</tr>
|
24
|
+
</thead>
|
25
|
+
<tbody id="volume_prices">
|
26
|
+
<%= f.fields_for :volume_prices do |vp_form| %>
|
27
|
+
<%= render partial: 'spree/admin/volume_prices/volume_price_fields', locals: { f: vp_form } %>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
31
|
+
<br/><br/>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<tr class="volume_price fields">
|
2
|
+
<td>
|
3
|
+
<%= error_message_on(f.object, :name) %>
|
4
|
+
<%= f.text_field :name, size: 10, class: 'form-control' %>
|
5
|
+
</td>
|
6
|
+
<td>
|
7
|
+
<%= error_message_on(f.object, :discount_type) %>
|
8
|
+
<%= f.select :discount_type, [
|
9
|
+
["#{Spree.t(:total_price)}", 'price'],
|
10
|
+
["#{Spree.t(:percent_discount)}", 'percent'],
|
11
|
+
["#{Spree.t(:price_discount)}", 'dollar']
|
12
|
+
], { inlcude_blank: true }, class: 'select2' %>
|
13
|
+
</td>
|
14
|
+
<td>
|
15
|
+
<%= error_message_on(f.object, :range) %>
|
16
|
+
<%= f.text_field :range, size: 10, class: 'form-control' %>
|
17
|
+
</td>
|
18
|
+
<td>
|
19
|
+
<%= error_message_on(f.object, :amount) %>
|
20
|
+
<%= f.text_field :amount, size: 10, class: 'form-control' %>
|
21
|
+
</td>
|
22
|
+
<td>
|
23
|
+
<%= error_message_on(f.object, :position) %>
|
24
|
+
<%= f.text_field :position, size: 3, class: 'form-control' %>
|
25
|
+
</td>
|
26
|
+
<td>
|
27
|
+
<%= error_message_on(f.object, :role_id) %>
|
28
|
+
<%= f.collection_select(:role_id, Spree::Role.all, :id, :name, { include_blank: Spree.t('match_choices.none') }, { class: 'select2' }) %>
|
29
|
+
</td>
|
30
|
+
<td class="actions">
|
31
|
+
<%= link_to_icon_remove_fields f %>
|
32
|
+
</td>
|
33
|
+
</tr>
|