spree_api 1.3.4 → 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/spree/api/orders_controller.rb +2 -0
- data/app/controllers/spree/api/products_controller.rb +18 -0
- data/app/helpers/spree/api/api_helpers.rb +1 -1
- data/app/models/spree/api_configuration.rb +1 -0
- data/app/models/spree/line_item_decorator.rb +1 -1
- data/app/models/spree/order_decorator.rb +23 -10
- data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +7 -0
- data/spec/controllers/spree/api/orders_controller_spec.rb +54 -3
- data/spec/controllers/spree/api/products_controller_spec.rb +73 -2
- data/spec/models/spree/order_spec.rb +40 -13
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f36fa5b9ac229e7e973c1c724fda3cf3e9cd50ad
|
4
|
+
data.tar.gz: 78a1596cc6c1ed5014fc22c65319c431cb6a08de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab336cf7a3b2b2c56070dd047fd1844c3abf8051431c8171d078534289f8274e323a9c6f85eae06132bf6427effc5fa67762b4c071660da4e7d02b552a2fc916
|
7
|
+
data.tar.gz: ec3c418cb4b1b6351d8cc879d27acab755e8c45f62900150203c8a6d7d8854507cc3199c63c210c47ee400553354556050c4aca371db63b3087f9f52a3d4aca7
|
@@ -56,6 +56,8 @@ module Spree
|
|
56
56
|
def sanitize_line_items(line_item_attributes)
|
57
57
|
return {} if line_item_attributes.blank?
|
58
58
|
line_item_attributes = line_item_attributes.map do |id, attributes|
|
59
|
+
attributes ||= id
|
60
|
+
|
59
61
|
# Faux Strong-Parameters code to strip price if user isn't an admin
|
60
62
|
if current_api_user.has_spree_role?("admin")
|
61
63
|
[id, attributes.slice(*Spree::LineItem.attr_accessible[:api])]
|
@@ -19,9 +19,27 @@ module Spree
|
|
19
19
|
def create
|
20
20
|
authorize! :create, Product
|
21
21
|
params[:product][:available_on] ||= Time.now
|
22
|
+
|
23
|
+
variants_attributes = params[:product].delete(:variants_attributes) || []
|
24
|
+
option_type_attributes = params[:product].delete(:option_types) || []
|
25
|
+
|
22
26
|
@product = Product.new(params[:product])
|
23
27
|
begin
|
24
28
|
if @product.save
|
29
|
+
variants_attributes.each do |variant_attribute|
|
30
|
+
variant = @product.variants.new
|
31
|
+
variant.update_attributes(variant_attribute)
|
32
|
+
end
|
33
|
+
|
34
|
+
option_type_attributes.each do |name|
|
35
|
+
option_type = OptionType.where(name: name).first_or_initialize do |option_type|
|
36
|
+
option_type.presentation = name
|
37
|
+
option_type.save!
|
38
|
+
end
|
39
|
+
|
40
|
+
@product.option_types << option_type unless @product.option_types.include?(option_type)
|
41
|
+
end
|
42
|
+
|
25
43
|
respond_with(@product, :status => 201, :default_template => :show)
|
26
44
|
else
|
27
45
|
invalid_resource!(@product)
|
@@ -33,7 +33,7 @@ module Spree
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def order_attributes
|
36
|
-
[:id, :number, :item_total, :total, :state, :adjustment_total, :user_id, :created_at, :updated_at, :completed_at, :payment_total, :shipment_state, :payment_state, :email, :special_instructions]
|
36
|
+
[:id, :number, :item_total, :total, :state, :adjustment_total, :user_id, :created_at, :updated_at, :completed_at, :payment_total, :shipment_state, :payment_state, :email, :special_instructions, :channel]
|
37
37
|
end
|
38
38
|
|
39
39
|
def line_item_attributes
|
@@ -1,4 +1,6 @@
|
|
1
1
|
Spree::Order.class_eval do
|
2
|
+
attr_accessible :channel, :as => :api_admin
|
3
|
+
|
2
4
|
def self.build_from_api(user, params)
|
3
5
|
begin
|
4
6
|
ensure_country_id_from_api params[:ship_address_attributes]
|
@@ -15,7 +17,12 @@ Spree::Order.class_eval do
|
|
15
17
|
order.complete_from_api params.delete(:completed_at)
|
16
18
|
|
17
19
|
destroy_automatic_taxes_on_import(order, params)
|
18
|
-
|
20
|
+
|
21
|
+
if user.has_spree_role? "admin"
|
22
|
+
order.update_attributes!(params, without_protection: true)
|
23
|
+
else
|
24
|
+
order.update_attributes!(params)
|
25
|
+
end
|
19
26
|
|
20
27
|
order.reload
|
21
28
|
rescue Exception => e
|
@@ -59,7 +66,7 @@ Spree::Order.class_eval do
|
|
59
66
|
shipment.adjustment.amount = s[:cost].to_f
|
60
67
|
shipment.adjustment.save
|
61
68
|
rescue Exception => e
|
62
|
-
raise "#{e.message} #{s}"
|
69
|
+
raise "Order import shipments: #{e.message} #{s}"
|
63
70
|
end
|
64
71
|
end
|
65
72
|
end
|
@@ -73,7 +80,7 @@ Spree::Order.class_eval do
|
|
73
80
|
payment.payment_method = Spree::PaymentMethod.find_by_name!(p[:payment_method])
|
74
81
|
payment.save!
|
75
82
|
rescue Exception => e
|
76
|
-
raise "#{e.message} #{p}"
|
83
|
+
raise "Order import payments: #{e.message} #{p}"
|
77
84
|
end
|
78
85
|
end
|
79
86
|
end
|
@@ -84,14 +91,14 @@ Spree::Order.class_eval do
|
|
84
91
|
line_item = line_items_hash[k]
|
85
92
|
self.class.ensure_variant_id_from_api(line_item)
|
86
93
|
|
87
|
-
item
|
94
|
+
item = self.add_variant(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity].to_i)
|
88
95
|
|
89
96
|
if line_item.key? :price
|
90
97
|
item.price = line_item[:price]
|
91
98
|
item.save!
|
92
99
|
end
|
93
100
|
rescue Exception => e
|
94
|
-
raise "#{e.message} #{line_item}"
|
101
|
+
raise "Order import line items: #{e.message} #{line_item}"
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|
@@ -104,7 +111,7 @@ Spree::Order.class_eval do
|
|
104
111
|
adjustment.locked = true
|
105
112
|
adjustment.save!
|
106
113
|
rescue Exception => e
|
107
|
-
raise "#{e.message} #{a}"
|
114
|
+
raise "Order import adjustments: #{e.message} #{a}"
|
108
115
|
end
|
109
116
|
end
|
110
117
|
end
|
@@ -116,7 +123,7 @@ Spree::Order.class_eval do
|
|
116
123
|
hash.delete(:sku)
|
117
124
|
end
|
118
125
|
rescue Exception => e
|
119
|
-
raise "#{e.message} #{hash}"
|
126
|
+
raise "Ensure order import variant: #{e.message} #{hash}"
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
@@ -139,7 +146,7 @@ Spree::Order.class_eval do
|
|
139
146
|
address[:country_id] = Spree::Country.where(search).first!.id
|
140
147
|
|
141
148
|
rescue Exception => e
|
142
|
-
raise "#{e.message} #{search}"
|
149
|
+
raise "Ensure order import address country: #{e.message} #{search}"
|
143
150
|
end
|
144
151
|
end
|
145
152
|
|
@@ -155,9 +162,15 @@ Spree::Order.class_eval do
|
|
155
162
|
end
|
156
163
|
|
157
164
|
address.delete(:state)
|
158
|
-
|
165
|
+
search[:country_id] = address[:country_id]
|
166
|
+
|
167
|
+
if state = Spree::State.where(search).first
|
168
|
+
address[:state_id] = state.id
|
169
|
+
else
|
170
|
+
address[:state_name] = search[:name] || search[:abbr]
|
171
|
+
end
|
159
172
|
rescue Exception => e
|
160
|
-
raise "#{e.message} #{search}"
|
173
|
+
raise "Ensure order import address state: #{e.message} #{search}"
|
161
174
|
end
|
162
175
|
end
|
163
176
|
end
|
@@ -11,10 +11,9 @@ module Spree
|
|
11
11
|
:completed_at, :payment_total, :shipment_state,
|
12
12
|
:payment_state, :email, :special_instructions] }
|
13
13
|
|
14
|
+
let(:variant) { create(:variant) }
|
14
15
|
|
15
|
-
before
|
16
|
-
stub_authentication!
|
17
|
-
end
|
16
|
+
before { stub_authentication! }
|
18
17
|
|
19
18
|
it "cannot view all orders" do
|
20
19
|
api_get :index
|
@@ -64,6 +63,50 @@ module Spree
|
|
64
63
|
json_response["state"].should == "cart"
|
65
64
|
end
|
66
65
|
|
66
|
+
context "import" do
|
67
|
+
let(:tax_rate) { create(:tax_rate, amount: 0.05, calculator: Calculator::DefaultTax.create) }
|
68
|
+
let(:other_variant) { create(:variant) }
|
69
|
+
|
70
|
+
# line items come in as an array when importing orders or when
|
71
|
+
# creating both an order an a line item at once
|
72
|
+
let(:order_params) do
|
73
|
+
{
|
74
|
+
:line_items => [
|
75
|
+
{ :variant_id => variant.to_param, :quantity => 5 },
|
76
|
+
{ :variant_id => other_variant.to_param, :quantity => 5 }
|
77
|
+
]
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
before do
|
82
|
+
Zone.stub default_tax: tax_rate.zone
|
83
|
+
current_api_user.stub has_spree_role?: true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "sets channel" do
|
87
|
+
api_post :create, :order => { channel: "amazon" }
|
88
|
+
expect(json_response['channel']).to eq "amazon"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "doesnt persist any automatic tax adjustment" do
|
92
|
+
expect {
|
93
|
+
api_post :create, :order => order_params.merge(:import => true)
|
94
|
+
}.not_to change { Adjustment.count }
|
95
|
+
expect(response.status).to eq 201
|
96
|
+
end
|
97
|
+
|
98
|
+
context "provides sku rather than variant id" do
|
99
|
+
let(:order_params) do
|
100
|
+
{ :line_items => [{ :sku => variant.sku, :quantity => 1 }] }
|
101
|
+
end
|
102
|
+
|
103
|
+
it "still finds the variant by sku and persist order" do
|
104
|
+
api_post :create, :order => order_params
|
105
|
+
expect(json_response['line_items'].count).to eq 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
67
110
|
it "can create an order without any parameters" do
|
68
111
|
lambda { api_post :create }.should_not raise_error(NoMethodError)
|
69
112
|
response.status.should == 201
|
@@ -210,6 +253,14 @@ module Spree
|
|
210
253
|
end
|
211
254
|
end
|
212
255
|
|
256
|
+
it "responds with orders updated_at with miliseconds precision" do
|
257
|
+
api_get :index
|
258
|
+
milisecond = order.updated_at.strftime("%L")
|
259
|
+
updated_at = json_response["orders"].first["updated_at"]
|
260
|
+
|
261
|
+
expect(updated_at.split("T").last).to have_content(milisecond)
|
262
|
+
end
|
263
|
+
|
213
264
|
context "with two orders" do
|
214
265
|
before { create(:order) }
|
215
266
|
|
@@ -8,6 +8,10 @@ module Spree
|
|
8
8
|
let!(:product) { create(:product) }
|
9
9
|
let!(:inactive_product) { create(:product, :available_on => Time.now.tomorrow, :name => "inactive") }
|
10
10
|
let(:attributes) { [:id, :name, :description, :price, :available_on, :permalink, :count_on_hand, :meta_description, :meta_keywords, :taxon_ids] }
|
11
|
+
let(:product_hash) do
|
12
|
+
{ :name => "The Other Product",
|
13
|
+
:price => 19.99 }
|
14
|
+
end
|
11
15
|
|
12
16
|
before do
|
13
17
|
stub_authentication!
|
@@ -157,12 +161,79 @@ module Spree
|
|
157
161
|
end
|
158
162
|
|
159
163
|
it "can create a new product" do
|
160
|
-
api_post :create, :product =>
|
161
|
-
:price => 19.99 }
|
164
|
+
api_post :create, :product => product_hash
|
162
165
|
json_response.should have_attributes(attributes)
|
163
166
|
response.status.should == 201
|
164
167
|
end
|
165
168
|
|
169
|
+
describe "creating products with" do
|
170
|
+
it "embedded variants" do
|
171
|
+
def attributes_for_variant
|
172
|
+
h = attributes_for(:variant).except(:is_master, :product)
|
173
|
+
h.delete(:option_values)
|
174
|
+
h.merge({
|
175
|
+
options: [
|
176
|
+
{ name: "size", value: "small" },
|
177
|
+
{ name: "color", value: "black" }
|
178
|
+
]
|
179
|
+
})
|
180
|
+
end
|
181
|
+
|
182
|
+
attributes = product_hash
|
183
|
+
|
184
|
+
attributes.merge!({
|
185
|
+
shipping_category_id: 1,
|
186
|
+
|
187
|
+
option_types: ['size', 'color'],
|
188
|
+
|
189
|
+
variants_attributes: [
|
190
|
+
attributes_for_variant,
|
191
|
+
attributes_for_variant
|
192
|
+
]
|
193
|
+
})
|
194
|
+
|
195
|
+
api_post :create, :product => attributes
|
196
|
+
|
197
|
+
expect(json_response['variants'].count).to eq(3) # 1 master + 2 variants
|
198
|
+
expect(json_response['variants'][1]['option_values'][0]['name']).to eq('small')
|
199
|
+
expect(json_response['variants'][1]['option_values'][0]['option_type_name']).to eq('size')
|
200
|
+
|
201
|
+
expect(json_response['option_types'].count).to eq(2) # size, color
|
202
|
+
end
|
203
|
+
|
204
|
+
it "embedded product_properties" do
|
205
|
+
attributes = product_hash
|
206
|
+
|
207
|
+
attributes.merge!({
|
208
|
+
shipping_category_id: 1,
|
209
|
+
|
210
|
+
product_properties_attributes: [{
|
211
|
+
property_name: "fabric",
|
212
|
+
value: "cotton"
|
213
|
+
}]
|
214
|
+
})
|
215
|
+
|
216
|
+
api_post :create, :product => attributes
|
217
|
+
|
218
|
+
expect(json_response['product_properties'][0]['property_name']).to eq('fabric')
|
219
|
+
expect(json_response['product_properties'][0]['value']).to eq('cotton')
|
220
|
+
end
|
221
|
+
|
222
|
+
it "option_types even if without variants" do
|
223
|
+
attributes = product_hash
|
224
|
+
|
225
|
+
attributes.merge!({
|
226
|
+
shipping_category_id: 1,
|
227
|
+
|
228
|
+
option_types: ['size', 'color']
|
229
|
+
})
|
230
|
+
|
231
|
+
api_post :create, :product => attributes
|
232
|
+
|
233
|
+
expect(json_response['option_types'].count).to eq(2)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
166
237
|
# Regression test for #2140
|
167
238
|
context "with authentication_required set to false" do
|
168
239
|
before do
|
@@ -62,6 +62,18 @@ module Spree
|
|
62
62
|
expect(line_item.variant_id).to eq attributes[:variant_id]
|
63
63
|
expect(line_item.price).to eq attributes[:price]
|
64
64
|
end
|
65
|
+
|
66
|
+
it "ensures quantity values are converted to integer" do
|
67
|
+
params = {
|
68
|
+
:line_items_attributes => {
|
69
|
+
"0" => { :variant_id => variant.id, :quantity => "5" },
|
70
|
+
"1" => { :variant_id => variant.id, :quantity => "5" }
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
order = Order.build_from_api(user, params)
|
75
|
+
expect(order.line_items.first.quantity).to eq 10
|
76
|
+
end
|
65
77
|
end
|
66
78
|
|
67
79
|
it 'uses line item price if present' do
|
@@ -133,7 +145,7 @@ module Spree
|
|
133
145
|
|
134
146
|
it 'can build an order from API with state attributes' do
|
135
147
|
ship_address.delete(:state_id)
|
136
|
-
ship_address[:state] = { 'name' =>
|
148
|
+
ship_address[:state] = { 'name' => state.name }
|
137
149
|
params = { :ship_address_attributes => ship_address,
|
138
150
|
:line_items_attributes => line_items }
|
139
151
|
|
@@ -141,15 +153,37 @@ module Spree
|
|
141
153
|
order.ship_address.state.name.should eq 'Alabama'
|
142
154
|
end
|
143
155
|
|
144
|
-
|
156
|
+
context "state passed is not associated with country" do
|
157
|
+
let(:params) do
|
158
|
+
params = { :ship_address_attributes => ship_address,
|
159
|
+
:line_items_attributes => line_items }
|
160
|
+
end
|
161
|
+
|
162
|
+
let(:other_state) { create(:state, name: "Uhuhuh", country: create(:country)) }
|
163
|
+
|
164
|
+
before do
|
165
|
+
country.states.destroy_all
|
166
|
+
|
167
|
+
ship_address.delete(:state_id)
|
168
|
+
ship_address[:state] = { 'name' => other_state.name }
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'sets states name instead of state id' do
|
172
|
+
order = Order.build_from_api(user, params)
|
173
|
+
expect(order.ship_address.state_name).to eq other_state.name
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'sets state name if state record not found' do
|
178
|
+
country.states.destroy_all
|
179
|
+
|
145
180
|
ship_address.delete(:state_id)
|
146
181
|
ship_address[:state] = { 'name' => 'XXX' }
|
147
182
|
params = { :ship_address_attributes => ship_address,
|
148
183
|
:line_items_attributes => line_items }
|
149
184
|
|
150
|
-
|
151
|
-
|
152
|
-
}.to raise_error /XXX/
|
185
|
+
order = Order.build_from_api(user, params)
|
186
|
+
expect(order.ship_address.state_name).to eq 'XXX'
|
153
187
|
end
|
154
188
|
|
155
189
|
context 'variant not deleted' do
|
@@ -187,19 +221,12 @@ module Spree
|
|
187
221
|
|
188
222
|
it 'ensures_state_id for state fields' do
|
189
223
|
[:name, :abbr].each do |field|
|
190
|
-
address = { :state => { field => state.send(field) }}
|
224
|
+
address = { country_id: country.id, :state => { field => state.send(field) }}
|
191
225
|
Order.ensure_state_id_from_api(address)
|
192
226
|
address[:state_id].should eq state.id
|
193
227
|
end
|
194
228
|
end
|
195
229
|
|
196
|
-
it "raises with proper message when cant find state" do
|
197
|
-
address = { :state => { "name" => "NoNoState" } }
|
198
|
-
expect {
|
199
|
-
Order.ensure_state_id_from_api(address)
|
200
|
-
}.to raise_error /NoNoState/
|
201
|
-
end
|
202
|
-
|
203
230
|
context "shippments" do
|
204
231
|
let(:params) do
|
205
232
|
{ :shipments_attributes => [
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Bigg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: spree_core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.3.
|
19
|
+
version: 1.3.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.3.
|
26
|
+
version: 1.3.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: versioncake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,8 +45,8 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
-
- .gitignore
|
49
|
-
- .rspec
|
48
|
+
- ".gitignore"
|
49
|
+
- ".rspec"
|
50
50
|
- Gemfile
|
51
51
|
- LICENSE
|
52
52
|
- Rakefile
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- db/migrate/20100107141738_add_api_key_to_spree_users.rb
|
142
142
|
- db/migrate/20120411123334_resize_api_key_field.rb
|
143
143
|
- db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb
|
144
|
+
- db/migrate/20131017162334_add_index_to_user_spree_api_key.rb
|
144
145
|
- lib/spree/api.rb
|
145
146
|
- lib/spree/api/controller_setup.rb
|
146
147
|
- lib/spree/api/engine.rb
|
@@ -188,17 +189,17 @@ require_paths:
|
|
188
189
|
- lib
|
189
190
|
required_ruby_version: !ruby/object:Gem::Requirement
|
190
191
|
requirements:
|
191
|
-
- -
|
192
|
+
- - ">="
|
192
193
|
- !ruby/object:Gem::Version
|
193
194
|
version: '0'
|
194
195
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
196
|
requirements:
|
196
|
-
- -
|
197
|
+
- - ">="
|
197
198
|
- !ruby/object:Gem::Version
|
198
199
|
version: '0'
|
199
200
|
requirements: []
|
200
201
|
rubyforge_project:
|
201
|
-
rubygems_version: 2.
|
202
|
+
rubygems_version: 2.2.0
|
202
203
|
signing_key:
|
203
204
|
specification_version: 4
|
204
205
|
summary: Spree's API
|