spree_core 1.0.0.rc3 → 1.0.0.rc4

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 (38) hide show
  1. data/app/assets/images/admin/payment_banner.png +0 -0
  2. data/app/assets/javascripts/admin/admin.js.erb +16 -5
  3. data/app/assets/javascripts/admin/spree_core.js +0 -1
  4. data/app/assets/javascripts/store/spree_core.js +0 -1
  5. data/app/assets/stylesheets/admin/admin.css.erb +57 -3
  6. data/app/assets/stylesheets/store/screen.css.scss +72 -29
  7. data/app/assets/stylesheets/store/spree_core.css +5 -4
  8. data/app/controllers/spree/admin/tax_categories_controller.rb +13 -0
  9. data/app/controllers/spree/admin/users_controller.rb +16 -0
  10. data/app/controllers/spree/products_controller.rb +1 -1
  11. data/app/helpers/spree/admin/navigation_helper.rb +3 -1
  12. data/app/models/spree/payment_method.rb +2 -0
  13. data/app/models/spree/preferences/preferable.rb +32 -1
  14. data/app/models/spree/preferences/preferable_class_methods.rb +21 -4
  15. data/app/models/spree/product.rb +4 -3
  16. data/app/models/spree/tax_category.rb +7 -1
  17. data/app/models/spree/tax_rate.rb +4 -1
  18. data/app/models/spree/user.rb +2 -0
  19. data/app/views/spree/admin/banners/_gateway.html.erb +14 -0
  20. data/app/views/spree/admin/images/index.html.erb +4 -4
  21. data/app/views/spree/admin/option_types/index.html.erb +2 -2
  22. data/app/views/spree/admin/payment_methods/index.html.erb +2 -0
  23. data/app/views/spree/admin/variants/index.html.erb +2 -2
  24. data/app/views/spree/orders/_line_item.html.erb +4 -4
  25. data/app/views/spree/shared/_order_details.html.erb +8 -9
  26. data/config/locales/en.yml +4 -0
  27. data/config/routes.rb +6 -3
  28. data/db/migrate/20120203153759_add_deleted_at_to_tax_category.rb +5 -0
  29. data/lib/spree/core/middleware/seo_assist.rb +1 -1
  30. data/lib/spree/core/user_banners.rb +25 -0
  31. data/lib/spree/core/version.rb +1 -1
  32. data/vendor/assets/images/jquery.formalize/button.png +0 -0
  33. data/vendor/assets/images/jquery.formalize/select_arrow.gif +0 -0
  34. data/vendor/assets/stylesheets/html5reset.css +177 -0
  35. data/vendor/assets/stylesheets/{jquery.formalize.css → jquery.formalize.css.erb} +3 -3
  36. data/{app/assets/stylesheets/store/base.css → vendor/assets/stylesheets/skeleton.css} +14 -159
  37. metadata +37 -31
  38. data/app/assets/javascripts/store/helpers.js.erb +0 -2
@@ -1,4 +1,3 @@
1
- //= require store/helpers
2
1
  //= require_self
3
2
 
