spree_api 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/app/controllers/spree/api/base_controller.rb +10 -1
  4. data/app/controllers/spree/api/countries_controller.rb +2 -0
  5. data/app/controllers/spree/api/orders_controller.rb +9 -2
  6. data/app/controllers/spree/api/payments_controller.rb +13 -2
  7. data/app/controllers/spree/api/states_controller.rb +2 -0
  8. data/app/controllers/spree/api/stock_items_controller.rb +2 -1
  9. data/app/controllers/spree/api/stock_locations_controller.rb +1 -0
  10. data/app/controllers/spree/api/stock_movements_controller.rb +1 -0
  11. data/app/helpers/spree/api/api_helpers.rb +2 -3
  12. data/app/models/spree/option_value_decorator.rb +4 -0
  13. data/app/models/spree/order_decorator.rb +25 -18
  14. data/app/views/spree/api/payments/credit_over_limit.v1.rabl +1 -1
  15. data/app/views/spree/api/payments/new.v1.rabl +0 -1
  16. data/app/views/spree/api/payments/update_forbidden.v1.rabl +2 -0
  17. data/config/locales/en.yml +3 -1
  18. data/config/routes.rb +1 -1
  19. data/lib/spree/api/responders/rabl_template.rb +1 -1
  20. data/spec/controllers/spree/api/base_controller_spec.rb +1 -1
  21. data/spec/controllers/spree/api/checkouts_controller_spec.rb +14 -0
  22. data/spec/controllers/spree/api/orders_controller_spec.rb +84 -17
  23. data/spec/controllers/spree/api/payments_controller_spec.rb +118 -77
  24. data/spec/controllers/spree/api/stock_items_controller_spec.rb +62 -26
  25. data/spec/controllers/spree/api/stock_locations_controller_spec.rb +56 -29
  26. data/spec/controllers/spree/api/stock_movements_controller_spec.rb +51 -27
  27. data/spec/controllers/spree/api/zones_controller_spec.rb +2 -2
  28. data/spec/models/spree/order_spec.rb +71 -4
  29. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fd56fb7c9cb4be0a012aac73a49541df13c15a8
4
- data.tar.gz: 812a59cc1cb657b17da7ed45433a61e3dbeb355e
3
+ metadata.gz: 2b88f0bb66f6241fa750c60df09e559515380ff9
4
+ data.tar.gz: c8c8111f3b16f720c3219105faf7d5a912dc5c45
5
5
  SHA512:
6
- metadata.gz: 0816177016ba6c6e6f911287b2dee7c3508938c8053ddf29d2f2fce86f79b6816fbebcd8cae725d66f55d775b0c241fa8e3965bf7e7ad4d9bee805411ea7e17f
7
- data.tar.gz: c5ec8647be4cf1fa347456b8ae8ff58727c59c986aa15babb28d7d87ee22e08144d50c3b6841e3b7473854e3107e9880b338fe9fdc0bb23a0d899797f51e605d
6
+ metadata.gz: 1c330a76aaf9c02fdfc52aa1c5da7cec9e1d20bd4eb607ae622dd7b9c3898a389b9f6955c8b0d0f52fda7ae02c3e052e100863fcd5535a80d98897b2cd9753e9
7
+ data.tar.gz: 9676ad30355100421c95579e8089ef471f0bd267327887ab9582f081ea5731ca0c7034cb68d37139528e5325bb03419b02f3eb8fbf1b14153de34935a4cd72ff
@@ -1,3 +1,21 @@
1
+ ## Spree 2.1.2 ##
2
+
3
+ * States and countries endpoints now do not require authentication, even if it is forced with the `requires_authentication` setting. This is so the frontend's checkout address page can still work.
4
+
5
+ *Ryan Bigg*
6
+
7
+ * You can now assign a location to a shipment when creating it through the orders API. f3ef2e1d46bc972442acbbcaae928e6ef2dc0eb5
8
+
9
+ *Washington Luiz*
10
+
11
+ * Stock Items, Stock Movements and Stock Locations are now invisible to non-admin users.
12
+
13
+ *Ryan Bigg*
14
+
15
+ * Fixed issue where X-Spree-Token header was being ignored. #3798
16
+
17
+ *Washington Luiz*
18
+
1
19
  ## Spree 2.1.0 ##
