spree_core 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/app/assets/javascripts/admin/admin.js.erb +27 -2
  2. data/app/assets/javascripts/admin/taxon_autocomplete.js.erb +25 -23
  3. data/app/assets/stylesheets/store/screen.css.scss +13 -0
  4. data/app/controllers/spree/admin/images_controller.rb +0 -11
  5. data/app/controllers/spree/admin/option_types_controller.rb +3 -14
  6. data/app/controllers/spree/admin/option_values_controller.rb +11 -0
  7. data/app/controllers/spree/admin/product_properties_controller.rb +12 -0
  8. data/app/controllers/spree/admin/resource_controller.rb +10 -0
  9. data/app/controllers/spree/admin/taxons_controller.rb +1 -1
  10. data/app/controllers/spree/admin/variants_controller.rb +0 -11
  11. data/app/controllers/spree/products_controller.rb +9 -3
  12. data/app/helpers/spree/admin/base_helper.rb +2 -1
  13. data/app/helpers/spree/admin/products_helper.rb +1 -1
  14. data/app/helpers/spree/checkout_helper.rb +15 -0
  15. data/app/models/spree/calculator/per_item.rb +3 -1
  16. data/app/models/spree/image.rb +1 -1
  17. data/app/models/spree/line_item.rb +1 -1
  18. data/app/models/spree/order.rb +25 -4
  19. data/app/models/spree/order/checkout.rb +4 -1
  20. data/app/models/spree/payment.rb +1 -1
  21. data/app/models/spree/payment/processing.rb +1 -4
  22. data/app/models/spree/preferences/preferable_class_methods.rb +6 -9
  23. data/app/models/spree/preferences/store.rb +22 -11
  24. data/app/models/spree/product.rb +1 -1
  25. data/app/models/spree/shipment.rb +19 -15
  26. data/app/models/spree/taxonomy.rb +2 -0
  27. data/app/views/spree/admin/image_settings/edit.html.erb +7 -0
  28. data/app/views/spree/admin/orders/edit.html.erb +1 -1
  29. data/app/views/spree/admin/products/_form.html.erb +6 -1
  30. data/app/views/spree/admin/shared/_order_tabs.html.erb +1 -1
  31. data/app/views/spree/admin/shared/_translations.html.erb +1 -1
  32. data/app/views/spree/admin/shipping_methods/_form.html.erb +1 -1
  33. data/app/views/spree/admin/taxonomies/_list.html.erb +2 -1
  34. data/app/views/spree/checkout/_address.html.erb +47 -47
  35. data/app/views/spree/checkout/payment/_gateway.html.erb +2 -2
  36. data/app/views/spree/layouts/spree_application.html.erb +1 -1
  37. data/app/views/spree/orders/_line_item.html.erb +1 -1
  38. data/app/views/spree/products/_thumbnails.html.erb +17 -15
  39. data/app/views/spree/products/show.html.erb +1 -1
  40. data/app/views/spree/shared/_footer.html.erb +1 -1
  41. data/app/views/spree/shared/_google_analytics.html.erb +8 -8
  42. data/app/views/spree/shared/_header.html.erb +1 -1
  43. data/app/views/spree/shared/_main_nav_bar.html.erb +1 -1
  44. data/app/views/spree/shared/_nav_bar.html.erb +1 -1
  45. data/app/views/spree/shared/_order_details.html.erb +3 -1
  46. data/app/views/spree/shared/_sidebar.html.erb +1 -1
  47. data/app/views/spree/taxons/show.html.erb +1 -1
  48. data/config/locales/en.yml +6 -15
  49. data/config/routes.rb +7 -0
  50. data/db/migrate/20121124203911_add_position_to_taxonomies.rb +5 -0
  51. data/lib/spree/core/controller_helpers.rb +1 -0
  52. data/lib/spree/core/testing_support/factories/payment_factory.rb +0 -18
  53. data/lib/spree/core/validators/email.rb +1 -1
  54. data/lib/spree/core/version.rb +1 -1
  55. data/lib/tasks/taxon.rake +1 -1
  56. metadata +147 -54
@@ -29,6 +29,7 @@ module Spree
29
29
 
30
30
  def capture!
31
31
  return true if completed?
32
+ started_processing!
32
33
  protect_from_connection_error do
33
34
  check_environment
34
35
 
@@ -165,10 +166,6 @@ module Spree
165
166
  end
166
167
  end
167
168
 
