spree_api 1.3.3 → 1.3.4

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