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.
Files changed (54) hide show
  1. data/app/assets/javascripts/admin/admin.js.erb +28 -2
  2. data/app/assets/javascripts/admin/checkouts/edit.js +52 -96
  3. data/app/assets/javascripts/admin/handlebar_extensions.js +9 -0
  4. data/app/assets/javascripts/admin/spree-select2.js.erb +17 -19
  5. data/app/assets/javascripts/admin/spree_core.js +0 -1
  6. data/app/assets/javascripts/admin/states.js +9 -0
  7. data/app/assets/javascripts/admin/taxon_autocomplete.js.erb +1 -1
  8. data/app/assets/javascripts/admin/variant_autocomplete.js.erb +2 -6
  9. data/app/assets/javascripts/store/checkout.js.coffee +4 -4
  10. data/app/assets/stylesheets/store/screen.css.scss +8 -0
  11. data/app/controllers/spree/admin/option_values_controller.rb +11 -0
  12. data/app/controllers/spree/admin/product_properties_controller.rb +12 -0
  13. data/app/controllers/spree/admin/products_controller.rb +9 -0
  14. data/app/helpers/spree/admin/base_helper.rb +2 -8
  15. data/app/models/spree/app_configuration.rb +1 -0
  16. data/app/models/spree/calculator/per_item.rb +3 -1
  17. data/app/models/spree/line_item.rb +2 -2
  18. data/app/models/spree/order/checkout.rb +4 -1
  19. data/app/models/spree/order.rb +5 -1
  20. data/app/models/spree/payment/processing.rb +1 -1
  21. data/app/models/spree/preferences/preferable_class_methods.rb +6 -9
  22. data/app/models/spree/preferences/store.rb +22 -11
  23. data/app/models/spree/product/scopes.rb +5 -1
  24. data/app/models/spree/shipment.rb +7 -4
  25. data/app/models/spree/shipping_method.rb +4 -0
  26. data/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb +19 -0
  27. data/app/views/spree/admin/orders/customer_details/edit.html.erb +4 -3
  28. data/app/views/spree/admin/orders/edit.html.erb +1 -1
  29. data/app/views/spree/admin/products/search.rabl +6 -0
  30. data/app/views/spree/admin/search/users.rabl +23 -25
  31. data/app/views/spree/admin/shared/_head.html.erb +1 -1
  32. data/app/views/spree/admin/shared/_routes.html.erb +3 -2
  33. data/app/views/spree/admin/shared/_translations.html.erb +3 -0
  34. data/app/views/spree/admin/shipping_methods/_form.html.erb +1 -1
  35. data/app/views/spree/admin/variants/_autocomplete.js.erb +2 -2
  36. data/app/views/spree/admin/variants/search.rabl +8 -10
  37. data/app/views/spree/checkout/payment/_gateway.html.erb +2 -2
  38. data/app/views/spree/order_mailer/cancel_email.text.erb +2 -2
  39. data/app/views/spree/order_mailer/confirm_email.text.erb +2 -2
  40. data/app/views/spree/orders/_line_item.html.erb +1 -1
  41. data/app/views/spree/products/_cart_form.html.erb +6 -2
  42. data/app/views/spree/shared/_google_analytics.html.erb +8 -8
  43. data/app/views/spree/shared/_order_details.html.erb +3 -1
  44. data/config/locales/en.yml +9 -7
  45. data/config/routes.rb +9 -0
  46. data/db/migrate/20121126040517_add_last_ip_to_spree_orders.rb +5 -0
  47. data/lib/spree/core/calculated_adjustments.rb +2 -1
  48. data/lib/spree/core/controller_helpers/common.rb +5 -0
  49. data/lib/spree/core/controller_helpers/order.rb +1 -0
  50. data/lib/spree/core/search/base.rb +5 -1
  51. data/lib/spree/core/testing_support/capybara_ext.rb +79 -0
  52. data/lib/spree/core/version.rb +1 -1
  53. metadata +13 -6
  54. data/vendor/assets/javascripts/jquery.tokeninput.js +0 -860
@@ -1,4 +1,5 @@
1
1
  //= require_self
2
+ //= require admin/handlebar_extensions
2
3
  //= require admin/variant_autocomplete
3
4
  //= require admin/taxon_autocomplete
4
5
  //= require admin/spree-select2
