spree_api 2.1.12 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -1
  3. data/app/controllers/spree/api/addresses_controller.rb +25 -10
  4. data/app/controllers/spree/api/base_controller.rb +18 -29
  5. data/app/controllers/spree/api/checkouts_controller.rb +23 -29
  6. data/app/controllers/spree/api/classifications_controller.rb +18 -0
  7. data/app/controllers/spree/api/line_items_controller.rb +13 -1
  8. data/app/controllers/spree/api/option_types_controller.rb +2 -2
  9. data/app/controllers/spree/api/option_values_controller.rb +1 -1
  10. data/app/controllers/spree/api/orders_controller.rb +12 -34
  11. data/app/controllers/spree/api/products_controller.rb +22 -23
  12. data/app/controllers/spree/api/taxons_controller.rb +9 -0
  13. data/app/controllers/spree/api/variants_controller.rb +1 -1
  14. data/app/helpers/spree/api/api_helpers.rb +5 -3
  15. data/app/models/spree/order_decorator.rb +2 -11
  16. data/app/views/spree/api/line_items/show.v1.rabl +4 -0
  17. data/app/views/spree/api/orders/order.v1.rabl +0 -1
  18. data/app/views/spree/api/products/show.v1.rabl +7 -10
  19. data/app/views/spree/api/promotions/handler.v1.rabl +4 -0
  20. data/app/views/spree/api/variants/index.v1.rabl +1 -1
  21. data/app/views/spree/api/variants/show.v1.rabl +2 -3
  22. data/app/views/spree/api/variants/variant.v1.rabl +2 -0
  23. data/app/views/spree/api/variants/{big_variant.v1.rabl → variant_full.v1.rabl} +0 -0
  24. data/config/routes.rb +6 -4
  25. data/lib/spree/api/controller_setup.rb +0 -1
  26. data/lib/spree/api/testing_support/helpers.rb +1 -0
  27. data/spec/controllers/spree/api/addresses_controller_spec.rb +57 -31
  28. data/spec/controllers/spree/api/base_controller_spec.rb +0 -36
  29. data/spec/controllers/spree/api/checkouts_controller_spec.rb +8 -41
  30. data/spec/controllers/spree/api/classifications_controller_spec.rb +38 -0
  31. data/spec/controllers/spree/api/line_items_controller_spec.rb +10 -21
  32. data/spec/controllers/spree/api/option_values_controller_spec.rb +0 -7
  33. data/spec/controllers/spree/api/orders_controller_spec.rb +24 -121
  34. data/spec/controllers/spree/api/products_controller_spec.rb +26 -48
  35. data/spec/controllers/spree/api/promotion_application_spec.rb +48 -0
  36. data/spec/controllers/spree/api/shipments_controller_spec.rb +1 -22
  37. data/spec/controllers/spree/api/unauthenticated_products_controller_spec.rb +1 -1
  38. data/spec/controllers/spree/api/users_controller_spec.rb +3 -2
  39. data/spec/controllers/spree/api/variants_controller_spec.rb +13 -7
  40. data/spec/models/spree/order_spec.rb +3 -28
  41. metadata +12 -7
  42. data/app/views/spree/api/orders/apply_coupon_code.v1.rabl +0 -7
@@ -10,12 +10,15 @@ module Spree
10
10
  end
11
11
 
12
12
  @products = @products.distinct.page(params[:page]).per(params[:per_page])
13
+ expires_in 15.minutes, :public => true
14
+ headers['Surrogate-Control'] = "max-age=#{15.minutes}"
13
15
  end
14
16
 
15
17
  def show
16
18
  @product = find_product(params[:id])
17
- expires_in 3.minutes
18
- respond_with(@product)
19
+ expires_in 15.minutes, :public => true
20
+ headers['Surrogate-Control'] = "max-age=#{15.minutes}"
21
+ headers['Surrogate-Key'] = "product_id=1"
19
22
  end
20
23
 
21
24
  # Takes besides the products attributes either an array of variants or
@@ -56,30 +59,25 @@ module Spree
56
59
  params[:product][:available_on] ||= Time.now
57
60
  set_up_shipping_category
58
61
 