168
- def record_log(response)
169
- log_entries.create({:details => response.to_yaml}, :without_protection => true)
170
- end
171
-
172
169
  def gateway_error(error)
173
170
  if error.is_a? ActiveMerchant::Billing::Response
174
171
  text = error.params['message'] || error.params['response_reason_text'] || error.message
@@ -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
- if preference_cache_key(name) && preference_store.exist?(preference_cache_key(name))
14
- preference_store.get preference_cache_key(name)
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
- if get_pending_preference(name)
17
- get_pending_preference(name)
18
- elsif Spree::Preference.table_exists? && preference = Spree::Preference.find_by_name(name)
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
- if (val = @cache.read(key)).present?
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
- return nil unless should_persist?
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
- # If it's not in the cache, maybe it's in the database, but
39
- # has been cleared from the cache
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
- # does it exist in the database?
42
- if preference = Spree::Preference.find_by_key(key)
43
- # it does exist, so let's put it back into the cache
44
- @cache.write(preference.key, preference.value)
47
+ # and return the value
48
+ return preference.value
49
+ end
50
+ end
45
51
 
46
- # and return the value
47
- preference.value
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)
@@ -37,7 +37,7 @@ module Spree
37
37
  has_many :variants,
38
38
  :class_name => 'Spree::Variant',
39
39
  :conditions => { :is_master => false, :deleted_at => nil },
40
- :order => :position
40
+ :order => "#{::Spree::Variant.quoted_table_name}.position ASC"
41
41
 
42
42
  has_many :variants_including_master,
43
43
  :class_name => 'Spree::Variant',
@@ -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, with_state('ready')
31
+ scope :ready, with_state('ready')
32
32
  scope :pending, with_state('pending')
33
33
 
34
34
  def to_param
@@ -47,12 +47,16 @@ module Spree
47
47
  def cost
48
48
  adjustment ? adjustment.amount : 0
49
49
  end
50
+
50
51
  alias_method :amount, :cost
51
52
 
52
53
  # shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
53
54
  state_machine :initial => 'pending', :use_transactions => false do
54
55
  event :ready do
55
- transition :from => 'pending', :to => 'ready'
56
+ transition :from => 'pending', :to => 'ready', :if => lambda { |shipment|
57
+ # Fix for #2040
58
+ shipment.determine_state(shipment.order) == 'ready'
59
+ }
56
60
  end
57
61
  event :pend do
58
62
  transition :from => 'ready', :to => 'pending'
@@ -92,12 +96,24 @@ module Spree
92
96
  after_ship if new_state == 'shipped' and old_state != 'shipped'
93
97
  end
94
98
 
99
+ # Determines the appropriate +state+ according to the following logic:
100
+ #
101
+ # pending unless order is complete and +order.payment_state+ is +paid+
102
+ # shipped if already shipped (ie. does not change the state)
103
+ # ready all other cases
104
+ def determine_state(order)
105
+ return 'pending' unless order.can_ship?
106
+ return 'pending' if inventory_units.any? &:backordered?
107
+ return 'shipped' if state == 'shipped'
108
+ order.paid? ? 'ready' : 'pending'
109
+ end
110
+
95
111
  private
96
112
  def generate_shipment_number
97
113
  return number unless number.blank?
98
114
  record = true
99
115
  while record
100
- random = "H#{Array.new(11){rand(9)}.join}"
116
+ random = "H#{Array.new(11) { rand(9) }.join}"
101
117
  record = self.class.where(:number => random).first
102
118
  end
103
119
  self.number = random
@@ -113,18 +129,6 @@ module Spree
113
129
  end
114
130
  end
115
131
 
116
- # Determines the appropriate +state+ according to the following logic:
117
- #
118
- # pending unless order is complete and +order.payment_state+ is +paid+
119
- # shipped if already shipped (ie. does not change the state)
120
- # ready all other cases
121
- def determine_state(order)
122
- return 'pending' unless order.complete?
123
- return 'pending' if inventory_units.any? &:backordered?
124
- return 'shipped' if state == 'shipped'
125
- order.paid? ? 'ready' : 'pending'
126
- end
127
-
128
132
  # Determines whether or not inventory units should be associated with the shipment. This is always +false+ when
129
133
  # +Spree::Config[:track_inventory_levels]+ is set to +false.+ Otherwise its +true+ whenever the order is completed
130
134
  # (and not canceled.)
@@ -10,6 +10,8 @@ module Spree
10
10
 