@@ -157,6 +158,13 @@ $(document).ready(function(){
157
158
  el.attr("id", el.attr("id").replace(/\d+/, new_id))
158
159
  el.attr("name", el.attr("name").replace(/\d+/, new_id))
159
160
  })
161
+ // When cloning a new row, set the href of all icons to be an empty "#"
162
+ // This is so that clicking on them does not perform the actions for the
163
+ // duplicated row
164
+ new_table_row.find("a").each(function () {
165
+ var el = $(this);
166
+ el.attr('href', '#');
167
+ })
160
168
  $(target).prepend(new_table_row);
161
169
  })
162
170
 
@@ -183,8 +191,26 @@ $(document).ready(function(){
183
191
  });
184
192
 
185
193
  $('body').on('click', 'a.remove_fields', function() {
186
- $(this).prev("input[type=hidden]").val("1");
187
- $(this).closest(".fields").hide();
194
+ el = $(this);
195
+ el.prev("input[type=hidden]").val("1");
196
+ el.closest(".fields").hide();
197
+ if (el.attr("href")) {
198
+ $.ajax({
199
+ type: 'POST',
200
+ url: el.attr("href"),
201
+ data: {
202
+ _method: 'delete',
203
+ authenticity_token: AUTH_TOKEN
204
+ },
205
+ success: function(response) {
206
+ el.parents("tr").fadeOut('hide');
207
+ },
208
+ error: function(response, textStatus, errorThrown) {
209
+ show_flash_error(response.responseText);
210
+ }
211
+
212
+ })
213
+ }
188
214
  return false;
189
215
  });
190
216
 
