spree_api 1.3.3 → 1.3.4

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: f397d8160397db229e68ecb1625d2a70c704abb6
4
- data.tar.gz: d21c61fe36137fccefe8d0a21d3904b658a82943
3
+ metadata.gz: 288706a5a4c81fc84a82d1f1aa91dcd8ce546fb6
4
+ data.tar.gz: 75057c9776f7ecbe0374da3d4c155aa3bf61130d
5
5
  SHA512:
6
- metadata.gz: fbc700d85f13b92900aedee047f0406ace478aa353fc3c283600bb40bd48e7fe121c555191d900df92fc55bdb0a01d3b9b11884603093f88fa7b56928c90898c
7
- data.tar.gz: 206781bde534695d6a1d56584560d3355b08d4582d36f0dede3b748b471ca951a4b7cb5ba950fc072290acb40f5ea69177313ae0e4f3b07d80ea0968cb1bd5d5
6
+ metadata.gz: 83df37343d301ff95eb8f78144c36d6a0b88703f704400510dedf050b511482339e731b1396d3312012cbbcaeb843451bed73f3a8e257b6305d61859c9665c83
7
+ data.tar.gz: e88252e0d65aeee9ffcefab0b9c18bc088068881f7f42787615e1094c26fa076c3377cf4bb4c4f591edaf987b325b5b1321d3993ce82d2a4e5d69593c01077df
@@ -4,8 +4,14 @@ module Spree
4
4
  before_filter :load_order, :only => :update
5
5
  before_filter :associate_user, :only => :update
6
6
 
7
+ # Spree::Core::ControllerHelpers::Auth overrides
8
+ # Spree::Api::BaseController's unauthorized method...
9
+ # Which is not a good thing.
10
+ # Here's a small hack to shuffle around the method.
11
+ alias_method :real_unauthorized, :unauthorized
7
12
  include Spree::Core::ControllerHelpers::Auth
8
13
  include Spree::Core::ControllerHelpers::Order
14
+ alias_method :unauthorized, :real_unauthorized
9
15
 
10
16
  respond_to :json
11
17
 
@@ -15,6 +21,7 @@ module Spree
15
21
  end
16
22
 
17
23
  def update
24
+ authorize! :update, @order, params[:order_token]
18
25
  respond_with(@order, :default_template => 'spree/api/orders/show') and return if @order.state == "complete"
19
26
 
20
27
  if object_params && object_params[:user_id].present?
@@ -17,12 +17,17 @@ module Spree
17
17
  end
18
18
 
19
19
  def create
20
+ nested_params[:line_items_attributes] = sanitize_line_items(nested_params[:line_items_attributes])
20
21
  @order = Order.build_from_api(current_api_user, nested_params)
21
22
  respond_with(order, :default_template => :show, :status => 201)
22
23
  end
23
24
 
24
25
  def update
25
26
  authorize! :update, Order
27
+ # Parsing line items through as an update_attributes call in the API will result in
28
+ # many line items for the same variant_id being created. We must be smarter about this,
29
+ # hence the use of the update_line_items method, defined within order_decorator.rb.
30
+ nested_params[:line_items_attributes] = sanitize_line_items(nested_params[:line_items_attributes])
26
31
  if order.update_attributes(nested_params)
27
32
  order.update!
28
33
  respond_with(order, :default_template => :show)
@@ -45,7 +50,20 @@ module Spree
45
50
  private
46
51
 
47
52
  def nested_params
48
- map_nested_attributes_keys Order, params[:order] || {}
53
+ @nested_params ||= map_nested_attributes_keys(Order, params[:order] || {})
54
+ end
55
+
56
+ def sanitize_line_items(line_item_attributes)
57
+ return {} if line_item_attributes.blank?
58
+ line_item_attributes = line_item_attributes.map do |id, attributes|
59
+ # Faux Strong-Parameters code to strip price if user isn't an admin
60
+ if current_api_user.has_spree_role?("admin")
61
+ [id, attributes.slice(*Spree::LineItem.attr_accessible[:api])]
62
+ else
63
+ [id, attributes.slice(*Spree::LineItem.attr_accessible[:default])]
64
+ end
65
+ end
66
+ line_item_attributes = Hash[line_item_attributes].delete_if { |k,v| v.empty? }
49
67
  end
50
68
 
51
69
  def order
@@ -20,10 +20,14 @@ module Spree
20
20
  authorize! :create, Product
21
21
  params[:product][:available_on] ||= Time.now
22
22
  @product = Product.new(params[:product])
23
- if @product.save
24
- respond_with(@product, :status => 201, :default_template => :show)
25
- else
26
- invalid_resource!(@product)
23
+ begin
24
+ if @product.save
25
+ respond_with(@product, :status => 201, :default_template => :show)
26
+ else
27
+ invalid_resource!(@product)
28
+ end
29
+ rescue ActiveRecord::RecordNotUnique
30
+ retry
27
31
  end