2
20
 
3
21
  * The Products API endpoint now returns an additional key called `shipping_category_id`, and also requires `shipping_category_id` on create.
@@ -45,6 +45,15 @@ module Spree
45
45
  end.with_indifferent_access
46
46
  end
47
47
 
48
+ # users should be able to set price when importing orders via api
49
+ def permitted_line_item_attributes
50
+ if current_api_user.has_spree_role?("admin")
51
+ super << [:price]
52
+ else
53
+ super
54
+ end
55
+ end
56
+
48
57
  private
49
58
 
50
59
  def set_content_type
@@ -109,7 +118,7 @@ module Spree
109
118
  end
110
119
 
111
120
  def api_key
112
- request.headers.env["X-Spree-Token"] || params[:token]
121
+ request.headers["X-Spree-Token"] || params[:token]
113
122
  end
114
123
  helper_method :api_key
115
124
 
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  module Api
3
3
  class CountriesController < Spree::Api::BaseController
4
+ skip_before_filter :check_for_user_or_api_key
5
+ skip_before_filter :authenticate_user
4
6
 
5
7
  def index
6
8
  @countries = Country.accessible_by(current_ability, :read).ransack(params[:q]).result.
@@ -50,7 +50,11 @@ module Spree
50
50
  # hence the use of the update_line_items method, defined within order_decorator.rb.
51
51
  order_params.delete("line_items_attributes")
52
52
  if @order.update_attributes(order_params)
53
- @order.update_line_items(params[:order][:line_items])
53
+ line_item_attributes = params[:order][:line_items].map do |id, attributes|
54
+ [id, attributes.slice(*permitted_line_item_attributes)]
55
+ end
56
+ line_item_attributes = Hash[line_item_attributes].delete_if { |k,v| v.empty? }
57
+ @order.update_line_items(line_item_attributes)
54
58
  @order.line_items.reload
55
59
  @order.update!
56
60
  respond_with(@order, default_template: :show)
@@ -72,6 +76,10 @@ module Spree
72
76
  end
73
77
  end
74
78
 
79
+ def permitted_order_attributes
80
+ super << [:import]
81
+ end
82
+
75
83
  def next!(options={})
76
84
  if @order.valid? && @order.next
77
85
  render :show, status: options[:status] || 200
@@ -88,7 +96,6 @@ module Spree
88
96
  def before_delivery
89
97
  @order.create_proposed_shipments
90
98
  end
91
-
92
99
  end
93
100
  end
94
101
  end
@@ -3,7 +3,7 @@ module Spree
3
3
  class PaymentsController < Spree::Api::BaseController
4
4
 
5
5
  before_filter :find_order
6
- before_filter :find_payment, only: [:show, :authorize, :purchase, :capture, :void, :credit]
6
+ before_filter :find_payment, only: [:update, :show, :authorize, :purchase, :capture, :void, :credit]
7
7
 
8
8
  def index
9
9
  @payments = @order.payments.ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
@@ -24,6 +24,17 @@ module Spree
24
24
  end
25
25
  end
26
26
 
27
+ def update
28
+ authorize! params[:action], @payment
29
+ if ! @payment.pending?
30
+ render 'update_forbidden', status: 403
31
+ elsif @payment.update_attributes(payment_params)
32
+ respond_with(@payment, default_template: :show)
33
+ else
34
+ invalid_resource!(@payment)
35
+ end
36
+ end
37
+
27
38
  def show
28
39
  respond_with(@payment)
29
40
  end
@@ -46,7 +57,7 @@ module Spree
46
57
 