11
11
  after_save :set_name
12
12
 
13
+ default_scope :order => "#{self.table_name}.position"
14
+
13
15
  private
14
16
  def set_name
15
17
  if root
@@ -13,6 +13,13 @@
13
13
  </label>
14
14
  </p>
15
15
 
16
+ <p data-hook="attachment_url">
17
+ <label>
18
+ <%= label_tag 'preferences[attachment_url]', t(:attachment_url) %>
19
+ <%= preference_field_tag 'preferences[attachment_url]', Spree::Config[:attachment_url], :type => :string, :size => 60 %>
20
+ </label>
21
+ </p>
22
+
16
23
  <p data-hook="attachment_default_url">
17
24
  <label>
18
25
  <%= label_tag 'preferences[attachment_default_url]', t(:attachment_default_url) %>
@@ -4,7 +4,7 @@
4
4
  <%= event_links %>
5
5
  </div>
6
6
  <div class="toolbar">
7
- <%= button_link_to t(:resend), resend_admin_order_url(@order), :method => :post, :icon => 'send-email' if @order.user %>
7
+ <%= button_link_to t(:resend), resend_admin_order_url(@order), :method => :post, :icon => 'send-email' %>
8
8
  </div>
9
9
  </div>
10
10
 
@@ -35,7 +35,12 @@
35
35
  <%= f.field_container :available_on do %>
36
36
  <%= f.label :available_on, t(:available_on) %><br />
37
37
  <%= f.error_message_on :available_on %>
38
- <%= f.text_field :available_on, :class => 'datepicker' %>
38
+ <% if @product.available_on? %>
39
+ <% available_on = l(@product.available_on, :format => t('spree.date_picker.format')) %>
40
+ <% else %>
41
+ <% available_on = nil %>
42
+ <% end %>
43
+ <%= f.text_field :available_on, :value => available_on, :class => 'datepicker' %>
39
44
  <% end %>
40
45
 
41
46
  <% unless @product.has_variants? %>
@@ -6,7 +6,7 @@
6
6
  <h5 id="order_status" data-hook><%= t(:status) %>: <%= t(@order.state, :scope => :order_state) %></h5>
7
7
  <h5 id="order_total" data-hook><%= t(:total) %>: <%= money @order.total %></h5>
8
8
  <% if @order.completed? %>
9
- <h5 id="shipment_status"><%= t(:shipment) %>: <%= t(@order.shipment_state, :scope => :shipment_state, :default => [:missing, "none"]) %></h5>
9
+ <h5 id="shipment_status"><%= t(:shipment) %>: <%= t(@order.shipment_state, :scope => :shipment_states, :default => [:missing, "none"]) %></h5>
10
10
  <h5 id="payment_status"><%= t(:payment) %>: <%= t(@order.payment_state, :scope => :payment_states, :default => [:missing, "none"]) %></h5>
11
11
  <h5 id="date_completed" style="width:100%; float:none;" data-hook><%= t(:date_completed) %>: <%= I18n.l(@order.completed? ? @order.completed_at : @order.created_at) %></h5>