28
32
  end
29
33
 
@@ -68,7 +68,7 @@ module Spree
68
68
  variants = variants.active
69
69
  end
70
70
  end
71
- variants
71
+ variants.readonly(false)
72
72
  end
73
73
  end
74
74
  end
@@ -21,7 +21,7 @@ module Spree
21
21
  end
22
22
 
23
23
  def variant_attributes
24
- [:id, :name, :count_on_hand, :sku, :price, :weight, :height, :width, :depth, :is_master, :cost_price, :permalink]
24
+ [:id, :name, :count_on_hand, :sku, :price, :weight, :height, :width, :depth, :is_master, :cost_price, :permalink, :product_id, :lock_version]
25
25
  end
26
26
 
27
27
  def image_attributes
@@ -1,13 +1,163 @@
1
1
  Spree::Order.class_eval do
2
2
  def self.build_from_api(user, params)
3
- order = create
4
- params[:line_items_attributes] ||= []
5
- unless params[:line_items_attributes].empty?
6
- params[:line_items_attributes].each_key do |k|
7
- order.add_variant(Spree::Variant.find(params[:line_items_attributes][k][:variant_id]), params[:line_items_attributes][k][:quantity])
3
+ begin
4
+ ensure_country_id_from_api params[:ship_address_attributes]
5
+ ensure_state_id_from_api params[:ship_address_attributes]
6
+ ensure_country_id_from_api params[:bill_address_attributes]
7
+ ensure_state_id_from_api params[:bill_address_attributes]
8
+
9
+ order = create!
10
+
11
+ order.create_shipments_from_api params.delete(:shipments_attributes) || []
12
+ order.create_line_items_from_api params.delete(:line_items_attributes) || {}
13
+ order.create_adjustments_from_api params.delete(:adjustments_attributes) || []
14
+ order.create_payments_from_api params.delete(:payments_attributes) || []
15
+ order.complete_from_api params.delete(:completed_at)
16
+
17
+ destroy_automatic_taxes_on_import(order, params)
18
+ order.update_attributes!(params)
19
+
20
+ order.reload
21
+ rescue Exception => e
22
+ order.destroy if order && order.persisted?
23
+ raise e.message
24
+ end
25
+ end
26
+
27
+ def self.destroy_automatic_taxes_on_import(order, params)
28
+ if params.delete :import
29
+ order.adjustments.tax.destroy_all
30
+ end
31
+ end
32
+
33
+ def complete_from_api(completed_at)
34
+ if completed_at
35
+ self.completed_at = completed_at
36
+ self.state = 'complete'
37
+ end
38
+ end
39
+
40
+ def create_shipments_from_api(shipments_hash)
41
+ shipments_hash.each do |s|
42
+ begin
43
+ shipment = shipments.build
44
+ shipment.tracking = s[:tracking]
45
+
46
+ inventory_units = s[:inventory_units] || []
47
+ inventory_units.each do |iu|
48
+ self.class.ensure_variant_id_from_api(iu)
49
+
50
+ unit = shipment.inventory_units.build
51
+ unit.order = self
52
+ unit.variant_id = iu[:variant_id]
53
+ end
54
+
55
+ shipment.shipping_method = Spree::ShippingMethod.find_by_name!(s[:shipping_method])
56
+ shipment.save!
57
+
58
+ shipment.adjustment.locked = true
59
+ shipment.adjustment.amount = s[:cost].to_f
60
+ shipment.adjustment.save
61
+ rescue Exception => e
62
+ raise "#{e.message} #{s}"
63
+ end
64
+ end
65
+ end
66
+
67
+ def create_payments_from_api(payments_hash)
68
+ payments_hash.each do |p|
69
+ begin
70
+ payment = payments.build
71
+ payment.amount = p[:amount].to_f
72
+ payment.state = p.fetch(:state, 'completed')
73
+ payment.payment_method = Spree::PaymentMethod.find_by_name!(p[:payment_method])
74
+ payment.save!
75
+ rescue Exception => e
76
+ raise "#{e.message} #{p}"
8
77
  end
9
78
  end
