spree 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of spree might be problematic. Click here for more details.

Files changed (181) hide show
  1. data/CHANGELOG +30 -0
  2. data/CONTRIBUTORS +38 -20
  3. data/app/controllers/admin/creditcard_payments_controller.rb +10 -3
  4. data/app/controllers/admin/orders_controller.rb +17 -16
  5. data/app/controllers/admin/products_controller.rb +12 -14
  6. data/app/controllers/admin/reports_controller.rb +12 -14
  7. data/app/controllers/admin/users_controller.rb +10 -5
  8. data/app/controllers/admin/zones_controller.rb +4 -1
  9. data/app/controllers/application.rb +0 -1
  10. data/app/controllers/checkout_controller.rb +96 -0
  11. data/app/controllers/content_controller.rb +11 -1
  12. data/app/controllers/orders_controller.rb +12 -33
  13. data/app/controllers/products_controller.rb +12 -7
  14. data/app/controllers/spree/base_controller.rb +1 -1
  15. data/app/controllers/states_controller.rb +14 -2
  16. data/app/controllers/taxons_controller.rb +6 -2
  17. data/app/controllers/users_controller.rb +9 -6
  18. data/app/helpers/application_helper.rb +1 -11
  19. data/app/helpers/products_helper.rb +3 -1
  20. data/app/helpers/spree/base_helper.rb +0 -26
  21. data/app/models/address.rb +3 -3
  22. data/app/models/app_configuration.rb +1 -0
  23. data/app/models/country.rb +4 -0
  24. data/app/models/creditcard.rb +6 -1
  25. data/app/models/creditcard_payment.rb +1 -1
  26. data/app/models/inventory_unit.rb +4 -1
  27. data/app/models/order.rb +37 -21
  28. data/app/models/product.rb +19 -8
  29. data/{vendor/extensions/shipping/app → app}/models/shipment.rb +20 -4
  30. data/{vendor/extensions/shipping/app → app}/models/shipping_category.rb +0 -0
  31. data/{vendor/extensions/shipping/app → app}/models/shipping_method.rb +6 -4
  32. data/app/models/state.rb +5 -0
  33. data/app/models/user.rb +4 -2
  34. data/app/models/variant.rb +19 -1
  35. data/app/presenters/checkout_presenter.rb +58 -0
  36. data/app/views/admin/creditcard_payments/edit.html.erb +1 -1
  37. data/app/views/admin/option_types/available.html.erb +1 -1
  38. data/app/views/admin/orders/index.html.erb +28 -18
  39. data/app/views/admin/orders/show.html.erb +1 -1
  40. data/app/views/admin/payments/index.html.erb +1 -1
  41. data/app/views/admin/products/_images.html.erb +1 -1
  42. data/app/views/admin/products/index.html.erb +17 -13
  43. data/app/views/admin/users/index.html.erb +8 -8
  44. data/app/views/admin/zones/index.html.erb +5 -2
  45. data/app/views/checkout/_form.html.erb +165 -0
  46. data/app/views/{creditcards → checkout}/cvv.html.erb +1 -1
  47. data/app/views/checkout/new.html.erb +6 -0
  48. data/app/views/layouts/admin.html.erb +2 -3
  49. data/app/views/layouts/application.html.erb +1 -1
  50. data/app/views/orders/_form.html.erb +6 -4
  51. data/app/views/orders/_google_order.html.erb +24 -0
  52. data/app/views/orders/_line_item.html.erb +2 -1
  53. data/app/views/orders/show.html.erb +4 -1
  54. data/app/views/products/index.html.erb +2 -1
  55. data/app/views/products/show.html.erb +4 -4
  56. data/app/views/shared/_footer.html.erb +12 -1
  57. data/app/views/shared/_login.html.erb +1 -1
  58. data/app/views/shared/_order_details.html.erb +8 -9
  59. data/app/views/shared/_products.html.erb +1 -1
  60. data/app/views/shared/_report_criteria.html.erb +28 -28
  61. data/app/views/states/index.js.erb +10 -1
  62. data/config/environment.rb +10 -4
  63. data/config/initializers/searchlogic.rb +6 -0
  64. data/config/locales/de.yml +14 -0
  65. data/config/locales/en-GB.yml +20 -6
  66. data/config/locales/en-US.yml +20 -4
  67. data/config/locales/es.yml +14 -0
  68. data/config/locales/fr-FR.yml +463 -0
  69. data/config/locales/fr-FR_rails.yml +115 -0
  70. data/config/locales/it.yml +14 -0
  71. data/config/locales/nb-NO.yml +457 -0
  72. data/config/locales/nb-NO_rails.yml +105 -0
  73. data/config/locales/pl.yml +14 -0
  74. data/config/locales/pt-BR.yml +14 -0
  75. data/config/locales/pt-PT.yml +14 -0
  76. data/config/locales/ru-RU.yml +458 -0
  77. data/config/locales/ru-RU_rails.yml +154 -0
  78. data/config/routes.rb +11 -4
  79. data/db/migrate/20090204200045_add_order_permalink.rb +13 -0
  80. data/db/migrate/20090225231119_add_more_needed_keys_items_and_conf.rb +19 -0
  81. data/db/migrate/20090302221152_give_all_users_user_role.rb +13 -0
  82. data/db/sample/orders.yml +1 -1
  83. data/lib/generators/instance/instance_generator.rb +1 -1
  84. data/lib/spree.rb +1 -1
  85. data/lib/spree/setup.rb +1 -1
  86. data/lib/tasks/database.rake +5 -2
  87. data/lib/tasks/release.rake +1 -1
  88. data/lib/tasks/upgrade.rake +11 -0
  89. data/public/assets/products/1009/mini/sean.jpg +0 -0
  90. data/public/assets/products/1009/original/sean.jpg +0 -0
  91. data/public/assets/products/1009/product/sean.jpg +0 -0
  92. data/public/assets/products/1009/small/sean.jpg +0 -0
  93. data/public/images/ajax_loader.gif +0 -0
  94. data/public/javascripts/checkout.js +284 -0
  95. data/public/javascripts/jquery-1.3.2.min.js +19 -0
  96. data/public/javascripts/jquery.validate.pack.js +15 -0
  97. data/public/stylesheets/checkout.css +25 -0
  98. data/public/stylesheets/spree-admin.css +6 -2
  99. data/public/stylesheets/spree.css +419 -432
  100. data/spec/controllers/countries_controller_spec.rb +3 -2
  101. data/spec/controllers/orders_controller_spec.rb +7 -5
  102. data/spec/controllers/states_controller_spec.rb +4 -2
  103. data/spec/models/creditcard_payment_spec.rb +6 -2
  104. data/spec/models/order_spec.rb +164 -157
  105. data/spec/models/product_spec.rb +2 -2
  106. data/vendor/extensions/payment_gateway/db/migrate/20090218091936_create_protx_gateway.rb +18 -0
  107. data/vendor/extensions/payment_gateway/lib/spree/payment_gateway.rb +7 -5
  108. data/vendor/extensions/shipping/app/controllers/admin/shipments_controller.rb +6 -5
  109. data/vendor/extensions/shipping/app/views/admin/shipments/index.html.erb +1 -1
  110. data/vendor/extensions/shipping/config/locales/nb-NO.yml +25 -0
  111. data/vendor/extensions/shipping/config/locales/ru-RU.yml +25 -0
  112. data/vendor/extensions/shipping/db/sample/shipping_methods.yml +5 -1
  113. data/vendor/extensions/shipping/db/sample/zone_members.yml +9 -1
  114. data/vendor/extensions/shipping/db/sample/zones.yml +4 -1
  115. data/vendor/extensions/shipping/lib/spree/shipping_calculator.rb +0 -16
  116. data/vendor/extensions/shipping/shipping_extension.rb +0 -15
  117. data/vendor/extensions/shipping/spec/models/shipping_method_spec.rb +16 -10
  118. data/vendor/extensions/shipping/spec/models/shipping_order_spec.rb +3 -17
  119. data/vendor/extensions/tax_calculator/config/locales/nb-NO.yml +30 -0
  120. data/vendor/extensions/tax_calculator/spec/models/{order_spec.rb → order_tax_calc_spec.rb} +2 -2
  121. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/.specification +3 -5
  122. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/LICENSE +0 -0
  123. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/README +9 -2
  124. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/Rakefile +0 -0
  125. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/lib/active_presenter.rb +0 -0
  126. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/lib/active_presenter/base.rb +38 -8
  127. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/lib/active_presenter/version.rb +1 -1
  128. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/lib/tasks/doc.rake +0 -0
  129. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/lib/tasks/gem.rake +0 -0
  130. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/test/base_test.rb +66 -30
  131. data/vendor/gems/{active_presenter-0.0.4 → active_presenter-0.0.6}/test/test_helper.rb +36 -0
  132. data/vendor/plugins/attribute_fu/lib/attribute_fu/associated_form_helper.rb +12 -4
  133. data/vendor/plugins/find_by_param/MIT-LICENSE +1 -1
  134. data/vendor/plugins/find_by_param/{README → README.markdown} +7 -1
  135. data/vendor/plugins/find_by_param/init.rb +0 -1
  136. data/vendor/plugins/find_by_param/lib/find_by_param.rb +23 -87
  137. data/vendor/plugins/find_by_param/test/find_by_param_test.rb +22 -8
  138. data/vendor/plugins/find_by_param/test/test_helper.rb +0 -1
  139. metadata +65 -193
  140. data/app/controllers/creditcards_controller.rb +0 -73
  141. data/app/models/order_filter.rb +0 -28
  142. data/app/models/user_filter.rb +0 -6
  143. data/app/views/creditcards/_form_credit_card.html.erb +0 -30
  144. data/app/views/creditcards/new.html.erb +0 -25
  145. data/app/views/shared/_paginate.html.erb +0 -34
  146. data/lib/plugins/paginating_find/CHANGELOG +0 -120
  147. data/lib/plugins/paginating_find/README +0 -89
  148. data/lib/plugins/paginating_find/init.rb +0 -2
  149. data/lib/plugins/paginating_find/lib/paginating_find.rb +0 -138
  150. data/lib/plugins/paginating_find/lib/paging_enumerator.rb +0 -158
  151. data/lib/plugins/paginating_find/lib/paging_helper.rb +0 -47
  152. data/lib/plugins/paginating_find/test_app/Rakefile +0 -10
  153. data/lib/plugins/paginating_find/test_app/app/controllers/application.rb +0 -2
  154. data/lib/plugins/paginating_find/test_app/config/boot.rb +0 -44
  155. data/lib/plugins/paginating_find/test_app/config/database.yml +0 -6
  156. data/lib/plugins/paginating_find/test_app/config/environment.rb +0 -53
  157. data/lib/plugins/paginating_find/test_app/config/environments/test.rb +0 -19
  158. data/lib/plugins/paginating_find/test_app/config/routes.rb +0 -22
  159. data/lib/plugins/paginating_find/test_app/script/breakpointer +0 -3
  160. data/lib/plugins/paginating_find/test_app/script/console +0 -3
  161. data/lib/plugins/paginating_find/test_app/test/fixtures/articles.yml +0 -19
  162. data/lib/plugins/paginating_find/test_app/test/fixtures/authors.yml +0 -7
  163. data/lib/plugins/paginating_find/test_app/test/fixtures/edits.yml +0 -11
  164. data/lib/plugins/paginating_find/test_app/test/fixtures/models.rb +0 -18
  165. data/lib/plugins/paginating_find/test_app/test/test_helper.rb +0 -33
  166. data/lib/plugins/paginating_find/test_app/test/unit/abstract_test.rb +0 -7
  167. data/lib/plugins/paginating_find/test_app/test/unit/group_test.rb +0 -40
  168. data/lib/plugins/paginating_find/test_app/test/unit/paginating_find_test.rb +0 -194
  169. data/lib/plugins/paginating_find/test_app/test/unit/paging_enumerator_test.rb +0 -143
  170. data/public/assets/products/1012/mini/bt.jpg +0 -0
  171. data/public/assets/products/1012/original/bt.jpg +0 -0
  172. data/public/assets/products/1012/product/bt.jpg +0 -0
  173. data/public/assets/products/1012/small/bt.jpg +0 -0
  174. data/spec/views/products/index.html.erb_spec.rb +0 -46
  175. data/spec/views/products/show.html.erb_spec.rb +0 -46
  176. data/vendor/extensions/shipping/app/controllers/shipments_controller.rb +0 -96
  177. data/vendor/extensions/shipping/app/helpers/shipments_helper.rb +0 -20
  178. data/vendor/extensions/shipping/app/views/orders/fatal_shipping.html.erb +0 -6
  179. data/vendor/extensions/shipping/app/views/shipments/_form.html.erb +0 -46
  180. data/vendor/extensions/shipping/app/views/shipments/edit.html.erb +0 -57
  181. data/vendor/extensions/shipping/app/views/shipments/new.html.erb +0 -10
