spree_api 2.0.4 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -3
- data/app/controllers/spree/api/addresses_controller.rb +21 -4
- data/app/controllers/spree/api/checkouts_controller.rb +22 -5
- data/app/controllers/spree/api/orders_controller.rb +7 -1
- data/app/controllers/spree/api/stock_items_controller.rb +4 -1
- data/app/controllers/spree/api/taxons_controller.rb +4 -2
- data/app/controllers/spree/api/variants_controller.rb +1 -1
- data/app/helpers/spree/api/api_helpers.rb +4 -0
- data/app/models/spree/order_decorator.rb +143 -7
- data/app/views/spree/api/addresses/show.v1.rabl +2 -4
- data/app/views/spree/api/taxons/index.v1.rabl +10 -4
- data/config/routes.rb +3 -1
- data/spec/controllers/spree/api/addresses_controller_spec.rb +10 -8
- data/spec/controllers/spree/api/checkouts_controller_spec.rb +13 -2
- data/spec/controllers/spree/api/orders_controller_spec.rb +30 -3
- data/spec/controllers/spree/api/stock_items_controller_spec.rb +20 -2
- data/spec/controllers/spree/api/taxons_controller_spec.rb +18 -6
- data/spec/models/spree/order_spec.rb +235 -5
- 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: 0c5fb9fd878e6c935137a8f09d6b4cffa35f78db
|
4
|
+
data.tar.gz: aef11d5c34c3cfa8f55c78fa0f987e493220618c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ccb7dc808ccfe6a0badbcca88f2fee1c7f40bff832051b851384be324fbe1c9d97c128b9447d18c6d836a1f77b921fa8dab75c19be1ad73a48c68ea6f2e3652
|
7
|
+
data.tar.gz: 560ebb4f8b5019b23c3686e8f92131b5ec4a692923e6173e0c93b6740568527b2466b039787c84503c07908caf008a9aee2971cb7434514cb87df920eaed3e37
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
## Spree 2.0.
|
2
|
-
|
3
|
-
## Spree 2.0.4
|
1
|
+
## Spree 2.0.x ##
|
4
2
|
|
5
3
|
* PUT requests to Checkouts API endpoints now require authorization to alter an order.
|
6
4
|
|
@@ -29,3 +27,17 @@
|
|
29
27
|
* Attributes other than "quantity" and "variant_id" will be added to a line item when creating along with an order. #3404
|
30
28
|
|
31
29
|
*Alex Marles & Ryan Bigg*
|
30
|
+
|
31
|
+
* Taxon attributes from `/api/taxons` are now returned within `taxons` subkey. Before:
|
32
|
+
|
33
|
+
```json
|
34
|
+
[{ name: 'Ruby' ... }]
|
35
|
+
```
|
36
|
+
|
37
|
+
Now:
|
38
|
+
|
39
|
+
```json
|
40
|
+
{ taxons: [{ name: 'Ruby' }]}
|
41
|
+
```
|
42
|
+
|
43
|
+
* Ryan Bigg
|
@@ -1,16 +1,17 @@
|
|
1
1
|
module Spree
|
2
2
|
module Api
|
3
3
|
class AddressesController < Spree::Api::BaseController
|
4
|
+
before_filter :find_order
|
4
5
|
|
5
6
|
def show
|
6
|
-
@
|
7
|
-
|
7
|
+
authorize! :read, @order, params[:order_token]
|
8
|
+
find_address
|
8
9
|
respond_with(@address)
|
9
10
|
end
|
10
11
|
|
11
12
|
def update
|
12
|
-
@
|
13
|
-
|
13
|
+
authorize! :update, @order, params[:order_token]
|
14
|
+
find_address
|
14
15
|
|
15
16
|
if @address.update_attributes(params[:address])
|
16
17
|
respond_with(@address, :default_template => :show)
|
@@ -18,6 +19,22 @@ module Spree
|
|
18
19
|
invalid_resource!(@address)
|
19
20
|
end
|
20
21
|
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_order
|
26
|
+
@order = Spree::Order.find_by_number!(params[:order_id])
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_address
|
30
|
+
@address = if @order.bill_address_id == params[:id].to_i
|
31
|
+
@order.bill_address
|
32
|
+
elsif @order.ship_address_id == params[:id].to_i
|
33
|
+
@order.ship_address
|
34
|
+
else
|
35
|
+
raise CanCan::AccessDenied
|
36
|
+
end
|
37
|
+
end
|
21
38
|
end
|
22
39
|
end
|
23
40
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Spree
|
2
2
|
module Api
|
3
3
|
class CheckoutsController < Spree::Api::BaseController
|
4
|
-
|
5
|
-
before_filter :
|
4
|
+
|
5
|
+
before_filter :load_order, only: [:show, :update, :next, :advance]
|
6
|
+
before_filter :associate_user, only: :update
|
6
7
|
|
7
8
|
include Spree::Core::ControllerHelpers::Auth
|
8
9
|
include Spree::Core::ControllerHelpers::Order
|
@@ -13,7 +14,25 @@ module Spree
|
|
13
14
|
|
14
15
|
def create
|
15
16
|
@order = Order.build_from_api(current_api_user, nested_params)
|
16
|
-
respond_with(@order, :
|
17
|
+
respond_with(@order, default_template: 'spree/api/orders/show', status: 201)
|
18
|
+
end
|
19
|
+
|
20
|
+
def next
|
21
|
+
authorize! :update, @order, params[:order_token]
|
22
|
+
@order.next!
|
23
|
+
respond_with(@order, default_template: 'spree/api/orders/show', status: 200)
|
24
|
+
rescue StateMachine::InvalidTransition
|
25
|
+
respond_with(@order, default_template: 'spree/api/orders/could_not_transition', status: 422)
|
26
|
+
end
|
27
|
+
|
28
|
+
def advance
|
29
|
+
authorize! :update, @order, params[:order_token]
|
30
|
+
while @order.next; end
|
31
|
+
respond_with(@order, default_template: 'spree/api/orders/show', status: 200)
|
32
|
+
end
|
33
|
+
|
34
|
+
def show
|
35
|
+
respond_with(@order, default_template: 'spree/api/orders/show', status: 200)
|
17
36
|
end
|
18
37
|
|
19
38
|
def update
|
@@ -23,8 +42,6 @@ module Spree
|
|
23
42
|
line_items = order_params.delete("line_items_attributes")
|
24
43
|
if @order.update_attributes(order_params)
|
25
44
|
@order.update_line_items(line_items)
|
26
|
-
# TODO: Replace with better code when we switch to strong_parameters
|
27
|
-
# Also remove above user_id stripping
|
28
45
|
if current_api_user.has_spree_role?("admin") && user_id.present?
|
29
46
|
@order.associate_user!(Spree.user_class.find(user_id))
|
30
47
|
end
|
@@ -23,7 +23,13 @@ module Spree
|
|
23
23
|
|
24
24
|
def update
|
25
25
|
authorize! :update, Order
|
26
|
+
# Parsing line items through as an update_attributes call in the API will result in
|
27
|
+
# many line items for the same variant_id being created. We must be smarter about this,
|
28
|
+
# hence the use of the update_line_items method, defined within order_decorator.rb.
|
29
|
+
line_items_params = params[:order].delete("line_items")
|
26
30
|
if order.update_attributes(nested_params)
|
31
|
+
order.update_line_items(line_items_params)
|
32
|
+
order.line_items.reload
|
27
33
|
order.update!
|
28
34
|
respond_with(order, :default_template => :show)
|
29
35
|
else
|
@@ -37,7 +43,7 @@ module Spree
|
|
37
43
|
end
|
38
44
|
|
39
45
|
def empty
|
40
|
-
order.
|
46
|
+
order.empty!
|
41
47
|
order.update!
|
42
48
|
render :text => nil, :status => 200
|
43
49
|
end
|
@@ -41,7 +41,10 @@ module Spree
|
|
41
41
|
params[:stock_item].delete(:count_on_hand)
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
updated = params[:stock_item][:force] ? @stock_item.set_count_on_hand(count_on_hand)
|
45
|
+
: @stock_item.adjust_count_on_hand(count_on_hand)
|
46
|
+
|
47
|
+
if updated
|
45
48
|
respond_with(@stock_item, status: 200, default_template: :show)
|
46
49
|
else
|
47
50
|
invalid_resource!(@stock_item)
|
@@ -8,11 +8,13 @@ module Spree
|
|
8
8
|
@taxons = taxonomy.root.children
|
9
9
|
else
|
10
10
|
if params[:ids]
|
11
|
-
@taxons = Taxon.where(:id => params[:ids].split(","))
|
11
|
+
@taxons = Taxon.accessible_by(current_ability, :read).where(:id => params[:ids].split(","))
|
12
12
|
else
|
13
|
-
@taxons = Taxon.ransack(params[:q]).result
|
13
|
+
@taxons = Taxon.accessible_by(current_ability, :read).order(:taxonomy_id, :lft).ransack(params[:q]).result
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
@taxons = @taxons.page(params[:page]).per(params[:per_page])
|
16
18
|
respond_with(@taxons)
|
17
19
|
end
|
18
20
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
6
6
|
before_filter :product
|
7
7
|
|
8
8
|
def index
|
9
|
-
@variants = scope.includes(:option_values).ransack(params[:q]).result.
|
9
|
+
@variants = scope.includes(:option_values, :stock_items, :product, :images, :prices).ransack(params[:q]).result.
|
10
10
|
page(params[:page]).per(params[:per_page])
|
11
11
|
respond_with(@variants)
|
12
12
|
end
|
@@ -71,6 +71,10 @@ module Spree
|
|
71
71
|
[:id, :number, :state, :amount, :order_id, :reason, :created_at, :updated_at]
|
72
72
|
end
|
73
73
|
|
74
|
+
def address_attributes
|
75
|
+
[:id, :firstname, :lastname, :full_name, :address1, :address2, :city, :zipcode, :phone, :company, :alternative_phone, :country_id, :state_id, :state_name]
|
76
|
+
end
|
77
|
+
|
74
78
|
def country_attributes
|
75
79
|
[:id, :iso_name, :iso, :iso3, :name, :numcode]
|
76
80
|
end
|
@@ -1,20 +1,155 @@
|
|
1
1
|
Spree::Order.class_eval do
|
2
2
|
def self.build_from_api(user, params)
|
3
|
-
|
3
|
+
completed_at = params.delete(:completed_at)
|
4
|
+
line_items = params.delete(:line_items_attributes) || {}
|
5
|
+
shipments = params.delete(:shipments_attributes) || []
|
6
|
+
payments = params.delete(:payments_attributes) || []
|
7
|
+
adjustments = params.delete(:adjustments_attributes) || []
|
4
8
|
|
5
|
-
|
9
|
+
ensure_country_id_from_api params[:ship_address_attributes]
|
10
|
+
ensure_state_id_from_api params[:ship_address_attributes]
|
11
|
+
|
12
|
+
ensure_country_id_from_api params[:bill_address_attributes]
|
13
|
+
ensure_state_id_from_api params[:bill_address_attributes]
|
14
|
+
|
15
|
+
order = create!(params)
|
6
16
|
order.associate_user!(user)
|
7
17
|
|
8
|
-
|
9
|
-
|
10
|
-
|
18
|
+
order.create_shipments_from_api(shipments)
|
19
|
+
order.create_line_items_from_api(line_items)
|
20
|
+
order.create_adjustments_from_api(adjustments)
|
21
|
+
order.create_payments_from_api(payments)
|
22
|
+
order.complete_from_api(completed_at)
|
23
|
+
|
24
|
+
order.save!
|
25
|
+
order.reload
|
26
|
+
end
|
27
|
+
|
28
|
+
def complete_from_api(completed_at)
|
29
|
+
if completed_at
|
30
|
+
self.completed_at = completed_at
|
31
|
+
self.state = 'complete'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_shipments_from_api(shipments_hash)
|
36
|
+
shipments_hash.each do |s|
|
37
|
+
begin
|
38
|
+
shipment = shipments.build
|
39
|
+
shipment.tracking = s[:tracking]
|
40
|
+
|
41
|
+
inventory_units = s[:inventory_units] || []
|
42
|
+
inventory_units.each do |iu|
|
43
|
+
self.class.ensure_variant_id_from_api(iu)
|
44
|
+
|
45
|
+
unit = shipment.inventory_units.build
|
46
|
+
unit.order = self
|
47
|
+
unit.variant_id = iu[:variant_id]
|
48
|
+
end
|
49
|
+
|
50
|
+
shipment.save!
|
51
|
+
|
52
|
+
shipping_method = Spree::ShippingMethod.find_by_name!(s[:shipping_method])
|
53
|
+
shipment.shipping_rates.create!(:shipping_method => shipping_method,
|
54
|
+
:cost => s[:cost])
|
55
|
+
rescue Exception => e
|
56
|
+
raise "#{e.message} #{s}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_payments_from_api(payments_hash)
|
62
|
+
payments_hash.each do |p|
|
63
|
+
begin
|
64
|
+
payment = payments.build
|
65
|
+
payment.amount = p[:amount].to_f
|
66
|
+
payment.state = p.fetch(:state, 'completed')
|
67
|
+
payment.payment_method = Spree::PaymentMethod.find_by_name!(p[:payment_method])
|
68
|
+
payment.save!
|
69
|
+
rescue Exception => e
|
70
|
+
raise "#{e.message} #{p}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_line_items_from_api(line_items_hash)
|
76
|
+
line_items_hash.each_key do |k|
|
77
|
+
begin
|
78
|
+
line_item = line_items_hash[k]
|
79
|
+
self.class.ensure_variant_id_from_api(line_item)
|
80
|
+
|
11
81
|
extra_params = line_item.except(:variant_id, :quantity)
|
12
|
-
line_item =
|
82
|
+
line_item = self.contents.add(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
|
13
83
|
line_item.update_attributes(extra_params) unless extra_params.empty?
|
84
|
+
rescue Exception => e
|
85
|
+
raise "#{e.message} #{line_item}"
|
14
86
|
end
|
15
87
|
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_adjustments_from_api(adjustments)
|
91
|
+
adjustments.each do |a|
|
92
|
+
begin
|
93
|
+
adjustment = self.adjustments.build(:amount => a['amount'].to_f,
|
94
|
+
:label => a['label'])
|
95
|
+
adjustment.save!
|
96
|
+
adjustment.finalize!
|
97
|
+
rescue Exception => e
|
98
|
+
raise "#{e.message} #{a}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.ensure_variant_id_from_api(hash)
|
104
|
+
begin
|
105
|
+
unless hash[:variant_id].present?
|
106
|
+
hash[:variant_id] = Spree::Variant.active.find_by_sku!(hash[:sku]).id
|
107
|
+
hash.delete(:sku)
|
108
|
+
end
|
109
|
+
rescue Exception => e
|
110
|
+
raise "#{e.message} #{hash}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.ensure_country_id_from_api(address)
|
115
|
+
return if address.nil? or address[:country_id].present? or address[:country].nil?
|
16
116
|
|
17
|
-
|
117
|
+
begin
|
118
|
+
search = {}
|
119
|
+
if name = address[:country]['name']
|
120
|
+
search[:name] = name
|
121
|
+
elsif iso_name = address[:country]['iso_name']
|
122
|
+
search[:iso_name] = iso_name.upcase
|
123
|
+
elsif iso = address[:country]['iso']
|
124
|
+
search[:iso] = iso.upcase
|
125
|
+
elsif iso3 = address[:country]['iso3']
|
126
|
+
search[:iso3] = iso3.upcase
|
127
|
+
end
|
128
|
+
|
129
|
+
address.delete(:country)
|
130
|
+
address[:country_id] = Spree::Country.where(search).first!.id
|
131
|
+
|
132
|
+
rescue Exception => e
|
133
|
+
raise "#{e.message} #{search}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.ensure_state_id_from_api(address)
|
138
|
+
return if address.nil? or address[:state_id].present? or address[:state].nil?
|
139
|
+
|
140
|
+
begin
|
141
|
+
search = {}
|
142
|
+
if name = address[:state]['name']
|
143
|
+
search[:name] = name
|
144
|
+
elsif abbr = address[:state]['abbr']
|
145
|
+
search[:abbr] = abbr.upcase
|
146
|
+
end
|
147
|
+
|
148
|
+
address.delete(:state)
|
149
|
+
address[:state_id] = Spree::State.where(search).first!.id
|
150
|
+
rescue Exception => e
|
151
|
+
raise "#{e.message} #{search}"
|
152
|
+
end
|
18
153
|
end
|
19
154
|
|
20
155
|
def update_line_items(line_item_params)
|
@@ -22,5 +157,6 @@ Spree::Order.class_eval do
|
|
22
157
|
line_item_params.each do |id, attributes|
|
23
158
|
self.line_items.find(id).update_attributes!(attributes)
|
24
159
|
end
|
160
|
+
self.ensure_updated_shipments
|
25
161
|
end
|
26
162
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
object @address
|
2
|
-
attributes
|
3
|
-
|
4
|
-
:company, :alternative_phone, :country_id, :state_id,
|
5
|
-
:state_name
|
2
|
+
attributes *address_attributes
|
3
|
+
|
6
4
|
child(:country) do |address|
|
7
5
|
attributes *country_attributes
|
8
6
|
end
|
@@ -1,4 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
object false
|
2
|
+
node(:count) { @taxons.count }
|
3
|
+
node(:total_count) { @taxons.total_count }
|
4
|
+
node(:current_page) { params[:page] ? params[:page].to_i : 1 }
|
5
|
+
node(:per_page) { params[:per_page] || Kaminari.config.default_per_page }
|
6
|
+
node(:pages) { @taxons.num_pages }
|
7
|
+
child(@taxons) do
|
8
|
+
attributes *taxon_attributes
|
9
|
+
extends "spree/api/taxons/taxons"
|
10
|
+
end
|
data/config/routes.rb
CHANGED
@@ -18,6 +18,7 @@ Spree::Core::Engine.routes.draw do
|
|
18
18
|
resources :checkouts do
|
19
19
|
member do
|
20
20
|
put :next
|
21
|
+
put :advance
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
@@ -28,6 +29,8 @@ Spree::Core::Engine.routes.draw do
|
|
28
29
|
end
|
29
30
|
|
30
31
|
resources :orders do
|
32
|
+
resources :addresses, :only => [:show, :update]
|
33
|
+
|
31
34
|
resources :return_authorizations do
|
32
35
|
member do
|
33
36
|
put :add
|
@@ -64,7 +67,6 @@ Spree::Core::Engine.routes.draw do
|
|
64
67
|
resources :zones
|
65
68
|
resources :countries, :only => [:index, :show]
|
66
69
|
resources :states, :only => [:index, :show]
|
67
|
-
resources :addresses, :only => [:show, :update]
|
68
70
|
|
69
71
|
resources :taxonomies do
|
70
72
|
member do
|
@@ -7,26 +7,27 @@ module Spree
|
|
7
7
|
before do
|
8
8
|
stub_authentication!
|
9
9
|
@address = create(:address)
|
10
|
+
@order = create(:order, :bill_address => @address)
|
10
11
|
end
|
11
12
|
|
12
13
|
context "with their own address" do
|
13
14
|
before do
|
14
|
-
|
15
|
+
Order.any_instance.stub :user => current_api_user
|
15
16
|
end
|
16
17
|
|
17
18
|
it "gets an address" do
|
18
|
-
api_get :show, :id => @address.id
|
19
|
+
api_get :show, :id => @address.id, :order_id => @order.number
|
19
20
|
json_response['address1'].should eq @address.address1
|
20
21
|
end
|
21
22
|
|
22
23
|
it "updates an address" do
|
23
|
-
api_put :update, :id => @address.id,
|
24
|
+
api_put :update, :id => @address.id, :order_id => @order.number,
|
24
25
|
:address => { :address1 => "123 Test Lane" }
|
25
26
|
json_response['address1'].should eq '123 Test Lane'
|
26
27
|
end
|
27
28
|
|
28
29
|
it "receives the errors object if address is invalid" do
|
29
|
-
api_put :update, :id => @address.id,
|
30
|
+
api_put :update, :id => @address.id, :order_id => @order.number,
|
30
31
|
:address => { :address1 => "" }
|
31
32
|
|
32
33
|
json_response['error'].should_not be_nil
|
@@ -35,18 +36,19 @@ module Spree
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
|
-
context "on
|
39
|
+
context "on an address that does not belong to this order" do
|
39
40
|
before do
|
40
|
-
|
41
|
+
@order.bill_address_id = nil
|
42
|
+
@order.ship_address = nil
|
41
43
|
end
|
42
44
|
|
43
45
|
it "cannot retreive address information" do
|
44
|
-
api_get :show, :id => @address.id
|
46
|
+
api_get :show, :id => @address.id, :order_id => @order.number
|
45
47
|
assert_unauthorized!
|
46
48
|
end
|
47
49
|
|
48
50
|
it "cannot update address information" do
|
49
|
-
api_get :update, :id => @address.id
|
51
|
+
api_get :update, :id => @address.id, :order_id => @order.number
|
50
52
|
assert_unauthorized!
|
51
53
|
end
|
52
54
|
end
|
@@ -66,7 +66,6 @@ module Spree
|
|
66
66
|
api_put :update, :id => order.to_param, :order_token => order.token,
|
67
67
|
:order => { :line_items_attributes => { line_item.id => { :quantity => 1 } } }
|
68
68
|
response.status.should == 200
|
69
|
-
order.reload.state.should eq "address"
|
70
69
|
end
|
71
70
|
|
72
71
|
it "can take line_items as a parameter" do
|
@@ -74,7 +73,6 @@ module Spree
|
|
74
73
|
api_put :update, :id => order.to_param, :order_token => order.token,
|
75
74
|
:order => { :line_items => { line_item.id => { :quantity => 1 } } }
|
76
75
|
response.status.should == 200
|
77
|
-
order.reload.state.should eq "address"
|
78
76
|
end
|
79
77
|
|
80
78
|
it "will return an error if the order cannot transition" do
|
@@ -234,5 +232,18 @@ module Spree
|
|
234
232
|
json_response["errors"]["base"].should include(Spree.t(:no_pending_payments))
|
235
233
|
end
|
236
234
|
end
|
235
|
+
|
236
|
+
context "PUT 'advance'" do
|
237
|
+
let!(:order) { create(:order_with_line_items) }
|
238
|
+
it 'continues to advance advances an order while it can move forward' do
|
239
|
+
Spree::Order.any_instance.should_receive(:next).exactly(3).times.and_return(true, true, false)
|
240
|
+
api_put :advance, :id => order.to_param, :order_token => order.token
|
241
|
+
end
|
242
|
+
it 'returns the order' do
|
243
|
+
api_put :advance, :id => order.to_param, :order_token => order.token
|
244
|
+
json_response['id'].should == order.id
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
237
248
|
end
|
238
249
|
end
|
@@ -79,7 +79,7 @@ module Spree
|
|
79
79
|
# Regression test for #3404
|
80
80
|
it "can specify additional parameters for a line item" do
|
81
81
|
variant = create(:variant)
|
82
|
-
Order.should_receive(:create).and_return(order = Spree::Order.new)
|
82
|
+
Order.should_receive(:create!).and_return(order = Spree::Order.new)
|
83
83
|
order.stub(:associate_user!)
|
84
84
|
order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
|
85
85
|
line_item.should_receive(:update_attributes).with("special" => true)
|
@@ -96,7 +96,7 @@ module Spree
|
|
96
96
|
# Regression test for #3404
|
97
97
|
it "does not update line item needlessly" do
|
98
98
|
variant = create(:variant)
|
99
|
-
Order.should_receive(:create).and_return(order = Spree::Order.new)
|
99
|
+
Order.should_receive(:create!).and_return(order = Spree::Order.new)
|
100
100
|
order.stub(:associate_user!)
|
101
101
|
order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
|
102
102
|
line_item.should_not_receive(:update_attributes)
|
@@ -156,7 +156,8 @@ module Spree
|
|
156
156
|
let!(:payment_method) { create(:payment_method) }
|
157
157
|
|
158
158
|
it "can add line items" do
|
159
|
-
api_put :update, :id => order.to_param, :order => {
|
159
|
+
api_put :update, :id => order.to_param, :order => {
|
160
|
+
:line_items_attributes => [{:variant_id => create(:variant).id, :quantity => 2}] }
|
160
161
|
|
161
162
|
response.status.should == 200
|
162
163
|
json_response['item_total'].to_f.should_not == order.item_total.to_f
|
@@ -165,6 +166,18 @@ module Spree
|
|
165
166
|
json_response['line_items'].last['quantity'].should == 2
|
166
167
|
end
|
167
168
|
|
169
|
+
it "updates quantities of existing line items" do
|
170
|
+
api_put :update, :id => order.to_param, :order => {
|
171
|
+
:line_items => {
|
172
|
+
line_item.id => { :quantity => 10 }
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
response.status.should == 200
|
177
|
+
json_response['line_items'].count.should == 1
|
178
|
+
json_response['line_items'].first['quantity'].should == 10
|
179
|
+
end
|
180
|
+
|
168
181
|
it "can add billing address" do
|
169
182
|
api_put :update, :id => order.to_param, :order => { :bill_address_attributes => billing_address }
|
170
183
|
|
@@ -201,6 +214,20 @@ module Spree
|
|
201
214
|
json_response['errors']['ship_address.firstname'].first.should eq "can't be blank"
|
202
215
|
end
|
203
216
|
|
217
|
+
context "order has shipments" do
|
218
|
+
before { order.create_proposed_shipments }
|
219
|
+
|
220
|
+
it "clears out all existing shipments on line item udpate" do
|
221
|
+
previous_shipments = order.shipments
|
222
|
+
api_put :update, :id => order.to_param, :order => {
|
223
|
+
:line_items => {
|
224
|
+
line_item.id => { :quantity => 10 }
|
225
|
+
}
|
226
|
+
}
|
227
|
+
expect(order.reload.shipments).to be_empty
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
204
231
|
context "with a line item" do
|
205
232
|
before do
|
206
233
|
create(:line_item, :order => order)
|
@@ -49,7 +49,9 @@ module Spree
|
|
49
49
|
|
50
50
|
it 'can create a new stock item' do
|
51
51
|
variant = create(:variant)
|
52
|
-
variant.
|
52
|
+
# Creating a variant also creates stock items.
|
53
|
+
# We don't want any to exist (as they would conflict with what we're about to create)
|
54
|
+
StockItem.delete_all
|
53
55
|
params = {
|
54
56
|
stock_location_id: stock_location.to_param,
|
55
57
|
stock_item: {
|
@@ -77,10 +79,26 @@ module Spree
|
|
77
79
|
json_response['count_on_hand'].should eq 50
|
78
80
|
end
|
79
81
|
|
82
|
+
it 'can set a stock item to modify the current inventory' do
|
83
|
+
stock_item.count_on_hand.should == 10
|
84
|
+
|
85
|
+
params = {
|
86
|
+
id: stock_item.to_param,
|
87
|
+
stock_item: {
|
88
|
+
count_on_hand: 40,
|
89
|
+
force: true,
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
api_put :update, params
|
94
|
+
response.status.should == 200
|
95
|
+
json_response['count_on_hand'].should eq 40
|
96
|
+
end
|
97
|
+
|
80
98
|
it 'can delete a stock item' do
|
81
99
|
api_delete :destroy, id: stock_item.to_param
|
82
100
|
response.status.should == 204
|
83
|
-
lambda { stock_item.
|
101
|
+
lambda { Spree::StockItem.find(stock_item.id) }.should raise_error(ActiveRecord::RecordNotFound)
|
84
102
|
end
|
85
103
|
end
|
86
104
|
end
|
@@ -20,18 +20,30 @@ module Spree
|
|
20
20
|
it "gets all taxons for a taxonomy" do
|
21
21
|
api_get :index, :taxonomy_id => taxonomy.id
|
22
22
|
|
23
|
-
json_response.first['name'].should eq taxon.name
|
24
|
-
children = json_response.first['taxons']
|
23
|
+
json_response['taxons'].first['name'].should eq taxon.name
|
24
|
+
children = json_response['taxons'].first['taxons']
|
25
25
|
children.count.should eq 1
|
26
26
|
children.first['name'].should eq taxon2.name
|
27
27
|
children.first['taxons'].count.should eq 1
|
28
28
|
end
|
29
29
|
|
30
|
+
it "paginates through taxons" do
|
31
|
+
new_taxon = create(:taxon, :name => "Go", :taxonomy => taxonomy)
|
32
|
+
taxonomy.root.children << new_taxon
|
33
|
+
expect(taxonomy.root.children.count).to eql(2)
|
34
|
+
api_get :index, :taxonomy_id => taxonomy.id, :page => 1, :per_page => 1
|
35
|
+
expect(json_response["count"]).to eql(1)
|
36
|
+
expect(json_response["total_count"]).to eql(2)
|
37
|
+
expect(json_response["current_page"]).to eql(1)
|
38
|
+
expect(json_response["per_page"]).to eql(1)
|
39
|
+
expect(json_response["pages"]).to eql(2)
|
40
|
+
end
|
41
|
+
|
30
42
|
it "gets all taxons" do
|
31
43
|
api_get :index
|
32
44
|
|
33
|
-
json_response.first['name'].should eq taxonomy.root.name
|
34
|
-
children = json_response.first['taxons']
|
45
|
+
json_response['taxons'].first['name'].should eq taxonomy.root.name
|
46
|
+
children = json_response['taxons'].first['taxons']
|
35
47
|
children.count.should eq 1
|
36
48
|
children.first['name'].should eq taxon.name
|
37
49
|
children.first['taxons'].count.should eq 1
|
@@ -40,8 +52,8 @@ module Spree
|
|
40
52
|
it "can search for a single taxon" do
|
41
53
|
api_get :index, :q => { :name_cont => "Ruby" }
|
42
54
|
|
43
|
-
json_response.count.should == 1
|
44
|
-
json_response.first['name'].should eq "Ruby"
|
55
|
+
json_response['taxons'].count.should == 1
|
56
|
+
json_response['taxons'].first['name'].should eq "Ruby"
|
45
57
|
end
|
46
58
|
|
47
59
|
it "gets a single taxon" do
|
@@ -2,17 +2,247 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
describe Order do
|
5
|
-
let(:
|
6
|
-
let(:
|
5
|
+
let!(:country) { FactoryGirl.create(:country) }
|
6
|
+
let!(:state) { country.states.first || FactoryGirl.create(:state, :country => country) }
|
7
|
+
let!(:stock_location) { FactoryGirl.create(:stock_location) }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
let(:user) { stub_model(LegacyUser, :email => 'fox@mudler.com') }
|
10
|
+
let(:shipping_method) { create(:shipping_method) }
|
11
|
+
let(:payment_method) { create(:payment_method) }
|
12
|
+
let(:product) { product = Spree::Product.create(:name => 'Test',
|
13
|
+
:sku => 'TEST-1',
|
14
|
+
:price => 33.22)
|
15
|
+
product.shipping_category = FactoryGirl.create(:shipping_category)
|
16
|
+
product.save
|
17
|
+
product }
|
18
|
+
let(:variant) { variant = product.master
|
19
|
+
variant.stock_items.each { |si| si.update_attribute(:count_on_hand, 10) }
|
20
|
+
variant }
|
21
|
+
let(:sku) { variant.sku }
|
22
|
+
let(:variant_id) { variant.id }
|
11
23
|
|
24
|
+
let(:line_items) {{ "0" => { :variant_id => variant.id, :quantity => 5 }}}
|
25
|
+
let(:ship_address) {{
|
26
|
+
:address1 => '123 Testable Way',
|
27
|
+
:firstname => 'Fox',
|
28
|
+
:lastname => 'Mulder',
|
29
|
+
:city => 'Washington',
|
30
|
+
:country_id => country.id,
|
31
|
+
:state_id => state.id,
|
32
|
+
:zipcode => '666',
|
33
|
+
:phone => '666-666-6666'
|
34
|
+
}}
|
35
|
+
|
36
|
+
it 'can import an order number' do
|
37
|
+
params = { number: '123-456-789' }
|
38
|
+
order = Order.build_from_api(user, params)
|
39
|
+
order.number.should eq '123-456-789'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'optionally add completed at' do
|
43
|
+
params = { email: 'test@test.com',
|
44
|
+
completed_at: Time.now,
|
45
|
+
line_items_attributes: line_items }
|
46
|
+
|
47
|
+
order = Order.build_from_api(user, params)
|
48
|
+
order.should be_completed
|
49
|
+
order.state.should eq 'complete'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'can build an order from API with just line items' do
|
53
|
+
params = { :line_items_attributes => line_items }
|
54
|
+
|
55
|
+
Order.should_receive(:ensure_variant_id_from_api)
|
56
|
+
order = Order.build_from_api(user, params)
|
12
57
|
order.user.should == nil
|
13
58
|
line_item = order.line_items.first
|
14
59
|
line_item.quantity.should == 5
|
15
60
|
line_item.variant_id.should == variant_id
|
16
61
|
end
|
62
|
+
|
63
|
+
it 'handles line_item building exceptions' do
|
64
|
+
line_items['0'][:variant_id] = 'XXX'
|
65
|
+
params = { :line_items_attributes => line_items }
|
66
|
+
|
67
|
+
expect {
|
68
|
+
order = Order.build_from_api(user, params)
|
69
|
+
}.to raise_error /XXX/
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'can build an order from API with variant sku' do
|
73
|
+
params = { :line_items_attributes => {
|
74
|
+
"0" => { :sku => sku, :quantity => 5 } }}
|
75
|
+
|
76
|
+
order = Order.build_from_api(user, params)
|
77
|
+
|
78
|
+
line_item = order.line_items.first
|
79
|
+
line_item.variant_id.should == variant_id
|
80
|
+
line_item.quantity.should == 5
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'handles exceptions when sku is not found' do
|
84
|
+
params = { :line_items_attributes => {
|
85
|
+
"0" => { :sku => 'XXX', :quantity => 5 } }}
|
86
|
+
expect {
|
87
|
+
order = Order.build_from_api(user, params)
|
88
|
+
}.to raise_error /XXX/
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'can build an order from API shipping address' do
|
92
|
+
params = { :ship_address_attributes => ship_address,
|
93
|
+
:line_items_attributes => line_items }
|
94
|
+
|
95
|
+
order = Order.build_from_api(user, params)
|
96
|
+
order.ship_address.address1.should eq '123 Testable Way'
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'can build an order from API with country attributes' do
|
100
|
+
ship_address.delete(:country_id)
|
101
|
+
ship_address[:country] = { 'iso' => 'US' }
|
102
|
+
params = { :ship_address_attributes => ship_address,
|
103
|
+
:line_items_attributes => line_items }
|
104
|
+
|
105
|
+
order = Order.build_from_api(user, params)
|
106
|
+
order.ship_address.country.iso.should eq 'US'
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'handles country lookup exceptions' do
|
110
|
+
ship_address.delete(:country_id)
|
111
|
+
ship_address[:country] = { 'iso' => 'XXX' }
|
112
|
+
params = { :ship_address_attributes => ship_address,
|
113
|
+
:line_items_attributes => line_items }
|
114
|
+
|
115
|
+
expect {
|
116
|
+
order = Order.build_from_api(user, params)
|
117
|
+
}.to raise_error /XXX/
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'can build an order from API with state attributes' do
|
121
|
+
ship_address.delete(:state_id)
|
122
|
+
ship_address[:state] = { 'name' => 'Alabama' }
|
123
|
+
params = { :ship_address_attributes => ship_address,
|
124
|
+
:line_items_attributes => line_items }
|
125
|
+
|
126
|
+
order = Order.build_from_api(user, params)
|
127
|
+
order.ship_address.state.name.should eq 'Alabama'
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'handles state lookup exceptions' do
|
131
|
+
ship_address.delete(:state_id)
|
132
|
+
ship_address[:state] = { 'name' => 'XXX' }
|
133
|
+
params = { :ship_address_attributes => ship_address,
|
134
|
+
:line_items_attributes => line_items }
|
135
|
+
|
136
|
+
expect {
|
137
|
+
order = Order.build_from_api(user, params)
|
138
|
+
}.to raise_error /XXX/
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'variant not deleted' do
|
142
|
+
it 'ensures variant id from api' do
|
143
|
+
hash = { sku: variant.sku }
|
144
|
+
Order.ensure_variant_id_from_api(hash)
|
145
|
+
expect(hash[:variant_id]).to eq variant.id
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'variant was deleted' do
|
150
|
+
it 'raise error as variant shouldnt be found' do
|
151
|
+
variant.product.destroy
|
152
|
+
hash = { sku: variant.sku }
|
153
|
+
expect {
|
154
|
+
Order.ensure_variant_id_from_api(hash)
|
155
|
+
}.to raise_error
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'ensures_country_id for country fields' do
|
160
|
+
[:name, :iso, :iso_name, :iso3].each do |field|
|
161
|
+
address = { :country => { field => country.send(field) }}
|
162
|
+
Order.ensure_country_id_from_api(address)
|
163
|
+
address[:country_id].should eq country.id
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'ensures_state_id for state fields' do
|
168
|
+
[:name, :abbr].each do |field|
|
169
|
+
address = { :state => { field => state.send(field) }}
|
170
|
+
Order.ensure_state_id_from_api(address)
|
171
|
+
address[:state_id].should eq state.id
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "shippments" do
|
176
|
+
let(:params) do
|
177
|
+
{ :shipments_attributes => [
|
178
|
+
{ :tracking => '123456789',
|
179
|
+
:cost => '4.99',
|
180
|
+
:shipping_method => shipping_method.name,
|
181
|
+
:inventory_units => [{ :sku => sku }]
|
182
|
+
}
|
183
|
+
] }
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'ensures variant exists and is not deleted' do
|
187
|
+
Order.should_receive(:ensure_variant_id_from_api)
|
188
|
+
order = Order.build_from_api(user, params)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'builds them properly' do
|
192
|
+
order = Order.build_from_api(user, params)
|
193
|
+
|
194
|
+
shipment = order.shipments.first
|
195
|
+
shipment.inventory_units.first.variant_id.should eq product.master.id
|
196
|
+
shipment.tracking.should eq '123456789'
|
197
|
+
shipment.shipping_rates.first.cost.should eq 4.99
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'handles shipment building exceptions' do
|
202
|
+
params = { :shipments_attributes => [{ tracking: '123456789',
|
203
|
+
cost: '4.99',
|
204
|
+
shipping_method: 'XXX',
|
205
|
+
inventory_units: [{ sku: sku }]
|
206
|
+
}] }
|
207
|
+
expect {
|
208
|
+
order = Order.build_from_api(user, params)
|
209
|
+
}.to raise_error /XXX/
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'adds adjustments' do
|
213
|
+
params = { :adjustments_attributes => [
|
214
|
+
{ "label" => "Shipping Discount", "amount" => "-4.99" },
|
215
|
+
{ "label" => "Promotion Discount", "amount" => "-3.00" }] }
|
216
|
+
|
217
|
+
order = Order.build_from_api(user, params)
|
218
|
+
order.adjustments.all?(&:finalized?).should be_true
|
219
|
+
order.adjustments.first.label.should eq 'Shipping Discount'
|
220
|
+
order.adjustments.first.amount.should eq -4.99
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'handles adjustment building exceptions' do
|
224
|
+
params = { :adjustments_attributes => [
|
225
|
+
{ "amount" => "XXX" },
|
226
|
+
{ "label" => "Promotion Discount", "amount" => "-3.00" }] }
|
227
|
+
|
228
|
+
expect {
|
229
|
+
order = Order.build_from_api(user, params)
|
230
|
+
}.to raise_error /XXX/
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'builds a payment' do
|
234
|
+
params = { :payments_attributes => [{ amount: '4.99',
|
235
|
+
payment_method: payment_method.name }] }
|
236
|
+
order = Order.build_from_api(user, params)
|
237
|
+
order.payments.first.amount.should eq 4.99
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'handles payment building exceptions' do
|
241
|
+
params = { :payments_attributes => [{ amount: '4.99',
|
242
|
+
payment_method: 'XXX' }] }
|
243
|
+
expect {
|
244
|
+
order = Order.build_from_api(user, params)
|
245
|
+
}.to raise_error /XXX/
|
246
|
+
end
|
17
247
|
end
|
18
248
|
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: 2.0.
|
4
|
+
version: 2.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Bigg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-16 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: 2.0.
|
19
|
+
version: 2.0.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.0.
|
26
|
+
version: 2.0.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rabl
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -244,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
244
244
|
version: '0'
|
245
245
|
requirements: []
|
246
246
|
rubyforge_project:
|
247
|
-
rubygems_version: 2.
|
247
|
+
rubygems_version: 2.1.0
|
248
248
|
signing_key:
|
249
249
|
specification_version: 4
|
250
250
|
summary: Spree's API
|