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 +4 -4
- data/app/controllers/spree/api/checkouts_controller.rb +7 -0
- data/app/controllers/spree/api/orders_controller.rb +19 -1
- data/app/controllers/spree/api/products_controller.rb +8 -4
- data/app/controllers/spree/api/variants_controller.rb +1 -1
- data/app/helpers/spree/api/api_helpers.rb +1 -1
- data/app/models/spree/order_decorator.rb +156 -6
- data/app/overrides/api_key_spree_layout.rb +2 -1
- data/app/views/spree/api/variants/variant.v1.rabl +4 -0
- data/lib/spree/api/testing_support/setup.rb +0 -13
- data/spec/controllers/spree/api/checkouts_controller_spec.rb +17 -10
- data/spec/controllers/spree/api/orders_controller_spec.rb +51 -20
- data/spec/controllers/spree/api/products_controller_spec.rb +1 -2
- data/spec/controllers/spree/api/variants_controller_spec.rb +19 -9
- data/spec/models/spree/order_spec.rb +301 -7
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 288706a5a4c81fc84a82d1f1aa91dcd8ce546fb6
|
4
|
+
data.tar.gz: 75057c9776f7ecbe0374da3d4c155aa3bf61130d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
|
@@ -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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
params[:
|
7
|
-
|
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
|
-
|
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
|
|
@@ -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, :
|
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, :
|
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
|
100
|
-
|
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(:
|
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
|
8
|
-
|
9
|
-
|
10
|
-
order
|
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.
|
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-
|
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.
|
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.
|
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.
|
201
|
+
rubygems_version: 2.1.0
|
202
202
|
signing_key:
|
203
203
|
specification_version: 4
|
204
204
|
summary: Spree's API
|