spree_core 1.3.0.rc1 → 1.3.0.rc2
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/app/assets/javascripts/admin/admin.js.erb +28 -2
- data/app/assets/javascripts/admin/checkouts/edit.js +52 -96
- data/app/assets/javascripts/admin/handlebar_extensions.js +9 -0
- data/app/assets/javascripts/admin/spree-select2.js.erb +17 -19
- data/app/assets/javascripts/admin/spree_core.js +0 -1
- data/app/assets/javascripts/admin/states.js +9 -0
- data/app/assets/javascripts/admin/taxon_autocomplete.js.erb +1 -1
- data/app/assets/javascripts/admin/variant_autocomplete.js.erb +2 -6
- data/app/assets/javascripts/store/checkout.js.coffee +4 -4
- data/app/assets/stylesheets/store/screen.css.scss +8 -0
- data/app/controllers/spree/admin/option_values_controller.rb +11 -0
- data/app/controllers/spree/admin/product_properties_controller.rb +12 -0
- data/app/controllers/spree/admin/products_controller.rb +9 -0
- data/app/helpers/spree/admin/base_helper.rb +2 -8
- data/app/models/spree/app_configuration.rb +1 -0
- data/app/models/spree/calculator/per_item.rb +3 -1
- data/app/models/spree/line_item.rb +2 -2
- data/app/models/spree/order/checkout.rb +4 -1
- data/app/models/spree/order.rb +5 -1
- data/app/models/spree/payment/processing.rb +1 -1
- data/app/models/spree/preferences/preferable_class_methods.rb +6 -9
- data/app/models/spree/preferences/store.rb +22 -11
- data/app/models/spree/product/scopes.rb +5 -1
- data/app/models/spree/shipment.rb +7 -4
- data/app/models/spree/shipping_method.rb +4 -0
- data/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb +19 -0
- data/app/views/spree/admin/orders/customer_details/edit.html.erb +4 -3
- data/app/views/spree/admin/orders/edit.html.erb +1 -1
- data/app/views/spree/admin/products/search.rabl +6 -0
- data/app/views/spree/admin/search/users.rabl +23 -25
- data/app/views/spree/admin/shared/_head.html.erb +1 -1
- data/app/views/spree/admin/shared/_routes.html.erb +3 -2
- data/app/views/spree/admin/shared/_translations.html.erb +3 -0
- data/app/views/spree/admin/shipping_methods/_form.html.erb +1 -1
- data/app/views/spree/admin/variants/_autocomplete.js.erb +2 -2
- data/app/views/spree/admin/variants/search.rabl +8 -10
- data/app/views/spree/checkout/payment/_gateway.html.erb +2 -2
- data/app/views/spree/order_mailer/cancel_email.text.erb +2 -2
- data/app/views/spree/order_mailer/confirm_email.text.erb +2 -2
- data/app/views/spree/orders/_line_item.html.erb +1 -1
- data/app/views/spree/products/_cart_form.html.erb +6 -2
- data/app/views/spree/shared/_google_analytics.html.erb +8 -8
- data/app/views/spree/shared/_order_details.html.erb +3 -1
- data/config/locales/en.yml +9 -7
- data/config/routes.rb +9 -0
- data/db/migrate/20121126040517_add_last_ip_to_spree_orders.rb +5 -0
- data/lib/spree/core/calculated_adjustments.rb +2 -1
- data/lib/spree/core/controller_helpers/common.rb +5 -0
- data/lib/spree/core/controller_helpers/order.rb +1 -0
- data/lib/spree/core/search/base.rb +5 -1
- data/lib/spree/core/testing_support/capybara_ext.rb +79 -0
- data/lib/spree/core/version.rb +1 -1
- metadata +13 -6
- data/vendor/assets/javascripts/jquery.tokeninput.js +0 -860
@@ -34,7 +34,9 @@ module Spree
|
|
34
34
|
# Shipping methods do not have promotions attached, but promotions do
|
35
35
|
# Therefore we must check for promotions
|
36
36
|
if self.calculable.respond_to?(:promotion)
|
37
|
-
self.calculable.promotion.rules.map
|
37
|
+
self.calculable.promotion.rules.map do |rule|
|
38
|
+
rule.respond_to?(:products) ? rule.products : []
|
39
|
+
end.flatten
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -100,7 +100,7 @@ module Spree
|
|
100
100
|
|
101
101
|
def ensure_not_shipped
|
102
102
|
if order.try(:inventory_units).to_a.any?{ |unit| unit.variant_id == variant_id && unit.shipped? }
|
103
|
-
errors.add :base, I18n.t('validation.
|
103
|
+
errors.add :base, I18n.t('validation.cannot_destroy_line_item_as_inventory_units_have_shipped')
|
104
104
|
return false
|
105
105
|
end
|
106
106
|
end
|
@@ -108,7 +108,7 @@ module Spree
|
|
108
108
|
# Validation
|
109
109
|
def stock_availability
|
110
110
|
return if sufficient_stock?
|
111
|
-
errors.add(:quantity, I18n.t('validation.
|
111
|
+
errors.add(:quantity, I18n.t('validation.exceeds_available_stock'))
|
112
112
|
end
|
113
113
|
|
114
114
|
def quantity_no_less_than_shipped
|
@@ -126,7 +126,10 @@ module Spree
|
|
126
126
|
end
|
127
127
|
checkout_steps << step
|
128
128
|
end
|
129
|
-
checkout_steps.map(&:to_s)
|
129
|
+
steps = checkout_steps.map(&:to_s)
|
130
|
+
# Ensure there is always a complete step
|
131
|
+
steps << "complete" unless steps.include?("complete")
|
132
|
+
steps
|
130
133
|
end
|
131
134
|
end
|
132
135
|
end
|
data/app/models/spree/order.rb
CHANGED
@@ -24,7 +24,7 @@ module Spree
|
|
24
24
|
order.payment_required?
|
25
25
|
}
|
26
26
|
go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
|
27
|
-
go_to_state :complete, :if => lambda { |order| (order.payment_required? && order.
|
27
|
+
go_to_state :complete, :if => lambda { |order| (order.payment_required? && order.payments.exists?) || !order.payment_required? }
|
28
28
|
remove_transition :from => :delivery, :to => :confirm
|
29
29
|
end
|
30
30
|
|
@@ -355,6 +355,10 @@ module Spree
|
|
355
355
|
end
|
356
356
|
end
|
357
357
|
|
358
|
+
def can_ship?
|
359
|
+
self.complete? || self.resumed?
|
360
|
+
end
|
361
|
+
|
358
362
|
def credit_cards
|
359
363
|
credit_card_ids = payments.from_credit_card.map(&:source_id).uniq
|
360
364
|
CreditCard.scoped(:conditions => { :id => credit_card_ids })
|
@@ -110,7 +110,7 @@ module Spree
|
|
110
110
|
def gateway_options
|
111
111
|
options = { :email => order.email,
|
112
112
|
:customer => order.email,
|
113
|
-
:ip =>
|
113
|
+
:ip => order.last_ip_address,
|
114
114
|
:order_id => order.number }
|
115
115
|
|
116
116
|
options.merge!({ :shipping => order.ship_total * 100,
|
@@ -10,16 +10,13 @@ module Spree::Preferences
|
|
10
10
|
# cache_key will be nil for new objects, then if we check if there
|
11
11
|
# is a pending preference before going to default
|
12
12
|
define_method preference_getter_method(name) do
|
13
|
-
|
14
|
-
|
13
|
+
|
14
|
+
# perference_cache_key will only be nil/false for new records
|
15
|
+
#
|
16
|
+
if preference_cache_key(name)
|
17
|
+
preference_store.get(preference_cache_key(name), default)
|
15
18
|
else
|
16
|
-
|
17
|
-
get_pending_preference(name)
|
18
|
-
elsif Spree::Preference.table_exists? && preference = Spree::Preference.find_by_key(name.to_s)
|
19
|
-
preference.value
|
20
|
-
else
|
21
|
-
send self.class.preference_default_getter_method(name)
|
22
|
-
end
|
19
|
+
get_pending_preference(name) || default
|
23
20
|
end
|
24
21
|
end
|
25
22
|
alias_method prefers_getter_method(name), preference_getter_method(name)
|
@@ -27,25 +27,36 @@ module Spree::Preferences
|
|
27
27
|
should_persist? && Spree::Preference.where(:key => key).exists?
|
28
28
|
end
|
29
29
|
|
30
|
-
def get(key)
|
30
|
+
def get(key,fallback=nil)
|
31
31
|
# return the retrieved value, if it's in the cache
|
32
|
-
|
32
|
+
# use unless nil? incase the value is actually boolean false
|
33
|
+
#
|
34
|
+
unless (val = @cache.read(key)).nil?
|
33
35
|
return val
|
34
36
|
end
|
35
37
|
|
36
|
-
|
38
|
+
if should_persist?
|
39
|
+
# If it's not in the cache, maybe it's in the database, but
|
40
|
+
# has been cleared from the cache
|
37
41
|
|
38
|
-
|
39
|
-
|
42
|
+
# does it exist in the database?
|
43
|
+
if Spree::Preference.table_exists? && preference = Spree::Preference.find_by_key(key)
|
44
|
+
# it does exist, so let's put it back into the cache
|
45
|
+
@cache.write(preference.key, preference.value)
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
47
|
+
# and return the value
|
48
|
+
return preference.value
|
49
|
+
end
|
50
|
+
end
|
45
51
|
|
46
|
-
|
47
|
-
|
52
|
+
unless fallback.nil?
|
53
|
+
# cache fallback so we won't hit the db above on
|
54
|
+
# subsequent queries for the same key
|
55
|
+
#
|
56
|
+
@cache.write(key, fallback)
|
48
57
|
end
|
58
|
+
|
59
|
+
return fallback
|
49
60
|
end
|
50
61
|
|
51
62
|
def delete(key)
|
@@ -189,7 +189,11 @@ module Spree
|
|
189
189
|
|
190
190
|
# Can't use add_search_scope for this as it needs a default argument
|
191
191
|
def self.available(available_on = nil, currency = nil)
|
192
|
-
joins(:master => :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
|
192
|
+
scope = joins(:master => :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
|
193
|
+
unless Spree::Config.show_products_without_price
|
194
|
+
scope = scope.where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
|
195
|
+
end
|
196
|
+
scope
|
193
197
|
end
|
194
198
|
search_scopes << :available
|
195
199
|
|
@@ -28,7 +28,7 @@ module Spree
|
|
28
28
|
|
29
29
|
scope :with_state, lambda { |s| where(:state => s) }
|
30
30
|
scope :shipped, with_state('shipped')
|
31
|
-
scope :ready,
|
31
|
+
scope :ready, with_state('ready')
|
32
32
|
scope :pending, with_state('pending')
|
33
33
|
|
34
34
|
def to_param
|
@@ -51,11 +51,13 @@ module Spree
|
|
51
51
|
def cost
|
52
52
|
adjustment ? adjustment.amount : 0
|
53
53
|
end
|
54
|
+
|
54
55
|
alias_method :amount, :cost
|
55
56
|
|
56
57
|
def display_cost
|
57
58
|
Spree::Money.new(cost, { :currency => currency })
|
58
59
|
end
|
60
|
+
|
59
61
|
alias_method :display_amount, :display_cost
|
60
62
|
|
61
63
|
# shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
|
@@ -110,7 +112,7 @@ module Spree
|
|
110
112
|
# shipped if already shipped (ie. does not change the state)
|
111
113
|
# ready all other cases
|
112
114
|
def determine_state(order)
|
113
|
-
return 'pending' unless order.
|
115
|
+
return 'pending' unless order.can_ship?
|
114
116
|
return 'pending' if inventory_units.any? &:backordered?
|
115
117
|
return 'shipped' if state == 'shipped'
|
116
118
|
order.paid? ? 'ready' : 'pending'
|
@@ -121,7 +123,7 @@ module Spree
|
|
121
123
|
return number unless number.blank?
|
122
124
|
record = true
|
123
125
|
while record
|
124
|
-
random = "H#{Array.new(11){rand(9)}.join}"
|
126
|
+
random = "H#{Array.new(11) { rand(9) }.join}"
|
125
127
|
record = self.class.where(:number => random).first
|
126
128
|
end
|
127
129
|
self.number = random
|
@@ -158,9 +160,10 @@ module Spree
|
|
158
160
|
def ensure_correct_adjustment
|
159
161
|
if adjustment
|
160
162
|
adjustment.originator = shipping_method
|
163
|
+
adjustment.label = shipping_method.adjustment_label
|
161
164
|
adjustment.save
|
162
165
|
else
|
163
|
-
shipping_method.create_adjustment(
|
166
|
+
shipping_method.create_adjustment(shipping_method.adjustment_label, order, self, true)
|
164
167
|
reload #ensure adjustment is present on later saves
|
165
168
|
end
|
166
169
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<script type='text/template' id='customer_autocomplete_template'>
|
2
|
+
<div class='customer-autocomplete-item'>
|
3
|
+
<div class='customer-details'>
|
4
|
+
<h5>{{customer.email}}</h5>
|
5
|
+
{{#if bill_address.firstname }}
|
6
|
+
<strong>{{t 'bill_address' }}</strong>
|
7
|
+
{{bill_address.firstname}} {{bill_address.lastname}}<br>
|
8
|
+
{{bill_address.address1}}, {{bill_address.address2}}<br>
|
9
|
+
{{bill_address.city}}<br>
|
10
|
+
{{#if bill_address.state_id }}
|
11
|
+
{{bill_address.state.name}}
|
12
|
+
{{else}}
|
13
|
+
{{bill_address.state_name}}
|
14
|
+
{{/if}}
|
15
|
+
{{bill_address.country.name}}
|
16
|
+
{{/if}}
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</script>
|
@@ -11,15 +11,16 @@
|
|
11
11
|
<% end %>
|
12
12
|
|
13
13
|
<% if @order.cart? %>
|
14
|
-
<div id="
|
14
|
+
<div id="select-customer" data-hook>
|
15
15
|
<fieldset class="no-border-bottom">
|
16
16
|
<legend align="center"><%= t(:customer_search) %></legend>
|
17
|
-
<%=
|
18
|
-
<%=
|
17
|
+
<%= hidden_field_tag :customer_search, nil, :class => 'fullwidth title' %>
|
18
|
+
<%= render :partial => "spree/admin/orders/customer_details/autocomplete", :formats => :js %>
|
19
19
|
</fieldset>
|
20
20
|
</div>
|
21
21
|
<% end %>
|
22
22
|
|
23
|
+
|
23
24
|
<%= render :partial => 'spree/shared/error_messages', :locals => { :target => @order } %>
|
24
25
|
|
25
26
|
<%= form_for @order, :url => admin_order_customer_url(@order) do |f| %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%= csrf_meta_tags %>
|
2
2
|
<% content_for :page_actions do %>
|
3
3
|
<li><%= event_links %></li>
|
4
|
-
<li><%= button_link_to t(:resend), resend_admin_order_url(@order), :method => :post, :icon => 'icon-email'
|
4
|
+
<li><%= button_link_to t(:resend), resend_admin_order_url(@order), :method => :post, :icon => 'icon-email' %></li>
|
5
5
|
<li><%= button_link_to t(:back_to_orders_list), admin_orders_path, :icon => 'icon-arrow-left' %></li>
|
6
6
|
<% end %>
|
7
7
|
|
@@ -1,32 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
:company]
|
1
|
+
collection(@users)
|
2
|
+
attributes :email, :id
|
3
|
+
address_fields = [:firstname, :lastname,
|
4
|
+
:address1, :address2,
|
5
|
+
:city, :zipcode,
|
6
|
+
:phone, :state_name,
|
7
|
+
:state_id, :country_id,
|
8
|
+
:company]
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
child :ship_address => :ship_address do
|
11
|
+
attributes *address_fields
|
12
|
+
child :state do
|
13
|
+
attributes :name
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
16
|
+
child :country do
|
17
|
+
attributes :name
|
20
18
|
end
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
child :bill_address => :bill_address do
|
22
|
+
attributes *address_fields
|
23
|
+
child :state do
|
24
|
+
attributes :name
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
end
|
27
|
+
child :country do
|
28
|
+
attributes :name
|
31
29
|
end
|
32
30
|
end
|
@@ -8,7 +8,7 @@
|
|
8
8
|
</title>
|
9
9
|
|
10
10
|
<!-- Get "Open Sans" font from Google -->
|
11
|
-
<link href='
|
11
|
+
<link href='//fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese' rel='stylesheet' type='text/css'>
|
12
12
|
|
13
13
|
<%= stylesheet_link_tag 'admin/all' %>
|
14
14
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
<script>
|
2
2
|
Spree.routes = <%== {
|
3
3
|
:variants_search => spree.admin_search_variants_path(:format => 'json'),
|
4
|
-
:taxon_search
|
5
|
-
:user_search
|
4
|
+
:taxon_search => spree.search_admin_taxons_path(:format => 'json'),
|
5
|
+
:user_search => spree.admin_search_users_path(:format => 'json'),
|
6
|
+
:product_search => spree.search_admin_products_path(:format => 'json')
|
6
7
|
}.to_json %>;
|
7
8
|
</script>
|
@@ -6,6 +6,8 @@
|
|
6
6
|
:abbr_day_names => I18n.t(:abbr_day_names, :scope => :date),
|
7
7
|
:add => I18n.t(:add),
|
8
8
|
:are_you_sure_delete => I18n.t(:are_you_sure_delete),
|
9
|
+
:bill_address => I18n.t(:bill_address),
|
10
|
+
:choose_a_customer => I18n.t(:choose_a_customer),
|
9
11
|
:confirm_delete => I18n.t(:confirm_delete),
|
10
12
|
:cut => I18n.t(:cut),
|
11
13
|
:destroy => I18n.t(:destroy),
|
@@ -24,6 +26,7 @@
|
|
24
26
|
:searching => I18n.t(:searching),
|
25
27
|
:sku => I18n.t(:sku),
|
26
28
|
:type_to_search => I18n.t(:type_to_search),
|
29
|
+
:taxon_placeholder => I18n.t(:taxon_placeholder),
|
27
30
|
:value => I18n.t(:value)
|
28
31
|
}.to_json
|
29
32
|
%>
|
@@ -24,7 +24,7 @@
|
|
24
24
|
</div>
|
25
25
|
</div>
|
26
26
|
|
27
|
-
<div data-hook"admin_shipping_method_form_availability_fields" class="alpha six columns">
|
27
|
+
<div data-hook="admin_shipping_method_form_availability_fields" class="alpha six columns">
|
28
28
|
<fieldset class="categories no-border-bottom">
|
29
29
|
<legend align="center"><%= t(:availability) %></legend>
|
30
30
|
|
@@ -13,8 +13,8 @@
|
|
13
13
|
<h6 class="variant-name">{{variant.name}}</h6>
|
14
14
|
|
15
15
|
<ul class='variant-data'>
|
16
|
-
<li class='variant-sku'><strong>{{
|
17
|
-
<li class='variant-on_hand'><strong>{{
|
16
|
+
<li class='variant-sku'><strong>{{t 'sku'}}:</strong> {{variant.sku}}</li>
|
17
|
+
<li class='variant-on_hand'><strong>{{t 'on_hand' }}:</strong> {{variant.count_on_hand}}</li>
|
18
18
|
</ul>
|
19
19
|
|
20
20
|
{{#if variant.option_values}}
|
@@ -1,15 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attributes :sku, :options_text, :count_on_hand, :id, :name
|
1
|
+
collection @variants
|
2
|
+
attributes :sku, :options_text, :count_on_hand, :id, :name
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
child(:images => :images) do
|
5
|
+
attributes :mini_url
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
attributes :name, :presentation
|
12
|
-
end
|
8
|
+
child(:option_values => :option_values) do
|
9
|
+
child(:option_type => :option_type) do
|
13
10
|
attributes :name, :presentation
|
14
11
|
end
|
12
|
+
attributes :name, :presentation
|
15
13
|
end
|
@@ -15,8 +15,8 @@
|
|
15
15
|
</p>
|
16
16
|
<p class="field" data-hook="card_expiration">
|
17
17
|
<%= label_tag nil, t(:expiration) %><br />
|
18
|
-
<%= select_month(Date.today, :prefix => param_prefix, :field_name => 'month', :use_month_numbers => true, :class => 'required') %>
|
19
|
-
<%= select_year(Date.today, :prefix => param_prefix, :field_name => 'year', :start_year => Date.today.year, :end_year => Date.today.year + 15, :class => 'required') %>
|
18
|
+
<%= select_month(Date.today, { :prefix => param_prefix, :field_name => 'month', :use_month_numbers => true }, :class => 'required') %>
|
19
|
+
<%= select_year(Date.today, { :prefix => param_prefix, :field_name => 'year', :start_year => Date.today.year, :end_year => Date.today.year + 15 }, :class => 'required') %>
|
20
20
|
<span class="required">*</span>
|
21
21
|
</p>
|
22
22
|
<p class="field" data-hook="card_code">
|
@@ -9,8 +9,8 @@
|
|
9
9
|
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) @ <%= item.variant.display_amount %> = <%= item.display_amount %>
|
10
10
|
<% end %>
|
11
11
|
============================================================
|
12
|
-
<%= t('order_mailer.cancel_email.subtotal'
|
12
|
+
<%= t('order_mailer.cancel_email.subtotal', :subtotal => @order.display_item_total) %>
|
13
13
|
<% @order.adjustments.eligible.each do |adjustment| %>
|
14
14
|
<%= raw(adjustment.label) %> <%= adjustment.display_amount %>
|
15
15
|
<% end %>
|
16
|
-
<%= t('order_mailer.cancel_email.total'
|
16
|
+
<%= t('order_mailer.cancel_email.total', :total => @order.display_total) %>
|