47
58
  def credit
48
59
  if params[:amount].to_f > @payment.credit_allowed
49
- render 'spree/api/payments/credit_over_limit', status: 422
60
+ render 'credit_over_limit', status: 422
50
61
  else
51
62
  perform_payment_action(:credit, params[:amount])
52
63
  end
@@ -2,6 +2,8 @@ module Spree
2
2
  module Api
3
3
  class StatesController < Spree::Api::BaseController
4
4
  skip_before_filter :set_expiry
5
+ skip_before_filter :check_for_user_or_api_key
6
+ skip_before_filter :authenticate_user
5
7
 
6
8
  def index
7
9
  @states = scope.ransack(params[:q]).result.
@@ -63,7 +63,8 @@ module Spree
63
63
  end
64
64
 
65
65
  def scope
66
- @stock_location.stock_items.accessible_by(current_ability, :read).includes(:variant => :product)
66
+ includes = {:variant => [{ :option_values => :option_type }, :product] }
67
+ @stock_location.stock_items.accessible_by(current_ability, :read).includes(includes)
67
68
  end
68
69
 
69
70
  def stock_item_params
@@ -2,6 +2,7 @@ module Spree
2
2
  module Api
3
3
  class StockLocationsController < Spree::Api::BaseController
4
4
  def index
5
+ authorize! :read, StockLocation
5
6
  @stock_locations = StockLocation.accessible_by(current_ability, :read).order('name ASC').ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
6
7
  respond_with(@stock_locations)
7
8
  end
@@ -4,6 +4,7 @@ module Spree
4
4
  before_filter :stock_location, except: [:update, :destroy]
5
5
 
6
6
  def index
7
+ authorize! :read, StockMovement
7
8
  @stock_movements = scope.ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
8
9
  respond_with(@stock_movements)
9
10
  end
@@ -28,7 +28,7 @@ module Spree
28
28
  end
29
29
 
30
30
  def option_value_attributes
31
- [:id, :name, :presentation, :option_type_name, :option_type_id]
31
+ [:id, :name, :presentation, :option_type_name, :option_type_id, :option_type_presentation]
32
32
  end
33
33
 
34
34
  def order_attributes
@@ -44,7 +44,7 @@ module Spree
44
44
  end
45
45
 
46
46
  def payment_attributes
47
- [:id, :source_type, :source_id, :amount, :payment_method_id, :response_code, :state, :avs_response, :created_at, :updated_at]
47
+ [:id, :source_type, :source_id, :amount, :display_amount, :payment_method_id, :response_code, :state, :avs_response, :created_at, :updated_at]
48
48
  end
49
49
 
50
50
  def payment_method_attributes
@@ -113,4 +113,3 @@ module Spree
113
113
  end
114
114
  end
115
115
  end
116
-
@@ -2,4 +2,8 @@ Spree::OptionValue.class_eval do
2
2
  def option_type_name
3
3
  option_type.name
4
4
  end
5
+
6
+ def option_type_presentation
7
+ option_type.presentation
8
+ end
5
9
  end
@@ -1,28 +1,34 @@
1
1
  Spree::Order.class_eval do
2
2
  def self.build_from_api(user, params)
3
- completed_at = params.delete(:completed_at)
4
- line_items = params.delete(:line_items_attributes) || {}
5
- shipments = params.delete(:shipments_attributes) || []
6
- payments = params.delete(:payments_attributes) || []
7
- adjustments = params.delete(:adjustments_attributes) || []
3
+ begin
4
+ ensure_country_id_from_api params[:ship_address_attributes]
5
+ ensure_state_id_from_api params[:ship_address_attributes]
6
+ ensure_country_id_from_api params[:bill_address_attributes]
7
+ ensure_state_id_from_api params[:bill_address_attributes]
8
8
 