@@ -26,14 +26,19 @@ class ProductsController < Spree::BaseController
26
26
  def collection
27
27
  if params[:taxon]
28
28
  @taxon = Taxon.find(params[:taxon])
29
-
30
- @collection ||= Product.active.find(
31
- :all,
32
- :conditions => ["products.id in (select product_id from products_taxons where taxon_id in (" + @taxon.descendents.inject( @taxon.id.to_s) { |clause, t| clause += ', ' + t.id.to_s} + "))" ],
33
- :page => {:start => 1, :size => Spree::Config[:products_per_page], :current => params[:p]},
34
- :include => :images)
29
+
30
+ @search = Product.active.scoped(:conditions =>
31
+ ["products.id in (select product_id from products_taxons where taxon_id in (" +
32
+ @taxon.descendents.inject( @taxon.id.to_s) { |clause, t| clause += ', ' + t.id.to_s} + "))"
33
+ ]).new_search(params[:search])
35
34
  else
36
- @collection ||= Product.active.find(:all, :page => {:start => 1, :size => Spree::Config[:products_per_page], :current => params[:p]}, :include => :images)
35
+ @search = Product.active.new_search(params[:search])
37
36
  end
37
+
38
+ @search.per_page = Spree::Config[:products_per_page]
39
+ @search.include = :images
40
+
41
+ @product_cols = 3
42
+ @products ||= @search.all
38
43
  end
