spree_api 2.1.1 → 2.1.2

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