9
- ensure_country_id_from_api params[:ship_address_attributes]
10
- ensure_state_id_from_api params[:ship_address_attributes]
9
+ order = create!
10
+ order.associate_user!(user)
11
11
 
12
- ensure_country_id_from_api params[:bill_address_attributes]
13
- ensure_state_id_from_api params[:bill_address_attributes]
12
+ order.create_shipments_from_api params.delete(:shipments_attributes) || []
13
+ order.create_line_items_from_api params.delete(:line_items_attributes) || {}
14
+ order.create_adjustments_from_api params.delete(:adjustments_attributes) || []
15
+ order.create_payments_from_api params.delete(:payments_attributes) || []
16
+ order.complete_from_api params.delete(:completed_at)
14
17
 
15
- order = create!(params)
16
- order.associate_user!(user)
18
+ destroy_automatic_taxes_on_import(order, params)
19
+ order.update_attributes!(params)
17
20
 
18
- order.create_shipments_from_api(shipments)
19
- order.create_line_items_from_api(line_items)
20
- order.create_adjustments_from_api(adjustments)
21
- order.create_payments_from_api(payments)
22
- order.complete_from_api(completed_at)
21
+ order.reload
22
+ rescue Exception => e
23
+ order.destroy if order && order.persisted?
24
+ raise e.message
25
+ end
26
+ end
23
27
 
24
- order.save!
25
- order.reload
28
+ def self.destroy_automatic_taxes_on_import(order, params)
29
+ if params.delete :import
30
+ order.adjustments.tax.destroy_all
31
+ end
26
32
  end
27
33
 
28
34
  def complete_from_api(completed_at)
@@ -37,6 +43,7 @@ Spree::Order.class_eval do
37
43
  begin
38
44
  shipment = shipments.build
39
45
  shipment.tracking = s[:tracking]
46
+ shipment.stock_location = Spree::StockLocation.find_by_name!(s[:stock_location])
40
47
 
41
48
  inventory_units = s[:inventory_units] || []
42
49
  inventory_units.each do |iu|
@@ -1,2 +1,2 @@
1
1
  object false
2
- node(:error) { I18n.t(:credit_over_limit, :limit => @payment.credit_allowed, :scope => 'spree.api') }
2
+ node(:error) { I18n.t(:credit_over_limit, :limit => @payment.credit_allowed, :scope => 'spree.api.payment') }
@@ -3,4 +3,3 @@ node(:attributes) { [*payment_attributes] }
3
3
  child @payment_methods => :payment_methods do
4
4
  attributes *payment_method_attributes
5
5
  end
6
-
@@ -0,0 +1,2 @@
1
+ object false
2
+ node(:error) { I18n.t(:update_forbidden, :state => @payment.state, :scope => 'spree.api.payment') }
@@ -7,7 +7,6 @@ en:
7
7
  invalid_resource: "Invalid resource. Please fix errors and try again."
8
8
  resource_not_found: "The resource you were looking for could not be found."
9
9
  gateway_error: "There was a problem with the payment gateway: %{text}"
10
- credit_over_limit: "This payment can only be credited up to %{limit}. Please specify an amount less than or equal to this number."
11
10
  access: "API Access"
12
11
  key: "Key"
13
12
  clear_key: "Clear key"
@@ -19,6 +18,9 @@ en:
19
18
  order:
20
19
  could_not_transition: "The order could not be transitioned. Please fix the errors and try again."
21
20
  invalid_shipping_method: "Invalid shipping method specified."
21
+ payment:
22
+ credit_over_limit: "This payment can only be credited up to %{limit}. Please specify an amount less than or equal to this number."
23
+ update_forbidden: "This payment cannot be updated because it is %{state}."
22
24
  shipment:
23
25
  cannot_ready: "Cannot ready shipment."
24
26
  stock_location_required: "A stock_location_id parameter must be provided in order to retrieve stock movements."
@@ -1,4 +1,4 @@
1
- Spree::Core::Engine.routes.draw do
1
+ Spree::Core::Engine.add_routes do
2
2
  namespace :admin do