12
12
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  Spree.translations = <%==
3
- { :date_picker => I18n.t(:format,
3
+ { :date_picker => I18n.t(:js_format,
4
4
  :scope => 'spree.date_picker',
5
5
  :default => 'yy/mm/dd'),
6
6
  :abbr_day_names => I18n.t(:abbr_day_names, :scope => :date),
@@ -18,7 +18,7 @@
18
18
  <% end %>
19
19
  </div>
20
20
 
21
- <div data-hook"admin_shipping_method_form_availability_fields">
21
+ <div data-hook="admin_shipping_method_form_availability_fields">
22
22
  <fieldset class="categories">
23
23
  <legend><%= t(:availability) %></legend>
24
24
  <%= f.field_container :shipping_category do %>
@@ -1,4 +1,4 @@
1
- <table class="index" id='listing_taxonomies' data-hook>
1
+ <table class="index sortable" id='listing_taxonomies' data-hook data-sortable-link="<%= update_positions_admin_taxonomies_url %>">
2
2
  <tr data-hook="taxonomies_header">
3
3
  <th><%= t(:name) %></th>
4
4
  <th></th>
@@ -6,6 +6,7 @@
6
6
  <% @taxonomies.each do |taxonomy| %>
7
7
  <tr id="<%= spree_dom_id taxonomy %>" data-hook="taxonomies_row">
8
8
  <td>
9
+ <span class="handle"></span>
9
10
  <%= taxonomy.name %>
10
11
  </td>
11
12
  <td class="actions">
@@ -38,29 +38,30 @@
38
38
  </span>
39
39
  </p>
40
40
 
41
- <% if Spree::Config[:address_requires_state] %>
42
- <p class="field" id="bstate">
43
- <% have_states = !@order.bill_address.country.states.empty? %>
44
- <%= bill_form.label :state, t(:state) %><span class="required">*</span><br />
45
- <% state_elements = [
46
- bill_form.collection_select(:state_id, @order.bill_address.country.states,
47
- :id, :name,
48
- {:include_blank => true},
49
- {:class => have_states ? 'required' : 'hidden',
50
- :disabled => !have_states}) +
51
- bill_form.text_field(:state_name,
52
- :class => !have_states ? 'required' : 'hidden',
53
- :disabled => have_states)
54
- ].join.gsub('"', "'").gsub("\n", "")
55
- %>
56
- <%= javascript_tag do -%>
57
- document.write("<%== state_elements %>");
58
- <% end -%>
59
- </p>
60
- <noscript>
61
- <%= bill_form.text_field :state_name, :class => 'required' %>
62
- </noscript>
63
- <% end %>
41
+ <p class="field" id="bstate">
42
+ <% have_states = !@order.bill_address.country.states.empty? %>
43
+
44
+ <%= bill_form.label :state, t(:state) %><%= state_required_label %><br />
45
+
46
+ <% state_elements = [
47
+ bill_form.collection_select(:state_id, @order.bill_address.country.states,
48
+ :id, :name,
49
+ {:include_blank => true},
50
+ {:class => have_states ? state_required_class : 'hidden',
51
+ :disabled => !have_states}) +
52
+ bill_form.text_field(:state_name,
53
+ :class => !have_states ? state_required_class : 'hidden',
54
+ :disabled => have_states)
55
+ ].join.gsub('"', "'").gsub("\n", "")
56
+ %>
57
+ <%= javascript_tag do -%>
58
+ document.write("<%== state_elements %>");
59
+ <% end -%>
60
+ </p>
61
+
62
+ <noscript>
63
+ <%= bill_form.text_field :state_name, :class => state_required_class %>
64
+ </noscript>
64
65
 
65
66
  <p class="field" id="bzipcode">
66
67
  <%= bill_form.label :zipcode, t(:zip) %><span class="required">*</span><br />
@@ -86,7 +87,7 @@
86
87
  <%= form.fields_for :ship_address do |ship_form| %>
87
88
  <legend><%= t(:shipping_address) %></legend>
88
89
  <p class="field checkbox" data-hook="use_billing">
89
- <%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address)) %>
90
+ <%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address)) %>
90
91
  <%= label_tag :order_use_billing, t(:use_billing_address), :id => 'use_billing' %>
91
92
  </p>
92
93
  <div class="inner" data-hook="shipping_inner">
@@ -125,29 +126,28 @@
125
126
  </span>
126
127
  </p>
127
128
 
128
- <% if Spree::Config[:address_requires_state] %>
129
- <p class="field" id="sstate">
130
- <% have_states = !@order.ship_address.country.states.empty? %>
131
- <%= ship_form.label :state, t(:state) %><span class="required">*</span><br />
132
- <% state_elements = [
133
- ship_form.collection_select(:state_id, @order.ship_address.country.states,
134
- :id, :name,
135
- {:include_blank => true},
136
- {:class => have_states ? 'required' : 'hidden',
137
- :disabled => !have_states}) +
138
- ship_form.text_field(:state_name,
139
- :class => !have_states ? 'required' : 'hidden',
140
- :disabled => have_states)
141
- ].join.gsub('"', "'").gsub("\n", "")
142
- %>
143
- <%= javascript_tag do -%>
144
- document.write("<%== state_elements %>");
145
- <% end %>
146
- </p>
147
- <noscript>
148
- <%= ship_form.text_field :state_name, :class => 'required' %>
149
- </noscript>
150
- <% end %>
129
+ <p class="field" id="sstate">
130
+ <% have_states = !@order.ship_address.country.states.empty? %>
131
+ <%= ship_form.label :state, t(:state) %><%= state_required_label %><br />
132
+ <% state_elements = [
133
+ ship_form.collection_select(:state_id, @order.ship_address.country.states,
134
+ :id, :name,
135
+ {:include_blank => true},
136
+ {:class => have_states ? state_required_class : 'hidden',
137
+ :disabled => !have_states}) +
138
+ ship_form.text_field(:state_name,
139
+ :class => !have_states ? state_required_class : 'hidden',
140
+ :disabled => have_states)
141
+ ].join.gsub('"', "'").gsub("\n", "")
142
+ %>
143
+ <%= javascript_tag do -%>
144
+ document.write("<%== state_elements %>");
145
+ <% end %>
146
+ </p>
147
+
148
+ <noscript>
149
+ <%= ship_form.text_field :state_name, :class => state_required_class %>
150
+ </noscript>
151
151
 
