spree_api 2.0.5 → 2.0.6
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/CHANGELOG.md +6 -0
- data/app/controllers/spree/api/countries_controller.rb +2 -0
- data/app/controllers/spree/api/orders_controller.rb +16 -2
- data/app/controllers/spree/api/payments_controller.rb +13 -2
- data/app/controllers/spree/api/states_controller.rb +2 -0
- data/app/controllers/spree/api/stock_items_controller.rb +4 -1
- data/app/controllers/spree/api/stock_locations_controller.rb +3 -1
- data/app/controllers/spree/api/stock_movements_controller.rb +2 -0
- data/app/helpers/spree/api/api_helpers.rb +2 -3
- data/app/models/spree/line_item_decorator.rb +1 -1
- data/app/models/spree/option_value_decorator.rb +4 -0
- data/app/models/spree/order_decorator.rb +27 -20
- data/app/views/spree/api/payments/credit_over_limit.v1.rabl +1 -1
- data/app/views/spree/api/payments/new.v1.rabl +0 -1
- data/app/views/spree/api/payments/update_forbidden.v1.rabl +2 -0
- data/config/locales/en.yml +3 -1
- data/spec/controllers/spree/api/orders_controller_spec.rb +22 -35
- data/spec/controllers/spree/api/payments_controller_spec.rb +123 -74
- data/spec/controllers/spree/api/stock_items_controller_spec.rb +62 -26
- data/spec/controllers/spree/api/stock_locations_controller_spec.rb +56 -29
- data/spec/controllers/spree/api/stock_movements_controller_spec.rb +51 -27
- data/spec/models/spree/order_spec.rb +81 -12
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cb2106c19046c8db51461b87b224d461e21fec1
|
4
|
+
data.tar.gz: e6acefe01a95c4b55e83b2ea0d651d7c205cf30f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f93f7762a47e706f13da9958f4d3993c9a69662cace7a8f68e3b47ee066e3df5a054309265d9a11bd59db7a5bb0c6df1cce8c3e5562617921317cc618b616578
|
7
|
+
data.tar.gz: 5da0e8c9a2b8960985e22049190a677d7415bbedf3e03d29b47a66a68c7707152df13a5336fa2433628d10337078f6a647893ec19c28f260defa7c10387710ef
|
data/CHANGELOG.md
CHANGED
@@ -17,6 +17,7 @@ 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
|
@@ -26,7 +27,7 @@ module Spree
|
|
26
27
|
# Parsing line items through as an update_attributes call in the API will result in
|
27
28
|
# many line items for the same variant_id being created. We must be smarter about this,
|
28
29
|
# hence the use of the update_line_items method, defined within order_decorator.rb.
|
29
|
-
line_items_params =
|
30
|
+
line_items_params = sanitize_line_items(nested_params.delete("line_items_attributes"))
|
30
31
|
if order.update_attributes(nested_params)
|
31
32
|
order.update_line_items(line_items_params)
|
32
33
|
order.line_items.reload
|
@@ -51,7 +52,20 @@ module Spree
|
|
51
52
|
private
|
52
53
|
|
53
54
|
def nested_params
|
54
|
-
map_nested_attributes_keys
|
55
|
+
@nested_params ||= map_nested_attributes_keys(Order, params[:order] || {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def sanitize_line_items(line_item_attributes)
|
59
|
+
return {} if line_item_attributes.blank?
|
60
|
+
line_item_attributes = line_item_attributes.map do |id, attributes|
|
61
|
+
# Faux Strong-Parameters code to strip price if user isn't an admin
|
62
|
+
if current_api_user.has_spree_role?("admin")
|
63
|
+
[id, attributes.slice(*Spree::LineItem.attr_accessible[:api])]
|
64
|
+
else
|
65
|
+
[id, attributes.slice(*Spree::LineItem.attr_accessible[:default])]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
line_item_attributes = Hash[line_item_attributes].delete_if { |k,v| v.empty? }
|
55
69
|
end
|
56
70
|
|
57
71
|
def order
|
@@ -4,7 +4,7 @@ module Spree
|
|
4
4
|
respond_to :json
|
5
5
|
|
6
6
|
before_filter :find_order
|
7
|
-
before_filter :find_payment, :
|
7
|
+
before_filter :find_payment, only: [:update, :show, :authorize, :purchase, :capture, :void, :credit]
|
8
8
|
|
9
9
|
def index
|
10
10
|
@payments = @order.payments.ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
|
@@ -25,6 +25,17 @@ module Spree
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
def update
|
29
|
+
authorize! params[:action], @payment
|
30
|
+
if !@payment.pending?
|
31
|
+
render 'update_forbidden', status: 403
|
32
|
+
elsif @payment.update_attributes(params[:payment])
|
33
|
+
respond_with(@payment, default_template: :show)
|
34
|
+
else
|
35
|
+
invalid_resource!(@payment)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
28
39
|
def show
|
29
40
|
respond_with(@payment)
|
30
41
|
end
|
@@ -47,7 +58,7 @@ module Spree
|
|
47
58
|
|
48
59
|
def credit
|
49
60
|
if params[:amount].to_f > @payment.credit_allowed
|
50
|
-
render
|
61
|
+
render 'credit_over_limit', status: 422
|
51
62
|
else
|
52
63
|
perform_payment_action(:credit, params[:amount])
|
53
64
|
end
|
@@ -4,11 +4,13 @@ module Spree
|
|
4
4
|
before_filter :stock_location, except: [:update, :destroy]
|
5
5
|
|
6
6
|
def index
|
7
|
+
authorize! :read, StockItem
|
7
8
|
@stock_items = scope.ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
|
8
9
|
respond_with(@stock_items)
|
9
10
|
end
|
10
11
|
|
11
12
|
def show
|
13
|
+
authorize! :read, StockItem
|
12
14
|
@stock_item = scope.find(params[:id])
|
13
15
|
respond_with(@stock_item)
|
14
16
|
end
|
@@ -66,7 +68,8 @@ module Spree
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def scope
|
69
|
-
|
71
|
+
includes = {:variant => [{ :option_values => :option_type }, :product] }
|
72
|
+
@stock_location.stock_items.includes(includes)
|
70
73
|
end
|
71
74
|
end
|
72
75
|
end
|
@@ -2,11 +2,13 @@ module Spree
|
|
2
2
|
module Api
|
3
3
|
class StockLocationsController < Spree::Api::BaseController
|
4
4
|
def index
|
5
|
-
|
5
|
+
authorize! :read, StockLocation
|
6
|
+
@stock_locations = StockLocation.accessible_by(current_ability, :read).order('name ASC').ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
|
6
7
|
respond_with(@stock_locations)
|
7
8
|
end
|
8
9
|
|
9
10
|
def show
|
11
|
+
authorize! :read, StockLocation
|
10
12
|
respond_with(stock_location)
|
11
13
|
end
|
12
14
|
|
@@ -4,11 +4,13 @@ module Spree
|
|
4
4
|
before_filter :stock_location, except: [:update, :destroy]
|
5
5
|
|
6
6
|
def index
|
7
|
+
authorize! :read, StockMovement
|
7
8
|
@stock_movements = scope.ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
|
8
9
|
respond_with(@stock_movements)
|
9
10
|
end
|
10
11
|
|
11
12
|
def show
|
13
|
+
authorize! :read, StockMovement
|
12
14
|
@stock_movement = scope.find(params[:id])
|
13
15
|
respond_with(@stock_movement)
|
14
16
|
end
|
@@ -28,7 +28,7 @@ module Spree
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def option_value_attributes
|
31
|
-
[:id, :name, :presentation, :option_type_name, :option_type_id]
|
31
|
+
[:id, :name, :presentation, :option_type_name, :option_type_id, :option_type_presentation]
|
32
32
|
end
|
33
33
|
|
34
34
|
def order_attributes
|
@@ -44,7 +44,7 @@ module Spree
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def payment_attributes
|
47
|
-
[:id, :source_type, :source_id, :amount, :payment_method_id, :response_code, :state, :avs_response, :created_at, :updated_at]
|
47
|
+
[:id, :source_type, :source_id, :amount, :display_amount, :payment_method_id, :response_code, :state, :avs_response, :created_at, :updated_at]
|
48
48
|
end
|
49
49
|
|
50
50
|
def payment_method_attributes
|
@@ -113,4 +113,3 @@ module Spree
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
@@ -1,28 +1,34 @@
|
|
1
1
|
Spree::Order.class_eval do
|
2
2
|
def self.build_from_api(user, params)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
8
|
|
9
|
-
|
10
|
-
|
9
|
+
order = create!
|
10
|
+
order.associate_user!(user)
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
order.create_shipments_from_api params.delete(:shipments_attributes) || []
|
13
|
+
order.create_line_items_from_api params.delete(:line_items_attributes) || {}
|
14
|
+
order.create_adjustments_from_api params.delete(:adjustments_attributes) || []
|
15
|
+
order.create_payments_from_api params.delete(:payments_attributes) || []
|
16
|
+
order.complete_from_api params.delete(:completed_at)
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
destroy_automatic_taxes_on_import(order, params)
|
19
|
+
order.update_attributes!(params)
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
order.reload
|
22
|
+
rescue Exception => e
|
23
|
+
order.destroy if order && order.persisted?
|
24
|
+
raise e.message
|
25
|
+
end
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
def self.destroy_automatic_taxes_on_import(order, params)
|
29
|
+
if params.delete :import
|
30
|
+
order.adjustments.tax.destroy_all
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
def complete_from_api(completed_at)
|
@@ -37,6 +43,7 @@ Spree::Order.class_eval do
|
|
37
43
|
begin
|
38
44
|
shipment = shipments.build
|
39
45
|
shipment.tracking = s[:tracking]
|
46
|
+
shipment.stock_location = Spree::StockLocation.find_by_name!(s[:stock_location])
|
40
47
|
|
41
48
|
inventory_units = s[:inventory_units] || []
|
42
49
|
inventory_units.each do |iu|
|
@@ -80,7 +87,7 @@ Spree::Order.class_eval do
|
|
80
87
|
|
81
88
|
extra_params = line_item.except(:variant_id, :quantity)
|
82
89
|
line_item = self.contents.add(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
|
83
|
-
line_item.update_attributes(extra_params) unless extra_params.empty?
|
90
|
+
line_item.update_attributes(extra_params, as: :api) unless extra_params.empty?
|
84
91
|
rescue Exception => e
|
85
92
|
raise "#{e.message} #{line_item}"
|
86
93
|
end
|
@@ -155,7 +162,7 @@ Spree::Order.class_eval do
|
|
155
162
|
def update_line_items(line_item_params)
|
156
163
|
return if line_item_params.blank?
|
157
164
|
line_item_params.each do |id, attributes|
|
158
|
-
self.line_items.find(id).update_attributes!(attributes)
|
165
|
+
self.line_items.find(id).update_attributes!(attributes, :as => :api)
|
159
166
|
end
|
160
167
|
self.ensure_updated_shipments
|
161
168
|
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
object false
|
2
|
-
node(:error) { I18n.t(:credit_over_limit, :limit => @payment.credit_allowed, :scope => 'spree.api') }
|
2
|
+
node(:error) { I18n.t(:credit_over_limit, :limit => @payment.credit_allowed, :scope => 'spree.api.payment') }
|
data/config/locales/en.yml
CHANGED
@@ -7,7 +7,6 @@ en:
|
|
7
7
|
invalid_resource: "Invalid resource. Please fix errors and try again."
|
8
8
|
resource_not_found: "The resource you were looking for could not be found."
|
9
9
|
gateway_error: "There was a problem with the payment gateway: %{text}"
|
10
|
-
credit_over_limit: "This payment can only be credited up to %{limit}. Please specify an amount less than or equal to this number."
|
11
10
|
access: "API Access"
|
12
11
|
key: "Key"
|
13
12
|
clear_key: "Clear key"
|
@@ -19,6 +18,9 @@ en:
|
|
19
18
|
order:
|
20
19
|
could_not_transition: "The order could not be transitioned. Please fix the errors and try again."
|
21
20
|
invalid_shipping_method: "Invalid shipping method specified."
|
21
|
+
payment:
|
22
|
+
credit_over_limit: "This payment can only be credited up to %{limit}. Please specify an amount less than or equal to this number."
|
23
|
+
update_forbidden: "This payment cannot be updated because it is %{state}."
|
22
24
|
shipment:
|
23
25
|
cannot_ready: "Cannot ready shipment."
|
24
26
|
stock_location_required: "A stock_location_id parameter must be provided in order to retrieve stock movements."
|
@@ -76,37 +76,23 @@ module Spree
|
|
76
76
|
json_response["user_id"].should == current_api_user.id
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
|
-
it "can specify additional parameters for a line item" do
|
79
|
+
it "cannot create an order with an abitrary price for the line item" do
|
81
80
|
variant = create(:variant)
|
82
|
-
|
83
|
-
order.stub(:associate_user!)
|
84
|
-
order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
|
85
|
-
line_item.should_receive(:update_attributes).with("special" => true)
|
86
|
-
api_post :create, :order => {
|
81
|
+
api_post :create, :order => {
|
87
82
|
:line_items => {
|
88
83
|
"0" => {
|
89
|
-
:variant_id => variant.to_param,
|
84
|
+
:variant_id => variant.to_param,
|
85
|
+
:quantity => 5,
|
86
|
+
:price => 0.44
|
90
87
|
}
|
91
88
|
}
|
92
89
|
}
|
93
90
|
response.status.should == 201
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
Order.should_receive(:create!).and_return(order = Spree::Order.new)
|
100
|
-
order.stub(:associate_user!)
|
101
|
-
order.stub_chain(:contents, :add).and_return(line_item = double('LineItem'))
|
102
|
-
line_item.should_not_receive(:update_attributes)
|
103
|
-
api_post :create, :order => {
|
104
|
-
:line_items => {
|
105
|
-
"0" => {
|
106
|
-
:variant_id => variant.to_param, :quantity => 5
|
107
|
-
}
|
108
|
-
}
|
109
|
-
}
|
91
|
+
order = Order.last
|
92
|
+
order.line_items.count.should == 1
|
93
|
+
order.line_items.first.variant.should == variant
|
94
|
+
order.line_items.first.quantity.should == 5
|
95
|
+
order.line_items.first.price.should == order.line_items.first.variant.price
|
110
96
|
end
|
111
97
|
end
|
112
98
|
|
@@ -155,17 +141,6 @@ module Spree
|
|
155
141
|
:country_id => Country.first.id, :state_id => State.first.id} }
|
156
142
|
let!(:payment_method) { create(:payment_method) }
|
157
143
|
|
158
|
-
it "can add line items" do
|
159
|
-
api_put :update, :id => order.to_param, :order => {
|
160
|
-
:line_items_attributes => [{:variant_id => create(:variant).id, :quantity => 2}] }
|
161
|
-
|
162
|
-
response.status.should == 200
|
163
|
-
json_response['item_total'].to_f.should_not == order.item_total.to_f
|
164
|
-
json_response['line_items'].count.should == 2
|
165
|
-
json_response['line_items'].first['quantity'].should == 1
|
166
|
-
json_response['line_items'].last['quantity'].should == 2
|
167
|
-
end
|
168
|
-
|
169
144
|
it "updates quantities of existing line items" do
|
170
145
|
api_put :update, :id => order.to_param, :order => {
|
171
146
|
:line_items => {
|
@@ -178,6 +153,18 @@ module Spree
|
|
178
153
|
json_response['line_items'].first['quantity'].should == 10
|
179
154
|
end
|
180
155
|
|
156
|
+
it "cannot set a price for a line item" do
|
157
|
+
variant = create(:variant)
|
158
|
+
api_put :update, :id => order.to_param, :order => {
|
159
|
+
:line_items_attributes => { order.line_items.first.id =>
|
160
|
+
{ :variant_id => variant.id, :quantity => 2, :price => 0.44}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
response.status.should == 200
|
164
|
+
json_response['line_items'].count.should == 1
|
165
|
+
expect(json_response['line_items'].first['price']).to eq(variant.price.to_s)
|
166
|
+
end
|
167
|
+
|
181
168
|
it "can add billing address" do
|
182
169
|
api_put :update, :id => order.to_param, :order => { :bill_address_attributes => billing_address }
|
183
170
|
|
@@ -5,11 +5,12 @@ module Spree
|
|
5
5
|
render_views
|
6
6
|
let!(:order) { create(:order) }
|
7
7
|
let!(:payment) { create(:payment, :order => order) }
|
8
|
-
let!(:attributes) { [:id, :source_type, :source_id, :amount,
|
8
|
+
let!(:attributes) { [:id, :source_type, :source_id, :amount, :display_amount,
|
9
9
|
:payment_method_id, :response_code, :state, :avs_response,
|
10
10
|
:created_at, :updated_at] }
|
11
11
|
|
12
12
|
let(:resource_scoping) { { :order_id => order.to_param } }
|
13
|
+
|
13
14
|
before do
|
14
15
|
stub_authentication!
|
15
16
|
end
|
@@ -43,6 +44,11 @@ module Spree
|
|
43
44
|
json_response.should have_attributes(attributes)
|
44
45
|
end
|
45
46
|
|
47
|
+
it "cannot update a payment" do
|
48
|
+
api_put :update, :id => payment.to_param, :payment => { :amount => 2.01 }
|
49
|
+
assert_unauthorized!
|
50
|
+
end
|
51
|
+
|
46
52
|
it "cannot authorize a payment" do
|
47
53
|
api_put :authorize, :id => payment.to_param
|
48
54
|
assert_unauthorized!
|
@@ -93,76 +99,120 @@ module Spree
|
|
93
99
|
end
|
94
100
|
|
95
101
|
context "for a given payment" do
|
102
|
+
context "updating" do
|
103
|
+
it "can update" do
|
104
|
+
payment.update_column(:state, 'pending')
|
105
|
+
api_put :update, :id => payment.to_param, :payment => { :amount => 2.01 }
|
106
|
+
response.status.should == 200
|
107
|
+
payment.reload.amount.should == 2.01
|
108
|
+
end
|
96
109
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
110
|
+
context "update fails" do
|
111
|
+
it "returns a 422 status when the amount is invalid" do
|
112
|
+
payment.update_column(:state, 'pending')
|
113
|
+
api_put :update, :id => payment.to_param, :payment => { :amount => 'invalid' }
|
114
|
+
response.status.should == 422
|
115
|
+
json_response["error"].should == "Invalid resource. Please fix errors and try again."
|
116
|
+
end
|
117
|
+
|
118
|
+
it "returns a 403 status when the payment is not pending" do
|
119
|
+
payment.update_column(:state, 'complete')
|
120
|
+
api_put :update, :id => payment.to_param, :payment => { :amount => 2.01 }
|
121
|
+
response.status.should == 403
|
122
|
+
json_response["error"].should == "This payment cannot be updated because it is complete."
|
123
|
+
end
|
124
|
+
end
|
102
125
|
end
|
103
126
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
payment.reload
|
111
|
-
payment.state.should == "failed"
|
112
|
-
end
|
127
|
+
context "authorizing" do
|
128
|
+
it "can authorize" do
|
129
|
+
api_put :authorize, :id => payment.to_param
|
130
|
+
response.status.should == 200
|
131
|
+
payment.reload.state.should == "pending"
|
132
|
+
end
|
113
133
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
134
|
+
context "authorization fails" do
|
135
|
+
before do
|
136
|
+
fake_response = double(:success? => false, :to_s => "Could not authorize card")
|
137
|
+
Spree::Gateway::Bogus.any_instance.should_receive(:authorize).and_return(fake_response)
|
138
|
+
api_put :authorize, :id => payment.to_param
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns a 422 status" do
|
142
|
+
response.status.should == 422
|
143
|
+
json_response["error"].should == "There was a problem with the payment gateway: Could not authorize card"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "does not raise a stack level error" do
|
147
|
+
pending "Investigate why a payment.reload after the request raises 'stack level too deep'"
|
148
|
+
payment.reload.state.should == "failed"
|
149
|
+
end
|
150
|
+
end
|
119
151
|
end
|
120
152
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
payment.reload
|
129
|
-
payment.state.should == "failed"
|
130
|
-
end
|
153
|
+
context "capturing" do
|
154
|
+
it "can capture" do
|
155
|
+
api_put :capture, :id => payment.to_param
|
156
|
+
response.status.should == 200
|
157
|
+
payment.reload.state.should == "completed"
|
158
|
+
end
|
131
159
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
160
|
+
context "capturing fails" do
|
161
|
+
before do
|
162
|
+
fake_response = double(:success? => false, :to_s => "Insufficient funds")
|
163
|
+
Spree::Gateway::Bogus.any_instance.should_receive(:capture).and_return(fake_response)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "returns a 422 status" do
|
167
|
+
api_put :capture, :id => payment.to_param
|
168
|
+
response.status.should == 422
|
169
|
+
json_response["error"].should == "There was a problem with the payment gateway: Insufficient funds"
|
170
|
+
end
|
171
|
+
end
|
137
172
|
end
|
138
173
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
174
|
+
context "purchasing" do
|
175
|
+
it "can purchase" do
|
176
|
+
api_put :purchase, :id => payment.to_param
|
177
|
+
response.status.should == 200
|
178
|
+
payment.reload.state.should == "completed"
|
179
|
+
end
|
145
180
|
|
146
|
-
|
147
|
-
|
181
|
+
context "purchasing fails" do
|
182
|
+
before do
|
183
|
+
fake_response = double(:success? => false, :to_s => "Insufficient funds")
|
184
|
+
Spree::Gateway::Bogus.any_instance.should_receive(:purchase).and_return(fake_response)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "returns a 422 status" do
|
188
|
+
api_put :purchase, :id => payment.to_param
|
189
|
+
response.status.should == 422
|
190
|
+
json_response["error"].should == "There was a problem with the payment gateway: Insufficient funds"
|
191
|
+
end
|
192
|
+
end
|
148
193
|
end
|
149
194
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
195
|
+
context "voiding" do
|
196
|
+
it "can void" do
|
197
|
+
api_put :void, :id => payment.to_param
|
198
|
+
response.status.should == 200
|
199
|
+
payment.reload.state.should == "void"
|
200
|
+
end
|
156
201
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
json_response["error"].should == "There was a problem with the payment gateway: NO REFUNDS"
|
202
|
+
context "voiding fails" do
|
203
|
+
before do
|
204
|
+
fake_response = double(:success? => false, :to_s => "NO REFUNDS")
|
205
|
+
Spree::Gateway::Bogus.any_instance.should_receive(:void).and_return(fake_response)
|
206
|
+
end
|
163
207
|
|
164
|
-
|
165
|
-
|
208
|
+
it "returns a 422 status" do
|
209
|
+
api_put :void, :id => payment.to_param
|
210
|
+
response.status.should == 422
|
211
|
+
json_response["error"].should == "There was a problem with the payment gateway: NO REFUNDS"
|
212
|
+
|
213
|
+
payment.reload.state.should == "checkout"
|
214
|
+
end
|
215
|
+
end
|
166
216
|
end
|
167
217
|
|
168
218
|
context "crediting" do
|
@@ -173,31 +223,30 @@ module Spree
|
|
173
223
|
it "can credit" do
|
174
224
|
api_put :credit, :id => payment.to_param
|
175
225
|
response.status.should == 200
|
176
|
-
payment.reload
|
177
|
-
payment.state.should == "completed"
|
226
|
+
payment.reload.state.should == "completed"
|
178
227
|
|
179
|
-
#
|
228
|
+
# Ensure that a credit payment was created, and it has correct credit amount
|
180
229
|
credit_payment = Payment.where(:source_type => 'Spree::Payment', :source_id => payment.id).last
|
181
230
|
credit_payment.amount.to_f.should == -45.75
|
182
231
|
end
|
183
232
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
233
|
+
context "crediting fails" do
|
234
|
+
it "returns a 422 status" do
|
235
|
+
fake_response = double(:success? => false, :to_s => "NO CREDIT FOR YOU")
|
236
|
+
Spree::Gateway::Bogus.any_instance.should_receive(:credit).and_return(fake_response)
|
237
|
+
api_put :credit, :id => payment.to_param
|
238
|
+
response.status.should == 422
|
239
|
+
json_response["error"].should == "There was a problem with the payment gateway: NO CREDIT FOR YOU"
|
240
|
+
end
|
241
|
+
|
242
|
+
it "cannot credit over credit_allowed limit" do
|
243
|
+
api_put :credit, :id => payment.to_param, :amount => 1000000
|
244
|
+
response.status.should == 422
|
245
|
+
json_response["error"].should == "This payment can only be credited up to 45.75. Please specify an amount less than or equal to this number."
|
246
|
+
end
|
196
247
|
end
|
197
248
|
end
|
198
249
|
end
|
199
|
-
|
200
250
|
end
|
201
|
-
|
202
251
|
end
|
203
252
|
end
|
@@ -13,40 +13,76 @@ module Spree
|
|
13
13
|
stub_authentication!
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
context "as a normal user" do
|
17
|
+
it "cannot list stock items for a stock location" do
|
18
|
+
api_get :index, stock_location_id: stock_location.to_param
|
19
|
+
response.status.should == 401
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
22
|
+
it "cannot see a stock item" do
|
23
|
+
api_get :show, stock_location_id: stock_location.to_param, id: stock_item.to_param
|
24
|
+
response.status.should == 401
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
it "cannot create a stock item" do
|
28
|
+
variant = create(:variant)
|
29
|
+
params = {
|
30
|
+
stock_location_id: stock_location.to_param,
|
31
|
+
stock_item: {
|
32
|
+
variant_id: variant.id,
|
33
|
+
count_on_hand: '20'
|
34
|
+
}
|
35
|
+
}
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
api_post :create, params
|
38
|
+
response.status.should == 401
|
39
|
+
end
|
40
|
+
|
41
|
+
it "cannot update a stock item" do
|
42
|
+
api_put :update, stock_location_id: stock_location.to_param, stock_item_id: stock_item.to_param
|
43
|
+
response.status.should == 401
|
44
|
+
end
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
it "cannot destroy a stock item" do
|
47
|
+
api_delete :destroy, stock_location_id: stock_location.to_param, stock_item_id: stock_item.to_param
|
48
|
+
response.status.should == 401
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
|
-
context
|
52
|
+
context "as an admin" do
|
48
53
|
sign_in_as_admin!
|
49
54
|
|
55
|
+
it 'cannot list of stock items' do
|
56
|
+
api_get :index, stock_location_id: stock_location.to_param
|
57
|
+
json_response['stock_items'].first.should have_attributes(attributes)
|
58
|
+
json_response['stock_items'].first['variant']['sku'].should eq 'ABC'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'requires a stock_location_id to be passed as a parameter' do
|
62
|
+
api_get :index
|
63
|
+
json_response['error'].should =~ /stock_location_id parameter must be provided/
|
64
|
+
response.status.should == 422
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'can control the page size through a parameter' do
|
68
|
+
api_get :index, stock_location_id: stock_location.to_param, per_page: 1
|
69
|
+
json_response['count'].should == 1
|
70
|
+
json_response['current_page'].should == 1
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'can query the results through a paramter' do
|
74
|
+
stock_item.update_column(:count_on_hand, 30)
|
75
|
+
api_get :index, stock_location_id: stock_location.to_param, q: { count_on_hand_eq: '30' }
|
76
|
+
json_response['count'].should == 1
|
77
|
+
json_response['stock_items'].first['count_on_hand'].should eq 30
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'gets a stock item' do
|
81
|
+
api_get :show, stock_location_id: stock_location.to_param, id: stock_item.to_param
|
82
|
+
json_response.should have_attributes(attributes)
|
83
|
+
json_response['count_on_hand'].should eq stock_item.count_on_hand
|
84
|
+
end
|
85
|
+
|
50
86
|
it 'can create a new stock item' do
|
51
87
|
variant = create(:variant)
|
52
88
|
# Creating a variant also creates stock items.
|
@@ -11,45 +11,72 @@ module Spree
|
|
11
11
|
stub_authentication!
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
context "as a user" do
|
15
|
+
it "cannot see stock locations" do
|
16
|
+
api_get :index
|
17
|
+
response.status.should == 401
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
it "cannot see a single stock location" do
|
21
|
+
api_get :show, :id => stock_location.id
|
22
|
+
response.status.should == 401
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
it "cannot create a new stock location" do
|
26
|
+
params = {
|
27
|
+
stock_location: {
|
28
|
+
name: "North Pole",
|
29
|
+
active: true
|
30
|
+
}
|
31
|
+
}
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
json_response['count'].should == 1
|
33
|
-
json_response['current_page'].should == 1
|
34
|
-
json_response['pages'].should == 2
|
35
|
-
end
|
33
|
+
api_post :create, params
|
34
|
+
response.status.should == 401
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
json_response['stock_locations'].first['name'].should eq expected_result.name
|
42
|
-
end
|
37
|
+
it "cannot update a stock location" do
|
38
|
+
api_put :update, :stock_location => { :name => "South Pole" }, :id => stock_location.to_param
|
39
|
+
response.status.should == 401
|
40
|
+
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
it "cannot delete a stock location" do
|
43
|
+
api_put :destroy, :id => stock_location.to_param
|
44
|
+
response.status.should == 401
|
45
|
+
end
|
48
46
|
end
|
49
47
|
|
48
|
+
|
50
49
|
context "as an admin" do
|
51
50
|
sign_in_as_admin!
|
52
51
|
|
52
|
+
it "gets list of stock locations" do
|
53
|
+
api_get :index
|
54
|
+
json_response['stock_locations'].first.should have_attributes(attributes)
|
55
|
+
json_response['stock_locations'].first['country'].should_not be_nil
|
56
|
+
json_response['stock_locations'].first['state'].should_not be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can control the page size through a parameter' do
|
60
|
+
create(:stock_location)
|
61
|
+
api_get :index, per_page: 1
|
62
|
+
json_response['count'].should == 1
|
63
|
+
json_response['current_page'].should == 1
|
64
|
+
json_response['pages'].should == 2
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'can query the results through a paramter' do
|
68
|
+
expected_result = create(:stock_location, name: 'South America')
|
69
|
+
api_get :index, q: { name_cont: 'south' }
|
70
|
+
json_response['count'].should == 1
|
71
|
+
json_response['stock_locations'].first['name'].should eq expected_result.name
|
72
|
+
end
|
73
|
+
|
74
|
+
it "gets a stock location" do
|
75
|
+
api_get :show, id: stock_location.to_param
|
76
|
+
json_response.should have_attributes(attributes)
|
77
|
+
json_response['name'].should eq stock_location.name
|
78
|
+
end
|
79
|
+
|
53
80
|
it "can create a new stock location" do
|
54
81
|
params = {
|
55
82
|
stock_location: {
|
@@ -13,41 +13,65 @@ module Spree
|
|
13
13
|
stub_authentication!
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
it 'requires a stock_location_id to be passed as a parameter' do
|
23
|
-
api_get :index
|
24
|
-
json_response['error'].should =~ /stock_location_id parameter must be provided/
|
25
|
-
response.status.should == 422
|
26
|
-
end
|
16
|
+
context 'as a user' do
|
17
|
+
it 'cannot see a list of stock movements' do
|
18
|
+
api_get :index, stock_location_id: stock_location.to_param
|
19
|
+
response.status.should == 401
|
20
|
+
end
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
json_response['current_page'].should == 1
|
33
|
-
json_response['pages'].should == 2
|
34
|
-
end
|
22
|
+
it 'cannot see a stock movement' do
|
23
|
+
api_get :show, stock_location_id: stock_location.to_param, id: stock_movement.id
|
24
|
+
response.status.should == 401
|
25
|
+
end
|
35
26
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
27
|
+
it 'cannot create a stock movement' do
|
28
|
+
params = {
|
29
|
+
stock_location_id: stock_location.to_param,
|
30
|
+
stock_movement: {
|
31
|
+
stock_item_id: stock_item.to_param
|
32
|
+
}
|
33
|
+
}
|
41
34
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
json_response['stock_item_id'].should eq stock_movement.stock_item_id
|
35
|
+
api_post :create, params
|
36
|
+
response.status.should == 401
|
37
|
+
end
|
46
38
|
end
|
47
39
|
|
48
40
|
context 'as an admin' do
|
49
41
|
sign_in_as_admin!
|
50
42
|
|
43
|
+
it 'gets list of stock movements' do
|
44
|
+
api_get :index, stock_location_id: stock_location.to_param
|
45
|
+
json_response['stock_movements'].first.should have_attributes(attributes)
|
46
|
+
json_response['stock_movements'].first['stock_item']['count_on_hand'].should eq 11
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'requires a stock_location_id to be passed as a parameter' do
|
50
|
+
api_get :index
|
51
|
+
json_response['error'].should =~ /stock_location_id parameter must be provided/
|
52
|
+
response.status.should == 422
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can control the page size through a parameter' do
|
56
|
+
create(:stock_movement, stock_item: stock_item)
|
57
|
+
api_get :index, stock_location_id: stock_location.to_param, per_page: 1
|
58
|
+
json_response['count'].should == 1
|
59
|
+
json_response['current_page'].should == 1
|
60
|
+
json_response['pages'].should == 2
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can query the results through a paramter' do
|
64
|
+
expected_result = create(:stock_movement, :received, quantity: 10, stock_item: stock_item)
|
65
|
+
api_get :index, stock_location_id: stock_location.to_param, q: { quantity_eq: '10' }
|
66
|
+
json_response['count'].should == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'gets a stock movement' do
|
70
|
+
api_get :show, stock_location_id: stock_location.to_param, id: stock_movement.to_param
|
71
|
+
json_response.should have_attributes(attributes)
|
72
|
+
json_response['stock_item_id'].should eq stock_movement.stock_item_id
|
73
|
+
end
|
74
|
+
|
51
75
|
it 'can create a new stock movement' do
|
52
76
|
params = {
|
53
77
|
stock_location_id: stock_location.to_param,
|
@@ -2,22 +2,25 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
describe Order do
|
5
|
-
let!(:country) {
|
6
|
-
let!(:state) { country.states.first ||
|
7
|
-
let!(:stock_location) {
|
5
|
+
let!(:country) { create(:country) }
|
6
|
+
let!(:state) { country.states.first || create(:state, :country => country) }
|
7
|
+
let!(:stock_location) { create(:stock_location) }
|
8
8
|
|
9
9
|
let(:user) { stub_model(LegacyUser, :email => 'fox@mudler.com') }
|
10
10
|
let(:shipping_method) { create(:shipping_method) }
|
11
11
|
let(:payment_method) { create(:payment_method) }
|
12
|
+
|
12
13
|
let(:product) { product = Spree::Product.create(:name => 'Test',
|
13
14
|
:sku => 'TEST-1',
|
14
15
|
:price => 33.22)
|
15
|
-
product.shipping_category =
|
16
|
+
product.shipping_category = create(:shipping_category)
|
16
17
|
product.save
|
17
18
|
product }
|
19
|
+
|
18
20
|
let(:variant) { variant = product.master
|
19
21
|
variant.stock_items.each { |si| si.update_attribute(:count_on_hand, 10) }
|
20
22
|
variant }
|
23
|
+
|
21
24
|
let(:sku) { variant.sku }
|
22
25
|
let(:variant_id) { variant.id }
|
23
26
|
|
@@ -49,15 +52,23 @@ module Spree
|
|
49
52
|
order.state.should eq 'complete'
|
50
53
|
end
|
51
54
|
|
52
|
-
|
53
|
-
|
55
|
+
context "build order with line items" do
|
56
|
+
let(:attributes) do
|
57
|
+
{ :variant_id => variant.id, :quantity => 5, :price => 33.77 }
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
it 'can build an order from API with just line items' do
|
61
|
+
params = { :line_items_attributes => { "0" => attributes } }
|
62
|
+
Order.should_receive(:ensure_variant_id_from_api)
|
63
|
+
order = Order.build_from_api(user, params)
|
64
|
+
|
65
|
+
order.user.should == nil
|
66
|
+
line_item = order.line_items.first
|
67
|
+
|
68
|
+
expect(line_item.quantity).to eq attributes[:quantity]
|
69
|
+
expect(line_item.variant_id).to eq attributes[:variant_id]
|
70
|
+
expect(line_item.price).to eq attributes[:price]
|
71
|
+
end
|
61
72
|
end
|
62
73
|
|
63
74
|
it 'handles line_item building exceptions' do
|
@@ -164,6 +175,13 @@ module Spree
|
|
164
175
|
end
|
165
176
|
end
|
166
177
|
|
178
|
+
it "raises with proper message when cant find country" do
|
179
|
+
address = { :country => { "name" => "NoNoCountry" } }
|
180
|
+
expect {
|
181
|
+
Order.ensure_country_id_from_api(address)
|
182
|
+
}.to raise_error /NoNoCountry/
|
183
|
+
end
|
184
|
+
|
167
185
|
it 'ensures_state_id for state fields' do
|
168
186
|
[:name, :abbr].each do |field|
|
169
187
|
address = { :state => { field => state.send(field) }}
|
@@ -172,12 +190,20 @@ module Spree
|
|
172
190
|
end
|
173
191
|
end
|
174
192
|
|
193
|
+
it "raises with proper message when cant find state" do
|
194
|
+
address = { :state => { "name" => "NoNoState" } }
|
195
|
+
expect {
|
196
|
+
Order.ensure_state_id_from_api(address)
|
197
|
+
}.to raise_error /NoNoState/
|
198
|
+
end
|
199
|
+
|
175
200
|
context "shippments" do
|
176
201
|
let(:params) do
|
177
202
|
{ :shipments_attributes => [
|
178
203
|
{ :tracking => '123456789',
|
179
204
|
:cost => '4.99',
|
180
205
|
:shipping_method => shipping_method.name,
|
206
|
+
:stock_location => stock_location.name,
|
181
207
|
:inventory_units => [{ :sku => sku }]
|
182
208
|
}
|
183
209
|
] }
|
@@ -195,6 +221,14 @@ module Spree
|
|
195
221
|
shipment.inventory_units.first.variant_id.should eq product.master.id
|
196
222
|
shipment.tracking.should eq '123456789'
|
197
223
|
shipment.shipping_rates.first.cost.should eq 4.99
|
224
|
+
shipment.stock_location.should eq stock_location
|
225
|
+
end
|
226
|
+
|
227
|
+
it "raises if cant find stock location" do
|
228
|
+
params[:shipments_attributes][0][:stock_location] = "doesnt exist"
|
229
|
+
expect {
|
230
|
+
order = Order.build_from_api(user, params)
|
231
|
+
}.to raise_error
|
198
232
|
end
|
199
233
|
end
|
200
234
|
|
@@ -244,5 +278,40 @@ module Spree
|
|
244
278
|
order = Order.build_from_api(user, params)
|
245
279
|
}.to raise_error /XXX/
|
246
280
|
end
|
281
|
+
|
282
|
+
context "raises error" do
|
283
|
+
it "clears out order from db" do
|
284
|
+
params = { :payments_attributes => [{ payment_method: "XXX" }] }
|
285
|
+
count = Order.count
|
286
|
+
|
287
|
+
expect { order = Order.build_from_api(user, params) }.to raise_error
|
288
|
+
expect(Order.count).to eq count
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context "import param and tax adjustments" do
|
293
|
+
let!(:tax_rate) { create(:tax_rate, amount: 0.05, calculator: Calculator::DefaultTax.create) }
|
294
|
+
let(:other_variant) { create(:variant) }
|
295
|
+
|
296
|
+
let(:line_item_attributes) do
|
297
|
+
line_items.merge({ "1" => { :variant_id => other_variant.id, :quantity => 5 }})
|
298
|
+
end
|
299
|
+
|
300
|
+
before { Zone.stub default_tax: tax_rate.zone }
|
301
|
+
|
302
|
+
it "doesnt create any tax ajustments when importing order" do
|
303
|
+
params = { import: true, line_items_attributes: line_item_attributes }
|
304
|
+
expect {
|
305
|
+
Order.build_from_api(user, params)
|
306
|
+
}.not_to change { Adjustment.count }
|
307
|
+
end
|
308
|
+
|
309
|
+
it "does create tax adjustments if not importing order" do
|
310
|
+
params = { import: false, line_items_attributes: line_item_attributes }
|
311
|
+
expect {
|
312
|
+
Order.build_from_api(user, params)
|
313
|
+
}.to change { Adjustment.count }
|
314
|
+
end
|
315
|
+
end
|
247
316
|
end
|
248
317
|
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.6
|
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: 2.0.
|
19
|
+
version: 2.0.6
|
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.6
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rabl
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -131,6 +131,7 @@ files:
|
|
131
131
|
- app/views/spree/api/payments/index.v1.rabl
|
132
132
|
- app/views/spree/api/payments/new.v1.rabl
|
133
133
|
- app/views/spree/api/payments/show.v1.rabl
|
134
|
+
- app/views/spree/api/payments/update_forbidden.v1.rabl
|
134
135
|
- app/views/spree/api/product_properties/index.v1.rabl
|
135
136
|
- app/views/spree/api/product_properties/new.v1.rabl
|
136
137
|
- app/views/spree/api/product_properties/show.v1.rabl
|