39
44
  end
@@ -1,6 +1,6 @@
1
1
  class Spree::BaseController < ApplicationController
2
2
 
3
- filter_parameter_logging "password"
3
+ filter_parameter_logging :password, :creditcard_number, :creditcard_verification_value
4
4
 
5
5
  # retrieve the order_id from the session and then load from the database (or return a new order if no
6
6
  # such id exists in the session)
@@ -1,10 +1,22 @@
1
1
  class StatesController < Spree::BaseController
2
2
  resource_controller
3
+
4
+ ssl_allowed :index
3
5
 
4
6
  index.response do |wants|
5
7
  wants.html
6
8
  wants.js do
7
- @states = end_of_association_chain.find(:all, :conditions => ['lower(name) LIKE ?', "%#{params[:q].downcase}%"], :order => :name)
9
+ # @states = end_of_association_chain.find(:all, :conditions => ['lower(name) LIKE ?', "%#{params[:q].downcase}%"], :order => :name)
10
+
11
+ # table of {country.id => { state.id => state.name }}
12
+ # blank added elsewhere, if needed
13
+ usa = {}
14
+ State.find(:all, :conditions => "country_id = 214",
15
+ :select => "id, name"
16
+ ).each do |s|
17
+ usa[s.name] = s.id
18
+ end
19
+ @state_info = { "214" => usa } # to be generalised...
8
20
  end