59
- begin
60
- @product = Product.new(product_params)
61
- if @product.save
62
- variants_params.each do |variant_attribute|
63
- # make sure the product is assigned before the options=
64
- @product.variants.create({ product: @product }.merge(variant_attribute))
65
- end
66
-
67
- option_types_params.each do |name|
68
- option_type = OptionType.where(name: name).first_or_initialize do |option_type|
69
- option_type.presentation = name
70
- option_type.save!
71
- end
62
+ @product = Product.new(product_params)
63
+ if @product.save
64
+ variants_params.each do |variant_attribute|
65
+ # make sure the product is assigned before the options=
66
+ @product.variants.create({ product: @product }.merge(variant_attribute))
67
+ end
72
68
 
73
- @product.option_types << option_type unless @product.option_types.include?(option_type)
69
+ option_types_params.each do |name|
70
+ option_type = OptionType.where(name: name).first_or_initialize do |option_type|
71
+ option_type.presentation = name
72
+ option_type.save!
74
73
  end
75
74
 
76
- respond_with(@product, :status => 201, :default_template => :show)
77
- else
78
- invalid_resource!(@product)
75
+ @product.option_types << option_type unless @product.option_types.include?(option_type)
79
76
  end
80
- rescue ActiveRecord::RecordNotUnique
81
- @product.permalink = nil
82
- retry
77
+
78
+ respond_with(@product, :status => 201, :default_template => :show)
79
+ else
80
+ invalid_resource!(@product)
83
81
  end
84
82
  end
85
83
 
@@ -116,7 +114,8 @@ module Spree
116
114
  def destroy
117
115
  @product = find_product(params[:id])
118
116
  authorize! :destroy, @product
119
- @product.destroy
117
+ @product.update_attribute(:deleted_at, Time.now)
118
+ @product.variants_including_master.update_all(:deleted_at => Time.now)
120
119
  respond_with(@product, :status => 204)
121
120
  end
122
121
 
@@ -60,6 +60,15 @@ module Spree
60
60
  respond_with(taxon, status: 204)
61
61
  end
62
62
 
63
+ def products
64
+ # Returns the products sorted by their position with the classification
65
+ # Products#index does not do the sorting.
66
+ taxon = Spree::Taxon.find(params[:id])
67
+ @products = taxon.products.ransack(params[:q]).result
68
+ @products = @products.page(params[:page]).per(500 || params[:per_page])
69
+ render "spree/api/products/index"
70
+ end
71
+
63
72
  private
64
73
 
65
74
  def taxonomy
@@ -46,7 +46,7 @@ module Spree
46
46
  private
47
47
 
48
48
  def product
49
- @product ||= Spree::Product.accessible_by(current_ability, :read).find_by(permalink: params[:product_id]) if params[:product_id]
49
+ @product ||= Spree::Product.accessible_by(current_ability, :read).friendly.find(params[:product_id]) if params[:product_id]
50
50
  end
51
51
 
52
52
  def scope
@@ -40,12 +40,14 @@ module Spree
40
40
  # Permalinks presence is validated, but are really automatically generated
41
41
  # Therefore we shouldn't tell API clients that they MUST send one through
42
42
  required_fields.map!(&:to_s).delete("permalink")
43
+ # Do not require slugs, either
44
+ required_fields.delete("slug")
43
45
  required_fields
44
46
  end
45
47
 
46
48
  @@product_attributes = [
47
49
  :id, :name, :description, :price, :display_price, :available_on,
48
- :permalink, :meta_description, :meta_keywords, :shipping_category_id,
50
+ :slug, :meta_description, :meta_keywords, :shipping_category_id,
49
51
  :taxon_ids
50
52
  ]
51
53
 
@@ -55,7 +57,7 @@ module Spree
55
57
 
56
58
  @@variant_attributes = [
57
59
  :id, :name, :sku, :price, :weight, :height, :width, :depth, :is_master,
58
- :cost_price, :permalink, :description, :track_inventory
60
+ :cost_price, :slug, :description, :track_inventory
59
61
  ]
60
62
 