4
3
  /**
@@ -17,6 +16,20 @@ $(document).ajaxStop(function(){
17
16
 
18
17
  $.fn.visible = function(cond) { this[cond ? 'show' : 'hide' ]() };
19
18
 
19
+ show_flash_error = function(message) {
20
+ error_div = $('.flash.error');
21
+ if (error_div.length > 0) {
22
+ error_div.html(message);
23
+ error_div.show();
24
+ } else {
25
+ if ($("#content .toolbar").length > 0) {
26
+ $("#content .toolbar").before('<div class="flash error">' + message + '</div>');
27
+ } else {
28
+ $("#content h1").before('<div class="flash error">' + message + '</div>');
29
+ }
30
+ }
31
+ }
32
+
20
33
  // Apply to individual radio button that makes another element visible when checked
21
34
  $.fn.radioControlsVisibilityOfElement = function(dependentElementSelector){
22
35
  if(!this.get(0)){ return }
@@ -227,19 +240,17 @@ $(document).ready(function(){
227
240
  update: function(event, ui) {
228
241
  $("#progress").show();
229
242
  positions = {};
230
- type = '';
231
243
  $.each($('table.sortable tbody tr'), function(position, obj){
232
244
  reg = /spree_(\w+_?)+_(\d+)/;
233
245
  parts = reg.exec($(obj).attr('id'));
234
246
  if (parts) {
235
247
  positions['positions['+parts[2]+']'] = position;
236
- type = parts[1];
237
248
  }
238
249
  });
239
250
  $.ajax({
240
251
  type: 'POST',
241
252
  dataType: 'script',
242
- url: Spree.base_path + 'admin/' + type + 's/update_positions',
253
+ url: $(ui.item).closest("table.sortable").data("sortable-link"),
243
254
  data: positions,
244
255
  success: function(data){ $("#progress").hide(); }
245
256
  });
@@ -250,7 +261,7 @@ $(document).ready(function(){
250
261
  });
251
262
 
252
263
  jQuery(document).ready(function() {
253
- $('div.alert a.dismiss').click(function() {
264
+ $('a.dismiss').click(function() {
254
265
  $(this).parent().fadeOut();
255
266
  });
256
267
  });
@@ -6,5 +6,4 @@
6
6
  //= require jquery.delayedobserver
7
7
  //= require jquery.jstree/jquery.jstree
8
8
  //= require jquery.alerts/jquery.alerts
9
- //= require store/helpers
10
9
  //= require_tree .
@@ -5,4 +5,3 @@
5
5
  //= require store/checkout
6
6
  //= require store/product
7
7
  //= require store/cart
8
- //= require store/helpers
@@ -616,17 +616,71 @@ span.handle{
616
616
  font-size: 0.8em;
617
617
  }
618
618
  .alert.release {
619
- background: #ccddff url(../images/shadow_top.png) 0px -50px repeat-x;
619
+ background-color: #ccddff;
620
620
  color: #556699;
621
621
  border: 1px solid #99aacc;
622
622
  }
623
623
  .alert.security {
624
- background: #f4b4b4 url(../images/shadow_top.png) 0px -50px repeat-x;
624
+ background-color: #f4b4b4;
625
625
  color: #000000;
626
626
  border: 1px solid #e75b5b;
627
627
  }
628
628
  .alert.news {
629
- background: #ccffd4 url(../images/shadow_top.png) 0px -50px repeat-x;
629
+ background-color: #ccffd4;
630
630
  color: #000000;
631
631
  border: 1px solid #66ff7e;
632
632
  }
633
+
634
+ /* Spree analytics preview buttons */
635
+ .analytics_splash{
636
+ text-align: center;
637
+ }
638
+ .preview-buttons {
639
+ position: absolute;
640
+ left: 860px;
641
+ top: 820px;
642
+ }
643
+ .preview-buttons a.button {
644
+ display: inline-block;
645
+ float: none;
646
+ font-size: 14px;
647
+ }
648
+
649
+ /* Spree admin banners*/
650
+ .banner {
651
+ overflow: auto;
652
+ }
653
+ .banner p {
654
+ text-transform: uppercase;
655
+ font-weight: bold;
656
+ }
657
+ .banner .button {
658
+ float: none !important;
659
+ display: inline-block;
660
+ }
661
+
662
+ .banner.payment_banner {
663
+ width: 739px;
664
+ height: 135px;
665
+ background: transparent url(<%= asset_path 'admin/payment_banner.png' %>) no-repeat left top;
666
+ position: absolute;
667
+ left: -17px;
668
+ }
669
+ .banner.payment_banner .message {
670
+ padding-left: 40px;
671
+ padding-top: 35px;
672
+ font-size: 16px;
673
+ width: 500px;
674
+ color: #5A81B3;
675
+ line-height: 25px;
676
+ }
677
+ .banner.payment_banner .message a {
678
+ color: #82a653 !important;
679
+ }
680
+
681
+ .banner.payment_banner .dismiss {
682
+ color: #B25B59 !important;
683
+ font-weight: bold;
684
+ float: right;
685
+ margin-right: 25px;
686
+ }
@@ -2,13 +2,18 @@
2
2
  /* Colors
3
3
  /*--------------------------------------*/
4
4
  $c_base: #404042; /* Dark gray */
5
- $c_gray1: #bbbbbb; /* Mid light gray */
5
+ $c_gray: #bbbbbb; /* Mid light gray */
6
6
  $c_colored: #00ADEE; /* Light blue */
7
7
  $c_colored_alt: #f0f8ff; /* Lighter blue */
8
8
  $c_border: #dedede; /* Light gray */
9
9
  $c_green: #8dba53; /* Spree green */
10
10
  $c_red: #e45353; /* Error red */
11
11
 