9
21
  end
10
- end
22
+ end
@@ -12,12 +12,16 @@ class TaxonsController < Spree::BaseController
12
12
 
13
13
  private
14
14
  def load_data
15
- @products ||= object.products.active.find(:all, :page => {:start => 1, :size => Spree::Config[:products_per_page], :current => params[:p]}, :include => :images)
15
+ @search = object.products.active.new_search(params[:search])
16
+ @search.per_page = Spree::Config[:products_per_page]
17
+ @search.include = :images
18
+
16
19
  @product_cols = 3
20
+ @products ||= @search.all
17
21
  end
18
22
 
19
23
  def object
20
- objects ||= end_of_association_chain.find_by_permalink(params[:id].join("/") + "/")
24
+ @object ||= end_of_association_chain.find_by_permalink(params[:id].join("/") + "/")
21
25
  end
22
26
 
23
27
  end
@@ -9,13 +9,16 @@ class UsersController < Spree::BaseController
9
9
  show.before do
10
10
  @orders = Order.checkout_completed(true).find_all_by_user_id(current_user.id)
11
11
  end
12
-
13
- create.after do
14
- self.current_user = @user
15
- end
16
-
17
- create.response do |wants|
12
+
13
+ create do
14
+ flash nil
18
15
  wants.html { redirect_back_or_default(products_path) }