3
3
  resources :users do
4
4
  member do
@@ -14,7 +14,7 @@ module Spree
14
14
  end
15
15
 
16
16
  def template
17
- request.headers.env['X-Spree-Template'] || controller.params[:template] || options[:default_template]
17
+ request.headers['X-Spree-Template'] || controller.params[:template] || options[:default_template]
18
18
  end
19
19
  end
20
20
  end
@@ -29,7 +29,7 @@ describe Spree::Api::BaseController do
29
29
  end
30
30
 
31
31
  it "with an invalid API key" do
32
- request.env["X-Spree-Token"] = "fake_key"
32
+ request.headers["X-Spree-Token"] = "fake_key"
33
33
  get :index, {}
34
34
  json_response.should == { "error" => "Invalid API key (fake_key) specified." }
35
35
  response.status.should == 401
@@ -29,6 +29,12 @@ module Spree
29
29
  json_response['number'].should be_present
30
30
  response.status.should == 201
31
31
  end
32
+
33
+ it "assigns email when creating a new order" do
34
+ api_post :create, :order => { :email => "guest@spreecommerce.com" }
35
+ expect(json_response['email']).not_to eq controller.current_api_user
36
+ expect(json_response['email']).to eq "guest@spreecommerce.com"
37
+ end
32
38
  end
33
39
 
34
40
  context "PUT 'update'" do
@@ -176,6 +182,14 @@ module Spree
176
182
  response.status.should == 200
177
183
  end
178
184
 
185
+ # Regression test for #3784
186
+ it "can update the special instructions for an order" do
187
+ instructions = "Don't drop it. (Please)"
188
+ api_put :update, :id => order.to_param, :order_token => order.token,
189
+ :order => { :special_instructions => instructions }
190
+ expect(json_response['special_instructions']).to eql(instructions)
191
+ end
192
+
179
193
  context "as an admin" do
180
194
  sign_in_as_admin!
181
195
  it "can assign a user to the order" do
@@ -5,6 +5,8 @@ module Spree
5
5
  render_views
6
6
 
7
7
  let!(:order) { create(:order) }
8
+ let(:variant) { create(:variant) }
9
+
8
10
  let(:attributes) { [:number, :item_total, :display_total, :total,
9
11
  :state, :adjustment_total,
10
12
  :user_id, :created_at, :updated_at,
@@ -12,6 +14,23 @@ module Spree
12
14
  :payment_state, :email, :special_instructions,
13
15
  :total_quantity, :display_item_total] }
14
16
 
17
+ let(:address_params) { { :country_id => Country.first.id, :state_id => State.first.id } }
18
+
19
+ let(:billing_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
20
+ :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
21
+ :country_id => Country.first.id, :state_id => State.first.id} }
22
+
23
+ let(:shipping_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
24
+ :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
25
+ :country_id => Country.first.id, :state_id => State.first.id} }
26
+
27
+ let!(:payment_method) { create(:payment_method) }
28
+
29
+ let(:current_api_user) do
30
+ user = Spree.user_class.new(:email => "spree@example.com")
31
+ user.generate_spree_api_key!
32
+ user
33
+ end
15
34
 
16
35
  before do
17
36
  stub_authentication!
@@ -68,22 +87,7 @@ module Spree
68
87
  assert_unauthorized!
69
88
  end
70
89
 
71
- let(:address_params) { { :country_id => Country.first.id, :state_id => State.first.id } }
72
- let(:billing_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
73
- :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
74
- :country_id => Country.first.id, :state_id => State.first.id} }
75
- let(:shipping_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
76
- :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
77
- :country_id => Country.first.id, :state_id => State.first.id} }
78
- let!(:payment_method) { create(:payment_method) }
79
- let(:current_api_user) do
80
- user = Spree.user_class.new(:email => "spree@example.com")
81
- user.generate_spree_api_key!
82
- user
83
- end
84
-
85
90
  it "can create an order" do