79
+ end
80
+
81
+ def create_line_items_from_api(line_items_hash)
82
+ line_items_hash.each_key do |k|
83
+ begin
84
+ line_item = line_items_hash[k]
85
+ self.class.ensure_variant_id_from_api(line_item)
86
+
87
+ item = self.add_variant(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
10
88
 
11
- order
89
+ if line_item.key? :price
90
+ item.price = line_item[:price]
91
+ item.save!
92
+ end
93
+ rescue Exception => e
94
+ raise "#{e.message} #{line_item}"
95
+ end
96
+ end
97
+ end
98
+
99
+ def create_adjustments_from_api(adjustments)
100
+ adjustments.each do |a|
101
+ begin
102
+ adjustment = self.adjustments.build(:amount => a['amount'].to_f,
103
+ :label => a['label'])
104
+ adjustment.locked = true
105
+ adjustment.save!
106
+ rescue Exception => e
107
+ raise "#{e.message} #{a}"
108
+ end
109
+ end
110
+ end
111
+
112
+ def self.ensure_variant_id_from_api(hash)
113
+ begin
114
+ unless hash[:variant_id].present?
115
+ hash[:variant_id] = Spree::Variant.active.find_by_sku!(hash[:sku]).id
116
+ hash.delete(:sku)
117
+ end
118
+ rescue Exception => e
119
+ raise "#{e.message} #{hash}"
120
+ end
121
+ end
122
+
123
+ def self.ensure_country_id_from_api(address)
124
+ return if address.nil? or address[:country_id].present? or address[:country].nil?
125
+
126
+ begin
127
+ search = {}
128
+ if name = address[:country]['name']
129
+ search[:name] = name
130
+ elsif iso_name = address[:country]['iso_name']
131
+ search[:iso_name] = iso_name.upcase
132
+ elsif iso = address[:country]['iso']
133
+ search[:iso] = iso.upcase
134
+ elsif iso3 = address[:country]['iso3']
135
+ search[:iso3] = iso3.upcase
136
+ end
137
+
138
+ address.delete(:country)
139
+ address[:country_id] = Spree::Country.where(search).first!.id
140
+
141
+ rescue Exception => e
142
+ raise "#{e.message} #{search}"
143
+ end
144
+ end
145
+
146
+ def self.ensure_state_id_from_api(address)
147
+ return if address.nil? or address[:state_id].present? or address[:state].nil?
148
+
149
+ begin
150
+ search = {}
151
+ if name = address[:state]['name']
152
+ search[:name] = name
153
+ elsif abbr = address[:state]['abbr']
154
+ search[:abbr] = abbr.upcase
155
+ end
156
+
157
+ address.delete(:state)
158
+ address[:state_id] = Spree::State.where(search).first!.id
159
+ rescue Exception => e
160
+ raise "#{e.message} #{search}"
161
+ end
12
162
  end
13
163
  end
@@ -2,5 +2,6 @@ Deface::Override.new(:virtual_path => "spree/layouts/spree_application",
2
2
  :name => "api_key_spree_layout",
3
3
  :insert_bottom => "body",
4
4
  :partial => "spree/api/key",
5
- :disabled => false)
5
+ :disabled => false,
6
+ :original => "eb4b04993e8e4d1c20a7c3d974dfed20b59aec4c")
6
7
 
@@ -1 +1,5 @@
1
1
  attributes *variant_attributes
2
+ node(:options_text) { |v| v.options_text }
3
+ child :option_values => :option_values do
4
+ attributes *option_value_attributes
5
+ end
@@ -9,19 +9,6 @@ module Spree
9
9
  user
10
10
  end
11
11
  end
12
-
13
- # Default kaminari's pagination to a certain range
14
- # Means that you don't need to create 25 objects to test pagination
15
- def default_per_page(count)
16
- before do
17
- @current_default_per_page = Kaminari.config.default_per_page
18
- Kaminari.config.default_per_page = 1
19
- end
20
-
21
- after do
22
- Kaminari.config.default_per_page = @current_default_per_page
23
- end
24
- end
25
12
  end
26
13
  end
27
14
  end
@@ -56,7 +56,7 @@ module Spree
56
56
  order.email = nil # email is necessary to transition from cart to address
57
57
  order.save!
58
58
 
59
- api_put :update, :id => order.to_param
59
+ api_put :update, :id => order.to_param, :order_token => order.token
60
60
 
61
61
  json_response['error'].should =~ /could not be transitioned/
62
62
  response.status.should == 422
@@ -65,13 +65,13 @@ module Spree
65
65
  it "should transition a recently created order from cart do address" do
66
66
  order.state.should eq "cart"
67
67
  order.email.should_not be_nil
68
- api_put :update, :id => order.to_param
68
+ api_put :update, :id => order.to_param, :order_token => order.token
69
69
  order.reload.state.should eq "address"
70
70
  end
71
71
 
72
72
  it "will return an error if the order cannot transition" do
73
73
  order.update_column(:state, "address")
74
- api_put :update, :id => order.to_param
74
+ api_put :update, :id => order.to_param, :order_token => order.token
75
75
  json_response['error'].should =~ /could not be transitioned/
76
76
  response.status.should == 422
77
77
  end
@@ -89,7 +89,7 @@ module Spree
89
89
  :country_id => @country.id
90
90
  }
91
91
  api_put :update,