19
16
  end
20
17
 
18
+ create.after do
19
+ @user.roles << Role.find_by_name("user")
20
+ @user.save
21
+ self.current_user = @user
22
+ end
23
+
21
24
  end
@@ -30,15 +30,5 @@ module ApplicationHelper
30
30
  def flag_image(code)
31
31
  "#{code.to_s.split("-").last.downcase}.png"
32
32
  end
33
-
34
- # Takes a filter and converts it into a hash of name/value pairs that can be used in query string
35
- def generate_search_options(filter)
36
- options = {}
37
- filter.attributes.each do |key, value|
38
- filter_key = "filter[#{key.to_s}]"
39
- options[filter_key] = value
40
- end
41
- options
42
- end
43
-
33
+
44
34
  end
@@ -22,7 +22,9 @@ module ProductsHelper
22
22
  end
23
23
  end
24
24
 
25
- def format_price(price)
25
+ def format_price(price)
26
+ # Don't be fooled - default implementation uses number_to_currency but other extensions may patch into this. It is
27
+ # suggested that you leave your format_price calls alone.
26
28
  number_to_currency(price)
27
29
  end
28
30
 
@@ -4,33 +4,7 @@ module Spree::BaseHelper
4
4
  return new_order_url if session[:order_id].blank?
5
5
  return edit_order_url(Order.find_or_create_by_id(session[:order_id]))
6
6
  end
7
-
8
- def windowed_pagination_links(pagingEnum, options)
9
- link_to_current_page = options[:link_to_current_page]
10
- always_show_anchors = options[:always_show_anchors]
11
- padding = options[:window_size]
12
-
13
- current_page = pagingEnum.page
14
- html = ''
15
-
16
- #Calculate the window start and end pages
17
- padding = padding < 0 ? 0 : padding
18
- first = pagingEnum.page_exists?(current_page - padding) ? current_page - padding : 1
19
- last = pagingEnum.page_exists?(current_page + padding) ? current_page + padding : pagingEnum.last_page
20
-
21
- # Print start page if anchors are enabled
22
- html << yield(1) if always_show_anchors and not first == 1
23
7
 
24
- # Print window pages
25
- first.upto(last) do |page|
26
- (current_page == page && !link_to_current_page) ? html << page : html << yield(page)
27
- end
28
-
29
- # Print end page if anchors are enabled
30
- html << yield(pagingEnum.last_page) if always_show_anchors and not last == pagingEnum.last_page
31
- html
32
- end
33
-
34
8
  def add_product_link(text, product)
35
9
  link_to_remote text, {:url => {:controller => "cart",
36
10
  :action => "add", :id => product}},
@@ -12,12 +12,12 @@ class Address < ActiveRecord::Base
12
12
  validates_presence_of :zipcode
13
13
  validates_presence_of :country
14
14
  validates_presence_of :phone