12
+ /*--------------------------------------*/
13
+ /* Fonts
14
+ /*--------------------------------------*/
15
+ @import url(http://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic|&subset=latin,cyrillic,greek,greek-ext,latin-ext,cyrillic-ext);
16
+
12
17
  /*--------------------------------------*/
13
18
  /* Basic styles
14
19
  /*--------------------------------------*/
@@ -19,6 +24,11 @@ body {
19
24
  font-size: 12px;
20
25
  }
21
26
 
27
+ /* Line style */
28
+ hr {
29
+ border-color: $c_border;
30
+ }
31
+
22
32
  /* Custom text-selection colors (remove any text shadows: twitter.com/miketaylr/status/12228805301) */
23
33
  ::-moz-selection{background: $c_colored; color: white; text-shadow: none;}
24
34
  ::selection {background: $c_colored; color: white; text-shadow: none;}
@@ -55,27 +65,25 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
55
65
  }
56
66
  }
57
67
  }
58
-
59
68
 
60
- dl {
61
- dt, dd {
62
- display: inline-block;
63
- width: 50%;
64
- padding: 5px;
69
+ dl {
70
+ dt, dd {
71
+ display: inline-block;
72
+ width: 50%;
73
+ padding: 5px;
65
74
 
66
- &.odd {
67
- background-color: $c_border;
68
- }
69
- }
70
- dt {
71
- font-weight: bold;
72
- text-transform: uppercase;
73
- }
74
- dd {
75
- margin-left: -23px;
75
+ &.odd {
76
+ background-color: $c_border;
76
77
  }
77
78
  }
78
-
79
+ dt {
80
+ font-weight: bold;
81
+ text-transform: uppercase;
82
+ }
83
+ dd {
84
+ margin-left: -23px;
85
+ }
86
+ }
79
87
 
80
88
  /*--------------------------------------*/
81
89
  /* Headers
@@ -90,7 +98,6 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
90
98
  h5 { font-size: 16px; line-height: 26px; }
91
99
  h6 { font-size: 14px; line-height: 24px; }
92
100
 
93
-
94
101
  /*--------------------------------------*/
95
102
  /* Forms
96
103
  /*--------------------------------------*/
@@ -121,6 +128,13 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
121
128
  select {
122
129
  border: 1px solid $c_border;
123
130
  font-family: "Ubuntu", sans-serif;
131
+ background-image: url('select_arrow.gif');
132
+ background-repeat: no-repeat;
133
+ background-position: right center;
134
+
135
+ &:active, &:focus {
136
+ @extend input[type="text"]:focus
137
+ }
124
138
  }
125
139
 
126
140
  label.error {
@@ -142,7 +156,6 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
142
156
  -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
143
157
  -khtml-box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
144
158
  -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
145
- -ms-box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
146
159
  -o-box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
147
160
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
148
161
  -webkit-border-radius: 0px;
@@ -290,7 +303,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
290
303
  font-weight: bold;
291
304
  border-left: 1px solid $c_border;
292
305
  padding-left: 5px;
293
- padding-bottom: 8px;
306
+ padding-bottom: 5px;
294
307
  }
295
308
  }
296
309
  }
@@ -386,7 +399,10 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
386
399
  margin-top: 15px;
387
400
 
388
401
  input[type="number"] {
389
- width: 40px;
402
+ width: 60px;
403
+ vertical-align: middle;
404
+ padding: 5px;
405
+ height: 35px;
390
406
  }
391
407
  }
392
408
 
@@ -417,7 +433,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
417
433
  &.info {
418
434
  height: 35px;
419
435
  margin-top: 5px;
420
- color: $c_gray1;
436
+ color: $c_gray;
421
437
  border-bottom: 1px solid $c_border;
422
438
  }
423
439
  }
@@ -534,7 +550,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
534
550
  font-weight: bold;
535
551
  text-transform: uppercase;
536
552
  padding: 5px 20px;
537
- color: $c_gray1;
553
+ color: $c_gray;
538
554
 
