spree 0.4.1 → 0.5.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 (182) hide show
  1. data/CHANGELOG +35 -0
  2. data/CONTRIBUTORS +2 -1
  3. data/README.markdown +8 -52
  4. data/app/controllers/account_controller.rb +1 -1
  5. data/app/controllers/addresses_controller.rb +5 -1
  6. data/app/controllers/admin/inventory_settings_controller.rb +13 -0
  7. data/app/controllers/admin/option_types_controller.rb +1 -1
  8. data/app/controllers/admin/orders_controller.rb +14 -8
  9. data/app/controllers/admin/products_controller.rb +2 -0
  10. data/app/controllers/admin/variants_controller.rb +7 -0
  11. data/app/controllers/content_controller.rb +5 -0
  12. data/app/controllers/creditcard_payments_controller.rb +2 -2
  13. data/app/controllers/orders_controller.rb +18 -2
  14. data/app/helpers/admin/inventory_settings_helper.rb +5 -0
  15. data/app/helpers/admin/product_properties_helper.rb +10 -2
  16. data/app/helpers/products_helper.rb +2 -2
  17. data/app/models/address.rb +2 -2
  18. data/app/models/app_configuration.rb +1 -0
  19. data/app/models/creditcard_payment.rb +6 -14
  20. data/app/models/order.rb +6 -12
  21. data/app/models/order_filter.rb +1 -0
  22. data/app/models/product.rb +9 -0
  23. data/app/models/product_property.rb +1 -0
  24. data/app/models/property.rb +0 -1
  25. data/app/models/zone.rb +17 -3
  26. data/app/views/account/login.html.erb +2 -14
  27. data/app/views/admin/configurations/index.html.erb +4 -0
  28. data/app/views/admin/inventory_settings/edit.html.erb +18 -0
  29. data/app/views/admin/inventory_settings/show.html.erb +11 -0
  30. data/app/views/admin/orders/_address.html.erb +1 -1
  31. data/app/views/admin/orders/index.html.erb +5 -1
  32. data/app/views/admin/orders/show.html.erb +3 -3
  33. data/app/views/admin/product_properties/_product_property.html.erb +6 -3
  34. data/app/views/admin/products/_form.html.erb +9 -1
  35. data/app/views/admin/prototypes/select.rjs +3 -1
  36. data/app/views/admin/variants/_form.html.erb +6 -0
  37. data/app/views/admin/variants/index.html.erb +7 -1
  38. data/app/views/creditcard_payments/_form_credit_card.html.erb +1 -1
  39. data/app/views/creditcard_payments/new.html.erb +7 -2
  40. data/app/views/products/show.html.erb +8 -2
  41. data/app/views/shared/_login.html.erb +17 -0
  42. data/app/views/shared/_products.html.erb +1 -1
  43. data/app/views/users/_form.html.erb +1 -1
  44. data/app/views/users/new.html.erb +19 -8
  45. data/config/boot.rb +1 -1
  46. data/config/database.yml +7 -3
  47. data/config/environment.rb +16 -2
  48. data/config/routes.rb +4 -0
  49. data/db/migrate/20081016002224_remove_defunct_order_fields.rb +10 -0
  50. data/db/migrate/20081016162924_drop_category_id_from_products.rb +9 -0
  51. data/db/sample/addresses.yml +14 -0
  52. data/db/sample/orders.yml +0 -1
  53. data/lang/ui/de-DE.yml +2 -1
  54. data/lang/ui/en-US.yml +50 -25
  55. data/lang/ui/es-ES.yml +2 -1
  56. data/lang/ui/it-IT.yml +2 -1
  57. data/lang/ui/pl-PL.yml +1 -0
  58. data/lang/ui/pt-BR.yml +5 -2
  59. data/lib/authenticated_system.rb +1 -1
  60. data/lib/generators/extension/extension_generator.rb +1 -0
  61. data/lib/generators/extension/templates/extension.rb +4 -5
  62. data/lib/generators/extension/templates/tasks.rake +12 -0
  63. data/lib/generators/extension_migration/extension_migration_generator.rb +32 -0
  64. data/lib/generators/extension_migration/templates/migration.rb +7 -0
  65. data/lib/spree.rb +2 -2
  66. data/lib/spree/extension.rb +0 -7
  67. data/lib/spree/extension_loader.rb +0 -8
  68. data/lib/tasks/extensions.rake +47 -0
  69. data/public/javascripts/application.js +34 -0
  70. data/public/javascripts/spree-yui.js +2 -2
  71. data/public/stylesheets/spree.css +11 -1
  72. data/spec/fixtures/preferences.yml +14 -6
  73. data/spec/models/address_spec.rb +78 -0
  74. data/spec/models/country_spec.rb +29 -0
  75. data/spec/models/option_type_spec.rb +36 -0
  76. data/spec/models/option_value_spec.rb +39 -0
  77. data/spec/models/product_option_type_spec.rb +38 -0
  78. data/spec/models/product_property_spec.rb +36 -0
  79. data/spec/models/product_spec.rb +109 -32
  80. data/spec/models/property_spec.rb +38 -0
  81. data/spec/models/prototype_spec.rb +35 -0
  82. data/spec/models/state_spec.rb +28 -0
  83. data/spec/models/taxon_spec.rb +38 -0
  84. data/spec/models/taxonomy_spec.rb +37 -0
  85. data/spec/models/variant_spec.rb +73 -12
  86. data/spec/models/zone_spec.rb +35 -15
  87. data/spec/spec_helper.rb +15 -0
  88. data/spec/views/admin/configurations/index.html.erb_spec.rb +29 -0
  89. data/spec/views/admin/mail_settings/show.html.erb_spec.rb +3 -3
  90. data/spec/views/products/index.html.erb_spec.rb +46 -0
  91. data/spec/views/products/show.html.erb_spec.rb +46 -0
  92. data/vendor/extensions/flat_rate_shipping/README.markdown +3 -0
  93. data/vendor/extensions/flat_rate_shipping/Rakefile +120 -0
  94. data/vendor/extensions/flat_rate_shipping/flat_rate_shipping_extension.rb +17 -0
  95. data/vendor/extensions/flat_rate_shipping/lib/flat_rate_shipping_configuration.rb +7 -0
  96. data/vendor/extensions/flat_rate_shipping/lib/spree/flat_rate_shipping/calculator.rb +9 -0
  97. data/vendor/extensions/flat_rate_shipping/lib/spree/flat_rate_shipping/config.rb +22 -0
  98. data/vendor/extensions/flat_rate_shipping/lib/tasks/flat_rate_shipping_extension_tasks.rake +29 -0
  99. data/vendor/extensions/flat_rate_shipping/spec/spec.opts +6 -0
  100. data/vendor/extensions/flat_rate_shipping/spec/spec_helper.rb +37 -0
  101. data/vendor/extensions/localization/localization_extension.rb +1 -6
  102. data/vendor/extensions/payment_gateway/lib/gateway_config.rb +7 -0
  103. data/vendor/extensions/payment_gateway/lib/spree/gateway/config.rb +22 -0
  104. data/vendor/extensions/payment_gateway/lib/spree/payment_gateway.rb +27 -3
  105. data/vendor/extensions/payment_gateway/payment_gateway_extension.rb +0 -4
  106. data/vendor/extensions/shipping/README.markdown +3 -0
  107. data/vendor/extensions/shipping/Rakefile +120 -0
  108. data/vendor/extensions/shipping/app/controllers/admin/shipping_categories_controller.rb +17 -0
  109. data/vendor/extensions/shipping/app/controllers/admin/shipping_methods_controller.rb +21 -0
  110. data/vendor/extensions/shipping/app/controllers/shipments_controller.rb +84 -0
  111. data/vendor/extensions/shipping/app/helpers/admin/shipping_categories_helper.rb +2 -0
  112. data/vendor/extensions/shipping/app/helpers/admin/shipping_methods_helper.rb +2 -0
  113. data/vendor/extensions/shipping/app/helpers/shipments_helper.rb +20 -0
  114. data/vendor/extensions/shipping/app/models/shipment.rb +11 -0
  115. data/vendor/extensions/shipping/app/models/shipping_category.rb +3 -0
  116. data/vendor/extensions/shipping/app/models/shipping_method.rb +12 -0
  117. data/vendor/extensions/shipping/app/views/admin/shipping_categories/_form.html.erb +6 -0
  118. data/vendor/extensions/shipping/app/views/admin/shipping_categories/edit.html.erb +8 -0
  119. data/vendor/extensions/shipping/app/views/admin/shipping_categories/index.html.erb +24 -0
  120. data/vendor/extensions/shipping/app/views/admin/shipping_categories/new.html.erb +10 -0
  121. data/vendor/extensions/shipping/app/views/admin/shipping_methods/_form.html.erb +14 -0
  122. data/vendor/extensions/shipping/app/views/admin/shipping_methods/edit.html.erb +8 -0
  123. data/vendor/extensions/shipping/app/views/admin/shipping_methods/index.html.erb +28 -0
  124. data/vendor/extensions/shipping/app/views/admin/shipping_methods/new.html.erb +10 -0
  125. data/vendor/extensions/shipping/app/views/orders/fatal_shipping.html.erb +6 -0
  126. data/vendor/extensions/shipping/app/views/shipments/_form.html.erb +46 -0
  127. data/vendor/extensions/shipping/app/views/shipments/edit.html.erb +8 -0
  128. data/vendor/extensions/shipping/app/views/shipments/new.html.erb +8 -0
  129. data/vendor/extensions/shipping/db/migrate/20081003211336_create_shipping_methods.rb +14 -0
  130. data/vendor/extensions/shipping/db/migrate/20081003233427_create_shipping_categories.rb +15 -0
  131. data/vendor/extensions/shipping/db/migrate/20081015001711_create_shipments.rb +14 -0
  132. data/vendor/extensions/shipping/db/migrate/20081023134446_add_product_dimensions.rb +19 -0
  133. data/vendor/extensions/shipping/db/sample/shipping_categories.yml +2 -0
  134. data/vendor/extensions/shipping/db/sample/shipping_methods.yml +12 -0
  135. data/vendor/extensions/shipping/db/sample/zone_members.yml +8 -0
  136. data/vendor/extensions/shipping/db/sample/zones.yml +3 -0
  137. data/vendor/extensions/shipping/lang/en-US.yml +9 -0
  138. data/vendor/extensions/shipping/lib/spree/shipping_calculator.rb +37 -0
  139. data/vendor/extensions/shipping/lib/spree/shipping_error.rb +3 -0
  140. data/vendor/extensions/shipping/lib/tasks/shipping_extension_tasks.rake +29 -0
  141. data/vendor/extensions/shipping/shipping_extension.rb +39 -0
  142. data/vendor/extensions/shipping/spec/controllers/admin/shipping_categories_controller_spec.rb +10 -0
  143. data/vendor/extensions/shipping/spec/controllers/admin/shipping_methods_controller_spec.rb +10 -0
  144. data/vendor/extensions/shipping/spec/models/order_spec.rb +98 -0
  145. data/vendor/extensions/shipping/spec/models/shipment_spec.rb +26 -0
  146. data/vendor/extensions/shipping/spec/models/shipping_category_spec.rb +8 -0
  147. data/vendor/extensions/shipping/spec/models/shipping_method_spec.rb +53 -0
  148. data/vendor/extensions/shipping/spec/spec.opts +6 -0
  149. data/vendor/extensions/shipping/spec/spec_helper.rb +37 -0
  150. data/vendor/extensions/tax_calculator/lib/spree/sales_tax_calculator.rb +12 -4
  151. data/vendor/extensions/tax_calculator/spec/controllers/tax_calculator_spec.rb +0 -4
  152. data/vendor/extensions/tax_calculator/spec/models/sales_tax_calculator_spec.rb +14 -14
  153. data/vendor/extensions/tax_calculator/tax_calculator_extension.rb +0 -4
  154. data/vendor/plugins/resource_controller/README.rdoc +38 -6
  155. data/vendor/plugins/resource_controller/Rakefile +7 -20
  156. data/vendor/plugins/resource_controller/TODO +0 -1
  157. data/vendor/plugins/resource_controller/lib/resource_controller/helpers/current_objects.rb +71 -69
  158. data/vendor/plugins/resource_controller/lib/resource_controller/helpers/internal.rb +69 -65
  159. data/vendor/plugins/resource_controller/lib/resource_controller/helpers/nested.rb +62 -57
  160. data/vendor/plugins/resource_controller/lib/resource_controller/helpers/singleton_customizations.rb +50 -46
  161. data/vendor/plugins/resource_controller/lib/resource_controller/helpers/urls.rb +73 -69
  162. data/vendor/plugins/resource_controller/resource_controller.gemspec +4 -3
  163. data/vendor/plugins/resource_controller/test/app/controllers/cms/personnel_controller.rb +2 -0
  164. data/vendor/plugins/resource_controller/test/app/controllers/cms/photos_controller.rb +6 -0
  165. data/vendor/plugins/resource_controller/test/app/models/personnel.rb +3 -0
  166. data/vendor/plugins/resource_controller/test/app/models/photo.rb +1 -0
  167. data/vendor/plugins/resource_controller/test/app/views/cms/photos/edit.rhtml +17 -0
  168. data/vendor/plugins/resource_controller/test/app/views/cms/photos/index.rhtml +20 -0
  169. data/vendor/plugins/resource_controller/test/app/views/cms/photos/new.rhtml +16 -0
  170. data/vendor/plugins/resource_controller/test/app/views/cms/photos/show.rhtml +8 -0
  171. data/vendor/plugins/resource_controller/test/config/database.yml +9 -0
  172. data/vendor/plugins/resource_controller/test/config/environment.rb +1 -18
  173. data/vendor/plugins/resource_controller/test/config/initializers/inflections.rb +14 -0
  174. data/vendor/plugins/resource_controller/test/config/routes.rb +3 -0
  175. data/vendor/plugins/resource_controller/test/db/migrate/013_create_personnel.rb +11 -0
  176. data/vendor/plugins/resource_controller/test/db/migrate/014_add_personnel_id_to_photos.rb +9 -0
  177. data/vendor/plugins/resource_controller/test/test/fixtures/personnel.yml +5 -0
  178. data/vendor/plugins/resource_controller/test/test/functional/cms/photos_controller_test.rb +43 -0
  179. metadata +136 -6
  180. data/app/models/spree/extension_meta.rb +0 -5
  181. data/app/models/variants.rb +0 -2
  182. data/vendor/plugins/resource_controller/lib/resource_controller/version.rb +0 -9