15
-
15
+
16
16
  def full_name
17
17
  self.firstname + " " + self.lastname
18
18
  end
19
-
19
+
20
20
  def state_text
21
- state.nil? ? state_name : (state.abbr=="" ? state.name : state.abbr)
21
+ state.nil? ? state_name : (state.abbr.blank? ? state.name : state.abbr)
22
22
  end
23
23
  end
@@ -31,6 +31,7 @@ class AppConfiguration < Configuration
31
31
  preference :admin_interface_logo, :string, :default => "spree/spree.jpg"
32
32
  preference :allow_ssl_in_production, :boolean, :default => true
33
33
  preference :allow_ssl_in_development_and_test, :boolean, :default => false
34
+ preference :google_analytics_id, :string, :default => '12312312' # Replace with real Google Analytics Id
34
35
 
35
36
  validates_presence_of :name
36
37
  validates_uniqueness_of :name
@@ -1,4 +1,8 @@
1
1
  class Country < ActiveRecord::Base
2
2
  has_many :states
3
3
  named_scope :order_by_name, :order => :name
4
+
5
+ def <=>(other)
6
+ name <=> other.name
7
+ end
4
8
  end
@@ -66,7 +66,12 @@ class Creditcard < ActiveRecord::Base
66
66
  def last_digits
67
67
  self.class.last_digits(number)
68
68
  end
69
-
69
+
70
+ # needed for some of the ActiveMerchant gateways (eg. Protx)
71
+ def brand
72
+ cc_type
73
+ end
74
+
70
75
  def validate
71
76
  validate_essential_attributes
72
77
  validate_card_type
@@ -7,7 +7,7 @@ class CreditcardPayment < Payment
7
7
  def find_authorization
8
8
  #find the transaction associated with the original authorization/capture
9
9
  txns.find(:first,
10
- :conditions => ["txn_type = ?", CreditcardTxn::TxnType::AUTHORIZE],
10
+ :conditions => ["txn_type = ? AND response_code IS NOT NULL", CreditcardTxn::TxnType::AUTHORIZE],
11
11
  :order => 'created_at DESC')
12
12
  end
13
13
 
@@ -9,6 +9,9 @@ class InventoryUnit < ActiveRecord::Base
9
9
  event :sell do
10
10
  transition :to => 'sold', :from => 'on_hand'
11
11
  end
12
+ event :fill_backorder do
13
+ transition :to => 'sold', :from => 'backordered'
14
+ end
12
15
  event :ship do
13
16
  transition :to => 'shipped', :if => :allow_ship? #, :from => 'sold'
14
17
  end
@@ -61,7 +64,7 @@ class InventoryUnit < ActiveRecord::Base
61
64
 
62
65
  private
63
66
  def allow_ship?
64
- state == 'sold' || Spree::Config[:allow_backorder_shipping]
67
+ state == 'ready_to_ship' || Spree::Config[:allow_backorder_shipping]
65
68
  end
66
69
 
67
70
  end
@@ -1,5 +1,5 @@
1
1
  class Order < ActiveRecord::Base
2
- before_create :generate_order_number
2
+ # before_create :generate_order_number
3
3
  before_save :update_line_items
4
4
 
5
5
  has_many :line_items, :dependent => :destroy, :attributes => true do
@@ -7,13 +7,13 @@ class Order < ActiveRecord::Base
7
7
  find :first, :conditions => ['variant_id = ?', variant.id]
8
8
  end
9
9
  end
10
- has_many :products, :through => :line_items
11
10
  has_many :inventory_units
12
11
  has_many :state_events
13
12
  has_many :payments
14
13
  has_many :creditcard_payments
15
14
  has_many :creditcards
16
15
  belongs_to :user
16
+ has_many :shipments, :dependent => :destroy
17
17
 
18
18
  validates_associated :line_items, :message => "are not valid"
19
19
  validates_numericality_of :tax_amount
@@ -31,6 +31,13 @@ class Order < ActiveRecord::Base
31
31
  # attr_accessible is a nightmare with attachment_fu, so use attr_protected instead.