92
- :id => order.to_param,
92
+ :id => order.to_param, :order_token => order.token,
93
93
  :order => { :bill_address_attributes => billing_address, :ship_address_attributes => shipping_address }
94
94
 
95
95
  json_response['state'].should == 'delivery'
@@ -100,7 +100,8 @@ module Spree
100
100
 
101
101
  it "can update shipping method and transition from delivery to payment" do
102
102
  order.update_column(:state, "delivery")
103
- api_put :update, :id => order.to_param, :order => { :shipping_method_id => @shipping_method.id }
103
+ api_put :update, :id => order.to_param, :order_token => order.token,
104
+ :order => { :shipping_method_id => @shipping_method.id }
104
105
 
105
106
  json_response['shipments'][0]['shipping_method']['name'].should == @shipping_method.name
106
107
  json_response['state'].should == 'payment'
@@ -109,7 +110,8 @@ module Spree
109
110
 
110
111
  it "can update payment method and transition from payment to confirm" do
111
112
  order.update_column(:state, "payment")
112
- api_put :update, :id => order.to_param, :order => { :payments_attributes => [{ :payment_method_id => @payment_method.id }] }
113
+ api_put :update, :id => order.to_param, :order_token => order.token,
114
+ :order => { :payments_attributes => [{ :payment_method_id => @payment_method.id }] }
113
115
  json_response['state'].should == 'confirm'
114
116
  json_response['payments'][0]['payment_method']['name'].should == @payment_method.name
115
117
  response.status.should == 200
@@ -118,30 +120,35 @@ module Spree
118
120
  it "can transition from confirm to complete" do
119
121
  order.update_column(:state, "confirm")
120
122
  Spree::Order.any_instance.stub(:payment_required? => false)
121
- api_put :update, :id => order.to_param
123
+ api_put :update, :id => order.to_param, :order_token => order.token
122
124
  json_response['state'].should == 'complete'
123
125
  response.status.should == 200
124
126
  end
125
127
 
126
128
  it "returns the order if the order is already complete" do
127
129
  order.update_column(:state, "complete")
128
- api_put :update, :id => order.to_param
130
+ api_put :update, :id => order.to_param, :order_token => order.token
129
131
  json_response['number'].should == order.number
130
132
  response.status.should == 200
131
133
  end
132
134
 
133
135
  it "can assign a user to the order" do
134
136
  user = create(:user)
135
- api_put :update, :id => order.to_param, :order => { :user_id => user.id }
137
+ api_put :update, :id => order.to_param, :order_token => order.token, :order => { :user_id => user.id }
136
138
  json_response['user_id'].should == user.id
137
139
  response.status.should == 200
138
140
  end
139
141
 
140
142
  it "can assign an email to the order" do
141
- api_put :update, :id => order.to_param, :order => { :email => "guest@spreecommerce.com" }
143
+ api_put :update, :id => order.to_param, :order_token => order.token, :order => { :email => "guest@spreecommerce.com" }
142
144
  json_response['email'].should == "guest@spreecommerce.com"
143
145
  response.status.should == 200
144
146
  end
147
+
148
+ it "cannot update an order without authorization" do
149
+ api_put :update, :id => order.to_param
150
+ assert_unauthorized!
151
+ end
145
152
  end
146
153
  end
147
154
  end
@@ -71,6 +71,25 @@ module Spree
71
71
  json_response["state"].should == "cart"
72
72
  end
73
73
 
74
+ it "cannot create an order with an abitrary price for the line item" do
75
+ variant = create(:variant)
76
+ api_post :create, :order => {
77
+ :line_items => {
78
+ "0" => {
79
+ :variant_id => variant.to_param,
80
+ :quantity => 5,
81
+ :price => 0.44
82
+ }
83
+ }
84
+ }
85
+ response.status.should == 201
86
+ order = Order.last
87
+ order.line_items.count.should == 1
88
+ order.line_items.first.variant.should == variant
89
+ order.line_items.first.quantity.should == 5
90
+ order.line_items.first.price.should == order.line_items.first.variant.price
91
+ end
92
+
74
93
  context "working with an order" do
75
94
  before do
76
95
  Order.any_instance.stub :user => current_api_user
@@ -87,55 +106,67 @@ module Spree
87
106
  end
88
107
 
89
108
  let(:address_params) { { :country_id => Country.first.id, :state_id => State.first.id } }
90
- let(:billing_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
109
+ let(:billing_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
91
110
  :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
92
111
  :country_id => Country.first.id, :state_id => State.first.id} }