539
555
  &.current-first, &.current {
540
556
  background-color: $c_colored;
@@ -638,7 +654,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
638
654
 
639
655
  table tfoot {
640
656
  text-align: right;
641
- color: $c_gray1;
657
+ color: $c_gray;
642
658
 
643
659
  tr {
644
660
  border: none;
@@ -723,7 +739,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
723
739
  #subtotal {
724
740
  text-align: right;
725
741
  text-transform: uppercase;
726
- margin-top: 10px;
742
+ margin-top: 15px;
727
743
 
728
744
  span.order-total {
729
745
  @extend span.price;
@@ -878,6 +894,33 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
878
894
  }
879
895
  }
880
896
 
897
+ table#cart-detail, table[data-hook="order_details"] {
898
+ tbody {
899
+ tr {
900
+ td[data-hook="cart_item_description"], td[data-hook="order_item_description"] {
901
+ font-size: 11px;
902
+ line-height: 15px;
903
+ width: 100px;
904
+
905
+ h4 {
906
+ font-size: 14px;
907
+ line-height: 17px;
908
+ margin-bottom: 10px;
909
+ }
910
+ }
911
+ td[data-hook="cart_item_price"], td[data-hook="cart_item_total"],
912
+ td[data-hook="order_item_price"], td[data-hook="order_item_total"] {
913
+ font-size: 12px !important;
914
+ }
915
+ td[data-hook="cart_item_image"], td[data-hook="order_item_image"] {
916
+ img {
917
+ width: 70px;
918
+ }
919
+ }
920
+ }
921
+ }
922
+ }
923
+
881
924
  }
882
925
 
883
926
 
@@ -907,10 +950,10 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
907
950
  margin-top: 0;
908
951
  }
909
952
 