152
152
  <p class="field" id="szipcode">
153
153
  <%= ship_form.label :zipcode, t(:zip) %><span class="required">*</span><br />
@@ -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">
@@ -13,7 +13,7 @@
13
13
  <div id="wrapper" class="row" data-hook>
14
14
  <%= breadcrumbs(@taxon) %>
15
15
  <%= render :partial => 'spree/shared/sidebar' if content_for? :sidebar %>
16
- <div id="content" class="columns omega <%= !content_for?(:sidebar) ? "sixteen alpha" : "twelve" %>" data-hook>
16
+ <div id="content" class="columns <%= !content_for?(:sidebar) ? "sixteen" : "twelve" %>" data-hook>
17
17
  <%= flash_messages %>
18
18
  <%= yield %>
19
19
  </div>
@@ -11,7 +11,7 @@
11
11
  <%= variant.options_text %>
12
12
  <% if @order.insufficient_stock_lines.include? line_item %>
13
13
  <span class="out-of-stock">
14
- <%= variant.in_stock? ? t(:insufficient_stock, :on_hand => variant.on_hand) : t(:out_of_stock) %><br />
14
+ <%= variant.in_stock? ? t(:insufficient_stock, :on_hand => variant.on_hand) : t(:out_of_stock) %>&nbsp;&nbsp;<br />
15
15
  </span>
16
16
  <% end %>
17
17
  <%= line_item_description(variant) %>
@@ -1,19 +1,21 @@
1
- <!-- no need for thumnails unless there is more then one image -->
2
- <% if product.images.size > 1 || product.variant_images.size > 0 %>
1
+ <%# no need for thumbnails unless there is more than one image %>
2
+ <% if (@product.images + @product.variant_images).uniq.size > 1 %>
3
3
  <ul id="product-thumbnails" class="thumbnails inline" data-hook>
4
- <% product.images.each do |i| %>
5
- <li class="tmb-all" id="tmb-<%= i.id.to_s %>"><%= link_to image_tag(i.attachment.url(:mini)), i.attachment.url(:product) %></li>
4
+ <% @product.images.each do |i| %>
5
+ <li class='tmb-all' id='tmb-<%= i.id %>'>
6
+ <%= link_to(image_tag(i.attachment.url(:mini)), i.attachment.url(:product), :class => 'tmb-all', :id => "tmb-#{i.id}") %>
7
+ </li>
8
+ <% end %>
9
+
10
+ <% if @product.has_variants? %>
11
+ <% @variants.select(&:available?).each do |v| %>
12
+ <% v.images.each do |i| %>
13
+ <% next if @product.images.include?(i) %>
14
+ <li class='vtmb-<%= v.id %> vtmb' id='tmb-<%= i.id %>'>
15
+ <%= link_to(image_tag(i.attachment.url(:mini)), i.attachment.url(:product)) %>
16
+ </li>
17
+ <% end %>
18
+ <% end %>
6
19
  <% end %>
7
- <% if @product.has_variants?
8
- @variants.each do |v|
9
- if v.available?
10
- v.images.each do |i| %>
11
- <li class="vtmb-<%= v.id.to_s %> vtmb" id="tmb-<%= i.id.to_s %>"><%= link_to image_tag(i.attachment.url(:mini)), i.attachment.url(:product) %></li>
12
- <%
13
- end
14
- end
15
- end
16
- end
17
- %>
18
20
  </ul>
19
21
  <% end %>
@@ -9,7 +9,7 @@
9
9
  <%= render :partial => 'image' %>
10
10
  </div>
11
11
  <div id="thumbnails" data-hook>
12
- <%= render :partial => 'thumbnails', :locals => { :product => @product } %>
12
+ <%= render :partial => 'thumbnails' %>
13
13
  </div>
14
14
  </div>
15
15