93
- let(:shipping_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
112
+ let(:shipping_address) { { :firstname => "Tiago", :lastname => "Motta", :address1 => "Av Paulista",
94
113
  :city => "Sao Paulo", :zipcode => "1234567", :phone => "12345678",
95
114
  :country_id => Country.first.id, :state_id => State.first.id} }
96
115
  let!(:shipping_method) { create(:shipping_method) }
97
116
  let!(:payment_method) { create(:payment_method) }
98
117
 
99
- it "can add line items" do
100
- api_put :update, :id => order.to_param, :order => { :line_items => [{:variant_id => create(:variant).id, :quantity => 2}] }
118
+ it "can not update line item prices" do
119
+ order.line_items << create(:line_item)
120
+ api_put :update,
121
+ :id => order.to_param,
122
+ :order => {
123
+ :line_items => {
124
+ order.line_items.first.id =>
125
+ {
126
+ :variant_id => create(:variant).id,
127
+ :quantity => 2,
128
+ :price => 0.44
129
+ }
130
+ }
131
+ }
101
132
 
102
133
  response.status.should == 200
103
134
  json_response['item_total'].to_f.should_not == order.item_total.to_f
104
135
  end
105
-
136
+
106
137
  it "can add billing address" do
107
138
  order.bill_address.should be_nil
108
-
139
+
109
140
  api_put :update, :id => order.to_param, :order => { :bill_address_attributes => billing_address }
110
-
141
+
111
142
  order.reload.bill_address.should_not be_nil
112
143
  end
113
-
144
+
114
145
  it "receives error message if trying to add billing address with errors" do
115
146
  order.bill_address.should be_nil
116
147
  billing_address[:firstname] = ""
117
-
148
+
118
149
  api_put :update, :id => order.to_param, :order => { :bill_address_attributes => billing_address }
119
-
150
+
120
151
  json_response['error'].should_not be_nil
121
152
  json_response['errors'].should_not be_nil
122
153
  json_response['errors']['bill_address.firstname'].first.should eq "can't be blank"
123
154
  end
124
-
155
+
125
156
  it "can add shipping address" do
126
157
  order.ship_address.should be_nil
127
-
158
+
128
159
  api_put :update, :id => order.to_param, :order => { :ship_address_attributes => shipping_address }
129
-
160
+
130
161
  order.reload.ship_address.should_not be_nil
131
162
  end
132
-
163
+
133
164
  it "receives error message if trying to add shipping address with errors" do
134
165
  order.ship_address.should be_nil
135
166
  shipping_address[:firstname] = ""
136
-
167
+
137
168
  api_put :update, :id => order.to_param, :order => { :ship_address_attributes => shipping_address }
138
-
169
+
139
170
  json_response['error'].should_not be_nil
140
171
  json_response['errors'].should_not be_nil
141
172
  json_response['errors']['ship_address.firstname'].first.should eq "can't be blank"
@@ -151,15 +182,15 @@ module Spree
151
182
  response.status.should == 200
152
183
  order.reload.line_items.should be_empty
153
184
  end
154
-
185
+
155
186
  it "can list its line items with images" do
156
187
  order.line_items.first.variant.images.create!(:attachment => image("thinking-cat.jpg"))
157
-
188
+
158
189
  api_get :show, :id => order.to_param
159
-
190
+
160
191
  json_response['line_items'].first['variant'].should have_attributes([:images])
161
192
  end
162
-
193
+
163
194
  it "lists variants product id" do
164
195
  api_get :show, :id => order.to_param
165
196
 
@@ -28,11 +28,10 @@ module Spree
28
28
  end
29
29
 
30
30
  context "pagination" do
31
- default_per_page(1)
32
31
 
33
32
  it "can select the next page of products" do
34
33
  second_product = create(:product)
35
- api_get :index, :page => 2
34
+ api_get :index, :page => 2, :per_page => 1
36
35
  json_response["products"].first.should have_attributes(attributes)
37
36
  json_response["total_count"].should == 2
38
37
  json_response["current_page"].should == 2
@@ -14,7 +14,7 @@ module Spree
14
14
  let!(:attributes) { [:id, :name, :count_on_hand,
15
15
  :sku, :price, :weight, :height,
16
16
  :width, :depth, :is_master, :cost_price,
17
- :permalink] }
17
+ :permalink, :product_id, :lock_version] }
18
18
 
19
19
  before do
20
20
  stub_authentication!
@@ -51,7 +51,7 @@ module Spree
51
51
  :option_type_name,
52
52
  :option_type_id])
53
53
  end
54
-
54
+
55
55
  it "variants returned contain images data" do
56
56
  variant.images.create!(:attachment => image("thinking-cat.jpg"))
57
57
 
@@ -78,11 +78,9 @@ module Spree
78
78
  end
79
79
 
80
80
  context "pagination" do
81
- default_per_page(1)
82
-
83
81
  it "can select the next page of variants" do
84
82
  second_variant = create(:variant)
85
- api_get :index, :page => 2
83
+ api_get :index, :page => 2, :per_page => 1
86
84
  json_response["variants"].first.should have_attributes(attributes)
