spree_api 1.3.4 → 1.3.5

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.
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