spree_core 1.1.0.rc1 → 1.1.0.rc2
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.
- 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
@@ -3,9 +3,10 @@ $(document).ready(function() {
|
|
3
3
|
$('input[type=checkbox]:not(:checked)').attr('disabled', true);
|
4
4
|
}
|
5
5
|
|
6
|
-
|
6
|
+
categoryCheckboxes = '.categories input[type=checkbox]';
|
7
|
+
$(categoryCheckboxes).change(function(){
|
7
8
|
if($(this).is(':checked')) {
|
8
|
-
$('
|
9
|
+
$(categoryCheckboxes + ':not(:checked)').attr('disabled', true);
|
9
10
|
$(this).removeAttr('disabled');
|
10
11
|
} else {
|
11
12
|
$('input[type=checkbox]').removeAttr('disabled');
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spree
|
2
2
|
module Admin
|
3
3
|
class OptionTypesController < ResourceController
|
4
|
-
before_filter :load_product, :only => [:selected, :available, :remove]
|
4
|
+
before_filter :load_product, :only => [:select, :selected, :available, :remove]
|
5
5
|
|
6
6
|
def available
|
7
7
|
set_available_option_types
|
@@ -32,7 +32,6 @@ module Spree
|
|
32
32
|
|
33
33
|
# AJAX method for selecting an existing option type and associating with the current product
|
34
34
|
def select
|
35
|
-
@product = Product.find_by_param!(params[:product_id])
|
36
35
|
@product.option_types << OptionType.find(params[:id])
|
37
36
|
@product.reload
|
38
37
|
@option_types = @product.option_types
|
@@ -55,13 +54,12 @@ module Spree
|
|
55
54
|
@product = Product.find_by_param!(params[:product_id])
|
56
55
|
end
|
57
56
|
|
58
|
-
def set_available_option_types
|
59
|
-
@available_option_types =
|
60
|
-
|
61
|
-
|
62
|
-
|
57
|
+
def set_available_option_types
|
58
|
+
@available_option_types = if @product.option_type_ids.any?
|
59
|
+
OptionType.where('id NOT IN (?)', @product.option_type_ids)
|
60
|
+
else
|
61
|
+
OptionType.all
|
63
62
|
end
|
64
|
-
@available_option_types.delete_if {|ot| selected_option_types.include? ot}
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
@@ -51,9 +51,8 @@ module Spree
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def fire
|
54
|
-
# TODO: consider finer-grained control for this type of action (right now anyone in admin role can perform)
|
55
54
|
return unless event = params[:e] and @payment.payment_source
|
56
|
-
if @payment.
|
55
|
+
if @payment.send("#{event}!")
|
57
56
|
flash.notice = t(:payment_updated)
|
58
57
|
else
|
59
58
|
flash[:error] = t(:cannot_perform_operation)
|
@@ -85,7 +85,18 @@ module Spree
|
|
85
85
|
params[:q][:s] ||= "name asc"
|
86
86
|
|
87
87
|
@search = super.search(params[:q])
|
88
|
-
@collection = @search.result.
|
88
|
+
@collection = @search.result.
|
89
|
+
group_by_products_id.
|
90
|
+
includes([:master, {:variants => [:images, :option_values]}]).
|
91
|
+
page(params[:page]).
|
92
|
+
per(Spree::Config[:admin_products_per_page])
|
93
|
+
|
94
|
+
if params[:q][:s].include?("master_price")
|
95
|
+
# By applying the group in the main query we get an undefined method gsub for Arel::Nodes::Descending
|
96
|
+
# It seems to only work when the price is actually being sorted in the query
|
97
|
+
# To be investigated later.
|
98
|
+
@collection = @collection.group("spree_variants.price")
|
99
|
+
end
|
89
100
|
else
|
90
101
|
includes = [{:variants => [:images, {:option_values => :option_type}]}, {:master => :images}]
|
91
102
|
|
@@ -95,10 +106,8 @@ module Spree
|
|
95
106
|
tmp = super.where(["#{Variant.table_name}.sku #{LIKE} ?", "%#{params[:q]}%"])
|
96
107
|
tmp = tmp.includes(:variants_including_master).limit(params[:limit] || 10)
|
97
108
|
@collection.concat(tmp)
|
98
|
-
|
99
|
-
@collection
|
100
109
|
end
|
101
|
-
|
110
|
+
@collection
|
102
111
|
end
|
103
112
|
|
104
113
|
def create_before
|
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def show
|
16
|
-
@product = Product.find_by_permalink!(params[:id])
|
16
|
+
@product = Product.active.find_by_permalink!(params[:id])
|
17
17
|
return unless @product
|
18
18
|
|
19
19
|
@variants = Variant.active.includes([:option_values, :images]).where(:product_id => @product.id)
|
@@ -7,7 +7,7 @@ module Spree
|
|
7
7
|
def index
|
8
8
|
# we return ALL known information, since billing country isn't restricted
|
9
9
|
# by shipping country
|
10
|
-
respond_with @state_info = Spree::State.states_group_by_country_id.to_json
|
10
|
+
respond_with @state_info = Spree::State.states_group_by_country_id.to_json, :layout => nil
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -64,6 +64,11 @@ module Spree
|
|
64
64
|
end
|
65
65
|
|
66
66
|
Spree::Image.attachment_definitions[:attachment][:styles].each do |style, v|
|
67
|
+
# Defines these methods by default:
|
68
|
+
# def mini_image
|
69
|
+
# def small_image
|
70
|
+
# def product_image
|
71
|
+
# def large_image
|
67
72
|
define_method "#{style}_image" do |product, *options|
|
68
73
|
options = options.first || {}
|
69
74
|
if product.images.empty?
|
@@ -100,13 +105,10 @@ module Spree
|
|
100
105
|
end
|
101
106
|
|
102
107
|
def flash_messages
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
''
|
108
|
-
end
|
109
|
-
end.join("\n").html_safe
|
108
|
+
flash.each do |msg_type, text|
|
109
|
+
concat(content_tag :div, text, :class => "flash #{msg_type}")
|
110
|
+
end
|
111
|
+
nil
|
110
112
|
end
|
111
113
|
|
112
114
|
def breadcrumbs(taxon, separator=" » ")
|
@@ -12,12 +12,6 @@ module Spree
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
# returns the price of the product to show for display purposes
|
16
|
-
def product_price(product_or_variant, options={})
|
17
|
-
ActiveSupport::Deprecation.warn('product_price is deprecated and no longer calculates
|
18
|
-
tax. Use number_to_currency instead.', caller)
|
19
|
-
end
|
20
|
-
|
21
15
|
# converts line breaks in product description into <p> tags (for html display purposes)
|
22
16
|
def product_description(product)
|
23
17
|
raw(product.description.gsub(/^(.*)$/, '<p>\1</p>'))
|
@@ -2,17 +2,17 @@ module Spree
|
|
2
2
|
class OrderMailer < ActionMailer::Base
|
3
3
|
helper 'spree/base'
|
4
4
|
|
5
|
-
def confirm_email(order, resend=false)
|
5
|
+
def confirm_email(order, resend = false)
|
6
6
|
@order = order
|
7
|
-
subject = (resend ? "[#{t(:resend).upcase}] " :
|
7
|
+
subject = (resend ? "[#{t(:resend).upcase}] " : '')
|
8
8
|
subject += "#{Spree::Config[:site_name]} #{t('order_mailer.confirm_email.subject')} ##{order.number}"
|
9
9
|
mail(:to => order.email,
|
10
10
|
:subject => subject)
|
11
11
|
end
|
12
12
|
|
13
|
-
def cancel_email(order, resend=false)
|
13
|
+
def cancel_email(order, resend = false)
|
14
14
|
@order = order
|
15
|
-
subject = (resend ? "[#{t(:resend).upcase}] " :
|
15
|
+
subject = (resend ? "[#{t(:resend).upcase}] " : '')
|
16
16
|
subject += "#{Spree::Config[:site_name]} #{t('order_mailer.cancel_email.subject')} ##{order.number}"
|
17
17
|
mail(:to => order.email,
|
18
18
|
:subject => subject)
|
@@ -2,9 +2,9 @@ module Spree
|
|
2
2
|
class ShipmentMailer < ActionMailer::Base
|
3
3
|
helper 'spree/base'
|
4
4
|
|
5
|
-
def shipped_email(shipment, resend=false)
|
5
|
+
def shipped_email(shipment, resend = false)
|
6
6
|
@shipment = shipment
|
7
|
-
subject = (resend ? "[#{t(:resend).upcase}] " :
|
7
|
+
subject = (resend ? "[#{t(:resend).upcase}] " : '')
|
8
8
|
subject += "#{Spree::Config[:site_name]} #{t('shipment_mailer.shipped_email.subject')} ##{shipment.order.number}"
|
9
9
|
mail(:to => shipment.order.email,
|
10
10
|
:subject => subject)
|
data/app/models/spree/address.rb
CHANGED
@@ -13,14 +13,12 @@ module Spree
|
|
13
13
|
:country, :state, :phone, :state_name,
|
14
14
|
:company, :alternative_phone
|
15
15
|
|
16
|
-
#
|
16
|
+
# Disconnected since there's no code to display error messages yet OR matching client-side validation
|
17
17
|
def phone_validate
|
18
18
|
return if phone.blank?
|
19
19
|
n_digits = phone.scan(/[0-9]/).size
|
20
20
|
valid_chars = (phone =~ /^[-+()\/\s\d]+$/)
|
21
|
-
|
22
|
-
errors.add(:phone, :invalid)
|
23
|
-
end
|
21
|
+
errors.add :phone, :invalid unless (n_digits > 5 && valid_chars)
|
24
22
|
end
|
25
23
|
|
26
24
|
def self.default
|
@@ -28,7 +26,7 @@ module Spree
|
|
28
26
|
new({:country => country}, :without_protection => true)
|
29
27
|
end
|
30
28
|
|
31
|
-
#
|
29
|
+
# Can modify an address if it's not been used in an order (but checkouts controller has finer control)
|
32
30
|
# def editable?
|
33
31
|
# new_record? || (shipments.empty? && checkouts.empty?)
|
34
32
|
# end
|
@@ -51,7 +49,7 @@ module Spree
|
|
51
49
|
|
52
50
|
def same_as?(other)
|
53
51
|
return false if other.nil?
|
54
|
-
attributes.except('id', 'updated_at', 'created_at') ==
|
52
|
+
attributes.except('id', 'updated_at', 'created_at') == other.attributes.except('id', 'updated_at', 'created_at')
|
55
53
|
end
|
56
54
|
|
57
55
|
alias same_as same_as?
|
@@ -77,14 +75,28 @@ module Spree
|
|
77
75
|
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id').all? { |_, v| v.nil? }
|
78
76
|
end
|
79
77
|
|
78
|
+
# Generates an ActiveMerchant compatible address hash
|
79
|
+
def active_merchant_hash
|
80
|
+
{
|
81
|
+
:name => full_name,
|
82
|
+
:address1 => address1,
|
83
|
+
:address2 => address2,
|
84
|
+
:city => city,
|
85
|
+
:state => state_text,
|
86
|
+
:zip => zipcode,
|
87
|
+
:country => country.try(:iso),
|
88
|
+
:phone => phone
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
80
92
|
private
|
81
93
|
|
82
94
|
def state_validate
|
83
|
-
#
|
84
|
-
#or when disabled by
|
85
|
-
return if
|
95
|
+
# Skip state validation without country (also required)
|
96
|
+
# or when disabled by preference
|
97
|
+
return if country.blank? || !Spree::Config[:address_requires_state]
|
86
98
|
|
87
|
-
#ensure associated state belongs to country
|
99
|
+
# ensure associated state belongs to country
|
88
100
|
if state.present?
|
89
101
|
if state.country == country
|
90
102
|
self.state_name = nil #not required as we have a valid state and country combo
|
@@ -97,7 +109,7 @@ module Spree
|
|
97
109
|
end
|
98
110
|
end
|
99
111
|
|
100
|
-
#ensure state_name belongs to country without states, or that it matches a predefined state name/abbr
|
112
|
+
# ensure state_name belongs to country without states, or that it matches a predefined state name/abbr
|
101
113
|
if state_name.present?
|
102
114
|
if country.states.present?
|
103
115
|
states = country.states.find_all_by_name_or_abbr(state_name)
|
@@ -111,10 +123,8 @@ module Spree
|
|
111
123
|
end
|
112
124
|
end
|
113
125
|
|
114
|
-
#ensure at least one state field is populated
|
115
|
-
if
|
116
|
-
errors.add(:state, :blank)
|
117
|
-
end
|
126
|
+
# ensure at least one state field is populated
|
127
|
+
errors.add :state, :blank if state.blank? && state_name.blank?
|
118
128
|
end
|
119
129
|
|
120
130
|
end
|
@@ -11,19 +11,14 @@ module Spree
|
|
11
11
|
validates :number, :presence => true, :unless => :has_payment_profile?, :on => :create
|
12
12
|
validates :verification_value, :presence => true, :unless => :has_payment_profile?, :on => :create
|
13
13
|
|
14
|
-
attr_accessible :first_name, :last_name, :number, :verification_value, :year,
|
14
|
+
attr_accessible :first_name, :last_name, :number, :verification_value, :year,
|
15
|
+
:month, :gateway_customer_profile_id
|
15
16
|
|
16
|
-
|
17
|
-
if Spree::Config[:auto_capture]
|
18
|
-
purchase(payment.amount.to_f, payment)
|
19
|
-
else
|
20
|
-
authorize(payment.amount.to_f, payment)
|
21
|
-
end
|
22
|
-
end
|
17
|
+
scope :with_payment_profile, where('gateway_customer_profile_id IS NOT NULL')
|
23
18
|
|
24
19
|
def set_last_digits
|
25
|
-
number.to_s.gsub!(/\s/,'')
|
26
|
-
verification_value.to_s.gsub!(/\s/,'')
|
20
|
+
number.to_s.gsub!(/\s/,'')
|
21
|
+
verification_value.to_s.gsub!(/\s/,'')
|
27
22
|
self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
|
28
23
|
end
|
29
24
|
|
@@ -37,7 +32,7 @@ module Spree
|
|
37
32
|
|
38
33
|
# sets self.cc_type while we still have the card number
|
39
34
|
def set_card_type
|
40
|
-
self.cc_type ||= CardDetector.type?(
|
35
|
+
self.cc_type ||= CardDetector.type?(number)
|
41
36
|
end
|
42
37
|
|
43
38
|
def name?
|
@@ -65,127 +60,11 @@ module Spree
|
|
65
60
|
"XXXX-XXXX-XXXX-#{last_digits}"
|
66
61
|
end
|
67
62
|
|
68
|
-
#RAILS 3 TODO
|
69
|
-
#alias :attributes_with_quotes_default :attributes_with_quotes
|
70
|
-
|
71
63
|
# needed for some of the ActiveMerchant gateways (eg. SagePay)
|
72
64
|
def brand
|
73
65
|
cc_type
|
74
66
|
end
|
75
67
|
|
76
|
-
scope :with_payment_profile, where('gateway_customer_profile_id IS NOT NULL')
|
77
|
-
|
78
|
-
def authorize(amount, payment)
|
79
|
-
# ActiveMerchant is configured to use cents so we need to multiply order total by 100
|
80
|
-
payment_gateway = payment.payment_method
|
81
|
-
check_environment(payment_gateway)
|
82
|
-
|
83
|
-
response = payment_gateway.authorize((amount * 100).round, self, gateway_options(payment))
|
84
|
-
record_log payment, response
|
85
|
-
|
86
|
-
if response.success?
|
87
|
-
payment.response_code = response.authorization
|
88
|
-
payment.avs_response = response.avs_result['code']
|
89
|
-
payment.pend
|
90
|
-
else
|
91
|
-
payment.failure
|
92
|
-
gateway_error(response)
|
93
|
-
end
|
94
|
-
rescue ActiveMerchant::ConnectionError => e
|
95
|
-
gateway_error e
|
96
|
-
end
|
97
|
-
|
98
|
-
def purchase(amount, payment)
|
99
|
-
#combined Authorize and Capture that gets processed by the ActiveMerchant gateway as one single transaction.
|
100
|
-
payment_gateway = payment.payment_method
|
101
|
-
check_environment(payment_gateway)
|
102
|
-
|
103
|
-
response = payment_gateway.purchase((amount * 100).round, self, gateway_options(payment))
|
104
|
-
record_log payment, response
|
105
|
-
|
106
|
-
if response.success?
|
107
|
-
payment.response_code = response.authorization
|
108
|
-
payment.avs_response = response.avs_result['code']
|
109
|
-
payment.complete
|
110
|
-
else
|
111
|
-
payment.failure
|
112
|
-
gateway_error(response) unless response.success?
|
113
|
-
end
|
114
|
-
rescue ActiveMerchant::ConnectionError => e
|
115
|
-
gateway_error e
|
116
|
-
end
|
117
|
-
|
118
|
-
def capture(payment)
|
119
|
-
return unless payment.pending?
|
120
|
-
payment_gateway = payment.payment_method
|
121
|
-
check_environment(payment_gateway)
|
122
|
-
|
123
|
-
if payment_gateway.payment_profiles_supported?
|
124
|
-
# Gateways supporting payment profiles will need access to creditcard object because this stores the payment profile information
|
125
|
-
# so supply the authorization itself as well as the creditcard, rather than just the authorization code
|
126
|
-
response = payment_gateway.capture(payment, self, minimal_gateway_options(payment, false))
|
127
|
-
else
|
128
|
-
# Standard ActiveMerchant capture usage
|
129
|
-
response = payment_gateway.capture((payment.amount * 100).round, payment.response_code, minimal_gateway_options(payment, false))
|
130
|
-
end
|
131
|
-
|
132
|
-
record_log payment, response
|
133
|
-
|
134
|
-
if response.success?
|
135
|
-
payment.response_code = response.authorization
|
136
|
-
payment.complete
|
137
|
-
else
|
138
|
-
payment.failure
|
139
|
-
gateway_error(response)
|
140
|
-
end
|
141
|
-
rescue ActiveMerchant::ConnectionError => e
|
142
|
-
gateway_error e
|
143
|
-
end
|
144
|
-
|
145
|
-
def void(payment)
|
146
|
-
payment_gateway = payment.payment_method
|
147
|
-
check_environment(payment_gateway)
|
148
|
-
|
149
|
-
response = payment_gateway.void(payment.response_code, minimal_gateway_options(payment, false))
|
150
|
-
record_log payment, response
|
151
|
-
|
152
|
-
if response.success?
|
153
|
-
payment.response_code = response.authorization
|
154
|
-
payment.void
|
155
|
-
else
|
156
|
-
gateway_error(response)
|
157
|
-
end
|
158
|
-
rescue ActiveMerchant::ConnectionError => e
|
159
|
-
gateway_error e
|
160
|
-
end
|
161
|
-
|
162
|
-
def credit(payment)
|
163
|
-
payment_gateway = payment.payment_method
|
164
|
-
check_environment(payment_gateway)
|
165
|
-
|
166
|
-
amount = payment.credit_allowed >= payment.order.outstanding_balance.abs ? payment.order.outstanding_balance.abs : payment.credit_allowed.abs
|
167
|
-
if payment_gateway.payment_profiles_supported?
|
168
|
-
response = payment_gateway.credit((amount * 100).round, self, payment.response_code, minimal_gateway_options(payment, false))
|
169
|
-
else
|
170
|
-
response = payment_gateway.credit((amount * 100).round, payment.response_code, minimal_gateway_options(payment, false))
|
171
|
-
end
|
172
|
-
|
173
|
-
record_log payment, response
|
174
|
-
|
175
|
-
if response.success?
|
176
|
-
Payment.create({:order => payment.order,
|
177
|
-
:source => payment,
|
178
|
-
:payment_method => payment.payment_method,
|
179
|
-
:amount => amount.abs * -1,
|
180
|
-
:response_code => response.authorization,
|
181
|
-
:state => 'completed'}, :without_protection => true)
|
182
|
-
else
|
183
|
-
gateway_error(response)
|
184
|
-
end
|
185
|
-
rescue ActiveMerchant::ConnectionError => e
|
186
|
-
gateway_error e
|
187
|
-
end
|
188
|
-
|
189
68
|
def actions
|
190
69
|
%w{capture void credit}
|
191
70
|
end
|
@@ -197,7 +76,7 @@ module Spree
|
|
197
76
|
|
198
77
|
# Indicates whether its possible to void the payment.
|
199
78
|
def can_void?(payment)
|
200
|
-
payment.state
|
79
|
+
payment.state != 'void'
|
201
80
|
end
|
202
81
|
|
203
82
|
# Indicates whether its possible to credit the payment. Note that most gateways require that the
|
@@ -212,64 +91,9 @@ module Spree
|
|
212
91
|
gateway_customer_profile_id.present?
|
213
92
|
end
|
214
93
|
|
215
|
-
def record_log(payment, response)
|
216
|
-
payment.log_entries.create({:details => response.to_yaml}, :without_protection => true)
|
217
|
-
end
|
218
|
-
|
219
|
-
def gateway_error(error)
|
220
|
-
if error.is_a? ActiveMerchant::Billing::Response
|
221
|
-
text = error.params['message'] || error.params['response_reason_text'] || error.message
|
222
|
-
elsif error.is_a? ActiveMerchant::ConnectionError
|
223
|
-
text = I18n.t(:unable_to_connect_to_gateway)
|
224
|
-
else
|
225
|
-
text = error.to_s
|
226
|
-
end
|
227
|
-
logger.error(I18n.t(:gateway_error))
|
228
|
-
logger.error(" #{error.to_yaml}")
|
229
|
-
raise Core::GatewayError.new(text)
|
230
|
-
end
|
231
|
-
|
232
|
-
def gateway_options(payment)
|
233
|
-
options = { :billing_address => generate_address_hash(payment.order.bill_address),
|
234
|
-
:shipping_address => generate_address_hash(payment.order.ship_address) }
|
235
|
-
options.merge minimal_gateway_options(payment)
|
236
|
-
end
|
237
|
-
|
238
|
-
# Generates an ActiveMerchant compatible address hash from one of Spree's address objects
|
239
|
-
def generate_address_hash(address)
|
240
|
-
return {} if address.nil?
|
241
|
-
{ :name => address.full_name, :address1 => address.address1, :address2 => address.address2, :city => address.city,
|
242
|
-
:state => address.state_text, :zip => address.zipcode, :country => address.country.iso, :phone => address.phone }
|
243
|
-
end
|
244
|
-
|
245
|
-
# Generates a minimal set of gateway options. There appears to be some issues with passing in
|
246
|
-
# a billing address when authorizing/voiding a previously captured transaction. So omits these
|
247
|
-
# options in this case since they aren't necessary.
|
248
|
-
def minimal_gateway_options(payment, totals=true)
|
249
|
-
|
250
|
-
options = { :email => payment.order.email,
|
251
|
-
:customer => payment.order.email,
|
252
|
-
:ip => payment.order.ip_address,
|
253
|
-
:order_id => payment.order.number }
|
254
|
-
if totals
|
255
|
-
options.merge!({ :shipping => payment.order.ship_total * 100,
|
256
|
-
:tax => payment.order.tax_total * 100,
|
257
|
-
:subtotal => payment.order.item_total * 100 })
|
258
|
-
end
|
259
|
-
options
|
260
|
-
end
|
261
|
-
|
262
94
|
def spree_cc_type
|
263
95
|
return 'visa' if Rails.env.development?
|
264
|
-
|
265
|
-
end
|
266
|
-
|
267
|
-
# Saftey check to make sure we're not accidentally performing operations on a live gateway.
|
268
|
-
# Ex. When testing in staging environment with a copy of production data.
|
269
|
-
def check_environment(gateway)
|
270
|
-
return if gateway.environment == Rails.env
|
271
|
-
message = I18n.t(:gateway_config_unavailable) + " - #{Rails.env}"
|
272
|
-
raise Core::GatewayError.new(message)
|
96
|
+
cc_type
|
273
97
|
end
|
274
98
|
end
|
275
99
|
end
|
data/app/models/spree/gateway.rb
CHANGED
@@ -6,6 +6,8 @@ module Spree
|
|
6
6
|
|
7
7
|
preference :server, :string, :default => 'test'
|
8
8
|
preference :test_mode, :boolean, :default => true
|
9
|
+
|
10
|
+
attr_accessible :preferred_server, :preferred_test_mode
|
9
11
|
|
10
12
|
def payment_source_class
|
11
13
|
Creditcard
|
@@ -25,7 +27,7 @@ module Spree
|
|
25
27
|
|
26
28
|
def options
|
27
29
|
options_hash = {}
|
28
|
-
self.preferences.each do |key,value|
|
30
|
+
self.preferences.each do |key, value|
|
29
31
|
options_hash[key.to_sym] = value
|
30
32
|
end
|
31
33
|
options_hash
|
@@ -106,12 +106,12 @@ module Spree
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def update_order
|
109
|
-
|
109
|
+
order.update!
|
110
110
|
end
|
111
111
|
|
112
112
|
def restock_variant
|
113
|
-
|
114
|
-
|
113
|
+
variant.on_hand = (variant.on_hand + 1)
|
114
|
+
variant.save
|
115
115
|
end
|
116
116
|
end
|
117
117
|
end
|
@@ -24,7 +24,7 @@ module Spree
|
|
24
24
|
after_destroy :update_order
|
25
25
|
|
26
26
|
def copy_price
|
27
|
-
self.price = variant.price if variant &&
|
27
|
+
self.price = variant.price if variant && price.nil?
|
28
28
|
end
|
29
29
|
|
30
30
|
def increment_quantity
|
@@ -36,16 +36,16 @@ module Spree
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def amount
|
39
|
-
|
39
|
+
price * quantity
|
40
40
|
end
|
41
41
|
alias total amount
|
42
42
|
|
43
43
|
def adjust_quantity
|
44
|
-
self.quantity = 0 if
|
44
|
+
self.quantity = 0 if quantity.nil? || quantity < 0
|
45
45
|
end
|
46
46
|
|
47
47
|
def sufficient_stock?
|
48
|
-
Spree::Config[:allow_backorders] ? true : (
|
48
|
+
Spree::Config[:allow_backorders] ? true : (variant.on_hand >= quantity)
|
49
49
|
end
|
50
50
|
|
51
51
|
def insufficient_stock?
|
@@ -54,23 +54,23 @@ module Spree
|
|
54
54
|
|
55
55
|
private
|
56
56
|
def update_inventory
|
57
|
-
return true unless
|
57
|
+
return true unless order.completed?
|
58
58
|
|
59
|
-
if
|
60
|
-
InventoryUnit.increase(
|
59
|
+
if new_record?
|
60
|
+
InventoryUnit.increase(order, variant, quantity)
|
61
61
|
elsif old_quantity = self.changed_attributes['quantity']
|
62
|
-
if old_quantity <
|
63
|
-
InventoryUnit.increase(
|
64
|
-
elsif old_quantity >
|
65
|
-
InventoryUnit.decrease(
|
62
|
+
if old_quantity < quantity
|
63
|
+
InventoryUnit.increase(order, variant, (quantity - old_quantity))
|
64
|
+
elsif old_quantity > quantity
|
65
|
+
InventoryUnit.decrease(order, variant, (old_quantity - quantity))
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
def remove_inventory
|
71
|
-
return true unless
|
71
|
+
return true unless order.completed?
|
72
72
|
|
73
|
-
InventoryUnit.decrease(
|
73
|
+
InventoryUnit.decrease(order, variant, quantity)
|
74
74
|
end
|
75
75
|
|
76
76
|
def update_order
|
@@ -79,7 +79,7 @@ module Spree
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def ensure_not_shipped
|
82
|
-
if order.try(:inventory_units).to_a.any?{|unit| unit.variant_id == variant_id && unit.shipped?}
|
82
|
+
if order.try(:inventory_units).to_a.any?{ |unit| unit.variant_id == variant_id && unit.shipped? }
|
83
83
|
errors.add :base, I18n.t('validation.cannot_destory_line_item_as_inventory_units_have_shipped')
|
84
84
|
return false
|
85
85
|
end
|