spree_api 3.1.14 → 3.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/app/controllers/spree/api/base_controller.rb +2 -2
  4. data/app/controllers/spree/api/v1/addresses_controller.rb +1 -1
  5. data/app/controllers/spree/api/v1/classifications_controller.rb +1 -1
  6. data/app/controllers/spree/api/v1/images_controller.rb +3 -0
  7. data/app/controllers/spree/api/v1/inventory_units_controller.rb +3 -3
  8. data/app/controllers/spree/api/v1/line_items_controller.rb +3 -0
  9. data/app/controllers/spree/api/v1/option_types_controller.rb +16 -7
  10. data/app/controllers/spree/api/v1/option_values_controller.rb +6 -3
  11. data/app/controllers/spree/api/v1/orders_controller.rb +13 -24
  12. data/app/controllers/spree/api/v1/payments_controller.rb +0 -1
  13. data/app/controllers/spree/api/v1/products_controller.rb +8 -5
  14. data/app/controllers/spree/api/v1/stock_items_controller.rb +1 -1
  15. data/app/controllers/spree/api/v1/stock_locations_controller.rb +1 -1
  16. data/app/controllers/spree/api/v1/tags_controller.rb +28 -0
  17. data/app/controllers/spree/api/v1/taxonomies_controller.rb +7 -4
  18. data/app/controllers/spree/api/v1/taxons_controller.rb +4 -1
  19. data/app/controllers/spree/api/v1/users_controller.rb +5 -3
  20. data/app/controllers/spree/api/v1/zones_controller.rb +3 -3
  21. data/app/helpers/spree/api/api_helpers.rb +4 -1
  22. data/app/models/spree/api_configuration.rb +1 -1
  23. data/app/views/spree/api/errors/invalid_api_key.v1.rabl +1 -1
  24. data/app/views/spree/api/errors/invalid_resource.v1.rabl +1 -1
  25. data/app/views/spree/api/errors/must_specify_api_key.v1.rabl +1 -1
  26. data/app/views/spree/api/errors/not_found.v1.rabl +1 -1
  27. data/app/views/spree/api/errors/unauthorized.v1.rabl +1 -1
  28. data/app/views/spree/api/v1/countries/show.v1.rabl +1 -1
  29. data/app/views/spree/api/v1/line_items/show.v1.rabl +2 -2
  30. data/app/views/spree/api/v1/option_types/show.v1.rabl +1 -1
  31. data/app/views/spree/api/v1/orders/invalid_shipping_method.v1.rabl +1 -1
  32. data/app/views/spree/api/v1/orders/payment.v1.rabl +1 -1
  33. data/app/views/spree/api/v1/orders/show.v1.rabl +9 -9
  34. data/app/views/spree/api/v1/payments/credit_over_limit.v1.rabl +1 -1
  35. data/app/views/spree/api/v1/payments/update_forbidden.v1.rabl +1 -1
  36. data/app/views/spree/api/v1/products/show.v1.rabl +5 -5
  37. data/app/views/spree/api/v1/shipments/cannot_ready_shipment.v1.rabl +1 -1
  38. data/app/views/spree/api/v1/shipments/show.v1.rabl +7 -7
  39. data/app/views/spree/api/v1/shipments/small.v1.rabl +8 -8
  40. data/app/views/spree/api/v1/tags/index.v1.rabl +9 -0
  41. data/app/views/spree/api/v1/taxonomies/jstree.rabl +2 -2
  42. data/app/views/spree/api/v1/taxonomies/nested.v1.rabl +2 -2
  43. data/app/views/spree/api/v1/taxons/jstree.rabl +3 -3
  44. data/app/views/spree/api/v1/taxons/show.v1.rabl +1 -1
  45. data/app/views/spree/api/v1/taxons/taxons.v1.rabl +1 -1
  46. data/app/views/spree/api/v1/users/show.v1.rabl +3 -2
  47. data/app/views/spree/api/v1/variants/big.v1.rabl +3 -3
  48. data/app/views/spree/api/v1/variants/small.v1.rabl +3 -2
  49. data/app/views/spree/api/v1/zones/show.v1.rabl +1 -1
  50. data/config/routes.rb +4 -6
  51. data/db/migrate/20100107141738_add_api_key_to_spree_users.rb +2 -2
  52. data/db/migrate/20120411123334_resize_api_key_field.rb +2 -2
  53. data/db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb +1 -1
  54. data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +1 -1
  55. data/lib/spree/api/engine.rb +11 -3
  56. data/lib/spree/api/responders/rabl_template.rb +1 -1
  57. data/lib/spree/api/testing_support/caching.rb +2 -2
  58. data/spec/controllers/spree/api/base_controller_spec.rb +96 -0
  59. data/spec/controllers/spree/api/v1/addresses_controller_spec.rb +56 -0
  60. data/spec/controllers/spree/api/v1/checkouts_controller_spec.rb +363 -0
  61. data/spec/controllers/spree/api/v1/classifications_controller_spec.rb +48 -0
  62. data/spec/controllers/spree/api/v1/countries_controller_spec.rb +48 -0
  63. data/spec/controllers/spree/api/v1/credit_cards_controller_spec.rb +80 -0
  64. data/spec/controllers/spree/api/v1/images_controller_spec.rb +114 -0
  65. data/spec/controllers/spree/api/v1/inventory_units_controller_spec.rb +48 -0
  66. data/spec/controllers/spree/api/v1/line_items_controller_spec.rb +203 -0
  67. data/spec/controllers/spree/api/v1/option_types_controller_spec.rb +122 -0
  68. data/spec/controllers/spree/api/v1/option_values_controller_spec.rb +141 -0
  69. data/spec/controllers/spree/api/v1/orders_controller_spec.rb +735 -0
  70. data/spec/controllers/spree/api/v1/payments_controller_spec.rb +234 -0
  71. data/spec/controllers/spree/api/v1/product_properties_controller_spec.rb +147 -0
  72. data/spec/controllers/spree/api/v1/products_controller_spec.rb +409 -0
  73. data/spec/controllers/spree/api/v1/promotion_application_spec.rb +50 -0
  74. data/spec/controllers/spree/api/v1/promotions_controller_spec.rb +64 -0
  75. data/spec/controllers/spree/api/v1/properties_controller_spec.rb +102 -0
  76. data/spec/controllers/spree/api/v1/return_authorizations_controller_spec.rb +161 -0
  77. data/spec/controllers/spree/api/v1/shipments_controller_spec.rb +187 -0
  78. data/spec/controllers/spree/api/v1/states_controller_spec.rb +86 -0
  79. data/spec/controllers/spree/api/v1/stock_items_controller_spec.rb +143 -0
  80. data/spec/controllers/spree/api/v1/stock_locations_controller_spec.rb +113 -0
  81. data/spec/controllers/spree/api/v1/stock_movements_controller_spec.rb +84 -0
  82. data/spec/controllers/spree/api/v1/stores_controller_spec.rb +133 -0
  83. data/spec/controllers/spree/api/v1/tags_controller_spec.rb +102 -0
  84. data/spec/controllers/spree/api/v1/taxonomies_controller_spec.rb +114 -0
  85. data/spec/controllers/spree/api/v1/taxons_controller_spec.rb +177 -0
  86. data/spec/controllers/spree/api/v1/unauthenticated_products_controller_spec.rb +26 -0
  87. data/spec/controllers/spree/api/v1/users_controller_spec.rb +153 -0
  88. data/spec/controllers/spree/api/v1/variants_controller_spec.rb +205 -0
  89. data/spec/controllers/spree/api/v1/zones_controller_spec.rb +91 -0
  90. data/spec/models/spree/legacy_user_spec.rb +19 -0
  91. data/spec/requests/rabl_cache_spec.rb +32 -0
  92. data/spec/requests/ransackable_attributes_spec.rb +79 -0
  93. data/spec/requests/version_spec.rb +19 -0
  94. data/spec/shared_examples/protect_product_actions.rb +17 -0
  95. data/spec/spec_helper.rb +60 -0
  96. data/spec/support/controller_hacks.rb +40 -0
  97. data/spec/support/database_cleaner.rb +14 -0
  98. data/spec/support/have_attributes_matcher.rb +13 -0
  99. data/spree_api.gemspec +7 -4
  100. metadata +99 -14
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::OptionTypesController, type: :controller do
5
+ render_views
6
+
7
+ let(:attributes) { [:id, :name, :presentation, :position] }
8
+ let!(:option_value) { create(:option_value) }
9
+ let!(:option_type) { option_value.option_type }
10
+
11
+ before do
12
+ stub_authentication!
13
+ end
14
+
15
+ def check_option_values(option_values)
16
+ expect(option_values.count).to eq(1)
17
+ expect(option_values.first).to have_attributes([:id, :name, :presentation,
18
+ :option_type_id, :option_type_name])
19
+ end
20
+
21
+ it "can list all option types" do
22
+ api_get :index
23
+ expect(json_response.count).to eq(1)
24
+ expect(json_response.first).to have_attributes(attributes)
25
+
26
+ check_option_values(json_response.first["option_values"])
27
+ end
28
+
29
+ it "can search for an option type" do
30
+ create(:option_type, name: "buzz")
31
+ api_get :index, q: { name_cont: option_type.name }
32
+ expect(json_response.count).to eq(1)
33
+ expect(json_response.first).to have_attributes(attributes)
34
+ end
35
+
36
+ it "can retrieve a list of specific option types" do
37
+ option_type_1 = create(:option_type)
38
+ option_type_2 = create(:option_type)
39
+ api_get :index, ids: "#{option_type.id},#{option_type_1.id}"
40
+ expect(json_response.count).to eq(2)
41
+
42
+ check_option_values(json_response.first["option_values"])
43
+ end
44
+
45
+ it "can list a single option type" do
46
+ api_get :show, id: option_type.id
47
+ expect(json_response).to have_attributes(attributes)
48
+ check_option_values(json_response["option_values"])
49
+ end
50
+
51
+ it "can learn how to create a new option type" do
52
+ api_get :new
53
+ expect(json_response["attributes"]).to eq(attributes.map(&:to_s))
54
+ expect(json_response["required_attributes"]).to_not be_empty
55
+ end
56
+
57
+ it "cannot create a new option type" do
58
+ api_post :create, option_type: {
59
+ name: "Option Type",
60
+ presentation: "Option Type"
61
+ }
62
+ assert_unauthorized!
63
+ end
64
+
65
+ it "cannot alter an option type" do
66
+ original_name = option_type.name
67
+ api_put :update, id: option_type.id,
68
+ option_type: {
69
+ name: "Option Type"
70
+ }
71
+ assert_not_found!
72
+ expect(option_type.reload.name).to eq(original_name)
73
+ end
74
+
75
+ it "cannot delete an option type" do
76
+ api_delete :destroy, id: option_type.id
77
+ assert_not_found!
78
+ expect { option_type.reload }.not_to raise_error
79
+ end
80
+
81
+ context "as an admin" do
82
+ sign_in_as_admin!
83
+
84
+ it "can create an option type" do
85
+ api_post :create, option_type: {
86
+ name: "Option Type",
87
+ presentation: "Option Type"
88
+ }
89
+ expect(json_response).to have_attributes(attributes)
90
+ expect(response.status).to eq(201)
91
+ end
92
+
93
+ it "cannot create an option type with invalid attributes" do
94
+ api_post :create, option_type: {}
95
+ expect(response.status).to eq(422)
96
+ end
97
+
98
+ it "can update an option type" do
99
+ original_name = option_type.name
100
+ api_put :update, id: option_type.id, option_type: {
101
+ name: "Option Type",
102
+ }
103
+ expect(response.status).to eq(200)
104
+
105
+ option_type.reload
106
+ expect(option_type.name).to eq("Option Type")
107
+ end
108
+
109
+ it "cannot update an option type with invalid attributes" do
110
+ api_put :update, id: option_type.id, option_type: {
111
+ name: ""
112
+ }
113
+ expect(response.status).to eq(422)
114
+ end
115
+
116
+ it "can delete an option type" do
117
+ api_delete :destroy, id: option_type.id
118
+ expect(response.status).to eq(204)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::OptionValuesController, type: :controller do
5
+ render_views
6
+
7
+ let(:attributes) { [:id, :name, :presentation, :option_type_name, :option_type_id, :option_type_presentation] }
8
+ let!(:option_value) { create(:option_value) }
9
+ let!(:option_type) { option_value.option_type }
10
+
11
+ before do
12
+ stub_authentication!
13
+ end
14
+
15
+ def check_option_values(option_values)
16
+ expect(option_values.count).to eq(1)
17
+ expect(option_values.first).to have_attributes([:id, :name, :presentation,
18
+ :option_type_name, :option_type_id])
19
+ end
20
+
21
+ context "without any option type scoping" do
22
+ before do
23
+ # Create another option value with a brand new option type
24
+ create(:option_value, option_type: create(:option_type))
25
+ end
26
+
27
+ it "can retrieve a list of all option values" do
28
+ api_get :index
29
+ expect(json_response.count).to eq(2)
30
+ expect(json_response.first).to have_attributes(attributes)
31
+ end
32
+ end
33
+
34
+ context "for a particular option type" do
35
+ let(:resource_scoping) { { option_type_id: option_type.id } }
36
+
37
+ it "can list all option values" do
38
+ api_get :index
39
+ expect(json_response.count).to eq(1)
40
+ expect(json_response.first).to have_attributes(attributes)
41
+ end
42
+
43
+ it "can search for an option type" do
44
+ create(:option_value, name: "buzz")
45
+ api_get :index, q: { name_cont: option_value.name }
46
+ expect(json_response.count).to eq(1)
47
+ expect(json_response.first).to have_attributes(attributes)
48
+ end
49
+
50
+ it "can retrieve a list of option types" do
51
+ option_value_1 = create(:option_value, option_type: option_type)
52
+ option_value_2 = create(:option_value, option_type: option_type)
53
+ api_get :index, ids: [option_value.id, option_value_1.id]
54
+ expect(json_response.count).to eq(2)
55
+ end
56
+
57
+ it "can list a single option value" do
58
+ api_get :show, id: option_value.id
59
+ expect(json_response).to have_attributes(attributes)
60
+ end
61
+
62
+ it "cannot create a new option value" do
63
+ api_post :create, option_value: {
64
+ name: "Option Value",
65
+ presentation: "Option Value"
66
+ }
67
+ assert_unauthorized!
68
+ end
69
+
70
+ it "cannot alter an option value" do
71
+ original_name = option_type.name
72
+ api_put :update, id: option_type.id,
73
+ option_value: {
74
+ name: "Option Value"
75
+ }
76
+ assert_not_found!
77
+ expect(option_type.reload.name).to eq(original_name)
78
+ end
79
+
80
+ it "cannot delete an option value" do
81
+ api_delete :destroy, id: option_type.id
82
+ assert_not_found!
83
+ expect { option_type.reload }.not_to raise_error
84
+ end
85
+
86
+ context "as an admin" do
87
+ sign_in_as_admin!
88
+
89
+ it "can learn how to create a new option value" do
90
+ api_get :new
91
+ expect(json_response["attributes"]).to eq(attributes.map(&:to_s))
92
+ expect(json_response["required_attributes"]).to_not be_empty
93
+ end
94
+
95
+ it "can create an option value" do
96
+ api_post :create, option_value: {
97
+ name: "Option Value",
98
+ presentation: "Option Value"
99
+ }
100
+ expect(json_response).to have_attributes(attributes)
101
+ expect(response.status).to eq(201)
102
+ end
103
+
104
+ it "cannot create an option type with invalid attributes" do
105
+ api_post :create, option_value: {}
106
+ expect(response.status).to eq(422)
107
+ end
108
+
109
+ it "can update an option value" do
110
+ original_name = option_value.name
111
+ api_put :update, id: option_value.id, option_value: {
112
+ name: "Option Value",
113
+ }
114
+ expect(response.status).to eq(200)
115
+
116
+ option_value.reload
117
+ expect(option_value.name).to eq("Option Value")
118
+ end
119
+
120
+ it "permits the correct attributes" do
121
+ expect(controller).to receive(:permitted_option_value_attributes)
122
+ api_put :update, id: option_value.id, option_value: {
123
+ name: ""
124
+ }
125
+ end
126
+
127
+ it "cannot update an option value with invalid attributes" do
128
+ api_put :update, id: option_value.id, option_value: {
129
+ name: ""
130
+ }
131
+ expect(response.status).to eq(422)
132
+ end
133
+
134
+ it "can delete an option value" do
135
+ api_delete :destroy, id: option_value.id
136
+ expect(response.status).to eq(204)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,735 @@
1
+ require 'spec_helper'
2
+ require 'spree/testing_support/bar_ability'
3
+
4
+ module Spree
5
+ describe Api::V1::OrdersController, type: :controller do
6
+ render_views
7
+
8
+ let!(:order) { create(:order) }
9
+ let(:variant) { create(:variant) }
10
+ let(:line_item) { create(:line_item) }
11
+
12
+ let(:attributes) do
13
+ [:number, :item_total, :display_total, :total, :state, :adjustment_total, :user_id,
14
+ :created_at, :updated_at, :completed_at, :payment_total, :shipment_state, :payment_state,
15
+ :email, :special_instructions, :total_quantity, :display_item_total, :currency, :considered_risky]
16
+ end
17
+
18
+ let(:address_params) { { country_id: Country.first.id, state_id: State.first.id } }
19
+
20
+ let(:current_api_user) do
21
+ user = Spree.user_class.new(email: "spree@example.com")
22
+ user.generate_spree_api_key!
23
+ user
24
+ end
25
+
26
+ before do
27
+ stub_authentication!
28
+ end
29
+
30
+ it "cannot view all orders" do
31
+ api_get :index
32
+ assert_unauthorized!
33
+ end
34
+
35
+ context "the current api user is not persisted" do
36
+ let(:current_api_user) { Spree.user_class.new }
37
+
38
+ it "returns a 401" do
39
+ api_get :mine
40
+ expect(response.status).to eq(401)
41
+ end
42
+ end
43
+
44
+ context "the current api user is authenticated" do
45
+ let(:current_api_user) { order.user }
46
+ let(:order) { create(:order, line_items: [line_item]) }
47
+
48
+ it "can view all of their own orders" do
49
+ api_get :mine
50
+
51
+ expect(response.status).to eq(200)
52
+ expect(json_response["pages"]).to eq(1)
53
+ expect(json_response["current_page"]).to eq(1)
54
+ expect(json_response["orders"].length).to eq(1)
55
+ expect(json_response["orders"].first["number"]).to eq(order.number)
56
+ expect(json_response["orders"].first["line_items"].length).to eq(1)
57
+ expect(json_response["orders"].first["line_items"].first["id"]).to eq(line_item.id)
58
+ end
59
+
60
+ it "can filter the returned results" do
61
+ api_get :mine, q: {completed_at_not_null: 1}
62
+
63
+ expect(response.status).to eq(200)
64
+ expect(json_response["orders"].length).to eq(0)
65
+ end
66
+
67
+ it "returns orders in reverse chronological order by completed_at" do
68
+ Timecop.scale(3600) do
69
+ order.update_columns completed_at: Time.current
70
+
71
+ order2 = Order.create user: order.user, completed_at: Time.current - 1.day
72
+ expect(order2.created_at).to be > order.created_at
73
+ order3 = Order.create user: order.user, completed_at: nil
74
+ expect(order3.created_at).to be > order2.created_at
75
+ order4 = Order.create user: order.user, completed_at: nil
76
+ expect(order4.created_at).to be > order3.created_at
77
+
78
+ api_get :mine
79
+ expect(response.status).to eq(200)
80
+ expect(json_response["pages"]).to eq(1)
81
+ expect(json_response["orders"].length).to eq(4)
82
+ expect(json_response["orders"][0]["number"]).to eq(order.number)
83
+ expect(json_response["orders"][1]["number"]).to eq(order2.number)
84
+ expect(json_response["orders"][2]["number"]).to eq(order4.number)
85
+ expect(json_response["orders"][3]["number"]).to eq(order3.number)
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'current' do
91
+ let(:current_api_user) { order.user }
92
+ let!(:order) { create(:order, line_items: [line_item]) }
93
+
94
+ subject do
95
+ api_get :current, format: 'json'
96
+ end
97
+
98
+ context "an incomplete order exists" do
99
+ it "returns that order" do
100
+ expect(JSON.parse(subject.body)['id']).to eq order.id
101
+ expect(subject).to be_success
102
+ end
103
+ end
104
+
105
+ context "multiple incomplete orders exist" do
106
+ it "returns the latest incomplete order" do
107
+ Timecop.scale(3600) do
108
+ new_order = Spree::Order.create! user: order.user
109
+ expect(new_order.created_at).to be > order.created_at
110
+ expect(JSON.parse(subject.body)['id']).to eq new_order.id
111
+ end
112
+ end
113
+ end
114
+
115
+ context "an incomplete order does not exist" do
116
+
117
+ before do
118
+ order.update_attribute(:state, order_state)
119
+ order.update_attribute(:completed_at, 5.minutes.ago)
120
+ end
121
+
122
+ ["complete", "returned", "awaiting_return"].each do |order_state|
123
+ context "order is in the #{order_state} state" do
124
+ let(:order_state) { order_state }
125
+
126
+ it "returns no content" do
127
+ expect(subject.status).to eq 204
128
+ expect(subject.body).to be_blank
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ it "can view their own order" do
136
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
137
+ api_get :show, id: order.to_param
138
+ expect(response.status).to eq(200)
139
+ expect(json_response).to have_attributes(attributes)
140
+ expect(json_response["adjustments"]).to be_empty
141
+ end
142
+
143
+ describe 'GET #show' do
144
+ let(:order) { create :order_with_line_items }
145
+ let(:adjustment) { FactoryGirl.create(:adjustment, order: order) }
146
+
147
+ subject { api_get :show, id: order.to_param }
148
+
149
+ before do
150
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
151
+ end
152
+
153
+ context 'when inventory information is present' do
154
+ it 'contains stock information on variant' do
155
+ subject
156
+ variant = json_response['line_items'][0]['variant']
157
+ expect(variant).to_not be_nil
158
+ expect(variant['in_stock']).to eq(false)
159
+ expect(variant['total_on_hand']).to eq(0)
160
+ expect(variant['is_backorderable']).to eq(true)
161
+ expect(variant['is_destroyed']).to eq(false)
162
+ end
163
+ end
164
+
165
+ context 'when shipment adjustments are present' do
166
+ before do
167
+ order.shipments.first.adjustments << adjustment
168
+ end
169
+
170
+ it 'contains adjustments on shipment' do
171
+ subject
172
+
173
+ # Test to insure shipment has adjustments
174
+ shipment = json_response['shipments'][0]
175
+ expect(shipment).to_not be_nil
176
+ expect(shipment['adjustments'][0]).not_to be_empty
177
+ expect(shipment['adjustments'][0]['label']).to eq(adjustment.label)
178
+ end
179
+ end
180
+ end
181
+
182
+ it "orders contain the basic checkout steps" do
183
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
184
+ api_get :show, id: order.to_param
185
+ expect(response.status).to eq(200)
186
+ expect(json_response["checkout_steps"]).to eq(["address", "delivery", "complete"])
187
+ end
188
+
189
+ # Regression test for #1992
190
+ it "can view an order not in a standard state" do
191
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
192
+ order.update_column(:state, 'shipped')
193
+ api_get :show, id: order.to_param
194
+ end
195
+
196
+ it "can not view someone else's order" do
197
+ allow_any_instance_of(Order).to receive_messages user: stub_model(Spree::LegacyUser)
198
+ api_get :show, id: order.to_param
199
+ assert_unauthorized!
200
+ end
201
+
202
+ it "can view an order if the token is known" do
203
+ api_get :show, id: order.to_param, order_token: order.guest_token
204
+ expect(response.status).to eq(200)
205
+ end
206
+
207
+ it "can view an order if the token is passed in header" do
208
+ request.headers["X-Spree-Order-Token"] = order.guest_token
209
+ api_get :show, id: order.to_param
210
+ expect(response.status).to eq(200)
211
+ end
212
+
213
+ context "with BarAbility registered" do
214
+ before { Spree::Ability.register_ability(::BarAbility) }
215
+ after { Spree::Ability.remove_ability(::BarAbility) }
216
+
217
+ it "can view an order" do
218
+ user = mock_model(Spree::LegacyUser)
219
+ allow(user).to receive_message_chain(:spree_roles, :pluck).and_return(["bar"])
220
+ allow(user).to receive(:has_spree_role?).with('bar').and_return(true)
221
+ allow(user).to receive(:has_spree_role?).with('admin').and_return(false)
222
+ allow(Spree.user_class).to receive_messages find_by: user
223
+ api_get :show, id: order.to_param
224
+ expect(response.status).to eq(200)
225
+ end
226
+ end
227
+
228
+ it "cannot cancel an order that doesn't belong to them" do
229
+ order.update_attribute(:completed_at, Time.current)
230
+ order.update_attribute(:shipment_state, "ready")
231
+ api_put :cancel, id: order.to_param
232
+ assert_unauthorized!
233
+ end
234
+
235
+ it "can create an order" do
236
+ api_post :create, order: { line_items: [{ variant_id: variant.to_param, quantity: 5 }] }
237
+ expect(response.status).to eq(201)
238
+
239
+ order = Order.last
240
+ expect(order.line_items.count).to eq(1)
241
+ expect(order.line_items.first.variant).to eq(variant)
242
+ expect(order.line_items.first.quantity).to eq(5)
243
+
244
+ expect(json_response['number']).to be_present
245
+ expect(json_response["token"]).not_to be_blank
246
+ expect(json_response["state"]).to eq("cart")
247
+ expect(order.user).to eq(current_api_user)
248
+ expect(order.email).to eq(current_api_user.email)
249
+ expect(json_response["user_id"]).to eq(current_api_user.id)
250
+ end
251
+
252
+ it "assigns email when creating a new order" do
253
+ api_post :create, order: { email: "guest@spreecommerce.org" }
254
+ expect(json_response['email']).not_to eq controller.current_api_user
255
+ expect(json_response['email']).to eq "guest@spreecommerce.org"
256
+ end
257
+
258
+ # Regression test for #3404
259
+ it "can specify additional parameters for a line item" do
260
+ expect(Order).to receive(:create!).and_return(order = Spree::Order.new)
261
+ allow(order).to receive(:associate_user!)
262
+ allow(order).to receive_message_chain(:contents, :add).and_return(line_item = double('LineItem'))
263
+ expect(line_item).to receive(:update_attributes!).with(hash_including("special" => "foo"))
264
+
265
+ allow(controller).to receive_messages(permitted_line_item_attributes: [:id, :variant_id, :quantity, :special])
266
+ api_post :create, order: {
267
+ line_items: [{ variant_id: variant.to_param, quantity: 5, special: "foo" }]
268
+ }
269
+ expect(response.status).to eq(201)
270
+ end
271
+
272
+ it "cannot arbitrarily set the line items price" do
273
+ api_post :create, order: {
274
+ line_items: [{ price: 33.0, variant_id: variant.to_param, quantity: 5 }]
275
+ }
276
+
277
+ expect(response.status).to eq 201
278
+ expect(Order.last.line_items.first.price.to_f).to eq(variant.price)
279
+ end
280
+
281
+ context "admin user imports order" do
282
+ before do
283
+ allow(current_api_user).to receive_messages has_spree_role?: true
284
+ allow(current_api_user).to receive_message_chain :spree_roles, pluck: ["admin"]
285
+ end
286
+
287
+ it "is able to set any default unpermitted attribute" do
288
+ api_post :create, order: { number: "WOW" }
289
+ expect(response.status).to eq 201
290
+ expect(json_response['number']).to eq "WOW"
291
+ end
292
+ end
293
+
294
+ # Regression test for #3404
295
+ it "does not update line item needlessly" do
296
+ expect(Order).to receive(:create!).and_return(order = Spree::Order.new)
297
+ allow(order).to receive(:associate_user!)
298
+ line_item = double('LineItem')
299
+ allow(line_item).to receive_messages(save!: line_item)
300
+ allow(order).to receive_message_chain(:contents, :add).and_return(line_item)
301
+ expect(line_item).not_to receive(:update_attributes)
302
+ api_post :create, order: { line_items: [{ variant_id: variant.to_param, quantity: 5 }] }
303
+ end
304
+
305
+ it "can create an order without any parameters" do
306
+ expect { api_post :create }.not_to raise_error
307
+ expect(response.status).to eq(201)
308
+ order = Order.last
309
+ expect(json_response["state"]).to eq("cart")
310
+ end
311
+
312
+ context "working with an order" do
313
+
314
+ let(:variant) { create(:variant) }
315
+ let!(:line_item) { order.contents.add(variant, 1) }
316
+ let!(:payment_method) { create(:check_payment_method) }
317
+
318
+ let(:address_params) { { country_id: country.id } }
319
+ let(:billing_address) { { firstname: "Tiago", lastname: "Motta", address1: "Av Paulista",
320
+ city: "Sao Paulo", zipcode: "01310-300", phone: "12345678",
321
+ country_id: country.id} }
322
+ let(:shipping_address) { { firstname: "Tiago", lastname: "Motta", address1: "Av Paulista",
323
+ city: "Sao Paulo", zipcode: "01310-300", phone: "12345678",
324
+ country_id: country.id} }
325
+ let(:country) { create(:country, {name: "Brazil", iso_name: "BRAZIL", iso: "BR", iso3: "BRA", numcode: 76 })}
326
+
327
+ before do
328
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
329
+ order.next # Switch from cart to address
330
+ order.bill_address = nil
331
+ order.ship_address = nil
332
+ order.save
333
+ expect(order.state).to eq("address")
334
+ end
335
+
336
+ def clean_address(address)
337
+ address.delete(:state)
338
+ address.delete(:country)
339
+ address
340
+ end
341
+
342
+ context "line_items hash not present in request" do
343
+ it "responds successfully" do
344
+ api_put :update, id: order.to_param, order: {
345
+ email: "hublock@spreecommerce.com"
346
+ }
347
+
348
+ expect(response).to be_success
349
+ end
350
+ end
351
+
352
+ it "updates quantities of existing line items" do
353
+ api_put :update, id: order.to_param, order: {
354
+ line_items: {
355
+ "0" => { id: line_item.id, quantity: 10 }
356
+ }
357
+ }
358
+
359
+ expect(response.status).to eq(200)
360
+ expect(json_response['line_items'].count).to eq(1)
361
+ expect(json_response['line_items'].first['quantity']).to eq(10)
362
+ end
363
+
364
+ it "adds an extra line item" do
365
+ variant2 = create(:variant)
366
+ api_put :update, id: order.to_param, order: {
367
+ line_items: {
368
+ "0" => { id: line_item.id, quantity: 10 },
369
+ "1" => { variant_id: variant2.id, quantity: 1}
370
+ }
371
+ }
372
+
373
+ expect(response.status).to eq(200)
374
+ expect(json_response['line_items'].count).to eq(2)
375
+ expect(json_response['line_items'][0]['quantity']).to eq(10)
376
+ expect(json_response['line_items'][1]['variant_id']).to eq(variant2.id)
377
+ expect(json_response['line_items'][1]['quantity']).to eq(1)
378
+ end
379
+
380
+ it "cannot change the price of an existing line item" do
381
+ api_put :update, id: order.to_param, order: {
382
+ line_items: {
383
+ 0 => { id: line_item.id, price: 0 }
384
+ }
385
+ }
386
+
387
+ expect(response.status).to eq(200)
388
+ expect(json_response['line_items'].count).to eq(1)
389
+ expect(json_response['line_items'].first['price'].to_f).to_not eq(0)
390
+ expect(json_response['line_items'].first['price'].to_f).to eq(line_item.variant.price)
391
+ end
392
+
393
+ it "can add billing address" do
394
+ api_put :update, id: order.to_param, order: { bill_address_attributes: billing_address }
395
+
396
+ expect(order.reload.bill_address).to_not be_nil
397
+ end
398
+
399
+ it "receives error message if trying to add billing address with errors" do
400
+ billing_address[:firstname] = ""
401
+
402
+ api_put :update, id: order.to_param, order: { bill_address_attributes: billing_address }
403
+
404
+ expect(json_response['error']).not_to be_nil
405
+ expect(json_response['errors']).not_to be_nil
406
+ expect(json_response['errors']['bill_address.firstname'].first).to eq "can't be blank"
407
+ end
408
+
409
+ it "can add shipping address" do
410
+ expect(order.ship_address).to be_nil
411
+
412
+ api_put :update, id: order.to_param, order: { ship_address_attributes: shipping_address }
413
+
414
+ expect(order.reload.ship_address).not_to be_nil
415
+ end
416
+
417
+ it "receives error message if trying to add shipping address with errors" do
418
+ expect(order.ship_address).to be_nil
419
+ shipping_address[:firstname] = ""
420
+
421
+ api_put :update, id: order.to_param, order: { ship_address_attributes: shipping_address }
422
+
423
+ expect(json_response['error']).not_to be_nil
424
+ expect(json_response['errors']).not_to be_nil
425
+ expect(json_response['errors']['ship_address.firstname'].first).to eq "can't be blank"
426
+ end
427
+
428
+ it "cannot set the user_id for the order" do
429
+ user = Spree.user_class.create
430
+ original_id = order.user_id
431
+ api_post :update, id: order.to_param, order: { user_id: user.id }
432
+ expect(response.status).to eq 200
433
+ expect(json_response["user_id"]).to eq(original_id)
434
+ end
435
+
436
+ context "order has shipments" do
437
+ before { order.create_proposed_shipments }
438
+
439
+ it "clears out all existing shipments on line item udpate" do
440
+ previous_shipments = order.shipments
441
+ api_put :update, id: order.to_param, order: {
442
+ line_items: {
443
+ 0 => { id: line_item.id, quantity: 10 }
444
+ }
445
+ }
446
+ expect(order.reload.shipments).to be_empty
447
+ end
448
+ end
449
+
450
+ context "with a line item" do
451
+ let(:order_with_line_items) do
452
+ order = create(:order_with_line_items)
453
+ create(:adjustment, order: order, adjustable: order)
454
+ order
455
+ end
456
+
457
+ it "can empty an order" do
458
+ expect(order_with_line_items.adjustments.count).to eq(1)
459
+ api_put :empty, id: order_with_line_items.to_param
460
+ expect(response.status).to eq(204)
461
+ order_with_line_items.reload
462
+ expect(order_with_line_items.line_items).to be_empty
463
+ expect(order_with_line_items.adjustments).to be_empty
464
+ end
465
+
466
+ it "can list its line items with images" do
467
+ order.line_items.first.variant.images.create!(attachment: image("thinking-cat.jpg"))
468
+
469
+ api_get :show, id: order.to_param
470
+
471
+ expect(json_response['line_items'].first['variant']).to have_attributes([:images])
472
+ end
473
+
474
+ it "lists variants product id" do
475
+ api_get :show, id: order.to_param
476
+
477
+ expect(json_response['line_items'].first['variant']).to have_attributes([:product_id])
478
+ end
479
+
480
+ it "includes the tax_total in the response" do
481
+ api_get :show, id: order.to_param
482
+
483
+ expect(json_response['included_tax_total']).to eq('0.0')
484
+ expect(json_response['additional_tax_total']).to eq('0.0')
485
+ expect(json_response['display_included_tax_total']).to eq('$0.00')
486
+ expect(json_response['display_additional_tax_total']).to eq('$0.00')
487
+ end
488
+
489
+ it "lists line item adjustments" do
490
+ adjustment = create(:adjustment,
491
+ label: "10% off!",
492
+ order: order,
493
+ adjustable: order.line_items.first)
494
+ adjustment.update_column(:amount, 5)
495
+ api_get :show, id: order.to_param
496
+
497
+ adjustment = json_response['line_items'].first['adjustments'].first
498
+ expect(adjustment['label']).to eq("10% off!")
499
+ expect(adjustment['amount']).to eq("5.0")
500
+ end
501
+
502
+ it "lists payments source without gateway info" do
503
+ order.payments.push payment = create(:payment)
504
+ api_get :show, id: order.to_param
505
+
506
+ source = json_response[:payments].first[:source]
507
+ expect(source[:name]).to eq payment.source.name
508
+ expect(source[:cc_type]).to eq payment.source.cc_type
509
+ expect(source[:last_digits]).to eq payment.source.last_digits
510
+ expect(source[:month].to_i).to eq payment.source.month
511
+ expect(source[:year].to_i).to eq payment.source.year
512
+ expect(source.has_key?(:gateway_customer_profile_id)).to be false
513
+ expect(source.has_key?(:gateway_payment_profile_id)).to be false
514
+ end
515
+
516
+ context "when in delivery" do
517
+ let!(:shipping_method) do
518
+ FactoryGirl.create(:shipping_method).tap do |shipping_method|
519
+ shipping_method.calculator.preferred_amount = 10
520
+ shipping_method.calculator.save
521
+ end
522
+ end
523
+
524
+ before do
525
+ order.bill_address = FactoryGirl.create(:address)
526
+ order.ship_address = FactoryGirl.create(:address)
527
+ order.next!
528
+ order.save
529
+ end
530
+
531
+ it "includes the ship_total in the response" do
532
+ api_get :show, id: order.to_param
533
+
534
+ expect(json_response['ship_total']).to eq '10.0'
535
+ expect(json_response['display_ship_total']).to eq '$10.00'
536
+ end
537
+
538
+ it "returns available shipments for an order" do
539
+ api_get :show, id: order.to_param
540
+ expect(response.status).to eq(200)
541
+ expect(json_response["shipments"]).not_to be_empty
542
+ shipment = json_response["shipments"][0]
543
+ # Test for correct shipping method attributes
544
+ # Regression test for #3206
545
+ expect(shipment["shipping_methods"]).not_to be_nil
546
+ json_shipping_method = shipment["shipping_methods"][0]
547
+ expect(json_shipping_method["id"]).to eq(shipping_method.id)
548
+ expect(json_shipping_method["name"]).to eq(shipping_method.name)
549
+ expect(json_shipping_method["code"]).to eq(shipping_method.code)
550
+ expect(json_shipping_method["zones"]).not_to be_empty
551
+ expect(json_shipping_method["shipping_categories"]).not_to be_empty
552
+
553
+ # Test for correct shipping rates attributes
554
+ # Regression test for #3206
555
+ expect(shipment["shipping_rates"]).not_to be_nil
556
+ shipping_rate = shipment["shipping_rates"][0]
557
+ expect(shipping_rate["name"]).to eq(json_shipping_method["name"])
558
+ expect(shipping_rate["cost"]).to eq("10.0")
559
+ expect(shipping_rate["selected"]).to be true
560
+ expect(shipping_rate["display_cost"]).to eq("$10.00")
561
+ expect(shipping_rate["shipping_method_code"]).to eq(json_shipping_method["code"])
562
+
563
+ expect(shipment["stock_location_name"]).not_to be_blank
564
+ manifest_item = shipment["manifest"][0]
565
+ expect(manifest_item["quantity"]).to eq(1)
566
+ expect(manifest_item["variant_id"]).to eq(order.line_items.first.variant_id)
567
+ end
568
+ end
569
+ end
570
+ end
571
+
572
+ context "as an admin" do
573
+ sign_in_as_admin!
574
+
575
+ context "with no orders" do
576
+ before { Spree::Order.delete_all }
577
+ it "still returns a root :orders key" do
578
+ api_get :index
579
+ expect(json_response["orders"]).to eq([])
580
+ end
581
+ end
582
+
583
+ it "responds with orders updated_at with miliseconds precision" do
584
+ if ApplicationRecord.connection.adapter_name == "Mysql2"
585
+ skip "MySQL does not support millisecond timestamps."
586
+ else
587
+ skip "Probable need to make it call as_json. See https://github.com/rails/rails/commit/0f33d70e89991711ff8b3dde134a61f4a5a0ec06"
588
+ end
589
+
590
+ api_get :index
591
+ milisecond = order.updated_at.strftime("%L")
592
+ updated_at = json_response["orders"].first["updated_at"]
593
+ expect(updated_at.split("T").last).to have_content(milisecond)
594
+ end
595
+
596
+ context "caching enabled" do
597
+ before do
598
+ ActionController::Base.perform_caching = true
599
+ 3.times { Order.create }
600
+ end
601
+
602
+ it "returns unique orders" do
603
+ api_get :index
604
+
605
+ orders = json_response[:orders]
606
+ expect(orders.count).to be >= 3
607
+ expect(orders.map { |o| o[:id] }).to match_array Order.pluck(:id)
608
+ end
609
+
610
+ after { ActionController::Base.perform_caching = false }
611
+ end
612
+
613
+ it "lists payments source with gateway info" do
614
+ order.payments.push payment = create(:payment)
615
+ api_get :show, id: order.to_param
616
+
617
+ source = json_response[:payments].first[:source]
618
+ expect(source[:name]).to eq payment.source.name
619
+ expect(source[:cc_type]).to eq payment.source.cc_type
620
+ expect(source[:last_digits]).to eq payment.source.last_digits
621
+ expect(source[:month].to_i).to eq payment.source.month
622
+ expect(source[:year].to_i).to eq payment.source.year
623
+ expect(source[:gateway_customer_profile_id]).to eq payment.source.gateway_customer_profile_id
624
+ expect(source[:gateway_payment_profile_id]).to eq payment.source.gateway_payment_profile_id
625
+ end
626
+
627
+ context "with two orders" do
628
+ before { create(:order) }
629
+
630
+ it "can view all orders" do
631
+ api_get :index
632
+ expect(json_response["orders"].first).to have_attributes(attributes)
633
+ expect(json_response["count"]).to eq(2)
634
+ expect(json_response["current_page"]).to eq(1)
635
+ expect(json_response["pages"]).to eq(1)
636
+ end
637
+
638
+ # Test for #1763
639
+ it "can control the page size through a parameter" do
640
+ api_get :index, per_page: 1
641
+ expect(json_response["orders"].count).to eq(1)
642
+ expect(json_response["orders"].first).to have_attributes(attributes)
643
+ expect(json_response["count"]).to eq(1)
644
+ expect(json_response["current_page"]).to eq(1)
645
+ expect(json_response["pages"]).to eq(2)
646
+ end
647
+ end
648
+
649
+ context "search" do
650
+ before do
651
+ create(:order)
652
+ Spree::Order.last.update_attribute(:email, 'spree@spreecommerce.com')
653
+ end
654
+
655
+ let(:expected_result) { Spree::Order.last }
656
+
657
+ it "can query the results through a parameter" do
658
+ api_get :index, q: { email_cont: 'spree' }
659
+ expect(json_response["orders"].count).to eq(1)
660
+ expect(json_response["orders"].first).to have_attributes(attributes)
661
+ expect(json_response["orders"].first["email"]).to eq(expected_result.email)
662
+ expect(json_response["count"]).to eq(1)
663
+ expect(json_response["current_page"]).to eq(1)
664
+ expect(json_response["pages"]).to eq(1)
665
+ end
666
+ end
667
+
668
+ context "creation" do
669
+ it "can create an order without any parameters" do
670
+ expect { api_post :create }.not_to raise_error
671
+ expect(response.status).to eq(201)
672
+ order = Order.last
673
+ expect(json_response["state"]).to eq("cart")
674
+ end
675
+
676
+ it "can arbitrarily set the line items price" do
677
+ api_post :create, order: {
678
+ line_items: [{ price: 33.0, variant_id: variant.to_param, quantity: 5 }]
679
+ }
680
+ expect(response.status).to eq 201
681
+ expect(Order.last.line_items.first.price.to_f).to eq(33.0)
682
+ end
683
+
684
+ it "can set the user_id for the order" do
685
+ user = Spree.user_class.create
686
+ api_post :create, order: { user_id: user.id }
687
+ expect(response.status).to eq 201
688
+ expect(json_response["user_id"]).to eq(user.id)
689
+ end
690
+ end
691
+
692
+ context "updating" do
693
+ it "can set the user_id for the order" do
694
+ user = Spree.user_class.create
695
+ api_post :update, id: order.number, order: { user_id: user.id }
696
+ expect(response.status).to eq 200
697
+ expect(json_response["user_id"]).to eq(user.id)
698
+ end
699
+ end
700
+
701
+ context "can cancel an order" do
702
+ before do
703
+ order.completed_at = Time.current
704
+ order.state = 'complete'
705
+ order.shipment_state = 'ready'
706
+ order.save!
707
+ end
708
+
709
+ specify do
710
+ api_put :cancel, id: order.to_param
711
+ expect(json_response["state"]).to eq("canceled")
712
+ expect(json_response["canceler_id"]).to eq(current_api_user.id)
713
+ end
714
+ end
715
+
716
+ context "can approve an order" do
717
+ before do
718
+ order.completed_at = Time.current
719
+ order.state = 'complete'
720
+ order.shipment_state = 'ready'
721
+ order.considered_risky = true
722
+ order.save!
723
+ end
724
+
725
+ specify do
726
+ api_put :approve, id: order.to_param
727
+ order.reload
728
+ expect(order.approver_id).to eq(current_api_user.id)
729
+ expect(order.considered_risky).to eq(false)
730
+ end
731
+ end
732
+
733
+ end
734
+ end
735
+ end