86
- variant = create(:variant)
87
91
  api_post :create, :order => { :line_items => { "0" => { :variant_id => variant.to_param, :quantity => 5 } } }
88
92
  response.status.should == 201
89
93
  order = Order.last
@@ -99,7 +103,6 @@ module Spree
99
103
 
100
104
  # Regression test for #3404
101
105
  it "can specify additional parameters for a line item" do
102
- variant = create(:variant)
103
106
  Order.should_receive(:create!).and_return(order = Spree::Order.new)
104
107
  order.stub(:associate_user!)
105
108
  order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
@@ -116,9 +119,45 @@ module Spree
116
119
  response.status.should == 201
117
120
  end
118
121
 
122
+ it "cannot arbitrarily set the line items price" do
123
+ api_post :create, :order => {
124
+ :line_items => {
125
+ "0" => {
126
+ :price => 33.0, :variant_id => variant.to_param, :quantity => 5
127
+ }
128
+ }
129
+ }
130
+
131
+ expect(response.status).to eq 201
132
+ expect(Order.last.line_items.first.price.to_f).to eq(variant.price)
133
+ end
134
+
135
+ context "import" do
136
+ let(:tax_rate) { create(:tax_rate, amount: 0.05, calculator: Calculator::DefaultTax.create) }
137
+ let(:other_variant) { create(:variant) }
138
+
139
+ let(:order_params) do
140
+ {
141
+ :line_items => {
142
+ "0" => { :variant_id => variant.to_param, :quantity => 5 },
143
+ "1" => { :variant_id => other_variant.to_param, :quantity => 5 }
144
+ }
145
+ }
146
+ end
147
+
148
+ before { Zone.stub default_tax: tax_rate.zone }
149
+
150
+ it "doesnt persist any automatic tax adjustment" do
151
+ expect {
152
+ api_post :create, :order => order_params.merge(:import => true)
153
+ }.not_to change { Adjustment.count }
154
+
155
+ expect(response.status).to eq 201
156
+ end
157
+ end
158
+
119
159
  # Regression test for #3404
120
160
  it "does not update line item needlessly" do
121
- variant = create(:variant)
122
161
  Order.should_receive(:create!).and_return(order = Spree::Order.new)
123
162
  order.stub(:associate_user!)
124
163
  order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
@@ -180,6 +219,19 @@ module Spree
180
219
  json_response['line_items'].first['quantity'].should == 10
181
220
  end
182
221
 
222
+ it "cannot change the price of an existing line item" do
223
+ api_put :update, :id => order.to_param, :order => {
224
+ :line_items => {
225
+ line_item.id => { :price => 0 }
226
+ }
227
+ }
228
+
229
+ response.status.should == 200
230
+ json_response['line_items'].count.should == 1
231
+ expect(json_response['line_items'].first['price'].to_f).to_not eq(0)
232
+ expect(json_response['line_items'].first['price'].to_f).to eq(line_item.variant.price)
233
+ end
234
+
183
235
  it "can add billing address" do
184
236
  api_put :update, :id => order.to_param, :order => { :bill_address_attributes => billing_address }
185
237
 
@@ -357,6 +409,21 @@ module Spree
357
409
  end
358
410
  end
359
411
 
412
+ context "creation" do
413
+ it "can arbitrarily set the line items price" do
414
+ api_post :create, :order => {
415
+ :line_items => {
416
+ "0" => {
417
+ :price => 33.0, :variant_id => variant.to_param, :quantity => 5
418
+ }
419
+ }
420
+ }
421
+
422
+ expect(response.status).to eq 201
423
+ expect(Order.last.line_items.first.price.to_f).to eq(33.0)
424
+ end
425
+ end
426
+
360
427
  context "can cancel an order" do
361
428
  before do
362
429
  Spree::Config[:mails_from] = "spree@example.com"