87
85
  json_response["total_count"].should == 3
88
86
  json_response["current_page"].should == 2
@@ -99,13 +97,13 @@ module Spree
99
97
  :option_type_name,
100
98
  :option_type_id])
101
99
  end
102
-
100
+
103
101
  it "can see a single variant with images" do
104
102
  variant.images.create!(:attachment => image("thinking-cat.jpg"))
105
-
103
+
106
104
  api_get :show, :id => variant.to_param
107
-
108
- json_response.should have_attributes(attributes + [:images])
105
+
106
+ json_response.should have_attributes(attributes + [:images])
109
107
  option_values = json_response["option_values"]
110
108
  option_values.first.should have_attributes([:name,
111
109
  :presentation,
@@ -170,6 +168,18 @@ module Spree
170
168
  response.status.should == 204
171
169
  lambda { variant.reload }.should raise_error(ActiveRecord::RecordNotFound)
172
170
  end
171
+
172
+ context "without product" do
173
+ sign_in_as_admin!
174
+ let(:resource_scoping) { { :product_id => variant.product.to_param } }
175
+
176
+ it "will not raise an ActiveRecord::ReadOnlyRecord exception" do
177
+ api_put :update, :id => variant.to_param, :variant => { :sku => "12345", :on_hand => 5 }
178
+ response.status.should_not eql 422
179
+ json_response["exception"].should_not eql "ActiveRecord::ReadOnlyRecord"
180
+ end
181
+ end
182
+
173
183
  end
174
184
 
175
185
 
@@ -2,17 +2,311 @@ require 'spec_helper'
2
2
 
3
3
  module Spree
4
4
  describe Order do
5
- let(:user) { stub_model(LegacyUser) }
5
+ let!(:country) { FactoryGirl.create(:country) }
6
+ let!(:state) { country.states.first || FactoryGirl.create(:state, :country => country) }
7
+ let(:user) { create(:user) }
8
+ let(:product) { Spree::Product.create!(:name => 'Test', :sku => 'TEST-1', :price => 33.22) }
9
+ let(:sku) { product.master.sku }
10
+ let(:variant) { product.master }
11
+ let(:variant_id) { product.master.id }
12
+ let(:line_items) {{ "0" => { :variant_id => variant.id, :quantity => 5 }}}
13
+ let(:shipping_method) { create(:shipping_method) }
14
+ let(:payment_method) { create(:payment_method) }
15
+ let(:ship_address) {{
16
+ :address1 => '123 Testable Way',
17
+ :firstname => 'Fox',
18
+ :lastname => 'Mulder',
19
+ :city => 'Washington',
20
+ :country_id => country.id,
21
+ :state_id => state.id,
22
+ :zipcode => '666',
23
+ :phone => '666-666-6666'
24
+ }}
6
25
 
7
- it 'can build an order from API parameters' do
8
- product = Spree::Product.create!(:name => 'Test', :sku => 'TEST-1', :price => 33.22)
9
- variant_id = product.master.id
10
- order = Order.build_from_api(user, { :line_items_attributes => { "0" => { :variant_id => variant_id, :quantity => 5 }}})
26
+ it 'can import an order number' do
27
+ params = { number: '123-456-789' }
28
+ order = Order.build_from_api(user, params)
29
+ order.number.should eq '123-456-789'
30
+ end
31
+
32
+ it 'optionally add completed at' do
33
+ params = {:email => 'test@test.com',
34
+ :completed_at => Time.now,
35
+ :line_items_attributes => line_items }
36
+
37
+ order = Order.build_from_api(user, params)
38
+ order.should be_completed
39
+ order.state.should eq 'complete'
40
+ end
41
+
42
+ it "assigns order[email] over user email to order" do
43
+ params = { email: 'wooowww@test.com' }
44
+ order = Order.build_from_api(user, params)
45
+ expect(order.email).to eq params[:email]
46
+ end
47
+
48
+ context "build order with line items" do
49
+ let(:attributes) do
50
+ { :variant_id => variant.id, :quantity => 5, :price => 33.77 }
51
+ end
52
+
53
+ it 'can build an order from API with just line items' do
54
+ params = { :line_items_attributes => { "0" => attributes } }
55
+ Order.should_receive(:ensure_variant_id_from_api)
56
+ order = Order.build_from_api(user, params)
57
+
58
+ order.user.should == nil
59
+ line_item = order.line_items.first
60
+
61
+ expect(line_item.quantity).to eq attributes[:quantity]
62
+ expect(line_item.variant_id).to eq attributes[:variant_id]
63
+ expect(line_item.price).to eq attributes[:price]
64
+ end
65
+ end
66
+
67
+ it 'uses line item price if present' do
68
+ line_items['0'][:price] = 12.00
69
+ params = { :line_items_attributes => line_items }
70
+
71
+ order = Order.build_from_api(user, params)
72
+
73
+ line_item = order.line_items.first
74
+ line_item.price.to_f.should == 12.00
75
+ end
76
+
77
+ it 'handles line_item building exceptions' do
78
+ line_items['0'][:variant_id] = 'XXX'
79
+ params = { :line_items_attributes => line_items }
80
+
81
+ expect {
82
+ order = Order.build_from_api(user, params)
83
+ }.to raise_error /XXX/
84
+ end
85
+
86
+ it 'can build an order from API with variant sku' do
87
+ params = { :line_items_attributes => {
88
+ "0" => { :sku => sku, :quantity => 5 } }}
89
+
90
+ order = Order.build_from_api(user, params)
11
91
 
12
- order.user.should == nil
13
92
  line_item = order.line_items.first
14
- line_item.quantity.should == 5
15
93
  line_item.variant_id.should == variant_id
94
+ line_item.quantity.should == 5
95
+ end
96
+
97
+ it 'handles exceptions when sku is not found' do
98
+ params = { :line_items_attributes => {
99
+ "0" => { :sku => 'XXX', :quantity => 5 } }}
100
+ expect {
101
+ order = Order.build_from_api(user, params)
102
+ }.to raise_error /XXX/
103
+ end
104
+
105
+ it 'can build an order from API shipping address' do
106
+ params = { :ship_address_attributes => ship_address,
107
+ :line_items_attributes => line_items }
108
+
109
+ order = Order.build_from_api(user, params)
110
+ order.ship_address.address1.should eq '123 Testable Way'
111
+ end
112
+
113
+ it 'can build an order from API with country attributes' do
114
+ ship_address.delete(:country_id)
115
+ ship_address[:country] = { 'iso' => 'US' }
116
+ params = { :ship_address_attributes => ship_address,
117
+ :line_items_attributes => line_items }
118
+
119
+ order = Order.build_from_api(user, params)
120
+ order.ship_address.country.iso.should eq 'US'
121
+ end
122
+
123
+ it 'handles country lookup exceptions' do
124
+ ship_address.delete(:country_id)
125
+ ship_address[:country] = { 'iso' => 'XXX' }
126
+ params = { :ship_address_attributes => ship_address,
127
+ :line_items_attributes => line_items }
128
+
129
+ expect {
130
+ order = Order.build_from_api(user, params)
131
+ }.to raise_error /XXX/
132
+ end
133
+
134
+ it 'can build an order from API with state attributes' do
135
+ ship_address.delete(:state_id)
136
+ ship_address[:state] = { 'name' => 'Alabama' }
137
+ params = { :ship_address_attributes => ship_address,
138
+ :line_items_attributes => line_items }
139
+
140
+ order = Order.build_from_api(user, params)
141
+ order.ship_address.state.name.should eq 'Alabama'
142
+ end
143
+
144
+ it 'handles state lookup exceptions' do
145
+ ship_address.delete(:state_id)
146
+ ship_address[:state] = { 'name' => 'XXX' }
147
+ params = { :ship_address_attributes => ship_address,
148
+ :line_items_attributes => line_items }
149
+
150
+ expect {
151
+ order = Order.build_from_api(user, params)
152
+ }.to raise_error /XXX/
153
+ end
154
+
155
+ context 'variant not deleted' do
156
+ it 'ensures variant id from api' do
157
+ hash = { sku: variant.sku }
158
+ Order.ensure_variant_id_from_api(hash)
159
+ expect(hash[:variant_id]).to eq variant.id
160
+ end
161
+ end
162
+
163
+ context 'variant was deleted' do
164
+ it 'raise error as variant shouldnt be found' do
165
+ variant.product.delete
166
+ hash = { sku: variant.sku }
167
+ expect {
168
+ Order.ensure_variant_id_from_api(hash)
169
+ }.to raise_error
170
+ end
171
+ end
172
+
173
+ it 'ensures_country_id for country fields' do
174
+ [:name, :iso, :iso_name, :iso3].each do |field|
175
+ address = { :country => { field => country.send(field) }}
176
+ Order.ensure_country_id_from_api(address)
177
+ address[:country_id].should eq country.id
178
+ end
179
+ end
180
+
181
+ it "raises with proper message when cant find country" do
182
+ address = { :country => { "name" => "NoNoCountry" } }
183
+ expect {
184
+ Order.ensure_country_id_from_api(address)
185
+ }.to raise_error /NoNoCountry/
186
+ end
187
+
188
+ it 'ensures_state_id for state fields' do
189
+ [:name, :abbr].each do |field|
190
+ address = { :state => { field => state.send(field) }}
191
+ Order.ensure_state_id_from_api(address)
192
+ address[:state_id].should eq state.id
193
+ end
194
+ end
195
+
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
+ context "shippments" do
204
+ let(:params) do
205
+ { :shipments_attributes => [
206
+ { :tracking => '123456789',
207
+ :cost => '4.99',
208
+ :shipping_method => shipping_method.name,
209
+ :inventory_units => [{ :sku => sku }]
210
+ }
211
+ ] }
212
+ end
213
+
214
+ it 'ensures variant exists and is not deleted' do
215
+ Order.should_receive(:ensure_variant_id_from_api)
216
+ order = Order.build_from_api(user, params)
217
+ end
218
+
219
+ it 'builds them properly' do
220
+ order = Order.build_from_api(user, params)
221
+
222
+ shipment = order.shipments.first
223
+ shipment.inventory_units.first.variant_id.should eq product.master.id
224
+ shipment.tracking.should eq '123456789'
225
+ shipment.adjustment.amount.should eq 4.99
226
+ shipment.adjustment.should be_locked
227
+ end
228
+ end
229
+
230
+ it 'handles shipment building exceptions' do
231
+ params = { :shipments_attributes => [{ :tracking => '123456789',
232
+ :cost => '4.99',
233
+ :shipping_method => 'XXX',
234
+ :inventory_units => [{ :sku => sku }]
235
+ }] }
236
+ expect {
237
+ order = Order.build_from_api(user, params)
238
+ }.to raise_error /XXX/
239
+ end
240
+
241
+ it 'adds adjustments' do
242
+ params = { :adjustments_attributes => [
243
+ { "label" => "Shipping Discount", "amount" => "-4.99" },
244
+ { "label" => "Promotion Discount", "amount" => "-3.00" }] }
245
+
246
+ order = Order.build_from_api(user, params)
247
+ order.adjustments.all?(&:locked).should be_true
248
+ order.adjustments.first.label.should eq 'Shipping Discount'
249
+ order.adjustments.first.amount.should eq -4.99
250
+ end
251
+
252
+ it 'handles adjustment building exceptions' do
253
+ params = { :adjustments_attributes => [
254
+ { "amount" => "XXX" },
255
+ { "label" => "Promotion Discount", "amount" => "-3.00" }] }
256
+
257
+ expect {
258
+ order = Order.build_from_api(user, params)
259
+ }.to raise_error /XXX/
260
+ end
261
+
262
+ it 'builds a payment' do
263
+ params = { :payments_attributes => [{ :amount => '4.99',
264
+ :payment_method => payment_method.name }] }
265
+ order = Order.build_from_api(user, params)
266
+ order.payments.first.amount.should eq 4.99
267
+ end
268
+
269
+ it 'handles payment building exceptions' do
270
+ params = { :payments_attributes => [{ :amount => '4.99',
271
+ :payment_method => 'XXX' }] }
272
+ expect {
273
+ order = Order.build_from_api(user, params)
274
+ }.to raise_error /XXX/
275
+ end
276
+
277
+ context "raises error" do
278
+ it "clears out order from db" do
279
+ params = { :payments_attributes => [{ payment_method: "XXX" }] }
280
+ count = Order.count
281
+
282
+ expect { order = Order.build_from_api(user, params) }.to raise_error
283
+ expect(Order.count).to eq count
284
+ end
285
+ end
286
+
287
+ context "import param and tax adjustments" do
288
+ let!(:tax_rate) { create(:tax_rate, amount: 0.05, calculator: Calculator::DefaultTax.create) }
289
+ let(:other_variant) { create(:variant) }
290
+
291
+ let(:line_item_attributes) do
292
+ line_items.merge({ "1" => { :variant_id => other_variant.id, :quantity => 5 }})
293
+ end
294
+
295
+ before { Zone.stub default_tax: tax_rate.zone }
296
+
297
+ it "doesnt create any tax ajustments when importing order" do
298
+ params = { import: true, line_items_attributes: line_item_attributes }
299
+ expect {
300
+ Order.build_from_api(user, params)
301
+ }.not_to change { Adjustment.count }
302
+ end
303
+
304
+ it "does create tax adjustments if not importing order" do
305
+ params = { import: false, line_items_attributes: line_item_attributes }
306
+ expect {
307
+ Order.build_from_api(user, params)
308
+ }.to change { Adjustment.count }
309
+ end
16
310
  end
17
311
  end
18
312
  end
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.3
4
+ version: 1.3.4
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-06-13 00:00:00.000000000 Z
11
+ date: 2013-10-15 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.3
19
+ version: 1.3.4
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.3
26
+ version: 1.3.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: versioncake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  version: '0'
199
199
  requirements: []
200
200
  rubyforge_project:
201
- rubygems_version: 2.0.0
201
+ rubygems_version: 2.1.0
202
202
  signing_key:
203
203
  specification_version: 4
204
204
  summary: Spree's API