spree_core 1.3.0.rc1 → 1.3.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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) %>
|