@@ -0,0 +1,39 @@
1
+ # Uncomment this if you reference any of your controllers in activate
2
+ require_dependency 'application'
3
+
4
+ class ShippingExtension < Spree::Extension
5
+ version "1.0"
6
+ description "Describe your extension here"
7
+ url "http://yourwebsite.com/shipping"
8
+
9
+ define_routes do |map|
10
+ map.namespace :admin do |admin|
11
+ admin.resources :shipping_methods
12
+ admin.resources :shipping_categories
13
+ end
14
+ map.resources :shipments
15
+ map.resources :orders, :has_many => :shipments, :member => {:fatal_shipping => :get}
16
+ end
17
+
18
+ def activate
19
+
20
+ Order.class_eval do
21
+ has_many :shipments, :dependent => :destroy
22
+ include Spree::ShippingCalculator
23
+ end
24
+ AddressesController.class_eval do
25
+ # limit the countries to the ones that are possible to ship to
26
+ def load_countries
27
+ @countries = @order.shipping_countries
28
+ @countries = [Country.find(Spree::Config[:default_country_id])] if @countries.empty?
29
+ end
30
+ end
31
+ Admin::ConfigurationsController.class_eval do
32
+ before_filter :add_shipping_links, :only => :index
33
+ def add_shipping_links
34
+ @extension_links << {:link => admin_shipping_methods_path, :link_text => Globalite.localize(:ext_shipping_shipping_methods), :description => Globalite.localize(:ext_shipping_shipping_methods_description)}
35
+ @extension_links << {:link => admin_shipping_categories_path, :link_text => Globalite.localize(:ext_shipping_shipping_categories), :description => Globalite.localize(:ext_shipping_shipping_categories_description)}
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Admin::ShippingCategoriesController do
4
+
5
+ #Delete this example and add some real ones
6
+ it "should use Admin::ShippingCategoriesController" do
7
+ controller.should be_an_instance_of(Admin::ShippingCategoriesController)
8
+ end
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Admin::ShippingMethodsController do
4
+
5
+ #Delete this example and add some real ones
6
+ it "should use Admin::ShippingMethodsController" do
7
+ controller.should be_an_instance_of(Admin::ShippingMethodsController)
8
+ end
9
+
10
+ end
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe Order do
4
+ before(:each) do
5
+ @order = Order.new(:address => @address = mock_model(Address, :null_object => true))
6
+ #add_stubs(@order, :save => true)
7
+ end
8
+
9
+ describe "shipping_countries" do
10
+ it "should return an empty array if there are no shipping methods configured" do
11
+ ShippingMethod.stub!(:all).and_return([])
12
+ @order.shipping_countries.should == []
13
+ end
14
+ it "should contain only a single country even if multiple shipping methods are configured with that same country" do
15
+ country = mock_model(Country)
16
+ method1 = mock_model(ShippingMethod, :zone => mock_model(Zone, :country_list => [country]))
17
+ method2 = mock_model(ShippingMethod, :zone => mock_model(Zone, :country_list => [country]))
18
+ ShippingMethod.stub!(:all).and_return([method1, method2])
19
+ @order.shipping_countries.should == [country]
20
+ end
21
+ it "should contain the unique list of countries that fall within at least one shipping method's zone" do
22
+ country1 = mock_model(Country)
23
+ country2 = mock_model(Country)
24
+ method1 = mock_model(ShippingMethod, :zone => mock_model(Zone, :country_list => [country1]))
25
+ method2 = mock_model(ShippingMethod, :zone => mock_model(Zone, :country_list => [country2]))
26
+ ShippingMethod.stub!(:all).and_return([method1, method2])
27
+ @order.shipping_countries.should == [country1, country2]
28
+ end
29
+ end
30
+
31
+ describe "shipping_methods" do
32
+ it "should return empty array if there are no shipping methods configured" do
33
+ ShippingMethod.stub!(:all).and_return([])
34
+ @order.shipping_methods.should == []
35
+ end
36
+ it "should check the shipping address against the shipping method's zone" do
37
+ zone = mock_model(Zone)
38
+ method = mock_model(ShippingMethod, :zone => zone)
39
+ ShippingMethod.stub!(:all).and_return([method])
40
+ zone.should_receive(:include?).with(@address)
41
+ @order.shipping_methods
42
+ end
43
+ it "should return empty array if none of the configured shipping methods cover the shipping address" do
44
+ method = mock_model(ShippingMethod, :zone => mock_model(Zone, :include? => false))
45
+ ShippingMethod.stub!(:all).and_return([method])
46
+ @order.shipping_methods.should == []
47
+ end
48
+ it "should return all shipping methiods that cover the shipping address" do
49
+ method1 = mock_model(ShippingMethod, :zone => mock_model(Zone, :include? => true))
50
+ method2 = mock_model(ShippingMethod, :zone => mock_model(Zone, :include? => true))
51
+ method3 = mock_model(ShippingMethod, :zone => mock_model(Zone, :include? => false))
52
+ ShippingMethod.stub!(:all).and_return([method1, method2, method3])
53
+ @order.shipping_methods.should == [method1, method2]
54
+ end
55
+ end
56
+
57
+ describe "state_machine in 'address' state" do
58
+ before :each do
59
+ @order.state = 'address'
60
+ end
61
+ describe "when there are no shipping methods" do
62
+ it "next! should transition to 'creditcard_payment'" do
63
+ @order.stub!(:shipping_methods).and_return([])
64
+ @order.next!
65
+ @order.state.should == "creditcard_payment"
66
+ end
67
+ end
68
+ describe "when there is only one shipping method" do
69
+ before :each do
70
+ @shipping_method = ShippingMethod.new
71
+ @order.stub!(:shipping_methods).and_return([@shipping_method])
72
+ end
73
+ it "next! should transition to 'creditcard_payment'" do
74
+ @order.next!
75
+ @order.state.should == "creditcard_payment"
76
+ end
77
+ it "should automatically calculate the shipping cost using the single shipping method" do
78
+ @order.next!
79
+ @order.shipments.first.shipping_method.should == @shipping_method
80
+ end
81
+ end
82
+ describe "when there is only one shipping method" do
83
+ it "next! should transition to 'shipment'" do
84
+ @order.stub!(:shipping_methods).and_return([ShippingMethod.new, ShippingMethod.new])
85
+ @order.next!
86
+ @order.state.should == "shipment"
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "state_machine in 'shipment' state" do
92
+ it "next! should transition to 'creditcard_payment'" do
93
+ @order.state = 'shipment'
94
+ @order.next!
95
+ @order.state.should == "creditcard_payment"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class MockCalculator
4
+ end
5
+
6
+ describe Shipment do
7
+ before :each do
8
+ @order = Order.new
9
+ @shipping_method = ShippingMethod.new(:shipping_calculator => "MockCalculator")
10
+ @shipment = Shipment.new(:order => @order, :shipping_method => @shipping_method)
11
+ @calculator = MockCalculator.new
12
+ MockCalculator.stub!(:new).and_return(@calculator)
13
+ end
14
+
15
+ describe "update" do
16
+ it "should calculate the shipping cost using the specified calculator" do
17
+ @calculator.should_receive(:calculate_shipping).with(@order)
18
+ @shipment.save
19
+ end
20
+ it "should assign the calculated cost to the order" do
21
+ @calculator.stub!(:calculate_shipping).with(@order).and_return(8.95)
22
+ @order.should_receive(:update_attribute).with(:ship_amount, 8.95)
23
+ @shipment.save
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe ShippingCategory do
4
+ before(:each) do
5
+ @shipping_category = ShippingCategory.new
6
+ end
7
+
8
+ end
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class MockCalculator
4
+ def calculate_shipping(order)
5
+ 2.5
6
+ end
7
+ end
8
+
9
+ describe ShippingMethod do
10
+ before(:each) do
11
+ @zone = mock_model(Zone)
12
+ @address = mock_model(Address)
13
+ @shipping_method = ShippingMethod.new(:zone => @zone, :shipping_calculator => "MockCalculator")
14
+ @order = mock_model(Order, :address => @address)
15
+ end
16
+
17
+ describe "available?" do
18
+ it "should check the shipping address against the zone" do
19
+ @zone.should_receive(:include?).with(@address)
20
+ @shipping_method.available?(@order)
21
+ end
22
+ it "should be true if the shipping address is located within the method's zone" do
23
+ @zone.stub!(:include?).with(@address).and_return(true)
24
+ @shipping_method.available?(@order).should be_true
25
+ end
26
+ it "should be false if the shipping address is located outside of the method's zone" do
27
+ @zone.stub!(:include?).with(@address).and_return(false)
28
+ @shipping_method.available?(@order).should be_false
29
+ end
30
+ end
31
+
32
+ describe "calculate_shipping" do
33
+ it "should be 0 if the shipping address does not fall within the method's zone" do
34
+ @zone.stub!(:include?).with(@address).and_return(false)
35
+ @shipping_method.calculate_shipping(@order).should == 0
36
+ end
37
+ describe "when the shipping address is included within the method's zone" do
38
+ before :each do
39
+ @zone.stub!(:include?).with(@address).and_return(true)
40
+ # TODO - stub out instatiation code
41
+ end
42
+ it "should use the calculate_shipping method of the specified calculator" do
43
+ @calculator = MockCalculator.new
44
+ MockCalculator.stub!(:new).and_return(@calculator)
45
+ @calculator.should_receive(:calculate_shipping).with(@order)
46
+ @shipping_method.calculate_shipping(@order)
47
+ end
48
+ it "should return the correct amount" do
49
+ @shipping_method.calculate_shipping(@order).should == 2.5
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ unless defined? SPREE_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["SPREE_ENV_FILE"]
5
+ require ENV["SPREE_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/SPREE/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{SPREE_ROOT}/spec/spec_helper"
13
+
14
+ if File.directory?(File.dirname(__FILE__) + "/scenarios")
15
+ Scenario.load_paths.unshift File.dirname(__FILE__) + "/scenarios"
16
+ end
17
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
18
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
19
+ end
20
+
21
+ Spec::Runner.configure do |config|
22
+ # config.use_transactional_fixtures = true
23
+ # config.use_instantiated_fixtures = false
24
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
25
+
26
+ # You can declare fixtures for each behaviour like this:
27
+ # describe "...." do
28
+ # fixtures :table_a, :table_b
29
+ #
30
+ # Alternatively, if you prefer to declare them only once, you can
31
+ # do so here, like so ...
32
+ #
33
+ # config.global_fixtures = :table_a, :table_b
34
+ #
35
+ # If you declare global fixtures, be aware that they will be declared
36
+ # for all of your examples, even those that don't use them.
37
+ end
@@ -3,18 +3,26 @@ module Spree #:nodoc:
3
3
 
4
4
  def self.calculate_tax(order, rates)
5
5
  return 0 if rates.empty?
6
+ # note: there is a bug with associations in rails 2.1 model caching so we're using this hack
7
+ # (see http://rails.lighthouseapp.com/projects/8994/tickets/785-caching-models-fails-in-development)
8
+ cache_hack = rates.first.respond_to?(:tax_category_id)
9
+
6
10
  taxable_totals = {}
7
11
  order.line_items.each do |line_item|
8
12
  next unless tax_category = line_item.variant.product.tax_category
9
- next unless rate = rates[tax_category]
10
- taxable_totals[tax_category] ||= 0
13
+ next unless rate = rates.find { | sales_rate | sales_rate.tax_category_id == tax_category.id } if cache_hack
14
+ next unless rate = rates.find { | sales_rate | sales_rate.tax_category == tax_category } unless cache_hack
15
+
16
+ taxable_totals[tax_category] ||= 0
11
17
  taxable_totals[tax_category] += line_item.total
12
18
  end
13
19
 
14
20
  return 0 if taxable_totals.empty?
15
21
  tax = 0
16
- rates.each do |category, rate|
17
- return unless taxable_total = taxable_totals[category]
22
+ rates.each do |rate|
23
+ tax_category = rate.tax_category unless cache_hack
24
+ tax_category = TaxCategory.find(rate.tax_category_id) if cache_hack
25
+ next unless taxable_total = taxable_totals[tax_category]
18
26
  tax += taxable_total * rate.amount
19
27
  end
20
28
  tax
@@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../spec_helper'
3
3
  describe ApplicationController do
4
4
 
5
5
  before(:each) do
6
- @new_york = mock_model State, :name => "New York"
7
- @ship_address = mock_model Address, {:state => @new_york}
8
- @order = mock_model Order, {:item_total => 100, :ship_address => @ship_address}
9
- @tax_rate = mock_model TaxRate, {:state => @new_york, :rate => 0.075}
10
6
  end
11
7
 
12
8
  it "should map :controller => 'admin/tax_rates', :action => 'index') to /admin/tax_rates" do
@@ -14,40 +14,40 @@ describe Spree::SalesTaxCalculator do
14
14
  end
15
15
 
16
16
  it "should calc zero tax if no rates provided" do
17
- Spree::SalesTaxCalculator.calculate_tax(@order, {}).should == 0
17
+ Spree::SalesTaxCalculator.calculate_tax(@order, []).should == 0
18
18
  end
19
19
 
20
20
  it "should calc zero tax if none of the line items contains a taxable product" do
21
- tax_category = mock_model(TaxCategory)
21
+ tax_category = TaxCategory.create(:name => "foo")
22
22
  tax_rate = mock_model(TaxRate, :amount => 0.05, :category => tax_category)
23
23
  @product1.should_receive(:tax_category).and_return(nil)
24
24
  @product2.should_receive(:tax_category).and_return(nil)
25
- Spree::SalesTaxCalculator.calculate_tax(@order, {tax_category => tax_rate}).should == 0
25
+ Spree::SalesTaxCalculator.calculate_tax(@order, [tax_rate]).should == 0
26
26
  end
27
27
 
28
28
  it "should calc tax only on the items that are taxable" do
29
- tax_category = mock_model(TaxCategory)
30
- tax_rate = mock_model(TaxRate, :amount => 0.05, :category => tax_category)
29
+ tax_category = TaxCategory.create(:name => "foo")
30
+ tax_rate = TaxRate.new(:amount => 0.05, :tax_category => tax_category)
31
31
  @product1.should_receive(:tax_category).and_return(nil)
32
32
  @product2.should_receive(:tax_category).and_return(tax_category)
33
- Spree::SalesTaxCalculator.calculate_tax(@order, {tax_category => tax_rate}).should == 5
33
+ Spree::SalesTaxCalculator.calculate_tax(@order, [tax_rate]).should == 5
34
34
  end
35
35
 
36
36
  it "should apply tax to the total of all taxable line items" do
37
- tax_category = mock_model(TaxCategory)
38
- tax_rate = mock_model(TaxRate, :amount => 0.10, :category => tax_category)
37
+ tax_category = TaxCategory.create(:name => "foo")
38
+ tax_rate = TaxRate.new(:amount => 0.10, :tax_category => tax_category)
39
39
  @product1.stub!(:tax_category).and_return(tax_category)
40
40
  @product2.stub!(:tax_category).and_return(tax_category)
41
- Spree::SalesTaxCalculator.calculate_tax(@order, {tax_category => tax_rate}).should == 20
41
+ Spree::SalesTaxCalculator.calculate_tax(@order, [tax_rate]).should == 20
42
42
  end
43
43
 
44
44
  it "should apply the correct tax rates based on tax category" do
45
- tax_category1 = mock_model(TaxCategory)
46
- tax_category2 = mock_model(TaxCategory)
47
- tax_rate1 = mock_model(TaxRate, :amount => 0.10, :category => tax_category1)
48
- tax_rate2 = mock_model(TaxRate, :amount => 0.05, :category => tax_category2)
45
+ tax_category1 = TaxCategory.create(:name => "foo")
46
+ tax_category2 = TaxCategory.create(:name => "bar")
47
+ tax_rate1 = TaxRate.create(:amount => 0.10, :tax_category => tax_category1)
48
+ tax_rate2 = TaxRate.create(:amount => 0.05, :tax_category => tax_category2)
49
49
  @product1.stub!(:tax_category).and_return(tax_category1)
50
50
  @product2.stub!(:tax_category).and_return(tax_category2)
51
- Spree::SalesTaxCalculator.calculate_tax(@order, {tax_category1 => tax_rate1, tax_category2 => tax_rate2}).should == 15
51
+ Spree::SalesTaxCalculator.calculate_tax(@order, [tax_rate1, tax_rate2]).should == 15
52
52
  end
53
53
  end
@@ -43,8 +43,4 @@ class TaxCalculatorExtension < Spree::Extension
43
43
  end
44
44
  end
45
45
  end
46
-
47
- def deactivate
48
- end
49
-
50
46
  end
@@ -4,13 +4,9 @@ resource_controller makes RESTful controllers easier, more maintainable, and sup
4
4
 
5
5
  == Get It
6
6
 
7
- Add it as a gem dependency
7
+ Install it as a plugin:
8
8
 
9
- config.gem 'giraffesoft-resource_controller', :lib => 'resource_controller', :source => 'http://gems.github.com'
10
-
11
- Or install it as a gem manually
12
-
13
- sudo gem install giraffesoft-resource_controller
9
+ script/plugin install git://github.com/giraffesoft/resource_controller.git
14
10
 
15
11
  Or grab the source
16
12
 
@@ -102,6 +98,42 @@ With actions that can fail, the scoping defaults to success. That means that cr
102
98
  end
103
99
 
104
100
  end
101
+
102
+ == Singleton Resource
103
+
104
+ If you want to create a singleton RESTful controller inherit from ResourceController::Singleton.
105
+
106
+ class AccountsController < ResourceController::Singleton
107
+ end
108
+
109
+ *Note:* This type of controllers handle a single resource only so the index action and all the collection helpers (collection_url, collection_path...) are not available for them.
110
+
111
+ Loading objects in singletons is similar to plural controllers with one exception. For non-nested singleton controllers you should override the object method as it defaults to nil for them.
112
+
113
+ class AccountsController < ResourceController::Singleton
114
+ private
115
+ def object
116
+ @object ||= Account.find(session[:account_id])
117
+ end
118
+ end
119
+
120
+ In other cases you can use the default logic and override it only if you use permalinks or anything special.
121
+
122
+ Singleton nesting with both :has_many and :has_one associations is provided...
123
+
124
+ map.resource :account, :has_many => :options # /account/options, account is a singleton parent
125
+ map.resources :users, :has_one => :image # /users/1/image, image is a singleton child
126
+
127
+ If you have the :has_many association with a singleton parent remember to override parent_object for your :has_many controller as it returns nil by default in this case.
128
+
129
+ class OptionsController < ResourceController::Base
130
+ belongs_to :account
131
+
132
+ protected
133
+ def parent_object
134
+ Account.find(session[:account_id])
135
+ end
136
+ end
105
137
 
106
138
  == Helpers (ResourceController::Helpers)
107
139