solidus_api 1.0.0.pre

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