32
32
  attr_protected :ship_amount, :tax_amount, :item_total, :total, :user, :number, :ip_address, :checkout_complete, :state
33
33
 
34
+ def to_param
35
+ self.number if self.number
36
+ generate_order_number unless self.number
37
+ self.number.parameterize.to_s.upcase
38
+ end
39
+ make_permalink :field => :number
40
+
34
41
  # order state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
35
42
  state_machine :initial => 'in_progress' do
36
43
  after_transition :to => 'in_progress', :do => lambda {|order| order.update_attribute(:checkout_complete, false)}
@@ -38,15 +45,9 @@ class Order < ActiveRecord::Base
38
45
  after_transition :to => 'canceled', :do => :cancel_order
39
46
  after_transition :to => 'returned', :do => :restock_inventory
40
47
  after_transition :to => 'resumed', :do => :restore_state
41
-
42
- before_transition :to => 'paid', :do => :record_payment_event
43
-
44
- event :next do
45
- transition :to => 'creditcard', :from => 'in_progress'
46
- transition :to => 'new', :from => 'creditcard'
47
- end
48
- event :edit do
49
- transition :to => 'in_progress', :from => %w{creditcard in_progress}
48
+
49
+ event :complete do
50
+ transition :to => 'new', :from => 'in_progress'
50
51
  end
51
52
  event :cancel do
52
53
  transition :to => 'canceled', :if => :allow_cancel?
@@ -60,11 +61,9 @@ class Order < ActiveRecord::Base
60
61
  event :pay do
61
62
  transition :to => 'paid', :if => :allow_pay?
62
63
  end
63
- end
64
-
65
- def record_payment_event
66
- # normally these types of transitions are recorded by controller
67
- state_events.create(:name => I18n.t(:pay), :previous_state => state)
64
+ event :ship do
65
+ transition :to => 'shipped', :from => 'paid'
66
+ end
68
67
  end
69
68
 
70
69
  def restore_state
@@ -74,7 +73,7 @@ class Order < ActiveRecord::Base
74
73
  end
75
74
 
76
75
  def allow_cancel?
77
- self.checkout_complete && self.state != 'canceled'
76
+ self.state != 'canceled'
78
77
  end
79
78
 
80
79
  def allow_resume?
@@ -112,12 +111,12 @@ class Order < ActiveRecord::Base
112
111
  end
113
112
  end
114
113
 
115
- def generate_order_number
114
+ def generate_order_number
116
115
  record = true
117
116
  while record
118
- random = Array.new(9){rand(9)}.join
117
+ random = "R#{Array.new(9){rand(9)}.join}"
119
118
  record = Order.find(:first, :conditions => ["number = ?", random])
120
- end
119
+ end
121
120
  self.number = random
122
121
  end
123
122
 
@@ -142,6 +141,18 @@ class Order < ActiveRecord::Base
142
141
  return nil if creditcards.empty?
143
142
  return creditcards.last.address
144
143
  end
144
+
145
+ # convenience method since many stores will not allow user to create multiple shipments
146
+ def shipment
147
+ shipments.last
148
+ end
149
+
150
+ def ship_address
151
+ return nil if shipments.empty?
152
+ return shipment.address
153
+ end
154
+
155
+ include Spree::ShippingCalculator
145
156
 
146
157
  private
147
158
  def complete_order
@@ -149,7 +160,12 @@ class Order < ActiveRecord::Base
149
160
  InventoryUnit.sell_units(self)
150
161
  if user && user.email
151
162
  OrderMailer.deliver_confirm(self)
152
- end
163
+ end
164
+ # finalize order totals
165
+ calculator = shipment.shipping_method.shipping_calculator.constantize.new
166
+ self.ship_amount = calculator.calculate_shipping(shipment)
167
+ self.tax_amount = calculate_tax
168
+ save
153
169
  end
154
170
 
155
171
  def cancel_order
@@ -15,19 +15,22 @@ class Product < ActiveRecord::Base
15
15
  validates_presence_of :name