@@ -1,108 +1,68 @@
1
- $(document).ready(function(){
2
-
3
- add_address = function(addr){
4
- var html = "";
5
- if(addr!=undefined){
6
- html += addr['firstname'] + " " + addr['lastname'] + ", ";
7
- html += addr['address1'] + ", " + addr['address2'] + ", ";
8
- html += addr['city'] + ", ";
9
-
10
- if(addr['state_id']!=null){
11
- html += addr['state']['name'] + ", ";
12
- }else{
13
- html += addr['state_name'] + ", ";
14
- }
15
-
16
- html += addr['country']['name'];
17
- }
18
- return html;
19
- }
20
-
21
- format_user_autocomplete = function(item){
22
- var data = item.data
23
- var html = "<h4>" + data['email'] +"</h4>";
24
- html += "<span><strong>Billing:</strong> ";
25
- html += add_address(data['bill_address']);
26
- html += "</span>";
27
-
28
- html += "<span><strong>Shipping:</strong> ";
29
- html += add_address(data['ship_address']);
30
- html += "</span>";
31
-
32
- return html
33
- }
34
-
35
- prep_user_autocomplete_data = function(data){
36
- return $.map(eval(data['users']), function(row) {
37
- return {
38
- data: row,
39
- value: row['email'],
40
- result: row['email']
41
- }
42
- });
1
+ $(document).ready(function() {
2
+ window.customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text());
3
+
4
+ formatCustomerResult = function(customer) {
5
+ return customerTemplate({
6
+ customer: customer,
7
+ bill_address: customer.bill_address,
8
+ ship_address: customer.ship_address
9
+ })
43
10
  }
44
11
 
45
12
  if ($("#customer_search").length > 0) {
46
- $("#customer_search").autocomplete({
47
- minChars: 5,
48
- delay: 500,
49
- source: function(request, response) {
50
- var params = { q: $('#customer_search').val(),
51
- authenticity_token: AUTH_TOKEN }
52
- $.get(Spree.routes.user_search + '&' + jQuery.param(params), function(data) {
53
- result = prep_user_autocomplete_data(data)
54
- response(result);
55
- });
56
- },
57
- focus: function(event, ui) {
58
- $('#customer_search').val(ui.item.label);
59
- $(ui).addClass('ac_over');
60
- return false;
13
+ $("#customer_search").select2({
14
+ placeholder: Spree.translations.choose_a_customer,
15
+ ajax: {
16
+ url: Spree.routes.user_search,
17
+ datatype: 'json',
18
+ data: function(term, page) {
19
+ return { q: term }
20
+ },
21
+ results: function(data, page) {
22
+ return { results: data }
23
+ }
61
24
  },
62
- select: function(event, ui) {
63
- $('#customer_search').val(ui.item.label);
64
- _.each(['bill', 'ship'], function(addr_name){
65
- var addr = ui.item.data[addr_name + '_address'];
66
- if(addr!=undefined){
67
- $('#order_' + addr_name + '_address_attributes_firstname').val(addr['firstname']);
68
- $('#order_' + addr_name + '_address_attributes_lastname').val(addr['lastname']);
69
- $('#order_' + addr_name + '_address_attributes_company').val(addr['company']);
70
- $('#order_' + addr_name + '_address_attributes_address1').val(addr['address1']);
71
- $('#order_' + addr_name + '_address_attributes_address2').val(addr['address2']);
72
- $('#order_' + addr_name + '_address_attributes_city').val(addr['city']);
73
- $('#order_' + addr_name + '_address_attributes_zipcode').val(addr['zipcode']);
74
- $('#order_' + addr_name + '_address_attributes_state_id').val(addr['state_id']);
75
- $('#order_' + addr_name + '_address_attributes_country_id').val(addr['country_id']);
76
- $('#order_' + addr_name + '_address_attributes_phone').val(addr['phone']);
25
+ formatResult: formatCustomerResult,
26
+ formatSelection: function (customer) {
27
+ _.each(['bill_address', 'ship_address'], function(address) {
28
+ var data = customer[address];
29
+ address_parts = ['firstname', 'lastname',
30
+ 'company', 'address1',
31
+ 'address2', 'city',
32
+ 'zipcode', 'phone']
33
+ var attribute_wrapper = '#order_' + address + '_attributes_'
34
+ if(data != undefined) {
35
+ _.each(address_parts, function(part) {
36
+ $(attribute_wrapper + part).val(data[part]);
37
+ })
38
+
39
+ $(attribute_wrapper + 'state_id').select2("val", data['state_id']);
40
+ $(attribute_wrapper + 'country_id').select2("val", data['country_id']);
41
+ }
42
+ else {
43
+ _.each(address_parts, function(part) {
44
+ $(attribute_wrapper + part).val("");
45
+ })
46
+
47
+ $(attribute_wrapper + 'state_id').select2("val", '');
48
+ $(attribute_wrapper + 'country_id').select2("val", '');
77
49
  }
78
50
  });
79
51
 
80
- $('#order_email').val(ui.item.data['email']);
81
- $('#user_id').val(ui.item.data['id']);
52
+ $('#order_email').val(customer.email);
53
+ $('#user_id').val(customer.id);
82
54
  $('#guest_checkout_true').prop("checked", false);
83
55
  $('#guest_checkout_false').prop("checked", true);
84
56
  $('#guest_checkout_false').prop("disabled", false);
85
- return true;
86
- }
87
- }).data("autocomplete")._renderItem = function(ul, item) {
88
- $(ul).addClass('ac_results');
89
- html = format_user_autocomplete(item);
90
- return $("<li></li>")
91
- .data("item.autocomplete", item)
92
- .append("<a class='ui-menu-item'>" + html + "</a>")
93
- .appendTo(ul);
94
- }
95
-
96
- $("#customer_search").data("autocomplete")._resizeMenu = function() {
97
- var ul = this.menu.element;
98
- ul.outerWidth(this.element.outerWidth());
99
- }
100
-
101
57
 
58
+ return customer.email;
59
+ }
60
+ })
102
61
  }
103
62
 
104
- var show_billing = function(show) {
105
- if(show) {
63
+
64
+ $('input#order_use_billing').click(function() {
65
+ if(!$(this).is(':checked')) {
106
66
  $('#shipping').show();
107
67
  $('#shipping input').prop("disabled", false);
108
68
  $('#shipping select').prop("disabled", false);
@@ -111,10 +71,6 @@ $(document).ready(function(){
111
71
  $('#shipping input').prop("disabled", true);
112
72
  $('#shipping select').prop("disabled", true);
113
73
  }
114
- }
115
-
116
- $('input#order_use_billing').click(function() {
117
- show_billing(!$(this).is(':checked'));
118
74
  });
119
75
 
120
76
  $('#guest_checkout_true').change(function() {
@@ -0,0 +1,9 @@
1
+ //= require handlebars
2
+ Handlebars.registerHelper("t", function(key) {
3
+ if (Spree.translations[key]) {
4
+ return Spree.translations[key]
5
+ } else {
6
+ console.error("No translation found for " + key + ". Does it exist within spree/admin/shared/_translations.html.erb?")
7
+ }
8
+ });
9
+
@@ -1,24 +1,22 @@
1
1
  //= require select2
2
2
  jQuery(function($) {
3
- <% unless Rails.env.test? %>
4
- // Make select beautiful
5
- $('select.select2').select2({
6
- allowClear: true
7
- });
3
+ // Make select beautiful
4
+ $('select.select2').select2({
5
+ allowClear: true
6
+ });
8
7
 
9
- function format_taxons(taxon) {
10
- new_taxon = taxon.text.replace('->', '<i class="icon-arrow-right">')
11
- return new_taxon;
12
- }
8
+ function format_taxons(taxon) {
9
+ new_taxon = taxon.text.replace('->', '<i class="icon-arrow-right">')
10
+ return new_taxon;
11
+ }
13
12
 
14
- $("#product_taxon_ids").on({
15
- change: function(e){
16
- $('.select2-search-choice .with-tip').powerTip({
17
- smartPlacement: true,
18
- fadeInTime: 50,
19
- fadeOutTime: 50
20
- })
21
- }
22
- })
23
- <% end %>
13
+ $("#product_taxon_ids").on({
14
+ change: function(e){
15
+ $('.select2-search-choice .with-tip').powerTip({
16
+ smartPlacement: true,
17
+ fadeInTime: 50,
18
+ fadeOutTime: 50
19
+ })
20
+ }
21
+ })
24
22
  })
@@ -1,7 +1,6 @@
1
1
  //= require jquery-ui
2
2
  //= require modernizr
3
3
  //= require jquery.cookie
4
- //= require jquery.tokeninput
5
4
  //= require jquery.delayedobserver
6
5
  //= require jquery.jstree/jquery.jstree
7
6
  //= require jquery.alerts/jquery.alerts
@@ -0,0 +1,9 @@
1
+ $(document).ready(function() {
2
+ $("#country").change(function() {
3
+ var new_state_link_href = $('#new_state_link a').attr('href');
4
+ var selected_country_id = $('#country option:selected').attr('value');
5
+ var new_link = new_state_link_href.replace(/countries\/(\d+)/,
6
+ 'countries/'+selected_country_id);
7
+ $('#new_state_link a').attr('href', new_link);
8
+ });
9
+ });
@@ -8,7 +8,7 @@ function cleanTaxons(data) {
8
8
  $(document).ready(function() {
9
9
  if ($("#product_taxon_ids").length > 0) {
10
10
  $("#product_taxon_ids").select2({
11
- placeholder: "Add a taxon",
11
+ placeholder: Spree.translations.taxon_placeholder,
12
12
  multiple: true,
13
13
  initSelection: function(element, callback) {
14
14
  return $.getJSON(Spree.routes.taxon_search + "?ids=" + (element.val()), null, function(data) {
@@ -1,4 +1,3 @@
1
- //= require handlebars
2
1
  <%#encoding: UTF-8%>
3
2
  // variant autocompletion
4
3
 
@@ -10,7 +9,7 @@ formatVariantResult = function(variant) {
10
9
  if (variant["images"][0] != undefined) {
11
10
  variant.image = variant.images[0].image.mini_url
12
11
  }
13
- return variantTemplate({ variant: variant, translations: Spree.translations })
12
+ return variantTemplate({ variant: variant })
14
13
  }
15
14
 
16
15
  $.fn.variantAutocomplete = function() {
@@ -25,10 +24,7 @@ $.fn.variantAutocomplete = function() {
25
24
  return { q: term }
26
25
  },
27
26
  results: function (data, page) {
28
- var variants = $.map(data['variants'], function(result) {
29
- return result['variant']
30
- })
31
- return { results: variants }
27
+ return { results: data }
32
28
  }
33
29
  },
34
30
  formatResult: formatVariantResult,
@@ -69,11 +69,11 @@ $ ->
69
69
  ).triggerHandler 'click'
70
70
 
71
71
  if ($ '#checkout_form_payment').is('*')
72
- # Activate already checked payment method if form is re-rendered
73
- # i.e. if user enters invalid data
74
- ($ 'input[type="radio"]:checked').click()
75
-
76
72
  ($ 'input[type="radio"][name="order[payments_attributes][][payment_method_id]"]').click(->
77
73
  ($ '#payment-methods li').hide()
78
74
  ($ '#payment_method_' + @value).show() if @checked
79
75
  )
76
+
77
+ # Activate already checked payment method if form is re-rendered
78
+ # i.e. if user enters invalid data
79
+ ($ 'input[type="radio"]:checked').click()
@@ -610,6 +610,14 @@ mark {background-color: $link_text_color; color: $layout_background_color; font-
610
610
  /*--------------------------------------*/
611
611
  /* Checkout
612
612
  /*--------------------------------------*/
613
+ .out-of-stock {
614
+ background: #df0000;
615
+ color: white;
616
+ padding: 5px;
617
+ padding-right: 10px;
618
+ font-weight: bold;
619
+ }
620
+
613
621
  .progress-steps {
614
622
  list-style: decimal inside;
615
623
  overflow: auto;
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Admin
3
+ class OptionValuesController < Spree::Admin::BaseController
4
+ def destroy
5
+ option_value = Spree::OptionValue.find(params[:id])
6
+ option_value.destroy
7
+ render :text => nil
8
+ end
9
+ end
10
+ end
11
+ end
@@ -5,6 +5,18 @@ module Spree
5
5
  before_filter :find_properties
6
6
  before_filter :setup_property, :only => [:index]
7
7
 
8
+ # We use a "custom" finder in destroy
9
+ # Because the request is scoped without a product
10
+ # on account of the request coming from the "link_to_remove_fields"
11
+ # helper on the admin/product_properties view
12
+ skip_before_filter :load_resource, :only => [:destroy]
13
+
14
+ def destroy
15
+ product_property = Spree::ProductProperty.find(params[:id])
16
+ product_property.destroy
17
+ render :text => nil
18
+ end
19
+
8
20
  private
9
21
  def find_properties
10
22
  @properties = Spree::Property.pluck(:name)
@@ -16,6 +16,15 @@ module Spree
16
16
  respond_with(@collection)
17
17
  end
18
18
 
19
+ def search
20
+ if params[:ids]
21
+ @products = Spree::Product.where(:id => params[:ids].split(","))
22
+ else
23
+ search_params = { :name_cont => params[:q], :sku_cont => params[:q] }
24
+ @products = Spree::Product.ransack(search_params.merge(:m => 'or')).result
25
+ end
26
+ end
27
+
19
28
  def update
20
29
  if params[:product][:taxon_ids].present?
21
30
  params[:product][:taxon_ids] = params[:product][:taxon_ids].split(',')
@@ -132,13 +132,6 @@ module Spree
132
132
  }.join("<br />").html_safe
133
133
  end
134
134
 
135
- def product_picker_field(name, value)
136
- products = Product.with_ids(value.split(','))
137
- product_names = products.inject({}){|memo,item| memo[item.id] = item.name; memo}
138
- product_rules = products.collect{ |p| { :id => p.id, :name => p.name } }
139
- %(<input type="text" name="#{name}" value="#{value}" class="tokeninput products" data-names='#{product_names.to_json}' data-pre='#{product_rules.to_json}'/>).html_safe
140
- end
141
-
142
135
  def link_to_add_fields(name, target, options = {})
143
136
  name = '' if options[:no_text]
144
137
  css_classes = options[:class] ? options[:class] + " add_fields" : "add_fields"
@@ -150,7 +143,8 @@ module Spree
150
143
  name = '' if options[:no_text]
151
144
  options[:class] = '' unless options[:class]
152
145
  options[:class] += 'no-text with-tip' if options[:no_text]
153
- link_to_with_icon('icon-trash', name, '#', :class => "remove_fields #{options[:class]}", :data => {:action => 'remove'}, :title => t(:remove)) + f.hidden_field(:_destroy)
146
+ url = f.object.persisted? ? [:admin, f.object] : '#'
147
+ link_to_with_icon('icon-trash', name, url, :class => "remove_fields #{options[:class]}", :data => {:action => 'remove'}, :title => t(:remove)) + f.hidden_field(:_destroy)
154
148
  end
155
149
 
156
150
  def spree_dom_id(record)
@@ -61,6 +61,7 @@ module Spree
61
61
  preference :show_only_complete_orders_by_default, :boolean, :default => true
62
62
  preference :show_zero_stock_products, :boolean, :default => true
63
63
  preference :show_variant_full_price, :boolean, :default => false #Displays variant full price or difference with product price. Default false to be compatible with older behavior
64
+ preference :show_products_without_price, :boolean, :default => false
64
65
  preference :site_name, :string, :default => 'Spree Demo Site'
65
66
  preference :site_url, :string, :default => 'demo.spreecommerce.com'
66
67
  preference :tax_using_ship_address, :boolean, :default => true