910
- table#cart-detail {
953
+ table#cart-detail, table[data-hook="order_details"] {
911
954
  tbody {
912
955
  tr {
913
- td[data-hook="cart_item_description"] {
956
+ td[data-hook="cart_item_description"], td[data-hook="order_item_description"] {
914
957
  padding: 0 !important;
915
958
  text-indent: -9999px;
916
959
 
@@ -918,7 +961,7 @@ mark {background-color: $c_colored; color: white; font-style: italic; font-weigh
918
961
  display: none;
919
962
  }
920
963
  }
921
- td[data-hook="cart_item_image"] {
964
+ td[data-hook="cart_item_image"], td[data-hook="order_item_image"] {
922
965
  img {
923
966
  width: 70px;
924
967
  }
@@ -1,6 +1,7 @@
1
1
  /*
2
- * This is a manifest file that includes stylesheets for spree_core
3
- *= require store/base
4
- *= require jquery.formalize.css
2
+ * This is a manifest file that includes stylesheets for spree_core
3
+ *= require html5reset
4
+ *= require skeleton
5
+ *= require jquery.formalize
5
6
  *= require store/screen
6
- */
7
+ */
@@ -1,6 +1,19 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class TaxCategoriesController < ResourceController
4
+ def destroy
5
+ if @object.mark_deleted!
6
+ flash.notice = flash_message_for(@object, :successfully_removed)
7
+ respond_with(@object) do |format|
8
+ format.html { redirect_to collection_url }
9
+ format.js { render :partial => "spree/admin/shared/destroy" }
10
+ end
11
+ else
12
+ respond_with(@object) do |format|
13
+ format.html { redirect_to collection_url }
14
+ end
15
+ end
16
+ end
4
17
  end
5
18
  end
6
19
  end
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class UsersController < ResourceController
4
+ rescue_from User::DestroyWithOrdersError, :with => :user_destroy_with_orders_error
5
+
4
6
  # http://spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/
5
7
  before_filter :check_json_authenticity, :only => :index
6
8
  before_filter :load_roles, :only => [:edit, :new, :update, :create]
@@ -16,6 +18,13 @@ module Spree
16
18
  end
17
19
  end
18
20
 
21
+ def dismiss_banner
22
+ if request.xhr? and params[:banner_id]
23
+ current_user.dismiss_banner(params[:banner_id])
24
+ render :nothing => true
25
+ end
26
+ end
27
+
19
28
  protected
20
29
  def collection
21
30
  return @collection if @collection.present?
@@ -48,6 +57,13 @@ module Spree
48
57
  end
49
58
 
50
59
  private
60
+
61
+ # handling raise from Admin::ResourceController#destroy
62
+ def user_destroy_with_orders_error
63
+ invoke_callbacks(:destroy, :fails)
64
+ render :status => :forbidden, :text => t(:error_user_destroy_with_orders)
65
+ end
66
+
51
67
  # Allow different formats of json data to suit different ajax calls
52
68
  def json_data
53
69
  json_format = params[:json_format] or 'default'
@@ -7,7 +7,7 @@ module Spree
7
7
  respond_to :html
8
8
 
9
9
  def index
10
- @searcher = Spree::Config.searcher_class.new(params)
10
+ @searcher = Config.searcher_class.new(params)
11
11
  @products = @searcher.retrieve_products
12
12
  respond_with(@products)
13
13
  end
@@ -64,6 +64,7 @@ module Spree
64
64
  options.reverse_merge! :title => t(:confirm_delete)
65
65
  options.reverse_merge! :dataType => 'script'
66
66
  options.reverse_merge! :success => "function(r){ $('##{dom_id resource}').fadeOut('hide'); }"
67
+ options.reverse_merge! :error => "function(jqXHR, textStatus, errorThrown){ show_flash_error(jqXHR.responseText); }"
67
68
  options.reverse_merge! :name => icon('delete') + ' ' + t(:delete)
68
69
 
69
70
  link_to_function_delete(options, html_options)
@@ -92,7 +93,8 @@ module Spree
92
93
  url: '#{options[:url]}',
93
94
  data: ({_method: 'delete', authenticity_token: AUTH_TOKEN}),
94
95
  dataType:'#{options[:dataType]}',
95
- success: #{options[:success]}
96
+ success: #{options[:success]},
97
+ error: #{options[:error]}
96
98
  });
97
99
  }
98
100
  end
@@ -3,6 +3,8 @@ module Spree
3
3
  DISPLAY = [:both, :front_end, :back_end]
4
4
  default_scope where(:deleted_at => nil)
5
5
 
6
+ scope :production, where(:environment => 'production')
7
+
6
8
  def self.providers
7
9
  Rails.application.config.spree.payment_methods
8
10
  end
@@ -1,3 +1,8 @@
1
+ # The preference_cache_key is used to determine if the preference
2
+ # can be set. The default behavior is to return nil if there is no
3
+ # id value. On ActiveRecords, new objects will have their preferences
4
+ # saved to a pending hash until it is persisted.
5
+ #
1
6
  # class_attributes are inheritied unless you reassign them in
2
7
  # the subclass, so when you inherit a Preferable class, the
3
8
  # inherited hook will assign a new hash for the subclass definitions
@@ -8,11 +13,19 @@ module Spree::Preferences::Preferable
8
13
  def self.included(base)
9
14
  base.class_eval do
10
15
  extend Spree::Preferences::PreferableClassMethods
16
+
17
+ if respond_to?(:after_create)
18
+ after_create do |obj|
19
+ obj.save_pending_preferences
20
+ end
21
+ end
22
+
11
23
  if respond_to?(:after_destroy)
12
24
  after_destroy do |obj|
13
25
  obj.clear_preferences
14
26
  end
15
27
  end
28
+
16
29
  end
17
30
  end
18
31
 
@@ -64,7 +77,15 @@ module Spree::Preferences::Preferable
64
77
  end
65
78
 
66
79
  def preference_cache_key(name)
67
- [self.class.name, name, (try(:id) || :new)].join('::').underscore
80
+ return unless id
81
+ [self.class.name, name, id].join('::').underscore
82
+ end
83
+
84
+ def save_pending_preferences
85
+ return unless @pending_preferences
86
+ @pending_preferences.each do |name, value|
87
+ set_preference(name, value)
88
+ end
68
89
  end
69
90
 
70
91
  def clear_preferences
@@ -73,6 +94,16 @@ module Spree::Preferences::Preferable
73
94
 
74
95
  private
75
96
 
97
+ def add_pending_preference(name, value)
98
+ @pending_preferences ||= {}
99
+ @pending_preferences[name] = value
100
+ end
101
+
102
+ def get_pending_preference(name)
103
+ return unless @pending_preferences
104
+ @pending_preferences[name]
105
+ end
106
+
76
107
  def preference_store
77
108
  Spree::Preferences::Store.instance
78
109
  end
@@ -7,11 +7,17 @@ module Spree::Preferences
7
7
  default = options[:default]
8
8
  description = options[:description] || name
9
9
 
10
+ # cache_key will be nil for new objects, then if we check if there
11
+ # is a pending preference before going to default
10
12
  define_method preference_getter_method(name) do
11
- if preference_store.exist? preference_cache_key(name)
13
+ if preference_cache_key(name) && preference_store.exist?(preference_cache_key(name))
12
14
  preference_store.get preference_cache_key(name)
13
15
  else
14
- send self.class.preference_default_getter_method(name)
16
+ if get_pending_preference(name)
17
+ get_pending_preference(name)
18
+ else
19
+ send self.class.preference_default_getter_method(name)
20
+ end
15
21
  end
16
22
  end
17
23
  alias_method prefers_getter_method(name), preference_getter_method(name)
@@ -20,9 +26,20 @@ module Spree::Preferences
20
26
  # Boolean attributes can come back from forms as '0' or '1'
21
27
  # Convert them to their correct values here
22
28
  if type == :boolean && !value.is_a?(TrueClass) && !value.is_a?(FalseClass)
23
- value = value.to_i == 1
29
+ value = value.downcase if value.respond_to? :downcase
30
+ case value
31
+ when 0, '0', 'false', 'f', "", []
32
+ value = false
33
+ else
34
+ value = true
35
+ end
36
+ end
37
+
38
+ if preference_cache_key(name)
39
+ preference_store.set preference_cache_key(name), value
40
+ else
41
+ add_pending_preference(name, value)
24
42
  end
25
- preference_store.set preference_cache_key(name), value
26
43
  end
27
44
  alias_method prefers_setter_method(name), preference_setter_method(name)
28
45
 
@@ -140,10 +140,11 @@ module Spree
140
140
  image_dup = lambda { |i| j = i.dup; j.attachment = i.attachment.clone; j }
141
141
  p.images = self.images.map { |i| image_dup.call i }
142
142
 
143
- variant = self.master.dup
144
- variant.sku = 'COPY OF ' + self.master.sku
143
+ master = Spree::Variant.find_by_product_id_and_is_master(self.id, true)
144
+ variant = master.dup
145
+ variant.sku = 'COPY OF ' + master.sku
145
146
  variant.deleted_at = nil
146
- variant.images = self.master.images.map { |i| image_dup.call i }
147
+ variant.images = master.images.map { |i| image_dup.call i }
147
148
  p.master = variant
148
149
 
149
150
  if self.has_variants?
@@ -1,11 +1,13 @@
1
1
  module Spree
2
2
  class TaxCategory < ActiveRecord::Base
3
- validates :name, :presence => true, :uniqueness => true
3
+ validates :name, :presence => true, :uniqueness => { :scope => :deleted_at }
4
4
 
5
5
  has_many :tax_rates, :dependent => :destroy
6
6
 
7
7
  before_save :set_default_category
8
8
 
9
+ default_scope where(:deleted_at => nil)
10
+
9
11
  def set_default_category
10
12
  #set existing default tax category to false if this one has been marked as default
11
13
 
@@ -14,5 +16,9 @@ module Spree
14
16
  end
15
17
  end
16
18
 
19
+ def mark_deleted!
20
+ self.deleted_at = Time.now
21
+ self.save
22
+ end
17
23
  end
18
24
  end
@@ -35,7 +35,10 @@ module Spree
35
35
  category = TaxCategory.includes(:tax_rates).where(:is_default => true).first
36
36
  return 0 unless category
37
37
 
38
- category.effective_amount || 0
38
+ address ||= Address.new(:country_id => Spree::Config[:default_country_id])
39
+ rate = category.tax_rates.detect { |rate| rate.zone.include? address }.try(:amount)
40
+
41
+ rate || 0
39
42
  end
40
43
 
41
44
  # Creates necessary tax adjustments for the order.
@@ -1,6 +1,8 @@
1
1
  # Default implementation of User. This class is intended to be modified by extensions (ex. spree_auth)
2
2
  module Spree
3
3
  class User < ActiveRecord::Base
4
+ include Core::UserBanners
5
+
4
6
  has_many :orders
5
7
 
6
8
  belongs_to :ship_address, :foreign_key => 'ship_address_id', :class_name => 'Spree::Address'
@@ -0,0 +1,14 @@
1
+ <% if !current_user.dismissed_banner?(:gateway) &&
2
+ Spree::PaymentMethod.production.where("type != 'Spree::Gateway::Bogus'").empty? %>
3
+
4
+ <div class="banner payment_banner">
5
+ <p class="message">
6
+ <%= t(:payment_processor_choose_banner_text)%>
7
+ <%= link_to t(:payment_processor_choose_link), "http://spreecommerce.com/products/gateway", :target => '_blank' %>
8
+ </p>
9
+
10
+ <%= link_to t(:dismiss_banner), dismiss_banner_admin_user_path(current_user, :banner_id => :gateway),
11
+ :remote => true, :method => :post, :class => 'dismiss' %>
12
+ </div>
13
+
14
+ <% end %>