spree_core 1.1.0.rc1 → 1.1.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/admin/shipping_methods.js +3 -2
- data/app/assets/javascripts/admin/spree_core.js +0 -2
- data/app/assets/javascripts/store/spree_core.js +0 -2
- data/app/controllers/spree/admin/option_types_controller.rb +6 -8
- data/app/controllers/spree/admin/payments_controller.rb +1 -2
- data/app/controllers/spree/admin/products_controller.rb +13 -4
- data/app/controllers/spree/products_controller.rb +1 -1
- data/app/controllers/spree/states_controller.rb +1 -1
- data/app/helpers/spree/base_helper.rb +9 -7
- data/app/helpers/spree/products_helper.rb +0 -6
- data/app/mailers/spree/order_mailer.rb +4 -4
- data/app/mailers/spree/shipment_mailer.rb +2 -2
- data/app/models/spree/address.rb +25 -15
- data/app/models/spree/calculator/per_item.rb +4 -1
- data/app/models/spree/calculator.rb +1 -1
- data/app/models/spree/creditcard.rb +8 -184
- data/app/models/spree/gateway/bogus.rb +1 -1
- data/app/models/spree/gateway.rb +3 -1
- data/app/models/spree/inventory_unit.rb +3 -3
- data/app/models/spree/line_item.rb +14 -14
- data/app/models/spree/mail_method.rb +6 -1
- data/app/models/spree/payment/processing.rb +179 -0
- data/app/models/spree/payment.rb +3 -22
- data/app/models/spree/payment_method.rb +2 -2
- data/app/models/spree/product.rb +11 -10
- data/app/models/spree/product_property.rb +2 -0
- data/app/models/spree/return_authorization.rb +9 -7
- data/app/models/spree/shipment.rb +7 -6
- data/app/models/spree/shipping_method.rb +6 -5
- data/app/models/spree/shipping_rate.rb +2 -2
- data/app/models/spree/state.rb +1 -1
- data/app/models/spree/tax_category.rb +2 -2
- data/app/models/spree/tax_rate.rb +7 -7
- data/app/models/spree/taxon.rb +4 -4
- data/app/models/spree/taxonomy.rb +3 -3
- data/app/models/spree/variant.rb +19 -8
- data/app/models/spree/zone.rb +10 -10
- data/app/views/spree/admin/products/index.html.erb +1 -1
- data/app/views/spree/admin/shared/_additional_field.html.erb +1 -1
- data/app/views/spree/admin/shared/_head.html.erb +0 -1
- data/app/views/spree/admin/tax_rates/_form.html.erb +5 -5
- data/app/views/spree/admin/variants/index.html.erb +1 -1
- data/app/views/spree/layouts/spree_application.html.erb +1 -1
- data/app/views/spree/products/_cart_form.html.erb +1 -1
- data/app/views/spree/shared/_head.html.erb +1 -1
- data/config/locales/en.yml +2 -2
- data/db/migrate/20120315064358_migrate_images_from_products_to_variants.rb +1 -1
- data/db/migrate/20120416233427_rename_attachment_size_to_attachment_file_size.rb +5 -0
- data/lib/generators/spree/install/templates/app/assets/javascripts/admin/all.js +2 -0
- data/lib/generators/spree/install/templates/app/assets/javascripts/store/all.js +2 -0
- data/lib/spree/core/controller_helpers.rb +0 -1
- data/lib/spree/core/engine.rb +5 -1
- data/lib/spree/core/search/base.rb +1 -1
- data/lib/spree/core/testing_support/controller_requests.rb +60 -0
- data/lib/spree/core/testing_support/factories.rb +1 -2
- data/lib/spree/core/version.rb +1 -1
- metadata +35 -33
- data/app/helpers/spree/hook_helper.rb +0 -11
@@ -16,7 +16,12 @@ module Spree
|
|
16
16
|
preference :mail_bcc, :string, :default => 'spree@example.com'
|
17
17
|
preference :intercept_email, :string, :default => nil
|
18
18
|
|
19
|
-
attr_accessible :environment, :preferred_enable_mail_delivery,
|
19
|
+
attr_accessible :environment, :preferred_enable_mail_delivery,
|
20
|
+
:preferred_mails_from, :preferred_mail_bcc,
|
21
|
+
:preferred_intercept_email, :preferred_mail_domain,
|
22
|
+
:preferred_mail_host, :preferred_mail_port,
|
23
|
+
:preferred_secure_connection_type, :preferred_mail_auth_type,
|
24
|
+
:preferred_smtp_username, :preferred_smtp_password
|
20
25
|
|
21
26
|
validates :environment, :presence => true
|
22
27
|
|
@@ -0,0 +1,179 @@
|
|
1
|
+
module Spree
|
2
|
+
class Payment < ActiveRecord::Base
|
3
|
+
module Processing
|
4
|
+
def process!
|
5
|
+
if payment_method && payment_method.source_required?
|
6
|
+
if source
|
7
|
+
if !processing?
|
8
|
+
if Spree::Config[:auto_capture]
|
9
|
+
purchase!
|
10
|
+
else
|
11
|
+
authorize!
|
12
|
+
end
|
13
|
+
end
|
14
|
+
else
|
15
|
+
raise Core::GatewayError.new(I18n.t(:payment_processing_failed))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def authorize!
|
21
|
+
started_processing!
|
22
|
+
gateway_action(source, :authorize, :pend)
|
23
|
+
end
|
24
|
+
|
25
|
+
def purchase!
|
26
|
+
started_processing!
|
27
|
+
gateway_action(source, :purchase, :complete)
|
28
|
+
end
|
29
|
+
|
30
|
+
def capture!
|
31
|
+
return unless pending?
|
32
|
+
protect_from_connection_error do
|
33
|
+
check_environment
|
34
|
+
|
35
|
+
if payment_method.payment_profiles_supported?
|
36
|
+
# Gateways supporting payment profiles will need access to creditcard object because this stores the payment profile information
|
37
|
+
# so supply the authorization itself as well as the creditcard, rather than just the authorization code
|
38
|
+
response = payment_method.capture(self, source, gateway_options)
|
39
|
+
else
|
40
|
+
# Standard ActiveMerchant capture usage
|
41
|
+
response = payment_method.capture((amount * 100).round,
|
42
|
+
response_code,
|
43
|
+
gateway_options)
|
44
|
+
end
|
45
|
+
|
46
|
+
handle_response(response, :complete, :failure)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def void_transaction!
|
51
|
+
protect_from_connection_error do
|
52
|
+
check_environment
|
53
|
+
|
54
|
+
response = payment_method.void(self.response_code, gateway_options)
|
55
|
+
record_response(response)
|
56
|
+
|
57
|
+
if response.success?
|
58
|
+
self.response_code = response.authorization
|
59
|
+
self.void
|
60
|
+
else
|
61
|
+
gateway_error(response)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def credit!(credit_amount=nil)
|
68
|
+
protect_from_connection_error do
|
69
|
+
check_environment
|
70
|
+
|
71
|
+
credit_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
|
72
|
+
credit_amount = credit_amount.to_f
|
73
|
+
|
74
|
+
if payment_method.payment_profiles_supported?
|
75
|
+
response = payment_method.credit((credit_amount * 100).round, source, response_code, gateway_options)
|
76
|
+
else
|
77
|
+
response = payment_method.credit((credit_amount * 100).round, response_code, gateway_options)
|
78
|
+
end
|
79
|
+
|
80
|
+
record_response(response)
|
81
|
+
|
82
|
+
if response.success?
|
83
|
+
self.class.create({ :order => order,
|
84
|
+
:source => self,
|
85
|
+
:payment_method => payment_method,
|
86
|
+
:amount => credit_amount.abs * -1,
|
87
|
+
:response_code => response.authorization,
|
88
|
+
:state => 'completed' }, :without_protection => true)
|
89
|
+
else
|
90
|
+
gateway_error(response)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def partial_credit(amount)
|
96
|
+
return if amount > credit_allowed
|
97
|
+
started_processing!
|
98
|
+
credit!(amount)
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def gateway_action(source, action, success_state)
|
104
|
+
protect_from_connection_error do
|
105
|
+
check_environment
|
106
|
+
|
107
|
+
response = payment_method.send(action, (amount * 100).round,
|
108
|
+
source,
|
109
|
+
gateway_options)
|
110
|
+
handle_response(response, success_state, :failure)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def handle_response(response, success_state, failure_state)
|
115
|
+
record_response(response)
|
116
|
+
|
117
|
+
if response.success?
|
118
|
+
self.response_code = response.authorization
|
119
|
+
self.avs_response = response.avs_result['code']
|
120
|
+
self.send(success_state)
|
121
|
+
else
|
122
|
+
self.send("#{failure_state}!")
|
123
|
+
gateway_error(response)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def record_response(response)
|
128
|
+
log_entries.create({:details => response.to_yaml}, :without_protection => true)
|
129
|
+
end
|
130
|
+
|
131
|
+
def gateway_options
|
132
|
+
options = { :email => order.email,
|
133
|
+
:customer => order.email,
|
134
|
+
:ip => order.ip_address,
|
135
|
+
:order_id => order.number }
|
136
|
+
|
137
|
+
options.merge!({ :shipping => order.ship_total * 100,
|
138
|
+
:tax => order.tax_total * 100,
|
139
|
+
:subtotal => order.item_total * 100 })
|
140
|
+
|
141
|
+
options.merge({ :billing_address => order.bill_address.try(:active_merchant_hash),
|
142
|
+
:shipping_address => order.ship_address.try(:active_merchant_hash) })
|
143
|
+
end
|
144
|
+
|
145
|
+
def protect_from_connection_error
|
146
|
+
begin
|
147
|
+
yield
|
148
|
+
rescue ActiveMerchant::ConnectionError => e
|
149
|
+
gateway_error(e)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def record_log(response)
|
154
|
+
log_entries.create({:details => response.to_yaml}, :without_protection => true)
|
155
|
+
end
|
156
|
+
|
157
|
+
def gateway_error(error)
|
158
|
+
if error.is_a? ActiveMerchant::Billing::Response
|
159
|
+
text = error.params['message'] || error.params['response_reason_text'] || error.message
|
160
|
+
elsif error.is_a? ActiveMerchant::ConnectionError
|
161
|
+
text = I18n.t(:unable_to_connect_to_gateway)
|
162
|
+
else
|
163
|
+
text = error.to_s
|
164
|
+
end
|
165
|
+
logger.error(I18n.t(:gateway_error))
|
166
|
+
logger.error(" #{error.to_yaml}")
|
167
|
+
raise Core::GatewayError.new(text)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Saftey check to make sure we're not accidentally performing operations on a live gateway.
|
171
|
+
# Ex. When testing in staging environment with a copy of production data.
|
172
|
+
def check_environment
|
173
|
+
return if payment_method.environment == Rails.env
|
174
|
+
message = I18n.t(:gateway_config_unavailable) + " - #{Rails.env}"
|
175
|
+
raise Core::GatewayError.new(message)
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
data/app/models/spree/payment.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Spree
|
2
2
|
class Payment < ActiveRecord::Base
|
3
|
+
include Spree::Payment::Processing
|
3
4
|
belongs_to :order
|
4
5
|
belongs_to :source, :polymorphic => true, :validate => true
|
5
6
|
belongs_to :payment_method
|
@@ -27,11 +28,11 @@ module Spree
|
|
27
28
|
state_machine :initial => 'checkout' do
|
28
29
|
# With card payments, happens before purchase or authorization happens
|
29
30
|
event :started_processing do
|
30
|
-
transition :from => ['checkout', 'pending', 'completed'], :to => 'processing'
|
31
|
+
transition :from => ['checkout', 'pending', 'completed', 'processing'], :to => 'processing'
|
31
32
|
end
|
32
33
|
# When processing during checkout fails
|
33
34
|
event :failure do
|
34
|
-
transition :from => 'processing', :to => 'failed'
|
35
|
+
transition :from => ['processing', 'pending'], :to => 'failed'
|
35
36
|
end
|
36
37
|
# With card payments this represents authorizing the payment
|
37
38
|
event :pend do
|
@@ -58,34 +59,14 @@ module Spree
|
|
58
59
|
credit_allowed > 0
|
59
60
|
end
|
60
61
|
|
61
|
-
def credit(amount)
|
62
|
-
return if amount > credit_allowed
|
63
|
-
started_processing!
|
64
|
-
source.credit(self, amount)
|
65
|
-
end
|
66
|
-
|
67
62
|
# see https://github.com/spree/spree/issues/981
|
68
63
|
def build_source
|
69
64
|
return if source_attributes.nil?
|
70
|
-
|
71
65
|
if payment_method and payment_method.payment_source_class
|
72
66
|
self.source = payment_method.payment_source_class.new(source_attributes)
|
73
67
|
end
|
74
68
|
end
|
75
69
|
|
76
|
-
def process!
|
77
|
-
if payment_method && payment_method.source_required?
|
78
|
-
if source
|
79
|
-
if !processing? && source.respond_to?(:process!)
|
80
|
-
started_processing!
|
81
|
-
source.process!(self) # source is responsible for updating the payment state when it's done processing
|
82
|
-
end
|
83
|
-
else
|
84
|
-
raise Core::GatewayError.new(I18n.t(:payment_processing_failed))
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
70
|
def actions
|
90
71
|
return [] unless payment_source and payment_source.respond_to? :actions
|
91
72
|
payment_source.actions.select { |action| !payment_source.respond_to?("can_#{action}?") or payment_source.send("can_#{action}?", self) }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Spree
|
2
2
|
class PaymentMethod < ActiveRecord::Base
|
3
|
-
DISPLAY =
|
3
|
+
DISPLAY = [:both, :front_end, :back_end]
|
4
4
|
default_scope where(:deleted_at => nil)
|
5
5
|
|
6
6
|
scope :production, where(:environment => 'production')
|
@@ -22,7 +22,7 @@ module Spree
|
|
22
22
|
raise 'You must implement payment_source_class method for this gateway.'
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.available(display_on='both')
|
25
|
+
def self.available(display_on = 'both')
|
26
26
|
all.select { |p| p.active && (p.display_on == display_on.to_s || p.display_on.blank?) && (p.environment == Rails.env || p.environment.blank?) }
|
27
27
|
end
|
28
28
|
|
data/app/models/spree/product.rb
CHANGED
@@ -71,7 +71,8 @@ module Spree
|
|
71
71
|
attr_accessible :name, :description, :available_on, :permalink, :meta_description,
|
72
72
|
:meta_keywords, :price, :sku, :deleted_at, :prototype_id,
|
73
73
|
:option_values_hash, :on_hand, :weight, :height, :width, :depth,
|
74
|
-
:shipping_category_id, :tax_category_id
|
74
|
+
:shipping_category_id, :tax_category_id, :product_properties_attributes,
|
75
|
+
:variants_attributes
|
75
76
|
|
76
77
|
attr_accessible :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
|
77
78
|
|
@@ -85,7 +86,7 @@ module Spree
|
|
85
86
|
after_initialize :ensure_master
|
86
87
|
|
87
88
|
def ensure_master
|
88
|
-
return unless
|
89
|
+
return unless new_record?
|
89
90
|
self.master ||= Variant.new
|
90
91
|
end
|
91
92
|
|
@@ -132,8 +133,8 @@ module Spree
|
|
132
133
|
def ensure_option_types_exist_for_values_hash
|
133
134
|
return if option_values_hash.nil?
|
134
135
|
option_values_hash.keys.map(&:to_i).each do |id|
|
135
|
-
self.option_type_ids << id unless
|
136
|
-
|
136
|
+
self.option_type_ids << id unless option_type_ids.include?(id)
|
137
|
+
product_option_types.create({:option_type_id => id}, :without_protection => true) unless product_option_types.map(&:option_type_id).include?(id)
|
137
138
|
end
|
138
139
|
end
|
139
140
|
|
@@ -141,12 +142,12 @@ module Spree
|
|
141
142
|
# define "duplicate_extra" for site-specific actions, eg for additional fields
|
142
143
|
def duplicate
|
143
144
|
p = self.dup
|
144
|
-
p.name = 'COPY OF ' +
|
145
|
+
p.name = 'COPY OF ' + name
|
145
146
|
p.deleted_at = nil
|
146
147
|
p.created_at = p.updated_at = nil
|
147
|
-
p.taxons =
|
148
|
+
p.taxons = taxons
|
148
149
|
|
149
|
-
p.product_properties =
|
150
|
+
p.product_properties = product_properties.map { |q| r = q.dup; r.created_at = r.updated_at = nil; r }
|
150
151
|
|
151
152
|
image_dup = lambda { |i| j = i.dup; j.attachment = i.attachment.clone; j }
|
152
153
|
|
@@ -157,7 +158,7 @@ module Spree
|
|
157
158
|
p.master = variant
|
158
159
|
|
159
160
|
# don't dup the actual variants, just the characterising types
|
160
|
-
p.option_types =
|
161
|
+
p.option_types = option_types if has_variants?
|
161
162
|
|
162
163
|
# allow site to do some customization
|
163
164
|
p.send(:duplicate_extra, self) if p.respond_to?(:duplicate_extra)
|
@@ -180,7 +181,7 @@ module Spree
|
|
180
181
|
end
|
181
182
|
|
182
183
|
def effective_tax_rate
|
183
|
-
if
|
184
|
+
if tax_category
|
184
185
|
tax_category.effective_amount
|
185
186
|
else
|
186
187
|
TaxRate.default
|
@@ -207,7 +208,7 @@ module Spree
|
|
207
208
|
values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
|
208
209
|
|
209
210
|
values.each do |ids|
|
210
|
-
variant =
|
211
|
+
variant = variants.create({ :option_value_ids => ids, :price => master.price }, :without_protection => true)
|
211
212
|
end
|
212
213
|
save
|
213
214
|
end
|
@@ -9,6 +9,8 @@ module Spree
|
|
9
9
|
validates :amount, :numericality => true
|
10
10
|
validate :must_have_shipped_units
|
11
11
|
|
12
|
+
attr_accessible :amount, :reason
|
13
|
+
|
12
14
|
state_machine :initial => 'authorized' do
|
13
15
|
after_transition :to => 'received', :do => :process_return
|
14
16
|
|
@@ -21,8 +23,8 @@ module Spree
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def add_variant(variant_id, quantity)
|
24
|
-
order_units =
|
25
|
-
returned_units =
|
26
|
+
order_units = order.inventory_units.group_by(&:variant_id)
|
27
|
+
returned_units = inventory_units.group_by(&:variant_id)
|
26
28
|
|
27
29
|
count = 0
|
28
30
|
|
@@ -44,7 +46,7 @@ module Spree
|
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
47
|
-
|
49
|
+
order.authorize_return! if inventory_units.reload.size > 0 && !order.awaiting_return?
|
48
50
|
end
|
49
51
|
|
50
52
|
private
|
@@ -53,7 +55,7 @@ module Spree
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def generate_number
|
56
|
-
return if
|
58
|
+
return if number
|
57
59
|
|
58
60
|
record = true
|
59
61
|
while record
|
@@ -65,8 +67,8 @@ module Spree
|
|
65
67
|
|
66
68
|
def process_return
|
67
69
|
inventory_units.each &:return!
|
68
|
-
credit = Adjustment.create(:source => self, :adjustable => order, :amount =>
|
69
|
-
|
70
|
+
credit = Adjustment.create(:source => self, :adjustable => order, :amount => amount.abs * -1, :label => I18n.t(:rma_credit))
|
71
|
+
order.update!
|
70
72
|
end
|
71
73
|
|
72
74
|
def allow_receive?
|
@@ -74,7 +76,7 @@ module Spree
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def force_positive_amount
|
77
|
-
self.amount =
|
79
|
+
self.amount = amount.abs
|
78
80
|
end
|
79
81
|
end
|
80
82
|
end
|
@@ -14,7 +14,8 @@ module Spree
|
|
14
14
|
|
15
15
|
attr_accessor :special_instructions
|
16
16
|
|
17
|
-
attr_accessible :order, :state, :shipping_method, :special_instructions,
|
17
|
+
attr_accessible :order, :state, :shipping_method, :special_instructions,
|
18
|
+
:shipping_method_id, :tracking
|
18
19
|
|
19
20
|
accepts_nested_attributes_for :address
|
20
21
|
accepts_nested_attributes_for :inventory_units
|
@@ -29,9 +30,9 @@ module Spree
|
|
29
30
|
scope :pending, where(:state => 'pending')
|
30
31
|
|
31
32
|
def to_param
|
32
|
-
|
33
|
-
generate_shipment_number unless
|
34
|
-
|
33
|
+
number if number
|
34
|
+
generate_shipment_number unless number
|
35
|
+
number.to_s.to_url.upcase
|
35
36
|
end
|
36
37
|
|
37
38
|
def shipped=(value)
|
@@ -83,7 +84,7 @@ module Spree
|
|
83
84
|
# Order object. This is necessary because the association actually has a stale (and unsaved) copy of the Order and so it will not
|
84
85
|
# yield the correct results.
|
85
86
|
def update!(order)
|
86
|
-
old_state =
|
87
|
+
old_state = state
|
87
88
|
new_state = determine_state(order)
|
88
89
|
update_attribute_without_callbacks 'state', determine_state(order)
|
89
90
|
after_ship if new_state == 'shipped' and old_state != 'shipped'
|
@@ -91,7 +92,7 @@ module Spree
|
|
91
92
|
|
92
93
|
private
|
93
94
|
def generate_shipment_number
|
94
|
-
return
|
95
|
+
return number unless number.blank?
|
95
96
|
record = true
|
96
97
|
while record
|
97
98
|
random = "H#{Array.new(11){rand(9)}.join}"
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module Spree
|
2
2
|
class ShippingMethod < ActiveRecord::Base
|
3
|
-
DISPLAY =
|
3
|
+
DISPLAY = [:both, :front_end, :back_end]
|
4
4
|
belongs_to :zone
|
5
5
|
has_many :shipments
|
6
6
|
validates :name, :calculator, :zone, :presence => true
|
7
7
|
belongs_to :shipping_category
|
8
8
|
|
9
|
-
attr_accessible :name, :zone_id, :display_on, :shipping_category_id,
|
9
|
+
attr_accessible :name, :zone_id, :display_on, :shipping_category_id,
|
10
|
+
:match_none, :match_one, :match_all, :calculator_type
|
10
11
|
|
11
12
|
calculated_adjustments
|
12
13
|
|
13
|
-
def available?(order, display_on=nil)
|
14
|
+
def available?(order, display_on = nil)
|
14
15
|
display_check = (self.display_on == display_on.to_s || self.display_on.blank?)
|
15
16
|
calculator_check = calculator.available?(order)
|
16
17
|
display_check && calculator_check
|
17
18
|
end
|
18
19
|
|
19
|
-
def available_to_order?(order, display_on=nil)
|
20
|
+
def available_to_order?(order, display_on = nil)
|
20
21
|
availability_check = available?(order,display_on)
|
21
22
|
zone_check = zone && zone.include?(order.ship_address)
|
22
23
|
category_check = category_match?(order)
|
@@ -37,7 +38,7 @@ module Spree
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
40
|
-
def self.all_available(order, display_on=nil)
|
41
|
+
def self.all_available(order, display_on = nil)
|
41
42
|
all.select { |method| method.available_to_order?(order,display_on) }
|
42
43
|
end
|
43
44
|
end
|
data/app/models/spree/state.rb
CHANGED
@@ -8,7 +8,7 @@ module Spree
|
|
8
8
|
validates :country, :name, :presence => true
|
9
9
|
|
10
10
|
def self.find_all_by_name_or_abbr(name_or_abbr)
|
11
|
-
where(
|
11
|
+
where('name = ? OR abbr = ?', name_or_abbr, name_or_abbr)
|
12
12
|
end
|
13
13
|
|
14
14
|
# table of { country.id => [ state.id , state.name ] }, arrays sorted by name
|
@@ -14,13 +14,13 @@ module Spree
|
|
14
14
|
#set existing default tax category to false if this one has been marked as default
|
15
15
|
|
16
16
|
if is_default && tax_category = self.class.where(:is_default => true).first
|
17
|
-
tax_category.update_attribute(:is_default, false)
|
17
|
+
tax_category.update_attribute(:is_default, false) unless tax_category == self
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def mark_deleted!
|
22
22
|
self.deleted_at = Time.now
|
23
|
-
|
23
|
+
save
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -20,7 +20,7 @@ module Spree
|
|
20
20
|
calculated_adjustments
|
21
21
|
scope :by_zone, lambda { |zone| where(:zone_id => zone) }
|
22
22
|
|
23
|
-
attr_accessible :amount, :tax_category_id, :calculator
|
23
|
+
attr_accessible :amount, :tax_category_id, :calculator, :zone_id, :included_in_price
|
24
24
|
|
25
25
|
# Gets the array of TaxRates appropriate for the specified order
|
26
26
|
def self.match(order)
|
@@ -46,17 +46,17 @@ module Spree
|
|
46
46
|
# Creates necessary tax adjustments for the order.
|
47
47
|
def adjust(order)
|
48
48
|
label = "#{tax_category.name} #{amount * 100}%"
|
49
|
-
if
|
49
|
+
if included_in_price
|
50
50
|
if Zone.default_tax.contains? order.tax_zone
|
51
51
|
order.line_items.each { |line_item| create_adjustment(label, line_item, line_item) }
|
52
52
|
else
|
53
53
|
amount = -1 * calculator.compute(order)
|
54
54
|
label = I18n.t(:refund) + label
|
55
|
-
order.adjustments.create({:amount => amount,
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
order.adjustments.create({ :amount => amount,
|
56
|
+
:source => order,
|
57
|
+
:originator => self,
|
58
|
+
:locked => true,
|
59
|
+
:label => label }, :without_protection => true)
|
60
60
|
end
|
61
61
|
else
|
62
62
|
create_adjustment(label, order, order)
|
data/app/models/spree/taxon.rb
CHANGED
@@ -6,7 +6,7 @@ module Spree
|
|
6
6
|
has_and_belongs_to_many :products, :join_table => 'spree_products_taxons'
|
7
7
|
before_create :set_permalink
|
8
8
|
|
9
|
-
attr_accessible :name, :parent_id, :position
|
9
|
+
attr_accessible :name, :parent_id, :position, :description, :permalink
|
10
10
|
|
11
11
|
validates :name, :presence => true
|
12
12
|
has_attached_file :icon,
|
@@ -33,15 +33,15 @@ module Spree
|
|
33
33
|
# Creates permalink based on Stringex's .to_url method
|
34
34
|
def set_permalink
|
35
35
|
if parent_id.nil?
|
36
|
-
self.permalink = name.to_url if
|
36
|
+
self.permalink = name.to_url if permalink.blank?
|
37
37
|
else
|
38
38
|
parent_taxon = Taxon.find(parent_id)
|
39
|
-
self.permalink = [parent_taxon.permalink, (
|
39
|
+
self.permalink = [parent_taxon.permalink, (permalink.blank? ? name.to_url : permalink.split('/').last)].join('/')
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def active_products
|
44
|
-
scope =
|
44
|
+
scope = products.active
|
45
45
|
scope = scope.on_hand unless Spree::Config[:show_zero_stock_products]
|
46
46
|
scope
|
47
47
|
end
|
@@ -12,10 +12,10 @@ module Spree
|
|
12
12
|
|
13
13
|
private
|
14
14
|
def set_name
|
15
|
-
if
|
16
|
-
|
15
|
+
if root
|
16
|
+
root.update_attribute(:name, name)
|
17
17
|
else
|
18
|
-
self.root = Taxon.create!({ :taxonomy_id =>
|
18
|
+
self.root = Taxon.create!({ :taxonomy_id => id, :name => name }, :without_protection => true)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|