spree_api 2.1.12 → 2.2.0

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 (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