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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 288706a5a4c81fc84a82d1f1aa91dcd8ce546fb6
4
- data.tar.gz: 75057c9776f7ecbe0374da3d4c155aa3bf61130d
3
+ metadata.gz: f36fa5b9ac229e7e973c1c724fda3cf3e9cd50ad
4
+ data.tar.gz: 78a1596cc6c1ed5014fc22c65319c431cb6a08de
5
5
  SHA512:
6
- metadata.gz: 83df37343d301ff95eb8f78144c36d6a0b88703f704400510dedf050b511482339e731b1396d3312012cbbcaeb843451bed73f3a8e257b6305d61859c9665c83
7
- data.tar.gz: e88252e0d65aeee9ffcefab0b9c18bc088068881f7f42787615e1094c26fa076c3377cf4bb4c4f591edaf987b325b5b1321d3993ce82d2a4e5d69593c01077df
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,5 +1,6 @@
1
1
  module Spree
2
2
  class ApiConfiguration < Preferences::Configuration
3
+ # Make sure the api requires authentication by default to prevent unwanted access
3
4
  preference :requires_authentication, :boolean, :default => true
4
5
  end
5
6
  end
@@ -1,3 +1,3 @@
1
1
  Spree::LineItem.class_eval do
2
- attr_accessible :quantity, :variant_id, :as => :api
2
+ attr_accessible :quantity, :variant_id, :sku, :as => :api
3
3
  end
@@ -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
- order.update_attributes!(params)
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 = self.add_variant(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
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
- address[:state_id] = Spree::State.where(search).first!.id
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
@@ -0,0 +1,7 @@
1
+ class AddIndexToUserSpreeApiKey < ActiveRecord::Migration
2
+ def change
3
+ unless defined?(User)
4
+ add_index :spree_users, :spree_api_key
5
+ end
6
+ end
7
+ 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 do
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 => { :name => "The Other 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' => 'Alabama' }
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
- it 'handles state lookup exceptions' do
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
- expect {
151
- order = Order.build_from_api(user, params)
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
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: 2013-10-15 00:00:00.000000000 Z
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.4
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.4
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.1.0
202
+ rubygems_version: 2.2.0
202
203
  signing_key:
203
204
  specification_version: 4
204
205
  summary: Spree's API