61
63
  @@image_attributes = [
@@ -73,7 +75,7 @@ module Spree
73
75
  :user_id, :created_at, :updated_at, :completed_at, :payment_total,
74
76
  :shipment_state, :payment_state, :email, :special_instructions, :channel,
75
77
  :included_tax_total, :additional_tax_total, :display_included_tax_total,
76
- :display_additional_tax_total, :tax_total, :currency
78
+ :display_additional_tax_total
77
79
  ]
78
80
 
79
81
  @@line_item_attributes = [:id, :quantity, :price, :variant_id]
@@ -15,9 +15,7 @@ Spree::Order.class_eval do
15
15
  order.create_payments_from_api params.delete(:payments_attributes) || []
16
16
  order.complete_from_api params.delete(:completed_at)
17
17
 
18
- destroy_automatic_taxes_on_import(order, params)
19
18
  order.update_attributes!(params)
20
-
21
19
  order.reload
22
20
  rescue Exception => e
23
21
  order.destroy if order && order.persisted?
@@ -25,12 +23,6 @@ Spree::Order.class_eval do
25
23
  end
26
24
  end
27
25
 
28
- def self.destroy_automatic_taxes_on_import(order, params)
29
- if params.delete :import
30
- order.adjustments.tax.destroy_all
31
- end
32
- end
33
-
34
26
  def complete_from_api(completed_at)
35
27
  if completed_at
36
28
  self.completed_at = completed_at
@@ -85,7 +77,7 @@ Spree::Order.class_eval do
85
77
  line_item = line_items_hash[k]
86
78
  self.class.ensure_variant_id_from_api(line_item)
87
79
 