16
16
  validates_presence_of :master_price
17
17
  validates_presence_of :description
18
-
19
- make_permalink :with => :name, :field => :permalink
18
+
19
+ make_permalink
20
20
 
21
21
  alias :options :product_option_types
22
22
 
23
23
  # default product scope only lists available and non-deleted products
24
24
  named_scope :active, lambda { |*args| { :conditions => ["products.available_on <= ? and products.deleted_at is null", (args.first || Time.zone.now)] } }
25
+ named_scope :not_deleted, lambda { |*args| { :conditions => ["products.deleted_at is null", (args.first || Time.zone.now)] } }
25
26
 
26
27
  named_scope :available, lambda { |*args| { :conditions => ["products.available_on <= ?", (args.first || Time.zone.now)] } }
27
- named_scope :by_name, lambda {|name| {:conditions => ["products.name like ?", "%#{name}%"]}}
28
- named_scope :by_sku, lambda {|sku| { :include => :variants, :conditions => ["variants.sku like ?", "%#{sku}%"]}}
29
- named_scope :deleted, :conditions => "not products.deleted_at is null"
30
-
28
+
29
+ def to_param
30
+ return permalink unless permalink.blank?
31
+ name.parameterize.to_s
32
+ end
33
+
31
34
  # checks is there are any meaningful variants (ie. variants with at least one option value)
32
35
  def variants?
33
36
  self.variants.each do |v|
@@ -65,16 +68,24 @@ class Product < ActiveRecord::Base
65
68
  def has_stock?
66
69
  variants.inject(false){ |tf, v| tf ||= v.in_stock }
67
70
  end
68
-
71
+
69
72
  private
70
73
 
71
- def adjust_inventory
74
+ def adjust_inventory
72
75
  return if self.new_record?
73
76
  return unless @quantity && @quantity.is_integer?
74
77
  new_level = @quantity.to_i
75
78
  # don't allow negative on_hand inventory
76
79
  return if new_level < 0
77
80
  variant.save
81
+ variant.inventory_units.with_state("backordered").each{|iu|
82
+ if new_level > 0
83
+ iu.fill_backorder
84
+ new_level = new_level - 1
85
+ end
86
+ break if new_level < 1
87
+ }
88
+
78
89
  adjustment = new_level - on_hand
79
90
  if adjustment > 0
80
91
  InventoryUnit.create_on_hand(variant, adjustment)
@@ -1,17 +1,28 @@
1
- class Shipment < ActiveRecord::Base
2
- before_create :generate_shipment_number
1
+ class Shipment < ActiveRecord::Base
2
+ include ActionView::Helpers::NumberHelper # Needed for JS usable rate information
3
+
3
4
  belongs_to :order
4
5
  belongs_to :shipping_method
6
+ has_one :address, :as => :addressable, :dependent => :destroy
5
7
 
8
+ before_create :generate_shipment_number
9
+ after_save :recalculate_tax
6
10
  after_save :transition_order
7
- has_one :address, :as => :addressable, :dependent => :destroy
8
11
 
9
12
  def shipped?
10
13
  self.shipped_at
11
14
  end
12
15
 
13
16
  def shipping_methods
14
- ShippingMethod.all.select { |method| method.zone.include?(address) }
17
+ ShippingMethod.all.select { |method| method.zone.include?(address) && method.available?(order) }
18
+ end
19
+
20
+ def rates
21
+ quotes = []
22
+ shipping_methods.each do |method|
23
+ quotes << {:id => method.id, :name => method.name, :rate => number_to_currency(method.calculate_shipping(self)) }
24
+ end
25
+ quotes
15
26
  end
16
27
 
17
28
  private
@@ -32,4 +43,9 @@ class Shipment < ActiveRecord::Base
32
43
  # transition order to shipped if all shipments have been shipped
33
44
  order.ship!
34
45
  end
46
+
47
+ def recalculate_tax
48
+ return unless order && order.respond_to?(:calculate_tax)
49
+ order.update_attribute("tax_amount", order.calculate_tax)
50
+ end
35
51
  end