88
- extra_params = line_item.except(:variant_id, :quantity, :sku)
80
+ extra_params = line_item.except(:variant_id, :quantity)
89
81
  line_item = self.contents.add(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
90
82
  line_item.update_attributes(extra_params) unless extra_params.empty?
91
83
  rescue Exception => e
@@ -97,11 +89,10 @@ Spree::Order.class_eval do
97
89
  def create_adjustments_from_api(adjustments)
98
90
  adjustments.each do |a|
99
91
  begin
100
- a.symbolize_keys! # For backwards compatibility sake (before it acccessed string keys)
101
92
  adjustment = self.adjustments.build(:amount => a[:amount].to_f,
102
93
  :label => a[:label])
103
94
  adjustment.save!
104
- adjustment.finalize!
95
+ adjustment.close!
105
96
  rescue Exception => e
106
97
  raise "Order import adjustments: #{e.message} #{a}"
107
98
  end
@@ -9,3 +9,7 @@ child :variant do
9
9
  attributes :product_id
10
10
  child(:images => :images) { extends "spree/api/images/show" }
11
11
  end
12
+
13
+ child :adjustments => :adjustments do
14
+ extends "spree/api/adjustments/show"
15
+ end
@@ -2,7 +2,6 @@ cache @order
2
2
  attributes *order_attributes
3
3
  node(:display_item_total) { |o| o.display_item_total.to_s }
4
4
  node(:total_quantity) { |o| o.line_items.sum(:quantity) }
5
- node(:display_tax_total) { |o| o.display_tax_total }
6
5
  node(:display_total) { |o| o.display_total.to_s }
7
6
  node(:display_ship_total) { |o| o.display_ship_total }
8
7
  node(:token) { |o| o.token }
@@ -1,17 +1,14 @@
1
1
  object @product
2
- cache [current_currency, root_object]
2
+ cache [current_currency, @product]
3
3
  attributes *product_attributes
4
4
  node(:display_price) { |p| p.display_price.to_s }
5
- child :variants_including_master => :variants do
6
- attributes *variant_attributes
5
+ node(:has_variants) { |p| p.has_variants? }
6
+ child :master => :master do
7
+ extends "spree/api/variants/show"
8
+ end
7
9
 
8
- child :option_values => :option_values do
9
- extends "spree/api/option_values/show"
10
- end
11
-
12
- child :images => :images do
13
- extends "spree/api/images/show"
14
- end
10
+ child :variants => :variants do
11
+ extends "spree/api/variants/show"
15
12
  end
16
13
 
17
14
  child :option_types => :option_types do
@@ -0,0 +1,4 @@
1
+ object false
2
+ node(:success) { @handler.success }
3
+ node(:error) { @handler.error }
4
+ node(:successful) { @handler.successful? }
@@ -5,5 +5,5 @@ node(:current_page) { params[:page] ? params[:page].to_i : 1 }
5
5
  node(:pages) { @variants.num_pages }
6
6
 
7
7
  child(@variants => :variants) do
8
- extends "spree/api/variants/big_variant"
8
+ extends "spree/api/variants/variant_full"
9
9
  end
@@ -1,5 +1,4 @@
1
1
  object @variant
2
2
  cache @variant
3
- extends "spree/api/variants/variant"
4
- child(:option_values => :option_values) { attributes *option_value_attributes }
5
- child(:images => :images) { extends "spree/api/images/show" }
3
+ extends "spree/api/variants/variant_full"
4
+ child(:images => :images) { extends "spree/api/images/show" }
@@ -1,5 +1,7 @@
1
1
  attributes *variant_attributes
2
+ node(:display_price) { |p| p.display_price.to_s }
2
3
  node(:options_text) { |v| v.options_text }
4
+ node(:in_stock) { |v| v.in_stock? }
3
5
  child :option_values => :option_values do
4
6
  attributes *option_value_attributes
5
7
  end
data/config/routes.rb CHANGED
@@ -31,10 +31,6 @@ Spree::Core::Engine.add_routes do
31
31
  get '/orders/mine', :to => 'orders#mine', :as => 'my_orders'
32
32
 
33
33
  resources :orders do
34
- member do
35
- put :apply_coupon_code
36
- end
37
-
38
34
  resources :addresses, :only => [:show, :update]
39
35
 
40
36
  resources :return_authorizations do
@@ -47,6 +43,7 @@ Spree::Core::Engine.add_routes do
47
43
  member do
48
44
  put :cancel
49
45
  put :empty
46
+ put :apply_coupon_code
50
47
  end
51
48
 
52
49
  resources :line_items
@@ -84,7 +81,9 @@ Spree::Core::Engine.add_routes do
84
81
  end
85
82
  end
86
83
  end
84
+
87
85
  resources :taxons, :only => [:index]
86
+
88
87
  resources :inventory_units, :only => [:show, :update]
89
88
  resources :users
90
89
  resources :properties
@@ -95,5 +94,8 @@ Spree::Core::Engine.add_routes do
95
94
 
96
95
  get '/config/money', :to => 'config#money'
97
96
  get '/config', :to => 'config#show'
97
+
98
+ put '/classifications', :to => 'classifications#update', :as => :classifications
99
+ get '/taxons/products', :to => 'taxons#products', :as => :taxon_products
98
100
  end
99
101
  end
@@ -5,7 +5,6 @@ module Spree
5
5
  module ControllerSetup
6
6
  def self.included(klass)
7
7
  klass.class_eval do
8
- include AbstractController::Rendering
9
8
  include AbstractController::ViewPaths
10
9
  include AbstractController::Callbacks
11
10
  include AbstractController::Helpers
@@ -17,6 +17,7 @@ module Spree
17
17
  end
18
18
 
19
19
  def stub_authentication!
20
+ controller.stub :check_for_user_or_api_key
20
21
  Spree::LegacyUser.stub(:find_by).with(hash_including(:spree_api_key)) { current_api_user }
21
22
  end
22
23
 
@@ -7,50 +7,76 @@ module Spree
7
7
  before do
8
8
  stub_authentication!
9
9
  @address = create(:address)
10
- @order = create(:order, :bill_address => @address)
11
10
  end
12
-
13
- context "with their own address" do
11
+
12
+ context "with order" do
14
13
  before do
15
- Order.any_instance.stub :user => current_api_user
14
+ @order = create(:order, :bill_address => @address)
16
15
  end
16
+
17
+ context "with their own address" do
18
+ before do
19
+ Order.any_instance.stub :user => current_api_user
20
+ end
17
21
 
18
- it "gets an address" do
19
- api_get :show, :id => @address.id, :order_id => @order.number
20
- json_response['address1'].should eq @address.address1
21
- end
22
+ it "gets an address" do
23
+ api_get :show, :id => @address.id, :order_id => @order.number
24
+ json_response['address1'].should eq @address.address1
25
+ end
22
26
 
23
- it "updates an address" do
24
- api_put :update, :id => @address.id, :order_id => @order.number,
25
- :address => { :address1 => "123 Test Lane" }
26
- json_response['address1'].should eq '123 Test Lane'
27
- end
27
+ it "updates an address" do
28
+ api_put :update, :id => @address.id, :order_id => @order.number,
29
+ :address => { :address1 => "123 Test Lane" }
30
+ json_response['address1'].should eq '123 Test Lane'
31
+ end
28
32
 
29
- it "receives the errors object if address is invalid" do
30
- api_put :update, :id => @address.id, :order_id => @order.number,
31
- :address => { :address1 => "" }
33
+ it "receives the errors object if address is invalid" do
34
+ api_put :update, :id => @address.id, :order_id => @order.number,
35
+ :address => { :address1 => "" }
32
36
 
33
- json_response['error'].should_not be_nil
34
- json_response['errors'].should_not be_nil
35
- json_response['errors']['address1'].first.should eq "can't be blank"
37
+ json_response['error'].should_not be_nil
38
+ json_response['errors'].should_not be_nil
39
+ json_response['errors']['address1'].first.should eq "can't be blank"
40
+ end
36
41
  end
37
- end
38
42
 
39
- context "on an address that does not belong to this order" do
40
- before do
41
- @order.bill_address_id = nil
42
- @order.ship_address = nil
43
+ context "on an address that does not belong to this order" do
44
+ before do
45
+ @order.bill_address_id = nil
46
+ @order.ship_address = nil
47
+ end
48
+
49
+ it "cannot retreive address information" do
50
+ api_get :show, :id => @address.id, :order_id => @order.number
51
+ assert_unauthorized!
52
+ end
53
+
54
+ it "cannot update address information" do
55
+ api_get :update, :id => @address.id, :order_id => @order.number
56
+ assert_unauthorized!
57
+ end
43
58
  end
59
+ end
60
+
61
+ context "without order" do
62
+ context "with their own address" do
63
+ before do
64
+ Address.any_instance.stub :user => current_api_user
65
+ end
44
66
 
45
- it "cannot retreive address information" do
46
- api_get :show, :id => @address.id, :order_id => @order.number
47
- assert_unauthorized!
67
+ it "gets an address" do
68
+ api_get :show, :id => @address.id
69
+ json_response['address1'].should eq @address.address1
70
+ end
48
71
  end
49
72
 
50
- it "cannot update address information" do
51
- api_get :update, :id => @address.id, :order_id => @order.number
52
- assert_unauthorized!
73
+ context "on an address that does not belong to this user" do
74
+ it "cannot update address information" do
75
+ api_put :update, :id => @address.id, :address => { :address1 => "123 Test Lane" }
76
+ json_response['address1'].should be_nil
77
+ assert_unauthorized!
78
+ end
53
79
  end
54
80
  end
55
81
  end
56
- end
82
+ end
@@ -21,42 +21,6 @@ describe Spree::Api::BaseController do
21
21
  end
22
22
  end
23
23
 
24
- context "when validating based on an order token" do
25
- let!(:order) { create :order }
26
-
27
- context "with a correct order token" do
28
- it "succeeds" do
29
- api_get :index, order_token: order.token, order_id: order.number
30
- response.status.should == 200
31
- end
32
- end
33
-
34
- context "with an incorrect order token" do
35
- it "returns unauthorized" do
36
- api_get :index, order_token: "NOT_A_TOKEN", order_id: order.number
37
- response.status.should == 401
38
- end
39
- end
40
- end
41
-
42
- context "when validating based on an order token" do
43
- let!(:order) { create :order }
44
-
45
- context "with a correct order token" do
46
- it "succeeds" do
47
- api_get :index, order_token: order.token, order_id: order.number
48
- response.status.should == 200
49
- end
50
- end
51
-
52
- context "with an incorrect order token" do
53
- it "returns unauthorized" do
54
- api_get :index, order_token: "NOT_A_TOKEN", order_id: order.number
55
- response.status.should == 401
56
- end
57
- end
58
- end
59
-
60
24
  context "cannot make a request to the API" do
61
25
  it "without an API key" do
62
26
  api_get :index